summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
commit34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch)
treed503eaf41d085669d1481bb46ec038bc866fece6 /libgo
parentf733cf303bcdc952c92b81dd62199a40a1f555ec (diff)
downloadgcc-tarball-34efdaf078b01a7387007c4e6bde6db86384c4b7.tar.gz
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'libgo')
-rw-r--r--libgo/MERGE2
-rw-r--r--libgo/Makefile.am3953
-rw-r--r--libgo/Makefile.in4365
-rw-r--r--libgo/VERSION2
-rw-r--r--libgo/aclocal.m41
-rw-r--r--libgo/config.h.in12
-rwxr-xr-xlibgo/configure535
-rw-r--r--libgo/configure.ac218
-rw-r--r--libgo/go/archive/tar/common.go64
-rw-r--r--libgo/go/archive/tar/format.go197
-rw-r--r--libgo/go/archive/tar/reader.go657
-rw-r--r--libgo/go/archive/tar/reader_test.go773
-rw-r--r--libgo/go/archive/tar/strconv.go252
-rw-r--r--libgo/go/archive/tar/strconv_test.go319
-rw-r--r--libgo/go/archive/tar/tar_test.go236
-rw-r--r--libgo/go/archive/tar/testdata/gnu-incremental.tarbin0 -> 2560 bytes
-rw-r--r--libgo/go/archive/tar/testdata/pax-bad-hdr-file.tarbin0 -> 2560 bytes
-rw-r--r--libgo/go/archive/tar/testdata/pax-bad-mtime-file.tarbin0 -> 2560 bytes
-rw-r--r--libgo/go/archive/tar/testdata/pax-pos-size-file.tarbin0 -> 2560 bytes
-rw-r--r--libgo/go/archive/tar/testdata/ustar.issue12594.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer-big-long.tarbin4096 -> 4096 bytes
-rw-r--r--libgo/go/archive/tar/writer.go212
-rw-r--r--libgo/go/archive/tar/writer_test.go505
-rw-r--r--libgo/go/archive/zip/reader.go13
-rw-r--r--libgo/go/archive/zip/reader_test.go2
-rw-r--r--libgo/go/archive/zip/register.go40
-rw-r--r--libgo/go/archive/zip/struct.go2
-rw-r--r--libgo/go/archive/zip/testdata/readme.notzipbin1905 -> 1906 bytes
-rw-r--r--libgo/go/archive/zip/testdata/readme.zipbin1885 -> 1886 bytes
-rw-r--r--libgo/go/archive/zip/writer.go13
-rw-r--r--libgo/go/archive/zip/writer_test.go8
-rw-r--r--libgo/go/archive/zip/zip_test.go345
-rw-r--r--libgo/go/bufio/bufio.go62
-rw-r--r--libgo/go/bufio/bufio_test.go27
-rw-r--r--libgo/go/bufio/scan.go1
-rw-r--r--libgo/go/bufio/scan_test.go6
-rw-r--r--libgo/go/builtin/builtin.go4
-rw-r--r--libgo/go/bytes/buffer.go57
-rw-r--r--libgo/go/bytes/buffer_test.go13
-rw-r--r--libgo/go/bytes/bytes.go170
-rw-r--r--libgo/go/bytes/bytes_amd64.go117
-rw-r--r--libgo/go/bytes/bytes_decl.go2
-rw-r--r--libgo/go/bytes/bytes_generic.go41
-rw-r--r--libgo/go/bytes/bytes_s390x.go120
-rw-r--r--libgo/go/bytes/bytes_test.go609
-rw-r--r--libgo/go/bytes/compare_test.go2
-rw-r--r--libgo/go/bytes/equal_test.go4
-rw-r--r--libgo/go/bytes/example_test.go203
-rw-r--r--libgo/go/bytes/reader.go20
-rw-r--r--libgo/go/bytes/reader_test.go50
-rw-r--r--libgo/go/cmd/cgo/ast.go32
-rw-r--r--libgo/go/cmd/cgo/doc.go54
-rw-r--r--libgo/go/cmd/cgo/gcc.go499
-rw-r--r--libgo/go/cmd/cgo/godefs.go2
-rw-r--r--libgo/go/cmd/cgo/main.go32
-rw-r--r--libgo/go/cmd/cgo/out.go294
-rw-r--r--libgo/go/cmd/cgo/util.go51
-rw-r--r--libgo/go/cmd/go/alldocs.go3209
-rw-r--r--libgo/go/cmd/go/bootstrap.go5
-rw-r--r--libgo/go/cmd/go/bug.go212
-rw-r--r--libgo/go/cmd/go/build.go825
-rw-r--r--libgo/go/cmd/go/build_test.go44
-rw-r--r--libgo/go/cmd/go/clean.go2
-rw-r--r--libgo/go/cmd/go/context.go3
-rw-r--r--libgo/go/cmd/go/discovery.go2
-rw-r--r--libgo/go/cmd/go/doc.go4
-rw-r--r--libgo/go/cmd/go/env.go51
-rw-r--r--libgo/go/cmd/go/fix.go2
-rw-r--r--libgo/go/cmd/go/fmt.go2
-rw-r--r--libgo/go/cmd/go/generate.go29
-rw-r--r--libgo/go/cmd/go/generate_test.go2
-rw-r--r--libgo/go/cmd/go/get.go149
-rw-r--r--libgo/go/cmd/go/go11.go2
-rw-r--r--libgo/go/cmd/go/go_test.go1416
-rw-r--r--libgo/go/cmd/go/go_unix_test.go2
-rw-r--r--libgo/go/cmd/go/go_windows_test.go3
-rw-r--r--libgo/go/cmd/go/help.go89
-rw-r--r--libgo/go/cmd/go/http.go9
-rw-r--r--libgo/go/cmd/go/list.go26
-rw-r--r--libgo/go/cmd/go/main.go88
-rw-r--r--libgo/go/cmd/go/match_test.go2
-rw-r--r--libgo/go/cmd/go/note.go6
-rw-r--r--libgo/go/cmd/go/note_test.go4
-rw-r--r--libgo/go/cmd/go/pkg.go434
-rw-r--r--libgo/go/cmd/go/pkg_test.go7
-rw-r--r--libgo/go/cmd/go/run.go4
-rw-r--r--libgo/go/cmd/go/tag_test.go2
-rw-r--r--libgo/go/cmd/go/test.go306
-rw-r--r--libgo/go/cmd/go/testdata/dep_test.go2
-rw-r--r--libgo/go/cmd/go/testdata/example1_test.go2
-rw-r--r--libgo/go/cmd/go/testdata/example2_test.go2
-rw-r--r--libgo/go/cmd/go/testdata/failssh/ssh2
-rw-r--r--libgo/go/cmd/go/testdata/generate/test1.go2
-rw-r--r--libgo/go/cmd/go/testdata/generate/test2.go2
-rw-r--r--libgo/go/cmd/go/testdata/generate/test3.go2
-rw-r--r--libgo/go/cmd/go/testdata/generate/test4.go2
-rw-r--r--libgo/go/cmd/go/testdata/src/badc/x.c1
-rw-r--r--libgo/go/cmd/go/testdata/src/benchfatal/x_test.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/a/a.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/a/vendor/c/c.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/b/b.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/d/d.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover/p.go (renamed from libgo/go/cmd/go/testdata/cgocover/p.go)0
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover/p_test.go (renamed from libgo/go/cmd/go/testdata/cgocover/p_test.go)0
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover2/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover2/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/p_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/dupload.go8
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/p/p.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/p2/p2.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/vendor/p/p.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/test/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/gencycle/gencycle.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/ismain/main.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/test/test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/test/test_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/src/my.pkg/main/main.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/my.pkg/pkg.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/testrace/race_test.go29
-rw-r--r--libgo/go/cmd/go/testdata/standalone_benchmark_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/standalone_fail_sub_test.go8
-rw-r--r--libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go14
-rw-r--r--libgo/go/cmd/go/testdata/standalone_sub_test.go7
-rw-r--r--libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go39
-rw-r--r--libgo/go/cmd/go/testdata/timeoutbench_test.go10
-rw-r--r--libgo/go/cmd/go/testflag.go6
-rw-r--r--libgo/go/cmd/go/testgo.go2
-rw-r--r--libgo/go/cmd/go/tool.go4
-rw-r--r--libgo/go/cmd/go/vcs.go188
-rw-r--r--libgo/go/cmd/go/vcs_test.go237
-rw-r--r--libgo/go/cmd/go/vendor_test.go79
-rw-r--r--libgo/go/cmd/go/version.go2
-rw-r--r--libgo/go/cmd/go/vet.go2
-rw-r--r--libgo/go/cmd/gofmt/doc.go5
-rw-r--r--libgo/go/cmd/gofmt/gofmt.go57
-rw-r--r--libgo/go/cmd/gofmt/gofmt_test.go17
-rw-r--r--libgo/go/cmd/gofmt/internal.go6
-rw-r--r--libgo/go/cmd/gofmt/rewrite.go4
-rw-r--r--libgo/go/cmd/gofmt/simplify.go88
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.golden14
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.input14
-rw-r--r--libgo/go/cmd/gofmt/testdata/emptydecl.golden14
-rw-r--r--libgo/go/cmd/gofmt/testdata/emptydecl.input16
-rw-r--r--libgo/go/cmd/gofmt/testdata/ranges.golden30
-rw-r--r--libgo/go/cmd/gofmt/testdata/ranges.input20
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices2.golden63
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices2.input63
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin5.golden3
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin5.input3
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin6.golden19
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin6.input21
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin7.golden19
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin7.input21
-rw-r--r--libgo/go/cmd/internal/browser/browser.go46
-rw-r--r--libgo/go/compress/bzip2/bzip2.go17
-rw-r--r--libgo/go/compress/bzip2/bzip2_test.go571
-rw-r--r--libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2bin124744 -> 118509 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/fail-issue5747.bz2bin0 -> 7232 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/pass-random1.binbin0 -> 1024 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/pass-random1.bz2bin0 -> 1309 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/pass-random2.bin1
-rw-r--r--libgo/go/compress/bzip2/testdata/pass-random2.bz2bin0 -> 125 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/pass-sawtooth.bz2bin0 -> 2017 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/random.data.bz2bin0 -> 16846 bytes
-rw-r--r--libgo/go/compress/flate/copy.go32
-rw-r--r--libgo/go/compress/flate/copy_test.go54
-rw-r--r--libgo/go/compress/flate/deflate.go406
-rw-r--r--libgo/go/compress/flate/deflate_test.go429
-rw-r--r--libgo/go/compress/flate/deflatefast.go285
-rw-r--r--libgo/go/compress/flate/dict_decoder.go184
-rw-r--r--libgo/go/compress/flate/dict_decoder_test.go139
-rw-r--r--libgo/go/compress/flate/example_test.go245
-rw-r--r--libgo/go/compress/flate/flate_test.go79
-rw-r--r--libgo/go/compress/flate/huffman_bit_writer.go550
-rw-r--r--libgo/go/compress/flate/huffman_bit_writer_test.go366
-rw-r--r--libgo/go/compress/flate/huffman_code.go119
-rw-r--r--libgo/go/compress/flate/inflate.go230
-rw-r--r--libgo/go/compress/flate/inflate_test.go59
-rw-r--r--libgo/go/compress/flate/reader_test.go126
-rw-r--r--libgo/go/compress/flate/reverse_bits.go2
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.dyn.expectbin0 -> 78 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect-noinputbin0 -> 78 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.goldenbin0 -> 8204 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.inbin0 -> 65535 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.wb.expectbin0 -> 78 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-null-max.wb.expect-noinputbin0 -> 78 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.dyn.expectbin0 -> 1696 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.dyn.expect-noinputbin0 -> 1696 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.goldenbin0 -> 1606 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.in1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.wb.expectbin0 -> 1696 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-pi.wb.expect-noinputbin0 -> 1696 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expectbin0 -> 1005 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinputbin0 -> 1054 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.goldenbin0 -> 1005 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.inbin0 -> 1000 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expectbin0 -> 1005 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect-noinputbin0 -> 1054 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expectbin0 -> 229 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinputbin0 -> 229 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.goldenbin0 -> 252 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.in4
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expectbin0 -> 186 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect-noinputbin0 -> 186 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-max.goldenbin0 -> 65540 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-rand-max.inbin0 -> 65535 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.dyn.expectbin0 -> 32 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect-noinputbin0 -> 32 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.goldenbin0 -> 1812 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.in2
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.wb.expectbin0 -> 32 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-shifts.wb.expect-noinputbin0 -> 32 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expectbin0 -> 231 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect-noinputbin0 -> 231 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.goldenbin0 -> 231 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.in14
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.wb.expectbin0 -> 231 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect-noinputbin0 -> 231 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.dyn.expect1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.dyn.expect-noinput1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.golden3
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.in13
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.wb.expect1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-text.wb.expect-noinput1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.dyn.expectbin0 -> 17 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.dyn.expect-noinputbin0 -> 17 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.goldenbin0 -> 51 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.in1
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.wb.expectbin0 -> 6 bytes
-rw-r--r--libgo/go/compress/flate/testdata/huffman-zero.wb.expect-noinputbin0 -> 6 bytes
-rw-r--r--libgo/go/compress/flate/testdata/null-long-match.dyn.expect-noinputbin0 -> 206 bytes
-rw-r--r--libgo/go/compress/flate/testdata/null-long-match.wb.expect-noinputbin0 -> 206 bytes
-rw-r--r--libgo/go/compress/flate/token.go3
-rw-r--r--libgo/go/compress/flate/writer_test.go195
-rw-r--r--libgo/go/compress/gzip/example_test.go130
-rw-r--r--libgo/go/compress/gzip/gunzip.go219
-rw-r--r--libgo/go/compress/gzip/gunzip_test.go132
-rw-r--r--libgo/go/compress/gzip/gzip.go64
-rw-r--r--libgo/go/compress/gzip/gzip_test.go4
-rw-r--r--libgo/go/compress/gzip/issue14937_test.go68
-rw-r--r--libgo/go/compress/gzip/testdata/issue6550.gzbin65536 -> 65536 bytes
-rw-r--r--libgo/go/compress/lzw/reader_test.go61
-rw-r--r--libgo/go/compress/lzw/writer.go2
-rw-r--r--libgo/go/compress/lzw/writer_test.go55
-rw-r--r--libgo/go/compress/zlib/reader.go57
-rw-r--r--libgo/go/compress/zlib/reader_test.go34
-rw-r--r--libgo/go/compress/zlib/writer.go11
-rw-r--r--libgo/go/compress/zlib/writer_test.go5
-rw-r--r--libgo/go/container/heap/heap.go11
-rw-r--r--libgo/go/container/heap/heap_test.go2
-rwxr-xr-xlibgo/go/container/list/list_test.go8
-rw-r--r--libgo/go/context/benchmark_test.go44
-rw-r--r--libgo/go/context/context.go479
-rw-r--r--libgo/go/context/context_test.go650
-rw-r--r--libgo/go/context/example_test.go116
-rw-r--r--libgo/go/context/net_test.go21
-rw-r--r--libgo/go/context/x_test.go29
-rw-r--r--libgo/go/crypto/aes/aes_gcm.go15
-rw-r--r--libgo/go/crypto/aes/aes_test.go36
-rw-r--r--libgo/go/crypto/aes/block.go2
-rw-r--r--libgo/go/crypto/aes/cbc_s390x.go63
-rw-r--r--libgo/go/crypto/aes/cipher.go18
-rw-r--r--libgo/go/crypto/aes/cipher_amd64.go85
-rw-r--r--libgo/go/crypto/aes/cipher_asm.go48
-rw-r--r--libgo/go/crypto/aes/cipher_generic.go27
-rw-r--r--libgo/go/crypto/aes/cipher_s390x.go88
-rw-r--r--libgo/go/crypto/aes/const.go7
-rw-r--r--libgo/go/crypto/aes/ctr_s390x.go78
-rw-r--r--libgo/go/crypto/aes/gcm_s390x.go272
-rw-r--r--libgo/go/crypto/aes/modes.go37
-rw-r--r--libgo/go/crypto/aes/modes_test.go112
-rw-r--r--libgo/go/crypto/cipher/cbc.go22
-rw-r--r--libgo/go/crypto/cipher/cipher.go4
-rw-r--r--libgo/go/crypto/cipher/cipher_test.go56
-rw-r--r--libgo/go/crypto/cipher/ctr.go10
-rw-r--r--libgo/go/crypto/cipher/example_test.go11
-rw-r--r--libgo/go/crypto/cipher/gcm.go14
-rw-r--r--libgo/go/crypto/cipher/gcm_test.go158
-rw-r--r--libgo/go/crypto/cipher/xor.go2
-rw-r--r--libgo/go/crypto/cipher/xor_test.go2
-rw-r--r--libgo/go/crypto/des/block.go2
-rw-r--r--libgo/go/crypto/dsa/dsa.go34
-rw-r--r--libgo/go/crypto/dsa/dsa_test.go38
-rw-r--r--libgo/go/crypto/ecdsa/ecdsa.go21
-rw-r--r--libgo/go/crypto/ecdsa/ecdsa_test.go37
-rw-r--r--libgo/go/crypto/ecdsa/testdata/SigVer.rsp.bz2bin0 -> 95485 bytes
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go6
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go2
-rw-r--r--libgo/go/crypto/elliptic/p224.go6
-rw-r--r--libgo/go/crypto/elliptic/p224_test.go2
-rw-r--r--libgo/go/crypto/elliptic/p256.go36
-rw-r--r--libgo/go/crypto/elliptic/p256_amd64.go11
-rw-r--r--libgo/go/crypto/elliptic/p256_generic.go16
-rw-r--r--libgo/go/crypto/elliptic/p256_s390x.go514
-rw-r--r--libgo/go/crypto/hmac/hmac.go36
-rw-r--r--libgo/go/crypto/hmac/hmac_test.go26
-rw-r--r--libgo/go/crypto/internal/cipherhw/cipherhw_amd64.go16
-rw-r--r--libgo/go/crypto/internal/cipherhw/cipherhw_s390x.go18
-rw-r--r--libgo/go/crypto/internal/cipherhw/doc.go7
-rw-r--r--libgo/go/crypto/internal/cipherhw/generic.go11
-rw-r--r--libgo/go/crypto/md5/gen.go2
-rw-r--r--libgo/go/crypto/md5/md5.go2
-rw-r--r--libgo/go/crypto/md5/md5block_decl.go5
-rw-r--r--libgo/go/crypto/md5/md5block_generic.go2
-rw-r--r--libgo/go/crypto/rand/eagain.go2
-rw-r--r--libgo/go/crypto/rand/rand.go5
-rw-r--r--libgo/go/crypto/rand/rand_linux.go2
-rw-r--r--libgo/go/crypto/rand/rand_openbsd.go28
-rw-r--r--libgo/go/crypto/rand/rand_test.go2
-rw-r--r--libgo/go/crypto/rand/rand_unix.go4
-rw-r--r--libgo/go/crypto/rand/rand_windows.go2
-rw-r--r--libgo/go/crypto/rand/util.go4
-rw-r--r--libgo/go/crypto/rand/util_test.go11
-rw-r--r--libgo/go/crypto/rc4/rc4.go4
-rw-r--r--libgo/go/crypto/rc4/rc4_asm.go2
-rw-r--r--libgo/go/crypto/rc4/rc4_ref.go2
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15.go73
-rw-r--r--libgo/go/crypto/rsa/pss.go8
-rw-r--r--libgo/go/crypto/rsa/rsa.go62
-rw-r--r--libgo/go/crypto/rsa/rsa_test.go11
-rw-r--r--libgo/go/crypto/sha1/fallback_test.go35
-rw-r--r--libgo/go/crypto/sha1/issue15617_test.go28
-rw-r--r--libgo/go/crypto/sha1/sha1.go68
-rw-r--r--libgo/go/crypto/sha1/sha1_test.go42
-rw-r--r--libgo/go/crypto/sha1/sha1block_amd64.go36
-rw-r--r--libgo/go/crypto/sha1/sha1block_decl.go5
-rw-r--r--libgo/go/crypto/sha1/sha1block_generic.go2
-rw-r--r--libgo/go/crypto/sha1/sha1block_s390x.go14
-rw-r--r--libgo/go/crypto/sha256/example_test.go43
-rw-r--r--libgo/go/crypto/sha256/fallback_test.go36
-rw-r--r--libgo/go/crypto/sha256/sha256.go2
-rw-r--r--libgo/go/crypto/sha256/sha256_test.go15
-rw-r--r--libgo/go/crypto/sha256/sha256block.go4
-rw-r--r--libgo/go/crypto/sha256/sha256block_decl.go5
-rw-r--r--libgo/go/crypto/sha256/sha256block_generic.go9
-rw-r--r--libgo/go/crypto/sha256/sha256block_s390x.go14
-rw-r--r--libgo/go/crypto/sha512/fallback_test.go38
-rw-r--r--libgo/go/crypto/sha512/sha512.go2
-rw-r--r--libgo/go/crypto/sha512/sha512_test.go15
-rw-r--r--libgo/go/crypto/sha512/sha512block.go4
-rw-r--r--libgo/go/crypto/sha512/sha512block_decl.go5
-rw-r--r--libgo/go/crypto/sha512/sha512block_generic.go9
-rw-r--r--libgo/go/crypto/sha512/sha512block_s390x.go14
-rw-r--r--libgo/go/crypto/subtle/constant_time.go2
-rw-r--r--libgo/go/crypto/tls/alert.go6
-rw-r--r--libgo/go/crypto/tls/cipher_suites.go163
-rw-r--r--libgo/go/crypto/tls/common.go305
-rw-r--r--libgo/go/crypto/tls/conn.go530
-rw-r--r--libgo/go/crypto/tls/conn_test.go139
-rw-r--r--libgo/go/crypto/tls/handshake_client.go437
-rw-r--r--libgo/go/crypto/tls/handshake_client_test.go1001
-rw-r--r--libgo/go/crypto/tls/handshake_messages.go143
-rw-r--r--libgo/go/crypto/tls/handshake_messages_test.go63
-rw-r--r--libgo/go/crypto/tls/handshake_server.go246
-rw-r--r--libgo/go/crypto/tls/handshake_server_test.go469
-rw-r--r--libgo/go/crypto/tls/handshake_test.go71
-rw-r--r--libgo/go/crypto/tls/key_agreement.go178
-rw-r--r--libgo/go/crypto/tls/prf.go2
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA112
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA175
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA176
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA239
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES93
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES168
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4145
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES95
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES170
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4145
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256149
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA25689
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384149
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN165
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch158
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA119
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA177
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384250
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA183
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA240
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES95
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM87
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA25691
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA38487
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY130577
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES170
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA25695
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY130581
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4145
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce231
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice376
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected234
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected89
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-SCT162
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM85
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES140
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES142
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4132
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES81
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES132
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES138
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4126
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV21
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4126
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN181
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch182
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA97
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA173
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven163
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven227
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven145
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES83
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket154
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable154
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES137
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES141
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM149
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384149
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4131
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-Resume64
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled160
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-SNI131
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate131
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound131
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM79
-rw-r--r--libgo/go/crypto/tls/ticket.go6
-rw-r--r--libgo/go/crypto/tls/tls.go67
-rw-r--r--libgo/go/crypto/tls/tls_test.go427
-rw-r--r--libgo/go/crypto/x509/cert_pool.go47
-rw-r--r--libgo/go/crypto/x509/pem_decrypt.go2
-rw-r--r--libgo/go/crypto/x509/pkcs1.go11
-rw-r--r--libgo/go/crypto/x509/pkcs8.go6
-rw-r--r--libgo/go/crypto/x509/pkix/pkix.go58
-rw-r--r--libgo/go/crypto/x509/root.go9
-rw-r--r--libgo/go/crypto/x509/root_cgo_darwin.go195
-rw-r--r--libgo/go/crypto/x509/root_darwin.go225
-rw-r--r--libgo/go/crypto/x509/root_darwin_arm_gen.go7
-rw-r--r--libgo/go/crypto/x509/root_darwin_armx.go7
-rw-r--r--libgo/go/crypto/x509/root_linux.go9
-rw-r--r--libgo/go/crypto/x509/root_nocgo_darwin.go4
-rw-r--r--libgo/go/crypto/x509/root_plan9.go18
-rw-r--r--libgo/go/crypto/x509/root_unix.go23
-rw-r--r--libgo/go/crypto/x509/root_windows.go41
-rw-r--r--libgo/go/crypto/x509/sec1.go6
-rw-r--r--libgo/go/crypto/x509/verify.go96
-rw-r--r--libgo/go/crypto/x509/verify_test.go355
-rw-r--r--libgo/go/crypto/x509/x509.go276
-rw-r--r--libgo/go/crypto/x509/x509_test.go359
-rw-r--r--libgo/go/database/sql/convert.go100
-rw-r--r--libgo/go/database/sql/convert_test.go95
-rw-r--r--libgo/go/database/sql/ctxutil.go149
-rw-r--r--libgo/go/database/sql/driver/driver.go205
-rw-r--r--libgo/go/database/sql/driver/types.go63
-rw-r--r--libgo/go/database/sql/driver/types_test.go16
-rw-r--r--libgo/go/database/sql/fakedb_test.go384
-rw-r--r--libgo/go/database/sql/sql.go1083
-rw-r--r--libgo/go/database/sql/sql_test.go733
-rw-r--r--libgo/go/debug/dwarf/buf.go10
-rw-r--r--libgo/go/debug/dwarf/const.go2
-rw-r--r--libgo/go/debug/dwarf/entry.go132
-rw-r--r--libgo/go/debug/dwarf/entry_test.go101
-rw-r--r--libgo/go/debug/dwarf/line.go4
-rw-r--r--libgo/go/debug/dwarf/line_test.go2
-rw-r--r--libgo/go/debug/dwarf/open.go6
-rw-r--r--libgo/go/debug/dwarf/testdata/ranges.c25
-rw-r--r--libgo/go/debug/dwarf/testdata/ranges.elfbin0 -> 10348 bytes
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.c2
-rw-r--r--libgo/go/debug/dwarf/type.go8
-rw-r--r--libgo/go/debug/dwarf/type_test.go4
-rw-r--r--libgo/go/debug/dwarf/typeunit.go10
-rw-r--r--libgo/go/debug/dwarf/unit.go2
-rw-r--r--libgo/go/debug/elf/elf.go136
-rw-r--r--libgo/go/debug/elf/elf_test.go2
-rw-r--r--libgo/go/debug/elf/file.go149
-rw-r--r--libgo/go/debug/elf/file_test.go88
-rw-r--r--libgo/go/debug/elf/reader.go8
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mipsle.objbin0 -> 2864 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc531-s390x.objbin0 -> 3864 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc540-mips.objbin0 -> 3064 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc620-sparc64.objbin0 -> 5952 bytes
-rw-r--r--libgo/go/debug/elf/testdata/hello-world-core.gzbin12678 -> 12678 bytes
-rw-r--r--libgo/go/debug/gosym/pclntab.go13
-rw-r--r--libgo/go/debug/gosym/pclntab_test.go25
-rw-r--r--libgo/go/debug/gosym/symtab.go33
-rw-r--r--libgo/go/debug/gosym/symtab_test.go43
-rw-r--r--libgo/go/debug/macho/fat.go8
-rw-r--r--libgo/go/debug/macho/file.go8
-rw-r--r--libgo/go/debug/macho/file_test.go2
-rw-r--r--libgo/go/debug/macho/macho.go27
-rw-r--r--libgo/go/debug/pe/file.go221
-rw-r--r--libgo/go/debug/pe/file_test.go112
-rw-r--r--libgo/go/debug/pe/pe.go26
-rw-r--r--libgo/go/debug/pe/section.go111
-rw-r--r--libgo/go/debug/pe/string.go66
-rw-r--r--libgo/go/debug/pe/symbol.go98
-rw-r--r--libgo/go/debug/pe/testdata/gcc-386-mingw-no-symbols-execbin0 -> 8704 bytes
-rw-r--r--libgo/go/debug/plan9obj/file.go2
-rw-r--r--libgo/go/debug/plan9obj/file_test.go2
-rw-r--r--libgo/go/debug/plan9obj/plan9obj.go2
-rw-r--r--libgo/go/encoding/ascii85/ascii85.go6
-rw-r--r--libgo/go/encoding/asn1/asn1.go16
-rw-r--r--libgo/go/encoding/asn1/asn1_test.go45
-rw-r--r--libgo/go/encoding/asn1/marshal.go623
-rw-r--r--libgo/go/encoding/asn1/marshal_test.go34
-rw-r--r--libgo/go/encoding/base32/base32.go10
-rw-r--r--libgo/go/encoding/base32/base32_test.go2
-rw-r--r--libgo/go/encoding/base64/base64.go36
-rw-r--r--libgo/go/encoding/base64/base64_test.go68
-rw-r--r--libgo/go/encoding/binary/binary.go83
-rw-r--r--libgo/go/encoding/binary/binary_test.go80
-rw-r--r--libgo/go/encoding/binary/varint.go2
-rw-r--r--libgo/go/encoding/csv/reader.go131
-rw-r--r--libgo/go/encoding/csv/reader_test.go72
-rw-r--r--libgo/go/encoding/csv/writer.go32
-rw-r--r--libgo/go/encoding/encoding.go2
-rw-r--r--libgo/go/encoding/gob/codec_test.go6
-rw-r--r--libgo/go/encoding/gob/debug.go6
-rw-r--r--libgo/go/encoding/gob/decode.go24
-rw-r--r--libgo/go/encoding/gob/decoder.go10
-rw-r--r--libgo/go/encoding/gob/doc.go9
-rw-r--r--libgo/go/encoding/gob/encode.go20
-rw-r--r--libgo/go/encoding/gob/encoder.go9
-rw-r--r--libgo/go/encoding/gob/encoder_test.go106
-rw-r--r--libgo/go/encoding/gob/error.go4
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go8
-rw-r--r--libgo/go/encoding/gob/type.go18
-rw-r--r--libgo/go/encoding/hex/example_test.go100
-rw-r--r--libgo/go/encoding/hex/hex.go19
-rw-r--r--libgo/go/encoding/hex/hex_test.go16
-rw-r--r--libgo/go/encoding/json/bench_test.go6
-rw-r--r--libgo/go/encoding/json/decode.go197
-rw-r--r--libgo/go/encoding/json/decode_test.go650
-rw-r--r--libgo/go/encoding/json/encode.go367
-rw-r--r--libgo/go/encoding/json/encode_test.go398
-rw-r--r--libgo/go/encoding/json/example_marshaling_test.go75
-rw-r--r--libgo/go/encoding/json/indent.go2
-rw-r--r--libgo/go/encoding/json/number_test.go2
-rw-r--r--libgo/go/encoding/json/scanner.go4
-rw-r--r--libgo/go/encoding/json/scanner_test.go3
-rw-r--r--libgo/go/encoding/json/stream.go65
-rw-r--r--libgo/go/encoding/json/stream_test.go68
-rw-r--r--libgo/go/encoding/json/tables.go218
-rw-r--r--libgo/go/encoding/json/tagkey_test.go7
-rw-r--r--libgo/go/encoding/json/tags_test.go2
-rw-r--r--libgo/go/encoding/json/testdata/code.json.gzbin120432 -> 120432 bytes
-rw-r--r--libgo/go/encoding/pem/example_test.go46
-rw-r--r--libgo/go/encoding/pem/pem.go21
-rw-r--r--libgo/go/encoding/pem/pem_test.go42
-rw-r--r--libgo/go/encoding/xml/marshal.go213
-rw-r--r--libgo/go/encoding/xml/marshal_test.go638
-rw-r--r--libgo/go/encoding/xml/read.go109
-rw-r--r--libgo/go/encoding/xml/read_test.go21
-rw-r--r--libgo/go/encoding/xml/typeinfo.go10
-rw-r--r--libgo/go/encoding/xml/xml.go17
-rw-r--r--libgo/go/encoding/xml/xml_test.go42
-rw-r--r--libgo/go/errors/errors.go2
-rw-r--r--libgo/go/errors/errors_test.go2
-rw-r--r--libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.datbin115 -> 0 bytes
-rw-r--r--libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat8
-rw-r--r--libgo/go/expvar/expvar.go41
-rw-r--r--libgo/go/expvar/expvar_test.go46
-rw-r--r--libgo/go/flag/export_test.go3
-rw-r--r--libgo/go/flag/flag.go68
-rw-r--r--libgo/go/fmt/doc.go82
-rw-r--r--libgo/go/fmt/export_test.go3
-rw-r--r--libgo/go/fmt/fmt_test.go836
-rw-r--r--libgo/go/fmt/format.go593
-rw-r--r--libgo/go/fmt/print.go863
-rw-r--r--libgo/go/fmt/scan.go248
-rw-r--r--libgo/go/fmt/scan_test.go270
-rw-r--r--libgo/go/go/ast/ast.go14
-rw-r--r--libgo/go/go/ast/commentmap.go2
-rw-r--r--libgo/go/go/ast/import.go2
-rw-r--r--libgo/go/go/ast/print.go7
-rw-r--r--libgo/go/go/ast/resolve.go2
-rw-r--r--libgo/go/go/ast/scope.go4
-rw-r--r--libgo/go/go/build/build.go159
-rw-r--r--libgo/go/go/build/build_test.go26
-rw-r--r--libgo/go/go/build/deps_test.go185
-rw-r--r--libgo/go/go/build/doc.go34
-rw-r--r--libgo/go/go/build/read.go5
-rw-r--r--libgo/go/go/build/read_test.go2
-rw-r--r--libgo/go/go/build/syslist.go4
-rw-r--r--libgo/go/go/build/syslist_test.go2
-rw-r--r--libgo/go/go/constant/value.go48
-rw-r--r--libgo/go/go/constant/value_test.go1
-rw-r--r--libgo/go/go/doc/comment.go6
-rw-r--r--libgo/go/go/doc/comment_test.go1
-rw-r--r--libgo/go/go/doc/doc_test.go5
-rw-r--r--libgo/go/go/doc/example.go30
-rw-r--r--libgo/go/go/doc/reader.go24
-rw-r--r--libgo/go/go/doc/testdata/benchmark.go8
-rw-r--r--libgo/go/go/doc/testdata/issue17788.0.golden8
-rw-r--r--libgo/go/go/doc/testdata/issue17788.1.golden8
-rw-r--r--libgo/go/go/doc/testdata/issue17788.2.golden8
-rw-r--r--libgo/go/go/doc/testdata/issue17788.go8
-rw-r--r--libgo/go/go/doc/testdata/predeclared.0.golden8
-rw-r--r--libgo/go/go/doc/testdata/predeclared.1.golden22
-rw-r--r--libgo/go/go/doc/testdata/predeclared.2.golden8
-rw-r--r--libgo/go/go/doc/testdata/predeclared.go22
-rw-r--r--libgo/go/go/doc/testdata/testing.0.golden4
-rw-r--r--libgo/go/go/doc/testdata/testing.1.golden10
-rw-r--r--libgo/go/go/doc/testdata/testing.2.golden4
-rw-r--r--libgo/go/go/doc/testdata/testing.go10
-rw-r--r--libgo/go/go/format/format_test.go27
-rw-r--r--libgo/go/go/format/internal.go6
-rw-r--r--libgo/go/go/importer/importer.go2
-rw-r--r--libgo/go/go/internal/gccgoimporter/importer.go13
-rw-r--r--libgo/go/go/internal/gccgoimporter/importer_test.go8
-rw-r--r--libgo/go/go/internal/gccgoimporter/parser.go54
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/complexnums.gox8
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/conversions.go5
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/conversions.gox6
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/imports.gox7
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/pointer.gox4
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/time.goxbin0 -> 7977 bytes
-rw-r--r--libgo/go/go/internal/gccgoimporter/testdata/unicode.goxbin0 -> 7945 bytes
-rw-r--r--libgo/go/go/internal/gcimporter/bimport.go588
-rw-r--r--libgo/go/go/internal/gcimporter/exportdata.go36
-rw-r--r--libgo/go/go/internal/gcimporter/gcimporter.go881
-rw-r--r--libgo/go/go/internal/gcimporter/gcimporter_test.go153
-rw-r--r--libgo/go/go/internal/gcimporter/testdata/exports.go7
-rw-r--r--libgo/go/go/internal/gcimporter/testdata/issue15920.go11
-rw-r--r--libgo/go/go/internal/gcimporter/testdata/p.go13
-rw-r--r--libgo/go/go/internal/gcimporter/testdata/versions/test.go25
-rw-r--r--libgo/go/go/parser/interface.go18
-rw-r--r--libgo/go/go/parser/parser.go26
-rw-r--r--libgo/go/go/parser/performance_test.go13
-rw-r--r--libgo/go/go/printer/nodes.go17
-rw-r--r--libgo/go/go/printer/printer.go43
-rw-r--r--libgo/go/go/printer/printer_test.go55
-rw-r--r--libgo/go/go/printer/testdata/comments.golden26
-rw-r--r--libgo/go/go/printer/testdata/comments.input18
-rw-r--r--libgo/go/go/printer/testdata/comments2.golden59
-rw-r--r--libgo/go/go/printer/testdata/comments2.input63
-rw-r--r--libgo/go/go/scanner/scanner.go14
-rw-r--r--libgo/go/go/scanner/scanner_test.go1
-rw-r--r--libgo/go/go/token/position.go3
-rw-r--r--libgo/go/go/token/position_test.go31
-rw-r--r--libgo/go/go/types/api.go15
-rw-r--r--libgo/go/go/types/api_test.go435
-rw-r--r--libgo/go/go/types/assignments.go12
-rw-r--r--libgo/go/go/types/builtins.go8
-rw-r--r--libgo/go/go/types/call.go36
-rw-r--r--libgo/go/go/types/check.go5
-rw-r--r--libgo/go/go/types/check_test.go2
-rw-r--r--libgo/go/go/types/conversions.go11
-rw-r--r--libgo/go/go/types/decl.go123
-rw-r--r--libgo/go/go/types/eval.go4
-rw-r--r--libgo/go/go/types/expr.go47
-rw-r--r--libgo/go/go/types/hilbert_test.go13
-rw-r--r--libgo/go/go/types/initorder.go253
-rw-r--r--libgo/go/go/types/labels.go2
-rw-r--r--libgo/go/go/types/object.go55
-rw-r--r--libgo/go/go/types/ordering.go20
-rw-r--r--libgo/go/go/types/package.go2
-rw-r--r--libgo/go/go/types/predicates.go37
-rw-r--r--libgo/go/go/types/resolver.go26
-rw-r--r--libgo/go/go/types/return.go9
-rw-r--r--libgo/go/go/types/scope.go2
-rw-r--r--libgo/go/go/types/sizes.go51
-rw-r--r--libgo/go/go/types/sizes_test.go119
-rw-r--r--libgo/go/go/types/stdlib_test.go20
-rw-r--r--libgo/go/go/types/stmt.go48
-rw-r--r--libgo/go/go/types/testdata/blank.src5
-rw-r--r--libgo/go/go/types/testdata/builtins.src901
-rw-r--r--libgo/go/go/types/testdata/const0.src295
-rw-r--r--libgo/go/go/types/testdata/const1.src322
-rw-r--r--libgo/go/go/types/testdata/constdecl.src97
-rw-r--r--libgo/go/go/types/testdata/conversions.src93
-rw-r--r--libgo/go/go/types/testdata/conversions2.src313
-rw-r--r--libgo/go/go/types/testdata/cycles.src143
-rw-r--r--libgo/go/go/types/testdata/cycles1.src77
-rw-r--r--libgo/go/go/types/testdata/cycles2.src118
-rw-r--r--libgo/go/go/types/testdata/cycles3.src60
-rw-r--r--libgo/go/go/types/testdata/cycles4.src110
-rw-r--r--libgo/go/go/types/testdata/decls0.src210
-rw-r--r--libgo/go/go/types/testdata/decls1.src144
-rw-r--r--libgo/go/go/types/testdata/decls2a.src111
-rw-r--r--libgo/go/go/types/testdata/decls2b.src65
-rw-r--r--libgo/go/go/types/testdata/decls3.src309
-rw-r--r--libgo/go/go/types/testdata/errors.src55
-rw-r--r--libgo/go/go/types/testdata/expr0.src180
-rw-r--r--libgo/go/go/types/testdata/expr1.src127
-rw-r--r--libgo/go/go/types/testdata/expr2.src247
-rw-r--r--libgo/go/go/types/testdata/expr3.src558
-rw-r--r--libgo/go/go/types/testdata/gotos.src560
-rw-r--r--libgo/go/go/types/testdata/importC.src10
-rw-r--r--libgo/go/go/types/testdata/importdecl0a.src53
-rw-r--r--libgo/go/go/types/testdata/importdecl0b.src33
-rw-r--r--libgo/go/go/types/testdata/importdecl1a.src11
-rw-r--r--libgo/go/go/types/testdata/importdecl1b.src7
-rw-r--r--libgo/go/go/types/testdata/init0.src106
-rw-r--r--libgo/go/go/types/testdata/init1.src97
-rw-r--r--libgo/go/go/types/testdata/init2.src139
-rw-r--r--libgo/go/go/types/testdata/issues.src188
-rw-r--r--libgo/go/go/types/testdata/labels.src207
-rw-r--r--libgo/go/go/types/testdata/methodsets.src214
-rw-r--r--libgo/go/go/types/testdata/shifts.src341
-rw-r--r--libgo/go/go/types/testdata/stmt0.src980
-rw-r--r--libgo/go/go/types/testdata/stmt1.src241
-rw-r--r--libgo/go/go/types/testdata/vardecl.src186
-rw-r--r--libgo/go/go/types/type.go13
-rw-r--r--libgo/go/go/types/typexpr.go25
-rw-r--r--libgo/go/go/types/universe.go2
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go83
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go80
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go70
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go15
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go182
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go332
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go199
-rw-r--r--libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go29
-rw-r--r--libgo/go/golang_org/x/crypto/curve25519/curve25519.go841
-rw-r--r--libgo/go/golang_org/x/crypto/curve25519/curve25519_test.go29
-rw-r--r--libgo/go/golang_org/x/crypto/curve25519/doc.go23
-rw-r--r--libgo/go/golang_org/x/crypto/curve25519/mont25519_amd64.go240
-rw-r--r--libgo/go/golang_org/x/crypto/poly1305/poly1305.go32
-rw-r--r--libgo/go/golang_org/x/crypto/poly1305/poly1305_test.go92
-rw-r--r--libgo/go/golang_org/x/crypto/poly1305/sum_amd64.go22
-rw-r--r--libgo/go/golang_org/x/crypto/poly1305/sum_arm.go22
-rw-r--r--libgo/go/golang_org/x/crypto/poly1305/sum_ref.go1531
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/encode.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/encode.go)2
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/encode_test.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go)0
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/hpack.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go)15
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/hpack_test.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go)41
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/huffman.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go)42
-rw-r--r--libgo/go/golang_org/x/net/http2/hpack/tables.go (renamed from libgo/go/internal/golang.org/x/net/http2/hpack/tables.go)0
-rw-r--r--libgo/go/golang_org/x/net/idna/idna.go68
-rw-r--r--libgo/go/golang_org/x/net/idna/idna_test.go43
-rw-r--r--libgo/go/golang_org/x/net/idna/punycode.go200
-rw-r--r--libgo/go/golang_org/x/net/idna/punycode_test.go198
-rw-r--r--libgo/go/golang_org/x/net/lex/httplex/httplex.go351
-rw-r--r--libgo/go/golang_org/x/net/lex/httplex/httplex_test.go (renamed from libgo/go/net/http/lex_test.go)24
-rw-r--r--libgo/go/golang_org/x/net/lif/address.go105
-rw-r--r--libgo/go/golang_org/x/net/lif/address_test.go121
-rw-r--r--libgo/go/golang_org/x/net/lif/binary.go68
-rw-r--r--libgo/go/golang_org/x/net/lif/defs_solaris.go90
-rw-r--r--libgo/go/golang_org/x/net/lif/lif.go43
-rw-r--r--libgo/go/golang_org/x/net/lif/link.go122
-rw-r--r--libgo/go/golang_org/x/net/lif/link_test.go61
-rw-r--r--libgo/go/golang_org/x/net/lif/syscall.go22
-rw-r--r--libgo/go/golang_org/x/net/lif/zsys_solaris.go98
-rw-r--r--libgo/go/golang_org/x/net/route/address.go281
-rw-r--r--libgo/go/golang_org/x/net/route/address_darwin_test.go63
-rw-r--r--libgo/go/golang_org/x/net/route/address_test.go103
-rw-r--r--libgo/go/golang_org/x/net/route/binary.go90
-rw-r--r--libgo/go/golang_org/x/net/route/defs_darwin.go106
-rw-r--r--libgo/go/golang_org/x/net/route/defs_dragonfly.go105
-rw-r--r--libgo/go/golang_org/x/net/route/defs_freebsd.go329
-rw-r--r--libgo/go/golang_org/x/net/route/defs_netbsd.go104
-rw-r--r--libgo/go/golang_org/x/net/route/defs_openbsd.go93
-rw-r--r--libgo/go/golang_org/x/net/route/interface.go64
-rw-r--r--libgo/go/golang_org/x/net/route/interface_announce.go32
-rw-r--r--libgo/go/golang_org/x/net/route/interface_classic.go66
-rw-r--r--libgo/go/golang_org/x/net/route/interface_freebsd.go78
-rw-r--r--libgo/go/golang_org/x/net/route/interface_multicast.go30
-rw-r--r--libgo/go/golang_org/x/net/route/interface_openbsd.go90
-rw-r--r--libgo/go/golang_org/x/net/route/message.go76
-rw-r--r--libgo/go/golang_org/x/net/route/message_darwin_test.go27
-rw-r--r--libgo/go/golang_org/x/net/route/message_freebsd_test.go106
-rw-r--r--libgo/go/golang_org/x/net/route/message_test.go118
-rw-r--r--libgo/go/golang_org/x/net/route/route.go74
-rw-r--r--libgo/go/golang_org/x/net/route/route_classic.go31
-rw-r--r--libgo/go/golang_org/x/net/route/route_openbsd.go32
-rw-r--r--libgo/go/golang_org/x/net/route/route_test.go386
-rw-r--r--libgo/go/golang_org/x/net/route/sys.go40
-rw-r--r--libgo/go/golang_org/x/net/route/sys_darwin.go80
-rw-r--r--libgo/go/golang_org/x/net/route/sys_dragonfly.go71
-rw-r--r--libgo/go/golang_org/x/net/route/sys_freebsd.go150
-rw-r--r--libgo/go/golang_org/x/net/route/sys_netbsd.go67
-rw-r--r--libgo/go/golang_org/x/net/route/sys_openbsd.go72
-rw-r--r--libgo/go/golang_org/x/net/route/syscall.go33
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_darwin.go93
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_dragonfly.go92
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_freebsd_386.go120
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_freebsd_amd64.go117
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_freebsd_arm.go117
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_netbsd.go91
-rw-r--r--libgo/go/golang_org/x/net/route/zsys_openbsd.go80
-rw-r--r--libgo/go/golang_org/x/text/transform/transform.go705
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/composition.go514
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/forminfo.go256
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/input.go105
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/iter.go450
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/normalize.go608
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/readwriter.go125
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/tables.go7627
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/transform.go88
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/trie.go54
-rw-r--r--libgo/go/golang_org/x/text/unicode/norm/triegen.go117
-rw-r--r--libgo/go/golang_org/x/text/width/kind_string.go16
-rw-r--r--libgo/go/golang_org/x/text/width/tables.go1284
-rw-r--r--libgo/go/golang_org/x/text/width/transform.go239
-rw-r--r--libgo/go/golang_org/x/text/width/trieval.go30
-rw-r--r--libgo/go/golang_org/x/text/width/width.go206
-rw-r--r--libgo/go/hash/adler32/adler32.go13
-rw-r--r--libgo/go/hash/crc32/crc32.go154
-rw-r--r--libgo/go/hash/crc32/crc32_amd64.go214
-rw-r--r--libgo/go/hash/crc32/crc32_amd64p32.go33
-rw-r--r--libgo/go/hash/crc32/crc32_generic.go90
-rw-r--r--libgo/go/hash/crc32/crc32_otherarch.go15
-rw-r--r--libgo/go/hash/crc32/crc32_s390x.go91
-rw-r--r--libgo/go/hash/crc32/crc32_test.go252
-rw-r--r--libgo/go/hash/crc64/crc64.go58
-rw-r--r--libgo/go/hash/crc64/crc64_test.go114
-rw-r--r--libgo/go/html/escape.go6
-rw-r--r--libgo/go/html/template/clone_test.go68
-rw-r--r--libgo/go/html/template/content.go29
-rw-r--r--libgo/go/html/template/content_test.go41
-rw-r--r--libgo/go/html/template/context.go14
-rw-r--r--libgo/go/html/template/css.go4
-rw-r--r--libgo/go/html/template/doc.go4
-rw-r--r--libgo/go/html/template/error.go4
-rw-r--r--libgo/go/html/template/escape.go110
-rw-r--r--libgo/go/html/template/escape_test.go16
-rw-r--r--libgo/go/html/template/examplefiles_test.go228
-rw-r--r--libgo/go/html/template/js.go44
-rw-r--r--libgo/go/html/template/js_test.go19
-rw-r--r--libgo/go/html/template/template.go95
-rw-r--r--libgo/go/html/template/template_test.go132
-rw-r--r--libgo/go/html/template/transition.go30
-rw-r--r--libgo/go/html/template/url.go4
-rw-r--r--libgo/go/image/color/color.go25
-rw-r--r--libgo/go/image/color/palette/gen.go2
-rw-r--r--libgo/go/image/color/palette/palette.go2
-rw-r--r--libgo/go/image/color/ycbcr.go204
-rw-r--r--libgo/go/image/color/ycbcr_test.go93
-rw-r--r--libgo/go/image/decode_test.go1
-rw-r--r--libgo/go/image/draw/bench_test.go2
-rw-r--r--libgo/go/image/draw/draw.go26
-rw-r--r--libgo/go/image/draw/example_test.go50
-rw-r--r--libgo/go/image/gif/reader.go110
-rw-r--r--libgo/go/image/gif/reader_test.go97
-rw-r--r--libgo/go/image/internal/imageutil/gen.go59
-rw-r--r--libgo/go/image/internal/imageutil/impl.go232
-rw-r--r--libgo/go/image/jpeg/reader.go6
-rw-r--r--libgo/go/image/jpeg/scan.go128
-rw-r--r--libgo/go/image/png/example_test.go79
-rw-r--r--libgo/go/image/png/reader.go278
-rw-r--r--libgo/go/image/png/reader_test.go212
-rw-r--r--libgo/go/image/png/testdata/pngsuite/README21
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g01.pngbin0 -> 176 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g01.sng44
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g02.pngbin0 -> 197 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g02.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g04.pngbin0 -> 429 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn0g04.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn2c16.pngbin0 -> 2041 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn2c16.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn3p08.pngbin0 -> 1499 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbbn3p08.sng292
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbgn2c16.pngbin0 -> 2041 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbgn2c16.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbgn3p08.pngbin0 -> 1499 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbgn3p08.sng292
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbrn2c08.pngbin0 -> 1633 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbrn2c08.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbwn0g16.pngbin0 -> 1313 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbwn0g16.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbwn3p08.pngbin0 -> 1496 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbwn3p08.sng291
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbyn3p08.pngbin0 -> 1499 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftbyn3p08.sng292
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n0g08.pngbin0 -> 719 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n0g08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n2c08.pngbin0 -> 1594 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n2c08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n3p08.pngbin0 -> 1476 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp0n3p08.sng288
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp1n3p08.pngbin0 -> 1483 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/ftp1n3p08.sng290
-rw-r--r--libgo/go/image/png/writer.go5
-rw-r--r--libgo/go/image/testdata/video-001.progressive.truncated.jpegbin0 -> 7456 bytes
-rw-r--r--libgo/go/image/testdata/video-001.progressive.truncated.pngbin0 -> 23616 bytes
-rw-r--r--libgo/go/index/suffixarray/example_test.go24
-rw-r--r--libgo/go/internal/nettrace/nettrace.go45
-rw-r--r--libgo/go/internal/pprof/profile/encode.go470
-rw-r--r--libgo/go/internal/pprof/profile/filter.go158
-rw-r--r--libgo/go/internal/pprof/profile/legacy_profile.go1266
-rw-r--r--libgo/go/internal/pprof/profile/profile.go572
-rw-r--r--libgo/go/internal/pprof/profile/profile_test.go79
-rw-r--r--libgo/go/internal/pprof/profile/proto.go360
-rw-r--r--libgo/go/internal/pprof/profile/proto_test.go67
-rw-r--r--libgo/go/internal/pprof/profile/prune.go97
-rw-r--r--libgo/go/internal/race/doc.go2
-rw-r--r--libgo/go/internal/race/norace.go4
-rw-r--r--libgo/go/internal/race/race.go6
-rw-r--r--libgo/go/internal/singleflight/singleflight.go2
-rw-r--r--libgo/go/internal/singleflight/singleflight_test.go2
-rw-r--r--libgo/go/internal/syscall/unix/getentropy_openbsd.go25
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux.go2
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_386.go4
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_alpha.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_amd64.go4
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_arm.go4
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_generic.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_ia64.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_m68k.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go6
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_mipsn32.go11
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_mipso32.go11
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_mipsx.go11
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go6
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_s390.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_s390x.go9
-rw-r--r--libgo/go/internal/syscall/unix/getrandom_linux_sparcx.go11
-rw-r--r--libgo/go/internal/syscall/windows/mksyscall.go7
-rw-r--r--libgo/go/internal/syscall/windows/registry/mksyscall.go7
-rw-r--r--libgo/go/internal/syscall/windows/registry/registry_test.go4
-rw-r--r--libgo/go/internal/syscall/windows/registry/syscall.go2
-rw-r--r--libgo/go/internal/syscall/windows/registry/zsyscall_windows.go35
-rw-r--r--libgo/go/internal/syscall/windows/reparse_windows.go64
-rw-r--r--libgo/go/internal/syscall/windows/security_windows.go57
-rw-r--r--libgo/go/internal/syscall/windows/syscall_windows.go28
-rw-r--r--libgo/go/internal/syscall/windows/zsyscall_windows.go182
-rw-r--r--libgo/go/internal/testenv/testenv.go94
-rw-r--r--libgo/go/internal/testenv/testenv_cgo.go11
-rw-r--r--libgo/go/internal/testenv/testenv_notwin.go20
-rw-r--r--libgo/go/internal/testenv/testenv_windows.go49
-rw-r--r--libgo/go/internal/trace/goroutines.go6
-rw-r--r--libgo/go/internal/trace/mkcanned.bash19
-rw-r--r--libgo/go/internal/trace/order.go279
-rw-r--r--libgo/go/internal/trace/parser.go537
-rw-r--r--libgo/go/internal/trace/parser_test.go76
-rw-r--r--libgo/go/internal/trace/testdata/http_1_5_goodbin0 -> 42218 bytes
-rw-r--r--libgo/go/internal/trace/testdata/http_1_7_goodbin0 -> 1971 bytes
-rw-r--r--libgo/go/internal/trace/testdata/stress_1_5_goodbin0 -> 7446 bytes
-rw-r--r--libgo/go/internal/trace/testdata/stress_1_5_unorderedbin0 -> 8194 bytes
-rw-r--r--libgo/go/internal/trace/testdata/stress_1_7_goodbin0 -> 396526 bytes
-rw-r--r--libgo/go/internal/trace/testdata/stress_start_stop_1_5_goodbin0 -> 6997 bytes
-rw-r--r--libgo/go/internal/trace/testdata/stress_start_stop_1_7_goodbin0 -> 2055 bytes
-rw-r--r--libgo/go/internal/trace/writer.go45
-rw-r--r--libgo/go/io/example_test.go2
-rw-r--r--libgo/go/io/io.go56
-rw-r--r--libgo/go/io/io_test.go4
-rw-r--r--libgo/go/io/ioutil/ioutil.go13
-rw-r--r--libgo/go/io/ioutil/tempfile.go15
-rw-r--r--libgo/go/io/ioutil/tempfile_test.go16
-rw-r--r--libgo/go/io/multi.go27
-rw-r--r--libgo/go/io/multi_test.go130
-rw-r--r--libgo/go/io/pipe.go24
-rw-r--r--libgo/go/io/pipe_test.go12
-rw-r--r--libgo/go/log/log.go20
-rw-r--r--libgo/go/log/syslog/doc.go2
-rw-r--r--libgo/go/log/syslog/example_test.go24
-rw-r--r--libgo/go/log/syslog/syslog.go44
-rw-r--r--libgo/go/log/syslog/syslog_libc.go2
-rw-r--r--libgo/go/log/syslog/syslog_test.go5
-rw-r--r--libgo/go/log/syslog/syslog_unix.go2
-rw-r--r--libgo/go/math/acosh.go2
-rw-r--r--libgo/go/math/all_test.go152
-rw-r--r--libgo/go/math/arith_s390x.go31
-rw-r--r--libgo/go/math/arith_s390x_test.go146
-rw-r--r--libgo/go/math/asinh.go2
-rw-r--r--libgo/go/math/atanh.go2
-rw-r--r--libgo/go/math/big/arith_decl.go3
-rw-r--r--libgo/go/math/big/arith_decl_pure.go4
-rw-r--r--libgo/go/math/big/arith_decl_s390x.go24
-rw-r--r--libgo/go/math/big/arith_s390x_test.go45
-rw-r--r--libgo/go/math/big/arith_test.go149
-rw-r--r--libgo/go/math/big/decimal.go7
-rw-r--r--libgo/go/math/big/decimal_test.go22
-rw-r--r--libgo/go/math/big/doc.go2
-rw-r--r--libgo/go/math/big/float.go318
-rw-r--r--libgo/go/math/big/float_test.go127
-rw-r--r--libgo/go/math/big/floatconv.go26
-rw-r--r--libgo/go/math/big/floatconv_test.go57
-rw-r--r--libgo/go/math/big/floatexample_test.go6
-rw-r--r--libgo/go/math/big/floatmarsh.go89
-rw-r--r--libgo/go/math/big/floatmarsh_test.go82
-rw-r--r--libgo/go/math/big/ftoa.go24
-rw-r--r--libgo/go/math/big/gcd_test.go19
-rw-r--r--libgo/go/math/big/int.go48
-rw-r--r--libgo/go/math/big/int_test.go173
-rw-r--r--libgo/go/math/big/intconv.go22
-rw-r--r--libgo/go/math/big/intmarsh.go6
-rw-r--r--libgo/go/math/big/nat.go185
-rw-r--r--libgo/go/math/big/nat_test.go27
-rw-r--r--libgo/go/math/big/natconv.go4
-rw-r--r--libgo/go/math/big/natconv_test.go139
-rw-r--r--libgo/go/math/big/prime.go320
-rw-r--r--libgo/go/math/big/prime_test.go214
-rw-r--r--libgo/go/math/big/rat.go4
-rw-r--r--libgo/go/math/big/rat_test.go12
-rw-r--r--libgo/go/math/big/ratconv.go28
-rw-r--r--libgo/go/math/big/ratconv_test.go14
-rw-r--r--libgo/go/math/cmplx/cmath_test.go15
-rw-r--r--libgo/go/math/cmplx/example_test.go30
-rw-r--r--libgo/go/math/cmplx/sqrt.go2
-rw-r--r--libgo/go/math/cmplx/tan.go12
-rw-r--r--libgo/go/math/erf.go2
-rw-r--r--libgo/go/math/exp.go2
-rw-r--r--libgo/go/math/expm1.go4
-rw-r--r--libgo/go/math/export_s390x_test.go16
-rw-r--r--libgo/go/math/export_test.go2
-rw-r--r--libgo/go/math/floor_asm.go3
-rw-r--r--libgo/go/math/gamma.go45
-rw-r--r--libgo/go/math/j0.go40
-rw-r--r--libgo/go/math/j1.go40
-rw-r--r--libgo/go/math/jn.go4
-rw-r--r--libgo/go/math/lgamma.go2
-rw-r--r--libgo/go/math/log.go2
-rw-r--r--libgo/go/math/log1p.go9
-rw-r--r--libgo/go/math/modf.go2
-rw-r--r--libgo/go/math/rand/gen_cooked.go89
-rw-r--r--libgo/go/math/rand/race_test.go48
-rw-r--r--libgo/go/math/rand/rand.go109
-rw-r--r--libgo/go/math/rand/rand_test.go55
-rw-r--r--libgo/go/math/rand/regress_test.go60
-rw-r--r--libgo/go/math/rand/rng.go295
-rw-r--r--libgo/go/math/remainder.go2
-rw-r--r--libgo/go/math/sin.go8
-rw-r--r--libgo/go/math/sincos.go4
-rw-r--r--libgo/go/math/sqrt.go8
-rw-r--r--libgo/go/math/tan.go4
-rw-r--r--libgo/go/mime/encodedword.go8
-rw-r--r--libgo/go/mime/encodedword_test.go37
-rw-r--r--libgo/go/mime/grammar.go2
-rw-r--r--libgo/go/mime/mediatype.go41
-rw-r--r--libgo/go/mime/mediatype_test.go14
-rw-r--r--libgo/go/mime/multipart/formdata.go10
-rw-r--r--libgo/go/mime/multipart/formdata_test.go36
-rw-r--r--libgo/go/mime/multipart/multipart.go243
-rw-r--r--libgo/go/mime/multipart/multipart_test.go73
-rw-r--r--libgo/go/mime/multipart/writer.go13
-rw-r--r--libgo/go/mime/multipart/writer_test.go30
-rw-r--r--libgo/go/mime/quotedprintable/example_test.go39
-rw-r--r--libgo/go/mime/quotedprintable/reader.go13
-rw-r--r--libgo/go/mime/quotedprintable/reader_test.go16
-rw-r--r--libgo/go/mime/testdata/test.types.plan98
-rw-r--r--libgo/go/mime/type_plan9.go2
-rw-r--r--libgo/go/net/addrselect.go51
-rw-r--r--libgo/go/net/addrselect_test.go85
-rw-r--r--libgo/go/net/cgo_android.go2
-rw-r--r--libgo/go/net/cgo_bsd.go2
-rw-r--r--libgo/go/net/cgo_linux.go2
-rw-r--r--libgo/go/net/cgo_netbsd.go2
-rw-r--r--libgo/go/net/cgo_openbsd.go2
-rw-r--r--libgo/go/net/cgo_solaris.go2
-rw-r--r--libgo/go/net/cgo_stub.go14
-rw-r--r--libgo/go/net/cgo_unix.go148
-rw-r--r--libgo/go/net/cgo_unix_test.go66
-rw-r--r--libgo/go/net/conf.go57
-rw-r--r--libgo/go/net/conf_netcgo.go2
-rw-r--r--libgo/go/net/conf_test.go132
-rw-r--r--libgo/go/net/conn_test.go4
-rw-r--r--libgo/go/net/dial.go398
-rw-r--r--libgo/go/net/dial_gen.go40
-rw-r--r--libgo/go/net/dial_test.go487
-rw-r--r--libgo/go/net/dial_unix_test.go108
-rw-r--r--libgo/go/net/dnsclient.go20
-rw-r--r--libgo/go/net/dnsclient_unix.go288
-rw-r--r--libgo/go/net/dnsclient_unix_test.go430
-rw-r--r--libgo/go/net/dnsconfig_unix.go101
-rw-r--r--libgo/go/net/dnsconfig_unix_test.go165
-rw-r--r--libgo/go/net/dnsmsg.go166
-rw-r--r--libgo/go/net/dnsmsg_test.go219
-rw-r--r--libgo/go/net/dnsname_test.go29
-rw-r--r--libgo/go/net/error_plan9_test.go2
-rw-r--r--libgo/go/net/error_posix_test.go10
-rw-r--r--libgo/go/net/error_test.go92
-rw-r--r--libgo/go/net/error_unix_test.go34
-rw-r--r--libgo/go/net/error_windows_test.go19
-rw-r--r--libgo/go/net/external_test.go11
-rw-r--r--libgo/go/net/fd_io_plan9.go93
-rw-r--r--libgo/go/net/fd_mutex.go101
-rw-r--r--libgo/go/net/fd_mutex_test.go72
-rw-r--r--libgo/go/net/fd_plan9.go220
-rw-r--r--libgo/go/net/fd_poll_nacl.go28
-rw-r--r--libgo/go/net/fd_poll_runtime.go46
-rw-r--r--libgo/go/net/fd_select.go182
-rw-r--r--libgo/go/net/fd_unix.go184
-rw-r--r--libgo/go/net/fd_windows.go202
-rw-r--r--libgo/go/net/file.go3
-rw-r--r--libgo/go/net/file_plan9.go6
-rw-r--r--libgo/go/net/hook.go16
-rw-r--r--libgo/go/net/hook_unix.go3
-rw-r--r--libgo/go/net/hook_windows.go11
-rw-r--r--libgo/go/net/hosts.go8
-rw-r--r--libgo/go/net/hosts_test.go62
-rw-r--r--libgo/go/net/http/cgi/host.go16
-rw-r--r--libgo/go/net/http/cgi/host_test.go55
-rw-r--r--libgo/go/net/http/cgi/testdata/test.cgi4
-rw-r--r--libgo/go/net/http/client.go570
-rw-r--r--libgo/go/net/http/client_test.go777
-rw-r--r--libgo/go/net/http/clientserver_test.go343
-rw-r--r--libgo/go/net/http/cookie.go68
-rw-r--r--libgo/go/net/http/cookie_test.go100
-rw-r--r--libgo/go/net/http/cookiejar/dummy_publicsuffix_test.go23
-rw-r--r--libgo/go/net/http/cookiejar/example_test.go67
-rw-r--r--libgo/go/net/http/cookiejar/jar.go33
-rw-r--r--libgo/go/net/http/cookiejar/punycode.go2
-rw-r--r--libgo/go/net/http/doc.go30
-rw-r--r--libgo/go/net/http/export_test.go103
-rw-r--r--libgo/go/net/http/fcgi/fcgi.go13
-rw-r--r--libgo/go/net/http/filetransport.go2
-rw-r--r--libgo/go/net/http/fs.go368
-rw-r--r--libgo/go/net/http/fs_test.go187
-rw-r--r--libgo/go/net/http/h2_bundle.go4117
-rw-r--r--libgo/go/net/http/header.go16
-rw-r--r--libgo/go/net/http/header_test.go2
-rw-r--r--libgo/go/net/http/http.go141
-rw-r--r--libgo/go/net/http/http_test.go55
-rw-r--r--libgo/go/net/http/httptest/httptest.go91
-rw-r--r--libgo/go/net/http/httptest/httptest_test.go177
-rw-r--r--libgo/go/net/http/httptest/recorder.go156
-rw-r--r--libgo/go/net/http/httptest/recorder_test.go140
-rw-r--r--libgo/go/net/http/httptest/server.go45
-rw-r--r--libgo/go/net/http/httptest/server_test.go4
-rw-r--r--libgo/go/net/http/httptrace/example_test.go31
-rw-r--r--libgo/go/net/http/httptrace/trace.go243
-rw-r--r--libgo/go/net/http/httptrace/trace_test.go89
-rw-r--r--libgo/go/net/http/httputil/dump.go55
-rw-r--r--libgo/go/net/http/httputil/dump_test.go73
-rw-r--r--libgo/go/net/http/httputil/example_test.go2
-rw-r--r--libgo/go/net/http/httputil/persist.go182
-rw-r--r--libgo/go/net/http/httputil/reverseproxy.go167
-rw-r--r--libgo/go/net/http/httputil/reverseproxy_test.go242
-rw-r--r--libgo/go/net/http/internal/chunked.go30
-rw-r--r--libgo/go/net/http/internal/chunked_test.go29
-rw-r--r--libgo/go/net/http/lex.go183
-rw-r--r--libgo/go/net/http/main_test.go42
-rw-r--r--libgo/go/net/http/method.go2
-rw-r--r--libgo/go/net/http/npn_test.go1
-rw-r--r--libgo/go/net/http/pprof/pprof.go39
-rw-r--r--libgo/go/net/http/range_test.go2
-rw-r--r--libgo/go/net/http/readrequest_test.go47
-rw-r--r--libgo/go/net/http/request.go471
-rw-r--r--libgo/go/net/http/request_test.go301
-rw-r--r--libgo/go/net/http/requestwrite_test.go300
-rw-r--r--libgo/go/net/http/response.go44
-rw-r--r--libgo/go/net/http/response_test.go70
-rw-r--r--libgo/go/net/http/responsewrite_test.go52
-rw-r--r--libgo/go/net/http/serve_test.go1163
-rw-r--r--libgo/go/net/http/server.go1046
-rw-r--r--libgo/go/net/http/sniff.go43
-rw-r--r--libgo/go/net/http/sniff_test.go13
-rw-r--r--libgo/go/net/http/status.go122
-rw-r--r--libgo/go/net/http/transfer.go256
-rw-r--r--libgo/go/net/http/transport.go1099
-rw-r--r--libgo/go/net/http/transport_internal_test.go141
-rw-r--r--libgo/go/net/http/transport_test.go1102
-rw-r--r--libgo/go/net/interface.go112
-rw-r--r--libgo/go/net/interface_bsd.go173
-rw-r--r--libgo/go/net/interface_bsdvar.go28
-rw-r--r--libgo/go/net/interface_darwin.go69
-rw-r--r--libgo/go/net/interface_dragonfly.go12
-rw-r--r--libgo/go/net/interface_freebsd.go74
-rw-r--r--libgo/go/net/interface_linux.go6
-rw-r--r--libgo/go/net/interface_netbsd.go12
-rw-r--r--libgo/go/net/interface_openbsd.go12
-rw-r--r--libgo/go/net/interface_plan9.go198
-rw-r--r--libgo/go/net/interface_solaris.go107
-rw-r--r--libgo/go/net/interface_stub.go8
-rw-r--r--libgo/go/net/interface_test.go297
-rw-r--r--libgo/go/net/interface_windows.go6
-rw-r--r--libgo/go/net/internal/socktest/switch.go2
-rw-r--r--libgo/go/net/internal/socktest/sys_windows.go30
-rw-r--r--libgo/go/net/ip.go151
-rw-r--r--libgo/go/net/ip_test.go151
-rw-r--r--libgo/go/net/iprawsock.go159
-rw-r--r--libgo/go/net/iprawsock_plan9.go76
-rw-r--r--libgo/go/net/iprawsock_posix.go163
-rw-r--r--libgo/go/net/iprawsock_test.go (renamed from libgo/go/net/ipraw_test.go)29
-rw-r--r--libgo/go/net/ipsock.go129
-rw-r--r--libgo/go/net/ipsock_plan9.go136
-rw-r--r--libgo/go/net/ipsock_posix.go78
-rw-r--r--libgo/go/net/ipsock_test.go14
-rw-r--r--libgo/go/net/listen_test.go35
-rw-r--r--libgo/go/net/lookup.go315
-rw-r--r--libgo/go/net/lookup_nacl.go52
-rw-r--r--libgo/go/net/lookup_plan9.go81
-rw-r--r--libgo/go/net/lookup_stub.go49
-rw-r--r--libgo/go/net/lookup_test.go267
-rw-r--r--libgo/go/net/lookup_unix.go80
-rw-r--r--libgo/go/net/lookup_windows.go232
-rw-r--r--libgo/go/net/mac.go2
-rw-r--r--libgo/go/net/mac_test.go2
-rw-r--r--libgo/go/net/mail/message.go202
-rw-r--r--libgo/go/net/mail/message_test.go97
-rw-r--r--libgo/go/net/main_conf_test.go38
-rw-r--r--libgo/go/net/main_noconf_test.go (renamed from libgo/go/net/non_unix_test.go)6
-rw-r--r--libgo/go/net/main_plan9_test.go1
-rw-r--r--libgo/go/net/main_test.go4
-rw-r--r--libgo/go/net/main_unix_test.go1
-rw-r--r--libgo/go/net/main_windows_test.go4
-rw-r--r--libgo/go/net/mockserver_test.go69
-rw-r--r--libgo/go/net/net.go148
-rw-r--r--libgo/go/net/net_test.go214
-rw-r--r--libgo/go/net/newpollserver_rtems.go2
-rw-r--r--libgo/go/net/packetconn_test.go2
-rw-r--r--libgo/go/net/parse.go62
-rw-r--r--libgo/go/net/parse_test.go7
-rw-r--r--libgo/go/net/pipe.go2
-rw-r--r--libgo/go/net/pipe_test.go2
-rw-r--r--libgo/go/net/platform_test.go3
-rw-r--r--libgo/go/net/port.go62
-rw-r--r--libgo/go/net/port_test.go52
-rw-r--r--libgo/go/net/port_unix.go32
-rw-r--r--libgo/go/net/protoconn_test.go2
-rw-r--r--libgo/go/net/rpc/client.go14
-rw-r--r--libgo/go/net/rpc/client_test.go4
-rw-r--r--libgo/go/net/rpc/jsonrpc/all_test.go2
-rw-r--r--libgo/go/net/rpc/jsonrpc/client.go2
-rw-r--r--libgo/go/net/rpc/jsonrpc/server.go4
-rw-r--r--libgo/go/net/rpc/server.go22
-rw-r--r--libgo/go/net/rpc/server_test.go10
-rw-r--r--libgo/go/net/sendfile_dragonfly.go6
-rw-r--r--libgo/go/net/sendfile_freebsd.go6
-rw-r--r--libgo/go/net/sendfile_linux.go4
-rw-r--r--libgo/go/net/sendfile_solaris.go15
-rw-r--r--libgo/go/net/sendfile_stub.go2
-rw-r--r--libgo/go/net/sendfile_test.go90
-rw-r--r--libgo/go/net/sendfile_windows.go4
-rw-r--r--libgo/go/net/smtp/smtp.go16
-rw-r--r--libgo/go/net/smtp/smtp_test.go71
-rw-r--r--libgo/go/net/sock_bsd.go2
-rw-r--r--libgo/go/net/sock_linux.go4
-rw-r--r--libgo/go/net/sock_plan9.go2
-rw-r--r--libgo/go/net/sock_posix.go15
-rw-r--r--libgo/go/net/sock_stub.go2
-rw-r--r--libgo/go/net/sock_windows.go2
-rw-r--r--libgo/go/net/sockopt_bsd.go4
-rw-r--r--libgo/go/net/sockopt_linux.go4
-rw-r--r--libgo/go/net/sockopt_plan9.go8
-rw-r--r--libgo/go/net/sockopt_posix.go2
-rw-r--r--libgo/go/net/sockopt_solaris.go4
-rw-r--r--libgo/go/net/sockopt_stub.go2
-rw-r--r--libgo/go/net/sockopt_windows.go4
-rw-r--r--libgo/go/net/sockoptip_bsd.go2
-rw-r--r--libgo/go/net/sockoptip_linux.go2
-rw-r--r--libgo/go/net/sockoptip_posix.go2
-rw-r--r--libgo/go/net/sockoptip_stub.go2
-rw-r--r--libgo/go/net/sockoptip_windows.go2
-rw-r--r--libgo/go/net/tcpsock.go243
-rw-r--r--libgo/go/net/tcpsock_plan9.go211
-rw-r--r--libgo/go/net/tcpsock_posix.go239
-rw-r--r--libgo/go/net/tcpsock_test.go (renamed from libgo/go/net/tcp_test.go)184
-rw-r--r--libgo/go/net/tcpsock_unix_test.go79
-rw-r--r--libgo/go/net/tcpsockopt_darwin.go2
-rw-r--r--libgo/go/net/tcpsockopt_dragonfly.go2
-rw-r--r--libgo/go/net/tcpsockopt_openbsd.go2
-rw-r--r--libgo/go/net/tcpsockopt_plan9.go7
-rw-r--r--libgo/go/net/tcpsockopt_posix.go2
-rw-r--r--libgo/go/net/tcpsockopt_solaris.go2
-rw-r--r--libgo/go/net/tcpsockopt_stub.go2
-rw-r--r--libgo/go/net/tcpsockopt_unix.go2
-rw-r--r--libgo/go/net/tcpsockopt_windows.go2
-rw-r--r--libgo/go/net/testdata/Mark.Twain-Tom.Sawyer.txt8465
-rw-r--r--libgo/go/net/testdata/invalid-ndots-resolv.conf1
-rw-r--r--libgo/go/net/testdata/large-ndots-resolv.conf1
-rw-r--r--libgo/go/net/testdata/negative-ndots-resolv.conf1
-rw-r--r--libgo/go/net/textproto/header.go8
-rw-r--r--libgo/go/net/textproto/pipeline.go6
-rw-r--r--libgo/go/net/textproto/reader.go106
-rw-r--r--libgo/go/net/textproto/reader_test.go8
-rw-r--r--libgo/go/net/textproto/textproto.go4
-rw-r--r--libgo/go/net/textproto/writer.go4
-rw-r--r--libgo/go/net/textproto/writer_test.go2
-rw-r--r--libgo/go/net/timeout_test.go111
-rw-r--r--libgo/go/net/udpsock.go197
-rw-r--r--libgo/go/net/udpsock_plan9.go182
-rw-r--r--libgo/go/net/udpsock_plan9_test.go69
-rw-r--r--libgo/go/net/udpsock_posix.go184
-rw-r--r--libgo/go/net/udpsock_test.go (renamed from libgo/go/net/udp_test.go)82
-rw-r--r--libgo/go/net/unixsock.go282
-rw-r--r--libgo/go/net/unixsock_plan9.go140
-rw-r--r--libgo/go/net/unixsock_posix.go290
-rw-r--r--libgo/go/net/unixsock_test.go (renamed from libgo/go/net/unix_test.go)159
-rw-r--r--libgo/go/net/url/url.go250
-rw-r--r--libgo/go/net/url/url_test.go366
-rw-r--r--libgo/go/net/writev_test.go225
-rw-r--r--libgo/go/net/writev_unix.go95
-rw-r--r--libgo/go/old/regexp/all_test.go421
-rw-r--r--libgo/go/old/regexp/find_test.go472
-rw-r--r--libgo/go/old/regexp/regexp.go1488
-rw-r--r--libgo/go/old/template/doc.go91
-rw-r--r--libgo/go/old/template/execute.go346
-rw-r--r--libgo/go/old/template/format.go77
-rw-r--r--libgo/go/old/template/parse.go742
-rw-r--r--libgo/go/old/template/template_test.go810
-rw-r--r--libgo/go/os/dir.go128
-rw-r--r--libgo/go/os/dir_gccgo.go102
-rw-r--r--libgo/go/os/dir_largefile.go2
-rw-r--r--libgo/go/os/dir_regfile.go4
-rw-r--r--libgo/go/os/dir_unix.go62
-rw-r--r--libgo/go/os/doc.go139
-rw-r--r--libgo/go/os/env.go9
-rw-r--r--libgo/go/os/env_test.go28
-rw-r--r--libgo/go/os/env_unix_test.go26
-rw-r--r--libgo/go/os/error.go14
-rw-r--r--libgo/go/os/error_plan9.go48
-rw-r--r--libgo/go/os/error_test.go14
-rw-r--r--libgo/go/os/error_unix.go35
-rw-r--r--libgo/go/os/error_unix_test.go39
-rw-r--r--libgo/go/os/error_windows.go34
-rw-r--r--libgo/go/os/error_windows_test.go39
-rw-r--r--libgo/go/os/example_test.go106
-rw-r--r--libgo/go/os/exec.go99
-rw-r--r--libgo/go/os/exec/exec.go108
-rw-r--r--libgo/go/os/exec/exec_test.go193
-rw-r--r--libgo/go/os/exec/lp_plan9.go10
-rw-r--r--libgo/go/os/exec/lp_unix.go12
-rw-r--r--libgo/go/os/exec/lp_unix_test.go2
-rw-r--r--libgo/go/os/exec/lp_windows.go86
-rw-r--r--libgo/go/os/exec_posix.go2
-rw-r--r--libgo/go/os/exec_unix.go18
-rw-r--r--libgo/go/os/exec_windows.go6
-rw-r--r--libgo/go/os/executable.go23
-rw-r--r--libgo/go/os/executable_darwin.go24
-rw-r--r--libgo/go/os/executable_freebsd.go33
-rw-r--r--libgo/go/os/executable_plan9.go19
-rw-r--r--libgo/go/os/executable_procfs.go36
-rw-r--r--libgo/go/os/executable_solaris.go27
-rw-r--r--libgo/go/os/executable_test.go87
-rw-r--r--libgo/go/os/executable_windows.go32
-rw-r--r--libgo/go/os/export_test.go2
-rw-r--r--libgo/go/os/export_windows_test.go13
-rw-r--r--libgo/go/os/file.go55
-rw-r--r--libgo/go/os/file_plan9.go26
-rw-r--r--libgo/go/os/file_posix.go22
-rw-r--r--libgo/go/os/file_unix.go105
-rw-r--r--libgo/go/os/getwd.go4
-rw-r--r--libgo/go/os/os_test.go269
-rw-r--r--libgo/go/os/os_unix_test.go54
-rw-r--r--libgo/go/os/path.go2
-rw-r--r--libgo/go/os/path_test.go12
-rw-r--r--libgo/go/os/path_unix.go18
-rw-r--r--libgo/go/os/path_windows.go193
-rw-r--r--libgo/go/os/path_windows_test.go46
-rw-r--r--libgo/go/os/pipe_test.go2
-rw-r--r--libgo/go/os/signal/doc.go6
-rw-r--r--libgo/go/os/signal/signal.go2
-rw-r--r--libgo/go/os/signal/signal_test.go13
-rw-r--r--libgo/go/os/stat.go7
-rw-r--r--libgo/go/os/stat_atim.go2
-rw-r--r--libgo/go/os/stat_atimespec.go2
-rw-r--r--libgo/go/os/stat_dragonfly.go4
-rw-r--r--libgo/go/os/stat_nacl.go2
-rw-r--r--libgo/go/os/stat_plan9.go14
-rw-r--r--libgo/go/os/stat_solaris.go2
-rw-r--r--libgo/go/os/stat_unix.go52
-rw-r--r--libgo/go/os/str.go2
-rw-r--r--libgo/go/os/sys.go10
-rw-r--r--libgo/go/os/sys_uname.go2
-rw-r--r--libgo/go/os/types.go7
-rw-r--r--libgo/go/os/types_plan9.go13
-rw-r--r--libgo/go/os/types_unix.go6
-rw-r--r--libgo/go/os/types_windows.go6
-rw-r--r--libgo/go/os/user/decls_solaris.go6
-rw-r--r--libgo/go/os/user/decls_unix.go9
-rw-r--r--libgo/go/os/user/listgroups_solaris.go17
-rw-r--r--libgo/go/os/user/listgroups_unix.go57
-rw-r--r--libgo/go/os/user/lookup.go21
-rw-r--r--libgo/go/os/user/lookup_android.go38
-rw-r--r--libgo/go/os/user/lookup_plan9.go20
-rw-r--r--libgo/go/os/user/lookup_stubs.go70
-rw-r--r--libgo/go/os/user/lookup_unix.go253
-rw-r--r--libgo/go/os/user/lookup_windows.go23
-rw-r--r--libgo/go/os/user/user.go62
-rw-r--r--libgo/go/os/user/user_test.go76
-rw-r--r--libgo/go/os/wait_unimp.go16
-rw-r--r--libgo/go/os/wait_wait6.go41
-rw-r--r--libgo/go/os/wait_waitid.go40
-rw-r--r--libgo/go/path/example_test.go9
-rw-r--r--libgo/go/path/filepath/example_unix_test.go14
-rw-r--r--libgo/go/path/filepath/export_windows_test.go10
-rw-r--r--libgo/go/path/filepath/match.go55
-rw-r--r--libgo/go/path/filepath/match_test.go182
-rw-r--r--libgo/go/path/filepath/path.go29
-rw-r--r--libgo/go/path/filepath/path_plan9.go3
-rw-r--r--libgo/go/path/filepath/path_test.go139
-rw-r--r--libgo/go/path/filepath/path_unix.go3
-rw-r--r--libgo/go/path/filepath/path_windows.go13
-rw-r--r--libgo/go/path/filepath/symlink.go7
-rw-r--r--libgo/go/path/filepath/symlink_windows.go123
-rw-r--r--libgo/go/path/match.go2
-rw-r--r--libgo/go/path/path.go6
-rw-r--r--libgo/go/path/path_test.go8
-rw-r--r--libgo/go/plugin/plugin.go73
-rw-r--r--libgo/go/plugin/plugin_dlopen.go138
-rw-r--r--libgo/go/plugin/plugin_stubs.go17
-rw-r--r--libgo/go/reflect/all_test.go1251
-rw-r--r--libgo/go/reflect/deepequal.go13
-rw-r--r--libgo/go/reflect/example_test.go71
-rw-r--r--libgo/go/reflect/export_test.go48
-rw-r--r--libgo/go/reflect/makefunc.go10
-rw-r--r--libgo/go/reflect/makefunc_ffi.go5
-rw-r--r--libgo/go/reflect/makefunc_ffi_c.c35
-rw-r--r--libgo/go/reflect/set_test.go4
-rw-r--r--libgo/go/reflect/swapper.go74
-rw-r--r--libgo/go/reflect/type.go596
-rw-r--r--libgo/go/reflect/value.go71
-rw-r--r--libgo/go/regexp/all_test.go124
-rw-r--r--libgo/go/regexp/backtrack.go5
-rw-r--r--libgo/go/regexp/exec.go45
-rw-r--r--libgo/go/regexp/exec_test.go89
-rw-r--r--libgo/go/regexp/onepass.go11
-rw-r--r--libgo/go/regexp/onepass_test.go4
-rw-r--r--libgo/go/regexp/regexp.go159
-rw-r--r--libgo/go/regexp/syntax/compile.go4
-rw-r--r--libgo/go/regexp/syntax/doc.go4
-rw-r--r--libgo/go/regexp/syntax/parse.go34
-rw-r--r--libgo/go/regexp/syntax/parse_test.go2
-rw-r--r--libgo/go/regexp/syntax/prog.go4
-rw-r--r--libgo/go/regexp/syntax/regexp.go6
-rw-r--r--libgo/go/regexp/syntax/simplify.go8
-rw-r--r--libgo/go/regexp/syntax/simplify_test.go6
-rw-r--r--libgo/go/runtime/alg.go390
-rw-r--r--libgo/go/runtime/append_test.go332
-rw-r--r--libgo/go/runtime/callers_test.go83
-rw-r--r--libgo/go/runtime/cgo_gccgo.go110
-rw-r--r--libgo/go/runtime/cgo_mmap.go41
-rw-r--r--libgo/go/runtime/cgo_ppc64x.go12
-rw-r--r--libgo/go/runtime/cgocheck.go37
-rw-r--r--libgo/go/runtime/chan.go739
-rw-r--r--libgo/go/runtime/chan_test.go120
-rw-r--r--libgo/go/runtime/chanbarrier_test.go2
-rw-r--r--libgo/go/runtime/compiler.go4
-rw-r--r--libgo/go/runtime/cpuprof.go454
-rw-r--r--libgo/go/runtime/cputicks.go9
-rw-r--r--libgo/go/runtime/crash_cgo_test.go252
-rw-r--r--libgo/go/runtime/crash_nonunix_test.go13
-rw-r--r--libgo/go/runtime/crash_test.go219
-rw-r--r--libgo/go/runtime/crash_unix_test.go85
-rw-r--r--libgo/go/runtime/debug.go184
-rw-r--r--libgo/go/runtime/debug/garbage.go64
-rw-r--r--libgo/go/runtime/debug/garbage_test.go32
-rw-r--r--libgo/go/runtime/debug/heapdump_test.go2
-rw-r--r--libgo/go/runtime/debug/stack_test.go12
-rw-r--r--libgo/go/runtime/debug/stubs.go17
-rw-r--r--libgo/go/runtime/defs_linux_mips64x.go183
-rw-r--r--libgo/go/runtime/env_posix.go20
-rw-r--r--libgo/go/runtime/error.go31
-rw-r--r--libgo/go/runtime/export_arm_test.go2
-rw-r--r--libgo/go/runtime/export_linux_test.go2
-rw-r--r--libgo/go/runtime/export_mmap_test.go11
-rw-r--r--libgo/go/runtime/export_test.go241
-rw-r--r--libgo/go/runtime/export_windows_test.go8
-rw-r--r--libgo/go/runtime/extern.go151
-rw-r--r--libgo/go/runtime/fastlog2.go6
-rw-r--r--libgo/go/runtime/fastlog2_test.go2
-rw-r--r--libgo/go/runtime/fastlog2table.go2
-rw-r--r--libgo/go/runtime/ffi.go315
-rw-r--r--libgo/go/runtime/gc_test.go62
-rw-r--r--libgo/go/runtime/gcinfo_test.go11
-rw-r--r--libgo/go/runtime/hash32.go94
-rw-r--r--libgo/go/runtime/hash64.go94
-rw-r--r--libgo/go/runtime/hashmap.go1202
-rw-r--r--libgo/go/runtime/hashmap_fast.go422
-rw-r--r--libgo/go/runtime/iface.go334
-rw-r--r--libgo/go/runtime/internal/atomic/atomic.c251
-rw-r--r--libgo/go/runtime/internal/atomic/atomic_test.go105
-rw-r--r--libgo/go/runtime/internal/atomic/bench_test.go28
-rw-r--r--libgo/go/runtime/internal/atomic/gccgo.go59
-rw-r--r--libgo/go/runtime/internal/atomic/stubs.go33
-rw-r--r--libgo/go/runtime/internal/sys/intrinsics.go55
-rw-r--r--libgo/go/runtime/internal/sys/intrinsics_test.go38
-rw-r--r--libgo/go/runtime/internal/sys/stubs.go11
-rw-r--r--libgo/go/runtime/internal/sys/sys.go15
-rw-r--r--libgo/go/runtime/lfstack.go50
-rw-r--r--libgo/go/runtime/lfstack_32bit.go19
-rw-r--r--libgo/go/runtime/lfstack_64bit.go48
-rw-r--r--libgo/go/runtime/lfstack_linux_mips64x.go32
-rw-r--r--libgo/go/runtime/lock_futex.go224
-rw-r--r--libgo/go/runtime/lock_sema.go278
-rw-r--r--libgo/go/runtime/malloc_test.go12
-rw-r--r--libgo/go/runtime/map_test.go38
-rw-r--r--libgo/go/runtime/mcache.go95
-rw-r--r--libgo/go/runtime/mem.go77
-rw-r--r--libgo/go/runtime/mksizeclasses.go325
-rw-r--r--libgo/go/runtime/mmap.go16
-rw-r--r--libgo/go/runtime/mprof.go775
-rw-r--r--libgo/go/runtime/msan.go55
-rw-r--r--libgo/go/runtime/msan0.go2
-rw-r--r--libgo/go/runtime/mstats.go693
-rw-r--r--libgo/go/runtime/mstkbar.go38
-rw-r--r--libgo/go/runtime/net_plan9.go29
-rw-r--r--libgo/go/runtime/netpoll.go456
-rw-r--r--libgo/go/runtime/netpoll_epoll.go116
-rw-r--r--libgo/go/runtime/netpoll_kqueue.go110
-rw-r--r--libgo/go/runtime/netpoll_nacl.go26
-rw-r--r--libgo/go/runtime/netpoll_solaris.go225
-rw-r--r--libgo/go/runtime/netpoll_stub.go (renamed from libgo/runtime/netpoll_stub.c)17
-rw-r--r--libgo/go/runtime/netpoll_windows.go145
-rw-r--r--libgo/go/runtime/norace_test.go2
-rw-r--r--libgo/go/runtime/os1_linux_generic.go27
-rw-r--r--libgo/go/runtime/os1_linux_mips64x.go26
-rw-r--r--libgo/go/runtime/os2_linux_generic.go29
-rw-r--r--libgo/go/runtime/os2_linux_mips64x.go25
-rw-r--r--libgo/go/runtime/os_android.go15
-rw-r--r--libgo/go/runtime/os_darwin.go329
-rw-r--r--libgo/go/runtime/os_dragonfly.go62
-rw-r--r--libgo/go/runtime/os_freebsd.go56
-rw-r--r--libgo/go/runtime/os_gccgo.go47
-rw-r--r--libgo/go/runtime/os_linux.go171
-rw-r--r--libgo/go/runtime/os_linux_mips64x.go18
-rw-r--r--libgo/go/runtime/os_linux_ppc64x.go61
-rw-r--r--libgo/go/runtime/os_netbsd.go73
-rw-r--r--libgo/go/runtime/os_openbsd.go76
-rw-r--r--libgo/go/runtime/os_solaris.go85
-rw-r--r--libgo/go/runtime/panic.go882
-rw-r--r--libgo/go/runtime/parfor_test.go128
-rw-r--r--libgo/go/runtime/pprof/internal/protopprof/protomemprofile.go83
-rw-r--r--libgo/go/runtime/pprof/internal/protopprof/protomemprofile_test.go104
-rw-r--r--libgo/go/runtime/pprof/internal/protopprof/protopprof.go105
-rw-r--r--libgo/go/runtime/pprof/internal/protopprof/protopprof_test.go171
-rw-r--r--libgo/go/runtime/pprof/mprof_test.go31
-rw-r--r--libgo/go/runtime/pprof/pprof.go368
-rw-r--r--libgo/go/runtime/pprof/pprof_test.go254
-rw-r--r--libgo/go/runtime/print.go64
-rw-r--r--libgo/go/runtime/proc.go2890
-rw-r--r--libgo/go/runtime/proc_runtime_test.go35
-rw-r--r--libgo/go/runtime/proc_test.go52
-rw-r--r--libgo/go/runtime/race/testdata/issue12225_test.go20
-rw-r--r--libgo/go/runtime/race/testdata/issue12664_test.go76
-rw-r--r--libgo/go/runtime/race/testdata/issue13264_test.go13
-rw-r--r--libgo/go/runtime/race0.go40
-rw-r--r--libgo/go/runtime/rdebug.go27
-rw-r--r--libgo/go/runtime/runtime-lldb_test.go8
-rw-r--r--libgo/go/runtime/runtime.go72
-rw-r--r--libgo/go/runtime/runtime1.go530
-rw-r--r--libgo/go/runtime/runtime2.go797
-rw-r--r--libgo/go/runtime/runtime_mmap_test.go37
-rw-r--r--libgo/go/runtime/runtime_test.go17
-rw-r--r--libgo/go/runtime/runtime_unix_test.go2
-rw-r--r--libgo/go/runtime/select.go758
-rw-r--r--libgo/go/runtime/sema.go385
-rw-r--r--libgo/go/runtime/signal2_unix.go69
-rw-r--r--libgo/go/runtime/signal_gccgo.go144
-rw-r--r--libgo/go/runtime/signal_linux_mips64x.go70
-rw-r--r--libgo/go/runtime/signal_mips64x.go188
-rw-r--r--libgo/go/runtime/signal_sighandler.go133
-rw-r--r--libgo/go/runtime/signal_sigtramp.go50
-rw-r--r--libgo/go/runtime/signal_unix.go606
-rw-r--r--libgo/go/runtime/sigqueue.go178
-rw-r--r--libgo/go/runtime/sigtab_linux_generic.go82
-rw-r--r--libgo/go/runtime/sigtab_linux_mips64x.go81
-rw-r--r--libgo/go/runtime/sizeclasses.go95
-rw-r--r--libgo/go/runtime/slice.go230
-rw-r--r--libgo/go/runtime/stack.go333
-rw-r--r--libgo/go/runtime/string.go463
-rw-r--r--libgo/go/runtime/string_test.go219
-rw-r--r--libgo/go/runtime/stubs.go642
-rw-r--r--libgo/go/runtime/stubs2.go33
-rw-r--r--libgo/go/runtime/symtab.go137
-rw-r--r--libgo/go/runtime/sys_mips64x.go43
-rw-r--r--libgo/go/runtime/sys_nonppc64x.go10
-rw-r--r--libgo/go/runtime/testdata/testprog/crash.go2
-rw-r--r--libgo/go/runtime/testdata/testprog/deadlock.go38
-rw-r--r--libgo/go/runtime/testdata/testprog/gc.go51
-rw-r--r--libgo/go/runtime/testdata/testprog/main.go2
-rw-r--r--libgo/go/runtime/testdata/testprog/map.go77
-rw-r--r--libgo/go/runtime/testdata/testprog/memprof.go49
-rw-r--r--libgo/go/runtime/testdata/testprog/misc.go2
-rw-r--r--libgo/go/runtime/testdata/testprog/signal.go16
-rw-r--r--libgo/go/runtime/testdata/testprog/stringconcat.go2
-rw-r--r--libgo/go/runtime/testdata/testprog/syscall_windows.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/aprof.go53
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/callback.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/cgo.go22
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/crash.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/deadlock.go30
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/dll_windows.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/dropm.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/dropm_stub.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/exec.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/main.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/pprof.go97
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/raceprof.go78
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/racesig.go102
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpanic.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpanic_unix.c26
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpanic_windows.c23
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpprof.go123
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadprof.go11
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/traceback.go81
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/tracebackctxt.go107
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/tracebackctxt_c.c91
-rw-r--r--libgo/go/runtime/testdata/testprognet/main.go2
-rw-r--r--libgo/go/runtime/testdata/testprognet/net.go2
-rw-r--r--libgo/go/runtime/testdata/testprognet/signal.go2
-rw-r--r--libgo/go/runtime/time.go303
-rw-r--r--libgo/go/runtime/trace.go1033
-rw-r--r--libgo/go/runtime/trace/trace.go42
-rw-r--r--libgo/go/runtime/trace/trace_stack_test.go282
-rw-r--r--libgo/go/runtime/trace/trace_test.go489
-rw-r--r--libgo/go/runtime/traceback_gccgo.go228
-rw-r--r--libgo/go/runtime/type.go125
-rw-r--r--libgo/go/runtime/typekind.go44
-rw-r--r--libgo/go/runtime/unaligned1.go17
-rw-r--r--libgo/go/runtime/unaligned2.go20
-rw-r--r--libgo/go/runtime/utf8.go130
-rw-r--r--libgo/go/runtime/vdso_none.go11
-rw-r--r--libgo/go/runtime/vlrt.go258
-rw-r--r--libgo/go/runtime/write_err_android.go4
-rw-r--r--libgo/go/sort/example_search_test.go42
-rw-r--r--libgo/go/sort/example_test.go19
-rw-r--r--libgo/go/sort/genzfunc.go122
-rw-r--r--libgo/go/sort/search.go8
-rw-r--r--libgo/go/sort/search_test.go2
-rw-r--r--libgo/go/sort/sort.go95
-rw-r--r--libgo/go/sort/sort_test.go133
-rw-r--r--libgo/go/sort/zfuncversion.go265
-rw-r--r--libgo/go/strconv/atob.go2
-rw-r--r--libgo/go/strconv/atof.go13
-rw-r--r--libgo/go/strconv/atof_test.go26
-rw-r--r--libgo/go/strconv/atoi.go18
-rw-r--r--libgo/go/strconv/atoi_test.go2
-rw-r--r--libgo/go/strconv/decimal.go6
-rw-r--r--libgo/go/strconv/extfloat.go4
-rw-r--r--libgo/go/strconv/fp_test.go2
-rw-r--r--libgo/go/strconv/ftoa.go2
-rw-r--r--libgo/go/strconv/ftoa_test.go88
-rw-r--r--libgo/go/strconv/isprint.go82
-rw-r--r--libgo/go/strconv/makeisprint.go2
-rw-r--r--libgo/go/strconv/quote.go160
-rw-r--r--libgo/go/strconv/quote_test.go31
-rw-r--r--libgo/go/strconv/strconv_test.go38
-rw-r--r--libgo/go/strings/compare.go2
-rw-r--r--libgo/go/strings/compare_test.go2
-rw-r--r--libgo/go/strings/reader.go20
-rw-r--r--libgo/go/strings/reader_test.go46
-rw-r--r--libgo/go/strings/strings.go200
-rw-r--r--libgo/go/strings/strings_amd64.go56
-rw-r--r--libgo/go/strings/strings_decl.go2
-rw-r--r--libgo/go/strings/strings_generic.go4
-rw-r--r--libgo/go/strings/strings_s390x.go100
-rw-r--r--libgo/go/strings/strings_test.go320
-rw-r--r--libgo/go/sync/atomic/64bit_arm.go2
-rw-r--r--libgo/go/sync/atomic/atomic.c20
-rw-r--r--libgo/go/sync/atomic/atomic_test.go35
-rw-r--r--libgo/go/sync/atomic/doc.go2
-rw-r--r--libgo/go/sync/atomic/value.go14
-rw-r--r--libgo/go/sync/atomic/value_test.go7
-rw-r--r--libgo/go/sync/cond.go63
-rw-r--r--libgo/go/sync/cond_test.go63
-rw-r--r--libgo/go/sync/example_pool_test.go45
-rw-r--r--libgo/go/sync/export_test.go2
-rw-r--r--libgo/go/sync/mutex.go14
-rw-r--r--libgo/go/sync/mutex_test.go108
-rw-r--r--libgo/go/sync/once.go4
-rw-r--r--libgo/go/sync/pool.go90
-rw-r--r--libgo/go/sync/pool_test.go3
-rw-r--r--libgo/go/sync/runtime.go40
-rw-r--r--libgo/go/sync/runtime_sema_test.go3
-rw-r--r--libgo/go/sync/rwmutex.go27
-rw-r--r--libgo/go/sync/rwmutex_test.go42
-rw-r--r--libgo/go/sync/waitgroup.go8
-rw-r--r--libgo/go/syscall/bpf_bsd.go20
-rw-r--r--libgo/go/syscall/clone_linux.c102
-rw-r--r--libgo/go/syscall/const_plan9.go11
-rw-r--r--libgo/go/syscall/creds_test.go2
-rw-r--r--libgo/go/syscall/dir_plan9.go3
-rw-r--r--libgo/go/syscall/dirent.go102
-rw-r--r--libgo/go/syscall/endian_big.go9
-rw-r--r--libgo/go/syscall/endian_little.go9
-rw-r--r--libgo/go/syscall/env_plan9.go2
-rw-r--r--libgo/go/syscall/env_unix.go2
-rw-r--r--libgo/go/syscall/env_windows.go4
-rw-r--r--libgo/go/syscall/errors_plan9.go2
-rw-r--r--libgo/go/syscall/errstr.go2
-rw-r--r--libgo/go/syscall/errstr_linux.go5
-rw-r--r--libgo/go/syscall/errstr_nor.go41
-rw-r--r--libgo/go/syscall/exec_bsd.go10
-rw-r--r--libgo/go/syscall/exec_linux.go76
-rw-r--r--libgo/go/syscall/exec_linux_test.go133
-rw-r--r--libgo/go/syscall/exec_solaris_test.go37
-rw-r--r--libgo/go/syscall/exec_stubs.go2
-rw-r--r--libgo/go/syscall/exec_unix.go26
-rw-r--r--libgo/go/syscall/exec_windows.go2
-rw-r--r--libgo/go/syscall/export_test.go2
-rw-r--r--libgo/go/syscall/export_unix_test.go2
-rw-r--r--libgo/go/syscall/libcall_bsd.go2
-rw-r--r--libgo/go/syscall/libcall_irix.go2
-rw-r--r--libgo/go/syscall/libcall_linux.go21
-rw-r--r--libgo/go/syscall/libcall_linux_ustat.go1
-rw-r--r--libgo/go/syscall/libcall_posix.go34
-rw-r--r--libgo/go/syscall/libcall_posix_largefile.go2
-rw-r--r--libgo/go/syscall/libcall_posix_regfile.go4
-rw-r--r--libgo/go/syscall/libcall_posix_utimesnano.go2
-rw-r--r--libgo/go/syscall/libcall_uname.go4
-rw-r--r--libgo/go/syscall/libcall_waitpid.go20
-rw-r--r--libgo/go/syscall/lsf_linux.go10
-rw-r--r--libgo/go/syscall/msan.go22
-rw-r--r--libgo/go/syscall/msan0.go2
-rw-r--r--libgo/go/syscall/netlink_linux.go7
-rw-r--r--libgo/go/syscall/route_bsd.go18
-rw-r--r--libgo/go/syscall/route_bsd_test.go260
-rw-r--r--libgo/go/syscall/route_darwin.go4
-rw-r--r--libgo/go/syscall/route_dragonfly.go6
-rw-r--r--libgo/go/syscall/route_freebsd.go6
-rw-r--r--libgo/go/syscall/route_ifma_test.go74
-rw-r--r--libgo/go/syscall/route_netbsd.go4
-rw-r--r--libgo/go/syscall/route_noifma_test.go63
-rw-r--r--libgo/go/syscall/route_openbsd.go4
-rw-r--r--libgo/go/syscall/security_windows.go2
-rw-r--r--libgo/go/syscall/setuidgid_32_linux.go13
-rw-r--r--libgo/go/syscall/setuidgid_linux.go13
-rw-r--r--libgo/go/syscall/sleep_rtems.go2
-rw-r--r--libgo/go/syscall/sleep_select.go8
-rw-r--r--libgo/go/syscall/sockcmsg_linux.go5
-rw-r--r--libgo/go/syscall/sockcmsg_unix.go11
-rw-r--r--libgo/go/syscall/socket_bsd.go2
-rw-r--r--libgo/go/syscall/socket_irix.go2
-rw-r--r--libgo/go/syscall/socket_linux_ppc64x_type.go2
-rw-r--r--libgo/go/syscall/socket_linux_type.go4
-rw-r--r--libgo/go/syscall/socket_posix.go2
-rw-r--r--libgo/go/syscall/socket_xnet.go2
-rw-r--r--libgo/go/syscall/syscall.go12
-rw-r--r--libgo/go/syscall/syscall_darwin.go19
-rw-r--r--libgo/go/syscall/syscall_dragonfly.go23
-rw-r--r--libgo/go/syscall/syscall_freebsd.go19
-rw-r--r--libgo/go/syscall/syscall_linux.go23
-rw-r--r--libgo/go/syscall/syscall_linux_mipsx.go12
-rw-r--r--libgo/go/syscall/syscall_linux_test.go28
-rw-r--r--libgo/go/syscall/syscall_netbsd.go19
-rw-r--r--libgo/go/syscall/syscall_openbsd.go19
-rw-r--r--libgo/go/syscall/syscall_solaris.go35
-rw-r--r--libgo/go/syscall/syscall_stubs.go2
-rw-r--r--libgo/go/syscall/syscall_test.go28
-rw-r--r--libgo/go/syscall/syscall_unix.go1
-rw-r--r--libgo/go/syscall/syscall_unix_test.go14
-rw-r--r--libgo/go/syscall/timestruct.go40
-rw-r--r--libgo/go/testing/allocs.go4
-rw-r--r--libgo/go/testing/allocs_test.go2
-rw-r--r--libgo/go/testing/benchmark.go298
-rw-r--r--libgo/go/testing/example.go36
-rw-r--r--libgo/go/testing/internal/testdeps/deps.go51
-rw-r--r--libgo/go/testing/iotest/reader.go2
-rw-r--r--libgo/go/testing/match.go167
-rw-r--r--libgo/go/testing/match_test.go185
-rw-r--r--libgo/go/testing/quick/quick.go46
-rw-r--r--libgo/go/testing/sub_test.go534
-rw-r--r--libgo/go/testing/testing.go584
-rw-r--r--libgo/go/testing/testing_test.go2
-rw-r--r--libgo/go/text/scanner/example_test.go21
-rw-r--r--libgo/go/text/scanner/scanner.go15
-rw-r--r--libgo/go/text/scanner/scanner_test.go62
-rw-r--r--libgo/go/text/tabwriter/example_test.go35
-rw-r--r--libgo/go/text/tabwriter/tabwriter.go51
-rw-r--r--libgo/go/text/template/doc.go7
-rw-r--r--libgo/go/text/template/exec.go92
-rw-r--r--libgo/go/text/template/exec_test.go136
-rw-r--r--libgo/go/text/template/funcs.go85
-rw-r--r--libgo/go/text/template/helper.go14
-rw-r--r--libgo/go/text/template/multi_test.go71
-rw-r--r--libgo/go/text/template/parse/lex.go81
-rw-r--r--libgo/go/text/template/parse/lex_test.go259
-rw-r--r--libgo/go/text/template/parse/parse.go35
-rw-r--r--libgo/go/text/template/parse/parse_test.go36
-rw-r--r--libgo/go/text/template/template.go17
-rw-r--r--libgo/go/time/example_test.go20
-rw-r--r--libgo/go/time/export_android_test.go12
-rw-r--r--libgo/go/time/format.go71
-rw-r--r--libgo/go/time/format_test.go47
-rw-r--r--libgo/go/time/genzabbrs.go2
-rw-r--r--libgo/go/time/sleep.go45
-rw-r--r--libgo/go/time/sys_plan9.go4
-rw-r--r--libgo/go/time/sys_unix.go4
-rw-r--r--libgo/go/time/sys_windows.go4
-rw-r--r--libgo/go/time/tick.go3
-rw-r--r--libgo/go/time/tick_test.go2
-rw-r--r--libgo/go/time/time.go135
-rw-r--r--libgo/go/time/time_test.go150
-rw-r--r--libgo/go/time/zoneinfo.go2
-rw-r--r--libgo/go/time/zoneinfo_abbrs_windows.go187
-rw-r--r--libgo/go/time/zoneinfo_android.go119
-rw-r--r--libgo/go/time/zoneinfo_android_test.go18
-rw-r--r--libgo/go/time/zoneinfo_read.go11
-rw-r--r--libgo/go/time/zoneinfo_test.go11
-rw-r--r--libgo/go/time/zoneinfo_unix.go10
-rw-r--r--libgo/go/time/zoneinfo_windows.go6
-rw-r--r--libgo/go/unicode/graphic.go2
-rw-r--r--libgo/go/unicode/letter.go27
-rw-r--r--libgo/go/unicode/letter_test.go6
-rw-r--r--libgo/go/unicode/script_test.go10
-rw-r--r--libgo/go/unicode/tables.go618
-rw-r--r--libgo/go/unicode/utf16/export_test.go2
-rw-r--r--libgo/go/unicode/utf16/utf16.go34
-rw-r--r--libgo/go/unicode/utf16/utf16_test.go55
-rw-r--r--libgo/go/unicode/utf8/utf8.go21
-rw-r--r--libgo/go/unicode/utf8/utf8_test.go91
-rw-r--r--libgo/godeps.sh5
-rwxr-xr-xlibgo/match.sh197
-rwxr-xr-xlibgo/merge.sh72
-rwxr-xr-xlibgo/mkrsysinfo.sh147
-rw-r--r--libgo/mksigtab.sh99
-rwxr-xr-xlibgo/mksysinfo.sh299
-rw-r--r--libgo/runtime/aeshash.c586
-rw-r--r--libgo/runtime/chan.goc1136
-rw-r--r--libgo/runtime/chan.h75
-rw-r--r--libgo/runtime/cpuprof.goc442
-rw-r--r--libgo/runtime/env_posix.c4
-rw-r--r--libgo/runtime/go-alloc.h11
-rw-r--r--libgo/runtime/go-append.c74
-rw-r--r--libgo/runtime/go-assert-interface.c45
-rw-r--r--libgo/runtime/go-byte-array-to-string.c24
-rw-r--r--libgo/runtime/go-caller.c101
-rw-r--r--libgo/runtime/go-can-convert-interface.c78
-rw-r--r--libgo/runtime/go-cgo.c193
-rw-r--r--libgo/runtime/go-check-interface.c46
-rw-r--r--libgo/runtime/go-construct-map.c26
-rw-r--r--libgo/runtime/go-convert-interface.c132
-rw-r--r--libgo/runtime/go-copy.c22
-rw-r--r--libgo/runtime/go-defer.c85
-rw-r--r--libgo/runtime/go-defer.h47
-rw-r--r--libgo/runtime/go-deferred-recover.c94
-rw-r--r--libgo/runtime/go-eface-compare.c35
-rw-r--r--libgo/runtime/go-eface-val-compare.c33
-rw-r--r--libgo/runtime/go-ffi.c394
-rw-r--r--libgo/runtime/go-ffi.h16
-rw-r--r--libgo/runtime/go-fieldtrack.c23
-rw-r--r--libgo/runtime/go-iface.goc130
-rw-r--r--libgo/runtime/go-int-array-to-string.c89
-rw-r--r--libgo/runtime/go-int-to-string.c69
-rw-r--r--libgo/runtime/go-interface-compare.c35
-rw-r--r--libgo/runtime/go-interface-eface-compare.c34
-rw-r--r--libgo/runtime/go-interface-val-compare.c33
-rw-r--r--libgo/runtime/go-libmain.c3
-rw-r--r--libgo/runtime/go-main.c5
-rw-r--r--libgo/runtime/go-make-slice.c99
-rw-r--r--libgo/runtime/go-map-delete.c61
-rw-r--r--libgo/runtime/go-map-index.c137
-rw-r--r--libgo/runtime/go-map-len.c25
-rw-r--r--libgo/runtime/go-map-range.c103
-rw-r--r--libgo/runtime/go-memclr.c16
-rw-r--r--libgo/runtime/go-memequal.c16
-rw-r--r--libgo/runtime/go-memmove.c16
-rw-r--r--libgo/runtime/go-nanotime.c6
-rw-r--r--libgo/runtime/go-new-map.c142
-rw-r--r--libgo/runtime/go-new.c1
-rw-r--r--libgo/runtime/go-nosys.c56
-rw-r--r--libgo/runtime/go-panic.c112
-rw-r--r--libgo/runtime/go-panic.h52
-rw-r--r--libgo/runtime/go-print.c36
-rw-r--r--libgo/runtime/go-recover.c275
-rw-r--r--libgo/runtime/go-reflect-call.c13
-rw-r--r--libgo/runtime/go-reflect-map.c156
-rw-r--r--libgo/runtime/go-rune.c97
-rw-r--r--libgo/runtime/go-setenv.c37
-rw-r--r--libgo/runtime/go-signal.c688
-rw-r--r--libgo/runtime/go-strcmp.c25
-rw-r--r--libgo/runtime/go-string-to-byte-array.c28
-rw-r--r--libgo/runtime/go-string-to-int-array.c56
-rw-r--r--libgo/runtime/go-strplus.c30
-rw-r--r--libgo/runtime/go-strslice.c3
-rw-r--r--libgo/runtime/go-traceback.c37
-rw-r--r--libgo/runtime/go-trampoline.c113
-rw-r--r--libgo/runtime/go-type-complex.c120
-rw-r--r--libgo/runtime/go-type-eface.c62
-rw-r--r--libgo/runtime/go-type-error.c34
-rw-r--r--libgo/runtime/go-type-float.c92
-rw-r--r--libgo/runtime/go-type-identity.c62
-rw-r--r--libgo/runtime/go-type-interface.c62
-rw-r--r--libgo/runtime/go-type-string.c49
-rw-r--r--libgo/runtime/go-type.h59
-rw-r--r--libgo/runtime/go-unsafe-new.c1
-rw-r--r--libgo/runtime/go-unsafe-newarray.c1
-rw-r--r--libgo/runtime/go-unsafe-pointer.c24
-rw-r--r--libgo/runtime/go-unsetenv.c17
-rw-r--r--libgo/runtime/go-unwind.c147
-rw-r--r--libgo/runtime/heapdump.c130
-rw-r--r--libgo/runtime/interface.h57
-rw-r--r--libgo/runtime/lfstack.goc95
-rw-r--r--libgo/runtime/lock_futex.c204
-rw-r--r--libgo/runtime/lock_sema.c281
-rw-r--r--libgo/runtime/malloc.goc216
-rw-r--r--libgo/runtime/malloc.h232
-rw-r--r--libgo/runtime/map.goc72
-rw-r--r--libgo/runtime/map.h87
-rw-r--r--libgo/runtime/mcache.c6
-rw-r--r--libgo/runtime/mcentral.c12
-rw-r--r--libgo/runtime/mem_posix_memalign.c4
-rw-r--r--libgo/runtime/mgc0.c427
-rw-r--r--libgo/runtime/mheap.c79
-rw-r--r--libgo/runtime/mprof.goc562
-rw-r--r--libgo/runtime/msize.c22
-rw-r--r--libgo/runtime/netpoll.goc472
-rw-r--r--libgo/runtime/netpoll_epoll.c174
-rw-r--r--libgo/runtime/netpoll_kqueue.c118
-rw-r--r--libgo/runtime/netpoll_select.c256
-rw-r--r--libgo/runtime/panic.c203
-rw-r--r--libgo/runtime/parfor.c7
-rw-r--r--libgo/runtime/print.c301
-rw-r--r--libgo/runtime/proc.c2977
-rw-r--r--libgo/runtime/rdebug.goc26
-rw-r--r--libgo/runtime/reflect.goc25
-rw-r--r--libgo/runtime/runtime.c454
-rw-r--r--libgo/runtime/runtime.h670
-rw-r--r--libgo/runtime/runtime1.goc96
-rw-r--r--libgo/runtime/runtime_c.c190
-rw-r--r--libgo/runtime/sema.goc299
-rw-r--r--libgo/runtime/signal_unix.c176
-rw-r--r--libgo/runtime/signal_unix.h22
-rw-r--r--libgo/runtime/sigqueue.goc172
-rw-r--r--libgo/runtime/string.goc123
-rw-r--r--libgo/runtime/thread-linux.c59
-rw-r--r--libgo/runtime/thread-sema.c125
-rw-r--r--libgo/runtime/time.goc353
-rw-r--r--libgo/runtime/yield.c3
-rw-r--r--libgo/sysinfo.c279
-rw-r--r--libgo/testsuite/Makefile.in13
-rwxr-xr-xlibgo/testsuite/gotest188
1919 files changed, 152788 insertions, 59040 deletions
diff --git a/libgo/MERGE b/libgo/MERGE
index a40967cea2..a5808db54f 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-f5cf5673590a68c55b2330df9dfcdd6fac75b893
+a4c18f063b6659079ca2848ca217a0587dabc001
The first line of this file holds the git revision number of the
last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index bae3634cff..515b61b71e 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -42,7 +42,7 @@ ACLOCAL_AMFLAGS = -I ./config -I ../config
AM_CFLAGS = -fexceptions -fnon-call-exceptions -fplan9-extensions \
$(SPLIT_STACK) $(WARN_CFLAGS) \
- $(STRINGOPS_FLAG) $(OSCFLAGS) \
+ $(STRINGOPS_FLAG) $(HWCAP_CFLAGS) $(OSCFLAGS) \
-I $(srcdir)/../libgcc -I $(srcdir)/../libbacktrace \
-I $(MULTIBUILDTOP)../../gcc/include
@@ -105,12 +105,13 @@ toolexeclib_LTLIBRARIES = libgo-llgo.la
toolexeclib_LIBRARIES = libgobegin-llgo.a
else
toolexeclib_LTLIBRARIES = libgo.la
-toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a
+toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
endif
toolexeclibgo_DATA = \
bufio.gox \
bytes.gox \
+ context.gox \
crypto.gox \
encoding.gox \
errors.gox \
@@ -315,6 +316,7 @@ toolexeclibgonethttp_DATA = \
net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
+ net/http/httptrace.gox \
net/http/httputil.gox \
net/http/pprof.gox
@@ -323,12 +325,6 @@ toolexeclibgonetrpcdir = $(toolexeclibgonetdir)/rpc
toolexeclibgonetrpc_DATA = \
net/rpc/jsonrpc.gox
-toolexeclibgoolddir = $(toolexeclibgodir)/old
-
-toolexeclibgoold_DATA = \
- old/regexp.gox \
- old/template.gox
-
toolexeclibgoosdir = $(toolexeclibgodir)/os
toolexeclibgoos_DATA = \
@@ -350,7 +346,8 @@ toolexeclibgoruntimedir = $(toolexeclibgodir)/runtime
toolexeclibgoruntime_DATA = \
runtime/debug.gox \
- runtime/pprof.gox
+ runtime/pprof.gox \
+ runtime/trace.gox
toolexeclibgosyncdir = $(toolexeclibgodir)/sync
@@ -363,6 +360,11 @@ toolexeclibgotesting_DATA = \
testing/iotest.gox \
testing/quick.gox
+toolexeclibgotestinginternaldir = $(toolexeclibgotestingdir)/internal
+
+toolexeclibgotestinginternal_DATA = \
+ testing/internal/testdeps.gox
+
toolexeclibgotextdir = $(toolexeclibgodir)/text
toolexeclibgotext_DATA = \
@@ -394,9 +396,9 @@ rtems_task_variable_add_file =
endif
if LIBGO_IS_LINUX
-runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c
+runtime_thread_files = runtime/thread-linux.c
else
-runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c
+runtime_thread_files = runtime/thread-sema.c
endif
if LIBGO_IS_LINUX
@@ -425,76 +427,31 @@ endif
endif
endif
-if LIBGO_IS_LINUX
-runtime_netpoll_files = runtime/netpoll_epoll.c
-else
-if LIBGO_IS_SOLARIS
-runtime_netpoll_files = runtime/netpoll_select.c
-else
-runtime_netpoll_files = runtime/netpoll_kqueue.c
-endif
-endif
-
runtime_files = \
- runtime/go-append.c \
+ runtime/aeshash.c \
runtime/go-assert.c \
- runtime/go-assert-interface.c \
- runtime/go-byte-array-to-string.c \
runtime/go-breakpoint.c \
runtime/go-caller.c \
runtime/go-callers.c \
- runtime/go-can-convert-interface.c \
runtime/go-cdiv.c \
runtime/go-cgo.c \
- runtime/go-check-interface.c \
runtime/go-construct-map.c \
- runtime/go-convert-interface.c \
- runtime/go-copy.c \
- runtime/go-defer.c \
- runtime/go-deferred-recover.c \
- runtime/go-eface-compare.c \
- runtime/go-eface-val-compare.c \
runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-int-array-to-string.c \
- runtime/go-int-to-string.c \
- runtime/go-interface-compare.c \
- runtime/go-interface-eface-compare.c \
- runtime/go-interface-val-compare.c \
- runtime/go-make-slice.c \
- runtime/go-map-delete.c \
- runtime/go-map-index.c \
- runtime/go-map-len.c \
- runtime/go-map-range.c \
runtime/go-matherr.c \
+ runtime/go-memclr.c \
runtime/go-memcmp.c \
+ runtime/go-memequal.c \
+ runtime/go-memmove.c \
runtime/go-nanotime.c \
runtime/go-now.c \
- runtime/go-new-map.c \
runtime/go-new.c \
runtime/go-nosys.c \
- runtime/go-panic.c \
- runtime/go-print.c \
- runtime/go-recover.c \
runtime/go-reflect-call.c \
- runtime/go-reflect-map.c \
- runtime/go-rune.c \
runtime/go-runtime-error.c \
runtime/go-setenv.c \
runtime/go-signal.c \
- runtime/go-strcmp.c \
- runtime/go-string-to-byte-array.c \
- runtime/go-string-to-int-array.c \
- runtime/go-strplus.c \
runtime/go-strslice.c \
- runtime/go-traceback.c \
- runtime/go-type-complex.c \
- runtime/go-type-eface.c \
- runtime/go-type-error.c \
- runtime/go-type-float.c \
- runtime/go-type-identity.c \
- runtime/go-type-interface.c \
- runtime/go-type-string.c \
runtime/go-typedesc-equal.c \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
@@ -504,7 +461,6 @@ runtime_files = \
runtime/go-varargs.c \
runtime/env_posix.c \
runtime/heapdump.c \
- $(runtime_lock_files) \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
@@ -512,31 +468,16 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
- $(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
runtime/proc.c \
- runtime/runtime.c \
- runtime/signal_unix.c \
+ runtime/runtime_c.c \
runtime/thread.c \
+ $(runtime_thread_files) \
runtime/yield.c \
$(rtems_task_variable_add_file) \
- chan.c \
- cpuprof.c \
- go-iface.c \
- lfstack.c \
malloc.c \
- map.c \
- mprof.c \
- netpoll.c \
- rdebug.c \
- reflect.c \
- runtime1.c \
- sema.c \
- sigqueue.c \
- string.c \
- time.c \
$(runtime_getncpu_file)
goc2c.$(OBJEXT): runtime/goc2c.c
@@ -549,519 +490,86 @@ malloc.c: $(srcdir)/runtime/malloc.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
-mprof.c: $(srcdir)/runtime/mprof.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-reflect.c: $(srcdir)/runtime/reflect.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-sema.c: $(srcdir)/runtime/sema.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
- ./goc2c --go-pkgpath os_signal $< > $@.tmp
- mv -f $@.tmp $@
-
-time.c: $(srcdir)/runtime/time.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
%.c: $(srcdir)/runtime/%.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
-go_bufio_files = \
- go/bufio/bufio.go \
- go/bufio/scan.go
-
-go_bytes_files = \
- go/bytes/buffer.go \
- go/bytes/bytes.go \
- go/bytes/bytes_decl.go \
- go/bytes/reader.go
-go_bytes_c_files = \
- go/bytes/indexbyte.c
-
-go_crypto_files = \
- go/crypto/crypto.go
-
-go_encoding_files = \
- go/encoding/encoding.go
-
-go_errors_files = \
- go/errors/errors.go
-
-go_expvar_files = \
- go/expvar/expvar.go
-
-go_flag_files = \
- go/flag/flag.go
-
-go_fmt_files = \
- go/fmt/doc.go \
- go/fmt/format.go \
- go/fmt/print.go \
- go/fmt/scan.go
-
-go_hash_files = \
- go/hash/hash.go
-
-go_html_files = \
- go/html/entity.go \
- go/html/escape.go
-
-go_image_files = \
- go/image/format.go \
- go/image/geom.go \
- go/image/image.go \
- go/image/names.go \
- go/image/ycbcr.go
-
-go_io_files = \
- go/io/multi.go \
- go/io/io.go \
- go/io/pipe.go
-
-go_log_files = \
- go/log/log.go
-
-go_math_files = \
- go/math/abs.go \
- go/math/acosh.go \
- go/math/asin.go \
- go/math/asinh.go \
- go/math/atan.go \
- go/math/atanh.go \
- go/math/atan2.go \
- go/math/bits.go \
- go/math/cbrt.go \
- go/math/const.go \
- go/math/copysign.go \
- go/math/dim.go \
- go/math/erf.go \
- go/math/exp.go \
- go/math/expm1.go \
- go/math/floor.go \
- go/math/frexp.go \
- go/math/gamma.go \
- go/math/hypot.go \
- go/math/j0.go \
- go/math/j1.go \
- go/math/jn.go \
- go/math/ldexp.go \
- go/math/lgamma.go \
- go/math/log.go \
- go/math/log1p.go \
- go/math/log10.go \
- go/math/logb.go \
- go/math/mod.go \
- go/math/modf.go \
- go/math/nextafter.go \
- go/math/pow.go \
- go/math/pow10.go \
- go/math/remainder.go \
- go/math/signbit.go \
- go/math/sin.go \
- go/math/sincos.go \
- go/math/sinh.go \
- go/math/sqrt.go \
- go/math/tan.go \
- go/math/tanh.go \
- go/math/unsafe.go
-
-if LIBGO_IS_OPENBSD
-go_mime_type_file = go/mime/type_openbsd.go
-else
-if LIBGO_IS_FREEBSD
-go_mime_type_file = go/mime/type_freebsd.go
-else
-if LIBGO_IS_DRAGONFLY
-go_mime_type_file = go/mime/type_dragonfly.go
-else
-go_mime_type_file =
-endif
-endif
-endif
-
-go_mime_files = \
- go/mime/encodedword.go \
- go/mime/grammar.go \
- go/mime/mediatype.go \
- go/mime/type.go \
- go/mime/type_unix.go \
- $(go_mime_type_file)
-
-if LIBGO_IS_LINUX
-go_net_cgo_file = go/net/cgo_linux.go
-go_net_sock_file = go/net/sock_linux.go
-go_net_sockopt_file = go/net/sockopt_linux.go
-go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
-go_net_cgo_sock_file = go/net/cgo_socknew.go
-go_net_cgo_res_file = go/net/cgo_resnew.go
-else
-if LIBGO_IS_IRIX
-go_net_cgo_file = go/net/cgo_linux.go
-go_net_sock_file = go/net/sock_linux.go
-go_net_sockopt_file = go/net/sockopt_linux.go
-go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
-go_net_cgo_sock_file = go/net/cgo_socknew.go
-go_net_cgo_res_file = go/net/cgo_resnew.go
-else
-if LIBGO_IS_SOLARIS
-go_net_cgo_file = go/net/cgo_solaris.go
-go_net_sock_file = go/net/sock_stub.go
-go_net_sockopt_file = go/net/sockopt_solaris.go
-go_net_sockoptip_file = go/net/sockoptip_stub.go
-go_net_cgo_sock_file = go/net/cgo_socknew.go
-go_net_cgo_res_file = go/net/cgo_resnew.go
-else
-if LIBGO_IS_FREEBSD
-go_net_cgo_file = go/net/cgo_bsd.go
-go_net_sock_file = go/net/sock_bsd.go
-go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-go_net_cgo_sock_file = go/net/cgo_sockold.go
-go_net_cgo_res_file = go/net/cgo_resold.go
-else
-if LIBGO_IS_NETBSD
-go_net_cgo_file = go/net/cgo_netbsd.go
-go_net_sock_file = go/net/sock_bsd.go
-go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-go_net_cgo_sock_file = go/net/cgo_sockold.go
-go_net_cgo_res_file = go/net/cgo_resnew.go
-else
-go_net_cgo_file = go/net/cgo_bsd.go
-go_net_sock_file = go/net/sock_bsd.go
-go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-go_net_cgo_sock_file = go/net/cgo_sockold.go
-go_net_cgo_res_file = go/net/cgo_resold.go
-endif
-endif
-endif
-endif
-endif
-
-if LIBGO_IS_LINUX
-go_net_sendfile_file = go/net/sendfile_linux.go
-else
-if LIBGO_IS_FREEBSD
-go_net_sendfile_file = go/net/sendfile_freebsd.go
-else
-if LIBGO_IS_DRAGONFLY
-go_net_sendfile_file = go/net/sendfile_dragonfly.go
-else
-if LIBGO_IS_SOLARIS
-go_net_sendfile_file = go/net/sendfile_solaris.go
-else
-go_net_sendfile_file = go/net/sendfile_stub.go
-endif
-endif
-endif
-endif
-
-if LIBGO_IS_LINUX
-go_net_interface_file = go/net/interface_linux.go
-else
-if LIBGO_IS_NETBSD
-go_net_interface_file = go/net/interface_netbsd.go
-else
-if LIBGO_IS_DRAGONFLY
-go_net_interface_file = go/net/interface_dragonfly.go
-else
-go_net_interface_file = go/net/interface_stub.go
-endif
-endif
-endif
-
-if LIBGO_IS_LINUX
-go_net_cloexec_file = go/net/sock_cloexec.go go/net/hook_cloexec.go
-else
-if LIBGO_IS_FREEBSD
-go_net_cloexec_file = go/net/sock_cloexec.go go/net/hook_cloexec.go
-else
-go_net_cloexec_file = go/net/sys_cloexec.go
-endif
-endif
-
-if LIBGO_IS_OPENBSD
-go_net_tcpsockopt_file = go/net/tcpsockopt_openbsd.go
-else
-if LIBGO_IS_DARWIN
-go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
-else
-if LIBGO_IS_SOLARIS
-go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
-else
-if LIBGO_IS_DRAGONFLY
-go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
-else
-go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
-endif
-endif
-endif
-endif
-
-go_net_common_files = \
- go/net/addrselect.go \
- $(go_net_cloexec_file) \
- go/net/conf.go \
- go/net/dial.go \
- go/net/dnsclient.go \
- go/net/dnsclient_unix.go \
- go/net/dnsconfig_unix.go \
- go/net/dnsmsg.go \
- go/net/fd_mutex.go \
- go/net/fd_posix.go \
- go/net/fd_unix.go \
- go/net/file.go \
- go/net/file_unix.go \
- go/net/hook.go \
- go/net/hook_unix.go \
- go/net/hosts.go \
- go/net/interface.go \
- $(go_net_interface_file) \
- go/net/ip.go \
- go/net/iprawsock.go \
- go/net/iprawsock_posix.go \
- go/net/ipsock.go \
- go/net/ipsock_posix.go \
- go/net/lookup.go \
- go/net/lookup_unix.go \
- go/net/mac.go \
- go/net/net.go \
- go/net/nss.go \
- go/net/parse.go \
- go/net/pipe.go \
- go/net/fd_poll_runtime.go \
- go/net/port_unix.go \
- $(go_net_sendfile_file) \
- go/net/sock_posix.go \
- $(go_net_sock_file) \
- go/net/sockopt_posix.go \
- $(go_net_sockopt_file) \
- $(go_net_sockoptip_file) \
- go/net/tcpsock.go \
- go/net/tcpsock_posix.go \
- go/net/tcpsockopt_posix.go \
- $(go_net_tcpsockopt_file) \
- go/net/udpsock.go \
- go/net/udpsock_posix.go \
- go/net/unixsock.go \
- go/net/unixsock_posix.go
-
-go_net_files = \
- go/net/cgo_unix.go \
- $(go_net_cgo_file) \
- $(go_net_cgo_res_file) \
- $(go_net_cgo_sock_file) \
- $(go_net_common_files)
-
-go_netgo_files = \
- go/net/cgo_stub.go \
- $(go_net_common_files)
-
-if LIBGO_IS_SOLARIS
-if LIBGO_IS_386
-go_os_dir_file = go/os/dir_largefile.go
-else
-if LIBGO_IS_SPARC
-go_os_dir_file = go/os/dir_largefile.go
-else
-go_os_dir_file = go/os/dir_regfile.go
-endif
-endif
-else
-if LIBGO_IS_LINUX
-go_os_dir_file = go/os/dir_largefile.go
-else
-go_os_dir_file = go/os/dir_regfile.go
-endif
-endif
-
-if LIBGO_IS_DARWIN
-go_os_getwd_file = go/os/getwd_darwin.go
-else
-go_os_getwd_file =
-endif
-
-if LIBGO_IS_LINUX
-go_os_sys_file = go/os/sys_linux.go
-else
-if LIBGO_IS_SOLARIS
-go_os_sys_file = go/os/sys_uname.go
-else
-if LIBGO_IS_IRIX
-go_os_sys_file = go/os/sys_uname.go
-else
-if LIBGO_IS_RTEMS
-go_os_sys_file = go/os/sys_uname.go
-else
-go_os_sys_file = go/os/sys_bsd.go
-endif
-endif
-endif
-endif
-
-if LIBGO_IS_FREEBSD
-go_os_cloexec_file = go/os/sys_freebsd.go
-else
-if LIBGO_IS_DARWIN
-go_os_cloexec_file = go/os/sys_darwin.go
-else
-go_os_cloexec_file = go/os/sys_unix.go
-endif
-endif
-
-if LIBGO_IS_SOLARIS
-if HAVE_STAT_TIMESPEC
-go_os_stat_file = go/os/stat_atim.go
-else
-go_os_stat_file = go/os/stat_solaris.go
-endif
-else
-if LIBGO_IS_LINUX
-go_os_stat_file = go/os/stat_atim.go
-else
-if LIBGO_IS_OPENBSD
-go_os_stat_file = go/os/stat_atim.go
-else
-if LIBGO_IS_DARWIN
-go_os_stat_file = go/os/stat_atimespec.go
-else
-if LIBGO_IS_FREEBSD
-go_os_stat_file = go/os/stat_atimespec.go
-else
-if LIBGO_IS_NETBSD
-go_os_stat_file = go/os/stat_atimespec.go
-else
-if LIBGO_IS_DRAGONFLY
-go_os_stat_file = go/os/stat_dragonfly.go
-else
-go_os_stat_file = go/os/stat.go
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-
-if LIBGO_IS_LINUX
-go_os_pipe_file = go/os/pipe_linux.go
-else
-go_os_pipe_file = go/os/pipe_bsd.go
-endif
-
-if LIBGO_IS_DARWIN
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-if LIBGO_IS_DRAGONFLY
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-if LIBGO_IS_FREEBSD
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-if LIBGO_IS_NETBSD
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-if LIBGO_IS_OPENBSD
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-if LIBGO_IS_SOLARIS
-go_os_sticky_file = go/os/sticky_bsd.go
-else
-go_os_sticky_file = go/os/sticky_notbsd.go
-endif
-endif
-endif
-endif
-endif
-endif
-
-go_os_files = \
- $(go_os_dir_file) \
- go/os/dir.go \
- go/os/doc.go \
- go/os/env.go \
- go/os/error.go \
- go/os/error_unix.go \
- go/os/exec.go \
- go/os/exec_posix.go \
- go/os/exec_unix.go \
- go/os/file.go \
- go/os/file_posix.go \
- go/os/file_unix.go \
- go/os/getwd.go \
- $(go_os_getwd_file) \
- go/os/path.go \
- go/os/path_unix.go \
- $(go_os_pipe_file) \
- go/os/proc.go \
- $(go_os_stat_file) \
- $(go_os_sticky_file) \
- go/os/str.go \
- $(go_os_sys_file) \
- $(go_os_cloexec_file) \
- go/os/types.go \
- go/os/types_unix.go
-
-go_path_files = \
- go/path/match.go \
- go/path/path.go
-
-go_reflect_files = \
- go/reflect/deepequal.go \
- go/reflect/makefunc.go \
- go/reflect/makefunc_ffi.go \
- go/reflect/type.go \
- go/reflect/value.go
-go_reflect_makefunc_c_file = \
- go/reflect/makefunc_ffi_c.c
-
-go_regexp_files = \
- go/regexp/backtrack.go \
- go/regexp/exec.go \
- go/regexp/onepass.go \
- go/regexp/regexp.go
-
-go_net_rpc_files = \
- go/net/rpc/client.go \
- go/net/rpc/debug.go \
- go/net/rpc/server.go
-
-go_runtime_files = \
- go/runtime/compiler.go \
- go/runtime/debug.go \
- go/runtime/error.go \
- go/runtime/extern.go \
- go/runtime/mem.go \
- version.go
-
version.go: s-version; @true
s-version: Makefile
rm -f version.go.tmp
- echo "package runtime" > version.go.tmp
- echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
- echo 'const theVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
- echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
- echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
- echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ echo "package sys" > version.go.tmp
+ echo 'const DefaultGoroot = "$(prefix)"' >> version.go.tmp
+ echo 'const TheVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const GOARCH = "'$(GOARCH)'"' >> version.go.tmp
+ echo 'const GOOS = "'$(GOOS)'"' >> version.go.tmp
+ echo 'const GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ echo >> version.go.tmp
+ echo "type ArchFamilyType int" >> version.go.tmp
+ echo >> version.go.tmp
+ echo "const (" >> version.go.tmp
+ echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
+ for a in $(ALLGOARCHFAMILY); do \
+ echo " $${a}" >> version.go.tmp; \
+ done
+ echo ")" >> version.go.tmp
+ echo >> version.go.tmp
+ for a in $(ALLGOARCH); do \
+ f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
+ n="$${f}`echo $${a} | sed -e 's/.//'`"; \
+ if test "$${a}" = "$(GOARCH)"; then \
+ echo "const Goarch$${n} = 1" >> version.go.tmp; \
+ else \
+ echo "const Goarch$${n} = 0" >> version.go.tmp; \
+ fi; \
+ done
+ echo >> version.go.tmp
+ echo "const (" >> version.go.tmp
+ echo " ArchFamily = $(GOARCH_FAMILY)" >> version.go.tmp
+ echo " BigEndian = $(GOARCH_BIGENDIAN)" >> version.go.tmp
+ echo " CacheLineSize = $(GOARCH_CACHELINESIZE)" >> version.go.tmp
+ echo " PhysPageSize = $(GOARCH_PHYSPAGESIZE)" >> version.go.tmp
+ echo " PCQuantum = $(GOARCH_PCQUANTUM)" >> version.go.tmp
+ echo " Int64Align = $(GOARCH_INT64ALIGN)" >> version.go.tmp
+ echo " HugePageSize = $(GOARCH_HUGEPAGESIZE)" >> version.go.tmp
+ echo " MinFrameSize = $(GOARCH_MINFRAMESIZE)" >> version.go.tmp
+ echo ")" >> version.go.tmp
+ echo >> version.go.tmp
+ for a in $(ALLGOOS); do \
+ f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
+ n="$${f}`echo $${a} | sed -e 's/.//'`"; \
+ if test "$${a}" = "$(GOOS)"; then \
+ echo "const Goos$${n} = 1" >> version.go.tmp; \
+ else \
+ echo "const Goos$${n} = 0" >> version.go.tmp; \
+ fi; \
+ done
+ echo >> version.go.tmp
+ echo "type Uintreg uintptr" >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@
+runtime_sysinfo.go: s-runtime_sysinfo; @true
+s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
+ $(SHELL) $(srcdir)/mkrsysinfo.sh
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
+ $(STAMP) $@
+
+sigtab.go: s-sigtab; @true
+s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
+ GOOS=$(GOOS) $(SHELL) $(srcdir)/mksigtab.sh > tmp-sigtab.go
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
+ $(STAMP) $@
+
+runtime.inc: s-runtime-inc; @true
+s-runtime-inc: runtime.lo Makefile
+ rm -f runtime.inc.tmp2
+ grep -v "#define _" runtime.inc.tmp | grep -v "#define [cm][01234] " > runtime.inc.tmp2
+ for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
+ grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
+ done
+ $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
+ $(STAMP) $@
+
noinst_DATA = zstdpkglist.go
# Generate the list of go std packages that were included in libgo
@@ -1071,1025 +579,28 @@ s-zstdpkglist: Makefile
echo 'package main' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
- echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | grep -v _c | sed 's/\.lo/\": true,/' | sed 's/^/\t\"/' | sort -u >> zstdpkglist.go.tmp
echo '}' >> zstdpkglist.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
-go_sort_files = \
- go/sort/search.go \
- go/sort/sort.go
-
-go_strconv_files = \
- go/strconv/atob.go \
- go/strconv/atof.go \
- go/strconv/atoi.go \
- go/strconv/decimal.go \
- go/strconv/doc.go \
- go/strconv/extfloat.go \
- go/strconv/ftoa.go \
- go/strconv/isprint.go \
- go/strconv/itoa.go \
- go/strconv/quote.go
-
-go_strings_files = \
- go/strings/compare.go \
- go/strings/reader.go \
- go/strings/replace.go \
- go/strings/search.go \
- go/strings/strings.go \
- go/strings/strings_decl.go \
- go/strings/strings_generic.go
-go_strings_c_files = \
- go/strings/indexbyte.c
-
-go_sync_files = \
- go/sync/cond.go \
- go/sync/mutex.go \
- go/sync/once.go \
- go/sync/pool.go \
- go/sync/runtime.go \
- go/sync/rwmutex.go \
- go/sync/waitgroup.go
-
-if LIBGO_IS_SOLARIS
-go_syslog_file = go/log/syslog/syslog_libc.go
-else
-if LIBGO_IS_IRIX
-go_syslog_file = go/log/syslog/syslog_libc.go
-else
-go_syslog_file = go/log/syslog/syslog_unix.go
-endif
-endif
-
-go_log_syslog_files = \
- go/log/syslog/doc.go \
- go/log/syslog/syslog.go \
- $(go_syslog_file)
-go_syslog_c_files = \
- go/log/syslog/syslog_c.c
-
-go_testing_files = \
- go/testing/allocs.go \
- go/testing/benchmark.go \
- go/testing/cover.go \
- go/testing/example.go \
- go/testing/testing.go
-
-go_time_files = \
- go/time/format.go \
- go/time/sleep.go \
- go/time/sys_unix.go \
- go/time/tick.go \
- go/time/time.go \
- go/time/zoneinfo.go \
- go/time/zoneinfo_read.go \
- go/time/zoneinfo_unix.go
-
-go_unicode_files = \
- go/unicode/casetables.go \
- go/unicode/digit.go \
- go/unicode/graphic.go \
- go/unicode/letter.go \
- go/unicode/tables.go
-
if LIBGO_IS_LINUX
-archive_tar_atim_file = go/archive/tar/stat_atim.go
-endif
-if LIBGO_IS_OPENBSD
-archive_tar_atim_file = go/archive/tar/stat_atim.go
-endif
-if LIBGO_IS_SOLARIS
-archive_tar_atim_file = go/archive/tar/stat_atim.go
-endif
-if LIBGO_IS_DARWIN
-archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-endif
-if LIBGO_IS_FREEBSD
-archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-endif
-if LIBGO_IS_NETBSD
-archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-endif
-
-go_archive_tar_files = \
- go/archive/tar/common.go \
- go/archive/tar/reader.go \
- go/archive/tar/stat_unix.go \
- go/archive/tar/writer.go \
- $(archive_tar_atim_file)
-
-go_archive_zip_files = \
- go/archive/zip/reader.go \
- go/archive/zip/register.go \
- go/archive/zip/struct.go \
- go/archive/zip/writer.go
-
-go_compress_bzip2_files = \
- go/compress/bzip2/bit_reader.go \
- go/compress/bzip2/bzip2.go \
- go/compress/bzip2/huffman.go \
- go/compress/bzip2/move_to_front.go
-
-go_compress_flate_files = \
- go/compress/flate/copy.go \
- go/compress/flate/deflate.go \
- go/compress/flate/huffman_bit_writer.go \
- go/compress/flate/huffman_code.go \
- go/compress/flate/inflate.go \
- go/compress/flate/reverse_bits.go \
- go/compress/flate/token.go
-
-go_compress_gzip_files = \
- go/compress/gzip/gzip.go \
- go/compress/gzip/gunzip.go
-
-go_compress_lzw_files = \
- go/compress/lzw/reader.go \
- go/compress/lzw/writer.go
-
-go_compress_zlib_files = \
- go/compress/zlib/reader.go \
- go/compress/zlib/writer.go
-
-go_container_heap_files = \
- go/container/heap/heap.go
-
-go_container_list_files = \
- go/container/list/list.go
-
-go_container_ring_files = \
- go/container/ring/ring.go
-
-go_crypto_aes_files = \
- go/crypto/aes/block.go \
- go/crypto/aes/cipher.go \
- go/crypto/aes/cipher_generic.go \
- go/crypto/aes/const.go
-go_crypto_cipher_files = \
- go/crypto/cipher/cbc.go \
- go/crypto/cipher/cfb.go \
- go/crypto/cipher/cipher.go \
- go/crypto/cipher/ctr.go \
- go/crypto/cipher/gcm.go \
- go/crypto/cipher/io.go \
- go/crypto/cipher/ofb.go \
- go/crypto/cipher/xor.go
-go_crypto_des_files = \
- go/crypto/des/block.go \
- go/crypto/des/cipher.go \
- go/crypto/des/const.go
-go_crypto_dsa_files = \
- go/crypto/dsa/dsa.go
-go_crypto_ecdsa_files = \
- go/crypto/ecdsa/ecdsa.go
-go_crypto_elliptic_files = \
- go/crypto/elliptic/elliptic.go \
- go/crypto/elliptic/p224.go \
- go/crypto/elliptic/p256.go
-go_crypto_hmac_files = \
- go/crypto/hmac/hmac.go
-go_crypto_md5_files = \
- go/crypto/md5/md5.go \
- go/crypto/md5/md5block.go \
- go/crypto/md5/md5block_generic.go
-
-if LIBGO_IS_LINUX
-crypto_rand_file = go/crypto/rand/rand_linux.go
-else
-crypto_rand_file =
-endif
-
-go_crypto_rand_files = \
- go/crypto/rand/eagain.go \
- go/crypto/rand/rand.go \
- go/crypto/rand/rand_unix.go \
- $(crypto_rand_file) \
- go/crypto/rand/util.go
-
-go_crypto_rc4_files = \
- go/crypto/rc4/rc4.go \
- go/crypto/rc4/rc4_ref.go
-go_crypto_rsa_files = \
- go/crypto/rsa/pkcs1v15.go \
- go/crypto/rsa/pss.go \
- go/crypto/rsa/rsa.go
-go_crypto_sha1_files = \
- go/crypto/sha1/sha1.go \
- go/crypto/sha1/sha1block.go \
- go/crypto/sha1/sha1block_generic.go
-go_crypto_sha256_files = \
- go/crypto/sha256/sha256.go \
- go/crypto/sha256/sha256block.go
-go_crypto_sha512_files = \
- go/crypto/sha512/sha512.go \
- go/crypto/sha512/sha512block.go
-go_crypto_subtle_files = \
- go/crypto/subtle/constant_time.go
-go_crypto_tls_files = \
- go/crypto/tls/alert.go \
- go/crypto/tls/cipher_suites.go \
- go/crypto/tls/common.go \
- go/crypto/tls/conn.go \
- go/crypto/tls/handshake_client.go \
- go/crypto/tls/handshake_messages.go \
- go/crypto/tls/handshake_server.go \
- go/crypto/tls/key_agreement.go \
- go/crypto/tls/prf.go \
- go/crypto/tls/ticket.go \
- go/crypto/tls/tls.go
-
-if LIBGO_IS_LINUX
-go_crypto_x509_root_file = go/crypto/x509/root_linux.go
-else
-if LIBGO_IS_SOLARIS
-go_crypto_x509_root_file = go/crypto/x509/root_solaris.go
-else
-if LIBGO_IS_DRAGONFLY
-go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-else
-if LIBGO_IS_FREEBSD
-go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-else
-if LIBGO_IS_NETBSD
-go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-else
-if LIBGO_IS_OPENBSD
-go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-else
-if LIBGO_IS_DARWIN
-go_crypto_x509_root_file = go/crypto/x509/root_darwin.go
-else
-go_crypto_x509_root_file =
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-
-go_crypto_x509_files = \
- go/crypto/x509/cert_pool.go \
- go/crypto/x509/pem_decrypt.go \
- go/crypto/x509/pkcs1.go \
- go/crypto/x509/pkcs8.go \
- go/crypto/x509/root.go \
- go/crypto/x509/root_unix.go \
- $(go_crypto_x509_root_file) \
- go/crypto/x509/sec1.go \
- go/crypto/x509/verify.go \
- go/crypto/x509/x509.go
-
-go_crypto_x509_pkix_files = \
- go/crypto/x509/pkix/pkix.go
-
-go_database_sql_files = \
- go/database/sql/convert.go \
- go/database/sql/sql.go
-
-go_database_sql_driver_files = \
- go/database/sql/driver/driver.go \
- go/database/sql/driver/types.go
-
-go_debug_dwarf_files = \
- go/debug/dwarf/buf.go \
- go/debug/dwarf/class_string.go \
- go/debug/dwarf/const.go \
- go/debug/dwarf/entry.go \
- go/debug/dwarf/line.go \
- go/debug/dwarf/open.go \
- go/debug/dwarf/type.go \
- go/debug/dwarf/typeunit.go \
- go/debug/dwarf/unit.go
-go_debug_elf_files = \
- go/debug/elf/elf.go \
- go/debug/elf/file.go \
- go/debug/elf/reader.go
-go_debug_gosym_files = \
- go/debug/gosym/pclntab.go \
- go/debug/gosym/symtab.go
-go_debug_macho_files = \
- go/debug/macho/fat.go \
- go/debug/macho/file.go \
- go/debug/macho/macho.go
-go_debug_pe_files = \
- go/debug/pe/file.go \
- go/debug/pe/pe.go
-go_debug_plan9obj_files = \
- go/debug/plan9obj/file.go \
- go/debug/plan9obj/plan9obj.go
-
-go_encoding_ascii85_files = \
- go/encoding/ascii85/ascii85.go
-go_encoding_asn1_files = \
- go/encoding/asn1/asn1.go \
- go/encoding/asn1/common.go \
- go/encoding/asn1/marshal.go
-go_encoding_base32_files = \
- go/encoding/base32/base32.go
-go_encoding_base64_files = \
- go/encoding/base64/base64.go
-go_encoding_binary_files = \
- go/encoding/binary/binary.go \
- go/encoding/binary/varint.go
-go_encoding_csv_files = \
- go/encoding/csv/reader.go \
- go/encoding/csv/writer.go
-go_encoding_gob_files = \
- go/encoding/gob/decode.go \
- go/encoding/gob/decoder.go \
- go/encoding/gob/dec_helpers.go \
- go/encoding/gob/doc.go \
- go/encoding/gob/encode.go \
- go/encoding/gob/encoder.go \
- go/encoding/gob/enc_helpers.go \
- go/encoding/gob/error.go \
- go/encoding/gob/type.go
-go_encoding_hex_files = \
- go/encoding/hex/hex.go
-go_encoding_json_files = \
- go/encoding/json/decode.go \
- go/encoding/json/encode.go \
- go/encoding/json/fold.go \
- go/encoding/json/indent.go \
- go/encoding/json/scanner.go \
- go/encoding/json/stream.go \
- go/encoding/json/tags.go
-go_encoding_pem_files = \
- go/encoding/pem/pem.go
-go_encoding_xml_files = \
- go/encoding/xml/marshal.go \
- go/encoding/xml/read.go \
- go/encoding/xml/typeinfo.go \
- go/encoding/xml/xml.go
-
-go_exp_proxy_files = \
- go/exp/proxy/direct.go \
- go/exp/proxy/per_host.go \
- go/exp/proxy/proxy.go \
- go/exp/proxy/socks5.go
-go_exp_terminal_files = \
- go/exp/terminal/terminal.go \
- go/exp/terminal/util.go
-
-go_go_ast_files = \
- go/go/ast/ast.go \
- go/go/ast/commentmap.go \
- go/go/ast/filter.go \
- go/go/ast/import.go \
- go/go/ast/print.go \
- go/go/ast/resolve.go \
- go/go/ast/scope.go \
- go/go/ast/walk.go
-go_go_build_files = \
- go/go/build/build.go \
- go/go/build/doc.go \
- go/go/build/read.go \
- go/go/build/syslist.go
-go_go_constant_files = \
- go/go/constant/value.go
-go_go_doc_files = \
- go/go/doc/comment.go \
- go/go/doc/doc.go \
- go/go/doc/example.go \
- go/go/doc/exports.go \
- go/go/doc/filter.go \
- go/go/doc/reader.go \
- go/go/doc/synopsis.go
-go_go_format_files = \
- go/go/format/format.go \
- go/go/format/internal.go
-go_go_importer_files = \
- go/go/importer/importer.go
-go_go_parser_files = \
- go/go/parser/interface.go \
- go/go/parser/parser.go
-go_go_printer_files = \
- go/go/printer/nodes.go \
- go/go/printer/printer.go
-go_go_scanner_files = \
- go/go/scanner/errors.go \
- go/go/scanner/scanner.go
-go_go_token_files = \
- go/go/token/position.go \
- go/go/token/serialize.go \
- go/go/token/token.go
-go_go_types_files = \
- go/go/types/api.go \
- go/go/types/assignments.go \
- go/go/types/builtins.go \
- go/go/types/call.go \
- go/go/types/check.go \
- go/go/types/conversions.go \
- go/go/types/decl.go \
- go/go/types/errors.go \
- go/go/types/eval.go \
- go/go/types/expr.go \
- go/go/types/exprstring.go \
- go/go/types/initorder.go \
- go/go/types/labels.go \
- go/go/types/lookup.go \
- go/go/types/methodset.go \
- go/go/types/object.go \
- go/go/types/objset.go \
- go/go/types/operand.go \
- go/go/types/ordering.go \
- go/go/types/package.go \
- go/go/types/predicates.go \
- go/go/types/resolver.go \
- go/go/types/return.go \
- go/go/types/scope.go \
- go/go/types/selection.go \
- go/go/types/stmt.go \
- go/go/types/sizes.go \
- go/go/types/type.go \
- go/go/types/typestring.go \
- go/go/types/typexpr.go \
- go/go/types/universe.go
-
-go_go_internal_gcimporter_files = \
- go/go/internal/gcimporter/bimport.go \
- go/go/internal/gcimporter/exportdata.go \
- go/go/internal/gcimporter/gcimporter.go
-go_go_internal_gccgoimporter_files = \
- go/go/internal/gccgoimporter/gccgoinstallation.go \
- go/go/internal/gccgoimporter/importer.go \
- go/go/internal/gccgoimporter/parser.go
-
-go_hash_adler32_files = \
- go/hash/adler32/adler32.go
-go_hash_crc32_files = \
- go/hash/crc32/crc32.go \
- go/hash/crc32/crc32_generic.go
-go_hash_crc64_files = \
- go/hash/crc64/crc64.go
-go_hash_fnv_files = \
- go/hash/fnv/fnv.go
-
-go_html_template_files = \
- go/html/template/attr.go \
- go/html/template/content.go \
- go/html/template/context.go \
- go/html/template/css.go \
- go/html/template/doc.go \
- go/html/template/error.go \
- go/html/template/escape.go \
- go/html/template/html.go \
- go/html/template/js.go \
- go/html/template/template.go \
- go/html/template/transition.go \
- go/html/template/url.go
-
-go_image_color_files = \
- go/image/color/color.go \
- go/image/color/ycbcr.go
-
-go_image_color_palette_files = \
- go/image/color/palette/palette.go
-
-go_image_draw_files = \
- go/image/draw/draw.go
-
-go_image_gif_files = \
- go/image/gif/reader.go \
- go/image/gif/writer.go
-
-go_image_internal_imageutil_files = \
- go/image/internal/imageutil/imageutil.go \
- go/image/internal/imageutil/impl.go
-
-go_image_jpeg_files = \
- go/image/jpeg/fdct.go \
- go/image/jpeg/huffman.go \
- go/image/jpeg/idct.go \
- go/image/jpeg/reader.go \
- go/image/jpeg/scan.go \
- go/image/jpeg/writer.go
-
-go_image_png_files = \
- go/image/png/paeth.go \
- go/image/png/reader.go \
- go/image/png/writer.go
-
-go_index_suffixarray_files = \
- go/index/suffixarray/qsufsort.go \
- go/index/suffixarray/suffixarray.go
-
-go_internal_golang_org_x_net_http2_hpack_files = \
- go/internal/golang.org/x/net/http2/hpack/encode.go \
- go/internal/golang.org/x/net/http2/hpack/hpack.go \
- go/internal/golang.org/x/net/http2/hpack/huffman.go \
- go/internal/golang.org/x/net/http2/hpack/tables.go
-go_internal_race_files = \
- go/internal/race/doc.go \
- go/internal/race/norace.go
-go_internal_singleflight_files = \
- go/internal/singleflight/singleflight.go
-
-if LIBGO_IS_LINUX
-if LIBGO_IS_386
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_386.go
-else
-if LIBGO_IS_X86_64
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_amd64.go
-else
-if LIBGO_IS_ARM
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_arm.go
-else
-if LIBGO_IS_PPC64
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_ppc64x.go
-else
-if LIBGO_IS_MIPS64
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_mips64x.go
-else
-internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_generic.go
-endif
-endif
-endif
-endif
-endif
-else
-internal_syscall_unix_getrandom_files =
-endif
-
-go_internal_syscall_unix_files = \
- go/internal/syscall/unix/dummy.go \
- $(internal_syscall_unix_getrandom_files)
-
-go_internal_testenv_files = \
- go/internal/testenv/testenv.go
-go_internal_trace_files = \
- go/internal/trace/goroutines.go \
- go/internal/trace/parser.go
-
-go_io_ioutil_files = \
- go/io/ioutil/ioutil.go \
- go/io/ioutil/tempfile.go
-
-go_math_big_files = \
- go/math/big/accuracy_string.go \
- go/math/big/arith.go \
- go/math/big/arith_decl_pure.go \
- go/math/big/decimal.go \
- go/math/big/doc.go \
- go/math/big/float.go \
- go/math/big/floatconv.go \
- go/math/big/floatmarsh.go \
- go/math/big/ftoa.go \
- go/math/big/int.go \
- go/math/big/intmarsh.go \
- go/math/big/intconv.go \
- go/math/big/nat.go \
- go/math/big/natconv.go \
- go/math/big/rat.go \
- go/math/big/ratconv.go \
- go/math/big/ratmarsh.go \
- go/math/big/roundingmode_string.go
-go_math_cmplx_files = \
- go/math/cmplx/abs.go \
- go/math/cmplx/asin.go \
- go/math/cmplx/conj.go \
- go/math/cmplx/exp.go \
- go/math/cmplx/isinf.go \
- go/math/cmplx/isnan.go \
- go/math/cmplx/log.go \
- go/math/cmplx/phase.go \
- go/math/cmplx/polar.go \
- go/math/cmplx/pow.go \
- go/math/cmplx/rect.go \
- go/math/cmplx/sin.go \
- go/math/cmplx/sqrt.go \
- go/math/cmplx/tan.go
-go_math_rand_files = \
- go/math/rand/exp.go \
- go/math/rand/normal.go \
- go/math/rand/rand.go \
- go/math/rand/rng.go \
- go/math/rand/zipf.go
-
-go_mime_multipart_files = \
- go/mime/multipart/formdata.go \
- go/mime/multipart/multipart.go \
- go/mime/multipart/writer.go
-
-go_mime_quotedprintable_files = \
- go/mime/quotedprintable/reader.go \
- go/mime/quotedprintable/writer.go
-
-go_net_http_files = \
- go/net/http/client.go \
- go/net/http/cookie.go \
- go/net/http/filetransport.go \
- go/net/http/fs.go \
- go/net/http/h2_bundle.go \
- go/net/http/header.go \
- go/net/http/jar.go \
- go/net/http/lex.go \
- go/net/http/method.go \
- go/net/http/request.go \
- go/net/http/response.go \
- go/net/http/server.go \
- go/net/http/sniff.go \
- go/net/http/status.go \
- go/net/http/transfer.go \
- go/net/http/transport.go
-go_net_mail_files = \
- go/net/mail/message.go
-go_net_smtp_files = \
- go/net/smtp/auth.go \
- go/net/smtp/smtp.go
-go_net_textproto_files = \
- go/net/textproto/header.go \
- go/net/textproto/pipeline.go \
- go/net/textproto/reader.go \
- go/net/textproto/textproto.go \
- go/net/textproto/writer.go
-go_net_url_files = \
- go/net/url/url.go
-
-go_net_http_cgi_files = \
- go/net/http/cgi/child.go \
- go/net/http/cgi/host.go
-go_net_http_cookiejar_files = \
- go/net/http/cookiejar/jar.go \
- go/net/http/cookiejar/punycode.go
-go_net_http_fcgi_files = \
- go/net/http/fcgi/child.go \
- go/net/http/fcgi/fcgi.go
-go_net_http_httptest_files = \
- go/net/http/httptest/recorder.go \
- go/net/http/httptest/server.go
-go_net_http_pprof_files = \
- go/net/http/pprof/pprof.go
-go_net_http_httputil_files = \
- go/net/http/httputil/dump.go \
- go/net/http/httputil/httputil.go \
- go/net/http/httputil/persist.go \
- go/net/http/httputil/reverseproxy.go
-go_net_http_internal_files = \
- go/net/http/internal/chunked.go \
- go/net/http/internal/testcert.go
-
-if LIBGO_IS_LINUX
-go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
-else
-if LIBGO_IS_FREEBSD
-go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
-else
-go_net_internal_socktest_sys =
-endif
-endif
-
-go_net_internal_socktest_files = \
- go/net/internal/socktest/switch.go \
- go/net/internal/socktest/switch_posix.go \
- go/net/internal/socktest/switch_unix.go \
- go/net/internal/socktest/sys_unix.go \
- $(go_net_internal_socktest_sys)
-
-go_old_regexp_files = \
- go/old/regexp/regexp.go
-go_old_template_files = \
- go/old/template/doc.go \
- go/old/template/execute.go \
- go/old/template/format.go \
- go/old/template/parse.go
-
-go_os_exec_files = \
- go/os/exec/exec.go \
- go/os/exec/exec_posix.go \
- go/os/exec/lp_unix.go
-
-go_os_signal_files = \
- go/os/signal/doc.go \
- go/os/signal/signal.go \
- go/os/signal/signal_unix.go
-
-if LIBGO_IS_SOLARIS
-os_user_decls_file = go/os/user/decls_solaris.go
-else
-os_user_decls_file = go/os/user/decls_unix.go
-endif
-
-go_os_user_files = \
- go/os/user/lookup.go \
- go/os/user/lookup_unix.go \
- go/os/user/user.go \
- $(os_user_decls_file)
-
-go_path_filepath_files = \
- go/path/filepath/match.go \
- go/path/filepath/path.go \
- go/path/filepath/path_unix.go \
- go/path/filepath/symlink.go \
- go/path/filepath/symlink_unix.go
-
-go_regexp_syntax_files = \
- go/regexp/syntax/compile.go \
- go/regexp/syntax/doc.go \
- go/regexp/syntax/parse.go \
- go/regexp/syntax/perl_groups.go \
- go/regexp/syntax/prog.go \
- go/regexp/syntax/regexp.go \
- go/regexp/syntax/simplify.go
-
-go_net_rpc_jsonrpc_files = \
- go/net/rpc/jsonrpc/client.go \
- go/net/rpc/jsonrpc/server.go
-
-go_runtime_debug_files = \
- go/runtime/debug/garbage.go \
- go/runtime/debug/stack.go
-go_runtime_pprof_files = \
- go/runtime/pprof/pprof.go
-
-go_text_tabwriter_files = \
- go/text/tabwriter/tabwriter.go
-go_text_template_files = \
- go/text/template/doc.go \
- go/text/template/exec.go \
- go/text/template/funcs.go \
- go/text/template/helper.go \
- go/text/template/option.go \
- go/text/template/template.go
-go_text_template_parse_files = \
- go/text/template/parse/lex.go \
- go/text/template/parse/node.go \
- go/text/template/parse/parse.go
-
-go_sync_atomic_files = \
- go/sync/atomic/doc.go \
- go/sync/atomic/value.go
-go_sync_atomic_c_files = \
- go/sync/atomic/atomic.c
-
-go_testing_iotest_files = \
- go/testing/iotest/logger.go \
- go/testing/iotest/reader.go \
- go/testing/iotest/writer.go
-go_testing_quick_files = \
- go/testing/quick/quick.go
-
-go_text_scanner_files = \
- go/text/scanner/scanner.go
-
-go_unicode_utf16_files = \
- go/unicode/utf16/utf16.go
-go_unicode_utf8_files = \
- go/unicode/utf8/utf8.go
-
-# Define Syscall and Syscall6.
-if LIBGO_IS_RTEMS
-syscall_syscall_file = go/syscall/syscall_stubs.go
-else
-syscall_syscall_file = go/syscall/syscall_unix.go
-endif
-
-# Define ForkExec and Exec.
-if LIBGO_IS_RTEMS
-syscall_exec_file = go/syscall/exec_stubs.go
-syscall_exec_os_file =
-else
-if LIBGO_IS_LINUX
-syscall_exec_file = go/syscall/exec_unix.go
-syscall_exec_os_file = go/syscall/exec_linux.go
-else
-syscall_exec_file = go/syscall/exec_unix.go
-syscall_exec_os_file = go/syscall/exec_bsd.go
-endif
-endif
-
-# Define Wait4.
-if LIBGO_IS_RTEMS
-syscall_wait_file =
-else
-if HAVE_WAIT4
-syscall_wait_file = go/syscall/libcall_wait4.go
-else
-syscall_wait_file = go/syscall/libcall_waitpid.go
-endif
-endif
-
-# Support for pulling apart wait status.
-if LIBGO_IS_RTEMS
-syscall_wait_c_file =
-else
-syscall_wait_c_file = go/syscall/wait.c
-endif
-
-# Define Sleep.
-if LIBGO_IS_RTEMS
-syscall_sleep_file = go/syscall/sleep_rtems.go
-else
-syscall_sleep_file = go/syscall/sleep_select.go
-endif
-
-# Define Errstr.
-if LIBGO_IS_LINUX
-syscall_errstr_file = go/syscall/errstr_linux.go
-else
-if LIBGO_IS_RTEMS
-syscall_errstr_file = go/syscall/errstr_linux.go
-else
-if HAVE_STRERROR_R
-syscall_errstr_file = go/syscall/errstr.go
-else
-syscall_errstr_file = go/syscall/errstr_nor.go
-endif
-endif
-endif
-
-# Declare libc functions that vary for largefile systems.
-if LIBGO_IS_LINUX
-# Always use lseek64 on GNU/Linux.
-syscall_size_file = go/syscall/libcall_posix_largefile.go
-else # !LIBGO_IS_LINUX
-if LIBGO_IS_SOLARIS
-if LIBGO_IS_386
-# Use lseek64 on 32-bit Solaris/x86.
-syscall_size_file = go/syscall/libcall_posix_largefile.go
-else # !LIBGO_IS_386
-if LIBGO_IS_SPARC
-# Use lseek64 on 32-bit Solaris/SPARC.
-syscall_size_file = go/syscall/libcall_posix_largefile.go
-else # !LIBGO_IS_386 && !LIBGO_IS_SPARC
-# Use lseek on 64-bit Solaris.
-syscall_size_file = go/syscall/libcall_posix_regfile.go
-endif # !LIBGO_IS_386 && !LIBGO_IS_SPARC
-endif # !LIBGO_IS_SOLARIS
-else # !LIBGO_IS_LINUX && !LIBGO_IS_SOLARIS
-# Use lseek by default.
-syscall_size_file = go/syscall/libcall_posix_regfile.go
-endif # !LIBGO_IS_SOLARIS
-endif # !LIBGO_IS_LINUX
-
-# Define socket sizes and types.
-if LIBGO_IS_LINUX
-syscall_socket_file = go/syscall/socket_linux.go epoll.go
-if LIBGO_IS_PPC64LE
-syscall_socket_type_file = go/syscall/socket_linux_ppc64x_type.go
-else
-if LIBGO_IS_PPC64
-syscall_socket_type_file = go/syscall/socket_linux_ppc64x_type.go
-else
-syscall_socket_type_file = go/syscall/socket_linux_type.go
-endif
-endif
-else
-syscall_socket_type_file =
-if LIBGO_IS_SOLARIS
-syscall_socket_file = go/syscall/socket_solaris.go
-else
-if LIBGO_IS_IRIX
-syscall_socket_file = go/syscall/socket_irix.go
-else
-syscall_socket_file = go/syscall/socket_bsd.go
-endif
-endif
-endif
-
-# Define socket functions.
-if LIBGO_IS_SOLARIS
-syscall_socket_os_file = go/syscall/socket_xnet.go
-else
-syscall_socket_os_file = go/syscall/socket_posix.go
-endif
-
-# Support for uname.
-if LIBGO_IS_SOLARIS
-if LIBGO_IS_386
-# 32-bit Solaris 2/x86 needs _nuname, handled in libcall_solaris_386.go.
-syscall_uname_file =
-else # !LIBGO_IS_386 && LIBGO_IS_SOLARIS
-syscall_uname_file = go/syscall/libcall_uname.go
-endif
-else # !LIBGO_IS_SOLARIS
-syscall_uname_file = go/syscall/libcall_uname.go
-endif
-
-# GNU/Linux specific socket control messages.
-if LIBGO_IS_LINUX
-syscall_sockcmsg_file = go/syscall/sockcmsg_linux.go
-else
-syscall_sockcmsg_file =
-endif
-
-# Support for netlink sockets and messages.
-if LIBGO_IS_LINUX
-syscall_netlink_file = go/syscall/netlink_linux.go
-else
-syscall_netlink_file =
-endif
-
-# GNU/Linux specific socket filters.
-if LIBGO_IS_LINUX
-syscall_lsf_file = go/syscall/lsf_linux.go
-else
-syscall_lsf_file =
-endif
-
-# GNU/Linux specific ustat support.
-if LIBGO_IS_LINUX
-if LIBGO_IS_ARM64
-syscall_ustat_file =
-else
-syscall_ustat_file = go/syscall/libcall_linux_ustat.go
-endif
-else
-syscall_ustat_file =
-endif
-
-# GNU/Linux specific utimesnano support.
-if LIBGO_IS_LINUX
-syscall_utimesnano_file = go/syscall/libcall_linux_utimesnano.go
-else
-syscall_utimesnano_file = go/syscall/libcall_posix_utimesnano.go
-endif
-
-# Test files.
-if LIBGO_IS_LINUX
-syscall_creds_test_file = go/syscall/creds_test.go
-else
-syscall_creds_test_file =
-endif
-
-if LIBGO_IS_LINUX
-syscall_exec_test_file = go/syscall/exec_linux_test.go go/syscall/syscall_linux_test.go
+syscall_epoll_file = epoll.go
else
-syscall_exec_test_file =
+syscall_epoll_file =
endif
-if LIBGO_IS_LINUX
-syscall_os_file =
-else
-syscall_os_file = go/syscall/libcall_bsd.go
-endif
-
-go_base_syscall_files = \
- go/syscall/env_unix.go \
- go/syscall/syscall_errno.go \
- go/syscall/libcall_support.go \
- go/syscall/libcall_posix.go \
- go/syscall/msan0.go \
- go/syscall/socket.go \
- go/syscall/sockcmsg_unix.go \
- go/syscall/str.go \
- go/syscall/syscall.go \
- $(syscall_sockcmsg_file) \
- $(syscall_syscall_file) \
- $(syscall_exec_file) \
- $(syscall_exec_os_file) \
- $(syscall_wait_file) \
- $(syscall_sleep_file) \
- $(syscall_errstr_file) \
- $(syscall_size_file) \
- $(syscall_os_file) \
- $(syscall_socket_file) \
- $(syscall_socket_os_file) \
- $(syscall_socket_type_file) \
- $(syscall_uname_file) \
- $(syscall_netlink_file) \
- $(syscall_lsf_file) \
- $(syscall_ustat_file) \
- $(syscall_utimesnano_file) \
- $(GO_LIBCALL_OS_FILE) \
- $(GO_LIBCALL_OS_ARCH_FILE) \
- $(GO_SYSCALL_OS_FILE) \
- $(GO_SYSCALL_OS_ARCH_FILE)
-
-go_syscall_files = \
- $(go_base_syscall_files) \
- libcalls.go \
- sysinfo.go \
- syscall_arch.go
-go_syscall_c_files = \
- go/syscall/errno.c \
- go/syscall/signame.c \
- $(syscall_wait_c_file)
-
-go_syscall_test_files = \
- $(syscall_creds_test_file) \
- $(syscall_exec_test_file) \
- go/syscall/exec_unix_test.go \
- go/syscall/export_test.go \
- go/syscall/export_unix_test.go \
- go/syscall/mmap_unix_test.go \
- go/syscall/syscall_test.go \
- go/syscall/syscall_unix_test.go
-
libcalls.go: s-libcalls; @true
-s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
+s-libcalls: libcalls-list go/syscall/mksyscall.awk $(srcdir)/go/syscall/*.go
rm -f libcalls.go.tmp
- files=`echo $^ | sed -e 's/libcalls-list//' -e 's|[^ ]*go/syscall/mksyscall.awk||'`; \
- $(AWK) -f $(srcdir)/go/syscall/mksyscall.awk $${files} > libcalls.go.tmp
+ $(AWK) -f $(srcdir)/go/syscall/mksyscall.awk `cat libcalls-list` > libcalls.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh libcalls.go.tmp libcalls.go
$(STAMP) $@
libcalls-list: s-libcalls-list; @true
-s-libcalls-list: Makefile
+s-libcalls-list: Makefile $(srcdir)/go/syscall/*.go
rm -f libcalls-list.tmp
- echo $(go_base_syscall_files) > libcalls-list.tmp
+ $(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/syscall $(matchargs_syscall) > libcalls-list.tmp
$(SHELL) $(srcdir)/mvifdiff.sh libcalls-list.tmp libcalls-list
$(STAMP) $@
@@ -2102,9 +613,26 @@ s-syscall_arch: Makefile
$(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
$(STAMP) $@
+SYSINFO_FLAGS = \
+ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(OSCFLAGS) -O
+
+gen-sysinfo.go: s-gen-sysinfo; @true
+s-gen-sysinfo: $(srcdir)/sysinfo.c config.h
+ $(CC) $(SYSINFO_FLAGS) -fdump-go-spec=tmp-gen-sysinfo.go -std=gnu99 -S -o sysinfo.s $(srcdir)/sysinfo.c
+ rm -f sysinfo.s
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-gen-sysinfo.go gen-sysinfo.go
+ $(STAMP) $@
+
+errno.i: s-errno; @true
+s-errno:
+ echo '#include <errno.h>' | $(CC) $(SYSINFO_FLAGS) -x c - -E -dM > tmp-errno.i
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-errno.i errno.i
+ $(STAMP) $@
+
sysinfo.go: s-sysinfo; @true
-s-sysinfo: $(srcdir)/mksysinfo.sh config.h
- CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS) -O" $(SHELL) $(srcdir)/mksysinfo.sh
+s-sysinfo: $(srcdir)/mksysinfo.sh gen-sysinfo.go errno.i
+ $(SHELL) $(srcdir)/mksysinfo.sh
$(SHELL) $(srcdir)/mvifdiff.sh tmp-sysinfo.go sysinfo.go
$(STAMP) $@
@@ -2137,172 +665,196 @@ s-epoll: Makefile
$(STAMP) $@
if LIBGO_IS_LINUX
-# os_lib_inotify_lo = os/inotify.lo
-os_lib_inotify_lo =
-else
-os_lib_inotify_lo =
-endif
+syscall_lib_clone_lo = syscall/clone_linux.lo
+else
+syscall_lib_clone_lo =
+endif
+
+PACKAGES = \
+ archive/tar \
+ archive/zip \
+ bufio \
+ bytes \
+ cmd/internal/browser \
+ compress/bzip2 \
+ compress/flate \
+ compress/gzip \
+ compress/lzw \
+ compress/zlib \
+ container/heap \
+ container/list \
+ container/ring \
+ context \
+ crypto \
+ crypto/aes \
+ crypto/cipher \
+ crypto/des \
+ crypto/dsa \
+ crypto/ecdsa \
+ crypto/elliptic \
+ crypto/hmac \
+ crypto/internal/cipherhw \
+ crypto/md5 \
+ crypto/rand \
+ crypto/rc4 \
+ crypto/rsa \
+ crypto/sha1 \
+ crypto/sha256 \
+ crypto/sha512 \
+ crypto/subtle \
+ crypto/tls \
+ crypto/x509 \
+ crypto/x509/pkix \
+ database/sql \
+ database/sql/driver \
+ debug/dwarf \
+ debug/elf \
+ debug/gosym \
+ debug/macho \
+ debug/pe \
+ debug/plan9obj \
+ encoding \
+ encoding/ascii85 \
+ encoding/asn1 \
+ encoding/base32 \
+ encoding/base64 \
+ encoding/binary \
+ encoding/csv \
+ encoding/gob \
+ encoding/hex \
+ encoding/json \
+ encoding/pem \
+ encoding/xml \
+ errors \
+ exp/proxy \
+ exp/terminal \
+ expvar \
+ flag \
+ fmt \
+ go/ast \
+ go/build \
+ go/constant \
+ go/doc \
+ go/format \
+ go/importer \
+ go/internal/gccgoimporter \
+ go/internal/gcimporter \
+ go/parser \
+ go/printer \
+ go/scanner \
+ go/token \
+ go/types \
+ golang_org/x/crypto/chacha20poly1305 \
+ golang_org/x/crypto/chacha20poly1305/internal/chacha20 \
+ golang_org/x/crypto/curve25519 \
+ golang_org/x/crypto/poly1305 \
+ golang_org/x/net/http2/hpack \
+ golang_org/x/net/idna \
+ golang_org/x/net/lex/httplex \
+ golang_org/x/text/transform \
+ golang_org/x/text/unicode/norm \
+ golang_org/x/text/width \
+ hash \
+ hash/adler32 \
+ hash/crc32 \
+ hash/crc64 \
+ hash/fnv \
+ html \
+ html/template \
+ image \
+ image/color \
+ image/color/palette \
+ image/draw \
+ image/gif \
+ image/internal/imageutil \
+ image/jpeg \
+ image/png \
+ index/suffixarray \
+ internal/nettrace \
+ internal/pprof/profile \
+ internal/race \
+ internal/singleflight \
+ internal/syscall/unix \
+ internal/testenv \
+ internal/trace \
+ io \
+ io/ioutil \
+ log \
+ log/syslog \
+ math \
+ math/big \
+ math/cmplx \
+ math/rand \
+ mime \
+ mime/multipart \
+ mime/quotedprintable \
+ net \
+ net/http \
+ net/http/cgi \
+ net/http/cookiejar \
+ net/http/fcgi \
+ net/http/httptest \
+ net/http/httptrace \
+ net/http/httputil \
+ net/http/internal \
+ net/http/pprof \
+ net/internal/socktest \
+ net/mail \
+ net/rpc \
+ net/rpc/jsonrpc \
+ net/smtp \
+ net/textproto \
+ net/url \
+ os \
+ os/exec \
+ os/signal \
+ os/user \
+ path \
+ path/filepath \
+ reflect \
+ regexp \
+ regexp/syntax \
+ runtime \
+ runtime/debug \
+ runtime/internal/atomic \
+ runtime/internal/sys \
+ runtime/pprof \
+ runtime/pprof/internal/protopprof \
+ runtime/trace \
+ sort \
+ strconv \
+ strings \
+ sync \
+ sync/atomic \
+ syscall \
+ testing \
+ testing/internal/testdeps \
+ testing/iotest \
+ testing/quick \
+ text/scanner \
+ text/tabwriter \
+ text/template \
+ text/template/parse \
+ time \
+ unicode \
+ unicode/utf16 \
+ unicode/utf8
libgo_go_objs = \
- bufio.lo \
- bytes.lo \
+ $(addsuffix .lo,$(PACKAGES)) \
bytes/index.lo \
- crypto.lo \
- encoding.lo \
- errors.lo \
- expvar.lo \
- flag.lo \
- fmt.lo \
- hash.lo \
- html.lo \
- image.lo \
- io.lo \
- log.lo \
- math.lo \
- mime.lo \
- net.lo \
- os.lo \
- path.lo \
- reflect-go.lo \
reflect/makefunc_ffi_c.lo \
- regexp.lo \
- runtime-go.lo \
- sort.lo \
- strconv.lo \
- strings.lo \
strings/index.lo \
- sync.lo \
- syscall.lo \
+ $(syscall_lib_clone_lo) \
syscall/errno.lo \
syscall/signame.lo \
syscall/wait.lo \
- testing.lo \
- time-go.lo \
- unicode.lo \
- archive/tar.lo \
- archive/zip.lo \
- compress/bzip2.lo \
- compress/flate.lo \
- compress/gzip.lo \
- compress/lzw.lo \
- compress/zlib.lo \
- container/heap.lo \
- container/list.lo \
- container/ring.lo \
- crypto/aes.lo \
- crypto/cipher.lo \
- crypto/des.lo \
- crypto/dsa.lo \
- crypto/ecdsa.lo \
- crypto/elliptic.lo \
- crypto/hmac.lo \
- crypto/md5.lo \
- crypto/rand.lo \
- crypto/rc4.lo \
- crypto/rsa.lo \
- crypto/sha1.lo \
- crypto/sha256.lo \
- crypto/sha512.lo \
- crypto/subtle.lo \
- crypto/tls.lo \
- crypto/x509.lo \
- crypto/x509/pkix.lo \
- database/sql.lo \
- database/sql/driver.lo \
- debug/dwarf.lo \
- debug/elf.lo \
- debug/gosym.lo \
- debug/macho.lo \
- debug/pe.lo \
- debug/plan9obj.lo \
- encoding/ascii85.lo \
- encoding/asn1.lo \
- encoding/base32.lo \
- encoding/base64.lo \
- encoding/binary.lo \
- encoding/csv.lo \
- encoding/gob.lo \
- encoding/hex.lo \
- encoding/json.lo \
- encoding/pem.lo \
- encoding/xml.lo \
- exp/proxy.lo \
- exp/terminal.lo \
- html/template.lo \
- go/ast.lo \
- go/build.lo \
- go/constant.lo \
- go/doc.lo \
- go/format.lo \
- go/importer.lo \
- go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo \
- go/parser.lo \
- go/printer.lo \
- go/scanner.lo \
- go/token.lo \
- go/types.lo \
- hash/adler32.lo \
- hash/crc32.lo \
- hash/crc64.lo \
- hash/fnv.lo \
- net/http/cgi.lo \
- net/http/cookiejar.lo \
- net/http/fcgi.lo \
- net/http/httptest.lo \
- net/http/httputil.lo \
- net/http/internal.lo \
- net/http/pprof.lo \
- image/color.lo \
- image/color/palette.lo \
- image/draw.lo \
- image/gif.lo \
- image/internal/imageutil.lo \
- image/jpeg.lo \
- image/png.lo \
- index/suffixarray.lo \
- internal/golang.org/x/net/http2/hpack.lo \
- internal/race.lo \
- internal/singleflight.lo \
- internal/syscall/unix.lo \
- internal/testenv.lo \
- internal/trace.lo \
- io/ioutil.lo \
- log/syslog.lo \
+ $(golang_org_x_net_lif_lo) \
+ $(golang_org_x_net_route_lo) \
log/syslog/syslog_c.lo \
- math/big.lo \
- math/cmplx.lo \
- math/rand.lo \
- mime/multipart.lo \
- mime/quotedprintable.lo \
- net/http.lo \
- net/internal/socktest.lo \
- net/mail.lo \
- net/rpc.lo \
- net/smtp.lo \
- net/textproto.lo \
- net/url.lo \
- old/regexp.lo \
- old/template.lo \
- os/exec.lo \
$(os_lib_inotify_lo) \
- os/signal.lo \
- os/user.lo \
- path/filepath.lo \
- regexp/syntax.lo \
- net/rpc/jsonrpc.lo \
- runtime/debug.lo \
- runtime/pprof.lo \
- sync/atomic.lo \
- sync/atomic_c.lo \
- text/scanner.lo \
- text/tabwriter.lo \
- text/template.lo \
- text/template/parse.lo \
- testing/iotest.lo \
- testing/quick.lo \
- unicode/utf16.lo \
- unicode/utf8.lo
+ runtime/internal/atomic_c.lo \
+ sync/atomic_c.lo
libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
@@ -2334,8 +886,12 @@ libgolibbegin_a_SOURCES = \
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
-libnetgo_a_SOURCES = $(go_netgo_files)
-libnetgo_a_LIBADD = netgo.o
+# Make sure runtime.inc is built before compiling any .c file.
+$(libgo_la_OBJECTS): runtime.inc
+$(libgo_llgo_la_OBJECTS): runtime.inc
+$(libgobegin_a_OBJECTS): runtime.inc
+$(libgobegin_llgo_a_OBJECTS): runtime.inc
+$(libgolibbegin_a_OBJECTS): runtime.inc
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
@@ -2352,20 +908,25 @@ GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
# Build the dependencies for a Go package.
BUILDDEPS = \
$(MKDIR_P) $(@D); \
- $(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $^ > $@.tmp; \
+ dir=`echo $@ | sed -e 's/.lo.dep$$//'`; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst .lo.dep,,$@)))" $(matchargs_$(subst /,_,$(subst .lo.dep,,$@)))`; \
+ $(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $$files > $@.tmp; \
+ if ! cmp $@.tmp $@ >/dev/null 2>/dev/null; then \
+ rm -f `echo $@ | sed -e 's/\.dep$$//'`; \
+ fi; \
mv -f $@.tmp $@
# Build the .go files for a package, generating a .lo file.
BUILDPACKAGE = \
$(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
+ $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
-# Build netgo.o.
-BUILDNETGO = \
- $(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp; \
+ $(SHELL) $(srcdir)/mvifdiff.sh $@.tmp `echo $@ | sed -e 's/s-gox/gox/'`
GOTESTFLAGS =
GOBENCH =
@@ -2386,12 +947,13 @@ CHECK = \
export LD_LIBRARY_PATH; \
$(MKDIR_P) $(@D); \
rm -f $@-testsum $@-testlog; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$(@D) --extrafiles="$(extra_go_files_$(subst /,_,$(@D)))" $(matchargs_$(subst /,_,$(@D)))`; \
if test "$(USE_DEJAGNU)" = "yes"; then \
- $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
+ $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" --testname="$(@D)" $(GOTESTFLAGS); \
elif test "$(GOBENCH)" != ""; then \
- $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
+ $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" --bench="$(GOBENCH)" $(GOTESTFLAGS); \
else \
- if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst .,_,$(subst /,_,$(@D)))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
+ if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" $(GOTESTFLAGS) >>$@-testlog 2>&1; then \
echo "PASS: $(@D)" >> $@-testlog; \
echo "PASS: $(@D)"; \
echo "PASS: $(@D)" > $@-testsum; \
@@ -2439,1736 +1001,165 @@ else
CHECK_DEPS += libgo.la libgobegin.a
endif
-@go_include@ bufio.lo.dep
-bufio.lo.dep: $(go_bufio_files)
- $(BUILDDEPS)
-bufio.lo: $(go_bufio_files)
- $(BUILDPACKAGE)
-bufio/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bufio/check
-
-@go_include@ bytes.lo.dep
-bytes.lo.dep: $(go_bytes_files)
- $(BUILDDEPS)
-bytes.lo: $(go_bytes_files)
- $(BUILDPACKAGE)
-bytes/index.lo: $(go_bytes_c_files)
- @$(MKDIR_P) bytes
- $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
-bytes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bytes/check
-
-@go_include@ crypto.lo.dep
-crypto.lo.dep: $(go_crypto_files)
- $(BUILDDEPS)
-crypto.lo: $(go_crypto_files)
- $(BUILDPACKAGE)
-crypto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/check
-
-@go_include@ encoding.lo.dep
-encoding.lo.dep: $(go_encoding_files)
- $(BUILDDEPS)
-encoding.lo: $(go_encoding_files)
- $(BUILDPACKAGE)
-encoding/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/check
-
-@go_include@ errors.lo.dep
-errors.lo.dep: $(go_errors_files)
- $(BUILDDEPS)
-errors.lo: $(go_errors_files)
- $(BUILDPACKAGE)
-errors/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: errors/check
-
-@go_include@ expvar.lo.dep
-expvar.lo.dep: $(go_expvar_files)
- $(BUILDDEPS)
-expvar.lo: $(go_expvar_files)
- $(BUILDPACKAGE)
-expvar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: expvar/check
-
-@go_include@ flag.lo.dep
-flag.lo.dep: $(go_flag_files)
- $(BUILDDEPS)
-flag.lo: $(go_flag_files)
- $(BUILDPACKAGE)
-flag/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: flag/check
-
-@go_include@ fmt.lo.dep
-fmt.lo.dep: $(go_fmt_files)
- $(BUILDDEPS)
-fmt.lo: $(go_fmt_files)
- $(BUILDPACKAGE)
-fmt/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: fmt/check
-
-@go_include@ hash.lo.dep
-hash.lo.dep: $(go_hash_files)
- $(BUILDDEPS)
-hash.lo: $(go_hash_files)
- $(BUILDPACKAGE)
-hash/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/check
-
-@go_include@ html.lo.dep
-html.lo.dep: $(go_html_files)
- $(BUILDDEPS)
-html.lo: $(go_html_files)
- $(BUILDPACKAGE)
-html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/check
-
-@go_include@ image.lo.dep
-image.lo.dep: $(go_image_files)
- $(BUILDDEPS)
-image.lo: $(go_image_files)
- $(BUILDPACKAGE)
-image/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/check
-
-@go_include@ io.lo.dep
-io.lo.dep: $(go_io_files)
- $(BUILDDEPS)
-io.lo: $(go_io_files)
- $(BUILDPACKAGE)
-io/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/check
-
-@go_include@ log.lo.dep
-log.lo.dep: $(go_log_files)
- $(BUILDDEPS)
-log.lo: $(go_log_files)
- $(BUILDPACKAGE)
-log/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/check
-
-@go_include@ math.lo.dep
-math.lo.dep: $(go_math_files)
- $(BUILDDEPS)
-math.lo: $(go_math_files)
- $(MKDIR_P) $(@D)
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) $(MATH_FLAG) -I . -c -fgo-pkgpath=math -o $@ $$files
-math/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/check
-
-@go_include@ mime.lo.dep
-mime.lo.dep: $(go_mime_files)
- $(BUILDDEPS)
-mime.lo: $(go_mime_files)
- $(BUILDPACKAGE)
-mime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/check
-
-@go_include@ net.lo.dep
-net.lo.dep: $(go_net_files)
- $(BUILDDEPS)
-net.lo: $(go_net_files)
- $(BUILDPACKAGE)
-net/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/check
-
-@go_include@ netgo.o.dep
-netgo.o.dep: $(go_netgo_files)
- $(BUILDDEPS)
-netgo.o: $(go_netgo_files)
- $(BUILDNETGO)
-
-@go_include@ os.lo.dep
-os.lo.dep: $(go_os_files)
- $(BUILDDEPS)
-os.lo: $(go_os_files)
- $(BUILDPACKAGE)
-os/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/check
-
-@go_include@ path.lo.dep
-path.lo.dep: $(go_path_files)
- $(BUILDDEPS)
-path.lo: $(go_path_files)
- $(BUILDPACKAGE)
-path/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/check
-
-@go_include@ reflect-go.lo.dep
-reflect-go.lo.dep: $(go_reflect_files)
- $(BUILDDEPS)
-reflect-go.lo: $(go_reflect_files)
- $(BUILDPACKAGE)
-reflect/check: $(CHECK_DEPS)
- @$(CHECK)
-reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
- @$(MKDIR_P) reflect
- $(LTCOMPILE) -c -o $@ $<
-.PHONY: reflect/check
-
-@go_include@ regexp.lo.dep
-regexp.lo.dep: $(go_regexp_files)
- $(BUILDDEPS)
-regexp.lo: $(go_regexp_files)
- $(BUILDPACKAGE)
-regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/check
-
-@go_include@ runtime-go.lo.dep
-runtime-go.lo.dep: $(go_runtime_files)
- $(BUILDDEPS)
-runtime-go.lo: $(go_runtime_files)
- $(BUILDPACKAGE)
-runtime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/check
-
-@go_include@ sort.lo.dep
-sort.lo.dep: $(go_sort_files)
- $(BUILDDEPS)
-sort.lo: $(go_sort_files)
- $(BUILDPACKAGE)
-sort/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sort/check
-
-@go_include@ strconv.lo.dep
-strconv.lo.dep: $(go_strconv_files)
- $(BUILDDEPS)
-strconv.lo: $(go_strconv_files)
- $(BUILDPACKAGE)
-strconv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strconv/check
-
-@go_include@ strings.lo.dep
-strings.lo.dep: $(go_strings_files)
- $(BUILDDEPS)
-strings.lo: $(go_strings_files)
- $(BUILDPACKAGE)
-strings/index.lo: $(go_strings_c_files)
- @$(MKDIR_P) strings
- $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c
-strings/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strings/check
-
-@go_include@ sync.lo.dep
-sync.lo.dep: $(go_sync_files)
- $(BUILDDEPS)
-sync.lo: $(go_sync_files)
- $(BUILDPACKAGE)
-sync/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/check
-
-@go_include@ testing.lo.dep
-testing.lo.dep: $(go_testing_files)
- $(BUILDDEPS)
-testing.lo: $(go_testing_files)
- $(BUILDPACKAGE)
-testing/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/check
-
-@go_include@ time-go.lo.dep
-time-go.lo.dep: $(go_time_files)
- $(BUILDDEPS)
-time-go.lo: $(go_time_files)
- $(BUILDPACKAGE)
-time/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: time/check
-
-@go_include@ unicode.lo.dep
-unicode.lo.dep: $(go_unicode_files)
- $(BUILDDEPS)
-unicode.lo: $(go_unicode_files)
- $(BUILDPACKAGE)
-unicode/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/check
-
-@go_include@ archive/tar.lo.dep
-archive/tar.lo.dep: $(go_archive_tar_files)
- $(BUILDDEPS)
-archive/tar.lo: $(go_archive_tar_files)
- $(BUILDPACKAGE)
-archive/tar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/tar/check
-
-@go_include@ archive/zip.lo.dep
-archive/zip.lo.dep: $(go_archive_zip_files)
- $(BUILDDEPS)
-archive/zip.lo: $(go_archive_zip_files)
- $(BUILDPACKAGE)
-archive/zip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/zip/check
-
-@go_include@ compress/bzip2.lo.dep
-compress/bzip2.lo.dep: $(go_compress_bzip2_files)
- $(BUILDDEPS)
-compress/bzip2.lo: $(go_compress_bzip2_files)
- $(BUILDPACKAGE)
-compress/bzip2/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/bzip2/check
-
-@go_include@ compress/flate.lo.dep
-compress/flate.lo.dep: $(go_compress_flate_files)
- $(BUILDDEPS)
-compress/flate.lo: $(go_compress_flate_files)
- $(BUILDPACKAGE)
-compress/flate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/flate/check
-
-@go_include@ compress/gzip.lo.dep
-compress/gzip.lo.dep: $(go_compress_gzip_files)
- $(BUILDDEPS)
-compress/gzip.lo: $(go_compress_gzip_files)
- $(BUILDPACKAGE)
-compress/gzip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/gzip/check
-
-@go_include@ compress/lzw.lo.dep
-compress/lzw.lo.dep: $(go_compress_lzw_files)
- $(BUILDDEPS)
-compress/lzw.lo: $(go_compress_lzw_files)
- $(BUILDPACKAGE)
-compress/lzw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/lzw/check
-
-@go_include@ compress/zlib.lo.dep
-compress/zlib.lo.dep: $(go_compress_zlib_files)
- $(BUILDDEPS)
-compress/zlib.lo: $(go_compress_zlib_files)
- $(BUILDPACKAGE)
-compress/zlib/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/zlib/check
-
-@go_include@ container/heap.lo.dep
-container/heap.lo.dep: $(go_container_heap_files)
- $(BUILDDEPS)
-container/heap.lo: $(go_container_heap_files)
- $(BUILDPACKAGE)
-container/heap/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/heap/check
-
-@go_include@ container/list.lo.dep
-container/list.lo.dep: $(go_container_list_files)
- $(BUILDDEPS)
-container/list.lo: $(go_container_list_files)
- $(BUILDPACKAGE)
-container/list/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/list/check
-
-@go_include@ container/ring.lo.dep
-container/ring.lo.dep: $(go_container_ring_files)
- $(BUILDDEPS)
-container/ring.lo: $(go_container_ring_files)
- $(BUILDPACKAGE)
-container/ring/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/ring/check
-
-@go_include@ crypto/aes.lo.dep
-crypto/aes.lo.dep: $(go_crypto_aes_files)
- $(BUILDDEPS)
-crypto/aes.lo: $(go_crypto_aes_files)
- $(BUILDPACKAGE)
-crypto/aes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/aes/check
-
-@go_include@ crypto/cipher.lo.dep
-crypto/cipher.lo.dep: $(go_crypto_cipher_files)
- $(BUILDDEPS)
-crypto/cipher.lo: $(go_crypto_cipher_files)
- $(BUILDPACKAGE)
-crypto/cipher/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/cipher/check
-
-@go_include@ crypto/des.lo.dep
-crypto/des.lo.dep: $(go_crypto_des_files)
- $(BUILDDEPS)
-crypto/des.lo: $(go_crypto_des_files)
- $(BUILDPACKAGE)
-crypto/des/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/des/check
-
-@go_include@ crypto/dsa.lo.dep
-crypto/dsa.lo.dep: $(go_crypto_dsa_files)
- $(BUILDDEPS)
-crypto/dsa.lo: $(go_crypto_dsa_files)
- $(BUILDPACKAGE)
-crypto/dsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/dsa/check
-
-@go_include@ crypto/ecdsa.lo.dep
-crypto/ecdsa.lo.dep: $(go_crypto_ecdsa_files)
- $(BUILDDEPS)
-crypto/ecdsa.lo: $(go_crypto_ecdsa_files)
- $(BUILDPACKAGE)
-crypto/ecdsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/ecdsa/check
-
-@go_include@ crypto/elliptic.lo.dep
-crypto/elliptic.lo.dep: $(go_crypto_elliptic_files)
- $(BUILDDEPS)
-crypto/elliptic.lo: $(go_crypto_elliptic_files)
- $(BUILDPACKAGE)
-crypto/elliptic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/elliptic/check
-
-@go_include@ crypto/hmac.lo.dep
-crypto/hmac.lo.dep: $(go_crypto_hmac_files)
- $(BUILDDEPS)
-crypto/hmac.lo: $(go_crypto_hmac_files)
- $(BUILDPACKAGE)
-crypto/hmac/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/hmac/check
-
-@go_include@ crypto/md5.lo.dep
-crypto/md5.lo.dep: $(go_crypto_md5_files)
- $(BUILDDEPS)
-crypto/md5.lo: $(go_crypto_md5_files)
- $(BUILDPACKAGE)
-crypto/md5/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/md5/check
-
-@go_include@ crypto/rand.lo.dep
-crypto/rand.lo.dep: $(go_crypto_rand_files)
- $(BUILDDEPS)
-crypto/rand.lo: $(go_crypto_rand_files)
- $(BUILDPACKAGE)
-crypto/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rand/check
-
-@go_include@ crypto/rc4.lo.dep
-crypto/rc4.lo.dep: $(go_crypto_rc4_files)
- $(BUILDDEPS)
-crypto/rc4.lo: $(go_crypto_rc4_files)
- $(BUILDPACKAGE)
-crypto/rc4/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rc4/check
-
-@go_include@ crypto/rsa.lo.dep
-crypto/rsa.lo.dep: $(go_crypto_rsa_files)
- $(BUILDDEPS)
-crypto/rsa.lo: $(go_crypto_rsa_files)
- $(BUILDPACKAGE)
-crypto/rsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rsa/check
-
-@go_include@ crypto/sha1.lo.dep
-crypto/sha1.lo.dep: $(go_crypto_sha1_files)
- $(BUILDDEPS)
-crypto/sha1.lo: $(go_crypto_sha1_files)
- $(BUILDPACKAGE)
-crypto/sha1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha1/check
-
-@go_include@ crypto/sha256.lo.dep
-crypto/sha256.lo.dep: $(go_crypto_sha256_files)
- $(BUILDDEPS)
-crypto/sha256.lo: $(go_crypto_sha256_files)
- $(BUILDPACKAGE)
-crypto/sha256/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha256/check
-
-@go_include@ crypto/sha512.lo.dep
-crypto/sha512.lo.dep: $(go_crypto_sha512_files)
- $(BUILDDEPS)
-crypto/sha512.lo: $(go_crypto_sha512_files)
- $(BUILDPACKAGE)
-crypto/sha512/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha512/check
-
-@go_include@ crypto/subtle.lo.dep
-crypto/subtle.lo.dep: $(go_crypto_subtle_files)
- $(BUILDDEPS)
-crypto/subtle.lo: $(go_crypto_subtle_files)
- $(BUILDPACKAGE)
-crypto/subtle/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/subtle/check
-
-@go_include@ crypto/tls.lo.dep
-crypto/tls.lo.dep: $(go_crypto_tls_files)
- $(BUILDDEPS)
-crypto/tls.lo: $(go_crypto_tls_files)
- $(BUILDPACKAGE)
-crypto/tls/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/tls/check
-
-@go_include@ crypto/x509.lo.dep
-crypto/x509.lo.dep: $(go_crypto_x509_files)
- $(BUILDDEPS)
-crypto/x509.lo: $(go_crypto_x509_files)
- $(BUILDPACKAGE)
-crypto/x509/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/check
-
-@go_include@ crypto/x509/pkix.lo.dep
-crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files)
- $(BUILDDEPS)
-crypto/x509/pkix.lo: $(go_crypto_x509_pkix_files)
- $(BUILDPACKAGE)
-crypto/x509/pkix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/pkix/check
-
-@go_include@ database/sql.lo.dep
-database/sql.lo.dep: $(go_database_sql_files)
- $(BUILDDEPS)
-database/sql.lo: $(go_database_sql_files)
- $(BUILDPACKAGE)
-database/sql/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/check
-
-@go_include@ database/sql/driver.lo.dep
-database/sql/driver.lo.dep: $(go_database_sql_driver_files)
- $(BUILDDEPS)
-database/sql/driver.lo: $(go_database_sql_driver_files)
- $(BUILDPACKAGE)
-database/sql/driver/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/driver/check
-
-@go_include@ debug/dwarf.lo.dep
-debug/dwarf.lo.dep: $(go_debug_dwarf_files)
- $(BUILDDEPS)
-debug/dwarf.lo: $(go_debug_dwarf_files)
- $(BUILDPACKAGE)
-debug/dwarf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/dwarf/check
-
-@go_include@ debug/elf.lo.dep
-debug/elf.lo.dep: $(go_debug_elf_files)
- $(BUILDDEPS)
-debug/elf.lo: $(go_debug_elf_files)
- $(BUILDPACKAGE)
-debug/elf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/elf/check
-
-@go_include@ debug/gosym.lo.dep
-debug/gosym.lo.dep: $(go_debug_gosym_files)
- $(BUILDDEPS)
-debug/gosym.lo: $(go_debug_gosym_files)
- $(BUILDPACKAGE)
-debug/gosym/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/gosym/check
-
-@go_include@ debug/macho.lo.dep
-debug/macho.lo.dep: $(go_debug_macho_files)
- $(BUILDDEPS)
-debug/macho.lo: $(go_debug_macho_files)
- $(BUILDPACKAGE)
-debug/macho/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/macho/check
-
-@go_include@ debug/pe.lo.dep
-debug/pe.lo.dep: $(go_debug_pe_files)
- $(BUILDDEPS)
-debug/pe.lo: $(go_debug_pe_files)
- $(BUILDPACKAGE)
-debug/pe/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/pe/check
-
-@go_include@ debug/plan9obj.lo.dep
-debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
- $(BUILDDEPS)
-debug/plan9obj.lo: $(go_debug_plan9obj_files)
- $(BUILDPACKAGE)
-debug/plan9obj/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/plan9obj/check
-
-@go_include@ encoding/asn1.lo.dep
-encoding/asn1.lo.dep: $(go_encoding_asn1_files)
- $(BUILDDEPS)
-encoding/asn1.lo: $(go_encoding_asn1_files)
- $(BUILDPACKAGE)
-encoding/asn1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/asn1/check
-
-@go_include@ encoding/ascii85.lo.dep
-encoding/ascii85.lo.dep: $(go_encoding_ascii85_files)
- $(BUILDDEPS)
-encoding/ascii85.lo: $(go_encoding_ascii85_files)
- $(BUILDPACKAGE)
-encoding/ascii85/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/ascii85/check
-
-@go_include@ encoding/base32.lo.dep
-encoding/base32.lo.dep: $(go_encoding_base32_files)
- $(BUILDDEPS)
-encoding/base32.lo: $(go_encoding_base32_files)
- $(BUILDPACKAGE)
-encoding/base32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base32/check
-
-@go_include@ encoding/base64.lo.dep
-encoding/base64.lo.dep: $(go_encoding_base64_files)
- $(BUILDDEPS)
-encoding/base64.lo: $(go_encoding_base64_files)
- $(BUILDPACKAGE)
-encoding/base64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base64/check
-
-@go_include@ encoding/binary.lo.dep
-encoding/binary.lo.dep: $(go_encoding_binary_files)
- $(BUILDDEPS)
-encoding/binary.lo: $(go_encoding_binary_files)
- $(BUILDPACKAGE)
-encoding/binary/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/binary/check
-
-@go_include@ encoding/csv.lo.dep
-encoding/csv.lo.dep: $(go_encoding_csv_files)
- $(BUILDDEPS)
-encoding/csv.lo: $(go_encoding_csv_files)
- $(BUILDPACKAGE)
-encoding/csv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/csv/check
-
-@go_include@ encoding/gob.lo.dep
-encoding/gob.lo.dep: $(go_encoding_gob_files)
- $(BUILDDEPS)
-encoding/gob.lo: $(go_encoding_gob_files)
- $(BUILDPACKAGE)
-encoding/gob/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/gob/check
-
-@go_include@ encoding/hex.lo.dep
-encoding/hex.lo.dep: $(go_encoding_hex_files)
- $(BUILDDEPS)
-encoding/hex.lo: $(go_encoding_hex_files)
- $(BUILDPACKAGE)
-encoding/hex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/hex/check
-
-@go_include@ encoding/json.lo.dep
-encoding/json.lo.dep: $(go_encoding_json_files)
- $(BUILDDEPS)
-encoding/json.lo: $(go_encoding_json_files)
- $(BUILDPACKAGE)
-encoding/json/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/json/check
-
-@go_include@ encoding/pem.lo.dep
-encoding/pem.lo.dep: $(go_encoding_pem_files)
- $(BUILDDEPS)
-encoding/pem.lo: $(go_encoding_pem_files)
- $(BUILDPACKAGE)
-encoding/pem/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/pem/check
-
-@go_include@ encoding/xml.lo.dep
-encoding/xml.lo.dep: $(go_encoding_xml_files)
- $(BUILDDEPS)
-encoding/xml.lo: $(go_encoding_xml_files)
- $(BUILDPACKAGE)
-encoding/xml/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/xml/check
-
-@go_include@ exp/proxy.lo.dep
-exp/proxy.lo.dep: $(go_exp_proxy_files)
- $(BUILDDEPS)
-exp/proxy.lo: $(go_exp_proxy_files)
- $(BUILDPACKAGE)
-exp/proxy/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/proxy/check
-
-@go_include@ exp/terminal.lo.dep
-exp/terminal.lo.dep: $(go_exp_terminal_files)
- $(BUILDDEPS)
-exp/terminal.lo: $(go_exp_terminal_files)
- $(BUILDPACKAGE)
-exp/terminal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/terminal/check
-
-@go_include@ html/template.lo.dep
-html/template.lo.dep: $(go_html_template_files)
- $(BUILDDEPS)
-html/template.lo: $(go_html_template_files)
- $(BUILDPACKAGE)
-html/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/template/check
-
-@go_include@ go/ast.lo.dep
-go/ast.lo.dep: $(go_go_ast_files)
- $(BUILDDEPS)
-go/ast.lo: $(go_go_ast_files)
- $(BUILDPACKAGE)
-go/ast/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/ast/check
-
-@go_include@ go/build.lo.dep
-go/build.lo.dep: $(go_go_build_files)
- $(BUILDDEPS)
-go/build.lo: $(go_go_build_files)
- $(BUILDPACKAGE)
-go/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/build/check
-
-@go_include@ go/constant.lo.dep
-go/constant.lo.dep: $(go_go_constant_files)
- $(BUILDDEPS)
-go/constant.lo: $(go_go_constant_files)
- $(BUILDPACKAGE)
-go/constant/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/constant/check
-
-@go_include@ go/doc.lo.dep
-go/doc.lo.dep: $(go_go_doc_files)
- $(BUILDDEPS)
-go/doc.lo: $(go_go_doc_files)
- $(BUILDPACKAGE)
-go/doc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/doc/check
-
-@go_include@ go/format.lo.dep
-go/format.lo.dep: $(go_go_format_files)
- $(BUILDDEPS)
-go/format.lo: $(go_go_format_files)
- $(BUILDPACKAGE)
-go/format/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/format/check
-
-@go_include@ go/importer.lo.dep
-go/importer.lo.dep: $(go_go_importer_files)
- $(BUILDDEPS)
-go/importer.lo: $(go_go_importer_files)
- $(BUILDPACKAGE)
-go/importer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/importer/check
-
-@go_include@ go/parser.lo.dep
-go/parser.lo.dep: $(go_go_parser_files)
- $(BUILDDEPS)
-go/parser.lo: $(go_go_parser_files)
- $(BUILDPACKAGE)
-go/parser/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/parser/check
-
-@go_include@ go/printer.lo.dep
-go/printer.lo.dep: $(go_go_printer_files)
- $(BUILDDEPS)
-go/printer.lo: $(go_go_printer_files)
- $(BUILDPACKAGE)
-go/printer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/printer/check
-
-@go_include@ go/scanner.lo.dep
-go/scanner.lo.dep: $(go_go_scanner_files)
- $(BUILDDEPS)
-go/scanner.lo: $(go_go_scanner_files)
- $(BUILDPACKAGE)
-go/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/scanner/check
-
-@go_include@ go/token.lo.dep
-go/token.lo.dep: $(go_go_token_files)
- $(BUILDDEPS)
-go/token.lo: $(go_go_token_files)
- $(BUILDPACKAGE)
-go/token/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/token/check
-
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(go_go_types_files)
- $(BUILDDEPS)
-go/types.lo: $(go_go_types_files)
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
-@go_include@ go/internal/gcimporter.lo.dep
-go/internal/gcimporter.lo.dep: $(go_go_internal_gcimporter_files)
- $(BUILDDEPS)
-go/internal/gcimporter.lo: $(go_go_internal_gcimporter_files)
- $(BUILDPACKAGE)
-go/internal/gcimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gcimporter/check
-
-@go_include@ go/internal/gccgoimporter.lo.dep
-go/internal/gccgoimporter.lo.dep: $(go_go_internal_gccgoimporter_files)
- $(BUILDDEPS)
-go/internal/gccgoimporter.lo: $(go_go_internal_gccgoimporter_files)
- $(BUILDPACKAGE)
-go/internal/gccgoimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gccgoimporter/check
-
-@go_include@ hash/adler32.lo.dep
-hash/adler32.lo.dep: $(go_hash_adler32_files)
- $(BUILDDEPS)
-hash/adler32.lo: $(go_hash_adler32_files)
- $(BUILDPACKAGE)
-hash/adler32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/adler32/check
-
-@go_include@ hash/crc32.lo.dep
-hash/crc32.lo.dep: $(go_hash_crc32_files)
- $(BUILDDEPS)
-hash/crc32.lo: $(go_hash_crc32_files)
- $(BUILDPACKAGE)
-hash/crc32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc32/check
-
-@go_include@ hash/crc64.lo.dep
-hash/crc64.lo.dep: $(go_hash_crc64_files)
- $(BUILDDEPS)
-hash/crc64.lo: $(go_hash_crc64_files)
- $(BUILDPACKAGE)
-hash/crc64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc64/check
-
-@go_include@ hash/fnv.lo.dep
-hash/fnv.lo.dep: $(go_hash_fnv_files)
- $(BUILDDEPS)
-hash/fnv.lo: $(go_hash_fnv_files)
- $(BUILDPACKAGE)
-hash/fnv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/fnv/check
-
-@go_include@ image/color.lo.dep
-image/color.lo.dep: $(go_image_color_files)
- $(BUILDDEPS)
-image/color.lo: $(go_image_color_files)
- $(BUILDPACKAGE)
-image/color/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/check
-
-@go_include@ image/color/palette.lo.dep
-image/color/palette.lo.dep: $(go_image_color_palette_files)
- $(BUILDDEPS)
-image/color/palette.lo: $(go_image_color_palette_files)
- $(BUILDPACKAGE)
-image/color/palette/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/palette/check
-
-@go_include@ image/draw.lo.dep
-image/draw.lo.dep: $(go_image_draw_files)
- $(BUILDDEPS)
-image/draw.lo: $(go_image_draw_files)
- $(BUILDPACKAGE)
-image/draw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/draw/check
-
-@go_include@ image/gif.lo.dep
-image/gif.lo.dep: $(go_image_gif_files)
- $(BUILDDEPS)
-image/gif.lo: $(go_image_gif_files)
- $(BUILDPACKAGE)
-image/gif/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/gif/check
-
-@go_include@ image/internal/imageutil.lo.dep
-image/internal/imageutil.lo.dep: $(go_image_internal_imageutil_files)
- $(BUILDDEPS)
-image/internal/imageutil.lo: $(go_image_internal_imageutil_files)
- $(BUILDPACKAGE)
-image/internal/imageutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/internal/imageutil/check
-
-@go_include@ image/jpeg.lo.dep
-image/jpeg.lo.dep: $(go_image_jpeg_files)
- $(BUILDDEPS)
-image/jpeg.lo: $(go_image_jpeg_files)
- $(BUILDPACKAGE)
-image/jpeg/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/jpeg/check
-
-@go_include@ image/png.lo.dep
-image/png.lo.dep: $(go_image_png_files)
- $(BUILDDEPS)
-image/png.lo: $(go_image_png_files)
- $(BUILDPACKAGE)
-image/png/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/png/check
-
-@go_include@ index/suffixarray.lo.dep
-index/suffixarray.lo.dep: $(go_index_suffixarray_files)
- $(BUILDDEPS)
-index/suffixarray.lo: $(go_index_suffixarray_files)
- $(BUILDPACKAGE)
-index/suffixarray/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: index/suffixarray/check
-
-@go_include@ internal/golang.org/x/net/http2/hpack.lo.dep
-internal/golang.org/x/net/http2/hpack.lo.dep: $(go_internal_golang_org_x_net_http2_hpack_files)
- $(BUILDDEPS)
-internal/golang.org/x/net/http2/hpack.lo: $(go_internal_golang_org_x_net_http2_hpack_files)
- $(BUILDPACKAGE)
-internal/golang.org/x/net/http2/hpack/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/golang.org/x/net/http2/hpack/check
-
-@go_include@ internal/race.lo.dep
-internal/race.lo.dep: $(go_internal_race_files)
- $(BUILDDEPS)
-internal/race.lo: $(go_internal_race_files)
- $(BUILDPACKAGE)
-internal/race/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/race/check
-
-@go_include@ internal/singleflight.lo.dep
-internal/singleflight.lo.dep: $(go_internal_singleflight_files)
- $(BUILDDEPS)
-internal/singleflight.lo: $(go_internal_singleflight_files)
- $(BUILDPACKAGE)
-internal/singleflight/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/singleflight/check
-
-@go_include@ internal/syscall/unix.lo.dep
-internal/syscall/unix.lo.dep: $(go_internal_syscall_unix_files)
- $(BUILDDEPS)
-internal/syscall/unix.lo: $(go_internal_syscall_unix_files)
- $(BUILDPACKAGE)
-internal/syscall/unix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/syscall/unix/check
-
-@go_include@ internal/testenv.lo.dep
-internal/testenv.lo.dep: $(go_internal_testenv_files)
- $(BUILDDEPS)
-internal/testenv.lo: $(go_internal_testenv_files)
- $(BUILDPACKAGE)
-internal/testenv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/testenv/check
-
-@go_include@ internal/trace.lo.dep
-internal/trace.lo.dep: $(go_internal_trace_files)
- $(BUILDDEPS)
-internal/trace.lo: $(go_internal_trace_files)
- $(BUILDPACKAGE)
-internal/trace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/trace/check
-
-@go_include@ io/ioutil.lo.dep
-io/ioutil.lo.dep: $(go_io_ioutil_files)
- $(BUILDDEPS)
-io/ioutil.lo: $(go_io_ioutil_files)
- $(BUILDPACKAGE)
-io/ioutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/ioutil/check
-
-@go_include@ log/syslog.lo.dep
-log/syslog.lo.dep: $(go_log_syslog_files)
- $(BUILDDEPS)
-log/syslog.lo: $(go_log_syslog_files)
- $(BUILDPACKAGE)
-log/syslog/syslog_c.lo: $(go_syslog_c_files) log/syslog.lo
- @$(MKDIR_P) log/syslog
- $(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c
-log/syslog/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/syslog/check
-
-@go_include@ math/big.lo.dep
-math/big.lo.dep: $(go_math_big_files)
- $(BUILDDEPS)
-math/big.lo: $(go_math_big_files)
- $(BUILDPACKAGE)
-math/big/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/big/check
-
-@go_include@ math/cmplx.lo.dep
-math/cmplx.lo.dep: $(go_math_cmplx_files)
- $(BUILDDEPS)
-math/cmplx.lo: $(go_math_cmplx_files)
- $(BUILDPACKAGE)
-math/cmplx/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/cmplx/check
-
-@go_include@ math/rand.lo.dep
-math/rand.lo.dep: $(go_math_rand_files)
- $(BUILDDEPS)
-math/rand.lo: $(go_math_rand_files)
- $(BUILDPACKAGE)
-math/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/rand/check
-
-@go_include@ mime/multipart.lo.dep
-mime/multipart.lo.dep: $(go_mime_multipart_files)
- $(BUILDDEPS)
-mime/multipart.lo: $(go_mime_multipart_files)
- $(BUILDPACKAGE)
-mime/multipart/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/multipart/check
-
-@go_include@ mime/quotedprintable.lo.dep
-mime/quotedprintable.lo.dep: $(go_mime_quotedprintable_files)
- $(BUILDDEPS)
-mime/quotedprintable.lo: $(go_mime_quotedprintable_files)
- $(BUILDPACKAGE)
-mime/quotedprintable/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/quotedprintable/check
-
-@go_include@ net/http.lo.dep
-net/http.lo.dep: $(go_net_http_files)
- $(BUILDDEPS)
-net/http.lo: $(go_net_http_files)
- $(BUILDPACKAGE)
-net/http/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/check
-
-@go_include@ net/mail.lo.dep
-net/mail.lo.dep: $(go_net_mail_files)
- $(BUILDDEPS)
-net/mail.lo: $(go_net_mail_files)
- $(BUILDPACKAGE)
-net/mail/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/mail/check
-
-@go_include@ net/rpc.lo.dep
-net/rpc.lo.dep: $(go_net_rpc_files)
- $(BUILDDEPS)
-net/rpc.lo: $(go_net_rpc_files)
- $(BUILDPACKAGE)
-net/rpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/check
-
-@go_include@ net/smtp.lo.dep
-net/smtp.lo.dep: $(go_net_smtp_files)
- $(BUILDDEPS)
-net/smtp.lo: $(go_net_smtp_files)
- $(BUILDPACKAGE)
-net/smtp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/smtp/check
-
-@go_include@ net/url.lo.dep
-net/url.lo.dep: $(go_net_url_files)
- $(BUILDDEPS)
-net/url.lo: $(go_net_url_files)
- $(BUILDPACKAGE)
-net/url/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/url/check
-
-@go_include@ net/textproto.lo.dep
-net/textproto.lo.dep: $(go_net_textproto_files)
- $(BUILDDEPS)
-net/textproto.lo: $(go_net_textproto_files)
- $(BUILDPACKAGE)
-net/textproto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/textproto/check
-
-@go_include@ net/http/cgi.lo.dep
-net/http/cgi.lo.dep: $(go_net_http_cgi_files)
- $(BUILDDEPS)
-net/http/cgi.lo: $(go_net_http_cgi_files)
- $(BUILDPACKAGE)
-net/http/cgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cgi/check
-
-@go_include@ net/http/cookiejar.lo.dep
-net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
- $(BUILDDEPS)
-net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
- $(BUILDPACKAGE)
-net/http/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cookiejar/check
-
-@go_include@ net/http/fcgi.lo.dep
-net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
- $(BUILDDEPS)
-net/http/fcgi.lo: $(go_net_http_fcgi_files)
- $(BUILDPACKAGE)
-net/http/fcgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/fcgi/check
-
-@go_include@ net/http/httptest.lo.dep
-net/http/httptest.lo.dep: $(go_net_http_httptest_files)
- $(BUILDDEPS)
-net/http/httptest.lo: $(go_net_http_httptest_files)
- $(BUILDPACKAGE)
-net/http/httptest/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptest/check
-
-@go_include@ net/http/httputil.lo.dep
-net/http/httputil.lo.dep: $(go_net_http_httputil_files)
- $(BUILDDEPS)
-net/http/httputil.lo: $(go_net_http_httputil_files)
- $(BUILDPACKAGE)
-net/http/httputil/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httputil/check
-
-@go_include@ net/http/internal.lo.dep
-net/http/internal.lo.dep: $(go_net_http_internal_files)
- $(BUILDDEPS)
-net/http/internal.lo: $(go_net_http_internal_files)
- $(BUILDPACKAGE)
-net/http/internal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/internal/check
-
-@go_include@ net/http/pprof.lo.dep
-net/http/pprof.lo.dep: $(go_net_http_pprof_files)
- $(BUILDDEPS)
-net/http/pprof.lo: $(go_net_http_pprof_files)
- $(BUILDPACKAGE)
-net/http/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/pprof/check
-
-@go_include@ net/internal/socktest.lo.dep
-net/internal/socktest.lo.dep: $(go_net_internal_socktest_files)
- $(BUILDDEPS)
-net/internal/socktest.lo: $(go_net_internal_socktest_files)
- $(BUILDPACKAGE)
-net/internal/socktest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/internal/socktest/check
-
-@go_include@ net/rpc/jsonrpc.lo.dep
-net/rpc/jsonrpc.lo.dep: $(go_net_rpc_jsonrpc_files)
- $(BUILDDEPS)
-net/rpc/jsonrpc.lo: $(go_net_rpc_jsonrpc_files)
- $(BUILDPACKAGE)
-net/rpc/jsonrpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/jsonrpc/check
-
-@go_include@ old/regexp.lo.dep
-old/regexp.lo.dep: $(go_old_regexp_files)
- $(BUILDDEPS)
-old/regexp.lo: $(go_old_regexp_files)
- $(BUILDPACKAGE)
-old/regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/regexp/check
-
-@go_include@ old/template.lo.dep
-old/template.lo.dep: $(go_old_template_files)
- $(BUILDDEPS)
-old/template.lo: $(go_old_template_files)
- $(BUILDPACKAGE)
-old/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/template/check
-
-@go_include@ os/exec.lo.dep
-os/exec.lo.dep: $(go_os_exec_files)
- $(BUILDDEPS)
-os/exec.lo: $(go_os_exec_files)
- $(BUILDPACKAGE)
-os/exec/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/exec/check
-
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(go_os_signal_files)
- $(BUILDDEPS)
-os/signal.lo: $(go_os_signal_files)
- $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/signal/check
-
-@go_include@ os/user.lo.dep
-os/user.lo.dep: $(go_os_user_files)
- $(BUILDDEPS)
-os/user.lo: $(go_os_user_files)
- $(BUILDPACKAGE)
-os/user/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/user/check
-
-@go_include@ path/filepath.lo.dep
-path/filepath.lo.dep: $(go_path_filepath_files)
- $(BUILDDEPS)
-path/filepath.lo: $(go_path_filepath_files)
- $(BUILDPACKAGE)
-path/filepath/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/filepath/check
-
-@go_include@ regexp/syntax.lo.dep
-regexp/syntax.lo.dep: $(go_regexp_syntax_files)
- $(BUILDDEPS)
-regexp/syntax.lo: $(go_regexp_syntax_files)
- $(BUILDPACKAGE)
-regexp/syntax/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/syntax/check
-
-@go_include@ runtime/debug.lo.dep
-runtime/debug.lo.dep: $(go_runtime_debug_files)
- $(BUILDDEPS)
-runtime/debug.lo: $(go_runtime_debug_files)
- $(BUILDPACKAGE)
-runtime/debug/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/debug/check
-
-@go_include@ runtime/pprof.lo.dep
-runtime/pprof.lo.dep: $(go_runtime_pprof_files)
- $(BUILDDEPS)
-runtime/pprof.lo: $(go_runtime_pprof_files)
- $(BUILDPACKAGE)
-runtime/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/pprof/check
+# PACKAGE_template defines the rules for each package.
+# For example, for the package bufio, it produces:
+#
+# @go_include@ bufio.lo.dep
+# bufio.lo.dep: $(srcdir)/go/bufio/*.go
+# $(BUILDDEPS)
+# bufio.lo:
+# $(BUILDPACKAGE)
+# bufio/check: $(CHECK_DEPS)
+# @$(CHECK)
+# .PHONY: bufio/check
+#
+# This is invoked with $(1) set to a package, which is a directory name,
+# such as "bufio" or "archive/tar".
+define PACKAGE_template
+@go_include@ $(1).lo.dep
+$(1).lo.dep: $(srcdir)/go/$(1)/*.go
+ $$(BUILDDEPS)
+$(1).lo:
+ $$(BUILDPACKAGE)
+$(1)/check: $$(CHECK_DEPS)
+ @$$(CHECK)
+.PHONY: $(1)/check
+$(1).gox: $(1).s-gox; @true
+$(1).s-gox: $(1).lo
+ $$(BUILDGOX)
+ $$(STAMP) $$@
+endef
+
+# This line expands PACKAGE_template once for each package name listed
+# in $(PACKAGES).
+$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
+
+# Pass -ffp-contract=off, or 386-specific options, when building the
+# math package. MATH_FLAG is defined in configure.ac.
+math_lo_GOCFLAGS = $(MATH_FLAG)
+
+# Add the generated file runtime_sysinfo.go to the runtime package.
+extra_go_files_runtime = runtime_sysinfo.go sigtab.go
+runtime.lo.dep: $(extra_go_files_runtime)
+
+# Add generated files to the syscall package.
+extra_go_files_syscall = \
+ libcalls.go \
+ sysinfo.go \
+ syscall_arch.go \
+ $(syscall_epoll_file)
+syscall.lo.dep: $(extra_go_files_syscall)
+
+# Pass -fgo-compiling-runtime when compiling the runtime package.
+runtime_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
+runtime_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime
+
+# If libffi is supported (the normal case) use the ffi build tag for
+# the runtime package.
+if USE_LIBFFI
+matchargs_runtime = --tag=libffi
+else
+matchargs_runtime =
+endif
+
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
-@go_include@ sync/atomic.lo.dep
-sync/atomic.lo.dep: $(go_sync_atomic_files)
- $(BUILDDEPS)
-sync/atomic.lo: $(go_sync_atomic_files)
- $(BUILDPACKAGE)
-sync/atomic_c.lo: $(go_sync_atomic_c_files) sync/atomic.lo
+extra_go_files_runtime_internal_sys = version.go
+runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
+
+# FIXME: The following C files may as well move to the runtime
+# directory and be treated like other C files.
+
+# Use C code to speed up {bytes,strings}.IndexByte and friends.
+bytes/index.lo: go/bytes/indexbyte.c runtime.inc
+ @$(MKDIR_P) bytes
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/bytes/indexbyte.c
+strings/index.lo: go/strings/indexbyte.c runtime.inc
+ @$(MKDIR_P) strings
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/strings/indexbyte.c
+
+# Use a C function with a fixed number of arguments to call a C
+# varargs function.
+log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc
+ @$(MKDIR_P) log/syslog
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c
+
+# The interface to libffi from the reflect package is written in C.
+reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
+ @$(MKDIR_P) reflect
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/reflect/makefunc_ffi_c.c
+
+# The atomic functions are written in C.
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) runtime/internal
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
+sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) sync
$(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c
-sync/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/atomic/check
-
-@go_include@ text/scanner.lo.dep
-text/scanner.lo.dep: $(go_text_scanner_files)
- $(BUILDDEPS)
-text/scanner.lo: $(go_text_scanner_files)
- $(BUILDPACKAGE)
-text/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/scanner/check
-
-@go_include@ text/tabwriter.lo.dep
-text/tabwriter.lo.dep: $(go_text_tabwriter_files)
- $(BUILDDEPS)
-text/tabwriter.lo: $(go_text_tabwriter_files)
- $(BUILDPACKAGE)
-text/tabwriter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/tabwriter/check
-
-@go_include@ text/template.lo.dep
-text/template.lo.dep: $(go_text_template_files)
- $(BUILDDEPS)
-text/template.lo: $(go_text_template_files)
- $(BUILDPACKAGE)
-text/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/check
-
-@go_include@ text/template/parse.lo.dep
-text/template/parse.lo.dep: $(go_text_template_parse_files)
- $(BUILDDEPS)
-text/template/parse.lo: $(go_text_template_parse_files)
- $(BUILDPACKAGE)
-text/template/parse/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/parse/check
-
-@go_include@ testing/iotest.lo.dep
-testing/iotest.lo.dep: $(go_testing_iotest_files)
- $(BUILDDEPS)
-testing/iotest.lo: $(go_testing_iotest_files)
- $(BUILDPACKAGE)
-testing/iotest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/iotest/check
-
-@go_include@ testing/quick.lo.dep
-testing/quick.lo.dep: $(go_testing_quick_files)
- $(BUILDDEPS)
-testing/quick.lo: $(go_testing_quick_files)
- $(BUILDPACKAGE)
-testing/quick/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/quick/check
-
-@go_include@ unicode/utf16.lo.dep
-unicode/utf16.lo.dep: $(go_unicode_utf16_files)
- $(BUILDDEPS)
-unicode/utf16.lo: $(go_unicode_utf16_files)
- $(BUILDPACKAGE)
-unicode/utf16/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf16/check
-
-@go_include@ unicode/utf8.lo.dep
-unicode/utf8.lo.dep: $(go_unicode_utf8_files)
- $(BUILDDEPS)
-unicode/utf8.lo: $(go_unicode_utf8_files)
- $(BUILDPACKAGE)
-unicode/utf8/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf8/check
-
-@go_include@ syscall.lo.dep
-syscall.lo.dep: $(go_syscall_files)
- $(BUILDDEPS)
-syscall.lo: $(go_syscall_files)
- $(BUILDPACKAGE)
-syscall/errno.lo: go/syscall/errno.c
+
+# A few syscall functions are written in C.
+syscall/clone_linux.lo: go/syscall/clone_linux.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/signame.lo: go/syscall/signame.c
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/clone_linux.c
+syscall/errno.lo: go/syscall/errno.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/wait.lo: go/syscall/wait.c
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/errno.c
+syscall/signame.lo: go/syscall/signame.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: syscall/check
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/signame.c
+syscall/wait.lo: go/syscall/wait.c runtime.inc
+ @$(MKDIR_P) syscall
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
-# How to build a .gox file from a .lo file.
-BUILDGOX = \
- f=`echo $< | sed -e 's/.lo$$/.o/'`; \
- $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
-
-bufio.gox: bufio.lo
- $(BUILDGOX)
-bytes.gox: bytes.lo
- $(BUILDGOX)
-crypto.gox: crypto.lo
- $(BUILDGOX)
-encoding.gox: encoding.lo
- $(BUILDGOX)
-errors.gox: errors.lo
- $(BUILDGOX)
-expvar.gox: expvar.lo
- $(BUILDGOX)
-flag.gox: flag.lo
- $(BUILDGOX)
-fmt.gox: fmt.lo
- $(BUILDGOX)
-hash.gox: hash.lo
- $(BUILDGOX)
-html.gox: html.lo
- $(BUILDGOX)
-image.gox: image.lo
- $(BUILDGOX)
-io.gox: io.lo
- $(BUILDGOX)
-log.gox: log.lo
- $(BUILDGOX)
-math.gox: math.lo
- $(BUILDGOX)
-mime.gox: mime.lo
- $(BUILDGOX)
-net.gox: net.lo
- $(BUILDGOX)
-os.gox: os.lo
- $(BUILDGOX)
-path.gox: path.lo
- $(BUILDGOX)
-reflect.gox: reflect-go.lo
- $(BUILDGOX)
-regexp.gox: regexp.lo
- $(BUILDGOX)
-runtime.gox: runtime-go.lo
- $(BUILDGOX)
-sort.gox: sort.lo
- $(BUILDGOX)
-strconv.gox: strconv.lo
- $(BUILDGOX)
-strings.gox: strings.lo
- $(BUILDGOX)
-sync.gox: sync.lo
- $(BUILDGOX)
-syscall.gox: syscall.lo
- $(BUILDGOX)
-testing.gox: testing.lo
- $(BUILDGOX)
-time.gox: time-go.lo
- $(BUILDGOX)
-unicode.gox: unicode.lo
- $(BUILDGOX)
-
-archive/tar.gox: archive/tar.lo
- $(BUILDGOX)
-archive/zip.gox: archive/zip.lo
- $(BUILDGOX)
-
-compress/bzip2.gox: compress/bzip2.lo
- $(BUILDGOX)
-compress/flate.gox: compress/flate.lo
- $(BUILDGOX)
-compress/gzip.gox: compress/gzip.lo
- $(BUILDGOX)
-compress/lzw.gox: compress/lzw.lo
- $(BUILDGOX)
-compress/zlib.gox: compress/zlib.lo
- $(BUILDGOX)
-
-container/heap.gox: container/heap.lo
- $(BUILDGOX)
-container/list.gox: container/list.lo
- $(BUILDGOX)
-container/ring.gox: container/ring.lo
- $(BUILDGOX)
-
-crypto/aes.gox: crypto/aes.lo
- $(BUILDGOX)
-crypto/cipher.gox: crypto/cipher.lo
- $(BUILDGOX)
-crypto/des.gox: crypto/des.lo
- $(BUILDGOX)
-crypto/dsa.gox: crypto/dsa.lo
- $(BUILDGOX)
-crypto/ecdsa.gox: crypto/ecdsa.lo
- $(BUILDGOX)
-crypto/elliptic.gox: crypto/elliptic.lo
- $(BUILDGOX)
-crypto/hmac.gox: crypto/hmac.lo
- $(BUILDGOX)
-crypto/md5.gox: crypto/md5.lo
- $(BUILDGOX)
-crypto/rand.gox: crypto/rand.lo
- $(BUILDGOX)
-crypto/rc4.gox: crypto/rc4.lo
- $(BUILDGOX)
-crypto/rsa.gox: crypto/rsa.lo
- $(BUILDGOX)
-crypto/sha1.gox: crypto/sha1.lo
- $(BUILDGOX)
-crypto/sha256.gox: crypto/sha256.lo
- $(BUILDGOX)
-crypto/sha512.gox: crypto/sha512.lo
- $(BUILDGOX)
-crypto/subtle.gox: crypto/subtle.lo
- $(BUILDGOX)
-crypto/tls.gox: crypto/tls.lo
- $(BUILDGOX)
-crypto/x509.gox: crypto/x509.lo
- $(BUILDGOX)
-
-crypto/x509/pkix.gox: crypto/x509/pkix.lo
- $(BUILDGOX)
-
-database/sql.gox: database/sql.lo
- $(BUILDGOX)
-
-database/sql/driver.gox: database/sql/driver.lo
- $(BUILDGOX)
-
-debug/dwarf.gox: debug/dwarf.lo
- $(BUILDGOX)
-debug/elf.gox: debug/elf.lo
- $(BUILDGOX)
-debug/gosym.gox: debug/gosym.lo
- $(BUILDGOX)
-debug/macho.gox: debug/macho.lo
- $(BUILDGOX)
-debug/pe.gox: debug/pe.lo
- $(BUILDGOX)
-debug/plan9obj.gox: debug/plan9obj.lo
- $(BUILDGOX)
-
-encoding/ascii85.gox: encoding/ascii85.lo
- $(BUILDGOX)
-encoding/asn1.gox: encoding/asn1.lo
- $(BUILDGOX)
-encoding/base32.gox: encoding/base32.lo
- $(BUILDGOX)
-encoding/base64.gox: encoding/base64.lo
- $(BUILDGOX)
-encoding/binary.gox: encoding/binary.lo
- $(BUILDGOX)
-encoding/csv.gox: encoding/csv.lo
- $(BUILDGOX)
-encoding/gob.gox: encoding/gob.lo
- $(BUILDGOX)
-encoding/hex.gox: encoding/hex.lo
- $(BUILDGOX)
-encoding/json.gox: encoding/json.lo
- $(BUILDGOX)
-encoding/pem.gox: encoding/pem.lo
- $(BUILDGOX)
-encoding/xml.gox: encoding/xml.lo
- $(BUILDGOX)
-
-exp/proxy.gox: exp/proxy.lo
- $(BUILDGOX)
-exp/terminal.gox: exp/terminal.lo
- $(BUILDGOX)
-
-html/template.gox: html/template.lo
- $(BUILDGOX)
-
-go/ast.gox: go/ast.lo
- $(BUILDGOX)
-go/build.gox: go/build.lo
- $(BUILDGOX)
-go/constant.gox: go/constant.lo
- $(BUILDGOX)
-go/doc.gox: go/doc.lo
- $(BUILDGOX)
-go/format.gox: go/format.lo
- $(BUILDGOX)
-go/importer.gox: go/importer.lo
- $(BUILDGOX)
-go/parser.gox: go/parser.lo
- $(BUILDGOX)
-go/printer.gox: go/printer.lo
- $(BUILDGOX)
-go/scanner.gox: go/scanner.lo
- $(BUILDGOX)
-go/token.gox: go/token.lo
- $(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
-
-go/internal/gcimporter.gox: go/internal/gcimporter.lo
- $(BUILDGOX)
-go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo
- $(BUILDGOX)
-
-hash/adler32.gox: hash/adler32.lo
- $(BUILDGOX)
-hash/crc32.gox: hash/crc32.lo
- $(BUILDGOX)
-hash/crc64.gox: hash/crc64.lo
- $(BUILDGOX)
-hash/fnv.gox: hash/fnv.lo
- $(BUILDGOX)
-
-image/color.gox: image/color.lo
- $(BUILDGOX)
-image/draw.gox: image/draw.lo
- $(BUILDGOX)
-image/gif.gox: image/gif.lo
- $(BUILDGOX)
-image/internal/imageutil.gox: image/internal/imageutil.lo
- $(BUILDGOX)
-image/jpeg.gox: image/jpeg.lo
- $(BUILDGOX)
-image/png.gox: image/png.lo
- $(BUILDGOX)
-
-image/color/palette.gox: image/color/palette.lo
- $(BUILDGOX)
-
-index/suffixarray.gox: index/suffixarray.lo
- $(BUILDGOX)
-
-internal/golang.org/x/net/http2/hpack.gox: internal/golang.org/x/net/http2/hpack.lo
- $(BUILDGOX)
-internal/race.gox: internal/race.lo
- $(BUILDGOX)
-internal/singleflight.gox: internal/singleflight.lo
- $(BUILDGOX)
-internal/syscall/unix.gox: internal/syscall/unix.lo
- $(BUILDGOX)
-internal/testenv.gox: internal/testenv.lo
- $(BUILDGOX)
-internal/trace.gox: internal/trace.lo
- $(BUILDGOX)
-
-io/ioutil.gox: io/ioutil.lo
- $(BUILDGOX)
-
-log/syslog.gox: log/syslog.lo
- $(BUILDGOX)
-
-math/big.gox: math/big.lo
- $(BUILDGOX)
-math/cmplx.gox: math/cmplx.lo
- $(BUILDGOX)
-math/rand.gox: math/rand.lo
- $(BUILDGOX)
-
-mime/multipart.gox: mime/multipart.lo
- $(BUILDGOX)
-mime/quotedprintable.gox: mime/quotedprintable.lo
- $(BUILDGOX)
-
-net/http.gox: net/http.lo
- $(BUILDGOX)
-net/mail.gox: net/mail.lo
- $(BUILDGOX)
-net/rpc.gox: net/rpc.lo
- $(BUILDGOX)
-net/smtp.gox: net/smtp.lo
- $(BUILDGOX)
-net/textproto.gox: net/textproto.lo
- $(BUILDGOX)
-net/url.gox: net/url.lo
- $(BUILDGOX)
-
-net/http/cgi.gox: net/http/cgi.lo
- $(BUILDGOX)
-net/http/cookiejar.gox: net/http/cookiejar.lo
- $(BUILDGOX)
-net/http/fcgi.gox: net/http/fcgi.lo
- $(BUILDGOX)
-net/http/httptest.gox: net/http/httptest.lo
- $(BUILDGOX)
-net/http/httputil.gox: net/http/httputil.lo
- $(BUILDGOX)
-net/http/pprof.gox: net/http/pprof.lo
- $(BUILDGOX)
-
-net/http/internal.gox: net/http/internal.lo
- $(BUILDGOX)
-
-net/internal/socktest.gox: net/internal/socktest.lo
- $(BUILDGOX)
-
-net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
- $(BUILDGOX)
-
-old/regexp.gox: old/regexp.lo
- $(BUILDGOX)
-old/template.gox: old/template.lo
- $(BUILDGOX)
-
-os/exec.gox: os/exec.lo
- $(BUILDGOX)
-os/signal.gox: os/signal.lo
- $(BUILDGOX)
-os/user.gox: os/user.lo
- $(BUILDGOX)
-
-path/filepath.gox: path/filepath.lo
- $(BUILDGOX)
-
-regexp/syntax.gox: regexp/syntax.lo
- $(BUILDGOX)
-
-runtime/debug.gox: runtime/debug.lo
- $(BUILDGOX)
-runtime/pprof.gox: runtime/pprof.lo
- $(BUILDGOX)
-
-sync/atomic.gox: sync/atomic.lo
- $(BUILDGOX)
-
-text/scanner.gox: text/scanner.lo
- $(BUILDGOX)
-text/tabwriter.gox: text/tabwriter.lo
- $(BUILDGOX)
-text/template.gox: text/template.lo
- $(BUILDGOX)
-text/template/parse.gox: text/template/parse.lo
- $(BUILDGOX)
-
-testing/iotest.gox: testing/iotest.lo
- $(BUILDGOX)
-testing/quick.gox: testing/quick.lo
- $(BUILDGOX)
-
-unicode/utf16.gox: unicode/utf16.lo
- $(BUILDGOX)
-unicode/utf8.gox: unicode/utf8.lo
- $(BUILDGOX)
+# Solaris 12 changed the type of fields in struct stat.
+# Use a build tag, based on a configure check, to cope.
+if LIBGO_IS_SOLARIS
+if HAVE_STAT_TIMESPEC
+matchargs_os = --tag=solaristag
+else
+matchargs_os =
+endif
+else
+matchargs_os =
+endif
+
+if LIBGO_IS_BSD
+
+# Build golang_org/x/net/route only on BSD systems.
+
+$(eval $(call PACKAGE_template,golang_org/x/net/route))
+
+golang_org_x_net_route_lo = \
+ golang_org/x/net/route.lo
+golang_org_x_net_route_check = \
+ golang_org/x/net/route/check
+
+endif
+
+if LIBGO_IS_SOLARIS
+
+# Build golang_org/x/net/lif only on Solaris systems.
+
+$(eval $(call PACKAGE_template,golang_org/x/net/lif))
+
+golang_org_x_net_lif_lo = \
+ golang_org/x/net/lif.lo
+golang_org_x_net_lif_check = \
+ golang_org/x/net/lif/check
+
+endif
TEST_PACKAGES = \
bufio/check \
bytes/check \
+ context/check \
errors/check \
expvar/check \
flag/check \
@@ -4252,6 +1243,15 @@ TEST_PACKAGES = \
go/scanner/check \
go/token/check \
go/types/check \
+ golang_org/x/crypto/chacha20poly1305/check \
+ golang_org/x/crypto/chacha20poly1305/internal/chacha20/check \
+ golang_org/x/crypto/curve25519/check \
+ golang_org/x/crypto/poly1305/check \
+ golang_org/x/net/http2/hpack/check \
+ golang_org/x/net/idna/check \
+ golang_org/x/net/lex/httplex/check \
+ $(golang_org_x_net_lif_check) \
+ $(golang_org_x_net_route_check) \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@@ -4261,7 +1261,7 @@ TEST_PACKAGES = \
image/jpeg/check \
image/png/check \
index/suffixarray/check \
- internal/golang.org/x/net/http2/hpack/check \
+ internal/pprof/profile/check \
internal/singleflight/check \
internal/trace/check \
io/ioutil/check \
@@ -4276,6 +1276,7 @@ TEST_PACKAGES = \
net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
+ net/http/httptrace/check \
net/http/httputil/check \
net/http/internal/check \
net/internal/socktest/check \
@@ -4285,14 +1286,16 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
- old/regexp/check \
- old/template/check \
os/exec/check \
os/signal/check \
os/user/check \
path/filepath/check \
regexp/syntax/check \
+ runtime/debug/check \
+ runtime/internal/atomic/check \
+ runtime/internal/sys/check \
runtime/pprof/check \
+ runtime/pprof/internal/protopprof/check \
sync/atomic/check \
text/scanner/check \
text/tabwriter/check \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 216ab6a9b1..d6e3eace40 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -71,6 +71,7 @@ DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(srcdir)/../depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+ $(top_srcdir)/../config/hwcaps.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../config/multi.m4 \
$(top_srcdir)/../config/override.m4 \
@@ -139,13 +140,13 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgonetdir)" \
"$(DESTDIR)$(toolexeclibgonethttpdir)" \
"$(DESTDIR)$(toolexeclibgonetrpcdir)" \
- "$(DESTDIR)$(toolexeclibgoolddir)" \
"$(DESTDIR)$(toolexeclibgoosdir)" \
"$(DESTDIR)$(toolexeclibgopathdir)" \
"$(DESTDIR)$(toolexeclibgoregexpdir)" \
"$(DESTDIR)$(toolexeclibgoruntimedir)" \
"$(DESTDIR)$(toolexeclibgosyncdir)" \
"$(DESTDIR)$(toolexeclibgotestingdir)" \
+ "$(DESTDIR)$(toolexeclibgotestinginternaldir)" \
"$(DESTDIR)$(toolexeclibgotextdir)" \
"$(DESTDIR)$(toolexeclibgotexttemplatedir)" \
"$(DESTDIR)$(toolexeclibgounicodedir)"
@@ -163,121 +164,54 @@ libgolibbegin_a_AR = $(AR) $(ARFLAGS)
libgolibbegin_a_LIBADD =
am_libgolibbegin_a_OBJECTS = libgolibbegin_a-go-libmain.$(OBJEXT)
libgolibbegin_a_OBJECTS = $(am_libgolibbegin_a_OBJECTS)
-libnetgo_a_AR = $(AR) $(ARFLAGS)
-libnetgo_a_DEPENDENCIES = netgo.o
-am__objects_1 =
-am__objects_2 = $(am__objects_1) $(am__objects_1) $(am__objects_1) \
- $(am__objects_1) $(am__objects_1) $(am__objects_1) \
- $(am__objects_1)
-am__objects_3 = $(am__objects_2)
-am_libnetgo_a_OBJECTS = $(am__objects_3)
-libnetgo_a_OBJECTS = $(am_libnetgo_a_OBJECTS)
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
-am__DEPENDENCIES_1 =
-am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
- encoding.lo errors.lo expvar.lo flag.lo fmt.lo hash.lo html.lo \
- image.lo io.lo log.lo math.lo mime.lo net.lo os.lo path.lo \
- reflect-go.lo reflect/makefunc_ffi_c.lo regexp.lo \
- runtime-go.lo sort.lo strconv.lo strings.lo strings/index.lo \
- sync.lo syscall.lo syscall/errno.lo syscall/signame.lo \
- syscall/wait.lo testing.lo time-go.lo unicode.lo \
- archive/tar.lo archive/zip.lo compress/bzip2.lo \
- compress/flate.lo compress/gzip.lo compress/lzw.lo \
- compress/zlib.lo container/heap.lo container/list.lo \
- container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \
- crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
- crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \
- crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
- crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
- crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
- debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
- debug/pe.lo debug/plan9obj.lo encoding/ascii85.lo \
- encoding/asn1.lo encoding/base32.lo encoding/base64.lo \
- encoding/binary.lo encoding/csv.lo encoding/gob.lo \
- encoding/hex.lo encoding/json.lo encoding/pem.lo \
- encoding/xml.lo exp/proxy.lo exp/terminal.lo html/template.lo \
- go/ast.lo go/build.lo go/constant.lo go/doc.lo go/format.lo \
- go/importer.lo go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo go/parser.lo go/printer.lo \
- go/scanner.lo go/token.lo go/types.lo hash/adler32.lo \
- hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
- net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
- net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
- image/color.lo image/color/palette.lo image/draw.lo \
- image/gif.lo image/internal/imageutil.lo image/jpeg.lo \
- image/png.lo index/suffixarray.lo \
- internal/golang.org/x/net/http2/hpack.lo internal/race.lo \
- internal/singleflight.lo internal/syscall/unix.lo \
- internal/testenv.lo internal/trace.lo io/ioutil.lo \
- log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
- math/rand.lo mime/multipart.lo mime/quotedprintable.lo \
- net/http.lo net/internal/socktest.lo net/mail.lo net/rpc.lo \
- net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \
- old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \
- os/user.lo path/filepath.lo regexp/syntax.lo \
- net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
- sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
- text/tabwriter.lo text/template.lo text/template/parse.lo \
- testing/iotest.lo testing/quick.lo unicode/utf16.lo \
- unicode/utf8.lo
-am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) \
- ../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
-@LIBGO_IS_LINUX_FALSE@am__objects_4 = lock_sema.lo thread-sema.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_4 = lock_futex.lo thread-linux.lo
-@HAVE_SYS_MMAN_H_FALSE@am__objects_5 = mem_posix_memalign.lo
-@HAVE_SYS_MMAN_H_TRUE@am__objects_5 = mem.lo
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_6 = netpoll_kqueue.lo
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_6 = netpoll_select.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_6 = netpoll_epoll.lo
-@LIBGO_IS_RTEMS_TRUE@am__objects_7 = rtems-task-variable-add.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-none.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_8 = getncpu-solaris.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_8 = getncpu-irix.lo
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_8 = \
+@LIBGO_IS_LINUX_TRUE@am__DEPENDENCIES_1 = syscall/clone_linux.lo
+am__DEPENDENCIES_2 = $(addsuffix .lo,$(PACKAGES)) bytes/index.lo \
+ reflect/makefunc_ffi_c.lo strings/index.lo \
+ $(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \
+ syscall/wait.lo $(golang_org_x_net_lif_lo) \
+ $(golang_org_x_net_route_lo) log/syslog/syslog_c.lo \
+ runtime/internal/atomic_c.lo sync/atomic_c.lo
+am__DEPENDENCIES_3 =
+am__DEPENDENCIES_4 = $(am__DEPENDENCIES_2) \
+ ../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_3)
+libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_4)
+@HAVE_SYS_MMAN_H_FALSE@am__objects_1 = mem_posix_memalign.lo
+@HAVE_SYS_MMAN_H_TRUE@am__objects_1 = mem.lo
+@LIBGO_IS_LINUX_FALSE@am__objects_2 = thread-sema.lo
+@LIBGO_IS_LINUX_TRUE@am__objects_2 = thread-linux.lo
+@LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-none.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_4 = getncpu-solaris.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = getncpu-irix.lo
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_8 = getncpu-linux.lo
-am__objects_9 = go-append.lo go-assert.lo go-assert-interface.lo \
- go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
- go-callers.lo go-can-convert-interface.lo go-cdiv.lo go-cgo.lo \
- go-check-interface.lo go-construct-map.lo \
- go-convert-interface.lo go-copy.lo go-defer.lo \
- go-deferred-recover.lo go-eface-compare.lo \
- go-eface-val-compare.lo go-ffi.lo go-fieldtrack.lo \
- go-int-array-to-string.lo go-int-to-string.lo \
- go-interface-compare.lo go-interface-eface-compare.lo \
- go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
- go-map-index.lo go-map-len.lo go-map-range.lo go-matherr.lo \
- go-memcmp.lo go-nanotime.lo go-now.lo go-new-map.lo go-new.lo \
- go-nosys.lo go-panic.lo go-print.lo go-recover.lo \
- go-reflect-call.lo go-reflect-map.lo go-rune.lo \
- go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \
- go-string-to-byte-array.lo go-string-to-int-array.lo \
- go-strplus.lo go-strslice.lo go-traceback.lo \
- go-type-complex.lo go-type-eface.lo go-type-error.lo \
- go-type-float.lo go-type-identity.lo go-type-interface.lo \
- go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
- go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
- go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo \
- $(am__objects_4) mcache.lo mcentral.lo $(am__objects_5) \
- mfixalloc.lo mgc0.lo mheap.lo msize.lo $(am__objects_6) \
- panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
- thread.lo yield.lo $(am__objects_7) chan.lo cpuprof.lo \
- go-iface.lo lfstack.lo malloc.lo map.lo mprof.lo netpoll.lo \
- rdebug.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo \
- time.lo $(am__objects_8)
-am_libgo_llgo_la_OBJECTS = $(am__objects_9)
+@LIBGO_IS_LINUX_TRUE@am__objects_4 = getncpu-linux.lo
+am__objects_5 = aeshash.lo go-assert.lo go-breakpoint.lo go-caller.lo \
+ go-callers.lo go-cdiv.lo go-cgo.lo go-construct-map.lo \
+ go-ffi.lo go-fieldtrack.lo go-matherr.lo go-memclr.lo \
+ go-memcmp.lo go-memequal.lo go-memmove.lo go-nanotime.lo \
+ go-now.lo go-new.lo go-nosys.lo go-reflect-call.lo \
+ go-runtime-error.lo go-setenv.lo go-signal.lo go-strslice.lo \
+ go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \
+ go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \
+ env_posix.lo heapdump.lo mcache.lo mcentral.lo \
+ $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
+ panic.lo parfor.lo print.lo proc.lo runtime_c.lo thread.lo \
+ $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
+ $(am__objects_4)
+am_libgo_llgo_la_OBJECTS = $(am__objects_5)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libgo_llgo_la_LDFLAGS) $(LDFLAGS) -o $@
@GOC_IS_LLGO_TRUE@am_libgo_llgo_la_rpath = -rpath $(toolexeclibdir)
-libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
-am_libgo_la_OBJECTS = $(am__objects_9)
+libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_4)
+am_libgo_la_OBJECTS = $(am__objects_5)
libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(libgo_la_LDFLAGS) \
@@ -297,8 +231,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
- $(libgolibbegin_a_SOURCES) $(libnetgo_a_SOURCES) \
- $(libgo_llgo_la_SOURCES) $(libgo_la_SOURCES)
+ $(libgolibbegin_a_SOURCES) $(libgo_llgo_la_SOURCES) \
+ $(libgo_la_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -329,12 +263,12 @@ DATA = $(noinst_DATA) $(toolexeclibgo_DATA) \
$(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
$(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \
$(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \
- $(toolexeclibgonetrpc_DATA) $(toolexeclibgoold_DATA) \
- $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
- $(toolexeclibgoregexp_DATA) $(toolexeclibgoruntime_DATA) \
- $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
- $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
- $(toolexeclibgounicode_DATA)
+ $(toolexeclibgonetrpc_DATA) $(toolexeclibgoos_DATA) \
+ $(toolexeclibgopath_DATA) $(toolexeclibgoregexp_DATA) \
+ $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \
+ $(toolexeclibgotesting_DATA) \
+ $(toolexeclibgotestinginternal_DATA) $(toolexeclibgotext_DATA) \
+ $(toolexeclibgotexttemplate_DATA) $(toolexeclibgounicode_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@@ -343,6 +277,9 @@ ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = testsuite
ACLOCAL = @ACLOCAL@
+ALLGOARCH = @ALLGOARCH@
+ALLGOARCHFAMILY = @ALLGOARCHFAMILY@
+ALLGOOS = @ALLGOOS@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
@@ -367,6 +304,14 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GOARCH = @GOARCH@
+GOARCH_BIGENDIAN = @GOARCH_BIGENDIAN@
+GOARCH_CACHELINESIZE = @GOARCH_CACHELINESIZE@
+GOARCH_FAMILY = @GOARCH_FAMILY@
+GOARCH_HUGEPAGESIZE = @GOARCH_HUGEPAGESIZE@
+GOARCH_INT64ALIGN = @GOARCH_INT64ALIGN@
+GOARCH_MINFRAMESIZE = @GOARCH_MINFRAMESIZE@
+GOARCH_PCQUANTUM = @GOARCH_PCQUANTUM@
+GOARCH_PHYSPAGESIZE = @GOARCH_PHYSPAGESIZE@
GOC = @GOC@
GOCFLAGS = $(CFLAGS)
GOOS = @GOOS@
@@ -376,6 +321,7 @@ GO_SPLIT_STACK = @GO_SPLIT_STACK@
GO_SYSCALL_OS_ARCH_FILE = @GO_SYSCALL_OS_ARCH_FILE@
GO_SYSCALL_OS_FILE = @GO_SYSCALL_OS_FILE@
GREP = @GREP@
+HWCAP_CFLAGS = @HWCAP_CFLAGS@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -513,7 +459,7 @@ AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) $(PTHREAD_CFLAGS)
ACLOCAL_AMFLAGS = -I ./config -I ../config
AM_CFLAGS = -fexceptions -fnon-call-exceptions -fplan9-extensions \
$(SPLIT_STACK) $(WARN_CFLAGS) \
- $(STRINGOPS_FLAG) $(OSCFLAGS) \
+ $(STRINGOPS_FLAG) $(HWCAP_CFLAGS) $(OSCFLAGS) \
-I $(srcdir)/../libgcc -I $(srcdir)/../libbacktrace \
-I $(MULTIBUILDTOP)../../gcc/include
@@ -571,11 +517,12 @@ AM_MAKEFLAGS = \
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la
@GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.la
-@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a
+@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
@GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a
toolexeclibgo_DATA = \
bufio.gox \
bytes.gox \
+ context.gox \
crypto.gox \
encoding.gox \
errors.gox \
@@ -758,6 +705,7 @@ toolexeclibgonethttp_DATA = \
net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
+ net/http/httptrace.gox \
net/http/httputil.gox \
net/http/pprof.gox
@@ -765,11 +713,6 @@ toolexeclibgonetrpcdir = $(toolexeclibgonetdir)/rpc
toolexeclibgonetrpc_DATA = \
net/rpc/jsonrpc.gox
-toolexeclibgoolddir = $(toolexeclibgodir)/old
-toolexeclibgoold_DATA = \
- old/regexp.gox \
- old/template.gox
-
toolexeclibgoosdir = $(toolexeclibgodir)/os
toolexeclibgoos_DATA = \
os/exec.gox \
@@ -787,7 +730,8 @@ toolexeclibgoregexp_DATA = \
toolexeclibgoruntimedir = $(toolexeclibgodir)/runtime
toolexeclibgoruntime_DATA = \
runtime/debug.gox \
- runtime/pprof.gox
+ runtime/pprof.gox \
+ runtime/trace.gox
toolexeclibgosyncdir = $(toolexeclibgodir)/sync
toolexeclibgosync_DATA = \
@@ -798,6 +742,10 @@ toolexeclibgotesting_DATA = \
testing/iotest.gox \
testing/quick.gox
+toolexeclibgotestinginternaldir = $(toolexeclibgotestingdir)/internal
+toolexeclibgotestinginternal_DATA = \
+ testing/internal/testdeps.gox
+
toolexeclibgotextdir = $(toolexeclibgodir)/text
toolexeclibgotext_DATA = \
text/scanner.gox \
@@ -817,8 +765,8 @@ toolexeclibgounicode_DATA = \
@HAVE_SYS_MMAN_H_TRUE@runtime_mem_file = runtime/mem.c
@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
-@LIBGO_IS_LINUX_FALSE@runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c
-@LIBGO_IS_LINUX_TRUE@runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c
+@LIBGO_IS_LINUX_FALSE@runtime_thread_files = runtime/thread-sema.c
+@LIBGO_IS_LINUX_TRUE@runtime_thread_files = runtime/thread-linux.c
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-none.c
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@@ -826,69 +774,31 @@ toolexeclibgounicode_DATA = \
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-irix.c
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@LIBGO_IS_LINUX_TRUE@runtime_getncpu_file = runtime/getncpu-linux.c
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_netpoll_files = runtime/netpoll_kqueue.c
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@runtime_netpoll_files = runtime/netpoll_select.c
-@LIBGO_IS_LINUX_TRUE@runtime_netpoll_files = runtime/netpoll_epoll.c
runtime_files = \
- runtime/go-append.c \
+ runtime/aeshash.c \
runtime/go-assert.c \
- runtime/go-assert-interface.c \
- runtime/go-byte-array-to-string.c \
runtime/go-breakpoint.c \
runtime/go-caller.c \
runtime/go-callers.c \
- runtime/go-can-convert-interface.c \
runtime/go-cdiv.c \
runtime/go-cgo.c \
- runtime/go-check-interface.c \
runtime/go-construct-map.c \
- runtime/go-convert-interface.c \
- runtime/go-copy.c \
- runtime/go-defer.c \
- runtime/go-deferred-recover.c \
- runtime/go-eface-compare.c \
- runtime/go-eface-val-compare.c \
runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-int-array-to-string.c \
- runtime/go-int-to-string.c \
- runtime/go-interface-compare.c \
- runtime/go-interface-eface-compare.c \
- runtime/go-interface-val-compare.c \
- runtime/go-make-slice.c \
- runtime/go-map-delete.c \
- runtime/go-map-index.c \
- runtime/go-map-len.c \
- runtime/go-map-range.c \
runtime/go-matherr.c \
+ runtime/go-memclr.c \
runtime/go-memcmp.c \
+ runtime/go-memequal.c \
+ runtime/go-memmove.c \
runtime/go-nanotime.c \
runtime/go-now.c \
- runtime/go-new-map.c \
runtime/go-new.c \
runtime/go-nosys.c \
- runtime/go-panic.c \
- runtime/go-print.c \
- runtime/go-recover.c \
runtime/go-reflect-call.c \
- runtime/go-reflect-map.c \
- runtime/go-rune.c \
runtime/go-runtime-error.c \
runtime/go-setenv.c \
runtime/go-signal.c \
- runtime/go-strcmp.c \
- runtime/go-string-to-byte-array.c \
- runtime/go-string-to-int-array.c \
- runtime/go-strplus.c \
runtime/go-strslice.c \
- runtime/go-traceback.c \
- runtime/go-type-complex.c \
- runtime/go-type-eface.c \
- runtime/go-type-error.c \
- runtime/go-type-float.c \
- runtime/go-type-identity.c \
- runtime/go-type-interface.c \
- runtime/go-type-string.c \
runtime/go-typedesc-equal.c \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
@@ -898,7 +808,6 @@ runtime_files = \
runtime/go-varargs.c \
runtime/env_posix.c \
runtime/heapdump.c \
- $(runtime_lock_files) \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
@@ -906,1414 +815,212 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
- $(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
runtime/proc.c \
- runtime/runtime.c \
- runtime/signal_unix.c \
+ runtime/runtime_c.c \
runtime/thread.c \
+ $(runtime_thread_files) \
runtime/yield.c \
$(rtems_task_variable_add_file) \
- chan.c \
- cpuprof.c \
- go-iface.c \
- lfstack.c \
malloc.c \
- map.c \
- mprof.c \
- netpoll.c \
- rdebug.c \
- reflect.c \
- runtime1.c \
- sema.c \
- sigqueue.c \
- string.c \
- time.c \
$(runtime_getncpu_file)
-go_bufio_files = \
- go/bufio/bufio.go \
- go/bufio/scan.go
-
-go_bytes_files = \
- go/bytes/buffer.go \
- go/bytes/bytes.go \
- go/bytes/bytes_decl.go \
- go/bytes/reader.go
-
-go_bytes_c_files = \
- go/bytes/indexbyte.c
-
-go_crypto_files = \
- go/crypto/crypto.go
-
-go_encoding_files = \
- go/encoding/encoding.go
-
-go_errors_files = \
- go/errors/errors.go
-
-go_expvar_files = \
- go/expvar/expvar.go
-
-go_flag_files = \
- go/flag/flag.go
-
-go_fmt_files = \
- go/fmt/doc.go \
- go/fmt/format.go \
- go/fmt/print.go \
- go/fmt/scan.go
-
-go_hash_files = \
- go/hash/hash.go
-
-go_html_files = \
- go/html/entity.go \
- go/html/escape.go
-
-go_image_files = \
- go/image/format.go \
- go/image/geom.go \
- go/image/image.go \
- go/image/names.go \
- go/image/ycbcr.go
-
-go_io_files = \
- go/io/multi.go \
- go/io/io.go \
- go/io/pipe.go
-
-go_log_files = \
- go/log/log.go
-
-go_math_files = \
- go/math/abs.go \
- go/math/acosh.go \
- go/math/asin.go \
- go/math/asinh.go \
- go/math/atan.go \
- go/math/atanh.go \
- go/math/atan2.go \
- go/math/bits.go \
- go/math/cbrt.go \
- go/math/const.go \
- go/math/copysign.go \
- go/math/dim.go \
- go/math/erf.go \
- go/math/exp.go \
- go/math/expm1.go \
- go/math/floor.go \
- go/math/frexp.go \
- go/math/gamma.go \
- go/math/hypot.go \
- go/math/j0.go \
- go/math/j1.go \
- go/math/jn.go \
- go/math/ldexp.go \
- go/math/lgamma.go \
- go/math/log.go \
- go/math/log1p.go \
- go/math/log10.go \
- go/math/logb.go \
- go/math/mod.go \
- go/math/modf.go \
- go/math/nextafter.go \
- go/math/pow.go \
- go/math/pow10.go \
- go/math/remainder.go \
- go/math/signbit.go \
- go/math/sin.go \
- go/math/sincos.go \
- go/math/sinh.go \
- go/math/sqrt.go \
- go/math/tan.go \
- go/math/tanh.go \
- go/math/unsafe.go
-
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file =
-@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file = go/mime/type_dragonfly.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file = go/mime/type_freebsd.go
-@LIBGO_IS_OPENBSD_TRUE@go_mime_type_file = go/mime/type_openbsd.go
-go_mime_files = \
- go/mime/encodedword.go \
- go/mime/grammar.go \
- go/mime/mediatype.go \
- go/mime/type.go \
- go/mime/type_unix.go \
- $(go_mime_type_file)
-
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_netbsd.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_file = go/net/cgo_solaris.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_file = go/net/cgo_linux.go
-@LIBGO_IS_LINUX_TRUE@go_net_cgo_file = go/net/cgo_linux.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_stub.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
-@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_solaris.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockopt_file = go/net/sockopt_linux.go
-@LIBGO_IS_LINUX_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_stub.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
-@LIBGO_IS_LINUX_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_sock_file = go/net/cgo_socknew.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_sock_file = go/net/cgo_socknew.go
-@LIBGO_IS_LINUX_TRUE@go_net_cgo_sock_file = go/net/cgo_socknew.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resold.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resnew.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resold.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_res_file = go/net/cgo_resnew.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_res_file = go/net/cgo_resnew.go
-@LIBGO_IS_LINUX_TRUE@go_net_cgo_res_file = go/net/cgo_resnew.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sendfile_file = go/net/sendfile_solaris.go
-@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_dragonfly.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_freebsd.go
-@LIBGO_IS_LINUX_TRUE@go_net_sendfile_file = go/net/sendfile_linux.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@go_net_interface_file = go/net/interface_stub.go
-@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@go_net_interface_file = go/net/interface_dragonfly.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@go_net_interface_file = go/net/interface_netbsd.go
-@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sock_cloexec.go go/net/hook_cloexec.go
-@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go go/net/hook_cloexec.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
-@LIBGO_IS_OPENBSD_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_openbsd.go
-go_net_common_files = \
- go/net/addrselect.go \
- $(go_net_cloexec_file) \
- go/net/conf.go \
- go/net/dial.go \
- go/net/dnsclient.go \
- go/net/dnsclient_unix.go \
- go/net/dnsconfig_unix.go \
- go/net/dnsmsg.go \
- go/net/fd_mutex.go \
- go/net/fd_posix.go \
- go/net/fd_unix.go \
- go/net/file.go \
- go/net/file_unix.go \
- go/net/hook.go \
- go/net/hook_unix.go \
- go/net/hosts.go \
- go/net/interface.go \
- $(go_net_interface_file) \
- go/net/ip.go \
- go/net/iprawsock.go \
- go/net/iprawsock_posix.go \
- go/net/ipsock.go \
- go/net/ipsock_posix.go \
- go/net/lookup.go \
- go/net/lookup_unix.go \
- go/net/mac.go \
- go/net/net.go \
- go/net/nss.go \
- go/net/parse.go \
- go/net/pipe.go \
- go/net/fd_poll_runtime.go \
- go/net/port_unix.go \
- $(go_net_sendfile_file) \
- go/net/sock_posix.go \
- $(go_net_sock_file) \
- go/net/sockopt_posix.go \
- $(go_net_sockopt_file) \
- $(go_net_sockoptip_file) \
- go/net/tcpsock.go \
- go/net/tcpsock_posix.go \
- go/net/tcpsockopt_posix.go \
- $(go_net_tcpsockopt_file) \
- go/net/udpsock.go \
- go/net/udpsock_posix.go \
- go/net/unixsock.go \
- go/net/unixsock_posix.go
-
-go_net_files = \
- go/net/cgo_unix.go \
- $(go_net_cgo_file) \
- $(go_net_cgo_res_file) \
- $(go_net_cgo_sock_file) \
- $(go_net_common_files)
-
-go_netgo_files = \
- go/net/cgo_stub.go \
- $(go_net_common_files)
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_FALSE@go_os_dir_file = go/os/dir_regfile.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_TRUE@go_os_dir_file = go/os/dir_largefile.go
-@LIBGO_IS_386_TRUE@@LIBGO_IS_SOLARIS_TRUE@go_os_dir_file = go/os/dir_largefile.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_dir_file = go/os/dir_regfile.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_dir_file = go/os/dir_largefile.go
-@LIBGO_IS_DARWIN_FALSE@go_os_getwd_file =
-@LIBGO_IS_DARWIN_TRUE@go_os_getwd_file = go/os/getwd_darwin.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_uname.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_uname.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_sys_file = go/os/sys_uname.go
-@LIBGO_IS_LINUX_TRUE@go_os_sys_file = go/os/sys_linux.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@go_os_cloexec_file = go/os/sys_unix.go
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_FREEBSD_FALSE@go_os_cloexec_file = go/os/sys_darwin.go
-@LIBGO_IS_FREEBSD_TRUE@go_os_cloexec_file = go/os/sys_freebsd.go
-@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_stat_file = go/os/stat_solaris.go
-@HAVE_STAT_TIMESPEC_TRUE@@LIBGO_IS_SOLARIS_TRUE@go_os_stat_file = go/os/stat_atim.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_dragonfly.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atimespec.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atimespec.go
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atimespec.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_OPENBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atim.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atim.go
-@LIBGO_IS_LINUX_FALSE@go_os_pipe_file = go/os/pipe_bsd.go
-@LIBGO_IS_LINUX_TRUE@go_os_pipe_file = go/os/pipe_linux.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sticky_file = go/os/sticky_notbsd.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-@LIBGO_IS_DARWIN_TRUE@go_os_sticky_file = go/os/sticky_bsd.go
-go_os_files = \
- $(go_os_dir_file) \
- go/os/dir.go \
- go/os/doc.go \
- go/os/env.go \
- go/os/error.go \
- go/os/error_unix.go \
- go/os/exec.go \
- go/os/exec_posix.go \
- go/os/exec_unix.go \
- go/os/file.go \
- go/os/file_posix.go \
- go/os/file_unix.go \
- go/os/getwd.go \
- $(go_os_getwd_file) \
- go/os/path.go \
- go/os/path_unix.go \
- $(go_os_pipe_file) \
- go/os/proc.go \
- $(go_os_stat_file) \
- $(go_os_sticky_file) \
- go/os/str.go \
- $(go_os_sys_file) \
- $(go_os_cloexec_file) \
- go/os/types.go \
- go/os/types_unix.go
-
-go_path_files = \
- go/path/match.go \
- go/path/path.go
-
-go_reflect_files = \
- go/reflect/deepequal.go \
- go/reflect/makefunc.go \
- go/reflect/makefunc_ffi.go \
- go/reflect/type.go \
- go/reflect/value.go
-
-go_reflect_makefunc_c_file = \
- go/reflect/makefunc_ffi_c.c
-
-go_regexp_files = \
- go/regexp/backtrack.go \
- go/regexp/exec.go \
- go/regexp/onepass.go \
- go/regexp/regexp.go
-
-go_net_rpc_files = \
- go/net/rpc/client.go \
- go/net/rpc/debug.go \
- go/net/rpc/server.go
-
-go_runtime_files = \
- go/runtime/compiler.go \
- go/runtime/debug.go \
- go/runtime/error.go \
- go/runtime/extern.go \
- go/runtime/mem.go \
- version.go
-
noinst_DATA = zstdpkglist.go
-go_sort_files = \
- go/sort/search.go \
- go/sort/sort.go
-
-go_strconv_files = \
- go/strconv/atob.go \
- go/strconv/atof.go \
- go/strconv/atoi.go \
- go/strconv/decimal.go \
- go/strconv/doc.go \
- go/strconv/extfloat.go \
- go/strconv/ftoa.go \
- go/strconv/isprint.go \
- go/strconv/itoa.go \
- go/strconv/quote.go
-
-go_strings_files = \
- go/strings/compare.go \
- go/strings/reader.go \
- go/strings/replace.go \
- go/strings/search.go \
- go/strings/strings.go \
- go/strings/strings_decl.go \
- go/strings/strings_generic.go
-
-go_strings_c_files = \
- go/strings/indexbyte.c
-
-go_sync_files = \
- go/sync/cond.go \
- go/sync/mutex.go \
- go/sync/once.go \
- go/sync/pool.go \
- go/sync/runtime.go \
- go/sync/rwmutex.go \
- go/sync/waitgroup.go
-
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_syslog_file = go/log/syslog/syslog_unix.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_syslog_file = go/log/syslog/syslog_libc.go
-@LIBGO_IS_SOLARIS_TRUE@go_syslog_file = go/log/syslog/syslog_libc.go
-go_log_syslog_files = \
- go/log/syslog/doc.go \
- go/log/syslog/syslog.go \
- $(go_syslog_file)
-
-go_syslog_c_files = \
- go/log/syslog/syslog_c.c
-
-go_testing_files = \
- go/testing/allocs.go \
- go/testing/benchmark.go \
- go/testing/cover.go \
- go/testing/example.go \
- go/testing/testing.go
-
-go_time_files = \
- go/time/format.go \
- go/time/sleep.go \
- go/time/sys_unix.go \
- go/time/tick.go \
- go/time/time.go \
- go/time/zoneinfo.go \
- go/time/zoneinfo_read.go \
- go/time/zoneinfo_unix.go
-
-go_unicode_files = \
- go/unicode/casetables.go \
- go/unicode/digit.go \
- go/unicode/graphic.go \
- go/unicode/letter.go \
- go/unicode/tables.go
-
-@LIBGO_IS_DARWIN_TRUE@archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-@LIBGO_IS_FREEBSD_TRUE@archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-@LIBGO_IS_LINUX_TRUE@archive_tar_atim_file = go/archive/tar/stat_atim.go
-@LIBGO_IS_NETBSD_TRUE@archive_tar_atim_file = go/archive/tar/stat_atimespec.go
-@LIBGO_IS_OPENBSD_TRUE@archive_tar_atim_file = go/archive/tar/stat_atim.go
-@LIBGO_IS_SOLARIS_TRUE@archive_tar_atim_file = go/archive/tar/stat_atim.go
-go_archive_tar_files = \
- go/archive/tar/common.go \
- go/archive/tar/reader.go \
- go/archive/tar/stat_unix.go \
- go/archive/tar/writer.go \
- $(archive_tar_atim_file)
-
-go_archive_zip_files = \
- go/archive/zip/reader.go \
- go/archive/zip/register.go \
- go/archive/zip/struct.go \
- go/archive/zip/writer.go
-
-go_compress_bzip2_files = \
- go/compress/bzip2/bit_reader.go \
- go/compress/bzip2/bzip2.go \
- go/compress/bzip2/huffman.go \
- go/compress/bzip2/move_to_front.go
-
-go_compress_flate_files = \
- go/compress/flate/copy.go \
- go/compress/flate/deflate.go \
- go/compress/flate/huffman_bit_writer.go \
- go/compress/flate/huffman_code.go \
- go/compress/flate/inflate.go \
- go/compress/flate/reverse_bits.go \
- go/compress/flate/token.go
-
-go_compress_gzip_files = \
- go/compress/gzip/gzip.go \
- go/compress/gzip/gunzip.go
-
-go_compress_lzw_files = \
- go/compress/lzw/reader.go \
- go/compress/lzw/writer.go
-
-go_compress_zlib_files = \
- go/compress/zlib/reader.go \
- go/compress/zlib/writer.go
-
-go_container_heap_files = \
- go/container/heap/heap.go
-
-go_container_list_files = \
- go/container/list/list.go
-
-go_container_ring_files = \
- go/container/ring/ring.go
-
-go_crypto_aes_files = \
- go/crypto/aes/block.go \
- go/crypto/aes/cipher.go \
- go/crypto/aes/cipher_generic.go \
- go/crypto/aes/const.go
-
-go_crypto_cipher_files = \
- go/crypto/cipher/cbc.go \
- go/crypto/cipher/cfb.go \
- go/crypto/cipher/cipher.go \
- go/crypto/cipher/ctr.go \
- go/crypto/cipher/gcm.go \
- go/crypto/cipher/io.go \
- go/crypto/cipher/ofb.go \
- go/crypto/cipher/xor.go
-
-go_crypto_des_files = \
- go/crypto/des/block.go \
- go/crypto/des/cipher.go \
- go/crypto/des/const.go
-
-go_crypto_dsa_files = \
- go/crypto/dsa/dsa.go
-
-go_crypto_ecdsa_files = \
- go/crypto/ecdsa/ecdsa.go
-
-go_crypto_elliptic_files = \
- go/crypto/elliptic/elliptic.go \
- go/crypto/elliptic/p224.go \
- go/crypto/elliptic/p256.go
-
-go_crypto_hmac_files = \
- go/crypto/hmac/hmac.go
-
-go_crypto_md5_files = \
- go/crypto/md5/md5.go \
- go/crypto/md5/md5block.go \
- go/crypto/md5/md5block_generic.go
-
-@LIBGO_IS_LINUX_FALSE@crypto_rand_file =
-@LIBGO_IS_LINUX_TRUE@crypto_rand_file = go/crypto/rand/rand_linux.go
-go_crypto_rand_files = \
- go/crypto/rand/eagain.go \
- go/crypto/rand/rand.go \
- go/crypto/rand/rand_unix.go \
- $(crypto_rand_file) \
- go/crypto/rand/util.go
-
-go_crypto_rc4_files = \
- go/crypto/rc4/rc4.go \
- go/crypto/rc4/rc4_ref.go
-
-go_crypto_rsa_files = \
- go/crypto/rsa/pkcs1v15.go \
- go/crypto/rsa/pss.go \
- go/crypto/rsa/rsa.go
-
-go_crypto_sha1_files = \
- go/crypto/sha1/sha1.go \
- go/crypto/sha1/sha1block.go \
- go/crypto/sha1/sha1block_generic.go
-
-go_crypto_sha256_files = \
- go/crypto/sha256/sha256.go \
- go/crypto/sha256/sha256block.go
-
-go_crypto_sha512_files = \
- go/crypto/sha512/sha512.go \
- go/crypto/sha512/sha512block.go
-
-go_crypto_subtle_files = \
- go/crypto/subtle/constant_time.go
-
-go_crypto_tls_files = \
- go/crypto/tls/alert.go \
- go/crypto/tls/cipher_suites.go \
- go/crypto/tls/common.go \
- go/crypto/tls/conn.go \
- go/crypto/tls/handshake_client.go \
- go/crypto/tls/handshake_messages.go \
- go/crypto/tls/handshake_server.go \
- go/crypto/tls/key_agreement.go \
- go/crypto/tls/prf.go \
- go/crypto/tls/ticket.go \
- go/crypto/tls/tls.go
-
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file =
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_darwin.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_crypto_x509_root_file = go/crypto/x509/root_solaris.go
-@LIBGO_IS_LINUX_TRUE@go_crypto_x509_root_file = go/crypto/x509/root_linux.go
-go_crypto_x509_files = \
- go/crypto/x509/cert_pool.go \
- go/crypto/x509/pem_decrypt.go \
- go/crypto/x509/pkcs1.go \
- go/crypto/x509/pkcs8.go \
- go/crypto/x509/root.go \
- go/crypto/x509/root_unix.go \
- $(go_crypto_x509_root_file) \
- go/crypto/x509/sec1.go \
- go/crypto/x509/verify.go \
- go/crypto/x509/x509.go
-
-go_crypto_x509_pkix_files = \
- go/crypto/x509/pkix/pkix.go
-
-go_database_sql_files = \
- go/database/sql/convert.go \
- go/database/sql/sql.go
-
-go_database_sql_driver_files = \
- go/database/sql/driver/driver.go \
- go/database/sql/driver/types.go
-
-go_debug_dwarf_files = \
- go/debug/dwarf/buf.go \
- go/debug/dwarf/class_string.go \
- go/debug/dwarf/const.go \
- go/debug/dwarf/entry.go \
- go/debug/dwarf/line.go \
- go/debug/dwarf/open.go \
- go/debug/dwarf/type.go \
- go/debug/dwarf/typeunit.go \
- go/debug/dwarf/unit.go
-
-go_debug_elf_files = \
- go/debug/elf/elf.go \
- go/debug/elf/file.go \
- go/debug/elf/reader.go
-
-go_debug_gosym_files = \
- go/debug/gosym/pclntab.go \
- go/debug/gosym/symtab.go
-
-go_debug_macho_files = \
- go/debug/macho/fat.go \
- go/debug/macho/file.go \
- go/debug/macho/macho.go
-
-go_debug_pe_files = \
- go/debug/pe/file.go \
- go/debug/pe/pe.go
-
-go_debug_plan9obj_files = \
- go/debug/plan9obj/file.go \
- go/debug/plan9obj/plan9obj.go
-
-go_encoding_ascii85_files = \
- go/encoding/ascii85/ascii85.go
-
-go_encoding_asn1_files = \
- go/encoding/asn1/asn1.go \
- go/encoding/asn1/common.go \
- go/encoding/asn1/marshal.go
-
-go_encoding_base32_files = \
- go/encoding/base32/base32.go
-
-go_encoding_base64_files = \
- go/encoding/base64/base64.go
-
-go_encoding_binary_files = \
- go/encoding/binary/binary.go \
- go/encoding/binary/varint.go
-
-go_encoding_csv_files = \
- go/encoding/csv/reader.go \
- go/encoding/csv/writer.go
-
-go_encoding_gob_files = \
- go/encoding/gob/decode.go \
- go/encoding/gob/decoder.go \
- go/encoding/gob/dec_helpers.go \
- go/encoding/gob/doc.go \
- go/encoding/gob/encode.go \
- go/encoding/gob/encoder.go \
- go/encoding/gob/enc_helpers.go \
- go/encoding/gob/error.go \
- go/encoding/gob/type.go
-
-go_encoding_hex_files = \
- go/encoding/hex/hex.go
-
-go_encoding_json_files = \
- go/encoding/json/decode.go \
- go/encoding/json/encode.go \
- go/encoding/json/fold.go \
- go/encoding/json/indent.go \
- go/encoding/json/scanner.go \
- go/encoding/json/stream.go \
- go/encoding/json/tags.go
-
-go_encoding_pem_files = \
- go/encoding/pem/pem.go
-
-go_encoding_xml_files = \
- go/encoding/xml/marshal.go \
- go/encoding/xml/read.go \
- go/encoding/xml/typeinfo.go \
- go/encoding/xml/xml.go
-
-go_exp_proxy_files = \
- go/exp/proxy/direct.go \
- go/exp/proxy/per_host.go \
- go/exp/proxy/proxy.go \
- go/exp/proxy/socks5.go
-
-go_exp_terminal_files = \
- go/exp/terminal/terminal.go \
- go/exp/terminal/util.go
-
-go_go_ast_files = \
- go/go/ast/ast.go \
- go/go/ast/commentmap.go \
- go/go/ast/filter.go \
- go/go/ast/import.go \
- go/go/ast/print.go \
- go/go/ast/resolve.go \
- go/go/ast/scope.go \
- go/go/ast/walk.go
-
-go_go_build_files = \
- go/go/build/build.go \
- go/go/build/doc.go \
- go/go/build/read.go \
- go/go/build/syslist.go
-
-go_go_constant_files = \
- go/go/constant/value.go
-
-go_go_doc_files = \
- go/go/doc/comment.go \
- go/go/doc/doc.go \
- go/go/doc/example.go \
- go/go/doc/exports.go \
- go/go/doc/filter.go \
- go/go/doc/reader.go \
- go/go/doc/synopsis.go
-
-go_go_format_files = \
- go/go/format/format.go \
- go/go/format/internal.go
-
-go_go_importer_files = \
- go/go/importer/importer.go
-
-go_go_parser_files = \
- go/go/parser/interface.go \
- go/go/parser/parser.go
-
-go_go_printer_files = \
- go/go/printer/nodes.go \
- go/go/printer/printer.go
-
-go_go_scanner_files = \
- go/go/scanner/errors.go \
- go/go/scanner/scanner.go
-
-go_go_token_files = \
- go/go/token/position.go \
- go/go/token/serialize.go \
- go/go/token/token.go
-
-go_go_types_files = \
- go/go/types/api.go \
- go/go/types/assignments.go \
- go/go/types/builtins.go \
- go/go/types/call.go \
- go/go/types/check.go \
- go/go/types/conversions.go \
- go/go/types/decl.go \
- go/go/types/errors.go \
- go/go/types/eval.go \
- go/go/types/expr.go \
- go/go/types/exprstring.go \
- go/go/types/initorder.go \
- go/go/types/labels.go \
- go/go/types/lookup.go \
- go/go/types/methodset.go \
- go/go/types/object.go \
- go/go/types/objset.go \
- go/go/types/operand.go \
- go/go/types/ordering.go \
- go/go/types/package.go \
- go/go/types/predicates.go \
- go/go/types/resolver.go \
- go/go/types/return.go \
- go/go/types/scope.go \
- go/go/types/selection.go \
- go/go/types/stmt.go \
- go/go/types/sizes.go \
- go/go/types/type.go \
- go/go/types/typestring.go \
- go/go/types/typexpr.go \
- go/go/types/universe.go
-
-go_go_internal_gcimporter_files = \
- go/go/internal/gcimporter/bimport.go \
- go/go/internal/gcimporter/exportdata.go \
- go/go/internal/gcimporter/gcimporter.go
-
-go_go_internal_gccgoimporter_files = \
- go/go/internal/gccgoimporter/gccgoinstallation.go \
- go/go/internal/gccgoimporter/importer.go \
- go/go/internal/gccgoimporter/parser.go
-
-go_hash_adler32_files = \
- go/hash/adler32/adler32.go
-
-go_hash_crc32_files = \
- go/hash/crc32/crc32.go \
- go/hash/crc32/crc32_generic.go
-
-go_hash_crc64_files = \
- go/hash/crc64/crc64.go
-
-go_hash_fnv_files = \
- go/hash/fnv/fnv.go
-
-go_html_template_files = \
- go/html/template/attr.go \
- go/html/template/content.go \
- go/html/template/context.go \
- go/html/template/css.go \
- go/html/template/doc.go \
- go/html/template/error.go \
- go/html/template/escape.go \
- go/html/template/html.go \
- go/html/template/js.go \
- go/html/template/template.go \
- go/html/template/transition.go \
- go/html/template/url.go
-
-go_image_color_files = \
- go/image/color/color.go \
- go/image/color/ycbcr.go
-
-go_image_color_palette_files = \
- go/image/color/palette/palette.go
-
-go_image_draw_files = \
- go/image/draw/draw.go
-
-go_image_gif_files = \
- go/image/gif/reader.go \
- go/image/gif/writer.go
-
-go_image_internal_imageutil_files = \
- go/image/internal/imageutil/imageutil.go \
- go/image/internal/imageutil/impl.go
-
-go_image_jpeg_files = \
- go/image/jpeg/fdct.go \
- go/image/jpeg/huffman.go \
- go/image/jpeg/idct.go \
- go/image/jpeg/reader.go \
- go/image/jpeg/scan.go \
- go/image/jpeg/writer.go
-
-go_image_png_files = \
- go/image/png/paeth.go \
- go/image/png/reader.go \
- go/image/png/writer.go
-
-go_index_suffixarray_files = \
- go/index/suffixarray/qsufsort.go \
- go/index/suffixarray/suffixarray.go
-
-go_internal_golang_org_x_net_http2_hpack_files = \
- go/internal/golang.org/x/net/http2/hpack/encode.go \
- go/internal/golang.org/x/net/http2/hpack/hpack.go \
- go/internal/golang.org/x/net/http2/hpack/huffman.go \
- go/internal/golang.org/x/net/http2/hpack/tables.go
-
-go_internal_race_files = \
- go/internal/race/doc.go \
- go/internal/race/norace.go
-
-go_internal_singleflight_files = \
- go/internal/singleflight/singleflight.go
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_MIPS64_FALSE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_generic.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_MIPS64_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_mips64x.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_ppc64x.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_TRUE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_arm.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_TRUE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_amd64.go
-@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_TRUE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_386.go
-@LIBGO_IS_LINUX_FALSE@internal_syscall_unix_getrandom_files =
-go_internal_syscall_unix_files = \
- go/internal/syscall/unix/dummy.go \
- $(internal_syscall_unix_getrandom_files)
-
-go_internal_testenv_files = \
- go/internal/testenv/testenv.go
-
-go_internal_trace_files = \
- go/internal/trace/goroutines.go \
- go/internal/trace/parser.go
-
-go_io_ioutil_files = \
- go/io/ioutil/ioutil.go \
- go/io/ioutil/tempfile.go
-
-go_math_big_files = \
- go/math/big/accuracy_string.go \
- go/math/big/arith.go \
- go/math/big/arith_decl_pure.go \
- go/math/big/decimal.go \
- go/math/big/doc.go \
- go/math/big/float.go \
- go/math/big/floatconv.go \
- go/math/big/floatmarsh.go \
- go/math/big/ftoa.go \
- go/math/big/int.go \
- go/math/big/intmarsh.go \
- go/math/big/intconv.go \
- go/math/big/nat.go \
- go/math/big/natconv.go \
- go/math/big/rat.go \
- go/math/big/ratconv.go \
- go/math/big/ratmarsh.go \
- go/math/big/roundingmode_string.go
-
-go_math_cmplx_files = \
- go/math/cmplx/abs.go \
- go/math/cmplx/asin.go \
- go/math/cmplx/conj.go \
- go/math/cmplx/exp.go \
- go/math/cmplx/isinf.go \
- go/math/cmplx/isnan.go \
- go/math/cmplx/log.go \
- go/math/cmplx/phase.go \
- go/math/cmplx/polar.go \
- go/math/cmplx/pow.go \
- go/math/cmplx/rect.go \
- go/math/cmplx/sin.go \
- go/math/cmplx/sqrt.go \
- go/math/cmplx/tan.go
-
-go_math_rand_files = \
- go/math/rand/exp.go \
- go/math/rand/normal.go \
- go/math/rand/rand.go \
- go/math/rand/rng.go \
- go/math/rand/zipf.go
-
-go_mime_multipart_files = \
- go/mime/multipart/formdata.go \
- go/mime/multipart/multipart.go \
- go/mime/multipart/writer.go
-
-go_mime_quotedprintable_files = \
- go/mime/quotedprintable/reader.go \
- go/mime/quotedprintable/writer.go
-
-go_net_http_files = \
- go/net/http/client.go \
- go/net/http/cookie.go \
- go/net/http/filetransport.go \
- go/net/http/fs.go \
- go/net/http/h2_bundle.go \
- go/net/http/header.go \
- go/net/http/jar.go \
- go/net/http/lex.go \
- go/net/http/method.go \
- go/net/http/request.go \
- go/net/http/response.go \
- go/net/http/server.go \
- go/net/http/sniff.go \
- go/net/http/status.go \
- go/net/http/transfer.go \
- go/net/http/transport.go
-
-go_net_mail_files = \
- go/net/mail/message.go
-
-go_net_smtp_files = \
- go/net/smtp/auth.go \
- go/net/smtp/smtp.go
-
-go_net_textproto_files = \
- go/net/textproto/header.go \
- go/net/textproto/pipeline.go \
- go/net/textproto/reader.go \
- go/net/textproto/textproto.go \
- go/net/textproto/writer.go
-
-go_net_url_files = \
- go/net/url/url.go
-
-go_net_http_cgi_files = \
- go/net/http/cgi/child.go \
- go/net/http/cgi/host.go
-
-go_net_http_cookiejar_files = \
- go/net/http/cookiejar/jar.go \
- go/net/http/cookiejar/punycode.go
-
-go_net_http_fcgi_files = \
- go/net/http/fcgi/child.go \
- go/net/http/fcgi/fcgi.go
-
-go_net_http_httptest_files = \
- go/net/http/httptest/recorder.go \
- go/net/http/httptest/server.go
-
-go_net_http_pprof_files = \
- go/net/http/pprof/pprof.go
-
-go_net_http_httputil_files = \
- go/net/http/httputil/dump.go \
- go/net/http/httputil/httputil.go \
- go/net/http/httputil/persist.go \
- go/net/http/httputil/reverseproxy.go
-
-go_net_http_internal_files = \
- go/net/http/internal/chunked.go \
- go/net/http/internal/testcert.go
-
-@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys =
-@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
-@LIBGO_IS_LINUX_TRUE@go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
-go_net_internal_socktest_files = \
- go/net/internal/socktest/switch.go \
- go/net/internal/socktest/switch_posix.go \
- go/net/internal/socktest/switch_unix.go \
- go/net/internal/socktest/sys_unix.go \
- $(go_net_internal_socktest_sys)
-
-go_old_regexp_files = \
- go/old/regexp/regexp.go
-
-go_old_template_files = \
- go/old/template/doc.go \
- go/old/template/execute.go \
- go/old/template/format.go \
- go/old/template/parse.go
-
-go_os_exec_files = \
- go/os/exec/exec.go \
- go/os/exec/exec_posix.go \
- go/os/exec/lp_unix.go
-
-go_os_signal_files = \
- go/os/signal/doc.go \
- go/os/signal/signal.go \
- go/os/signal/signal_unix.go
-
-@LIBGO_IS_SOLARIS_FALSE@os_user_decls_file = go/os/user/decls_unix.go
-@LIBGO_IS_SOLARIS_TRUE@os_user_decls_file = go/os/user/decls_solaris.go
-go_os_user_files = \
- go/os/user/lookup.go \
- go/os/user/lookup_unix.go \
- go/os/user/user.go \
- $(os_user_decls_file)
-
-go_path_filepath_files = \
- go/path/filepath/match.go \
- go/path/filepath/path.go \
- go/path/filepath/path_unix.go \
- go/path/filepath/symlink.go \
- go/path/filepath/symlink_unix.go
-
-go_regexp_syntax_files = \
- go/regexp/syntax/compile.go \
- go/regexp/syntax/doc.go \
- go/regexp/syntax/parse.go \
- go/regexp/syntax/perl_groups.go \
- go/regexp/syntax/prog.go \
- go/regexp/syntax/regexp.go \
- go/regexp/syntax/simplify.go
-
-go_net_rpc_jsonrpc_files = \
- go/net/rpc/jsonrpc/client.go \
- go/net/rpc/jsonrpc/server.go
-
-go_runtime_debug_files = \
- go/runtime/debug/garbage.go \
- go/runtime/debug/stack.go
-
-go_runtime_pprof_files = \
- go/runtime/pprof/pprof.go
-
-go_text_tabwriter_files = \
- go/text/tabwriter/tabwriter.go
-
-go_text_template_files = \
- go/text/template/doc.go \
- go/text/template/exec.go \
- go/text/template/funcs.go \
- go/text/template/helper.go \
- go/text/template/option.go \
- go/text/template/template.go
-
-go_text_template_parse_files = \
- go/text/template/parse/lex.go \
- go/text/template/parse/node.go \
- go/text/template/parse/parse.go
-
-go_sync_atomic_files = \
- go/sync/atomic/doc.go \
- go/sync/atomic/value.go
-
-go_sync_atomic_c_files = \
- go/sync/atomic/atomic.c
-
-go_testing_iotest_files = \
- go/testing/iotest/logger.go \
- go/testing/iotest/reader.go \
- go/testing/iotest/writer.go
-
-go_testing_quick_files = \
- go/testing/quick/quick.go
-
-go_text_scanner_files = \
- go/text/scanner/scanner.go
-
-go_unicode_utf16_files = \
- go/unicode/utf16/utf16.go
-
-go_unicode_utf8_files = \
- go/unicode/utf8/utf8.go
-
-@LIBGO_IS_RTEMS_FALSE@syscall_syscall_file = go/syscall/syscall_unix.go
-
-# Define Syscall and Syscall6.
-@LIBGO_IS_RTEMS_TRUE@syscall_syscall_file = go/syscall/syscall_stubs.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_exec_file = go/syscall/exec_unix.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@syscall_exec_file = go/syscall/exec_unix.go
-
-# Define ForkExec and Exec.
-@LIBGO_IS_RTEMS_TRUE@syscall_exec_file = go/syscall/exec_stubs.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_exec_os_file = go/syscall/exec_bsd.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@syscall_exec_os_file = go/syscall/exec_linux.go
-@LIBGO_IS_RTEMS_TRUE@syscall_exec_os_file =
-@HAVE_WAIT4_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_wait_file = go/syscall/libcall_waitpid.go
-@HAVE_WAIT4_TRUE@@LIBGO_IS_RTEMS_FALSE@syscall_wait_file = go/syscall/libcall_wait4.go
-
-# Define Wait4.
-@LIBGO_IS_RTEMS_TRUE@syscall_wait_file =
-@LIBGO_IS_RTEMS_FALSE@syscall_wait_c_file = go/syscall/wait.c
-
-# Support for pulling apart wait status.
-@LIBGO_IS_RTEMS_TRUE@syscall_wait_c_file =
-@LIBGO_IS_RTEMS_FALSE@syscall_sleep_file = go/syscall/sleep_select.go
-
-# Define Sleep.
-@LIBGO_IS_RTEMS_TRUE@syscall_sleep_file = go/syscall/sleep_rtems.go
-@HAVE_STRERROR_R_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_file = go/syscall/errstr_nor.go
-@HAVE_STRERROR_R_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_file = go/syscall/errstr.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_TRUE@syscall_errstr_file = go/syscall/errstr_linux.go
-
-# Define Errstr.
-@LIBGO_IS_LINUX_TRUE@syscall_errstr_file = go/syscall/errstr_linux.go
-# Use lseek on 64-bit Solaris.
-@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_FALSE@syscall_size_file = go/syscall/libcall_posix_regfile.go
-# Use lseek64 on 32-bit Solaris/SPARC.
-@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_TRUE@syscall_size_file = go/syscall/libcall_posix_largefile.go
-# Use lseek64 on 32-bit Solaris/x86.
-@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_size_file = go/syscall/libcall_posix_largefile.go
-# Use lseek by default.
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_size_file = go/syscall/libcall_posix_regfile.go
-
-# Declare libc functions that vary for largefile systems.
-# Always use lseek64 on GNU/Linux.
-@LIBGO_IS_LINUX_TRUE@syscall_size_file = go/syscall/libcall_posix_largefile.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_socket_file = go/syscall/socket_bsd.go
-@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_socket_file = go/syscall/socket_irix.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_socket_file = go/syscall/socket_solaris.go
-
-# Define socket sizes and types.
-@LIBGO_IS_LINUX_TRUE@syscall_socket_file = go/syscall/socket_linux.go epoll.go
-@LIBGO_IS_LINUX_FALSE@syscall_socket_type_file =
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_PPC64LE_FALSE@@LIBGO_IS_PPC64_FALSE@syscall_socket_type_file = go/syscall/socket_linux_type.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_PPC64LE_FALSE@@LIBGO_IS_PPC64_TRUE@syscall_socket_type_file = go/syscall/socket_linux_ppc64x_type.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_PPC64LE_TRUE@syscall_socket_type_file = go/syscall/socket_linux_ppc64x_type.go
-@LIBGO_IS_SOLARIS_FALSE@syscall_socket_os_file = go/syscall/socket_posix.go
-
-# Define socket functions.
-@LIBGO_IS_SOLARIS_TRUE@syscall_socket_os_file = go/syscall/socket_xnet.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_uname_file = go/syscall/libcall_uname.go
-
-# Support for uname.
-# 32-bit Solaris 2/x86 needs _nuname, handled in libcall_solaris_386.go.
-@LIBGO_IS_386_TRUE@@LIBGO_IS_SOLARIS_TRUE@syscall_uname_file =
-@LIBGO_IS_SOLARIS_FALSE@syscall_uname_file = go/syscall/libcall_uname.go
-@LIBGO_IS_LINUX_FALSE@syscall_sockcmsg_file =
-
-# GNU/Linux specific socket control messages.
-@LIBGO_IS_LINUX_TRUE@syscall_sockcmsg_file = go/syscall/sockcmsg_linux.go
-@LIBGO_IS_LINUX_FALSE@syscall_netlink_file =
-
-# Support for netlink sockets and messages.
-@LIBGO_IS_LINUX_TRUE@syscall_netlink_file = go/syscall/netlink_linux.go
-@LIBGO_IS_LINUX_FALSE@syscall_lsf_file =
-
-# GNU/Linux specific socket filters.
-@LIBGO_IS_LINUX_TRUE@syscall_lsf_file = go/syscall/lsf_linux.go
-@LIBGO_IS_ARM64_FALSE@@LIBGO_IS_LINUX_TRUE@syscall_ustat_file = go/syscall/libcall_linux_ustat.go
-
-# GNU/Linux specific ustat support.
-@LIBGO_IS_ARM64_TRUE@@LIBGO_IS_LINUX_TRUE@syscall_ustat_file =
-@LIBGO_IS_LINUX_FALSE@syscall_ustat_file =
-@LIBGO_IS_LINUX_FALSE@syscall_utimesnano_file = go/syscall/libcall_posix_utimesnano.go
-
-# GNU/Linux specific utimesnano support.
-@LIBGO_IS_LINUX_TRUE@syscall_utimesnano_file = go/syscall/libcall_linux_utimesnano.go
-@LIBGO_IS_LINUX_FALSE@syscall_creds_test_file =
-
-# Test files.
-@LIBGO_IS_LINUX_TRUE@syscall_creds_test_file = go/syscall/creds_test.go
-@LIBGO_IS_LINUX_FALSE@syscall_exec_test_file =
-@LIBGO_IS_LINUX_TRUE@syscall_exec_test_file = go/syscall/exec_linux_test.go go/syscall/syscall_linux_test.go
-@LIBGO_IS_LINUX_FALSE@syscall_os_file = go/syscall/libcall_bsd.go
-@LIBGO_IS_LINUX_TRUE@syscall_os_file =
-go_base_syscall_files = \
- go/syscall/env_unix.go \
- go/syscall/syscall_errno.go \
- go/syscall/libcall_support.go \
- go/syscall/libcall_posix.go \
- go/syscall/msan0.go \
- go/syscall/socket.go \
- go/syscall/sockcmsg_unix.go \
- go/syscall/str.go \
- go/syscall/syscall.go \
- $(syscall_sockcmsg_file) \
- $(syscall_syscall_file) \
- $(syscall_exec_file) \
- $(syscall_exec_os_file) \
- $(syscall_wait_file) \
- $(syscall_sleep_file) \
- $(syscall_errstr_file) \
- $(syscall_size_file) \
- $(syscall_os_file) \
- $(syscall_socket_file) \
- $(syscall_socket_os_file) \
- $(syscall_socket_type_file) \
- $(syscall_uname_file) \
- $(syscall_netlink_file) \
- $(syscall_lsf_file) \
- $(syscall_ustat_file) \
- $(syscall_utimesnano_file) \
- $(GO_LIBCALL_OS_FILE) \
- $(GO_LIBCALL_OS_ARCH_FILE) \
- $(GO_SYSCALL_OS_FILE) \
- $(GO_SYSCALL_OS_ARCH_FILE)
-
-go_syscall_files = \
- $(go_base_syscall_files) \
- libcalls.go \
- sysinfo.go \
- syscall_arch.go
-
-go_syscall_c_files = \
- go/syscall/errno.c \
- go/syscall/signame.c \
- $(syscall_wait_c_file)
-
-go_syscall_test_files = \
- $(syscall_creds_test_file) \
- $(syscall_exec_test_file) \
- go/syscall/exec_unix_test.go \
- go/syscall/export_test.go \
- go/syscall/export_unix_test.go \
- go/syscall/mmap_unix_test.go \
- go/syscall/syscall_test.go \
- go/syscall/syscall_unix_test.go
-
-@LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo =
-
-# os_lib_inotify_lo = os/inotify.lo
-@LIBGO_IS_LINUX_TRUE@os_lib_inotify_lo =
+@LIBGO_IS_LINUX_FALSE@syscall_epoll_file =
+@LIBGO_IS_LINUX_TRUE@syscall_epoll_file = epoll.go
+SYSINFO_FLAGS = \
+ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(OSCFLAGS) -O
+
+@LIBGO_IS_LINUX_FALSE@syscall_lib_clone_lo =
+@LIBGO_IS_LINUX_TRUE@syscall_lib_clone_lo = syscall/clone_linux.lo
+PACKAGES = \
+ archive/tar \
+ archive/zip \
+ bufio \
+ bytes \
+ cmd/internal/browser \
+ compress/bzip2 \
+ compress/flate \
+ compress/gzip \
+ compress/lzw \
+ compress/zlib \
+ container/heap \
+ container/list \
+ container/ring \
+ context \
+ crypto \
+ crypto/aes \
+ crypto/cipher \
+ crypto/des \
+ crypto/dsa \
+ crypto/ecdsa \
+ crypto/elliptic \
+ crypto/hmac \
+ crypto/internal/cipherhw \
+ crypto/md5 \
+ crypto/rand \
+ crypto/rc4 \
+ crypto/rsa \
+ crypto/sha1 \
+ crypto/sha256 \
+ crypto/sha512 \
+ crypto/subtle \
+ crypto/tls \
+ crypto/x509 \
+ crypto/x509/pkix \
+ database/sql \
+ database/sql/driver \
+ debug/dwarf \
+ debug/elf \
+ debug/gosym \
+ debug/macho \
+ debug/pe \
+ debug/plan9obj \
+ encoding \
+ encoding/ascii85 \
+ encoding/asn1 \
+ encoding/base32 \
+ encoding/base64 \
+ encoding/binary \
+ encoding/csv \
+ encoding/gob \
+ encoding/hex \
+ encoding/json \
+ encoding/pem \
+ encoding/xml \
+ errors \
+ exp/proxy \
+ exp/terminal \
+ expvar \
+ flag \
+ fmt \
+ go/ast \
+ go/build \
+ go/constant \
+ go/doc \
+ go/format \
+ go/importer \
+ go/internal/gccgoimporter \
+ go/internal/gcimporter \
+ go/parser \
+ go/printer \
+ go/scanner \
+ go/token \
+ go/types \
+ golang_org/x/crypto/chacha20poly1305 \
+ golang_org/x/crypto/chacha20poly1305/internal/chacha20 \
+ golang_org/x/crypto/curve25519 \
+ golang_org/x/crypto/poly1305 \
+ golang_org/x/net/http2/hpack \
+ golang_org/x/net/idna \
+ golang_org/x/net/lex/httplex \
+ golang_org/x/text/transform \
+ golang_org/x/text/unicode/norm \
+ golang_org/x/text/width \
+ hash \
+ hash/adler32 \
+ hash/crc32 \
+ hash/crc64 \
+ hash/fnv \
+ html \
+ html/template \
+ image \
+ image/color \
+ image/color/palette \
+ image/draw \
+ image/gif \
+ image/internal/imageutil \
+ image/jpeg \
+ image/png \
+ index/suffixarray \
+ internal/nettrace \
+ internal/pprof/profile \
+ internal/race \
+ internal/singleflight \
+ internal/syscall/unix \
+ internal/testenv \
+ internal/trace \
+ io \
+ io/ioutil \
+ log \
+ log/syslog \
+ math \
+ math/big \
+ math/cmplx \
+ math/rand \
+ mime \
+ mime/multipart \
+ mime/quotedprintable \
+ net \
+ net/http \
+ net/http/cgi \
+ net/http/cookiejar \
+ net/http/fcgi \
+ net/http/httptest \
+ net/http/httptrace \
+ net/http/httputil \
+ net/http/internal \
+ net/http/pprof \
+ net/internal/socktest \
+ net/mail \
+ net/rpc \
+ net/rpc/jsonrpc \
+ net/smtp \
+ net/textproto \
+ net/url \
+ os \
+ os/exec \
+ os/signal \
+ os/user \
+ path \
+ path/filepath \
+ reflect \
+ regexp \
+ regexp/syntax \
+ runtime \
+ runtime/debug \
+ runtime/internal/atomic \
+ runtime/internal/sys \
+ runtime/pprof \
+ runtime/pprof/internal/protopprof \
+ runtime/trace \
+ sort \
+ strconv \
+ strings \
+ sync \
+ sync/atomic \
+ syscall \
+ testing \
+ testing/internal/testdeps \
+ testing/iotest \
+ testing/quick \
+ text/scanner \
+ text/tabwriter \
+ text/template \
+ text/template/parse \
+ time \
+ unicode \
+ unicode/utf16 \
+ unicode/utf8
+
libgo_go_objs = \
- bufio.lo \
- bytes.lo \
+ $(addsuffix .lo,$(PACKAGES)) \
bytes/index.lo \
- crypto.lo \
- encoding.lo \
- errors.lo \
- expvar.lo \
- flag.lo \
- fmt.lo \
- hash.lo \
- html.lo \
- image.lo \
- io.lo \
- log.lo \
- math.lo \
- mime.lo \
- net.lo \
- os.lo \
- path.lo \
- reflect-go.lo \
reflect/makefunc_ffi_c.lo \
- regexp.lo \
- runtime-go.lo \
- sort.lo \
- strconv.lo \
- strings.lo \
strings/index.lo \
- sync.lo \
- syscall.lo \
+ $(syscall_lib_clone_lo) \
syscall/errno.lo \
syscall/signame.lo \
syscall/wait.lo \
- testing.lo \
- time-go.lo \
- unicode.lo \
- archive/tar.lo \
- archive/zip.lo \
- compress/bzip2.lo \
- compress/flate.lo \
- compress/gzip.lo \
- compress/lzw.lo \
- compress/zlib.lo \
- container/heap.lo \
- container/list.lo \
- container/ring.lo \
- crypto/aes.lo \
- crypto/cipher.lo \
- crypto/des.lo \
- crypto/dsa.lo \
- crypto/ecdsa.lo \
- crypto/elliptic.lo \
- crypto/hmac.lo \
- crypto/md5.lo \
- crypto/rand.lo \
- crypto/rc4.lo \
- crypto/rsa.lo \
- crypto/sha1.lo \
- crypto/sha256.lo \
- crypto/sha512.lo \
- crypto/subtle.lo \
- crypto/tls.lo \
- crypto/x509.lo \
- crypto/x509/pkix.lo \
- database/sql.lo \
- database/sql/driver.lo \
- debug/dwarf.lo \
- debug/elf.lo \
- debug/gosym.lo \
- debug/macho.lo \
- debug/pe.lo \
- debug/plan9obj.lo \
- encoding/ascii85.lo \
- encoding/asn1.lo \
- encoding/base32.lo \
- encoding/base64.lo \
- encoding/binary.lo \
- encoding/csv.lo \
- encoding/gob.lo \
- encoding/hex.lo \
- encoding/json.lo \
- encoding/pem.lo \
- encoding/xml.lo \
- exp/proxy.lo \
- exp/terminal.lo \
- html/template.lo \
- go/ast.lo \
- go/build.lo \
- go/constant.lo \
- go/doc.lo \
- go/format.lo \
- go/importer.lo \
- go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo \
- go/parser.lo \
- go/printer.lo \
- go/scanner.lo \
- go/token.lo \
- go/types.lo \
- hash/adler32.lo \
- hash/crc32.lo \
- hash/crc64.lo \
- hash/fnv.lo \
- net/http/cgi.lo \
- net/http/cookiejar.lo \
- net/http/fcgi.lo \
- net/http/httptest.lo \
- net/http/httputil.lo \
- net/http/internal.lo \
- net/http/pprof.lo \
- image/color.lo \
- image/color/palette.lo \
- image/draw.lo \
- image/gif.lo \
- image/internal/imageutil.lo \
- image/jpeg.lo \
- image/png.lo \
- index/suffixarray.lo \
- internal/golang.org/x/net/http2/hpack.lo \
- internal/race.lo \
- internal/singleflight.lo \
- internal/syscall/unix.lo \
- internal/testenv.lo \
- internal/trace.lo \
- io/ioutil.lo \
- log/syslog.lo \
+ $(golang_org_x_net_lif_lo) \
+ $(golang_org_x_net_route_lo) \
log/syslog/syslog_c.lo \
- math/big.lo \
- math/cmplx.lo \
- math/rand.lo \
- mime/multipart.lo \
- mime/quotedprintable.lo \
- net/http.lo \
- net/internal/socktest.lo \
- net/mail.lo \
- net/rpc.lo \
- net/smtp.lo \
- net/textproto.lo \
- net/url.lo \
- old/regexp.lo \
- old/template.lo \
- os/exec.lo \
$(os_lib_inotify_lo) \
- os/signal.lo \
- os/user.lo \
- path/filepath.lo \
- regexp/syntax.lo \
- net/rpc/jsonrpc.lo \
- runtime/debug.lo \
- runtime/pprof.lo \
- sync/atomic.lo \
- sync/atomic_c.lo \
- text/scanner.lo \
- text/tabwriter.lo \
- text/template.lo \
- text/template/parse.lo \
- testing/iotest.lo \
- testing/quick.lo \
- unicode/utf16.lo \
- unicode/utf8.lo
+ runtime/internal/atomic_c.lo \
+ sync/atomic_c.lo
libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
@@ -2342,8 +1049,6 @@ libgolibbegin_a_SOURCES = \
runtime/go-libmain.c
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
-libnetgo_a_SOURCES = $(go_netgo_files)
-libnetgo_a_LIBADD = netgo.o
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
AM_GOCFLAGS = $(STRINGOPS_FLAG) $(GO_SPLIT_STACK)
GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
@@ -2357,22 +1062,27 @@ GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
# Build the dependencies for a Go package.
BUILDDEPS = \
$(MKDIR_P) $(@D); \
- $(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $^ > $@.tmp; \
+ dir=`echo $@ | sed -e 's/.lo.dep$$//'`; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst .lo.dep,,$@)))" $(matchargs_$(subst /,_,$(subst .lo.dep,,$@)))`; \
+ $(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $$files > $@.tmp; \
+ if ! cmp $@.tmp $@ >/dev/null 2>/dev/null; then \
+ rm -f `echo $@ | sed -e 's/\.dep$$//'`; \
+ fi; \
mv -f $@.tmp $@
# Build the .go files for a package, generating a .lo file.
BUILDPACKAGE = \
$(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
+ $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
-# Build netgo.o.
-BUILDNETGO = \
- $(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp; \
+ $(SHELL) $(srcdir)/mvifdiff.sh $@.tmp `echo $@ | sed -e 's/s-gox/gox/'`
GOTESTFLAGS =
GOBENCH =
@@ -2393,12 +1103,13 @@ CHECK = \
export LD_LIBRARY_PATH; \
$(MKDIR_P) $(@D); \
rm -f $@-testsum $@-testlog; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$(@D) --extrafiles="$(extra_go_files_$(subst /,_,$(@D)))" $(matchargs_$(subst /,_,$(@D)))`; \
if test "$(USE_DEJAGNU)" = "yes"; then \
- $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
+ $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" --testname="$(@D)" $(GOTESTFLAGS); \
elif test "$(GOBENCH)" != ""; then \
- $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
+ $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" --bench="$(GOBENCH)" $(GOTESTFLAGS); \
else \
- if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst .,_,$(subst /,_,$(@D)))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
+ if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$$files" $(GOTESTFLAGS) >>$@-testlog 2>&1; then \
echo "PASS: $(@D)" >> $@-testlog; \
echo "PASS: $(@D)"; \
echo "PASS: $(@D)" > $@-testsum; \
@@ -2426,19 +1137,62 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
$(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
+
+# Pass -ffp-contract=off, or 386-specific options, when building the
+# math package. MATH_FLAG is defined in configure.ac.
+math_lo_GOCFLAGS = $(MATH_FLAG)
+
+# Add the generated file runtime_sysinfo.go to the runtime package.
+extra_go_files_runtime = runtime_sysinfo.go sigtab.go
+
+# Add generated files to the syscall package.
+extra_go_files_syscall = \
+ libcalls.go \
+ sysinfo.go \
+ syscall_arch.go \
+ $(syscall_epoll_file)
+
+
+# Pass -fgo-compiling-runtime when compiling the runtime package.
+runtime_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
+runtime_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime
+@USE_LIBFFI_FALSE@matchargs_runtime =
+
+# If libffi is supported (the normal case) use the ffi build tag for
+# the runtime package.
+@USE_LIBFFI_TRUE@matchargs_runtime = --tag=libffi
+
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
+extra_go_files_runtime_internal_sys = version.go
+@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
-# How to build a .gox file from a .lo file.
-BUILDGOX = \
- f=`echo $< | sed -e 's/.lo$$/.o/'`; \
- $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
+# Solaris 12 changed the type of fields in struct stat.
+# Use a build tag, based on a configure check, to cope.
+@HAVE_STAT_TIMESPEC_TRUE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = --tag=solaristag
+@LIBGO_IS_SOLARIS_FALSE@matchargs_os =
+@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_lo = \
+@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route.lo
+
+@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_check = \
+@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/check
+
+@LIBGO_IS_SOLARIS_TRUE@golang_org_x_net_lif_lo = \
+@LIBGO_IS_SOLARIS_TRUE@ golang_org/x/net/lif.lo
+
+@LIBGO_IS_SOLARIS_TRUE@golang_org_x_net_lif_check = \
+@LIBGO_IS_SOLARIS_TRUE@ golang_org/x/net/lif/check
TEST_PACKAGES = \
bufio/check \
bytes/check \
+ context/check \
errors/check \
expvar/check \
flag/check \
@@ -2522,6 +1276,15 @@ TEST_PACKAGES = \
go/scanner/check \
go/token/check \
go/types/check \
+ golang_org/x/crypto/chacha20poly1305/check \
+ golang_org/x/crypto/chacha20poly1305/internal/chacha20/check \
+ golang_org/x/crypto/curve25519/check \
+ golang_org/x/crypto/poly1305/check \
+ golang_org/x/net/http2/hpack/check \
+ golang_org/x/net/idna/check \
+ golang_org/x/net/lex/httplex/check \
+ $(golang_org_x_net_lif_check) \
+ $(golang_org_x_net_route_check) \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@@ -2531,7 +1294,7 @@ TEST_PACKAGES = \
image/jpeg/check \
image/png/check \
index/suffixarray/check \
- internal/golang.org/x/net/http2/hpack/check \
+ internal/pprof/profile/check \
internal/singleflight/check \
internal/trace/check \
io/ioutil/check \
@@ -2546,6 +1309,7 @@ TEST_PACKAGES = \
net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
+ net/http/httptrace/check \
net/http/httputil/check \
net/http/internal/check \
net/internal/socktest/check \
@@ -2555,14 +1319,16 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
- old/regexp/check \
- old/template/check \
os/exec/check \
os/signal/check \
os/user/check \
path/filepath/check \
regexp/syntax/check \
+ runtime/debug/check \
+ runtime/internal/atomic/check \
+ runtime/internal/sys/check \
runtime/pprof/check \
+ runtime/pprof/internal/protopprof/check \
sync/atomic/check \
text/scanner/check \
text/tabwriter/check \
@@ -2671,10 +1437,6 @@ libgolibbegin.a: $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_DEPENDENCIES) $(EX
-rm -f libgolibbegin.a
$(libgolibbegin_a_AR) libgolibbegin.a $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_LIBADD)
$(RANLIB) libgolibbegin.a
-libnetgo.a: $(libnetgo_a_OBJECTS) $(libnetgo_a_DEPENDENCIES) $(EXTRA_libnetgo_a_DEPENDENCIES)
- -rm -f libnetgo.a
- $(libnetgo_a_AR) libnetgo.a $(libnetgo_a_OBJECTS) $(libnetgo_a_LIBADD)
- $(RANLIB) libnetgo.a
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
@@ -2718,74 +1480,36 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chan.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpuprof.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aeshash.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env_posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-bsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-irix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-none.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-solaris.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-append.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert-interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-breakpoint.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-byte-array-to-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-callers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cdiv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-defer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-ffi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-iface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-compare.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-eface-compare.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-val-compare.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-make-slice.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-delete.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-index.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-matherr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memclr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memcmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memequal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memmove.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nosys.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-now.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-byte-array.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-int-array.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strplus.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-traceback.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-complex.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-error.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-float.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
@@ -2794,14 +1518,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfstack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_a-go-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_llgo_a-go-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_futex.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_sema.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
@@ -2809,29 +1529,16 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_epoll.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_kqueue.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_select.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parfor.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdebug.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflect.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime1.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sema.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal_unix.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigqueue.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime_c.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-sema.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yield.Plo@am__quote@
.c.o:
@@ -2897,12 +1604,12 @@ libgolibbegin_a-go-libmain.obj: runtime/go-libmain.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -c -o libgolibbegin_a-go-libmain.obj `if test -f 'runtime/go-libmain.c'; then $(CYGPATH_W) 'runtime/go-libmain.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-libmain.c'; fi`
-go-append.lo: runtime/go-append.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-append.c' object='go-append.lo' libtool=yes @AMDEPBACKSLASH@
+aeshash.lo: runtime/aeshash.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aeshash.lo -MD -MP -MF $(DEPDIR)/aeshash.Tpo -c -o aeshash.lo `test -f 'runtime/aeshash.c' || echo '$(srcdir)/'`runtime/aeshash.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/aeshash.Tpo $(DEPDIR)/aeshash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/aeshash.c' object='aeshash.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aeshash.lo `test -f 'runtime/aeshash.c' || echo '$(srcdir)/'`runtime/aeshash.c
go-assert.lo: runtime/go-assert.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert.lo -MD -MP -MF $(DEPDIR)/go-assert.Tpo -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
@@ -2911,20 +1618,6 @@ go-assert.lo: runtime/go-assert.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
-go-assert-interface.lo: runtime/go-assert-interface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert-interface.lo -MD -MP -MF $(DEPDIR)/go-assert-interface.Tpo -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-assert-interface.Tpo $(DEPDIR)/go-assert-interface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-assert-interface.c' object='go-assert-interface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
-
-go-byte-array-to-string.lo: runtime/go-byte-array-to-string.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-byte-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-byte-array-to-string.Tpo -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-byte-array-to-string.Tpo $(DEPDIR)/go-byte-array-to-string.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-byte-array-to-string.c' object='go-byte-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
-
go-breakpoint.lo: runtime/go-breakpoint.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-breakpoint.lo -MD -MP -MF $(DEPDIR)/go-breakpoint.Tpo -c -o go-breakpoint.lo `test -f 'runtime/go-breakpoint.c' || echo '$(srcdir)/'`runtime/go-breakpoint.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-breakpoint.Tpo $(DEPDIR)/go-breakpoint.Plo
@@ -2946,13 +1639,6 @@ go-callers.lo: runtime/go-callers.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-callers.lo `test -f 'runtime/go-callers.c' || echo '$(srcdir)/'`runtime/go-callers.c
-go-can-convert-interface.lo: runtime/go-can-convert-interface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-can-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-can-convert-interface.Tpo -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-can-convert-interface.Tpo $(DEPDIR)/go-can-convert-interface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-can-convert-interface.c' object='go-can-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
-
go-cdiv.lo: runtime/go-cdiv.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-cdiv.lo -MD -MP -MF $(DEPDIR)/go-cdiv.Tpo -c -o go-cdiv.lo `test -f 'runtime/go-cdiv.c' || echo '$(srcdir)/'`runtime/go-cdiv.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-cdiv.Tpo $(DEPDIR)/go-cdiv.Plo
@@ -2967,13 +1653,6 @@ go-cgo.lo: runtime/go-cgo.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c
-go-check-interface.lo: runtime/go-check-interface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-check-interface.c' object='go-check-interface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
-
go-construct-map.lo: runtime/go-construct-map.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo
@@ -2981,48 +1660,6 @@ go-construct-map.lo: runtime/go-construct-map.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
-go-convert-interface.lo: runtime/go-convert-interface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-convert-interface.Tpo -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-convert-interface.Tpo $(DEPDIR)/go-convert-interface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-convert-interface.c' object='go-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
-
-go-copy.lo: runtime/go-copy.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-copy.lo -MD -MP -MF $(DEPDIR)/go-copy.Tpo -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-copy.Tpo $(DEPDIR)/go-copy.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-copy.c' object='go-copy.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
-
-go-defer.lo: runtime/go-defer.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-defer.lo -MD -MP -MF $(DEPDIR)/go-defer.Tpo -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-defer.Tpo $(DEPDIR)/go-defer.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-defer.c' object='go-defer.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
-
-go-deferred-recover.lo: runtime/go-deferred-recover.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-deferred-recover.lo -MD -MP -MF $(DEPDIR)/go-deferred-recover.Tpo -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-deferred-recover.Tpo $(DEPDIR)/go-deferred-recover.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-deferred-recover.c' object='go-deferred-recover.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
-
-go-eface-compare.lo: runtime/go-eface-compare.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-compare.Tpo -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-eface-compare.Tpo $(DEPDIR)/go-eface-compare.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-eface-compare.c' object='go-eface-compare.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
-
-go-eface-val-compare.lo: runtime/go-eface-val-compare.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-val-compare.Tpo -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-eface-val-compare.Tpo $(DEPDIR)/go-eface-val-compare.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-eface-val-compare.c' object='go-eface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
-
go-ffi.lo: runtime/go-ffi.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-ffi.lo -MD -MP -MF $(DEPDIR)/go-ffi.Tpo -c -o go-ffi.lo `test -f 'runtime/go-ffi.c' || echo '$(srcdir)/'`runtime/go-ffi.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-ffi.Tpo $(DEPDIR)/go-ffi.Plo
@@ -3037,76 +1674,6 @@ go-fieldtrack.lo: runtime/go-fieldtrack.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
-go-int-array-to-string.lo: runtime/go-int-array-to-string.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-array-to-string.Tpo -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-int-array-to-string.Tpo $(DEPDIR)/go-int-array-to-string.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-int-array-to-string.c' object='go-int-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
-
-go-int-to-string.lo: runtime/go-int-to-string.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-to-string.Tpo -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-int-to-string.Tpo $(DEPDIR)/go-int-to-string.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-int-to-string.c' object='go-int-to-string.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
-
-go-interface-compare.lo: runtime/go-interface-compare.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-compare.Tpo -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-compare.Tpo $(DEPDIR)/go-interface-compare.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-compare.c' object='go-interface-compare.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
-
-go-interface-eface-compare.lo: runtime/go-interface-eface-compare.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-eface-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-eface-compare.Tpo -c -o go-interface-eface-compare.lo `test -f 'runtime/go-interface-eface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-eface-compare.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-eface-compare.Tpo $(DEPDIR)/go-interface-eface-compare.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-eface-compare.c' object='go-interface-eface-compare.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-eface-compare.lo `test -f 'runtime/go-interface-eface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-eface-compare.c
-
-go-interface-val-compare.lo: runtime/go-interface-val-compare.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-val-compare.Tpo -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-val-compare.Tpo $(DEPDIR)/go-interface-val-compare.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-val-compare.c' object='go-interface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
-
-go-make-slice.lo: runtime/go-make-slice.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-make-slice.lo -MD -MP -MF $(DEPDIR)/go-make-slice.Tpo -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-make-slice.Tpo $(DEPDIR)/go-make-slice.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-make-slice.c' object='go-make-slice.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
-
-go-map-delete.lo: runtime/go-map-delete.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-delete.lo -MD -MP -MF $(DEPDIR)/go-map-delete.Tpo -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-delete.Tpo $(DEPDIR)/go-map-delete.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-delete.c' object='go-map-delete.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
-
-go-map-index.lo: runtime/go-map-index.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-index.lo -MD -MP -MF $(DEPDIR)/go-map-index.Tpo -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-index.Tpo $(DEPDIR)/go-map-index.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-index.c' object='go-map-index.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
-
-go-map-len.lo: runtime/go-map-len.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-len.lo -MD -MP -MF $(DEPDIR)/go-map-len.Tpo -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-len.Tpo $(DEPDIR)/go-map-len.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-len.c' object='go-map-len.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
-
-go-map-range.lo: runtime/go-map-range.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-range.lo -MD -MP -MF $(DEPDIR)/go-map-range.Tpo -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-range.Tpo $(DEPDIR)/go-map-range.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-range.c' object='go-map-range.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
-
go-matherr.lo: runtime/go-matherr.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-matherr.lo -MD -MP -MF $(DEPDIR)/go-matherr.Tpo -c -o go-matherr.lo `test -f 'runtime/go-matherr.c' || echo '$(srcdir)/'`runtime/go-matherr.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-matherr.Tpo $(DEPDIR)/go-matherr.Plo
@@ -3114,6 +1681,13 @@ go-matherr.lo: runtime/go-matherr.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-matherr.lo `test -f 'runtime/go-matherr.c' || echo '$(srcdir)/'`runtime/go-matherr.c
+go-memclr.lo: runtime/go-memclr.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-memclr.lo -MD -MP -MF $(DEPDIR)/go-memclr.Tpo -c -o go-memclr.lo `test -f 'runtime/go-memclr.c' || echo '$(srcdir)/'`runtime/go-memclr.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-memclr.Tpo $(DEPDIR)/go-memclr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-memclr.c' object='go-memclr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-memclr.lo `test -f 'runtime/go-memclr.c' || echo '$(srcdir)/'`runtime/go-memclr.c
+
go-memcmp.lo: runtime/go-memcmp.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-memcmp.lo -MD -MP -MF $(DEPDIR)/go-memcmp.Tpo -c -o go-memcmp.lo `test -f 'runtime/go-memcmp.c' || echo '$(srcdir)/'`runtime/go-memcmp.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-memcmp.Tpo $(DEPDIR)/go-memcmp.Plo
@@ -3121,6 +1695,20 @@ go-memcmp.lo: runtime/go-memcmp.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-memcmp.lo `test -f 'runtime/go-memcmp.c' || echo '$(srcdir)/'`runtime/go-memcmp.c
+go-memequal.lo: runtime/go-memequal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-memequal.lo -MD -MP -MF $(DEPDIR)/go-memequal.Tpo -c -o go-memequal.lo `test -f 'runtime/go-memequal.c' || echo '$(srcdir)/'`runtime/go-memequal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-memequal.Tpo $(DEPDIR)/go-memequal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-memequal.c' object='go-memequal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-memequal.lo `test -f 'runtime/go-memequal.c' || echo '$(srcdir)/'`runtime/go-memequal.c
+
+go-memmove.lo: runtime/go-memmove.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-memmove.lo -MD -MP -MF $(DEPDIR)/go-memmove.Tpo -c -o go-memmove.lo `test -f 'runtime/go-memmove.c' || echo '$(srcdir)/'`runtime/go-memmove.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-memmove.Tpo $(DEPDIR)/go-memmove.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-memmove.c' object='go-memmove.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-memmove.lo `test -f 'runtime/go-memmove.c' || echo '$(srcdir)/'`runtime/go-memmove.c
+
go-nanotime.lo: runtime/go-nanotime.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-nanotime.lo -MD -MP -MF $(DEPDIR)/go-nanotime.Tpo -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-nanotime.Tpo $(DEPDIR)/go-nanotime.Plo
@@ -3135,13 +1723,6 @@ go-now.lo: runtime/go-now.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-now.lo `test -f 'runtime/go-now.c' || echo '$(srcdir)/'`runtime/go-now.c
-go-new-map.lo: runtime/go-new-map.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-map.c' object='go-new-map.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
-
go-new.lo: runtime/go-new.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new.lo -MD -MP -MF $(DEPDIR)/go-new.Tpo -c -o go-new.lo `test -f 'runtime/go-new.c' || echo '$(srcdir)/'`runtime/go-new.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new.Tpo $(DEPDIR)/go-new.Plo
@@ -3156,27 +1737,6 @@ go-nosys.lo: runtime/go-nosys.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nosys.lo `test -f 'runtime/go-nosys.c' || echo '$(srcdir)/'`runtime/go-nosys.c
-go-panic.lo: runtime/go-panic.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-panic.lo -MD -MP -MF $(DEPDIR)/go-panic.Tpo -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-panic.Tpo $(DEPDIR)/go-panic.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-panic.c' object='go-panic.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
-
-go-print.lo: runtime/go-print.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-print.lo -MD -MP -MF $(DEPDIR)/go-print.Tpo -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-print.Tpo $(DEPDIR)/go-print.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-print.c' object='go-print.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
-
-go-recover.lo: runtime/go-recover.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-recover.c' object='go-recover.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
-
go-reflect-call.lo: runtime/go-reflect-call.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-call.lo -MD -MP -MF $(DEPDIR)/go-reflect-call.Tpo -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-call.Tpo $(DEPDIR)/go-reflect-call.Plo
@@ -3184,20 +1744,6 @@ go-reflect-call.lo: runtime/go-reflect-call.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
-go-reflect-map.lo: runtime/go-reflect-map.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-map.c' object='go-reflect-map.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
-
-go-rune.lo: runtime/go-rune.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rune.lo -MD -MP -MF $(DEPDIR)/go-rune.Tpo -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rune.Tpo $(DEPDIR)/go-rune.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rune.c' object='go-rune.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
-
go-runtime-error.lo: runtime/go-runtime-error.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-runtime-error.lo -MD -MP -MF $(DEPDIR)/go-runtime-error.Tpo -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-runtime-error.Tpo $(DEPDIR)/go-runtime-error.Plo
@@ -3219,34 +1765,6 @@ go-signal.lo: runtime/go-signal.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-signal.lo `test -f 'runtime/go-signal.c' || echo '$(srcdir)/'`runtime/go-signal.c
-go-strcmp.lo: runtime/go-strcmp.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strcmp.lo -MD -MP -MF $(DEPDIR)/go-strcmp.Tpo -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strcmp.Tpo $(DEPDIR)/go-strcmp.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-strcmp.c' object='go-strcmp.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
-
-go-string-to-byte-array.lo: runtime/go-string-to-byte-array.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-byte-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-byte-array.Tpo -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-string-to-byte-array.Tpo $(DEPDIR)/go-string-to-byte-array.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-string-to-byte-array.c' object='go-string-to-byte-array.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
-
-go-string-to-int-array.lo: runtime/go-string-to-int-array.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-int-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-int-array.Tpo -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-string-to-int-array.Tpo $(DEPDIR)/go-string-to-int-array.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-string-to-int-array.c' object='go-string-to-int-array.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
-
-go-strplus.lo: runtime/go-strplus.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strplus.lo -MD -MP -MF $(DEPDIR)/go-strplus.Tpo -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strplus.Tpo $(DEPDIR)/go-strplus.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-strplus.c' object='go-strplus.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
-
go-strslice.lo: runtime/go-strslice.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strslice.lo -MD -MP -MF $(DEPDIR)/go-strslice.Tpo -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strslice.Tpo $(DEPDIR)/go-strslice.Plo
@@ -3254,62 +1772,6 @@ go-strslice.lo: runtime/go-strslice.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
-go-traceback.lo: runtime/go-traceback.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-traceback.lo -MD -MP -MF $(DEPDIR)/go-traceback.Tpo -c -o go-traceback.lo `test -f 'runtime/go-traceback.c' || echo '$(srcdir)/'`runtime/go-traceback.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-traceback.Tpo $(DEPDIR)/go-traceback.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-traceback.c' object='go-traceback.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-traceback.lo `test -f 'runtime/go-traceback.c' || echo '$(srcdir)/'`runtime/go-traceback.c
-
-go-type-complex.lo: runtime/go-type-complex.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-complex.lo -MD -MP -MF $(DEPDIR)/go-type-complex.Tpo -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-complex.Tpo $(DEPDIR)/go-type-complex.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-complex.c' object='go-type-complex.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
-
-go-type-eface.lo: runtime/go-type-eface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-eface.lo -MD -MP -MF $(DEPDIR)/go-type-eface.Tpo -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-eface.Tpo $(DEPDIR)/go-type-eface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-eface.c' object='go-type-eface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
-
-go-type-error.lo: runtime/go-type-error.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-error.lo -MD -MP -MF $(DEPDIR)/go-type-error.Tpo -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-error.Tpo $(DEPDIR)/go-type-error.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-error.c' object='go-type-error.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
-
-go-type-float.lo: runtime/go-type-float.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-float.lo -MD -MP -MF $(DEPDIR)/go-type-float.Tpo -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-float.Tpo $(DEPDIR)/go-type-float.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-float.c' object='go-type-float.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
-
-go-type-identity.lo: runtime/go-type-identity.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-identity.c' object='go-type-identity.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
-
-go-type-interface.lo: runtime/go-type-interface.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-interface.lo -MD -MP -MF $(DEPDIR)/go-type-interface.Tpo -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-interface.Tpo $(DEPDIR)/go-type-interface.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-interface.c' object='go-type-interface.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
-
-go-type-string.lo: runtime/go-type-string.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-string.lo -MD -MP -MF $(DEPDIR)/go-type-string.Tpo -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-string.Tpo $(DEPDIR)/go-type-string.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-string.c' object='go-type-string.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
-
go-typedesc-equal.lo: runtime/go-typedesc-equal.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typedesc-equal.lo -MD -MP -MF $(DEPDIR)/go-typedesc-equal.Tpo -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typedesc-equal.Tpo $(DEPDIR)/go-typedesc-equal.Plo
@@ -3373,34 +1835,6 @@ heapdump.lo: runtime/heapdump.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o heapdump.lo `test -f 'runtime/heapdump.c' || echo '$(srcdir)/'`runtime/heapdump.c
-lock_sema.lo: runtime/lock_sema.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock_sema.lo -MD -MP -MF $(DEPDIR)/lock_sema.Tpo -c -o lock_sema.lo `test -f 'runtime/lock_sema.c' || echo '$(srcdir)/'`runtime/lock_sema.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lock_sema.Tpo $(DEPDIR)/lock_sema.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/lock_sema.c' object='lock_sema.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock_sema.lo `test -f 'runtime/lock_sema.c' || echo '$(srcdir)/'`runtime/lock_sema.c
-
-thread-sema.lo: runtime/thread-sema.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-sema.lo -MD -MP -MF $(DEPDIR)/thread-sema.Tpo -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-sema.Tpo $(DEPDIR)/thread-sema.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-sema.c' object='thread-sema.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c
-
-lock_futex.lo: runtime/lock_futex.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock_futex.lo -MD -MP -MF $(DEPDIR)/lock_futex.Tpo -c -o lock_futex.lo `test -f 'runtime/lock_futex.c' || echo '$(srcdir)/'`runtime/lock_futex.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lock_futex.Tpo $(DEPDIR)/lock_futex.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/lock_futex.c' object='lock_futex.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock_futex.lo `test -f 'runtime/lock_futex.c' || echo '$(srcdir)/'`runtime/lock_futex.c
-
-thread-linux.lo: runtime/thread-linux.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-linux.lo -MD -MP -MF $(DEPDIR)/thread-linux.Tpo -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-linux.Tpo $(DEPDIR)/thread-linux.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-linux.c' object='thread-linux.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c
-
mcache.lo: runtime/mcache.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcache.lo -MD -MP -MF $(DEPDIR)/mcache.Tpo -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mcache.Tpo $(DEPDIR)/mcache.Plo
@@ -3457,27 +1891,6 @@ msize.lo: runtime/msize.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
-netpoll_kqueue.lo: runtime/netpoll_kqueue.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_kqueue.lo -MD -MP -MF $(DEPDIR)/netpoll_kqueue.Tpo -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_kqueue.Tpo $(DEPDIR)/netpoll_kqueue.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_kqueue.c' object='netpoll_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
-
-netpoll_select.lo: runtime/netpoll_select.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_select.lo -MD -MP -MF $(DEPDIR)/netpoll_select.Tpo -c -o netpoll_select.lo `test -f 'runtime/netpoll_select.c' || echo '$(srcdir)/'`runtime/netpoll_select.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_select.Tpo $(DEPDIR)/netpoll_select.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_select.c' object='netpoll_select.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_select.lo `test -f 'runtime/netpoll_select.c' || echo '$(srcdir)/'`runtime/netpoll_select.c
-
-netpoll_epoll.lo: runtime/netpoll_epoll.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_epoll.lo -MD -MP -MF $(DEPDIR)/netpoll_epoll.Tpo -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_epoll.Tpo $(DEPDIR)/netpoll_epoll.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_epoll.c' object='netpoll_epoll.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
-
panic.lo: runtime/panic.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT panic.lo -MD -MP -MF $(DEPDIR)/panic.Tpo -c -o panic.lo `test -f 'runtime/panic.c' || echo '$(srcdir)/'`runtime/panic.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/panic.Tpo $(DEPDIR)/panic.Plo
@@ -3506,19 +1919,12 @@ proc.lo: runtime/proc.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
-runtime.lo: runtime/runtime.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT runtime.lo -MD -MP -MF $(DEPDIR)/runtime.Tpo -c -o runtime.lo `test -f 'runtime/runtime.c' || echo '$(srcdir)/'`runtime/runtime.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/runtime.Tpo $(DEPDIR)/runtime.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/runtime.c' object='runtime.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o runtime.lo `test -f 'runtime/runtime.c' || echo '$(srcdir)/'`runtime/runtime.c
-
-signal_unix.lo: runtime/signal_unix.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT signal_unix.lo -MD -MP -MF $(DEPDIR)/signal_unix.Tpo -c -o signal_unix.lo `test -f 'runtime/signal_unix.c' || echo '$(srcdir)/'`runtime/signal_unix.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/signal_unix.Tpo $(DEPDIR)/signal_unix.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/signal_unix.c' object='signal_unix.lo' libtool=yes @AMDEPBACKSLASH@
+runtime_c.lo: runtime/runtime_c.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT runtime_c.lo -MD -MP -MF $(DEPDIR)/runtime_c.Tpo -c -o runtime_c.lo `test -f 'runtime/runtime_c.c' || echo '$(srcdir)/'`runtime/runtime_c.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/runtime_c.Tpo $(DEPDIR)/runtime_c.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/runtime_c.c' object='runtime_c.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o signal_unix.lo `test -f 'runtime/signal_unix.c' || echo '$(srcdir)/'`runtime/signal_unix.c
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o runtime_c.lo `test -f 'runtime/runtime_c.c' || echo '$(srcdir)/'`runtime/runtime_c.c
thread.lo: runtime/thread.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread.lo -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
@@ -3527,6 +1933,20 @@ thread.lo: runtime/thread.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
+thread-sema.lo: runtime/thread-sema.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-sema.lo -MD -MP -MF $(DEPDIR)/thread-sema.Tpo -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-sema.Tpo $(DEPDIR)/thread-sema.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-sema.c' object='thread-sema.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c
+
+thread-linux.lo: runtime/thread-linux.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-linux.lo -MD -MP -MF $(DEPDIR)/thread-linux.Tpo -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-linux.Tpo $(DEPDIR)/thread-linux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-linux.c' object='thread-linux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c
+
yield.lo: runtime/yield.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT yield.lo -MD -MP -MF $(DEPDIR)/yield.Tpo -c -o yield.lo `test -f 'runtime/yield.c' || echo '$(srcdir)/'`runtime/yield.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/yield.Tpo $(DEPDIR)/yield.Plo
@@ -4105,27 +2525,6 @@ uninstall-toolexeclibgonetrpcDATA:
@list='$(toolexeclibgonetrpc_DATA)'; test -n "$(toolexeclibgonetrpcdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(toolexeclibgonetrpcdir)'; $(am__uninstall_files_from_dir)
-install-toolexeclibgooldDATA: $(toolexeclibgoold_DATA)
- @$(NORMAL_INSTALL)
- @list='$(toolexeclibgoold_DATA)'; test -n "$(toolexeclibgoolddir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibgoolddir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoolddir)" || exit 1; \
- fi; \
- for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- echo "$$d$$p"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoolddir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoolddir)" || exit $$?; \
- done
-
-uninstall-toolexeclibgooldDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(toolexeclibgoold_DATA)'; test -n "$(toolexeclibgoolddir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(toolexeclibgoolddir)'; $(am__uninstall_files_from_dir)
install-toolexeclibgoosDATA: $(toolexeclibgoos_DATA)
@$(NORMAL_INSTALL)
@list='$(toolexeclibgoos_DATA)'; test -n "$(toolexeclibgoosdir)" || list=; \
@@ -4252,6 +2651,27 @@ uninstall-toolexeclibgotestingDATA:
@list='$(toolexeclibgotesting_DATA)'; test -n "$(toolexeclibgotestingdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(toolexeclibgotestingdir)'; $(am__uninstall_files_from_dir)
+install-toolexeclibgotestinginternalDATA: $(toolexeclibgotestinginternal_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(toolexeclibgotestinginternal_DATA)'; test -n "$(toolexeclibgotestinginternaldir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibgotestinginternaldir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(toolexeclibgotestinginternaldir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgotestinginternaldir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgotestinginternaldir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgotestinginternalDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgotestinginternal_DATA)'; test -n "$(toolexeclibgotestinginternaldir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(toolexeclibgotestinginternaldir)'; $(am__uninstall_files_from_dir)
install-toolexeclibgotextDATA: $(toolexeclibgotext_DATA)
@$(NORMAL_INSTALL)
@list='$(toolexeclibgotext_DATA)'; test -n "$(toolexeclibgotextdir)" || list=; \
@@ -4456,7 +2876,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
config.h
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoimagecolordir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoimagecolordir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotestinginternaldir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -4539,11 +2959,12 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
install-toolexeclibgologDATA install-toolexeclibgomathDATA \
install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
install-toolexeclibgonethttpDATA \
- install-toolexeclibgonetrpcDATA install-toolexeclibgooldDATA \
- install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
- install-toolexeclibgoregexpDATA \
+ install-toolexeclibgonetrpcDATA install-toolexeclibgoosDATA \
+ install-toolexeclibgopathDATA install-toolexeclibgoregexpDATA \
install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
- install-toolexeclibgotestingDATA install-toolexeclibgotextDATA \
+ install-toolexeclibgotestingDATA \
+ install-toolexeclibgotestinginternalDATA \
+ install-toolexeclibgotextDATA \
install-toolexeclibgotexttemplateDATA \
install-toolexeclibgounicodeDATA
@@ -4608,12 +3029,12 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
uninstall-toolexeclibgonethttpDATA \
uninstall-toolexeclibgonetrpcDATA \
- uninstall-toolexeclibgooldDATA uninstall-toolexeclibgoosDATA \
- uninstall-toolexeclibgopathDATA \
+ uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
uninstall-toolexeclibgoregexpDATA \
uninstall-toolexeclibgoruntimeDATA \
uninstall-toolexeclibgosyncDATA \
uninstall-toolexeclibgotestingDATA \
+ uninstall-toolexeclibgotestinginternalDATA \
uninstall-toolexeclibgotextDATA \
uninstall-toolexeclibgotexttemplateDATA \
uninstall-toolexeclibgounicodeDATA
@@ -4652,11 +3073,12 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
install-toolexeclibgologDATA install-toolexeclibgomathDATA \
install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
install-toolexeclibgonethttpDATA \
- install-toolexeclibgonetrpcDATA install-toolexeclibgooldDATA \
- install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
- install-toolexeclibgoregexpDATA \
+ install-toolexeclibgonetrpcDATA install-toolexeclibgoosDATA \
+ install-toolexeclibgopathDATA install-toolexeclibgoregexpDATA \
install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
- install-toolexeclibgotestingDATA install-toolexeclibgotextDATA \
+ install-toolexeclibgotestingDATA \
+ install-toolexeclibgotestinginternalDATA \
+ install-toolexeclibgotextDATA \
install-toolexeclibgotexttemplateDATA \
install-toolexeclibgounicodeDATA installcheck installcheck-am \
installdirs installdirs-am maintainer-clean \
@@ -4685,12 +3107,12 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
uninstall-toolexeclibgonethttpDATA \
uninstall-toolexeclibgonetrpcDATA \
- uninstall-toolexeclibgooldDATA uninstall-toolexeclibgoosDATA \
- uninstall-toolexeclibgopathDATA \
+ uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
uninstall-toolexeclibgoregexpDATA \
uninstall-toolexeclibgoruntimeDATA \
uninstall-toolexeclibgosyncDATA \
uninstall-toolexeclibgotestingDATA \
+ uninstall-toolexeclibgotestinginternalDATA \
uninstall-toolexeclibgotextDATA \
uninstall-toolexeclibgotexttemplateDATA \
uninstall-toolexeclibgounicodeDATA
@@ -4706,34 +3128,6 @@ malloc.c: $(srcdir)/runtime/malloc.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
-mprof.c: $(srcdir)/runtime/mprof.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-reflect.c: $(srcdir)/runtime/reflect.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-sema.c: $(srcdir)/runtime/sema.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
-sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
- ./goc2c --go-pkgpath os_signal $< > $@.tmp
- mv -f $@.tmp $@
-
-time.c: $(srcdir)/runtime/time.goc goc2c
- ./goc2c $< > $@.tmp
- mv -f $@.tmp $@
-
%.c: $(srcdir)/runtime/%.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
@@ -4741,15 +3135,79 @@ time.c: $(srcdir)/runtime/time.goc goc2c
version.go: s-version; @true
s-version: Makefile
rm -f version.go.tmp
- echo "package runtime" > version.go.tmp
- echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
- echo 'const theVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
- echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
- echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
- echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ echo "package sys" > version.go.tmp
+ echo 'const DefaultGoroot = "$(prefix)"' >> version.go.tmp
+ echo 'const TheVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const GOARCH = "'$(GOARCH)'"' >> version.go.tmp
+ echo 'const GOOS = "'$(GOOS)'"' >> version.go.tmp
+ echo 'const GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ echo >> version.go.tmp
+ echo "type ArchFamilyType int" >> version.go.tmp
+ echo >> version.go.tmp
+ echo "const (" >> version.go.tmp
+ echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
+ for a in $(ALLGOARCHFAMILY); do \
+ echo " $${a}" >> version.go.tmp; \
+ done
+ echo ")" >> version.go.tmp
+ echo >> version.go.tmp
+ for a in $(ALLGOARCH); do \
+ f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
+ n="$${f}`echo $${a} | sed -e 's/.//'`"; \
+ if test "$${a}" = "$(GOARCH)"; then \
+ echo "const Goarch$${n} = 1" >> version.go.tmp; \
+ else \
+ echo "const Goarch$${n} = 0" >> version.go.tmp; \
+ fi; \
+ done
+ echo >> version.go.tmp
+ echo "const (" >> version.go.tmp
+ echo " ArchFamily = $(GOARCH_FAMILY)" >> version.go.tmp
+ echo " BigEndian = $(GOARCH_BIGENDIAN)" >> version.go.tmp
+ echo " CacheLineSize = $(GOARCH_CACHELINESIZE)" >> version.go.tmp
+ echo " PhysPageSize = $(GOARCH_PHYSPAGESIZE)" >> version.go.tmp
+ echo " PCQuantum = $(GOARCH_PCQUANTUM)" >> version.go.tmp
+ echo " Int64Align = $(GOARCH_INT64ALIGN)" >> version.go.tmp
+ echo " HugePageSize = $(GOARCH_HUGEPAGESIZE)" >> version.go.tmp
+ echo " MinFrameSize = $(GOARCH_MINFRAMESIZE)" >> version.go.tmp
+ echo ")" >> version.go.tmp
+ echo >> version.go.tmp
+ for a in $(ALLGOOS); do \
+ f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
+ n="$${f}`echo $${a} | sed -e 's/.//'`"; \
+ if test "$${a}" = "$(GOOS)"; then \
+ echo "const Goos$${n} = 1" >> version.go.tmp; \
+ else \
+ echo "const Goos$${n} = 0" >> version.go.tmp; \
+ fi; \
+ done
+ echo >> version.go.tmp
+ echo "type Uintreg uintptr" >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@
+runtime_sysinfo.go: s-runtime_sysinfo; @true
+s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
+ $(SHELL) $(srcdir)/mkrsysinfo.sh
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
+ $(STAMP) $@
+
+sigtab.go: s-sigtab; @true
+s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
+ GOOS=$(GOOS) $(SHELL) $(srcdir)/mksigtab.sh > tmp-sigtab.go
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
+ $(STAMP) $@
+
+runtime.inc: s-runtime-inc; @true
+s-runtime-inc: runtime.lo Makefile
+ rm -f runtime.inc.tmp2
+ grep -v "#define _" runtime.inc.tmp | grep -v "#define [cm][01234] " > runtime.inc.tmp2
+ for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
+ grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
+ done
+ $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
+ $(STAMP) $@
+
# Generate the list of go std packages that were included in libgo
zstdpkglist.go: s-zstdpkglist; @true
s-zstdpkglist: Makefile
@@ -4757,23 +3215,22 @@ s-zstdpkglist: Makefile
echo 'package main' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
- echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | grep -v _c | sed 's/\.lo/\": true,/' | sed 's/^/\t\"/' | sort -u >> zstdpkglist.go.tmp
echo '}' >> zstdpkglist.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
libcalls.go: s-libcalls; @true
-s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
+s-libcalls: libcalls-list go/syscall/mksyscall.awk $(srcdir)/go/syscall/*.go
rm -f libcalls.go.tmp
- files=`echo $^ | sed -e 's/libcalls-list//' -e 's|[^ ]*go/syscall/mksyscall.awk||'`; \
- $(AWK) -f $(srcdir)/go/syscall/mksyscall.awk $${files} > libcalls.go.tmp
+ $(AWK) -f $(srcdir)/go/syscall/mksyscall.awk `cat libcalls-list` > libcalls.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh libcalls.go.tmp libcalls.go
$(STAMP) $@
libcalls-list: s-libcalls-list; @true
-s-libcalls-list: Makefile
+s-libcalls-list: Makefile $(srcdir)/go/syscall/*.go
rm -f libcalls-list.tmp
- echo $(go_base_syscall_files) > libcalls-list.tmp
+ $(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/syscall $(matchargs_syscall) > libcalls-list.tmp
$(SHELL) $(srcdir)/mvifdiff.sh libcalls-list.tmp libcalls-list
$(STAMP) $@
@@ -4786,9 +3243,22 @@ s-syscall_arch: Makefile
$(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
$(STAMP) $@
+gen-sysinfo.go: s-gen-sysinfo; @true
+s-gen-sysinfo: $(srcdir)/sysinfo.c config.h
+ $(CC) $(SYSINFO_FLAGS) -fdump-go-spec=tmp-gen-sysinfo.go -std=gnu99 -S -o sysinfo.s $(srcdir)/sysinfo.c
+ rm -f sysinfo.s
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-gen-sysinfo.go gen-sysinfo.go
+ $(STAMP) $@
+
+errno.i: s-errno; @true
+s-errno:
+ echo '#include <errno.h>' | $(CC) $(SYSINFO_FLAGS) -x c - -E -dM > tmp-errno.i
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-errno.i errno.i
+ $(STAMP) $@
+
sysinfo.go: s-sysinfo; @true
-s-sysinfo: $(srcdir)/mksysinfo.sh config.h
- CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS) -O" $(SHELL) $(srcdir)/mksysinfo.sh
+s-sysinfo: $(srcdir)/mksysinfo.sh gen-sysinfo.go errno.i
+ $(SHELL) $(srcdir)/mksysinfo.sh
$(SHELL) $(srcdir)/mvifdiff.sh tmp-sysinfo.go sysinfo.go
$(STAMP) $@
@@ -4820,1723 +3290,100 @@ s-epoll: Makefile
$(SHELL) $(srcdir)/mvifdiff.sh epoll.go.tmp epoll.go
$(STAMP) $@
-@go_include@ bufio.lo.dep
-bufio.lo.dep: $(go_bufio_files)
- $(BUILDDEPS)
-bufio.lo: $(go_bufio_files)
- $(BUILDPACKAGE)
-bufio/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bufio/check
-
-@go_include@ bytes.lo.dep
-bytes.lo.dep: $(go_bytes_files)
- $(BUILDDEPS)
-bytes.lo: $(go_bytes_files)
- $(BUILDPACKAGE)
-bytes/index.lo: $(go_bytes_c_files)
+# Make sure runtime.inc is built before compiling any .c file.
+$(libgo_la_OBJECTS): runtime.inc
+$(libgo_llgo_la_OBJECTS): runtime.inc
+$(libgobegin_a_OBJECTS): runtime.inc
+$(libgobegin_llgo_a_OBJECTS): runtime.inc
+$(libgolibbegin_a_OBJECTS): runtime.inc
+
+# PACKAGE_template defines the rules for each package.
+# For example, for the package bufio, it produces:
+#
+# @go_include@ bufio.lo.dep
+# bufio.lo.dep: $(srcdir)/go/bufio/*.go
+# $(BUILDDEPS)
+# bufio.lo:
+# $(BUILDPACKAGE)
+# bufio/check: $(CHECK_DEPS)
+# @$(CHECK)
+# .PHONY: bufio/check
+#
+# This is invoked with $(1) set to a package, which is a directory name,
+# such as "bufio" or "archive/tar".
+define PACKAGE_template
+@go_include@ $(1).lo.dep
+$(1).lo.dep: $(srcdir)/go/$(1)/*.go
+ $$(BUILDDEPS)
+$(1).lo:
+ $$(BUILDPACKAGE)
+$(1)/check: $$(CHECK_DEPS)
+ @$$(CHECK)
+.PHONY: $(1)/check
+$(1).gox: $(1).s-gox; @true
+$(1).s-gox: $(1).lo
+ $$(BUILDGOX)
+ $$(STAMP) $$@
+endef
+
+# This line expands PACKAGE_template once for each package name listed
+# in $(PACKAGES).
+$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
+runtime.lo.dep: $(extra_go_files_runtime)
+syscall.lo.dep: $(extra_go_files_syscall)
+runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
+
+# FIXME: The following C files may as well move to the runtime
+# directory and be treated like other C files.
+
+# Use C code to speed up {bytes,strings}.IndexByte and friends.
+bytes/index.lo: go/bytes/indexbyte.c runtime.inc
@$(MKDIR_P) bytes
- $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
-bytes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bytes/check
-
-@go_include@ crypto.lo.dep
-crypto.lo.dep: $(go_crypto_files)
- $(BUILDDEPS)
-crypto.lo: $(go_crypto_files)
- $(BUILDPACKAGE)
-crypto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/check
-
-@go_include@ encoding.lo.dep
-encoding.lo.dep: $(go_encoding_files)
- $(BUILDDEPS)
-encoding.lo: $(go_encoding_files)
- $(BUILDPACKAGE)
-encoding/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/check
-
-@go_include@ errors.lo.dep
-errors.lo.dep: $(go_errors_files)
- $(BUILDDEPS)
-errors.lo: $(go_errors_files)
- $(BUILDPACKAGE)
-errors/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: errors/check
-
-@go_include@ expvar.lo.dep
-expvar.lo.dep: $(go_expvar_files)
- $(BUILDDEPS)
-expvar.lo: $(go_expvar_files)
- $(BUILDPACKAGE)
-expvar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: expvar/check
-
-@go_include@ flag.lo.dep
-flag.lo.dep: $(go_flag_files)
- $(BUILDDEPS)
-flag.lo: $(go_flag_files)
- $(BUILDPACKAGE)
-flag/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: flag/check
-
-@go_include@ fmt.lo.dep
-fmt.lo.dep: $(go_fmt_files)
- $(BUILDDEPS)
-fmt.lo: $(go_fmt_files)
- $(BUILDPACKAGE)
-fmt/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: fmt/check
-
-@go_include@ hash.lo.dep
-hash.lo.dep: $(go_hash_files)
- $(BUILDDEPS)
-hash.lo: $(go_hash_files)
- $(BUILDPACKAGE)
-hash/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/check
-
-@go_include@ html.lo.dep
-html.lo.dep: $(go_html_files)
- $(BUILDDEPS)
-html.lo: $(go_html_files)
- $(BUILDPACKAGE)
-html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/check
-
-@go_include@ image.lo.dep
-image.lo.dep: $(go_image_files)
- $(BUILDDEPS)
-image.lo: $(go_image_files)
- $(BUILDPACKAGE)
-image/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/check
-
-@go_include@ io.lo.dep
-io.lo.dep: $(go_io_files)
- $(BUILDDEPS)
-io.lo: $(go_io_files)
- $(BUILDPACKAGE)
-io/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/check
-
-@go_include@ log.lo.dep
-log.lo.dep: $(go_log_files)
- $(BUILDDEPS)
-log.lo: $(go_log_files)
- $(BUILDPACKAGE)
-log/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/check
-
-@go_include@ math.lo.dep
-math.lo.dep: $(go_math_files)
- $(BUILDDEPS)
-math.lo: $(go_math_files)
- $(MKDIR_P) $(@D)
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) $(MATH_FLAG) -I . -c -fgo-pkgpath=math -o $@ $$files
-math/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/check
-
-@go_include@ mime.lo.dep
-mime.lo.dep: $(go_mime_files)
- $(BUILDDEPS)
-mime.lo: $(go_mime_files)
- $(BUILDPACKAGE)
-mime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/check
-
-@go_include@ net.lo.dep
-net.lo.dep: $(go_net_files)
- $(BUILDDEPS)
-net.lo: $(go_net_files)
- $(BUILDPACKAGE)
-net/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/check
-
-@go_include@ netgo.o.dep
-netgo.o.dep: $(go_netgo_files)
- $(BUILDDEPS)
-netgo.o: $(go_netgo_files)
- $(BUILDNETGO)
-
-@go_include@ os.lo.dep
-os.lo.dep: $(go_os_files)
- $(BUILDDEPS)
-os.lo: $(go_os_files)
- $(BUILDPACKAGE)
-os/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/check
-
-@go_include@ path.lo.dep
-path.lo.dep: $(go_path_files)
- $(BUILDDEPS)
-path.lo: $(go_path_files)
- $(BUILDPACKAGE)
-path/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/check
-
-@go_include@ reflect-go.lo.dep
-reflect-go.lo.dep: $(go_reflect_files)
- $(BUILDDEPS)
-reflect-go.lo: $(go_reflect_files)
- $(BUILDPACKAGE)
-reflect/check: $(CHECK_DEPS)
- @$(CHECK)
-reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
- @$(MKDIR_P) reflect
- $(LTCOMPILE) -c -o $@ $<
-.PHONY: reflect/check
-
-@go_include@ regexp.lo.dep
-regexp.lo.dep: $(go_regexp_files)
- $(BUILDDEPS)
-regexp.lo: $(go_regexp_files)
- $(BUILDPACKAGE)
-regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/check
-
-@go_include@ runtime-go.lo.dep
-runtime-go.lo.dep: $(go_runtime_files)
- $(BUILDDEPS)
-runtime-go.lo: $(go_runtime_files)
- $(BUILDPACKAGE)
-runtime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/check
-
-@go_include@ sort.lo.dep
-sort.lo.dep: $(go_sort_files)
- $(BUILDDEPS)
-sort.lo: $(go_sort_files)
- $(BUILDPACKAGE)
-sort/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sort/check
-
-@go_include@ strconv.lo.dep
-strconv.lo.dep: $(go_strconv_files)
- $(BUILDDEPS)
-strconv.lo: $(go_strconv_files)
- $(BUILDPACKAGE)
-strconv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strconv/check
-
-@go_include@ strings.lo.dep
-strings.lo.dep: $(go_strings_files)
- $(BUILDDEPS)
-strings.lo: $(go_strings_files)
- $(BUILDPACKAGE)
-strings/index.lo: $(go_strings_c_files)
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/bytes/indexbyte.c
+strings/index.lo: go/strings/indexbyte.c runtime.inc
@$(MKDIR_P) strings
- $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c
-strings/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strings/check
-
-@go_include@ sync.lo.dep
-sync.lo.dep: $(go_sync_files)
- $(BUILDDEPS)
-sync.lo: $(go_sync_files)
- $(BUILDPACKAGE)
-sync/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/check
-
-@go_include@ testing.lo.dep
-testing.lo.dep: $(go_testing_files)
- $(BUILDDEPS)
-testing.lo: $(go_testing_files)
- $(BUILDPACKAGE)
-testing/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/check
-
-@go_include@ time-go.lo.dep
-time-go.lo.dep: $(go_time_files)
- $(BUILDDEPS)
-time-go.lo: $(go_time_files)
- $(BUILDPACKAGE)
-time/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: time/check
-
-@go_include@ unicode.lo.dep
-unicode.lo.dep: $(go_unicode_files)
- $(BUILDDEPS)
-unicode.lo: $(go_unicode_files)
- $(BUILDPACKAGE)
-unicode/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/check
-
-@go_include@ archive/tar.lo.dep
-archive/tar.lo.dep: $(go_archive_tar_files)
- $(BUILDDEPS)
-archive/tar.lo: $(go_archive_tar_files)
- $(BUILDPACKAGE)
-archive/tar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/tar/check
-
-@go_include@ archive/zip.lo.dep
-archive/zip.lo.dep: $(go_archive_zip_files)
- $(BUILDDEPS)
-archive/zip.lo: $(go_archive_zip_files)
- $(BUILDPACKAGE)
-archive/zip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/zip/check
-
-@go_include@ compress/bzip2.lo.dep
-compress/bzip2.lo.dep: $(go_compress_bzip2_files)
- $(BUILDDEPS)
-compress/bzip2.lo: $(go_compress_bzip2_files)
- $(BUILDPACKAGE)
-compress/bzip2/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/bzip2/check
-
-@go_include@ compress/flate.lo.dep
-compress/flate.lo.dep: $(go_compress_flate_files)
- $(BUILDDEPS)
-compress/flate.lo: $(go_compress_flate_files)
- $(BUILDPACKAGE)
-compress/flate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/flate/check
-
-@go_include@ compress/gzip.lo.dep
-compress/gzip.lo.dep: $(go_compress_gzip_files)
- $(BUILDDEPS)
-compress/gzip.lo: $(go_compress_gzip_files)
- $(BUILDPACKAGE)
-compress/gzip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/gzip/check
-
-@go_include@ compress/lzw.lo.dep
-compress/lzw.lo.dep: $(go_compress_lzw_files)
- $(BUILDDEPS)
-compress/lzw.lo: $(go_compress_lzw_files)
- $(BUILDPACKAGE)
-compress/lzw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/lzw/check
-
-@go_include@ compress/zlib.lo.dep
-compress/zlib.lo.dep: $(go_compress_zlib_files)
- $(BUILDDEPS)
-compress/zlib.lo: $(go_compress_zlib_files)
- $(BUILDPACKAGE)
-compress/zlib/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/zlib/check
-
-@go_include@ container/heap.lo.dep
-container/heap.lo.dep: $(go_container_heap_files)
- $(BUILDDEPS)
-container/heap.lo: $(go_container_heap_files)
- $(BUILDPACKAGE)
-container/heap/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/heap/check
-
-@go_include@ container/list.lo.dep
-container/list.lo.dep: $(go_container_list_files)
- $(BUILDDEPS)
-container/list.lo: $(go_container_list_files)
- $(BUILDPACKAGE)
-container/list/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/list/check
-
-@go_include@ container/ring.lo.dep
-container/ring.lo.dep: $(go_container_ring_files)
- $(BUILDDEPS)
-container/ring.lo: $(go_container_ring_files)
- $(BUILDPACKAGE)
-container/ring/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/ring/check
-
-@go_include@ crypto/aes.lo.dep
-crypto/aes.lo.dep: $(go_crypto_aes_files)
- $(BUILDDEPS)
-crypto/aes.lo: $(go_crypto_aes_files)
- $(BUILDPACKAGE)
-crypto/aes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/aes/check
-
-@go_include@ crypto/cipher.lo.dep
-crypto/cipher.lo.dep: $(go_crypto_cipher_files)
- $(BUILDDEPS)
-crypto/cipher.lo: $(go_crypto_cipher_files)
- $(BUILDPACKAGE)
-crypto/cipher/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/cipher/check
-
-@go_include@ crypto/des.lo.dep
-crypto/des.lo.dep: $(go_crypto_des_files)
- $(BUILDDEPS)
-crypto/des.lo: $(go_crypto_des_files)
- $(BUILDPACKAGE)
-crypto/des/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/des/check
-
-@go_include@ crypto/dsa.lo.dep
-crypto/dsa.lo.dep: $(go_crypto_dsa_files)
- $(BUILDDEPS)
-crypto/dsa.lo: $(go_crypto_dsa_files)
- $(BUILDPACKAGE)
-crypto/dsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/dsa/check
-
-@go_include@ crypto/ecdsa.lo.dep
-crypto/ecdsa.lo.dep: $(go_crypto_ecdsa_files)
- $(BUILDDEPS)
-crypto/ecdsa.lo: $(go_crypto_ecdsa_files)
- $(BUILDPACKAGE)
-crypto/ecdsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/ecdsa/check
-
-@go_include@ crypto/elliptic.lo.dep
-crypto/elliptic.lo.dep: $(go_crypto_elliptic_files)
- $(BUILDDEPS)
-crypto/elliptic.lo: $(go_crypto_elliptic_files)
- $(BUILDPACKAGE)
-crypto/elliptic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/elliptic/check
-
-@go_include@ crypto/hmac.lo.dep
-crypto/hmac.lo.dep: $(go_crypto_hmac_files)
- $(BUILDDEPS)
-crypto/hmac.lo: $(go_crypto_hmac_files)
- $(BUILDPACKAGE)
-crypto/hmac/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/hmac/check
-
-@go_include@ crypto/md5.lo.dep
-crypto/md5.lo.dep: $(go_crypto_md5_files)
- $(BUILDDEPS)
-crypto/md5.lo: $(go_crypto_md5_files)
- $(BUILDPACKAGE)
-crypto/md5/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/md5/check
-
-@go_include@ crypto/rand.lo.dep
-crypto/rand.lo.dep: $(go_crypto_rand_files)
- $(BUILDDEPS)
-crypto/rand.lo: $(go_crypto_rand_files)
- $(BUILDPACKAGE)
-crypto/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rand/check
-
-@go_include@ crypto/rc4.lo.dep
-crypto/rc4.lo.dep: $(go_crypto_rc4_files)
- $(BUILDDEPS)
-crypto/rc4.lo: $(go_crypto_rc4_files)
- $(BUILDPACKAGE)
-crypto/rc4/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rc4/check
-
-@go_include@ crypto/rsa.lo.dep
-crypto/rsa.lo.dep: $(go_crypto_rsa_files)
- $(BUILDDEPS)
-crypto/rsa.lo: $(go_crypto_rsa_files)
- $(BUILDPACKAGE)
-crypto/rsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rsa/check
-
-@go_include@ crypto/sha1.lo.dep
-crypto/sha1.lo.dep: $(go_crypto_sha1_files)
- $(BUILDDEPS)
-crypto/sha1.lo: $(go_crypto_sha1_files)
- $(BUILDPACKAGE)
-crypto/sha1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha1/check
-
-@go_include@ crypto/sha256.lo.dep
-crypto/sha256.lo.dep: $(go_crypto_sha256_files)
- $(BUILDDEPS)
-crypto/sha256.lo: $(go_crypto_sha256_files)
- $(BUILDPACKAGE)
-crypto/sha256/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha256/check
-
-@go_include@ crypto/sha512.lo.dep
-crypto/sha512.lo.dep: $(go_crypto_sha512_files)
- $(BUILDDEPS)
-crypto/sha512.lo: $(go_crypto_sha512_files)
- $(BUILDPACKAGE)
-crypto/sha512/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha512/check
-
-@go_include@ crypto/subtle.lo.dep
-crypto/subtle.lo.dep: $(go_crypto_subtle_files)
- $(BUILDDEPS)
-crypto/subtle.lo: $(go_crypto_subtle_files)
- $(BUILDPACKAGE)
-crypto/subtle/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/subtle/check
-
-@go_include@ crypto/tls.lo.dep
-crypto/tls.lo.dep: $(go_crypto_tls_files)
- $(BUILDDEPS)
-crypto/tls.lo: $(go_crypto_tls_files)
- $(BUILDPACKAGE)
-crypto/tls/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/tls/check
-
-@go_include@ crypto/x509.lo.dep
-crypto/x509.lo.dep: $(go_crypto_x509_files)
- $(BUILDDEPS)
-crypto/x509.lo: $(go_crypto_x509_files)
- $(BUILDPACKAGE)
-crypto/x509/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/check
-
-@go_include@ crypto/x509/pkix.lo.dep
-crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files)
- $(BUILDDEPS)
-crypto/x509/pkix.lo: $(go_crypto_x509_pkix_files)
- $(BUILDPACKAGE)
-crypto/x509/pkix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/pkix/check
-
-@go_include@ database/sql.lo.dep
-database/sql.lo.dep: $(go_database_sql_files)
- $(BUILDDEPS)
-database/sql.lo: $(go_database_sql_files)
- $(BUILDPACKAGE)
-database/sql/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/check
-
-@go_include@ database/sql/driver.lo.dep
-database/sql/driver.lo.dep: $(go_database_sql_driver_files)
- $(BUILDDEPS)
-database/sql/driver.lo: $(go_database_sql_driver_files)
- $(BUILDPACKAGE)
-database/sql/driver/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/driver/check
-
-@go_include@ debug/dwarf.lo.dep
-debug/dwarf.lo.dep: $(go_debug_dwarf_files)
- $(BUILDDEPS)
-debug/dwarf.lo: $(go_debug_dwarf_files)
- $(BUILDPACKAGE)
-debug/dwarf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/dwarf/check
-
-@go_include@ debug/elf.lo.dep
-debug/elf.lo.dep: $(go_debug_elf_files)
- $(BUILDDEPS)
-debug/elf.lo: $(go_debug_elf_files)
- $(BUILDPACKAGE)
-debug/elf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/elf/check
-
-@go_include@ debug/gosym.lo.dep
-debug/gosym.lo.dep: $(go_debug_gosym_files)
- $(BUILDDEPS)
-debug/gosym.lo: $(go_debug_gosym_files)
- $(BUILDPACKAGE)
-debug/gosym/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/gosym/check
-
-@go_include@ debug/macho.lo.dep
-debug/macho.lo.dep: $(go_debug_macho_files)
- $(BUILDDEPS)
-debug/macho.lo: $(go_debug_macho_files)
- $(BUILDPACKAGE)
-debug/macho/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/macho/check
-
-@go_include@ debug/pe.lo.dep
-debug/pe.lo.dep: $(go_debug_pe_files)
- $(BUILDDEPS)
-debug/pe.lo: $(go_debug_pe_files)
- $(BUILDPACKAGE)
-debug/pe/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/pe/check
-
-@go_include@ debug/plan9obj.lo.dep
-debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
- $(BUILDDEPS)
-debug/plan9obj.lo: $(go_debug_plan9obj_files)
- $(BUILDPACKAGE)
-debug/plan9obj/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/plan9obj/check
-
-@go_include@ encoding/asn1.lo.dep
-encoding/asn1.lo.dep: $(go_encoding_asn1_files)
- $(BUILDDEPS)
-encoding/asn1.lo: $(go_encoding_asn1_files)
- $(BUILDPACKAGE)
-encoding/asn1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/asn1/check
-
-@go_include@ encoding/ascii85.lo.dep
-encoding/ascii85.lo.dep: $(go_encoding_ascii85_files)
- $(BUILDDEPS)
-encoding/ascii85.lo: $(go_encoding_ascii85_files)
- $(BUILDPACKAGE)
-encoding/ascii85/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/ascii85/check
-
-@go_include@ encoding/base32.lo.dep
-encoding/base32.lo.dep: $(go_encoding_base32_files)
- $(BUILDDEPS)
-encoding/base32.lo: $(go_encoding_base32_files)
- $(BUILDPACKAGE)
-encoding/base32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base32/check
-
-@go_include@ encoding/base64.lo.dep
-encoding/base64.lo.dep: $(go_encoding_base64_files)
- $(BUILDDEPS)
-encoding/base64.lo: $(go_encoding_base64_files)
- $(BUILDPACKAGE)
-encoding/base64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base64/check
-
-@go_include@ encoding/binary.lo.dep
-encoding/binary.lo.dep: $(go_encoding_binary_files)
- $(BUILDDEPS)
-encoding/binary.lo: $(go_encoding_binary_files)
- $(BUILDPACKAGE)
-encoding/binary/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/binary/check
-
-@go_include@ encoding/csv.lo.dep
-encoding/csv.lo.dep: $(go_encoding_csv_files)
- $(BUILDDEPS)
-encoding/csv.lo: $(go_encoding_csv_files)
- $(BUILDPACKAGE)
-encoding/csv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/csv/check
-
-@go_include@ encoding/gob.lo.dep
-encoding/gob.lo.dep: $(go_encoding_gob_files)
- $(BUILDDEPS)
-encoding/gob.lo: $(go_encoding_gob_files)
- $(BUILDPACKAGE)
-encoding/gob/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/gob/check
-
-@go_include@ encoding/hex.lo.dep
-encoding/hex.lo.dep: $(go_encoding_hex_files)
- $(BUILDDEPS)
-encoding/hex.lo: $(go_encoding_hex_files)
- $(BUILDPACKAGE)
-encoding/hex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/hex/check
-
-@go_include@ encoding/json.lo.dep
-encoding/json.lo.dep: $(go_encoding_json_files)
- $(BUILDDEPS)
-encoding/json.lo: $(go_encoding_json_files)
- $(BUILDPACKAGE)
-encoding/json/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/json/check
-
-@go_include@ encoding/pem.lo.dep
-encoding/pem.lo.dep: $(go_encoding_pem_files)
- $(BUILDDEPS)
-encoding/pem.lo: $(go_encoding_pem_files)
- $(BUILDPACKAGE)
-encoding/pem/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/pem/check
-
-@go_include@ encoding/xml.lo.dep
-encoding/xml.lo.dep: $(go_encoding_xml_files)
- $(BUILDDEPS)
-encoding/xml.lo: $(go_encoding_xml_files)
- $(BUILDPACKAGE)
-encoding/xml/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/xml/check
-
-@go_include@ exp/proxy.lo.dep
-exp/proxy.lo.dep: $(go_exp_proxy_files)
- $(BUILDDEPS)
-exp/proxy.lo: $(go_exp_proxy_files)
- $(BUILDPACKAGE)
-exp/proxy/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/proxy/check
-
-@go_include@ exp/terminal.lo.dep
-exp/terminal.lo.dep: $(go_exp_terminal_files)
- $(BUILDDEPS)
-exp/terminal.lo: $(go_exp_terminal_files)
- $(BUILDPACKAGE)
-exp/terminal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/terminal/check
-
-@go_include@ html/template.lo.dep
-html/template.lo.dep: $(go_html_template_files)
- $(BUILDDEPS)
-html/template.lo: $(go_html_template_files)
- $(BUILDPACKAGE)
-html/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/template/check
-
-@go_include@ go/ast.lo.dep
-go/ast.lo.dep: $(go_go_ast_files)
- $(BUILDDEPS)
-go/ast.lo: $(go_go_ast_files)
- $(BUILDPACKAGE)
-go/ast/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/ast/check
-
-@go_include@ go/build.lo.dep
-go/build.lo.dep: $(go_go_build_files)
- $(BUILDDEPS)
-go/build.lo: $(go_go_build_files)
- $(BUILDPACKAGE)
-go/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/build/check
-
-@go_include@ go/constant.lo.dep
-go/constant.lo.dep: $(go_go_constant_files)
- $(BUILDDEPS)
-go/constant.lo: $(go_go_constant_files)
- $(BUILDPACKAGE)
-go/constant/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/constant/check
-
-@go_include@ go/doc.lo.dep
-go/doc.lo.dep: $(go_go_doc_files)
- $(BUILDDEPS)
-go/doc.lo: $(go_go_doc_files)
- $(BUILDPACKAGE)
-go/doc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/doc/check
-
-@go_include@ go/format.lo.dep
-go/format.lo.dep: $(go_go_format_files)
- $(BUILDDEPS)
-go/format.lo: $(go_go_format_files)
- $(BUILDPACKAGE)
-go/format/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/format/check
-
-@go_include@ go/importer.lo.dep
-go/importer.lo.dep: $(go_go_importer_files)
- $(BUILDDEPS)
-go/importer.lo: $(go_go_importer_files)
- $(BUILDPACKAGE)
-go/importer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/importer/check
-
-@go_include@ go/parser.lo.dep
-go/parser.lo.dep: $(go_go_parser_files)
- $(BUILDDEPS)
-go/parser.lo: $(go_go_parser_files)
- $(BUILDPACKAGE)
-go/parser/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/parser/check
-
-@go_include@ go/printer.lo.dep
-go/printer.lo.dep: $(go_go_printer_files)
- $(BUILDDEPS)
-go/printer.lo: $(go_go_printer_files)
- $(BUILDPACKAGE)
-go/printer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/printer/check
-
-@go_include@ go/scanner.lo.dep
-go/scanner.lo.dep: $(go_go_scanner_files)
- $(BUILDDEPS)
-go/scanner.lo: $(go_go_scanner_files)
- $(BUILDPACKAGE)
-go/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/scanner/check
-
-@go_include@ go/token.lo.dep
-go/token.lo.dep: $(go_go_token_files)
- $(BUILDDEPS)
-go/token.lo: $(go_go_token_files)
- $(BUILDPACKAGE)
-go/token/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/token/check
-
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(go_go_types_files)
- $(BUILDDEPS)
-go/types.lo: $(go_go_types_files)
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
-@go_include@ go/internal/gcimporter.lo.dep
-go/internal/gcimporter.lo.dep: $(go_go_internal_gcimporter_files)
- $(BUILDDEPS)
-go/internal/gcimporter.lo: $(go_go_internal_gcimporter_files)
- $(BUILDPACKAGE)
-go/internal/gcimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gcimporter/check
-
-@go_include@ go/internal/gccgoimporter.lo.dep
-go/internal/gccgoimporter.lo.dep: $(go_go_internal_gccgoimporter_files)
- $(BUILDDEPS)
-go/internal/gccgoimporter.lo: $(go_go_internal_gccgoimporter_files)
- $(BUILDPACKAGE)
-go/internal/gccgoimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gccgoimporter/check
-
-@go_include@ hash/adler32.lo.dep
-hash/adler32.lo.dep: $(go_hash_adler32_files)
- $(BUILDDEPS)
-hash/adler32.lo: $(go_hash_adler32_files)
- $(BUILDPACKAGE)
-hash/adler32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/adler32/check
-
-@go_include@ hash/crc32.lo.dep
-hash/crc32.lo.dep: $(go_hash_crc32_files)
- $(BUILDDEPS)
-hash/crc32.lo: $(go_hash_crc32_files)
- $(BUILDPACKAGE)
-hash/crc32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc32/check
-
-@go_include@ hash/crc64.lo.dep
-hash/crc64.lo.dep: $(go_hash_crc64_files)
- $(BUILDDEPS)
-hash/crc64.lo: $(go_hash_crc64_files)
- $(BUILDPACKAGE)
-hash/crc64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc64/check
-
-@go_include@ hash/fnv.lo.dep
-hash/fnv.lo.dep: $(go_hash_fnv_files)
- $(BUILDDEPS)
-hash/fnv.lo: $(go_hash_fnv_files)
- $(BUILDPACKAGE)
-hash/fnv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/fnv/check
-
-@go_include@ image/color.lo.dep
-image/color.lo.dep: $(go_image_color_files)
- $(BUILDDEPS)
-image/color.lo: $(go_image_color_files)
- $(BUILDPACKAGE)
-image/color/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/check
-
-@go_include@ image/color/palette.lo.dep
-image/color/palette.lo.dep: $(go_image_color_palette_files)
- $(BUILDDEPS)
-image/color/palette.lo: $(go_image_color_palette_files)
- $(BUILDPACKAGE)
-image/color/palette/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/palette/check
-
-@go_include@ image/draw.lo.dep
-image/draw.lo.dep: $(go_image_draw_files)
- $(BUILDDEPS)
-image/draw.lo: $(go_image_draw_files)
- $(BUILDPACKAGE)
-image/draw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/draw/check
-
-@go_include@ image/gif.lo.dep
-image/gif.lo.dep: $(go_image_gif_files)
- $(BUILDDEPS)
-image/gif.lo: $(go_image_gif_files)
- $(BUILDPACKAGE)
-image/gif/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/gif/check
-
-@go_include@ image/internal/imageutil.lo.dep
-image/internal/imageutil.lo.dep: $(go_image_internal_imageutil_files)
- $(BUILDDEPS)
-image/internal/imageutil.lo: $(go_image_internal_imageutil_files)
- $(BUILDPACKAGE)
-image/internal/imageutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/internal/imageutil/check
-
-@go_include@ image/jpeg.lo.dep
-image/jpeg.lo.dep: $(go_image_jpeg_files)
- $(BUILDDEPS)
-image/jpeg.lo: $(go_image_jpeg_files)
- $(BUILDPACKAGE)
-image/jpeg/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/jpeg/check
-
-@go_include@ image/png.lo.dep
-image/png.lo.dep: $(go_image_png_files)
- $(BUILDDEPS)
-image/png.lo: $(go_image_png_files)
- $(BUILDPACKAGE)
-image/png/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/png/check
-
-@go_include@ index/suffixarray.lo.dep
-index/suffixarray.lo.dep: $(go_index_suffixarray_files)
- $(BUILDDEPS)
-index/suffixarray.lo: $(go_index_suffixarray_files)
- $(BUILDPACKAGE)
-index/suffixarray/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: index/suffixarray/check
-
-@go_include@ internal/golang.org/x/net/http2/hpack.lo.dep
-internal/golang.org/x/net/http2/hpack.lo.dep: $(go_internal_golang_org_x_net_http2_hpack_files)
- $(BUILDDEPS)
-internal/golang.org/x/net/http2/hpack.lo: $(go_internal_golang_org_x_net_http2_hpack_files)
- $(BUILDPACKAGE)
-internal/golang.org/x/net/http2/hpack/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/golang.org/x/net/http2/hpack/check
-
-@go_include@ internal/race.lo.dep
-internal/race.lo.dep: $(go_internal_race_files)
- $(BUILDDEPS)
-internal/race.lo: $(go_internal_race_files)
- $(BUILDPACKAGE)
-internal/race/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/race/check
-
-@go_include@ internal/singleflight.lo.dep
-internal/singleflight.lo.dep: $(go_internal_singleflight_files)
- $(BUILDDEPS)
-internal/singleflight.lo: $(go_internal_singleflight_files)
- $(BUILDPACKAGE)
-internal/singleflight/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/singleflight/check
-
-@go_include@ internal/syscall/unix.lo.dep
-internal/syscall/unix.lo.dep: $(go_internal_syscall_unix_files)
- $(BUILDDEPS)
-internal/syscall/unix.lo: $(go_internal_syscall_unix_files)
- $(BUILDPACKAGE)
-internal/syscall/unix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/syscall/unix/check
-
-@go_include@ internal/testenv.lo.dep
-internal/testenv.lo.dep: $(go_internal_testenv_files)
- $(BUILDDEPS)
-internal/testenv.lo: $(go_internal_testenv_files)
- $(BUILDPACKAGE)
-internal/testenv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/testenv/check
-
-@go_include@ internal/trace.lo.dep
-internal/trace.lo.dep: $(go_internal_trace_files)
- $(BUILDDEPS)
-internal/trace.lo: $(go_internal_trace_files)
- $(BUILDPACKAGE)
-internal/trace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/trace/check
-
-@go_include@ io/ioutil.lo.dep
-io/ioutil.lo.dep: $(go_io_ioutil_files)
- $(BUILDDEPS)
-io/ioutil.lo: $(go_io_ioutil_files)
- $(BUILDPACKAGE)
-io/ioutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/ioutil/check
-
-@go_include@ log/syslog.lo.dep
-log/syslog.lo.dep: $(go_log_syslog_files)
- $(BUILDDEPS)
-log/syslog.lo: $(go_log_syslog_files)
- $(BUILDPACKAGE)
-log/syslog/syslog_c.lo: $(go_syslog_c_files) log/syslog.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/strings/indexbyte.c
+
+# Use a C function with a fixed number of arguments to call a C
+# varargs function.
+log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc
@$(MKDIR_P) log/syslog
$(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c
-log/syslog/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/syslog/check
-
-@go_include@ math/big.lo.dep
-math/big.lo.dep: $(go_math_big_files)
- $(BUILDDEPS)
-math/big.lo: $(go_math_big_files)
- $(BUILDPACKAGE)
-math/big/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/big/check
-
-@go_include@ math/cmplx.lo.dep
-math/cmplx.lo.dep: $(go_math_cmplx_files)
- $(BUILDDEPS)
-math/cmplx.lo: $(go_math_cmplx_files)
- $(BUILDPACKAGE)
-math/cmplx/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/cmplx/check
-
-@go_include@ math/rand.lo.dep
-math/rand.lo.dep: $(go_math_rand_files)
- $(BUILDDEPS)
-math/rand.lo: $(go_math_rand_files)
- $(BUILDPACKAGE)
-math/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/rand/check
-
-@go_include@ mime/multipart.lo.dep
-mime/multipart.lo.dep: $(go_mime_multipart_files)
- $(BUILDDEPS)
-mime/multipart.lo: $(go_mime_multipart_files)
- $(BUILDPACKAGE)
-mime/multipart/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/multipart/check
-
-@go_include@ mime/quotedprintable.lo.dep
-mime/quotedprintable.lo.dep: $(go_mime_quotedprintable_files)
- $(BUILDDEPS)
-mime/quotedprintable.lo: $(go_mime_quotedprintable_files)
- $(BUILDPACKAGE)
-mime/quotedprintable/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/quotedprintable/check
-
-@go_include@ net/http.lo.dep
-net/http.lo.dep: $(go_net_http_files)
- $(BUILDDEPS)
-net/http.lo: $(go_net_http_files)
- $(BUILDPACKAGE)
-net/http/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/check
-
-@go_include@ net/mail.lo.dep
-net/mail.lo.dep: $(go_net_mail_files)
- $(BUILDDEPS)
-net/mail.lo: $(go_net_mail_files)
- $(BUILDPACKAGE)
-net/mail/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/mail/check
-
-@go_include@ net/rpc.lo.dep
-net/rpc.lo.dep: $(go_net_rpc_files)
- $(BUILDDEPS)
-net/rpc.lo: $(go_net_rpc_files)
- $(BUILDPACKAGE)
-net/rpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/check
-
-@go_include@ net/smtp.lo.dep
-net/smtp.lo.dep: $(go_net_smtp_files)
- $(BUILDDEPS)
-net/smtp.lo: $(go_net_smtp_files)
- $(BUILDPACKAGE)
-net/smtp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/smtp/check
-
-@go_include@ net/url.lo.dep
-net/url.lo.dep: $(go_net_url_files)
- $(BUILDDEPS)
-net/url.lo: $(go_net_url_files)
- $(BUILDPACKAGE)
-net/url/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/url/check
-
-@go_include@ net/textproto.lo.dep
-net/textproto.lo.dep: $(go_net_textproto_files)
- $(BUILDDEPS)
-net/textproto.lo: $(go_net_textproto_files)
- $(BUILDPACKAGE)
-net/textproto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/textproto/check
-
-@go_include@ net/http/cgi.lo.dep
-net/http/cgi.lo.dep: $(go_net_http_cgi_files)
- $(BUILDDEPS)
-net/http/cgi.lo: $(go_net_http_cgi_files)
- $(BUILDPACKAGE)
-net/http/cgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cgi/check
-
-@go_include@ net/http/cookiejar.lo.dep
-net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
- $(BUILDDEPS)
-net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
- $(BUILDPACKAGE)
-net/http/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cookiejar/check
-
-@go_include@ net/http/fcgi.lo.dep
-net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
- $(BUILDDEPS)
-net/http/fcgi.lo: $(go_net_http_fcgi_files)
- $(BUILDPACKAGE)
-net/http/fcgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/fcgi/check
-
-@go_include@ net/http/httptest.lo.dep
-net/http/httptest.lo.dep: $(go_net_http_httptest_files)
- $(BUILDDEPS)
-net/http/httptest.lo: $(go_net_http_httptest_files)
- $(BUILDPACKAGE)
-net/http/httptest/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptest/check
-
-@go_include@ net/http/httputil.lo.dep
-net/http/httputil.lo.dep: $(go_net_http_httputil_files)
- $(BUILDDEPS)
-net/http/httputil.lo: $(go_net_http_httputil_files)
- $(BUILDPACKAGE)
-net/http/httputil/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httputil/check
-
-@go_include@ net/http/internal.lo.dep
-net/http/internal.lo.dep: $(go_net_http_internal_files)
- $(BUILDDEPS)
-net/http/internal.lo: $(go_net_http_internal_files)
- $(BUILDPACKAGE)
-net/http/internal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/internal/check
-
-@go_include@ net/http/pprof.lo.dep
-net/http/pprof.lo.dep: $(go_net_http_pprof_files)
- $(BUILDDEPS)
-net/http/pprof.lo: $(go_net_http_pprof_files)
- $(BUILDPACKAGE)
-net/http/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/pprof/check
-
-@go_include@ net/internal/socktest.lo.dep
-net/internal/socktest.lo.dep: $(go_net_internal_socktest_files)
- $(BUILDDEPS)
-net/internal/socktest.lo: $(go_net_internal_socktest_files)
- $(BUILDPACKAGE)
-net/internal/socktest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/internal/socktest/check
-
-@go_include@ net/rpc/jsonrpc.lo.dep
-net/rpc/jsonrpc.lo.dep: $(go_net_rpc_jsonrpc_files)
- $(BUILDDEPS)
-net/rpc/jsonrpc.lo: $(go_net_rpc_jsonrpc_files)
- $(BUILDPACKAGE)
-net/rpc/jsonrpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/jsonrpc/check
-
-@go_include@ old/regexp.lo.dep
-old/regexp.lo.dep: $(go_old_regexp_files)
- $(BUILDDEPS)
-old/regexp.lo: $(go_old_regexp_files)
- $(BUILDPACKAGE)
-old/regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/regexp/check
-
-@go_include@ old/template.lo.dep
-old/template.lo.dep: $(go_old_template_files)
- $(BUILDDEPS)
-old/template.lo: $(go_old_template_files)
- $(BUILDPACKAGE)
-old/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/template/check
-
-@go_include@ os/exec.lo.dep
-os/exec.lo.dep: $(go_os_exec_files)
- $(BUILDDEPS)
-os/exec.lo: $(go_os_exec_files)
- $(BUILDPACKAGE)
-os/exec/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/exec/check
-
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(go_os_signal_files)
- $(BUILDDEPS)
-os/signal.lo: $(go_os_signal_files)
- $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/signal/check
-
-@go_include@ os/user.lo.dep
-os/user.lo.dep: $(go_os_user_files)
- $(BUILDDEPS)
-os/user.lo: $(go_os_user_files)
- $(BUILDPACKAGE)
-os/user/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/user/check
-
-@go_include@ path/filepath.lo.dep
-path/filepath.lo.dep: $(go_path_filepath_files)
- $(BUILDDEPS)
-path/filepath.lo: $(go_path_filepath_files)
- $(BUILDPACKAGE)
-path/filepath/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/filepath/check
-
-@go_include@ regexp/syntax.lo.dep
-regexp/syntax.lo.dep: $(go_regexp_syntax_files)
- $(BUILDDEPS)
-regexp/syntax.lo: $(go_regexp_syntax_files)
- $(BUILDPACKAGE)
-regexp/syntax/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/syntax/check
-
-@go_include@ runtime/debug.lo.dep
-runtime/debug.lo.dep: $(go_runtime_debug_files)
- $(BUILDDEPS)
-runtime/debug.lo: $(go_runtime_debug_files)
- $(BUILDPACKAGE)
-runtime/debug/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/debug/check
-
-@go_include@ runtime/pprof.lo.dep
-runtime/pprof.lo.dep: $(go_runtime_pprof_files)
- $(BUILDDEPS)
-runtime/pprof.lo: $(go_runtime_pprof_files)
- $(BUILDPACKAGE)
-runtime/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/pprof/check
-
-@go_include@ sync/atomic.lo.dep
-sync/atomic.lo.dep: $(go_sync_atomic_files)
- $(BUILDDEPS)
-sync/atomic.lo: $(go_sync_atomic_files)
- $(BUILDPACKAGE)
-sync/atomic_c.lo: $(go_sync_atomic_c_files) sync/atomic.lo
+
+# The interface to libffi from the reflect package is written in C.
+reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
+ @$(MKDIR_P) reflect
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/reflect/makefunc_ffi_c.c
+
+# The atomic functions are written in C.
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) runtime/internal
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
+sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) sync
$(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c
-sync/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/atomic/check
-
-@go_include@ text/scanner.lo.dep
-text/scanner.lo.dep: $(go_text_scanner_files)
- $(BUILDDEPS)
-text/scanner.lo: $(go_text_scanner_files)
- $(BUILDPACKAGE)
-text/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/scanner/check
-
-@go_include@ text/tabwriter.lo.dep
-text/tabwriter.lo.dep: $(go_text_tabwriter_files)
- $(BUILDDEPS)
-text/tabwriter.lo: $(go_text_tabwriter_files)
- $(BUILDPACKAGE)
-text/tabwriter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/tabwriter/check
-
-@go_include@ text/template.lo.dep
-text/template.lo.dep: $(go_text_template_files)
- $(BUILDDEPS)
-text/template.lo: $(go_text_template_files)
- $(BUILDPACKAGE)
-text/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/check
-
-@go_include@ text/template/parse.lo.dep
-text/template/parse.lo.dep: $(go_text_template_parse_files)
- $(BUILDDEPS)
-text/template/parse.lo: $(go_text_template_parse_files)
- $(BUILDPACKAGE)
-text/template/parse/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/parse/check
-
-@go_include@ testing/iotest.lo.dep
-testing/iotest.lo.dep: $(go_testing_iotest_files)
- $(BUILDDEPS)
-testing/iotest.lo: $(go_testing_iotest_files)
- $(BUILDPACKAGE)
-testing/iotest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/iotest/check
-
-@go_include@ testing/quick.lo.dep
-testing/quick.lo.dep: $(go_testing_quick_files)
- $(BUILDDEPS)
-testing/quick.lo: $(go_testing_quick_files)
- $(BUILDPACKAGE)
-testing/quick/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/quick/check
-
-@go_include@ unicode/utf16.lo.dep
-unicode/utf16.lo.dep: $(go_unicode_utf16_files)
- $(BUILDDEPS)
-unicode/utf16.lo: $(go_unicode_utf16_files)
- $(BUILDPACKAGE)
-unicode/utf16/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf16/check
-
-@go_include@ unicode/utf8.lo.dep
-unicode/utf8.lo.dep: $(go_unicode_utf8_files)
- $(BUILDDEPS)
-unicode/utf8.lo: $(go_unicode_utf8_files)
- $(BUILDPACKAGE)
-unicode/utf8/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf8/check
-
-@go_include@ syscall.lo.dep
-syscall.lo.dep: $(go_syscall_files)
- $(BUILDDEPS)
-syscall.lo: $(go_syscall_files)
- $(BUILDPACKAGE)
-syscall/errno.lo: go/syscall/errno.c
+
+# A few syscall functions are written in C.
+syscall/clone_linux.lo: go/syscall/clone_linux.c runtime.inc
+ @$(MKDIR_P) syscall
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/clone_linux.c
+syscall/errno.lo: go/syscall/errno.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/signame.lo: go/syscall/signame.c
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/errno.c
+syscall/signame.lo: go/syscall/signame.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/wait.lo: go/syscall/wait.c
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/signame.c
+syscall/wait.lo: go/syscall/wait.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: syscall/check
-
-bufio.gox: bufio.lo
- $(BUILDGOX)
-bytes.gox: bytes.lo
- $(BUILDGOX)
-crypto.gox: crypto.lo
- $(BUILDGOX)
-encoding.gox: encoding.lo
- $(BUILDGOX)
-errors.gox: errors.lo
- $(BUILDGOX)
-expvar.gox: expvar.lo
- $(BUILDGOX)
-flag.gox: flag.lo
- $(BUILDGOX)
-fmt.gox: fmt.lo
- $(BUILDGOX)
-hash.gox: hash.lo
- $(BUILDGOX)
-html.gox: html.lo
- $(BUILDGOX)
-image.gox: image.lo
- $(BUILDGOX)
-io.gox: io.lo
- $(BUILDGOX)
-log.gox: log.lo
- $(BUILDGOX)
-math.gox: math.lo
- $(BUILDGOX)
-mime.gox: mime.lo
- $(BUILDGOX)
-net.gox: net.lo
- $(BUILDGOX)
-os.gox: os.lo
- $(BUILDGOX)
-path.gox: path.lo
- $(BUILDGOX)
-reflect.gox: reflect-go.lo
- $(BUILDGOX)
-regexp.gox: regexp.lo
- $(BUILDGOX)
-runtime.gox: runtime-go.lo
- $(BUILDGOX)
-sort.gox: sort.lo
- $(BUILDGOX)
-strconv.gox: strconv.lo
- $(BUILDGOX)
-strings.gox: strings.lo
- $(BUILDGOX)
-sync.gox: sync.lo
- $(BUILDGOX)
-syscall.gox: syscall.lo
- $(BUILDGOX)
-testing.gox: testing.lo
- $(BUILDGOX)
-time.gox: time-go.lo
- $(BUILDGOX)
-unicode.gox: unicode.lo
- $(BUILDGOX)
-
-archive/tar.gox: archive/tar.lo
- $(BUILDGOX)
-archive/zip.gox: archive/zip.lo
- $(BUILDGOX)
-
-compress/bzip2.gox: compress/bzip2.lo
- $(BUILDGOX)
-compress/flate.gox: compress/flate.lo
- $(BUILDGOX)
-compress/gzip.gox: compress/gzip.lo
- $(BUILDGOX)
-compress/lzw.gox: compress/lzw.lo
- $(BUILDGOX)
-compress/zlib.gox: compress/zlib.lo
- $(BUILDGOX)
-
-container/heap.gox: container/heap.lo
- $(BUILDGOX)
-container/list.gox: container/list.lo
- $(BUILDGOX)
-container/ring.gox: container/ring.lo
- $(BUILDGOX)
-
-crypto/aes.gox: crypto/aes.lo
- $(BUILDGOX)
-crypto/cipher.gox: crypto/cipher.lo
- $(BUILDGOX)
-crypto/des.gox: crypto/des.lo
- $(BUILDGOX)
-crypto/dsa.gox: crypto/dsa.lo
- $(BUILDGOX)
-crypto/ecdsa.gox: crypto/ecdsa.lo
- $(BUILDGOX)
-crypto/elliptic.gox: crypto/elliptic.lo
- $(BUILDGOX)
-crypto/hmac.gox: crypto/hmac.lo
- $(BUILDGOX)
-crypto/md5.gox: crypto/md5.lo
- $(BUILDGOX)
-crypto/rand.gox: crypto/rand.lo
- $(BUILDGOX)
-crypto/rc4.gox: crypto/rc4.lo
- $(BUILDGOX)
-crypto/rsa.gox: crypto/rsa.lo
- $(BUILDGOX)
-crypto/sha1.gox: crypto/sha1.lo
- $(BUILDGOX)
-crypto/sha256.gox: crypto/sha256.lo
- $(BUILDGOX)
-crypto/sha512.gox: crypto/sha512.lo
- $(BUILDGOX)
-crypto/subtle.gox: crypto/subtle.lo
- $(BUILDGOX)
-crypto/tls.gox: crypto/tls.lo
- $(BUILDGOX)
-crypto/x509.gox: crypto/x509.lo
- $(BUILDGOX)
-
-crypto/x509/pkix.gox: crypto/x509/pkix.lo
- $(BUILDGOX)
-
-database/sql.gox: database/sql.lo
- $(BUILDGOX)
-
-database/sql/driver.gox: database/sql/driver.lo
- $(BUILDGOX)
-
-debug/dwarf.gox: debug/dwarf.lo
- $(BUILDGOX)
-debug/elf.gox: debug/elf.lo
- $(BUILDGOX)
-debug/gosym.gox: debug/gosym.lo
- $(BUILDGOX)
-debug/macho.gox: debug/macho.lo
- $(BUILDGOX)
-debug/pe.gox: debug/pe.lo
- $(BUILDGOX)
-debug/plan9obj.gox: debug/plan9obj.lo
- $(BUILDGOX)
-
-encoding/ascii85.gox: encoding/ascii85.lo
- $(BUILDGOX)
-encoding/asn1.gox: encoding/asn1.lo
- $(BUILDGOX)
-encoding/base32.gox: encoding/base32.lo
- $(BUILDGOX)
-encoding/base64.gox: encoding/base64.lo
- $(BUILDGOX)
-encoding/binary.gox: encoding/binary.lo
- $(BUILDGOX)
-encoding/csv.gox: encoding/csv.lo
- $(BUILDGOX)
-encoding/gob.gox: encoding/gob.lo
- $(BUILDGOX)
-encoding/hex.gox: encoding/hex.lo
- $(BUILDGOX)
-encoding/json.gox: encoding/json.lo
- $(BUILDGOX)
-encoding/pem.gox: encoding/pem.lo
- $(BUILDGOX)
-encoding/xml.gox: encoding/xml.lo
- $(BUILDGOX)
-
-exp/proxy.gox: exp/proxy.lo
- $(BUILDGOX)
-exp/terminal.gox: exp/terminal.lo
- $(BUILDGOX)
-
-html/template.gox: html/template.lo
- $(BUILDGOX)
-
-go/ast.gox: go/ast.lo
- $(BUILDGOX)
-go/build.gox: go/build.lo
- $(BUILDGOX)
-go/constant.gox: go/constant.lo
- $(BUILDGOX)
-go/doc.gox: go/doc.lo
- $(BUILDGOX)
-go/format.gox: go/format.lo
- $(BUILDGOX)
-go/importer.gox: go/importer.lo
- $(BUILDGOX)
-go/parser.gox: go/parser.lo
- $(BUILDGOX)
-go/printer.gox: go/printer.lo
- $(BUILDGOX)
-go/scanner.gox: go/scanner.lo
- $(BUILDGOX)
-go/token.gox: go/token.lo
- $(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
-
-go/internal/gcimporter.gox: go/internal/gcimporter.lo
- $(BUILDGOX)
-go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo
- $(BUILDGOX)
-
-hash/adler32.gox: hash/adler32.lo
- $(BUILDGOX)
-hash/crc32.gox: hash/crc32.lo
- $(BUILDGOX)
-hash/crc64.gox: hash/crc64.lo
- $(BUILDGOX)
-hash/fnv.gox: hash/fnv.lo
- $(BUILDGOX)
-
-image/color.gox: image/color.lo
- $(BUILDGOX)
-image/draw.gox: image/draw.lo
- $(BUILDGOX)
-image/gif.gox: image/gif.lo
- $(BUILDGOX)
-image/internal/imageutil.gox: image/internal/imageutil.lo
- $(BUILDGOX)
-image/jpeg.gox: image/jpeg.lo
- $(BUILDGOX)
-image/png.gox: image/png.lo
- $(BUILDGOX)
-
-image/color/palette.gox: image/color/palette.lo
- $(BUILDGOX)
-
-index/suffixarray.gox: index/suffixarray.lo
- $(BUILDGOX)
-
-internal/golang.org/x/net/http2/hpack.gox: internal/golang.org/x/net/http2/hpack.lo
- $(BUILDGOX)
-internal/race.gox: internal/race.lo
- $(BUILDGOX)
-internal/singleflight.gox: internal/singleflight.lo
- $(BUILDGOX)
-internal/syscall/unix.gox: internal/syscall/unix.lo
- $(BUILDGOX)
-internal/testenv.gox: internal/testenv.lo
- $(BUILDGOX)
-internal/trace.gox: internal/trace.lo
- $(BUILDGOX)
-
-io/ioutil.gox: io/ioutil.lo
- $(BUILDGOX)
-
-log/syslog.gox: log/syslog.lo
- $(BUILDGOX)
-
-math/big.gox: math/big.lo
- $(BUILDGOX)
-math/cmplx.gox: math/cmplx.lo
- $(BUILDGOX)
-math/rand.gox: math/rand.lo
- $(BUILDGOX)
-
-mime/multipart.gox: mime/multipart.lo
- $(BUILDGOX)
-mime/quotedprintable.gox: mime/quotedprintable.lo
- $(BUILDGOX)
-
-net/http.gox: net/http.lo
- $(BUILDGOX)
-net/mail.gox: net/mail.lo
- $(BUILDGOX)
-net/rpc.gox: net/rpc.lo
- $(BUILDGOX)
-net/smtp.gox: net/smtp.lo
- $(BUILDGOX)
-net/textproto.gox: net/textproto.lo
- $(BUILDGOX)
-net/url.gox: net/url.lo
- $(BUILDGOX)
-
-net/http/cgi.gox: net/http/cgi.lo
- $(BUILDGOX)
-net/http/cookiejar.gox: net/http/cookiejar.lo
- $(BUILDGOX)
-net/http/fcgi.gox: net/http/fcgi.lo
- $(BUILDGOX)
-net/http/httptest.gox: net/http/httptest.lo
- $(BUILDGOX)
-net/http/httputil.gox: net/http/httputil.lo
- $(BUILDGOX)
-net/http/pprof.gox: net/http/pprof.lo
- $(BUILDGOX)
-
-net/http/internal.gox: net/http/internal.lo
- $(BUILDGOX)
-
-net/internal/socktest.gox: net/internal/socktest.lo
- $(BUILDGOX)
-
-net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
- $(BUILDGOX)
-
-old/regexp.gox: old/regexp.lo
- $(BUILDGOX)
-old/template.gox: old/template.lo
- $(BUILDGOX)
-
-os/exec.gox: os/exec.lo
- $(BUILDGOX)
-os/signal.gox: os/signal.lo
- $(BUILDGOX)
-os/user.gox: os/user.lo
- $(BUILDGOX)
-
-path/filepath.gox: path/filepath.lo
- $(BUILDGOX)
-
-regexp/syntax.gox: regexp/syntax.lo
- $(BUILDGOX)
-
-runtime/debug.gox: runtime/debug.lo
- $(BUILDGOX)
-runtime/pprof.gox: runtime/pprof.lo
- $(BUILDGOX)
-
-sync/atomic.gox: sync/atomic.lo
- $(BUILDGOX)
-
-text/scanner.gox: text/scanner.lo
- $(BUILDGOX)
-text/tabwriter.gox: text/tabwriter.lo
- $(BUILDGOX)
-text/template.gox: text/template.lo
- $(BUILDGOX)
-text/template/parse.gox: text/template/parse.lo
- $(BUILDGOX)
-
-testing/iotest.gox: testing/iotest.lo
- $(BUILDGOX)
-testing/quick.gox: testing/quick.lo
- $(BUILDGOX)
-
-unicode/utf16.gox: unicode/utf16.lo
- $(BUILDGOX)
-unicode/utf8.gox: unicode/utf8.lo
- $(BUILDGOX)
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
+
+# Build golang_org/x/net/route only on BSD systems.
+
+@LIBGO_IS_BSD_TRUE@$(eval $(call PACKAGE_template,golang_org/x/net/route))
+
+# Build golang_org/x/net/lif only on Solaris systems.
+
+@LIBGO_IS_SOLARIS_TRUE@$(eval $(call PACKAGE_template,golang_org/x/net/lif))
check: check-tail
check-recursive: check-head
diff --git a/libgo/VERSION b/libgo/VERSION
index e1bf218d1d..dce1d463ba 100644
--- a/libgo/VERSION
+++ b/libgo/VERSION
@@ -1 +1 @@
-go1.6.1 \ No newline at end of file
+go1.8.1
diff --git a/libgo/aclocal.m4 b/libgo/aclocal.m4
index aefbad20a0..07305fd701 100644
--- a/libgo/aclocal.m4
+++ b/libgo/aclocal.m4
@@ -989,6 +989,7 @@ AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([../config/depstand.m4])
+m4_include([../config/hwcaps.m4])
m4_include([../config/lead-dot.m4])
m4_include([../config/multi.m4])
m4_include([../config/override.m4])
diff --git a/libgo/config.h.in b/libgo/config.h.in
index 298b8d660e..a669ff7add 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -21,6 +21,9 @@
/* Define if your assembler supports unwind section type. */
#undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
+/* Define if your assembler supports AES instructions. */
+#undef HAVE_AS_X86_AES
+
/* Define if your assembler supports PC relative relocs. */
#undef HAVE_AS_X86_PCREL
@@ -186,6 +189,9 @@
/* Define to 1 if you have the `pipe2' function. */
#undef HAVE_PIPE2
+/* Define to 1 if you have the <port.h> header file. */
+#undef HAVE_PORT_H
+
/* Define to 1 if you have the `removexattr' function. */
#undef HAVE_REMOVEXATTR
@@ -195,6 +201,9 @@
/* Define to 1 if you have the <sched.h> header file. */
#undef HAVE_SCHED_H
+/* Define to 1 if you have the <semaphore.h> header file. */
+#undef HAVE_SEMAPHORE_H
+
/* Define to 1 if you have the `sem_timedwait' function. */
#undef HAVE_SEM_TIMEDWAIT
@@ -256,6 +265,9 @@
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
+/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H
+
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
diff --git a/libgo/configure b/libgo/configure
index a418a88531..f571d97aad 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -624,52 +624,28 @@ GO_SPLIT_STACK
USING_SPLIT_STACK_FALSE
USING_SPLIT_STACK_TRUE
SPLIT_STACK
+HWCAP_CFLAGS
OSCFLAGS
GO_SYSCALL_OS_ARCH_FILE
GO_SYSCALL_OS_FILE
GO_LIBCALL_OS_ARCH_FILE
GO_LIBCALL_OS_FILE
+ALLGOARCHFAMILY
+ALLGOARCH
+GOARCH_MINFRAMESIZE
+GOARCH_HUGEPAGESIZE
+GOARCH_INT64ALIGN
+GOARCH_PCQUANTUM
+GOARCH_PHYSPAGESIZE
+GOARCH_CACHELINESIZE
+GOARCH_BIGENDIAN
+GOARCH_FAMILY
GOARCH
-LIBGO_IS_X86_64_FALSE
-LIBGO_IS_X86_64_TRUE
-LIBGO_IS_SPARC64_FALSE
-LIBGO_IS_SPARC64_TRUE
-LIBGO_IS_SPARC_FALSE
-LIBGO_IS_SPARC_TRUE
-LIBGO_IS_S390X_FALSE
-LIBGO_IS_S390X_TRUE
-LIBGO_IS_S390_FALSE
-LIBGO_IS_S390_TRUE
-LIBGO_IS_PPC64LE_FALSE
-LIBGO_IS_PPC64LE_TRUE
-LIBGO_IS_PPC64_FALSE
-LIBGO_IS_PPC64_TRUE
-LIBGO_IS_PPC_FALSE
-LIBGO_IS_PPC_TRUE
-LIBGO_IS_MIPS64_FALSE
-LIBGO_IS_MIPS64_TRUE
-LIBGO_IS_MIPSO64_FALSE
-LIBGO_IS_MIPSO64_TRUE
-LIBGO_IS_MIPSN64_FALSE
-LIBGO_IS_MIPSN64_TRUE
-LIBGO_IS_MIPSN32_FALSE
-LIBGO_IS_MIPSN32_TRUE
-LIBGO_IS_MIPSO32_FALSE
-LIBGO_IS_MIPSO32_TRUE
-LIBGO_IS_MIPS_FALSE
-LIBGO_IS_MIPS_TRUE
-LIBGO_IS_M68K_FALSE
-LIBGO_IS_M68K_TRUE
-LIBGO_IS_ARM64_FALSE
-LIBGO_IS_ARM64_TRUE
-LIBGO_IS_ARM_FALSE
-LIBGO_IS_ARM_TRUE
-LIBGO_IS_ALPHA_FALSE
-LIBGO_IS_ALPHA_TRUE
-LIBGO_IS_386_FALSE
-LIBGO_IS_386_TRUE
USE_DEJAGNU
+ALLGOOS
GOOS
+LIBGO_IS_BSD_FALSE
+LIBGO_IS_BSD_TRUE
LIBGO_IS_SOLARIS_FALSE
LIBGO_IS_SOLARIS_TRUE
LIBGO_IS_RTEMS_FALSE
@@ -690,6 +666,8 @@ LIBGO_IS_DARWIN_FALSE
LIBGO_IS_DARWIN_TRUE
go_include
LIBATOMIC
+USE_LIBFFI_FALSE
+USE_LIBFFI_TRUE
LIBFFIINCS
LIBFFI
nover_glibgo_toolexeclibdir
@@ -2514,7 +2492,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers config.h"
-libtool_VERSION=9:0:0
+libtool_VERSION=11:0:0
# Default to --enable-multilib
@@ -11126,7 +11104,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11129 "configure"
+#line 11107 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11232,7 +11210,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11235 "configure"
+#line 11213 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13494,6 +13472,14 @@ $as_echo "#define USE_LIBFFI 1" >>confdefs.h
fi
+ if test "$with_liffi" != "no"; then
+ USE_LIBFFI_TRUE=
+ USE_LIBFFI_FALSE='#'
+else
+ USE_LIBFFI_TRUE='#'
+ USE_LIBFFI_FALSE=
+fi
+
# See if the user wants to configure without libatomic. This is useful if we are
# on an architecture for which libgo does not need an atomic support library and
@@ -13518,6 +13504,11 @@ fi
go_include="-include"
+# All known GOOS values. This is the union of all operating systems
+# supported by the gofrontend and all operating systems supported by
+# the gc toolchain.
+ALLGOOS="android darwin dragonfly freebsd irix linux netbsd openbsd plan9 rtems solaris windows"
+
is_darwin=no
is_freebsd=no
is_irix=no
@@ -13611,6 +13602,15 @@ else
LIBGO_IS_SOLARIS_FALSE=
fi
+ if test $is_darwin = yes -o $is_dragonfly = yes -o $is_freebsd = yes -o $is_netbsd = yes -o $is_openbsd = yes; then
+ LIBGO_IS_BSD_TRUE=
+ LIBGO_IS_BSD_FALSE='#'
+else
+ LIBGO_IS_BSD_TRUE='#'
+ LIBGO_IS_BSD_FALSE=
+fi
+
+
USE_DEJAGNU=no
@@ -13621,33 +13621,45 @@ case ${host} in
esac
-is_386=no
-is_alpha=no
-is_arm=no
-is_arm64=no
-is_m68k=no
-mips_abi=unknown
-is_ppc=no
-is_ppc64=no
-is_ppc64le=no
-is_s390=no
-is_s390x=no
-is_sparc=no
-is_sparc64=no
-is_x86_64=no
+# All known GOARCH values. This is the union of all architectures
+# supported by the gofrontend and all architectures supported by the
+# gc toolchain.
+# N.B. Keep in sync with gcc/testsuite/go.test/go-test.exp (go-set-goarch).
+ALLGOARCH="386 alpha amd64 amd64p32 arm armbe arm64 arm64be ia64 m68k mipso32 mipsn32 mipso64 mipsn64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc ppc64 ppc64le s390 s390x sparc sparc64"
+
+# All known GOARCH_FAMILY values.
+ALLGOARCHFAMILY="I386 ALPHA AMD64 ARM ARM64 IA64 M68K MIPS MIPS64 PPC PPC64 S390 S390X SPARC SPARC64"
+
GOARCH=unknown
+GOARCH_FAMILY=unknown
+GOARCH_BIGENDIAN=0
+GOARCH_CACHELINESIZE=64
+GOARCH_PHYSPAGESIZE=4096
+GOARCH_PCQUANTUM=1
+GOARCH_INT64ALIGN=8
+GOARCH_HUGEPAGESIZE=0
+GOARCH_MINFRAMESIZE=0
case ${host} in
alpha*-*-*)
- is_alpha=yes
GOARCH=alpha
+ GOARCH_FAMILY=ALPHA
+ GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PCQUANTUM=4
;;
aarch64-*-*)
- is_arm64=yes
GOARCH=arm64
+ GOARCH_FAMILY=ARM64
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PHYSPAGESIZE=65536
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=8
;;
arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
- is_arm=yes
GOARCH=arm
+ GOARCH_FAMILY=ARM
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=4
;;
i[34567]86-*-* | x86_64-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13658,20 +13670,32 @@ case ${host} in
#endif
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- is_386=yes
+ GOARCH=386
+GOARCH_FAMILY=I386
+GOARCH_INT64ALIGN=4
+GOARCH_HUGEPAGESIZE="1 << 21"
+
else
- is_x86_64=yes
+ GOARCH=amd64
+GOARCH_FAMILY=AMD64
+GOARCH_HUGEPAGESIZE="1 << 21"
+
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- if test "$is_386" = "yes"; then
- GOARCH=386
- else
- GOARCH=amd64
- fi
+ ;;
+ ia64-*-*)
+ GOARCH=ia64
+ GOARCH_FAMILY=IA64
+ GOARCH_CACHELINESIZE=16384
+ GOARCH_PHYSPAGESIZE=65536
;;
m68k*-*-*)
- is_m68k=yes
GOARCH=m68k
+ GOARCH_FAMILY=M68K
+ GOARCH_BIGENDIAN=1
+ GOARCH_CACHELINESIZE=16
+ GOARCH_PCQUANTUM=4
+ GOARCH_INT64ALIGN=2
;;
mips*-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13730,6 +13754,26 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
"n64") GOARCH=mipsn64 ;;
"o64") GOARCH=mipso64 ;;
esac
+ case "$mips_abi" in
+ "o32" | "n32")
+ GOARCH_FAMILY=MIPS
+ GOARCH_MINFRAMESIZE=4
+ ;;
+ "n64" | "o64")
+ GOARCH_FAMILY=MIPS64
+ GOARCH_MINFRAMESIZE=8
+ ;;
+ esac
+ case "${host}" in
+ mips*el)
+ ;;
+ *)
+ GOARCH_BIGENDIAN=1
+ ;;
+ esac
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PHYSPAGESIZE=16384
+ GOARCH_PCQUANTUM=4
;;
rs6000*-*-* | powerpc*-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13740,9 +13784,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
#endif
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- is_ppc=yes
+ GOARCH=ppc
+GOARCH_FAMILY=PPC
+GOARCH_BIGENDIAN=1
+
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+GOARCH_FAMILY=PPC64
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
@@ -13750,20 +13799,19 @@ else
#endif
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- is_ppc64le=yes
+ GOARCH=ppc64le
+
else
- is_ppc64=yes
+ GOARCH=ppc64
+GOARCH_BIGENDIAN=1
+
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- if test "$is_ppc" = "yes"; then
- GOARCH=ppc
- elif test "$is_ppc64" = "yes"; then
- GOARCH=ppc64
- else
- GOARCH=ppc64le
- fi
+ GOARCH_PHYSPAGESIZE=65536
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=32
;;
s390*-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13774,16 +13822,20 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
#endif
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- is_s390=yes
+ GOARCH=s390
+GOARCH_FAMILY=S390
+GOARCH_MINFRAMESIZE=4
+
else
- is_s390x=yes
+ GOARCH=s390x
+GOARCH_FAMILY=S390X
+GOARCH_MINFRAMESIZE=8
+
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- if test "$is_s390" = "yes"; then
- GOARCH=s390
- else
- GOARCH=s390x
- fi
+ GOARCH_BIGENDIAN=1
+ GOARCH_CACHELINESIZE=256
+ GOARCH_PCQUANTUM=2
;;
sparc*-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13794,169 +13846,29 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
#endif
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- is_sparc=yes
+ GOARCH=sparc
+GOARCH_FAMILY=SPARC
+
else
- is_sparc64=yes
+ GOARCH=sparc64
+GOARCH_FAMILY=SPARC64
+
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- if test "$is_sparc" = "yes"; then
- GOARCH=sparc
- else
- GOARCH=sparc64
- fi
+ GOARCH_BIGENDIAN=1
+ GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PCQUANTUM=4
;;
esac
- if test $is_386 = yes; then
- LIBGO_IS_386_TRUE=
- LIBGO_IS_386_FALSE='#'
-else
- LIBGO_IS_386_TRUE='#'
- LIBGO_IS_386_FALSE=
-fi
- if test $is_alpha = yes; then
- LIBGO_IS_ALPHA_TRUE=
- LIBGO_IS_ALPHA_FALSE='#'
-else
- LIBGO_IS_ALPHA_TRUE='#'
- LIBGO_IS_ALPHA_FALSE=
-fi
- if test $is_arm = yes; then
- LIBGO_IS_ARM_TRUE=
- LIBGO_IS_ARM_FALSE='#'
-else
- LIBGO_IS_ARM_TRUE='#'
- LIBGO_IS_ARM_FALSE=
-fi
- if test $is_arm64 = yes; then
- LIBGO_IS_ARM64_TRUE=
- LIBGO_IS_ARM64_FALSE='#'
-else
- LIBGO_IS_ARM64_TRUE='#'
- LIBGO_IS_ARM64_FALSE=
-fi
- if test $is_m68k = yes; then
- LIBGO_IS_M68K_TRUE=
- LIBGO_IS_M68K_FALSE='#'
-else
- LIBGO_IS_M68K_TRUE='#'
- LIBGO_IS_M68K_FALSE=
-fi
- if test $mips_abi != unknown; then
- LIBGO_IS_MIPS_TRUE=
- LIBGO_IS_MIPS_FALSE='#'
-else
- LIBGO_IS_MIPS_TRUE='#'
- LIBGO_IS_MIPS_FALSE=
-fi
- if test $mips_abi = o32; then
- LIBGO_IS_MIPSO32_TRUE=
- LIBGO_IS_MIPSO32_FALSE='#'
-else
- LIBGO_IS_MIPSO32_TRUE='#'
- LIBGO_IS_MIPSO32_FALSE=
-fi
-
- if test $mips_abi = n32; then
- LIBGO_IS_MIPSN32_TRUE=
- LIBGO_IS_MIPSN32_FALSE='#'
-else
- LIBGO_IS_MIPSN32_TRUE='#'
- LIBGO_IS_MIPSN32_FALSE=
-fi
-
- if test $mips_abi = n64; then
- LIBGO_IS_MIPSN64_TRUE=
- LIBGO_IS_MIPSN64_FALSE='#'
-else
- LIBGO_IS_MIPSN64_TRUE='#'
- LIBGO_IS_MIPSN64_FALSE=
-fi
-
- if test $mips_abi = o64; then
- LIBGO_IS_MIPSO64_TRUE=
- LIBGO_IS_MIPSO64_FALSE='#'
-else
- LIBGO_IS_MIPSO64_TRUE='#'
- LIBGO_IS_MIPSO64_FALSE=
-fi
- if test $mips_abi = n64 -o $mips_abi = o64; then
- LIBGO_IS_MIPS64_TRUE=
- LIBGO_IS_MIPS64_FALSE='#'
-else
- LIBGO_IS_MIPS64_TRUE='#'
- LIBGO_IS_MIPS64_FALSE=
-fi
-
- if test $is_ppc = yes; then
- LIBGO_IS_PPC_TRUE=
- LIBGO_IS_PPC_FALSE='#'
-else
- LIBGO_IS_PPC_TRUE='#'
- LIBGO_IS_PPC_FALSE=
-fi
-
- if test $is_ppc64 = yes; then
- LIBGO_IS_PPC64_TRUE=
- LIBGO_IS_PPC64_FALSE='#'
-else
- LIBGO_IS_PPC64_TRUE='#'
- LIBGO_IS_PPC64_FALSE=
-fi
-
- if test $is_ppc64le = yes; then
- LIBGO_IS_PPC64LE_TRUE=
- LIBGO_IS_PPC64LE_FALSE='#'
-else
- LIBGO_IS_PPC64LE_TRUE='#'
- LIBGO_IS_PPC64LE_FALSE=
-fi
-
- if test $is_s390 = yes; then
- LIBGO_IS_S390_TRUE=
- LIBGO_IS_S390_FALSE='#'
-else
- LIBGO_IS_S390_TRUE='#'
- LIBGO_IS_S390_FALSE=
-fi
-
- if test $is_s390x = yes; then
- LIBGO_IS_S390X_TRUE=
- LIBGO_IS_S390X_FALSE='#'
-else
- LIBGO_IS_S390X_TRUE='#'
- LIBGO_IS_S390X_FALSE=
-fi
-
- if test $is_sparc = yes; then
- LIBGO_IS_SPARC_TRUE=
- LIBGO_IS_SPARC_FALSE='#'
-else
- LIBGO_IS_SPARC_TRUE='#'
- LIBGO_IS_SPARC_FALSE=
-fi
- if test $is_sparc64 = yes; then
- LIBGO_IS_SPARC64_TRUE=
- LIBGO_IS_SPARC64_FALSE='#'
-else
- LIBGO_IS_SPARC64_TRUE='#'
- LIBGO_IS_SPARC64_FALSE=
-fi
- if test $is_x86_64 = yes; then
- LIBGO_IS_X86_64_TRUE=
- LIBGO_IS_X86_64_FALSE='#'
-else
- LIBGO_IS_X86_64_TRUE='#'
- LIBGO_IS_X86_64_FALSE=
-fi
@@ -13997,6 +13909,48 @@ case "$target" in
esac
+
+ test -z "$HWCAP_CFLAGS" && HWCAP_CFLAGS=''
+
+ # Restrict the test to Solaris, other assemblers (e.g. AIX as) have -nH
+ # with a different meaning.
+ case ${target_os} in
+ solaris2*)
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Wa,-nH"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for as that supports -Wa,-nH" >&5
+$as_echo_n "checking for as that supports -Wa,-nH... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hwcap_flags=yes
+else
+ ac_hwcap_flags=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$ac_hwcap_flags" = "yes"; then
+ HWCAP_CFLAGS="-Wa,-nH $HWCAP_CFLAGS"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_hwcap_flags" >&5
+$as_echo "$ac_hwcap_flags" >&6; }
+
+ CFLAGS="$ac_save_CFLAGS"
+ ;;
+ esac
+
+
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fsplit-stack is supported" >&5
$as_echo_n "checking whether -fsplit-stack is supported... " >&6; }
if test "${libgo_cv_c_split_stack_supported+set}" = set; then :
@@ -14031,9 +13985,9 @@ EOF
cat > conftest2.c << EOF
void f() {}
EOF
-$CC -c -fsplit-stack $CFLAGS $CPPFLAGS conftest1.c
-$CC -c $CFLAGS $CPPFLAGS conftest2.c
-if $CC -o conftest conftest1.$ac_objext conftest2.$ac_objext; then
+$CC -c -fsplit-stack $CFLAGS $CPPFLAGS conftest1.c >/dev/null 2>&1
+$CC -c $CFLAGS $CPPFLAGS conftest2.c > /dev/null 2>&1
+if $CC -o conftest conftest1.$ac_objext conftest2.$ac_objext > /dev/null 2>&1; then
libgo_cv_c_linker_split_non_split=yes
else
libgo_cv_c_linker_split_non_split=no
@@ -14808,7 +14762,7 @@ $as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
fi
-for ac_header in sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h
+for ac_header in port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -15529,6 +15483,32 @@ $as_echo "#define HAVE_AS_X86_64_UNWIND_SECTION_TYPE 1" >>confdefs.h
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler supports AES instructions" >&5
+$as_echo_n "checking assembler supports AES instructions... " >&6; }
+if test "${libgo_cv_as_x86_aes+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+libgo_cv_as_x86_aes=yes
+echo 'aesenc %xmm0, %xmm1' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
+if $CC $CFLAGS -c conftest.s 2>&1 | grep -i error > /dev/null; then
+ libgo_cv_as_x86_aes=no
+fi
+CFLAGS=$CFLAGS_hold
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_as_x86_aes" >&5
+$as_echo "$libgo_cv_as_x86_aes" >&6; }
+if test "x$libgo_cv_as_x86_aes" = xyes; then
+
+$as_echo "#define HAVE_AS_X86_AES 1" >>confdefs.h
+
+fi
+
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -15733,6 +15713,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
as_fn_error "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${USE_LIBFFI_TRUE}" && test -z "${USE_LIBFFI_FALSE}"; then
+ as_fn_error "conditional \"USE_LIBFFI\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${LIBGO_IS_DARWIN_TRUE}" && test -z "${LIBGO_IS_DARWIN_FALSE}"; then
as_fn_error "conditional \"LIBGO_IS_DARWIN\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -15769,80 +15753,8 @@ if test -z "${LIBGO_IS_SOLARIS_TRUE}" && test -z "${LIBGO_IS_SOLARIS_FALSE}"; th
as_fn_error "conditional \"LIBGO_IS_SOLARIS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
-if test -z "${LIBGO_IS_386_TRUE}" && test -z "${LIBGO_IS_386_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_386\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_ALPHA_TRUE}" && test -z "${LIBGO_IS_ALPHA_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_ALPHA\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_ARM_TRUE}" && test -z "${LIBGO_IS_ARM_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_ARM\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_ARM64_TRUE}" && test -z "${LIBGO_IS_ARM64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_ARM64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_M68K_TRUE}" && test -z "${LIBGO_IS_M68K_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_M68K\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPS_TRUE}" && test -z "${LIBGO_IS_MIPS_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPS\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPSO32_TRUE}" && test -z "${LIBGO_IS_MIPSO32_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPSO32\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPSN32_TRUE}" && test -z "${LIBGO_IS_MIPSN32_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPSN32\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPSN64_TRUE}" && test -z "${LIBGO_IS_MIPSN64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPSN64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPSO64_TRUE}" && test -z "${LIBGO_IS_MIPSO64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPSO64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_MIPS64_TRUE}" && test -z "${LIBGO_IS_MIPS64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_MIPS64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_PPC_TRUE}" && test -z "${LIBGO_IS_PPC_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_PPC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_PPC64_TRUE}" && test -z "${LIBGO_IS_PPC64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_PPC64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_PPC64LE_TRUE}" && test -z "${LIBGO_IS_PPC64LE_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_PPC64LE\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_S390_TRUE}" && test -z "${LIBGO_IS_S390_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_S390\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_S390X_TRUE}" && test -z "${LIBGO_IS_S390X_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_S390X\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_SPARC_TRUE}" && test -z "${LIBGO_IS_SPARC_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_SPARC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_SPARC64_TRUE}" && test -z "${LIBGO_IS_SPARC64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_SPARC64\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${LIBGO_IS_X86_64_TRUE}" && test -z "${LIBGO_IS_X86_64_FALSE}"; then
- as_fn_error "conditional \"LIBGO_IS_X86_64\" was never defined.
+if test -z "${LIBGO_IS_BSD_TRUE}" && test -z "${LIBGO_IS_BSD_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_BSD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${USING_SPLIT_STACK_TRUE}" && test -z "${USING_SPLIT_STACK_FALSE}"; then
@@ -16466,7 +16378,6 @@ CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
CC="$CC"
CXX="$CXX"
GFORTRAN="$GFORTRAN"
-GCJ="$GCJ"
AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
diff --git a/libgo/configure.ac b/libgo/configure.ac
index a86bcb8231..7c49d5514e 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, libgo)
AC_CONFIG_SRCDIR(Makefile.am)
AC_CONFIG_HEADER(config.h)
-libtool_VERSION=9:0:0
+libtool_VERSION=11:0:0
AC_SUBST(libtool_VERSION)
AM_ENABLE_MULTILIB(, ..)
@@ -121,6 +121,7 @@ if test "$with_libffi" != no; then
fi
AC_SUBST(LIBFFI)
AC_SUBST(LIBFFIINCS)
+AM_CONDITIONAL(USE_LIBFFI, test "$with_liffi" != "no")
# See if the user wants to configure without libatomic. This is useful if we are
# on an architecture for which libgo does not need an atomic support library and
@@ -142,6 +143,11 @@ AC_SUBST(LIBATOMIC)
go_include="-include"
AC_SUBST(go_include)
+# All known GOOS values. This is the union of all operating systems
+# supported by the gofrontend and all operating systems supported by
+# the gc toolchain.
+ALLGOOS="android darwin dragonfly freebsd irix linux netbsd openbsd plan9 rtems solaris windows"
+
is_darwin=no
is_freebsd=no
is_irix=no
@@ -172,7 +178,9 @@ AM_CONDITIONAL(LIBGO_IS_OPENBSD, test $is_openbsd = yes)
AM_CONDITIONAL(LIBGO_IS_DRAGONFLY, test $is_dragonfly = yes)
AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
AM_CONDITIONAL(LIBGO_IS_SOLARIS, test $is_solaris = yes)
+AM_CONDITIONAL(LIBGO_IS_BSD, test $is_darwin = yes -o $is_dragonfly = yes -o $is_freebsd = yes -o $is_netbsd = yes -o $is_openbsd = yes)
AC_SUBST(GOOS)
+AC_SUBST(ALLGOOS)
dnl Test whether we need to use DejaGNU or whether we can use the
dnl simpler gotest approach. We can only use gotest for a native
@@ -185,34 +193,45 @@ case ${host} in
esac
AC_SUBST(USE_DEJAGNU)
-dnl N.B. Keep in sync with gcc/testsuite/go.test/go-test.exp (go-set-goarch).
-is_386=no
-is_alpha=no
-is_arm=no
-is_arm64=no
-is_m68k=no
-mips_abi=unknown
-is_ppc=no
-is_ppc64=no
-is_ppc64le=no
-is_s390=no
-is_s390x=no
-is_sparc=no
-is_sparc64=no
-is_x86_64=no
+# All known GOARCH values. This is the union of all architectures
+# supported by the gofrontend and all architectures supported by the
+# gc toolchain.
+# N.B. Keep in sync with gcc/testsuite/go.test/go-test.exp (go-set-goarch).
+ALLGOARCH="386 alpha amd64 amd64p32 arm armbe arm64 arm64be ia64 m68k mipso32 mipsn32 mipso64 mipsn64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc ppc64 ppc64le s390 s390x sparc sparc64"
+
+# All known GOARCH_FAMILY values.
+ALLGOARCHFAMILY="I386 ALPHA AMD64 ARM ARM64 IA64 M68K MIPS MIPS64 PPC PPC64 S390 S390X SPARC SPARC64"
+
GOARCH=unknown
+GOARCH_FAMILY=unknown
+GOARCH_BIGENDIAN=0
+GOARCH_CACHELINESIZE=64
+GOARCH_PHYSPAGESIZE=4096
+GOARCH_PCQUANTUM=1
+GOARCH_INT64ALIGN=8
+GOARCH_HUGEPAGESIZE=0
+GOARCH_MINFRAMESIZE=0
case ${host} in
alpha*-*-*)
- is_alpha=yes
GOARCH=alpha
+ GOARCH_FAMILY=ALPHA
+ GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PCQUANTUM=4
;;
aarch64-*-*)
- is_arm64=yes
GOARCH=arm64
+ GOARCH_FAMILY=ARM64
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PHYSPAGESIZE=65536
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=8
;;
arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
- is_arm=yes
GOARCH=arm
+ GOARCH_FAMILY=ARM
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=4
;;
changequote(,)dnl
i[34567]86-*-* | x86_64-*-*)
@@ -221,16 +240,29 @@ changequote([,])dnl
#ifdef __x86_64__
#error 64-bit
#endif],
-[is_386=yes], [is_x86_64=yes])
- if test "$is_386" = "yes"; then
- GOARCH=386
- else
- GOARCH=amd64
- fi
+[GOARCH=386
+GOARCH_FAMILY=I386
+GOARCH_INT64ALIGN=4
+GOARCH_HUGEPAGESIZE="1 << 21"
+],
+[GOARCH=amd64
+GOARCH_FAMILY=AMD64
+GOARCH_HUGEPAGESIZE="1 << 21"
+])
+ ;;
+ ia64-*-*)
+ GOARCH=ia64
+ GOARCH_FAMILY=IA64
+ GOARCH_CACHELINESIZE=16384
+ GOARCH_PHYSPAGESIZE=65536
;;
m68k*-*-*)
- is_m68k=yes
GOARCH=m68k
+ GOARCH_FAMILY=M68K
+ GOARCH_BIGENDIAN=1
+ GOARCH_CACHELINESIZE=16
+ GOARCH_PCQUANTUM=4
+ GOARCH_INT64ALIGN=2
;;
mips*-*-*)
AC_COMPILE_IFELSE([
@@ -261,71 +293,94 @@ changequote([,])dnl
"n64") GOARCH=mipsn64 ;;
"o64") GOARCH=mipso64 ;;
esac
+ case "$mips_abi" in
+ "o32" | "n32")
+ GOARCH_FAMILY=MIPS
+ GOARCH_MINFRAMESIZE=4
+ ;;
+ "n64" | "o64")
+ GOARCH_FAMILY=MIPS64
+ GOARCH_MINFRAMESIZE=8
+ ;;
+ esac
+ case "${host}" in
+ mips*el)
+ ;;
+ *)
+ GOARCH_BIGENDIAN=1
+ ;;
+ esac
+ GOARCH_CACHELINESIZE=32
+ GOARCH_PHYSPAGESIZE=16384
+ GOARCH_PCQUANTUM=4
;;
rs6000*-*-* | powerpc*-*-*)
AC_COMPILE_IFELSE([
#ifdef _ARCH_PPC64
#error 64-bit
#endif],
-[is_ppc=yes],
- [AC_COMPILE_IFELSE([
+[GOARCH=ppc
+GOARCH_FAMILY=PPC
+GOARCH_BIGENDIAN=1
+],
+ [
+GOARCH_FAMILY=PPC64
+AC_COMPILE_IFELSE([
#if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
#error 64be
#endif],
-[is_ppc64le=yes],[is_ppc64=yes])])
- if test "$is_ppc" = "yes"; then
- GOARCH=ppc
- elif test "$is_ppc64" = "yes"; then
- GOARCH=ppc64
- else
- GOARCH=ppc64le
- fi
+[GOARCH=ppc64le
+],
+[GOARCH=ppc64
+GOARCH_BIGENDIAN=1
+])])
+ GOARCH_PHYSPAGESIZE=65536
+ GOARCH_PCQUANTUM=4
+ GOARCH_MINFRAMESIZE=32
;;
s390*-*-*)
AC_COMPILE_IFELSE([
#if defined(__s390x__)
#error 64-bit
#endif],
-[is_s390=yes], [is_s390x=yes])
- if test "$is_s390" = "yes"; then
- GOARCH=s390
- else
- GOARCH=s390x
- fi
+[GOARCH=s390
+GOARCH_FAMILY=S390
+GOARCH_MINFRAMESIZE=4
+], [GOARCH=s390x
+GOARCH_FAMILY=S390X
+GOARCH_MINFRAMESIZE=8
+])
+ GOARCH_BIGENDIAN=1
+ GOARCH_CACHELINESIZE=256
+ GOARCH_PCQUANTUM=2
;;
sparc*-*-*)
AC_COMPILE_IFELSE([
#if defined(__sparcv9) || defined(__arch64__)
#error 64-bit
#endif],
-[is_sparc=yes], [is_sparc64=yes])
- if test "$is_sparc" = "yes"; then
- GOARCH=sparc
- else
- GOARCH=sparc64
- fi
+[GOARCH=sparc
+GOARCH_FAMILY=SPARC
+],
+[GOARCH=sparc64
+GOARCH_FAMILY=SPARC64
+])
+ GOARCH_BIGENDIAN=1
+ GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PCQUANTUM=4
;;
esac
-AM_CONDITIONAL(LIBGO_IS_386, test $is_386 = yes)
-AM_CONDITIONAL(LIBGO_IS_ALPHA, test $is_alpha = yes)
-AM_CONDITIONAL(LIBGO_IS_ARM, test $is_arm = yes)
-AM_CONDITIONAL(LIBGO_IS_ARM64, test $is_arm64 = yes)
-AM_CONDITIONAL(LIBGO_IS_M68K, test $is_m68k = yes)
-AM_CONDITIONAL(LIBGO_IS_MIPS, test $mips_abi != unknown)
-AM_CONDITIONAL(LIBGO_IS_MIPSO32, test $mips_abi = o32)
-AM_CONDITIONAL(LIBGO_IS_MIPSN32, test $mips_abi = n32)
-AM_CONDITIONAL(LIBGO_IS_MIPSN64, test $mips_abi = n64)
-AM_CONDITIONAL(LIBGO_IS_MIPSO64, test $mips_abi = o64)
-AM_CONDITIONAL(LIBGO_IS_MIPS64, test $mips_abi = n64 -o $mips_abi = o64)
-AM_CONDITIONAL(LIBGO_IS_PPC, test $is_ppc = yes)
-AM_CONDITIONAL(LIBGO_IS_PPC64, test $is_ppc64 = yes)
-AM_CONDITIONAL(LIBGO_IS_PPC64LE, test $is_ppc64le = yes)
-AM_CONDITIONAL(LIBGO_IS_S390, test $is_s390 = yes)
-AM_CONDITIONAL(LIBGO_IS_S390X, test $is_s390x = yes)
-AM_CONDITIONAL(LIBGO_IS_SPARC, test $is_sparc = yes)
-AM_CONDITIONAL(LIBGO_IS_SPARC64, test $is_sparc64 = yes)
-AM_CONDITIONAL(LIBGO_IS_X86_64, test $is_x86_64 = yes)
AC_SUBST(GOARCH)
+AC_SUBST(GOARCH_FAMILY)
+AC_SUBST(GOARCH_BIGENDIAN)
+AC_SUBST(GOARCH_CACHELINESIZE)
+AC_SUBST(GOARCH_PHYSPAGESIZE)
+AC_SUBST(GOARCH_PCQUANTUM)
+AC_SUBST(GOARCH_INT64ALIGN)
+AC_SUBST(GOARCH_HUGEPAGESIZE)
+AC_SUBST(GOARCH_MINFRAMESIZE)
+AC_SUBST(ALLGOARCH)
+AC_SUBST(ALLGOARCHFAMILY)
dnl Some files are only present when needed for specific architectures.
GO_LIBCALL_OS_FILE=
@@ -366,6 +421,9 @@ case "$target" in
esac
AC_SUBST(OSCFLAGS)
+dnl Check if assembler supports disabling hardware capability support.
+GCC_CHECK_ASSEMBLER_HWCAP
+
dnl Use -fsplit-stack when compiling C code if available.
AC_CACHE_CHECK([whether -fsplit-stack is supported],
[libgo_cv_c_split_stack_supported],
@@ -388,9 +446,9 @@ EOF
cat > conftest2.c << EOF
void f() {}
EOF
-$CC -c -fsplit-stack $CFLAGS $CPPFLAGS conftest1.c
-$CC -c $CFLAGS $CPPFLAGS conftest2.c
-if $CC -o conftest conftest1.$ac_objext conftest2.$ac_objext; then
+$CC -c -fsplit-stack $CFLAGS $CPPFLAGS conftest1.c >/dev/null 2>&1
+$CC -c $CFLAGS $CPPFLAGS conftest2.c > /dev/null 2>&1
+if $CC -o conftest conftest1.$ac_objext conftest2.$ac_objext > /dev/null 2>&1; then
libgo_cv_c_linker_split_non_split=yes
else
libgo_cv_c_linker_split_non_split=no
@@ -511,7 +569,7 @@ AC_C_BIGENDIAN
GCC_CHECK_UNWIND_GETIPINFO
-AC_CHECK_HEADERS(sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
+AC_CHECK_HEADERS(port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
AC_CHECK_HEADERS([linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h], [], [],
[#ifdef HAVE_SYS_SOCKET_H
@@ -876,6 +934,24 @@ if test "x$libgo_cv_as_x86_64_unwind_section_type" = xyes; then
[Define if your assembler supports unwind section type.])
fi
+AC_CACHE_CHECK([assembler supports AES instructions],
+libgo_cv_as_x86_aes, [
+libgo_cv_as_x86_aes=yes
+echo 'aesenc %xmm0, %xmm1' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
+if $CC $CFLAGS -c conftest.s 2>&1 | grep -i error > /dev/null; then
+ libgo_cv_as_x86_aes=no
+fi
+CFLAGS=$CFLAGS_hold
+])
+if test "x$libgo_cv_as_x86_aes" = xyes; then
+ AC_DEFINE(HAVE_AS_X86_AES, 1,
+ [Define if your assembler supports AES instructions.])
+fi
+
AC_CACHE_SAVE
if test ${multilib} = yes; then
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
index 36f4e23980..d2ae66d554 100644
--- a/libgo/go/archive/tar/common.go
+++ b/libgo/go/archive/tar/common.go
@@ -13,7 +13,6 @@
package tar
import (
- "bytes"
"errors"
"fmt"
"os"
@@ -21,10 +20,12 @@ import (
"time"
)
-const (
- blockSize = 512
+// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
+// architectures. If a large value is encountered when decoding, the result
+// stored in Header will be the truncated version.
- // Types
+// Header type flags.
+const (
TypeReg = '0' // regular file
TypeRegA = '\x00' // regular file
TypeLink = '1' // hard link
@@ -61,12 +62,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,55 +274,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 {
- return false
- }
- }
- return true
-}
-
-func toASCII(s string) string {
- if isASCII(s) {
- return s
- }
- var buf bytes.Buffer
- for _, c := range s {
- if c < 0x80 {
- buf.WriteByte(byte(c))
- }
- }
- return buf.String()
-}
-
// isHeaderOnlyType checks if the given type flag is of the type that has no
// data section even if a size is specified.
func isHeaderOnlyType(flag byte) bool {
diff --git a/libgo/go/archive/tar/format.go b/libgo/go/archive/tar/format.go
new file mode 100644
index 0000000000..c2c9910d00
--- /dev/null
+++ b/libgo/go/archive/tar/format.go
@@ -0,0 +1,197 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// Constants to identify various tar formats.
+const (
+ // The format is unknown.
+ formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc...
+
+ // The format of the original Unix V7 tar tool prior to standardization.
+ formatV7
+
+ // The old and new GNU formats, which are incompatible with USTAR.
+ // This does cover the old GNU sparse extension.
+ // This does not cover the GNU sparse extensions using PAX headers,
+ // versions 0.0, 0.1, and 1.0; these fall under the PAX format.
+ formatGNU
+
+ // Schily's tar format, which is incompatible with USTAR.
+ // This does not cover STAR extensions to the PAX format; these fall under
+ // the PAX format.
+ formatSTAR
+
+ // USTAR is the former standardization of tar defined in POSIX.1-1988.
+ // This is incompatible with the GNU and STAR formats.
+ formatUSTAR
+
+ // PAX is the latest standardization of tar defined in POSIX.1-2001.
+ // This is an extension of USTAR and is "backwards compatible" with it.
+ //
+ // Some newer formats add their own extensions to PAX, such as GNU sparse
+ // files and SCHILY extended attributes. Since they are backwards compatible
+ // with PAX, they will be labelled as "PAX".
+ formatPAX
+)
+
+// Magics used to identify various formats.
+const (
+ magicGNU, versionGNU = "ustar ", " \x00"
+ magicUSTAR, versionUSTAR = "ustar\x00", "00"
+ trailerSTAR = "tar\x00"
+)
+
+// Size constants from various tar specifications.
+const (
+ blockSize = 512 // Size of each block in a tar stream
+ nameSize = 100 // Max length of the name field in USTAR format
+ prefixSize = 155 // Max length of the prefix field in USTAR format
+)
+
+var zeroBlock block
+
+type block [blockSize]byte
+
+// Convert block to any number of formats.
+func (b *block) V7() *headerV7 { return (*headerV7)(b) }
+func (b *block) GNU() *headerGNU { return (*headerGNU)(b) }
+func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) }
+func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
+func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) }
+
+// GetFormat checks that the block is a valid tar header based on the checksum.
+// It then attempts to guess the specific format based on magic values.
+// If the checksum fails, then formatUnknown is returned.
+func (b *block) GetFormat() (format int) {
+ // Verify checksum.
+ var p parser
+ value := p.parseOctal(b.V7().Chksum())
+ chksum1, chksum2 := b.ComputeChecksum()
+ if p.err != nil || (value != chksum1 && value != chksum2) {
+ return formatUnknown
+ }
+
+ // Guess the magic values.
+ magic := string(b.USTAR().Magic())
+ version := string(b.USTAR().Version())
+ trailer := string(b.STAR().Trailer())
+ switch {
+ case magic == magicUSTAR && trailer == trailerSTAR:
+ return formatSTAR
+ case magic == magicUSTAR:
+ return formatUSTAR
+ case magic == magicGNU && version == versionGNU:
+ return formatGNU
+ default:
+ return formatV7
+ }
+}
+
+// SetFormat writes the magic values necessary for specified format
+// and then updates the checksum accordingly.
+func (b *block) SetFormat(format int) {
+ // Set the magic values.
+ switch format {
+ case formatV7:
+ // Do nothing.
+ case formatGNU:
+ copy(b.GNU().Magic(), magicGNU)
+ copy(b.GNU().Version(), versionGNU)
+ case formatSTAR:
+ copy(b.STAR().Magic(), magicUSTAR)
+ copy(b.STAR().Version(), versionUSTAR)
+ copy(b.STAR().Trailer(), trailerSTAR)
+ case formatUSTAR, formatPAX:
+ copy(b.USTAR().Magic(), magicUSTAR)
+ copy(b.USTAR().Version(), versionUSTAR)
+ default:
+ panic("invalid format")
+ }
+
+ // Update checksum.
+ // This field is special in that it is terminated by a NULL then space.
+ var f formatter
+ field := b.V7().Chksum()
+ chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
+ f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
+ field[7] = ' '
+}
+
+// ComputeChecksum computes the checksum for the header block.
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
+// signed byte values.
+// We compute and return both.
+func (b *block) ComputeChecksum() (unsigned, signed int64) {
+ for i, c := range b {
+ if 148 <= i && i < 156 {
+ c = ' ' // Treat the checksum field itself as all spaces.
+ }
+ unsigned += int64(uint8(c))
+ signed += int64(int8(c))
+ }
+ return unsigned, signed
+}
+
+type headerV7 [blockSize]byte
+
+func (h *headerV7) Name() []byte { return h[000:][:100] }
+func (h *headerV7) Mode() []byte { return h[100:][:8] }
+func (h *headerV7) UID() []byte { return h[108:][:8] }
+func (h *headerV7) GID() []byte { return h[116:][:8] }
+func (h *headerV7) Size() []byte { return h[124:][:12] }
+func (h *headerV7) ModTime() []byte { return h[136:][:12] }
+func (h *headerV7) Chksum() []byte { return h[148:][:8] }
+func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
+func (h *headerV7) LinkName() []byte { return h[157:][:100] }
+
+type headerGNU [blockSize]byte
+
+func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) }
+func (h *headerGNU) Magic() []byte { return h[257:][:6] }
+func (h *headerGNU) Version() []byte { return h[263:][:2] }
+func (h *headerGNU) UserName() []byte { return h[265:][:32] }
+func (h *headerGNU) GroupName() []byte { return h[297:][:32] }
+func (h *headerGNU) DevMajor() []byte { return h[329:][:8] }
+func (h *headerGNU) DevMinor() []byte { return h[337:][:8] }
+func (h *headerGNU) AccessTime() []byte { return h[345:][:12] }
+func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] }
+func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) }
+func (h *headerGNU) RealSize() []byte { return h[483:][:12] }
+
+type headerSTAR [blockSize]byte
+
+func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) }
+func (h *headerSTAR) Magic() []byte { return h[257:][:6] }
+func (h *headerSTAR) Version() []byte { return h[263:][:2] }
+func (h *headerSTAR) UserName() []byte { return h[265:][:32] }
+func (h *headerSTAR) GroupName() []byte { return h[297:][:32] }
+func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] }
+func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] }
+func (h *headerSTAR) Prefix() []byte { return h[345:][:131] }
+func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
+func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
+func (h *headerSTAR) Trailer() []byte { return h[508:][:4] }
+
+type headerUSTAR [blockSize]byte
+
+func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) }
+func (h *headerUSTAR) Magic() []byte { return h[257:][:6] }
+func (h *headerUSTAR) Version() []byte { return h[263:][:2] }
+func (h *headerUSTAR) UserName() []byte { return h[265:][:32] }
+func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
+func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] }
+func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] }
+func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] }
+
+type sparseArray []byte
+
+func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) }
+func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] }
+func (s sparseArray) MaxEntries() int { return len(s) / 24 }
+
+type sparseNode []byte
+
+func (s sparseNode) Offset() []byte { return s[00:][:12] }
+func (s sparseNode) NumBytes() []byte { return s[12:][:12] }
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
index c8cb69a178..9abe888218 100644
--- a/libgo/go/archive/tar/reader.go
+++ b/libgo/go/archive/tar/reader.go
@@ -13,7 +13,6 @@ import (
"io"
"io/ioutil"
"math"
- "os"
"strconv"
"strings"
"time"
@@ -23,22 +22,20 @@ var (
ErrHeader = errors.New("archive/tar: invalid tar header")
)
-const maxNanoSecondIntSize = 9
-
// A Reader provides sequential access to the contents of a tar archive.
// A tar archive consists of a sequence of files.
// 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
-}
-
-type parser struct {
- err error // Last error seen
+ r io.Reader
+ 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
+
+ // err is a persistent error.
+ // It is only the responsibility of every exported method of Reader to
+ // ensure that this error is sticky.
+ err error
}
// A numBytesReader is an io.Reader with a numBytes method, returning the number
@@ -99,17 +96,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} }
@@ -120,8 +106,12 @@ func (tr *Reader) Next() (*Header, error) {
if tr.err != nil {
return nil, tr.err
}
+ hdr, err := tr.next()
+ tr.err = err
+ return hdr, err
+}
- var hdr *Header
+func (tr *Reader) next() (*Header, error) {
var extHdrs map[string]string
// Externally, Next iterates through the tar archive as if it is a series of
@@ -131,29 +121,29 @@ func (tr *Reader) Next() (*Header, error) {
// one or more "header files" until it finds a "normal file".
loop:
for {
- tr.err = tr.skipUnread()
- if tr.err != nil {
- return nil, tr.err
+ if err := tr.skipUnread(); err != nil {
+ return nil, err
}
-
- hdr = tr.readHeader()
- if tr.err != nil {
- return nil, tr.err
+ hdr, rawHdr, err := tr.readHeader()
+ if err != nil {
+ return nil, err
+ }
+ if err := tr.handleRegularFile(hdr); err != nil {
+ return nil, err
}
// Check for PAX/GNU special headers and files.
switch hdr.Typeflag {
case TypeXHeader:
- extHdrs, tr.err = parsePAX(tr)
- if tr.err != nil {
- return nil, tr.err
+ extHdrs, err = parsePAX(tr)
+ if err != nil {
+ return nil, err
}
continue loop // This is a meta header affecting the next header
case TypeGNULongName, TypeGNULongLink:
- var realname []byte
- realname, tr.err = ioutil.ReadAll(tr)
- if tr.err != nil {
- return nil, tr.err
+ realname, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return nil, err
}
// Convert GNU extensions to use PAX headers.
@@ -168,31 +158,73 @@ loop:
extHdrs[paxLinkpath] = p.parseString(realname)
}
if p.err != nil {
- tr.err = p.err
- return nil, tr.err
+ return nil, p.err
}
continue loop // This is a meta header affecting the next header
default:
- mergePAX(hdr, extHdrs)
+ // The old GNU sparse format is handled here since it is technically
+ // just a regular file with additional attributes.
- // Check for a PAX format sparse file
- sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
- if err != nil {
- tr.err = err
+ if err := mergePAX(hdr, extHdrs); err != nil {
return nil, err
}
- if sp != nil {
- // Current file is a PAX format GNU sparse file.
- // Set the current file reader to a sparse file reader.
- tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
- if tr.err != nil {
- return nil, tr.err
- }
+
+ // The extended headers may have updated the size.
+ // Thus, setup the regFileReader again after merging PAX headers.
+ if err := tr.handleRegularFile(hdr); err != nil {
+ return nil, err
}
- break loop // This is a file, so stop
+
+ // Sparse formats rely on being able to read from the logical data
+ // section; there must be a preceding call to handleRegularFile.
+ if err := tr.handleSparseFile(hdr, rawHdr, extHdrs); err != nil {
+ return nil, err
+ }
+ return hdr, nil // This is a file, so stop
}
}
- return hdr, nil
+}
+
+// handleRegularFile sets up the current file reader and padding such that it
+// can only read the following logical data section. It will properly handle
+// special headers that contain no data section.
+func (tr *Reader) handleRegularFile(hdr *Header) error {
+ nb := hdr.Size
+ if isHeaderOnlyType(hdr.Typeflag) {
+ nb = 0
+ }
+ if nb < 0 {
+ return ErrHeader
+ }
+
+ tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+ tr.curr = &regFileReader{r: tr.r, nb: nb}
+ return nil
+}
+
+// handleSparseFile checks if the current file is a sparse format of any type
+// and sets the curr reader appropriately.
+func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[string]string) error {
+ var sp []sparseEntry
+ var err error
+ if hdr.Typeflag == TypeGNUSparse {
+ sp, err = tr.readOldGNUSparseMap(hdr, rawHdr)
+ if err != nil {
+ return err
+ }
+ } else {
+ sp, err = tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
+ if err != nil {
+ return err
+ }
+ }
+
+ // If sp is non-nil, then this is a sparse file.
+ // Note that it is possible for len(sp) to be zero.
+ if sp != nil {
+ tr.curr, err = newSparseFileReader(tr.curr, sp, hdr.Size)
+ }
+ return err
}
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
@@ -231,13 +263,13 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
hdr.Name = sparseName
}
if sparseSizeOk {
- realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+ realSize, err := strconv.ParseInt(sparseSize, 10, 64)
if err != nil {
return nil, ErrHeader
}
hdr.Size = realSize
} else if sparseRealSizeOk {
- realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+ realSize, err := strconv.ParseInt(sparseRealSize, 10, 64)
if err != nil {
return nil, ErrHeader
}
@@ -261,53 +293,32 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
// in the header struct overwrite those found in the header
// struct with higher precision or longer values. Esp. useful
// for name and linkname fields.
-func mergePAX(hdr *Header, headers map[string]string) error {
+func mergePAX(hdr *Header, headers map[string]string) (err error) {
+ var id64 int64
for k, v := range headers {
switch k {
case paxPath:
hdr.Name = v
case paxLinkpath:
hdr.Linkname = v
- case paxGname:
- hdr.Gname = v
case paxUname:
hdr.Uname = v
+ case paxGname:
+ hdr.Gname = v
case paxUid:
- uid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Uid = int(uid)
+ id64, err = strconv.ParseInt(v, 10, 64)
+ hdr.Uid = int(id64) // Integer overflow possible
case paxGid:
- gid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Gid = int(gid)
+ id64, err = strconv.ParseInt(v, 10, 64)
+ hdr.Gid = int(id64) // Integer overflow possible
case paxAtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.AccessTime = t
+ hdr.AccessTime, err = parsePAXTime(v)
case paxMtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ModTime = t
+ hdr.ModTime, err = parsePAXTime(v)
case paxCtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ChangeTime = t
+ hdr.ChangeTime, err = parsePAXTime(v)
case paxSize:
- size, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Size = int64(size)
+ hdr.Size, err = strconv.ParseInt(v, 10, 64)
default:
if strings.HasPrefix(k, paxXattr) {
if hdr.Xattrs == nil {
@@ -316,44 +327,11 @@ func mergePAX(hdr *Header, headers map[string]string) error {
hdr.Xattrs[k[len(paxXattr):]] = v
}
}
- }
- return nil
-}
-
-// parsePAXTime takes a string of the form %d.%d as described in
-// the PAX specification.
-func parsePAXTime(t string) (time.Time, error) {
- buf := []byte(t)
- pos := bytes.IndexByte(buf, '.')
- var seconds, nanoseconds int64
- var err error
- if pos == -1 {
- seconds, err = strconv.ParseInt(t, 10, 0)
if err != nil {
- return time.Time{}, err
- }
- } else {
- seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- nano_buf := string(buf[pos+1:])
- // Pad as needed before converting to a decimal.
- // For example .030 -> .030000000 -> 30000000 nanoseconds
- if len(nano_buf) < maxNanoSecondIntSize {
- // Right pad
- nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
- } else if len(nano_buf) > maxNanoSecondIntSize {
- // Right truncate
- nano_buf = nano_buf[:maxNanoSecondIntSize]
- }
- nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
- if err != nil {
- return time.Time{}, err
+ return ErrHeader
}
}
- ts := time.Unix(seconds, nanoseconds)
- return ts, nil
+ return nil
}
// parsePAX parses PAX headers.
@@ -366,12 +344,11 @@ func parsePAX(r io.Reader) (map[string]string, error) {
sbuf := string(buf)
// For GNU PAX sparse format 0.0 support.
- // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
- var sparseMap bytes.Buffer
+ // This function transforms the sparse format 0.0 headers into format 0.1
+ // headers since 0.0 headers were not PAX compliant.
+ var sparseMap []string
- headers := make(map[string]string)
- // Each record is constructed as
- // "%d %s=%s\n", length, keyword, value
+ extHdrs := make(map[string]string)
for len(sbuf) > 0 {
key, value, residual, err := parsePAXRecord(sbuf)
if err != nil {
@@ -379,127 +356,29 @@ func parsePAX(r io.Reader) (map[string]string, error) {
}
sbuf = residual
- keyStr := string(key)
- if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
- // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
- sparseMap.WriteString(value)
- sparseMap.Write([]byte{','})
- } else {
- // Normal key. Set the value in the headers map.
- headers[keyStr] = string(value)
- }
- }
- if sparseMap.Len() != 0 {
- // Add sparse info to headers, chopping off the extra comma
- sparseMap.Truncate(sparseMap.Len() - 1)
- headers[paxGNUSparseMap] = sparseMap.String()
- }
- return headers, nil
-}
-
-// parsePAXRecord parses the input PAX record string into a key-value pair.
-// If parsing is successful, it will slice off the currently read record and
-// return the remainder as r.
-//
-// A PAX record is of the following form:
-// "%d %s=%s\n" % (size, key, value)
-func parsePAXRecord(s string) (k, v, r string, err error) {
- // The size field ends at the first space.
- sp := strings.IndexByte(s, ' ')
- if sp == -1 {
- return "", "", s, ErrHeader
- }
-
- // Parse the first token as a decimal integer.
- n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
- if perr != nil || n < 5 || int64(len(s)) < n {
- return "", "", s, ErrHeader
- }
-
- // Extract everything between the space and the final newline.
- rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
- if nl != "\n" {
- return "", "", s, ErrHeader
- }
-
- // The first equals separates the key from the value.
- eq := strings.IndexByte(rec, '=')
- if eq == -1 {
- return "", "", s, ErrHeader
- }
- return rec[:eq], rec[eq+1:], rem, nil
-}
-
-// parseString parses bytes as a NUL-terminated C-style string.
-// If a NUL byte is not found then the whole slice is returned as a string.
-func (*parser) parseString(b []byte) string {
- n := 0
- for n < len(b) && b[n] != 0 {
- n++
- }
- return string(b[0:n])
-}
-
-// parseNumeric parses the input as being encoded in either base-256 or octal.
-// This function may return negative numbers.
-// If parsing fails or an integer overflow occurs, err will be set.
-func (p *parser) parseNumeric(b []byte) int64 {
- // Check for base-256 (binary) format first.
- // If the first bit is set, then all following bits constitute a two's
- // complement encoded number in big-endian byte order.
- if len(b) > 0 && b[0]&0x80 != 0 {
- // Handling negative numbers relies on the following identity:
- // -a-1 == ^a
- //
- // If the number is negative, we use an inversion mask to invert the
- // data bytes and treat the value as an unsigned number.
- var inv byte // 0x00 if positive or zero, 0xff if negative
- if b[0]&0x40 != 0 {
- inv = 0xff
- }
-
- var x uint64
- for i, c := range b {
- c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
- if i == 0 {
- c &= 0x7f // Ignore signal bit in first byte
+ switch key {
+ case paxGNUSparseOffset, paxGNUSparseNumBytes:
+ // Validate sparse header order and value.
+ if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
+ (len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
+ strings.Contains(value, ",") {
+ return nil, ErrHeader
}
- if (x >> 56) > 0 {
- p.err = ErrHeader // Integer overflow
- return 0
+ sparseMap = append(sparseMap, value)
+ default:
+ // According to PAX specification, a value is stored only if it is
+ // non-empty. Otherwise, the key is deleted.
+ if len(value) > 0 {
+ extHdrs[key] = value
+ } else {
+ delete(extHdrs, key)
}
- x = x<<8 | uint64(c)
- }
- if (x >> 63) > 0 {
- p.err = ErrHeader // Integer overflow
- return 0
}
- if inv == 0xff {
- return ^int64(x)
- }
- return int64(x)
}
-
- // Normal case is base-8 (octal) format.
- return p.parseOctal(b)
-}
-
-func (p *parser) parseOctal(b []byte) int64 {
- // Because unused fields are filled with NULs, we need
- // to skip leading NULs. Fields may also be padded with
- // spaces or NULs.
- // So we remove leading and trailing NULs and spaces to
- // be sure.
- b = bytes.Trim(b, " \x00")
-
- if len(b) == 0 {
- return 0
- }
- x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
- if perr != nil {
- p.err = ErrHeader
+ if len(sparseMap) > 0 {
+ extHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
}
- return int64(x)
+ return extHdrs, nil
}
// skipUnread skips any unread bytes in the existing file entry, as well as any
@@ -523,217 +402,169 @@ func (tr *Reader) skipUnread() error {
// io.Seeker, but calling Seek always returns an error and performs
// no action. Thus, we try an innocent seek to the current position
// to see if Seek is really supported.
- pos1, err := sr.Seek(0, os.SEEK_CUR)
+ pos1, err := sr.Seek(0, io.SeekCurrent)
if err == nil {
// Seek seems supported, so perform the real Seek.
- pos2, err := sr.Seek(dataSkip-1, os.SEEK_CUR)
+ pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent)
if err != nil {
- tr.err = err
- return tr.err
+ return err
}
seekSkipped = pos2 - pos1
}
}
- var copySkipped int64 // Number of bytes skipped via CopyN
- copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
- if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip {
- tr.err = io.ErrUnexpectedEOF
- }
- return tr.err
-}
-
-func (tr *Reader) verifyChecksum(header []byte) bool {
- if tr.err != nil {
- return false
+ copySkipped, err := io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
+ if err == io.EOF && seekSkipped+copySkipped < dataSkip {
+ err = io.ErrUnexpectedEOF
}
-
- var p parser
- given := p.parseOctal(header[148:156])
- unsigned, signed := checksum(header)
- return p.err == nil && (given == unsigned || given == signed)
+ return err
}
// readHeader reads the next block header and assumes that the underlying reader
-// is already aligned to a block boundary.
+// is already aligned to a block boundary. It returns the raw block of the
+// header in case further processing is required.
//
// The err will be set to io.EOF only when one of the following occurs:
// * Exactly 0 bytes are read and EOF is hit.
// * 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 {
- return nil // io.EOF is okay here
- }
-
+func (tr *Reader) readHeader() (*Header, *block, error) {
// 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 {
- return nil // io.EOF is okay here
+ if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
+ return nil, nil, err // EOF is okay here; exactly 0 bytes read
+ }
+ if bytes.Equal(tr.blk[:], zeroBlock[:]) {
+ if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
+ return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
}
- if bytes.Equal(header, zeroBlock[0:blockSize]) {
- tr.err = io.EOF
- } else {
- tr.err = ErrHeader // zero block and then non-zero block
+ if bytes.Equal(tr.blk[:], zeroBlock[:]) {
+ return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
}
- return nil
+ return nil, nil, ErrHeader // Zero block and then non-zero block
}
- if !tr.verifyChecksum(header) {
- tr.err = ErrHeader
- return nil
+ // Verify the header matches a known format.
+ format := tr.blk.GetFormat()
+ if format == formatUnknown {
+ return nil, nil, ErrHeader
}
- // 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())
+
+ // The atime and ctime fields are often left unused. Some versions of Go
+ // had a bug in the tar.Writer where it would output an invalid tar file
+ // in certain rare situations because the logic incorrectly believed that
+ // the old GNU format had a prefix field. This is wrong and leads to
+ // an outputted file that actually mangles the atime and ctime fields.
+ //
+ // In order to continue reading tar files created by a buggy writer, we
+ // try to parse the atime and ctime fields, but just return the zero value
+ // of time.Time when we cannot parse them.
+ //
+ // See https://golang.org/issues/12594
+ tryParseTime := func(b []byte) time.Time {
+ var p parser
+ n := p.parseNumeric(b)
+ if b[0] != 0x00 && p.err == nil {
+ return time.Unix(n, 0)
+ }
+ return time.Time{}
+ }
+
+ // 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:
+ 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)
+ case formatGNU:
+ gnu := tr.blk.GNU()
+ hdr.AccessTime = tryParseTime(gnu.AccessTime())
+ hdr.ChangeTime = tryParseTime(gnu.ChangeTime())
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name
}
}
+ return hdr, &tr.blk, p.err
+}
- if p.err != nil {
- tr.err = p.err
- return nil
- }
-
- nb := hdr.Size
- if isHeaderOnlyType(hdr.Typeflag) {
- nb = 0
- }
- if nb < 0 {
- tr.err = ErrHeader
- return nil
- }
-
- // Set the current file reader.
- tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
- tr.curr = &regFileReader{r: tr.r, nb: nb}
-
- // 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])
- if p.err != nil {
- tr.err = p.err
- return nil
- }
-
- // Read the sparse map.
- sp := tr.readOldGNUSparseMap(header)
- if tr.err != nil {
- return nil
- }
-
- // Current file is a GNU sparse file. Update the current file reader.
- tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
- if tr.err != nil {
- return nil
- }
+// readOldGNUSparseMap reads the sparse map from 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.
+//
+// The Header.Size does not reflect the size of any extended headers used.
+// Thus, this function will read from the raw io.Reader to fetch extra headers.
+// This method mutates blk in the process.
+func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) {
+ // Make sure that the input format is GNU.
+ // Unfortunately, the STAR format also has a sparse header format that uses
+ // the same type flag but has a completely different layout.
+ if blk.GetFormat() != formatGNU {
+ return nil, ErrHeader
}
- 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 {
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))
- if p.err != nil {
- tr.err = p.err
- return nil
- }
- if offset == 0 && numBytes == 0 {
- break
- }
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ hdr.Size = p.parseNumeric(blk.GNU().RealSize())
+ if p.err != nil {
+ return nil, p.err
}
-
- for isExtended {
- // 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 {
- 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))
- if p.err != nil {
- tr.err = p.err
- return nil
+ var s sparseArray = blk.GNU().Sparse()
+ var sp = make([]sparseEntry, 0, s.MaxEntries())
+ for {
+ for i := 0; i < s.MaxEntries(); i++ {
+ // This termination condition is identical to GNU and BSD tar.
+ if s.Entry(i).Offset()[0] == 0x00 {
+ break // Don't return, need to process extended headers (even if empty)
}
- if offset == 0 && numBytes == 0 {
- break
+ offset := p.parseNumeric(s.Entry(i).Offset())
+ numBytes := p.parseNumeric(s.Entry(i).NumBytes())
+ if p.err != nil {
+ return nil, p.err
}
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
}
+
+ if s.IsExtended()[0] > 0 {
+ // There are more entries. Read an extension header and parse its entries.
+ if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+ s = blk.Sparse()
+ continue
+ }
+ return sp, nil // Done
}
- return sp
}
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
@@ -861,7 +692,7 @@ func (tr *Reader) numBytes() int64 {
// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
// the Header.Size claims.
-func (tr *Reader) Read(b []byte) (n int, err error) {
+func (tr *Reader) Read(b []byte) (int, error) {
if tr.err != nil {
return 0, tr.err
}
@@ -869,11 +700,11 @@ func (tr *Reader) Read(b []byte) (n int, err error) {
return 0, io.EOF
}
- n, err = tr.curr.Read(b)
+ n, err := tr.curr.Read(b)
if err != nil && err != io.EOF {
tr.err = err
}
- return
+ return n, err
}
func (rfr *regFileReader) Read(b []byte) (n int, err error) {
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
index 7b148b5122..338686836b 100644
--- a/libgo/go/archive/tar/reader_test.go
+++ b/libgo/go/archive/tar/reader_test.go
@@ -18,17 +18,15 @@ import (
"time"
)
-type untarTest struct {
- file string // Test input file
- headers []*Header // Expected output headers
- chksums []string // MD5 checksum of files, leave as nil if not checked
- err error // Expected error to occur
-}
-
-var gnuTarTest = &untarTest{
- file: "testdata/gnu.tar",
- headers: []*Header{
- {
+func TestReader(t *testing.T) {
+ vectors := []struct {
+ file string // Test input file
+ headers []*Header // Expected output headers
+ chksums []string // MD5 checksum of files, leave as nil if not checked
+ err error // Expected error to occur
+ }{{
+ file: "testdata/gnu.tar",
+ headers: []*Header{{
Name: "small.txt",
Mode: 0640,
Uid: 73025,
@@ -38,8 +36,7 @@ var gnuTarTest = &untarTest{
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
- },
- {
+ }, {
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
@@ -49,18 +46,14 @@ var gnuTarTest = &untarTest{
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
+ }},
+ chksums: []string{
+ "e38b27eaccb4391bdec553a7f3ae6b2f",
+ "c65bd2e50a56a2138bf1716f2fd56fe9",
},
- },
- chksums: []string{
- "e38b27eaccb4391bdec553a7f3ae6b2f",
- "c65bd2e50a56a2138bf1716f2fd56fe9",
- },
-}
-
-var sparseTarTest = &untarTest{
- file: "testdata/sparse-formats.tar",
- headers: []*Header{
- {
+ }, {
+ file: "testdata/sparse-formats.tar",
+ headers: []*Header{{
Name: "sparse-gnu",
Mode: 420,
Uid: 1000,
@@ -73,8 +66,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-0.0",
Mode: 420,
Uid: 1000,
@@ -87,8 +79,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-0.1",
Mode: 420,
Uid: 1000,
@@ -101,8 +92,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-1.0",
Mode: 420,
Uid: 1000,
@@ -115,8 +105,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "end",
Mode: 420,
Uid: 1000,
@@ -129,209 +118,237 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
+ }},
+ chksums: []string{
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "b0061974914468de549a2af8ced10316",
},
- },
- chksums: []string{
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "b0061974914468de549a2af8ced10316",
- },
-}
-
-var untarTests = []*untarTest{
- gnuTarTest,
- sparseTarTest,
- {
+ }, {
file: "testdata/star.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- {
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
+ }, {
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
+ }},
+ }, {
file: "testdata/v7.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- {
- Name: "small2.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244593104, 0),
+ Typeflag: '\x00',
+ }, {
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244593104, 0),
+ Typeflag: '\x00',
+ }},
+ }, {
file: "testdata/pax.tar",
- headers: []*Header{
- {
- Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- Mode: 0664,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 7,
- ModTime: time.Unix(1350244992, 23960108),
- ChangeTime: time.Unix(1350244992, 23960108),
- AccessTime: time.Unix(1350244992, 23960108),
- Typeflag: TypeReg,
- },
- {
- Name: "a/b",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 0,
- ModTime: time.Unix(1350266320, 910238425),
- ChangeTime: time.Unix(1350266320, 910238425),
- AccessTime: time.Unix(1350266320, 910238425),
- Typeflag: TypeSymlink,
- Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- },
+ headers: []*Header{{
+ Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ Mode: 0664,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 7,
+ ModTime: time.Unix(1350244992, 23960108),
+ ChangeTime: time.Unix(1350244992, 23960108),
+ AccessTime: time.Unix(1350244992, 23960108),
+ Typeflag: TypeReg,
+ }, {
+ Name: "a/b",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 0,
+ ModTime: time.Unix(1350266320, 910238425),
+ ChangeTime: time.Unix(1350266320, 910238425),
+ AccessTime: time.Unix(1350266320, 910238425),
+ Typeflag: TypeSymlink,
+ Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ }},
+ }, {
+ file: "testdata/pax-bad-hdr-file.tar",
+ err: ErrHeader,
+ }, {
+ file: "testdata/pax-bad-mtime-file.tar",
+ err: ErrHeader,
+ }, {
+ file: "testdata/pax-pos-size-file.tar",
+ headers: []*Header{{
+ Name: "foo",
+ Mode: 0640,
+ Uid: 319973,
+ Gid: 5000,
+ Size: 999,
+ ModTime: time.Unix(1442282516, 0),
+ Typeflag: '0',
+ Uname: "joetsai",
+ Gname: "eng",
+ }},
+ chksums: []string{
+ "0afb597b283fe61b5d4879669a350556",
},
- },
- {
+ }, {
file: "testdata/nil-uid.tar", // golang.org/issue/5290
- headers: []*Header{
- {
- Name: "P1050238.JPG.log",
- Mode: 0664,
- Uid: 0,
- Gid: 0,
- Size: 14,
- ModTime: time.Unix(1365454838, 0),
- Typeflag: TypeReg,
- Linkname: "",
- Uname: "eyefi",
- Gname: "eyefi",
- Devmajor: 0,
- Devminor: 0,
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "P1050238.JPG.log",
+ Mode: 0664,
+ Uid: 0,
+ Gid: 0,
+ Size: 14,
+ ModTime: time.Unix(1365454838, 0),
+ Typeflag: TypeReg,
+ Linkname: "",
+ Uname: "eyefi",
+ Gname: "eyefi",
+ Devmajor: 0,
+ Devminor: 0,
+ }},
+ }, {
file: "testdata/xattrs.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 5,
- ModTime: time.Unix(1386065770, 448252320),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1389782956, 794414986),
- Xattrs: map[string]string{
- "user.key": "value",
- "user.key2": "value2",
- // Interestingly, selinux encodes the terminating null inside the xattr
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 5,
+ ModTime: time.Unix(1386065770, 448252320),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1389782956, 794414986),
+ Xattrs: map[string]string{
+ "user.key": "value",
+ "user.key2": "value2",
+ // Interestingly, selinux encodes the terminating null inside the xattr
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
- {
- Name: "small2.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 11,
- ModTime: time.Unix(1386065770, 449252304),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1386065770, 449252304),
- Xattrs: map[string]string{
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
+ }, {
+ Name: "small2.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 11,
+ ModTime: time.Unix(1386065770, 449252304),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1386065770, 449252304),
+ Xattrs: map[string]string{
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
- },
- },
- {
+ }},
+ }, {
// Matches the behavior of GNU, BSD, and STAR tar utilities.
file: "testdata/gnu-multi-hdrs.tar",
- headers: []*Header{
- {
- Name: "GNU2/GNU2/long-path-name",
- Linkname: "GNU4/GNU4/long-linkpath-name",
- ModTime: time.Unix(0, 0),
- Typeflag: '2',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "GNU2/GNU2/long-path-name",
+ Linkname: "GNU4/GNU4/long-linkpath-name",
+ ModTime: time.Unix(0, 0),
+ Typeflag: '2',
+ }},
+ }, {
+ // GNU tar file with atime and ctime fields set.
+ // Created with the GNU tar v1.27.1.
+ // tar --incremental -S -cvf gnu-incremental.tar test2
+ file: "testdata/gnu-incremental.tar",
+ headers: []*Header{{
+ Name: "test2/",
+ Mode: 16877,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 14,
+ ModTime: time.Unix(1441973427, 0),
+ Typeflag: 'D',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441974501, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }, {
+ Name: "test2/foo",
+ Mode: 33188,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 64,
+ ModTime: time.Unix(1441973363, 0),
+ Typeflag: '0',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441974501, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }, {
+ Name: "test2/sparse",
+ Mode: 33188,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 536870912,
+ ModTime: time.Unix(1441973427, 0),
+ Typeflag: 'S',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441991948, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }},
+ }, {
// Matches the behavior of GNU and BSD tar utilities.
file: "testdata/pax-multi-hdrs.tar",
- headers: []*Header{
- {
- Name: "bar",
- Linkname: "PAX4/PAX4/long-linkpath-name",
- ModTime: time.Unix(0, 0),
- Typeflag: '2',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "bar",
+ Linkname: "PAX4/PAX4/long-linkpath-name",
+ ModTime: time.Unix(0, 0),
+ Typeflag: '2',
+ }},
+ }, {
file: "testdata/neg-size.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue10968.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue11169.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue12435.tar",
err: ErrHeader,
- },
-}
+ }}
-func TestReader(t *testing.T) {
- for i, v := range untarTests {
+ for i, v := range vectors {
f, err := os.Open(v.file)
if err != nil {
t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err)
@@ -440,83 +457,8 @@ func TestPartialRead(t *testing.T) {
}
}
-func TestParsePAXHeader(t *testing.T) {
- paxTests := [][3]string{
- {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
- {"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
- {"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
- for _, test := range paxTests {
- key, expected, raw := test[0], test[1], test[2]
- reader := bytes.NewReader([]byte(raw))
- headers, err := parsePAX(reader)
- if err != nil {
- t.Errorf("Couldn't parse correctly formatted headers: %v", err)
- continue
- }
- if strings.EqualFold(headers[key], expected) {
- t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
- continue
- }
- trailer := make([]byte, 100)
- n, err := reader.Read(trailer)
- if err != io.EOF || n != 0 {
- t.Error("Buffer wasn't consumed")
- }
- }
- badHeaderTests := [][]byte{
- []byte("3 somelongkey=\n"),
- []byte("50 tooshort=\n"),
- }
- for _, test := range badHeaderTests {
- if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader {
- t.Fatal("Unexpected success when parsing bad header")
- }
- }
-}
-
-func TestParsePAXTime(t *testing.T) {
- // Some valid PAX time values
- timestamps := map[string]time.Time{
- "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
- "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
- "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
- "1350244992": time.Unix(1350244992, 0), // Low precision value
- }
- for input, expected := range timestamps {
- ts, err := parsePAXTime(input)
- if err != nil {
- t.Fatal(err)
- }
- if !ts.Equal(expected) {
- t.Fatalf("Time parsing failure %s %s", ts, expected)
- }
- }
-}
-
-func TestMergePAX(t *testing.T) {
- hdr := new(Header)
- // Test a string, integer, and time based value.
- headers := map[string]string{
- "path": "a/b/c",
- "uid": "1000",
- "mtime": "1350244992.023960108",
- }
- err := mergePAX(hdr, headers)
- if err != nil {
- t.Fatal(err)
- }
- want := &Header{
- Name: "a/b/c",
- Uid: 1000,
- ModTime: time.Unix(1350244992, 23960108),
- }
- if !reflect.DeepEqual(hdr, want) {
- t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
- }
-}
-
func TestSparseFileReader(t *testing.T) {
- var vectors = []struct {
+ vectors := []struct {
realSize int64 // Real size of the output file
sparseMap []sparseEntry // Input sparse map
sparseData string // Input compact data
@@ -639,9 +581,11 @@ func TestSparseFileReader(t *testing.T) {
r := bytes.NewReader([]byte(v.sparseData))
rfr := &regFileReader{r: r, nb: int64(len(v.sparseData))}
- var sfr *sparseFileReader
- var err error
- var buf []byte
+ var (
+ sfr *sparseFileReader
+ err error
+ buf []byte
+ )
sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize)
if err != nil {
@@ -668,6 +612,64 @@ func TestSparseFileReader(t *testing.T) {
}
}
+func TestReadOldGNUSparseMap(t *testing.T) {
+ const (
+ t00 = "00000000000\x0000000000000\x00"
+ t11 = "00000000001\x0000000000001\x00"
+ t12 = "00000000001\x0000000000002\x00"
+ t21 = "00000000002\x0000000000001\x00"
+ )
+
+ mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block {
+ var blk block
+ copy(blk.GNU().RealSize(), size)
+ copy(blk.GNU().Sparse().Entry(0), sp0)
+ copy(blk.GNU().Sparse().Entry(1), sp1)
+ copy(blk.GNU().Sparse().Entry(2), sp2)
+ copy(blk.GNU().Sparse().Entry(3), sp3)
+ copy(blk.GNU().Sparse().IsExtended(), ext)
+ if format != formatUnknown {
+ blk.SetFormat(format)
+ }
+ return &blk
+ }
+
+ vectors := []struct {
+ data string // Input data
+ rawHdr *block // Input raw header
+ want []sparseEntry // Expected sparse entries to be outputted
+ err error // Expected error to be returned
+ }{
+ {"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader},
+ {"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader},
+ {"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil},
+ {"", mkBlk("1234", t00, t11, "", "", "", formatGNU),
+ []sparseEntry{{0, 0}, {1, 1}}, nil},
+ {"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU),
+ []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil},
+ {"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{}, io.ErrUnexpectedEOF},
+ {t11 + t11,
+ mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{}, io.ErrUnexpectedEOF},
+ {t11 + t21 + strings.Repeat("\x00", 512),
+ mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil},
+ }
+
+ for i, v := range vectors {
+ tr := Reader{r: strings.NewReader(v.data)}
+ hdr := new(Header)
+ got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr)
+ if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
+ t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want)
+ }
+ if err != v.err {
+ t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
+ }
+ }
+}
+
func TestReadGNUSparseMap0x1(t *testing.T) {
const (
maxUint = ^uint(0)
@@ -679,7 +681,7 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
big3 = fmt.Sprintf("%d", (int64(maxInt) / 3))
)
- var vectors = []struct {
+ vectors := []struct {
extHdrs map[string]string // Input data
sparseMap []sparseEntry // Expected sparse entries to be outputted
err error // Expected errors that may be raised
@@ -745,12 +747,12 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
}
func TestReadGNUSparseMap1x0(t *testing.T) {
- var sp = []sparseEntry{{1, 2}, {3, 4}}
+ sp := []sparseEntry{{1, 2}, {3, 4}}
for i := 0; i < 98; i++ {
sp = append(sp, sparseEntry{54321, 12345})
}
- var vectors = []struct {
+ vectors := []struct {
input string // Input data
sparseMap []sparseEntry // Expected sparse entries to be outputted
cnt int // Expected number of bytes read
@@ -825,8 +827,7 @@ func TestReadGNUSparseMap1x0(t *testing.T) {
}
func TestUninitializedRead(t *testing.T) {
- test := gnuTarTest
- f, err := os.Open(test.file)
+ f, err := os.Open("testdata/gnu.tar")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@@ -868,7 +869,7 @@ func TestReadTruncation(t *testing.T) {
data2 += strings.Repeat("\x00", 10*512)
trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
- var vectors = []struct {
+ vectors := []struct {
input string // Input stream
cnt int // Expected number of headers read
err error // Expected error outcome
@@ -904,8 +905,7 @@ func TestReadTruncation(t *testing.T) {
{pax + trash[:1], 0, io.ErrUnexpectedEOF},
{pax + trash[:511], 0, io.ErrUnexpectedEOF},
{sparse[:511], 0, io.ErrUnexpectedEOF},
- // TODO(dsnet): This should pass, but currently fails.
- // {sparse[:512], 0, io.ErrUnexpectedEOF},
+ {sparse[:512], 0, io.ErrUnexpectedEOF},
{sparse[:3584], 1, io.EOF},
{sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
{sparse[:9216], 1, io.EOF},
@@ -1002,7 +1002,7 @@ func TestReadHeaderOnly(t *testing.T) {
t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
}
for i := 0; i < 8; i++ {
- var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
+ hdr1, hdr2 := hdrs[i+0], hdrs[i+8]
hdr1.Size, hdr2.Size = 0, 0
if !reflect.DeepEqual(*hdr1, *hdr2) {
t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
@@ -1010,116 +1010,87 @@ func TestReadHeaderOnly(t *testing.T) {
}
}
-func TestParsePAXRecord(t *testing.T) {
- var medName = strings.Repeat("CD", 50)
- var longName = strings.Repeat("AB", 100)
-
- var vectors = []struct {
- input string
- residual string
- outputKey string
- outputVal string
- ok bool
- }{
- {"6 k=v\n\n", "\n", "k", "v", true},
- {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
- {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
- {"110 path=" + medName + "\n", "", "path", medName, true},
- {"9 foo=ba\n", "", "foo", "ba", true},
- {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
- {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
- {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
- {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
- {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
- {"1 k=1\n", "1 k=1\n", "", "", false},
- {"6 k~1\n", "6 k~1\n", "", "", false},
- {"6_k=1\n", "6_k=1\n", "", "", false},
- {"6 k=1 ", "6 k=1 ", "", "", false},
- {"632 k=1\n", "632 k=1\n", "", "", false},
- {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
- {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
- {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
- }
+func TestMergePAX(t *testing.T) {
+ vectors := []struct {
+ in map[string]string
+ want *Header
+ ok bool
+ }{{
+ in: map[string]string{
+ "path": "a/b/c",
+ "uid": "1000",
+ "mtime": "1350244992.023960108",
+ },
+ want: &Header{
+ Name: "a/b/c",
+ Uid: 1000,
+ ModTime: time.Unix(1350244992, 23960108),
+ },
+ ok: true,
+ }, {
+ in: map[string]string{
+ "gid": "gtgergergersagersgers",
+ },
+ }, {
+ in: map[string]string{
+ "missing": "missing",
+ "SCHILY.xattr.key": "value",
+ },
+ want: &Header{
+ Xattrs: map[string]string{"key": "value"},
+ },
+ ok: true,
+ }}
- for _, v := range vectors {
- key, val, res, err := parsePAXRecord(v.input)
- ok := (err == nil)
- if v.ok != ok {
- if v.ok {
- t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
- } else {
- t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
- }
- }
- if ok && (key != v.outputKey || val != v.outputVal) {
- t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
- v.input, key, val, v.outputKey, v.outputVal)
+ for i, v := range vectors {
+ got := new(Header)
+ err := mergePAX(got, v.in)
+ if v.ok && !reflect.DeepEqual(*got, *v.want) {
+ t.Errorf("test %d, mergePAX(...):\ngot %+v\nwant %+v", i, *got, *v.want)
}
- if res != v.residual {
- t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
- v.input, res, v.residual)
+ if ok := err == nil; ok != v.ok {
+ t.Errorf("test %d, mergePAX(...): got %v, want %v", i, ok, v.ok)
}
}
}
-func TestParseNumeric(t *testing.T) {
- var vectors = []struct {
- input string
- output int64
- ok bool
+func TestParsePAX(t *testing.T) {
+ vectors := []struct {
+ in string
+ want map[string]string
+ ok bool
}{
- // Test base-256 (binary) encoded values.
- {"", 0, true},
- {"\x80", 0, true},
- {"\x80\x00", 0, true},
- {"\x80\x00\x00", 0, true},
- {"\xbf", (1 << 6) - 1, true},
- {"\xbf\xff", (1 << 14) - 1, true},
- {"\xbf\xff\xff", (1 << 22) - 1, true},
- {"\xff", -1, true},
- {"\xff\xff", -1, true},
- {"\xff\xff\xff", -1, true},
- {"\xc0", -1 * (1 << 6), true},
- {"\xc0\x00", -1 * (1 << 14), true},
- {"\xc0\x00\x00", -1 * (1 << 22), true},
- {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
- {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
- {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
- {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
- {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
- {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
- {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
- {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
- {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
-
- // Test base-8 (octal) encoded values.
- {"0000000\x00", 0, true},
- {" \x0000000\x00", 0, true},
- {" \x0000003\x00", 3, true},
- {"00000000227\x00", 0227, true},
- {"032033\x00 ", 032033, true},
- {"320330\x00 ", 0320330, true},
- {"0000660\x00 ", 0660, true},
- {"\x00 0000660\x00 ", 0660, true},
- {"0123456789abcdef", 0, false},
- {"0123456789\x00abcdef", 0, false},
- {"01234567\x0089abcdef", 342391, true},
- {"0123\x7e\x5f\x264123", 0, false},
+ {"", nil, true},
+ {"6 k=1\n", map[string]string{"k": "1"}, true},
+ {"10 a=name\n", map[string]string{"a": "name"}, true},
+ {"9 a=name\n", map[string]string{"a": "name"}, true},
+ {"30 mtime=1350244992.023960108\n", map[string]string{"mtime": "1350244992.023960108"}, true},
+ {"3 somelongkey=\n", nil, false},
+ {"50 tooshort=\n", nil, false},
+ {"13 key1=haha\n13 key2=nana\n13 key3=kaka\n",
+ map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true},
+ {"13 key1=val1\n13 key2=val2\n8 key1=\n",
+ map[string]string{"key2": "val2"}, true},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" +
+ "23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" +
+ "23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n",
+ map[string]string{paxGNUSparseSize: "10", paxGNUSparseNumBlocks: "2", paxGNUSparseMap: "1,2,3,4"}, true},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
+ "25 GNU.sparse.numbytes=2\n23 GNU.sparse.offset=1\n",
+ nil, false},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
+ "25 GNU.sparse.offset=1,2\n25 GNU.sparse.numbytes=2\n",
+ nil, false},
}
- for _, v := range vectors {
- var p parser
- num := p.parseNumeric([]byte(v.input))
- ok := (p.err == nil)
- if v.ok != ok {
- if v.ok {
- t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
- } else {
- t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
- }
+ for i, v := range vectors {
+ r := strings.NewReader(v.in)
+ got, err := parsePAX(r)
+ if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
+ t.Errorf("test %d, parsePAX(...):\ngot %v\nwant %v", i, got, v.want)
}
- if ok && num != v.output {
- t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
+ if ok := err == nil; ok != v.ok {
+ t.Errorf("test %d, parsePAX(...): got %v, want %v", i, ok, v.ok)
}
}
}
diff --git a/libgo/go/archive/tar/strconv.go b/libgo/go/archive/tar/strconv.go
new file mode 100644
index 0000000000..bb5b51c02d
--- /dev/null
+++ b/libgo/go/archive/tar/strconv.go
@@ -0,0 +1,252 @@
+// 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
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+func isASCII(s string) bool {
+ for _, c := range s {
+ if c >= 0x80 {
+ return false
+ }
+ }
+ return true
+}
+
+func toASCII(s string) string {
+ if isASCII(s) {
+ return s
+ }
+ var buf bytes.Buffer
+ for _, c := range s {
+ if c < 0x80 {
+ buf.WriteByte(byte(c))
+ }
+ }
+ return buf.String()
+}
+
+type parser struct {
+ err error // Last error seen
+}
+
+type formatter struct {
+ err error // Last error seen
+}
+
+// parseString parses bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func (*parser) parseString(b []byte) string {
+ n := 0
+ for n < len(b) && b[n] != 0 {
+ n++
+ }
+ return string(b[0:n])
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (f *formatter) formatString(b []byte, s string) {
+ if len(s) > len(b) {
+ f.err = ErrFieldTooLong
+ return
+ }
+ ascii := toASCII(s)
+ copy(b, ascii)
+ if len(ascii) < len(b) {
+ b[len(ascii)] = 0
+ }
+}
+
+// fitsInBase256 reports whether x can be encoded into n bytes using base-256
+// encoding. Unlike octal encoding, base-256 encoding does not require that the
+// string ends with a NUL character. Thus, all n bytes are available for output.
+//
+// If operating in binary mode, this assumes strict GNU binary mode; which means
+// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
+// equivalent to the sign bit in two's complement form.
+func fitsInBase256(n int, x int64) bool {
+ var binBits = uint(n-1) * 8
+ return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
+}
+
+// parseNumeric parses the input as being encoded in either base-256 or octal.
+// This function may return negative numbers.
+// If parsing fails or an integer overflow occurs, err will be set.
+func (p *parser) parseNumeric(b []byte) int64 {
+ // Check for base-256 (binary) format first.
+ // If the first bit is set, then all following bits constitute a two's
+ // complement encoded number in big-endian byte order.
+ if len(b) > 0 && b[0]&0x80 != 0 {
+ // Handling negative numbers relies on the following identity:
+ // -a-1 == ^a
+ //
+ // If the number is negative, we use an inversion mask to invert the
+ // data bytes and treat the value as an unsigned number.
+ var inv byte // 0x00 if positive or zero, 0xff if negative
+ if b[0]&0x40 != 0 {
+ inv = 0xff
+ }
+
+ var x uint64
+ for i, c := range b {
+ c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
+ if i == 0 {
+ c &= 0x7f // Ignore signal bit in first byte
+ }
+ if (x >> 56) > 0 {
+ p.err = ErrHeader // Integer overflow
+ return 0
+ }
+ x = x<<8 | uint64(c)
+ }
+ if (x >> 63) > 0 {
+ p.err = ErrHeader // Integer overflow
+ return 0
+ }
+ if inv == 0xff {
+ return ^int64(x)
+ }
+ return int64(x)
+ }
+
+ // Normal case is base-8 (octal) format.
+ return p.parseOctal(b)
+}
+
+// Write x into b, as binary (GNUtar/star extension).
+func (f *formatter) formatNumeric(b []byte, x int64) {
+ if fitsInBase256(len(b), x) {
+ for i := len(b) - 1; i >= 0; i-- {
+ b[i] = byte(x)
+ x >>= 8
+ }
+ b[0] |= 0x80 // Highest bit indicates binary format
+ return
+ }
+
+ f.formatOctal(b, 0) // Last resort, just write zero
+ f.err = ErrFieldTooLong
+}
+
+func (p *parser) parseOctal(b []byte) int64 {
+ // Because unused fields are filled with NULs, we need
+ // to skip leading NULs. Fields may also be padded with
+ // spaces or NULs.
+ // So we remove leading and trailing NULs and spaces to
+ // be sure.
+ b = bytes.Trim(b, " \x00")
+
+ if len(b) == 0 {
+ return 0
+ }
+ x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
+ if perr != nil {
+ p.err = ErrHeader
+ }
+ return int64(x)
+}
+
+func (f *formatter) formatOctal(b []byte, x int64) {
+ s := strconv.FormatInt(x, 8)
+ // Add leading zeros, but leave room for a NUL.
+ if n := len(b) - len(s) - 1; n > 0 {
+ s = strings.Repeat("0", n) + s
+ }
+ f.formatString(b, s)
+}
+
+// parsePAXTime takes a string of the form %d.%d as described in the PAX
+// specification. Note that this implementation allows for negative timestamps,
+// which is allowed for by the PAX specification, but not always portable.
+func parsePAXTime(s string) (time.Time, error) {
+ const maxNanoSecondDigits = 9
+
+ // Split string into seconds and sub-seconds parts.
+ ss, sn := s, ""
+ if pos := strings.IndexByte(s, '.'); pos >= 0 {
+ ss, sn = s[:pos], s[pos+1:]
+ }
+
+ // Parse the seconds.
+ secs, err := strconv.ParseInt(ss, 10, 64)
+ if err != nil {
+ return time.Time{}, ErrHeader
+ }
+ if len(sn) == 0 {
+ return time.Unix(secs, 0), nil // No sub-second values
+ }
+
+ // Parse the nanoseconds.
+ if strings.Trim(sn, "0123456789") != "" {
+ return time.Time{}, ErrHeader
+ }
+ if len(sn) < maxNanoSecondDigits {
+ sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
+ } else {
+ sn = sn[:maxNanoSecondDigits] // Right truncate
+ }
+ nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
+ if len(ss) > 0 && ss[0] == '-' {
+ return time.Unix(secs, -1*int64(nsecs)), nil // Negative correction
+ }
+ return time.Unix(secs, int64(nsecs)), nil
+}
+
+// TODO(dsnet): Implement formatPAXTime.
+
+// parsePAXRecord parses the input PAX record string into a key-value pair.
+// If parsing is successful, it will slice off the currently read record and
+// return the remainder as r.
+//
+// A PAX record is of the following form:
+// "%d %s=%s\n" % (size, key, value)
+func parsePAXRecord(s string) (k, v, r string, err error) {
+ // The size field ends at the first space.
+ sp := strings.IndexByte(s, ' ')
+ if sp == -1 {
+ return "", "", s, ErrHeader
+ }
+
+ // Parse the first token as a decimal integer.
+ n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
+ if perr != nil || n < 5 || int64(len(s)) < n {
+ return "", "", s, ErrHeader
+ }
+
+ // Extract everything between the space and the final newline.
+ rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
+ if nl != "\n" {
+ return "", "", s, ErrHeader
+ }
+
+ // The first equals separates the key from the value.
+ eq := strings.IndexByte(rec, '=')
+ if eq == -1 {
+ return "", "", s, ErrHeader
+ }
+ return rec[:eq], rec[eq+1:], rem, nil
+}
+
+// formatPAXRecord formats a single PAX record, prefixing it with the
+// appropriate length.
+func formatPAXRecord(k, v string) string {
+ const padding = 3 // Extra padding for ' ', '=', and '\n'
+ size := len(k) + len(v) + padding
+ size += len(strconv.Itoa(size))
+ record := fmt.Sprintf("%d %s=%s\n", size, k, v)
+
+ // Final adjustment if adding size field increased the record size.
+ if len(record) != size {
+ size = len(record)
+ record = fmt.Sprintf("%d %s=%s\n", size, k, v)
+ }
+ return record
+}
diff --git a/libgo/go/archive/tar/strconv_test.go b/libgo/go/archive/tar/strconv_test.go
new file mode 100644
index 0000000000..beb70938bf
--- /dev/null
+++ b/libgo/go/archive/tar/strconv_test.go
@@ -0,0 +1,319 @@
+// 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
+
+import (
+ "math"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestFitsInBase256(t *testing.T) {
+ vectors := []struct {
+ in int64
+ width int
+ ok bool
+ }{
+ {+1, 8, true},
+ {0, 8, true},
+ {-1, 8, true},
+ {1 << 56, 8, false},
+ {(1 << 56) - 1, 8, true},
+ {-1 << 56, 8, true},
+ {(-1 << 56) - 1, 8, false},
+ {121654, 8, true},
+ {-9849849, 8, true},
+ {math.MaxInt64, 9, true},
+ {0, 9, true},
+ {math.MinInt64, 9, true},
+ {math.MaxInt64, 12, true},
+ {0, 12, true},
+ {math.MinInt64, 12, true},
+ }
+
+ for _, v := range vectors {
+ ok := fitsInBase256(v.width, v.in)
+ if ok != v.ok {
+ t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
+ }
+ }
+}
+
+func TestParseNumeric(t *testing.T) {
+ vectors := []struct {
+ in string
+ want int64
+ ok bool
+ }{
+ // Test base-256 (binary) encoded values.
+ {"", 0, true},
+ {"\x80", 0, true},
+ {"\x80\x00", 0, true},
+ {"\x80\x00\x00", 0, true},
+ {"\xbf", (1 << 6) - 1, true},
+ {"\xbf\xff", (1 << 14) - 1, true},
+ {"\xbf\xff\xff", (1 << 22) - 1, true},
+ {"\xff", -1, true},
+ {"\xff\xff", -1, true},
+ {"\xff\xff\xff", -1, true},
+ {"\xc0", -1 * (1 << 6), true},
+ {"\xc0\x00", -1 * (1 << 14), true},
+ {"\xc0\x00\x00", -1 * (1 << 22), true},
+ {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+ {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+ {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+ {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+ {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
+ {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
+ {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
+ {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
+ {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
+
+ // Test base-8 (octal) encoded values.
+ {"0000000\x00", 0, true},
+ {" \x0000000\x00", 0, true},
+ {" \x0000003\x00", 3, true},
+ {"00000000227\x00", 0227, true},
+ {"032033\x00 ", 032033, true},
+ {"320330\x00 ", 0320330, true},
+ {"0000660\x00 ", 0660, true},
+ {"\x00 0000660\x00 ", 0660, true},
+ {"0123456789abcdef", 0, false},
+ {"0123456789\x00abcdef", 0, false},
+ {"01234567\x0089abcdef", 342391, true},
+ {"0123\x7e\x5f\x264123", 0, false},
+ }
+
+ for _, v := range vectors {
+ var p parser
+ got := p.parseNumeric([]byte(v.in))
+ ok := (p.err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if ok && got != v.want {
+ t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
+ }
+ }
+}
+
+func TestFormatNumeric(t *testing.T) {
+ vectors := []struct {
+ in int64
+ want string
+ ok bool
+ }{
+ // Test base-256 (binary) encoded values.
+ {-1, "\xff", true},
+ {-1, "\xff\xff", true},
+ {-1, "\xff\xff\xff", true},
+ {(1 << 0), "0", false},
+ {(1 << 8) - 1, "\x80\xff", true},
+ {(1 << 8), "0\x00", false},
+ {(1 << 16) - 1, "\x80\xff\xff", true},
+ {(1 << 16), "00\x00", false},
+ {-1 * (1 << 0), "\xff", true},
+ {-1*(1<<0) - 1, "0", false},
+ {-1 * (1 << 8), "\xff\x00", true},
+ {-1*(1<<8) - 1, "0\x00", false},
+ {-1 * (1 << 16), "\xff\x00\x00", true},
+ {-1*(1<<16) - 1, "00\x00", false},
+ {537795476381659745, "0000000\x00", false},
+ {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
+ {-615126028225187231, "0000000\x00", false},
+ {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
+ {math.MaxInt64, "0000000\x00", false},
+ {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+ {math.MinInt64, "0000000\x00", false},
+ {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+ {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+ {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+ }
+
+ for _, v := range vectors {
+ var f formatter
+ got := make([]byte, len(v.want))
+ f.formatNumeric(got, v.in)
+ ok := (f.err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
+ } else {
+ t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
+ }
+ }
+ if string(got) != v.want {
+ t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
+ }
+ }
+}
+
+func TestParsePAXTime(t *testing.T) {
+ vectors := []struct {
+ in string
+ want time.Time
+ ok bool
+ }{
+ {"1350244992.023960108", time.Unix(1350244992, 23960108), true},
+ {"1350244992.02396010", time.Unix(1350244992, 23960100), true},
+ {"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
+ {"1350244992.3", time.Unix(1350244992, 300000000), true},
+ {"1350244992", time.Unix(1350244992, 0), true},
+ {"-1.000000001", time.Unix(-1, -1e0+0e0), true},
+ {"-1.000001", time.Unix(-1, -1e3+0e0), true},
+ {"-1.001000", time.Unix(-1, -1e6+0e0), true},
+ {"-1", time.Unix(-1, -0e0+0e0), true},
+ {"-1.999000", time.Unix(-1, -1e9+1e6), true},
+ {"-1.999999", time.Unix(-1, -1e9+1e3), true},
+ {"-1.999999999", time.Unix(-1, -1e9+1e0), true},
+ {"0.000000001", time.Unix(0, 1e0+0e0), true},
+ {"0.000001", time.Unix(0, 1e3+0e0), true},
+ {"0.001000", time.Unix(0, 1e6+0e0), true},
+ {"0", time.Unix(0, 0e0), true},
+ {"0.999000", time.Unix(0, 1e9-1e6), true},
+ {"0.999999", time.Unix(0, 1e9-1e3), true},
+ {"0.999999999", time.Unix(0, 1e9-1e0), true},
+ {"1.000000001", time.Unix(+1, +1e0-0e0), true},
+ {"1.000001", time.Unix(+1, +1e3-0e0), true},
+ {"1.001000", time.Unix(+1, +1e6-0e0), true},
+ {"1", time.Unix(+1, +0e0-0e0), true},
+ {"1.999000", time.Unix(+1, +1e9-1e6), true},
+ {"1.999999", time.Unix(+1, +1e9-1e3), true},
+ {"1.999999999", time.Unix(+1, +1e9-1e0), true},
+ {"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
+ {"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
+ {"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
+ {"-1350244992.3", time.Unix(-1350244992, -300000000), true},
+ {"-1350244992", time.Unix(-1350244992, 0), true},
+ {"", time.Time{}, false},
+ {"0", time.Unix(0, 0), true},
+ {"1.", time.Unix(1, 0), true},
+ {"0.0", time.Unix(0, 0), true},
+ {".5", time.Time{}, false},
+ {"-1.3", time.Unix(-1, -3e8), true},
+ {"-1.0", time.Unix(-1, -0e0), true},
+ {"-0.0", time.Unix(-0, -0e0), true},
+ {"-0.1", time.Unix(-0, -1e8), true},
+ {"-0.01", time.Unix(-0, -1e7), true},
+ {"-0.99", time.Unix(-0, -99e7), true},
+ {"-0.98", time.Unix(-0, -98e7), true},
+ {"-1.1", time.Unix(-1, -1e8), true},
+ {"-1.01", time.Unix(-1, -1e7), true},
+ {"-2.99", time.Unix(-2, -99e7), true},
+ {"-5.98", time.Unix(-5, -98e7), true},
+ {"-", time.Time{}, false},
+ {"+", time.Time{}, false},
+ {"-1.-1", time.Time{}, false},
+ {"99999999999999999999999999999999999999999999999", time.Time{}, false},
+ {"0.123456789abcdef", time.Time{}, false},
+ {"foo", time.Time{}, false},
+ {"\x00", time.Time{}, false},
+ {"ðŸµðŸ´ðŸ³ðŸ²ðŸ±.ðŸ°ðŸ¯ðŸ®ðŸ­ðŸ¬", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
+ {"98765ï¹’43210", time.Time{}, false}, // Unicode period (U+FE52)
+ }
+
+ for _, v := range vectors {
+ ts, err := parsePAXTime(v.in)
+ ok := (err == nil)
+ if v.ok != ok {
+ if v.ok {
+ t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if ok && !ts.Equal(v.want) {
+ t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
+ v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond())
+ }
+ }
+}
+
+func TestParsePAXRecord(t *testing.T) {
+ medName := strings.Repeat("CD", 50)
+ longName := strings.Repeat("AB", 100)
+
+ vectors := []struct {
+ in string
+ wantRes string
+ wantKey string
+ wantVal string
+ ok bool
+ }{
+ {"6 k=v\n\n", "\n", "k", "v", true},
+ {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
+ {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
+ {"110 path=" + medName + "\n", "", "path", medName, true},
+ {"9 foo=ba\n", "", "foo", "ba", true},
+ {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
+ {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
+ {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
+ {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
+ {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
+ {"1 k=1\n", "1 k=1\n", "", "", false},
+ {"6 k~1\n", "6 k~1\n", "", "", false},
+ {"6_k=1\n", "6_k=1\n", "", "", false},
+ {"6 k=1 ", "6 k=1 ", "", "", false},
+ {"632 k=1\n", "632 k=1\n", "", "", false},
+ {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
+ {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
+ {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
+ }
+
+ for _, v := range vectors {
+ key, val, res, err := parsePAXRecord(v.in)
+ ok := (err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if v.ok && (key != v.wantKey || val != v.wantVal) {
+ t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
+ v.in, key, val, v.wantKey, v.wantVal)
+ }
+ if res != v.wantRes {
+ t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
+ v.in, res, v.wantRes)
+ }
+ }
+}
+
+func TestFormatPAXRecord(t *testing.T) {
+ medName := strings.Repeat("CD", 50)
+ longName := strings.Repeat("AB", 100)
+
+ vectors := []struct {
+ inKey string
+ inVal string
+ want string
+ }{
+ {"k", "v", "6 k=v\n"},
+ {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
+ {"path", longName, "210 path=" + longName + "\n"},
+ {"path", medName, "110 path=" + medName + "\n"},
+ {"foo", "ba", "9 foo=ba\n"},
+ {"foo", "bar", "11 foo=bar\n"},
+ {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
+ {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
+ {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
+ {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
+ }
+
+ for _, v := range vectors {
+ got := formatPAXRecord(v.inKey, v.inVal)
+ if got != v.want {
+ t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
+ v.inKey, v.inVal, got, v.want)
+ }
+ }
+}
diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go
index d63c072eb9..cf8337c2ad 100644
--- a/libgo/go/archive/tar/tar_test.go
+++ b/libgo/go/archive/tar/tar_test.go
@@ -135,190 +135,178 @@ type headerRoundTripTest struct {
}
func TestHeaderRoundTrip(t *testing.T) {
- golden := []headerRoundTripTest{
+ vectors := []headerRoundTripTest{{
// regular file.
- {
- h: &Header{
- Name: "test.txt",
- Mode: 0644 | c_ISREG,
- Size: 12,
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeReg,
- },
- fm: 0644,
+ h: &Header{
+ Name: "test.txt",
+ Mode: 0644 | c_ISREG,
+ Size: 12,
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeReg,
},
+ fm: 0644,
+ }, {
// symbolic link.
- {
- h: &Header{
- Name: "link.txt",
- Mode: 0777 | c_ISLNK,
- Size: 0,
- ModTime: time.Unix(1360600852, 0),
- Typeflag: TypeSymlink,
- },
- fm: 0777 | os.ModeSymlink,
+ h: &Header{
+ Name: "link.txt",
+ Mode: 0777 | c_ISLNK,
+ Size: 0,
+ ModTime: time.Unix(1360600852, 0),
+ Typeflag: TypeSymlink,
},
+ fm: 0777 | os.ModeSymlink,
+ }, {
// character device node.
- {
- h: &Header{
- Name: "dev/null",
- Mode: 0666 | c_ISCHR,
- Size: 0,
- ModTime: time.Unix(1360578951, 0),
- Typeflag: TypeChar,
- },
- fm: 0666 | os.ModeDevice | os.ModeCharDevice,
+ h: &Header{
+ Name: "dev/null",
+ Mode: 0666 | c_ISCHR,
+ Size: 0,
+ ModTime: time.Unix(1360578951, 0),
+ Typeflag: TypeChar,
},
+ fm: 0666 | os.ModeDevice | os.ModeCharDevice,
+ }, {
// block device node.
- {
- h: &Header{
- Name: "dev/sda",
- Mode: 0660 | c_ISBLK,
- Size: 0,
- ModTime: time.Unix(1360578954, 0),
- Typeflag: TypeBlock,
- },
- fm: 0660 | os.ModeDevice,
+ h: &Header{
+ Name: "dev/sda",
+ Mode: 0660 | c_ISBLK,
+ Size: 0,
+ ModTime: time.Unix(1360578954, 0),
+ Typeflag: TypeBlock,
},
+ fm: 0660 | os.ModeDevice,
+ }, {
// directory.
- {
- h: &Header{
- Name: "dir/",
- Mode: 0755 | c_ISDIR,
- Size: 0,
- ModTime: time.Unix(1360601116, 0),
- Typeflag: TypeDir,
- },
- fm: 0755 | os.ModeDir,
+ h: &Header{
+ Name: "dir/",
+ Mode: 0755 | c_ISDIR,
+ Size: 0,
+ ModTime: time.Unix(1360601116, 0),
+ Typeflag: TypeDir,
},
+ fm: 0755 | os.ModeDir,
+ }, {
// fifo node.
- {
- h: &Header{
- Name: "dev/initctl",
- Mode: 0600 | c_ISFIFO,
- Size: 0,
- ModTime: time.Unix(1360578949, 0),
- Typeflag: TypeFifo,
- },
- fm: 0600 | os.ModeNamedPipe,
+ h: &Header{
+ Name: "dev/initctl",
+ Mode: 0600 | c_ISFIFO,
+ Size: 0,
+ ModTime: time.Unix(1360578949, 0),
+ Typeflag: TypeFifo,
},
+ fm: 0600 | os.ModeNamedPipe,
+ }, {
// setuid.
- {
- h: &Header{
- Name: "bin/su",
- Mode: 0755 | c_ISREG | c_ISUID,
- Size: 23232,
- ModTime: time.Unix(1355405093, 0),
- Typeflag: TypeReg,
- },
- fm: 0755 | os.ModeSetuid,
+ h: &Header{
+ Name: "bin/su",
+ Mode: 0755 | c_ISREG | c_ISUID,
+ Size: 23232,
+ ModTime: time.Unix(1355405093, 0),
+ Typeflag: TypeReg,
},
+ fm: 0755 | os.ModeSetuid,
+ }, {
// setguid.
- {
- h: &Header{
- Name: "group.txt",
- Mode: 0750 | c_ISREG | c_ISGID,
- Size: 0,
- ModTime: time.Unix(1360602346, 0),
- Typeflag: TypeReg,
- },
- fm: 0750 | os.ModeSetgid,
+ h: &Header{
+ Name: "group.txt",
+ Mode: 0750 | c_ISREG | c_ISGID,
+ Size: 0,
+ ModTime: time.Unix(1360602346, 0),
+ Typeflag: TypeReg,
},
+ fm: 0750 | os.ModeSetgid,
+ }, {
// sticky.
- {
- h: &Header{
- Name: "sticky.txt",
- Mode: 0600 | c_ISREG | c_ISVTX,
- Size: 7,
- ModTime: time.Unix(1360602540, 0),
- Typeflag: TypeReg,
- },
- fm: 0600 | os.ModeSticky,
+ h: &Header{
+ Name: "sticky.txt",
+ Mode: 0600 | c_ISREG | c_ISVTX,
+ Size: 7,
+ ModTime: time.Unix(1360602540, 0),
+ Typeflag: TypeReg,
},
+ fm: 0600 | os.ModeSticky,
+ }, {
// hard link.
- {
- h: &Header{
- Name: "hard.txt",
- Mode: 0644 | c_ISREG,
- Size: 0,
- Linkname: "file.txt",
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeLink,
- },
- fm: 0644,
+ h: &Header{
+ Name: "hard.txt",
+ Mode: 0644 | c_ISREG,
+ Size: 0,
+ Linkname: "file.txt",
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeLink,
},
+ fm: 0644,
+ }, {
// More information.
- {
- h: &Header{
- Name: "info.txt",
- Mode: 0600 | c_ISREG,
- Size: 0,
- Uid: 1000,
- Gid: 1000,
- ModTime: time.Unix(1360602540, 0),
- Uname: "slartibartfast",
- Gname: "users",
- Typeflag: TypeReg,
- },
- fm: 0600,
+ h: &Header{
+ Name: "info.txt",
+ Mode: 0600 | c_ISREG,
+ Size: 0,
+ Uid: 1000,
+ Gid: 1000,
+ ModTime: time.Unix(1360602540, 0),
+ Uname: "slartibartfast",
+ Gname: "users",
+ Typeflag: TypeReg,
},
- }
+ fm: 0600,
+ }}
- for i, g := range golden {
- fi := g.h.FileInfo()
+ for i, v := range vectors {
+ fi := v.h.FileInfo()
h2, err := FileInfoHeader(fi, "")
if err != nil {
t.Error(err)
continue
}
if strings.Contains(fi.Name(), "/") {
- t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
+ t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
}
- name := path.Base(g.h.Name)
+ name := path.Base(v.h.Name)
if fi.IsDir() {
name += "/"
}
if got, want := h2.Name, name; got != want {
t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
}
- if got, want := h2.Size, g.h.Size; got != want {
+ if got, want := h2.Size, v.h.Size; got != want {
t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
}
- if got, want := h2.Uid, g.h.Uid; got != want {
+ if got, want := h2.Uid, v.h.Uid; got != want {
t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
}
- if got, want := h2.Gid, g.h.Gid; got != want {
+ if got, want := h2.Gid, v.h.Gid; got != want {
t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
}
- if got, want := h2.Uname, g.h.Uname; got != want {
+ if got, want := h2.Uname, v.h.Uname; got != want {
t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
}
- if got, want := h2.Gname, g.h.Gname; got != want {
+ if got, want := h2.Gname, v.h.Gname; got != want {
t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
}
- if got, want := h2.Linkname, g.h.Linkname; got != want {
+ if got, want := h2.Linkname, v.h.Linkname; got != want {
t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
}
- if got, want := h2.Typeflag, g.h.Typeflag; got != want {
- t.Logf("%#v %#v", g.h, fi.Sys())
+ if got, want := h2.Typeflag, v.h.Typeflag; got != want {
+ t.Logf("%#v %#v", v.h, fi.Sys())
t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
}
- if got, want := h2.Mode, g.h.Mode; got != want {
+ if got, want := h2.Mode, v.h.Mode; got != want {
t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
}
- if got, want := fi.Mode(), g.fm; got != want {
+ if got, want := fi.Mode(), v.fm; got != want {
t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
}
- if got, want := h2.AccessTime, g.h.AccessTime; got != want {
+ if got, want := h2.AccessTime, v.h.AccessTime; got != want {
t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
}
- if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
+ if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
}
- if got, want := h2.ModTime, g.h.ModTime; got != want {
+ if got, want := h2.ModTime, v.h.ModTime; got != want {
t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
}
- if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
+ if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
t.Errorf("i=%d: Sys didn't return original *Header", i)
}
}
diff --git a/libgo/go/archive/tar/testdata/gnu-incremental.tar b/libgo/go/archive/tar/testdata/gnu-incremental.tar
new file mode 100644
index 0000000000..4c442e5b82
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/gnu-incremental.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/pax-bad-hdr-file.tar b/libgo/go/archive/tar/testdata/pax-bad-hdr-file.tar
new file mode 100644
index 0000000000..b97cc981f2
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/pax-bad-hdr-file.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/pax-bad-mtime-file.tar b/libgo/go/archive/tar/testdata/pax-bad-mtime-file.tar
new file mode 100644
index 0000000000..9b22f7e8d9
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/pax-bad-mtime-file.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/pax-pos-size-file.tar b/libgo/go/archive/tar/testdata/pax-pos-size-file.tar
new file mode 100644
index 0000000000..aed9a8aa48
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/pax-pos-size-file.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/ustar.issue12594.tar b/libgo/go/archive/tar/testdata/ustar.issue12594.tar
new file mode 100644
index 0000000000..c7910ae9f4
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/ustar.issue12594.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer-big-long.tar b/libgo/go/archive/tar/testdata/writer-big-long.tar
index 5960ee8247..52bd748f3b 100644
--- a/libgo/go/archive/tar/testdata/writer-big-long.tar
+++ b/libgo/go/archive/tar/testdata/writer-big-long.tar
Binary files differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
index 042638175c..596fb8b9e1 100644
--- a/libgo/go/archive/tar/writer.go
+++ b/libgo/go/archive/tar/writer.go
@@ -36,14 +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
-}
-
-type formatter struct {
- err error // Last error seen
+ 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
}
// NewWriter creates a new Writer writing to w.
@@ -71,56 +67,6 @@ func (tw *Writer) Flush() error {
return tw.err
}
-// Write s into b, terminating it with a NUL if there is room.
-func (f *formatter) formatString(b []byte, s string) {
- if len(s) > len(b) {
- f.err = ErrFieldTooLong
- return
- }
- ascii := toASCII(s)
- copy(b, ascii)
- if len(ascii) < len(b) {
- b[len(ascii)] = 0
- }
-}
-
-// Encode x as an octal ASCII string and write it into b with leading zeros.
-func (f *formatter) formatOctal(b []byte, x int64) {
- s := strconv.FormatInt(x, 8)
- // leading zeros, but leave room for a NUL.
- for len(s)+1 < len(b) {
- s = "0" + s
- }
- f.formatString(b, s)
-}
-
-// fitsInBase256 reports whether x can be encoded into n bytes using base-256
-// encoding. Unlike octal encoding, base-256 encoding does not require that the
-// string ends with a NUL character. Thus, all n bytes are available for output.
-//
-// If operating in binary mode, this assumes strict GNU binary mode; which means
-// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
-// equivalent to the sign bit in two's complement form.
-func fitsInBase256(n int, x int64) bool {
- var binBits = uint(n-1) * 8
- return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
-}
-
-// Write x into b, as binary (GNUtar/star extension).
-func (f *formatter) formatNumeric(b []byte, x int64) {
- if fitsInBase256(len(b), x) {
- for i := len(b) - 1; i >= 0; i-- {
- b[i] = byte(x)
- x >>= 8
- }
- b[0] |= 0x80 // Highest bit indicates binary format
- return
- }
-
- f.formatOctal(b, 0) // Last resort, just write zero
- f.err = ErrFieldTooLong
-}
-
var (
minTime = time.Unix(0, 0)
// There is room for 11 octal digits (33 bits) of mtime.
@@ -153,27 +99,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,61 +145,82 @@ 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
-
- // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
- if tw.usedBinary {
- copy(header[257:265], []byte("ustar \x00"))
- }
+ 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)
+
+ // TODO(dsnet): The logic surrounding the prefix field is broken when trying
+ // to encode the header as GNU format. The challenge with the current logic
+ // is that we are unsure what format we are using at any given moment until
+ // we have processed *all* of the fields. The problem is that by the time
+ // all fields have been processed, some work has already been done to handle
+ // each field under the assumption that it is for one given format or
+ // another. In some situations, this causes the Writer to be confused and
+ // encode a prefix field when the format being used is GNU. Thus, producing
+ // an invalid tar file.
+ //
+ // As a short-term fix, we disable the logic to use the prefix field, which
+ // will force the badly generated GNU files to become encoded as being
+ // the PAX format.
+ //
+ // As an alternative fix, we could hard-code preferPax to be true. However,
+ // this is problematic for the following reasons:
+ // * The preferPax functionality is not tested at all.
+ // * This can result in headers that try to use both the GNU and PAX
+ // features at the same time, which is also wrong.
+ //
+ // The proper fix for this is to use a two-pass method:
+ // * The first pass simply determines what set of formats can possibly
+ // encode the given header.
+ // * The second pass actually encodes the header as that given format
+ // without worrying about violating the format.
+ //
+ // See the following:
+ // https://golang.org/issue/12594
+ // https://golang.org/issue/17630
+ // https://golang.org/issue/9683
+ const usePrefix = false
- _, paxPathUsed := paxHeaders[paxPath]
// try to use a ustar header when only the name is too long
- if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
+ _, paxPathUsed := paxHeaders[paxPath]
+ if usePrefix && !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
prefix, suffix, ok := splitUSTARPath(hdr.Name)
if ok {
// Since we can encode in USTAR format, disable PAX header.
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 {
@@ -278,10 +242,10 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
return err
}
}
- tw.nb = int64(hdr.Size)
+ 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 +253,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 +264,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
@@ -316,22 +280,22 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
// succeed, and seems harmless enough.
ext.ModTime = hdr.ModTime
// The spec asks that we namespace our pseudo files
- // with the current pid. However, this results in differing outputs
- // for identical inputs. As such, the constant 0 is now used instead.
+ // with the current pid. However, this results in differing outputs
+ // for identical inputs. As such, the constant 0 is now used instead.
// golang.org/issue/12358
dir, file := path.Split(hdr.Name)
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
var buf bytes.Buffer
// Keys are sorted before writing to body to allow deterministic output.
- var keys []string
+ keys := make([]string, 0, len(paxHeaders))
for k := range paxHeaders {
keys = append(keys, k)
}
@@ -354,22 +318,6 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
return nil
}
-// formatPAXRecord formats a single PAX record, prefixing it with the
-// appropriate length.
-func formatPAXRecord(k, v string) string {
- const padding = 3 // Extra padding for ' ', '=', and '\n'
- size := len(k) + len(v) + padding
- size += len(strconv.Itoa(size))
- record := fmt.Sprintf("%d %s=%s\n", size, k, v)
-
- // Final adjustment if adding size field increased the record size.
- if len(record) != size {
- size = len(record)
- record = fmt.Sprintf("%d %s=%s\n", size, k, v)
- }
- return record
-}
-
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.
@@ -407,7 +355,7 @@ func (tw *Writer) Close() error {
// trailer: two zero blocks
for i := 0; i < 2; i++ {
- _, tw.err = tw.w.Write(zeroBlock)
+ _, tw.err = tw.w.Write(zeroBlock[:])
if tw.err != nil {
break
}
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
index 6e91d907ce..d88b8f41ca 100644
--- a/libgo/go/archive/tar/writer_test.go
+++ b/libgo/go/archive/tar/writer_test.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "math"
"os"
"reflect"
"sort"
@@ -19,176 +18,6 @@ import (
"time"
)
-type writerTestEntry struct {
- header *Header
- contents string
-}
-
-type writerTest struct {
- file string // filename of expected output
- entries []*writerTestEntry
-}
-
-var writerTests = []*writerTest{
- // The writer test file was produced with this command:
- // tar (GNU tar) 1.26
- // ln -s small.txt link.txt
- // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
- {
- file: "testdata/writer.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1246508266, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Kilts",
- },
- {
- header: &Header{
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1245217492, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Google.com\n",
- },
- {
- header: &Header{
- Name: "link.txt",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Size: 0,
- ModTime: time.Unix(1314603082, 0),
- Typeflag: '2',
- Linkname: "small.txt",
- Uname: "strings",
- Gname: "strings",
- },
- // no contents
- },
- },
- },
- // The truncated test file was produced using these commands:
- // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
- // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
- {
- file: "testdata/writer-big.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "tmp/16gig.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 16 << 30,
- ModTime: time.Unix(1254699560, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // The truncated test file was produced using these commands:
- // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
- // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
- {
- file: "testdata/writer-big-long.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "16gig.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 1000,
- Size: 16 << 30,
- ModTime: time.Unix(1399583047, 0),
- Typeflag: '0',
- Uname: "guillaume",
- Gname: "guillaume",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // This file was produced using gnu tar 1.17
- // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
- {
- file: "testdata/ustar.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "file.txt",
- Mode: 0644,
- Uid: 0765,
- Gid: 024,
- Size: 06,
- ModTime: time.Unix(1360135598, 0),
- Typeflag: '0',
- Uname: "shane",
- Gname: "staff",
- },
- contents: "hello\n",
- },
- },
- },
- // This file was produced using gnu tar 1.26
- // echo "Slartibartfast" > file.txt
- // ln file.txt hard.txt
- // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
- {
- file: "testdata/hardlink.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "file.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 100,
- Size: 15,
- ModTime: time.Unix(1425484303, 0),
- Typeflag: '0',
- Uname: "vbatts",
- Gname: "users",
- },
- contents: "Slartibartfast\n",
- },
- {
- header: &Header{
- Name: "hard.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 100,
- Size: 0,
- ModTime: time.Unix(1425484303, 0),
- Typeflag: '1',
- Linkname: "file.txt",
- Uname: "vbatts",
- Gname: "users",
- },
- // no contents
- },
- },
- },
-}
-
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
func bytestr(offset int, b []byte) string {
const rowLen = 32
@@ -228,9 +57,168 @@ func bytediff(a []byte, b []byte) string {
}
func TestWriter(t *testing.T) {
+ type entry struct {
+ header *Header
+ contents string
+ }
+
+ vectors := []struct {
+ file string // filename of expected output
+ entries []*entry
+ }{{
+ // The writer test file was produced with this command:
+ // tar (GNU tar) 1.26
+ // ln -s small.txt link.txt
+ // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
+ file: "testdata/writer.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1246508266, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ }, {
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1245217492, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ }, {
+ header: &Header{
+ Name: "link.txt",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 0,
+ ModTime: time.Unix(1314603082, 0),
+ Typeflag: '2',
+ Linkname: "small.txt",
+ Uname: "strings",
+ Gname: "strings",
+ },
+ // no contents
+ }},
+ }, {
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ file: "testdata/writer-big.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1254699560, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ }},
+ }, {
+ // This truncated file was produced using this library.
+ // It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2.
+ // dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar
+ // gnutar -xvf writer-big-long.tar
+ // bsdtar -xvf writer-big-long.tar
+ //
+ // This file is in PAX format.
+ file: "testdata/writer-big-long.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "16gig.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1399583047, 0),
+ Typeflag: '0',
+ Uname: "guillaume",
+ Gname: "guillaume",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ }},
+ }, {
+ // TODO(dsnet): The Writer output should match the following file.
+ // To fix an issue (see https://golang.org/issue/12594), we disabled
+ // prefix support, which alters the generated output.
+ /*
+ // This file was produced using gnu tar 1.17
+ // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
+ file: "testdata/ustar.tar"
+ */
+ file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected
+ entries: []*entry{{
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "file.txt",
+ Mode: 0644,
+ Uid: 0765,
+ Gid: 024,
+ Size: 06,
+ ModTime: time.Unix(1360135598, 0),
+ Typeflag: '0',
+ Uname: "shane",
+ Gname: "staff",
+ },
+ contents: "hello\n",
+ }},
+ }, {
+ // This file was produced using gnu tar 1.26
+ // echo "Slartibartfast" > file.txt
+ // ln file.txt hard.txt
+ // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
+ file: "testdata/hardlink.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "file.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 100,
+ Size: 15,
+ ModTime: time.Unix(1425484303, 0),
+ Typeflag: '0',
+ Uname: "vbatts",
+ Gname: "users",
+ },
+ contents: "Slartibartfast\n",
+ }, {
+ header: &Header{
+ Name: "hard.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 100,
+ Size: 0,
+ ModTime: time.Unix(1425484303, 0),
+ Typeflag: '1',
+ Linkname: "file.txt",
+ Uname: "vbatts",
+ Gname: "users",
+ },
+ // no contents
+ }},
+ }}
+
testLoop:
- for i, test := range writerTests {
- expected, err := ioutil.ReadFile(test.file)
+ for i, v := range vectors {
+ expected, err := ioutil.ReadFile(v.file)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
@@ -239,7 +227,7 @@ testLoop:
buf := new(bytes.Buffer)
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
big := false
- for j, entry := range test.entries {
+ for j, entry := range v.entries {
big = big || entry.header.Size > 1<<10
if err := tw.WriteHeader(entry.header); err != nil {
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
@@ -576,9 +564,9 @@ func TestWriteAfterClose(t *testing.T) {
}
func TestSplitUSTARPath(t *testing.T) {
- var sr = strings.Repeat
+ sr := strings.Repeat
- var vectors = []struct {
+ vectors := []struct {
input string // Input path
prefix string // Expected output prefix
suffix string // Expected output suffix
@@ -587,17 +575,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 {
@@ -609,114 +597,51 @@ func TestSplitUSTARPath(t *testing.T) {
}
}
-func TestFormatPAXRecord(t *testing.T) {
- var medName = strings.Repeat("CD", 50)
- var longName = strings.Repeat("AB", 100)
-
- var vectors = []struct {
- inputKey string
- inputVal string
- output string
- }{
- {"k", "v", "6 k=v\n"},
- {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
- {"path", longName, "210 path=" + longName + "\n"},
- {"path", medName, "110 path=" + medName + "\n"},
- {"foo", "ba", "9 foo=ba\n"},
- {"foo", "bar", "11 foo=bar\n"},
- {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
- {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
- {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
- {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
- }
-
- for _, v := range vectors {
- output := formatPAXRecord(v.inputKey, v.inputVal)
- if output != v.output {
- t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
- v.inputKey, v.inputVal, output, v.output)
+// TestIssue12594 tests that the Writer does not attempt to populate the prefix
+// field when encoding a header in the GNU format. The prefix field is valid
+// in USTAR and PAX, but not GNU.
+func TestIssue12594(t *testing.T) {
+ names := []string{
+ "0/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/26/27/28/29/30/file.txt",
+ "0/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/26/27/28/29/30/31/32/33/file.txt",
+ "0/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/26/27/28/29/30/31/32/333/file.txt",
+ "0/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/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
+ "/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
+ }
+
+ for i, name := range names {
+ var b bytes.Buffer
+
+ tw := NewWriter(&b)
+ if err := tw.WriteHeader(&Header{
+ Name: name,
+ Uid: 1 << 25, // Prevent USTAR format
+ }); err != nil {
+ t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
}
- }
-}
-
-func TestFitsInBase256(t *testing.T) {
- var vectors = []struct {
- input int64
- width int
- ok bool
- }{
- {+1, 8, true},
- {0, 8, true},
- {-1, 8, true},
- {1 << 56, 8, false},
- {(1 << 56) - 1, 8, true},
- {-1 << 56, 8, true},
- {(-1 << 56) - 1, 8, false},
- {121654, 8, true},
- {-9849849, 8, true},
- {math.MaxInt64, 9, true},
- {0, 9, true},
- {math.MinInt64, 9, true},
- {math.MaxInt64, 12, true},
- {0, 12, true},
- {math.MinInt64, 12, true},
- }
-
- for _, v := range vectors {
- ok := fitsInBase256(v.width, v.input)
- if ok != v.ok {
- t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
+ if err := tw.Close(); err != nil {
+ t.Errorf("test %d, unexpected Close error: %v", i, err)
}
- }
-}
-func TestFormatNumeric(t *testing.T) {
- var vectors = []struct {
- input int64
- output string
- ok bool
- }{
- // Test base-256 (binary) encoded values.
- {-1, "\xff", true},
- {-1, "\xff\xff", true},
- {-1, "\xff\xff\xff", true},
- {(1 << 0), "0", false},
- {(1 << 8) - 1, "\x80\xff", true},
- {(1 << 8), "0\x00", false},
- {(1 << 16) - 1, "\x80\xff\xff", true},
- {(1 << 16), "00\x00", false},
- {-1 * (1 << 0), "\xff", true},
- {-1*(1<<0) - 1, "0", false},
- {-1 * (1 << 8), "\xff\x00", true},
- {-1*(1<<8) - 1, "0\x00", false},
- {-1 * (1 << 16), "\xff\x00\x00", true},
- {-1*(1<<16) - 1, "00\x00", false},
- {537795476381659745, "0000000\x00", false},
- {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
- {-615126028225187231, "0000000\x00", false},
- {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
- {math.MaxInt64, "0000000\x00", false},
- {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
- {math.MinInt64, "0000000\x00", false},
- {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
- {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
- {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
- }
+ // The prefix field should never appear in the GNU format.
+ var blk block
+ copy(blk[:], b.Bytes())
+ prefix := string(blk.USTAR().Prefix())
+ if i := strings.IndexByte(prefix, 0); i >= 0 {
+ prefix = prefix[:i] // Truncate at the NUL terminator
+ }
+ if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
+ t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
+ }
- for _, v := range vectors {
- var f formatter
- output := make([]byte, len(v.output))
- f.formatNumeric(output, v.input)
- ok := (f.err == nil)
- if ok != v.ok {
- if v.ok {
- t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
- } else {
- t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
- }
+ tr := NewReader(&b)
+ hdr, err := tr.Next()
+ if err != nil {
+ t.Errorf("test %d, unexpected Next error: %v", i, err)
}
- if string(output) != v.output {
- t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
+ if hdr.Name != name {
+ t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
}
}
}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index 10e8172875..f6c3ead3be 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -87,7 +87,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
z.File = make([]*File, 0, end.directoryRecords)
z.Comment = end.comment
rs := io.NewSectionReader(r, 0, size)
- if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
+ if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
return err
}
buf := bufio.NewReader(rs)
@@ -153,19 +153,18 @@ func (f *File) DataOffset() (offset int64, err error) {
// Open returns a ReadCloser that provides access to the File's contents.
// Multiple files may be read concurrently.
-func (f *File) Open() (rc io.ReadCloser, err error) {
+func (f *File) Open() (io.ReadCloser, error) {
bodyOffset, err := f.findBodyOffset()
if err != nil {
- return
+ return nil, err
}
size := int64(f.CompressedSize64)
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
dcomp := f.zip.decompressor(f.Method)
if dcomp == nil {
- err = ErrAlgorithm
- return
+ return nil, ErrAlgorithm
}
- rc = dcomp(r)
+ var rc io.ReadCloser = dcomp(r)
var desr io.Reader
if f.hasDataDescriptor() {
desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
@@ -176,7 +175,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
f: f,
desr: desr,
}
- return
+ return rc, nil
}
type checksumReader struct {
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index 72cf5d9cf4..dfaae78436 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -399,7 +399,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
// Don't bother uncompressing: too big.
if ft.Content == nil && ft.File == "" && ft.Size > 0 {
if size != ft.Size {
- t.Errorf("%v: uncompressed size %#x, want %#x", size, ft.Size)
+ t.Errorf("%v: uncompressed size %#x, want %#x", ft.Name, size, ft.Size)
}
r.Close()
return
diff --git a/libgo/go/archive/zip/register.go b/libgo/go/archive/zip/register.go
index 8fccbf7ca0..2e76386b1f 100644
--- a/libgo/go/archive/zip/register.go
+++ b/libgo/go/archive/zip/register.go
@@ -64,6 +64,44 @@ func (w *pooledFlateWriter) Close() error {
return err
}
+var flateReaderPool sync.Pool
+
+func newFlateReader(r io.Reader) io.ReadCloser {
+ fr, ok := flateReaderPool.Get().(io.ReadCloser)
+ if ok {
+ fr.(flate.Resetter).Reset(r, nil)
+ } else {
+ fr = flate.NewReader(r)
+ }
+ return &pooledFlateReader{fr: fr}
+}
+
+type pooledFlateReader struct {
+ mu sync.Mutex // guards Close and Read
+ fr io.ReadCloser
+}
+
+func (r *pooledFlateReader) Read(p []byte) (n int, err error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.fr == nil {
+ return 0, errors.New("Read after Close")
+ }
+ return r.fr.Read(p)
+}
+
+func (r *pooledFlateReader) Close() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ var err error
+ if r.fr != nil {
+ err = r.fr.Close()
+ flateReaderPool.Put(r.fr)
+ r.fr = nil
+ }
+ return err
+}
+
var (
mu sync.RWMutex // guards compressor and decompressor maps
@@ -74,7 +112,7 @@ var (
decompressors = map[uint16]Decompressor{
Store: ioutil.NopCloser,
- Deflate: flate.NewReader,
+ Deflate: newFlateReader,
}
)
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index 5ee4f88f80..e92d02f8a2 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -5,7 +5,7 @@
/*
Package zip provides support for reading and writing ZIP archives.
-See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
This package does not support disk spanning.
diff --git a/libgo/go/archive/zip/testdata/readme.notzip b/libgo/go/archive/zip/testdata/readme.notzip
index 06668c4c1c..81737275c6 100644
--- a/libgo/go/archive/zip/testdata/readme.notzip
+++ b/libgo/go/archive/zip/testdata/readme.notzip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/readme.zip b/libgo/go/archive/zip/testdata/readme.zip
index db3bb900e4..5642a67e77 100644
--- a/libgo/go/archive/zip/testdata/readme.zip
+++ b/libgo/go/archive/zip/testdata/readme.zip
Binary files differ
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index 5ce66e6be5..8940e25560 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -22,6 +22,10 @@ type Writer struct {
last *fileWriter
closed bool
compressors map[uint16]Compressor
+
+ // testHookCloseSizeOffset if non-nil is called with the size
+ // of offset of the central directory at Close.
+ testHookCloseSizeOffset func(size, offset uint64)
}
type header struct {
@@ -52,7 +56,7 @@ func (w *Writer) Flush() error {
}
// Close finishes writing the zip file by writing the central directory.
-// It does not (and can not) close the underlying writer.
+// It does not (and cannot) close the underlying writer.
func (w *Writer) Close() error {
if w.last != nil && !w.last.closed {
if err := w.last.close(); err != nil {
@@ -98,6 +102,7 @@ func (w *Writer) Close() error {
b.uint32(h.CompressedSize)
b.uint32(h.UncompressedSize)
}
+
b.uint16(uint16(len(h.Name)))
b.uint16(uint16(len(h.Extra)))
b.uint16(uint16(len(h.Comment)))
@@ -127,7 +132,11 @@ func (w *Writer) Close() error {
size := uint64(end - start)
offset := uint64(start)
- if records > uint16max || size > uint32max || offset > uint32max {
+ if f := w.testHookCloseSizeOffset; f != nil {
+ f(size, offset)
+ }
+
+ if records >= uint16max || size >= uint32max || offset >= uint32max {
var buf [directory64EndLen + directory64LocLen]byte
b := writeBuf(buf[:])
diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go
index 01b63f2358..86841c755f 100644
--- a/libgo/go/archive/zip/writer_test.go
+++ b/libgo/go/archive/zip/writer_test.go
@@ -184,7 +184,7 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
b.ReportAllocs()
var buf bytes.Buffer
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
- for i := 0; i < b.N; i++ {
+ for i := 0; i <= b.N; i++ {
buf.Reset()
zw := NewWriter(&buf)
for j := 0; j < 3; j++ {
@@ -195,5 +195,11 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
w.Write(bigBuf)
}
zw.Close()
+ if i == 0 {
+ // Reset the timer after the first time through.
+ // This effectively discards the very large initial flate setup cost,
+ // as well as the initialization of bigBuf.
+ b.ResetTimer()
+ }
}
}
diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go
index f785abf50a..57edb2cabf 100644
--- a/libgo/go/archive/zip/zip_test.go
+++ b/libgo/go/archive/zip/zip_test.go
@@ -8,8 +8,10 @@ package zip
import (
"bytes"
+ "errors"
"fmt"
"hash"
+ "internal/race"
"internal/testenv"
"io"
"io/ioutil"
@@ -232,6 +234,7 @@ func TestZip64(t *testing.T) {
if testing.Short() {
t.Skip("slow test; skipping")
}
+ t.Parallel()
const size = 1 << 32 // before the "END\n" part
buf := testZip64(t, size)
testZip64DirectoryRecordLength(buf, t)
@@ -241,6 +244,7 @@ func TestZip64EdgeCase(t *testing.T) {
if testing.Short() {
t.Skip("slow test; skipping")
}
+ t.Parallel()
// Test a zip file with uncompressed size 0xFFFFFFFF.
// That's the magic marker for a 64-bit file, so even though
// it fits in a 32-bit field we must use the 64-bit field.
@@ -251,6 +255,256 @@ func TestZip64EdgeCase(t *testing.T) {
testZip64DirectoryRecordLength(buf, t)
}
+// Tests that we generate a zip64 file if the the directory at offset
+// 0xFFFFFFFF, but not before.
+func TestZip64DirectoryOffset(t *testing.T) {
+ if testing.Short() && race.Enabled {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ const filename = "huge.txt"
+ gen := func(wantOff uint64) func(*Writer) {
+ return func(w *Writer) {
+ w.testHookCloseSizeOffset = func(size, off uint64) {
+ if off != wantOff {
+ t.Errorf("central directory offset = %d (%x); want %d", off, off, wantOff)
+ }
+ }
+ f, err := w.CreateHeader(&FileHeader{
+ Name: filename,
+ Method: Store,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.(*fileWriter).crc32 = fakeHash32{}
+ size := wantOff - fileHeaderLen - uint64(len(filename)) - dataDescriptorLen
+ if _, err := io.CopyN(f, zeros{}, int64(size)); err != nil {
+ t.Fatal(err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ t.Run("uint32max-2_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(0xfffffffe)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ t.Run("uint32max-1_Zip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(0xffffffff)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
+// At 16k records, we need to generate a zip64 file.
+func TestZip64ManyRecords(t *testing.T) {
+ if testing.Short() && race.Enabled {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ gen := func(numRec int) func(*Writer) {
+ return func(w *Writer) {
+ for i := 0; i < numRec; i++ {
+ _, err := w.CreateHeader(&FileHeader{
+ Name: "a.txt",
+ Method: Store,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ // 16k-1 records shouldn't make a zip64:
+ t.Run("uint16max-1_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(0xfffe)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ // 16k records should make a zip64:
+ t.Run("uint16max_Zip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(0xffff)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
+// suffixSaver is an io.Writer & io.ReaderAt that remembers the last 0
+// to 'keep' bytes of data written to it. Call Suffix to get the
+// suffix bytes.
+type suffixSaver struct {
+ keep int
+ buf []byte
+ start int
+ size int64
+}
+
+func (ss *suffixSaver) Size() int64 { return ss.size }
+
+var errDiscardedBytes = errors.New("ReadAt of discarded bytes")
+
+func (ss *suffixSaver) ReadAt(p []byte, off int64) (n int, err error) {
+ back := ss.size - off
+ if back > int64(ss.keep) {
+ return 0, errDiscardedBytes
+ }
+ suf := ss.Suffix()
+ n = copy(p, suf[len(suf)-int(back):])
+ if n != len(p) {
+ err = io.EOF
+ }
+ return
+}
+
+func (ss *suffixSaver) Suffix() []byte {
+ if len(ss.buf) < ss.keep {
+ return ss.buf
+ }
+ buf := make([]byte, ss.keep)
+ n := copy(buf, ss.buf[ss.start:])
+ copy(buf[n:], ss.buf[:])
+ return buf
+}
+
+func (ss *suffixSaver) Write(p []byte) (n int, err error) {
+ n = len(p)
+ ss.size += int64(len(p))
+ if len(ss.buf) < ss.keep {
+ space := ss.keep - len(ss.buf)
+ add := len(p)
+ if add > space {
+ add = space
+ }
+ ss.buf = append(ss.buf, p[:add]...)
+ p = p[add:]
+ }
+ for len(p) > 0 {
+ n := copy(ss.buf[ss.start:], p)
+ p = p[n:]
+ ss.start += n
+ if ss.start == ss.keep {
+ ss.start = 0
+ }
+ }
+ return
+}
+
+// generatesZip64 reports whether f wrote a zip64 file.
+// f is also responsible for closing w.
+func generatesZip64(t *testing.T, f func(w *Writer)) bool {
+ ss := &suffixSaver{keep: 10 << 20}
+ w := NewWriter(ss)
+ f(w)
+ return suffixIsZip64(t, ss)
+}
+
+type sizedReaderAt interface {
+ io.ReaderAt
+ Size() int64
+}
+
+func suffixIsZip64(t *testing.T, zip sizedReaderAt) bool {
+ d := make([]byte, 1024)
+ if _, err := zip.ReadAt(d, zip.Size()-int64(len(d))); err != nil {
+ t.Fatalf("ReadAt: %v", err)
+ }
+
+ sigOff := findSignatureInBlock(d)
+ if sigOff == -1 {
+ t.Errorf("failed to find signature in block")
+ return false
+ }
+
+ dirOff, err := findDirectory64End(zip, zip.Size()-int64(len(d))+int64(sigOff))
+ if err != nil {
+ t.Fatalf("findDirectory64End: %v", err)
+ }
+ if dirOff == -1 {
+ return false
+ }
+
+ d = make([]byte, directory64EndLen)
+ if _, err := zip.ReadAt(d, dirOff); err != nil {
+ t.Fatalf("ReadAt(off=%d): %v", dirOff, err)
+ }
+
+ b := readBuf(d)
+ if sig := b.uint32(); sig != directory64EndSignature {
+ return false
+ }
+
+ size := b.uint64()
+ if size != directory64EndLen-12 {
+ t.Errorf("expected length of %d, got %d", directory64EndLen-12, size)
+ }
+ return true
+}
+
+// Zip64 is required if the total size of the records is uint32max.
+func TestZip64LargeDirectory(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ // gen returns a func that writes a zip with a wantLen bytes
+ // of central directory.
+ gen := func(wantLen int64) func(*Writer) {
+ return func(w *Writer) {
+ w.testHookCloseSizeOffset = func(size, off uint64) {
+ if size != uint64(wantLen) {
+ t.Errorf("Close central directory size = %d; want %d", size, wantLen)
+ }
+ }
+
+ uint16string := strings.Repeat(".", uint16max)
+ remain := wantLen
+ for remain > 0 {
+ commentLen := int(uint16max) - directoryHeaderLen - 1
+ thisRecLen := directoryHeaderLen + int(uint16max) + commentLen
+ if int64(thisRecLen) > remain {
+ remove := thisRecLen - int(remain)
+ commentLen -= remove
+ thisRecLen -= remove
+ }
+ remain -= int64(thisRecLen)
+ f, err := w.CreateHeader(&FileHeader{
+ Name: uint16string,
+ Comment: uint16string[:commentLen],
+ })
+ if err != nil {
+ t.Fatalf("CreateHeader: %v", err)
+ }
+ f.(*fileWriter).crc32 = fakeHash32{}
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ }
+ }
+ t.Run("uint32max-1_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(uint32max-1)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ t.Run("uint32max_HasZip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(uint32max)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
func testZip64(t testing.TB, size int64) *rleBuffer {
const chunkSize = 1024
chunks := int(size / chunkSize)
@@ -339,51 +593,8 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
// Issue 9857
func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
- d := make([]byte, 1024)
- if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
- t.Fatal("read:", err)
- }
-
- sigOff := findSignatureInBlock(d)
- dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
- if err != nil {
- t.Fatal("findDirectory64End:", err)
- }
-
- d = make([]byte, directory64EndLen)
- if _, err := buf.ReadAt(d, dirOff); err != nil {
- t.Fatal("read:", err)
- }
-
- b := readBuf(d)
- if sig := b.uint32(); sig != directory64EndSignature {
- t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
- }
-
- size := b.uint64()
- if size != directory64EndLen-12 {
- t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
- }
-}
-
-func testInvalidHeader(h *FileHeader, t *testing.T) {
- var buf bytes.Buffer
- z := NewWriter(&buf)
-
- f, err := z.CreateHeader(h)
- if err != nil {
- t.Fatalf("error creating header: %v", err)
- }
- if _, err := f.Write([]byte("hi")); err != nil {
- t.Fatalf("error writing content: %v", err)
- }
- if err := z.Close(); err != nil {
- t.Fatalf("error closing zip writer: %v", err)
- }
-
- b := buf.Bytes()
- if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != ErrFormat {
- t.Fatalf("got %v, expected ErrFormat", err)
+ if !suffixIsZip64(t, buf) {
+ t.Fatal("not a zip64")
}
}
@@ -469,3 +680,47 @@ func BenchmarkZip64Test(b *testing.B) {
testZip64(b, 1<<26)
}
}
+
+func TestSuffixSaver(t *testing.T) {
+ const keep = 10
+ ss := &suffixSaver{keep: keep}
+ ss.Write([]byte("abc"))
+ if got := string(ss.Suffix()); got != "abc" {
+ t.Errorf("got = %q; want abc", got)
+ }
+ ss.Write([]byte("defghijklmno"))
+ if got := string(ss.Suffix()); got != "fghijklmno" {
+ t.Errorf("got = %q; want fghijklmno", got)
+ }
+ if got, want := ss.Size(), int64(len("abc")+len("defghijklmno")); got != want {
+ t.Errorf("Size = %d; want %d", got, want)
+ }
+ buf := make([]byte, ss.Size())
+ for off := int64(0); off < ss.Size(); off++ {
+ for size := 1; size <= int(ss.Size()-off); size++ {
+ readBuf := buf[:size]
+ n, err := ss.ReadAt(readBuf, off)
+ if off < ss.Size()-keep {
+ if err != errDiscardedBytes {
+ t.Errorf("off %d, size %d = %v, %v (%q); want errDiscardedBytes", off, size, n, err, readBuf[:n])
+ }
+ continue
+ }
+ want := "abcdefghijklmno"[off : off+int64(size)]
+ got := string(readBuf[:n])
+ if err != nil || got != want {
+ t.Errorf("off %d, size %d = %v, %v (%q); want %q", off, size, n, err, got, want)
+ }
+ }
+ }
+
+}
+
+type zeros struct{}
+
+func (zeros) Read(p []byte) (int, error) {
+ for i := range p {
+ p[i] = 0
+ }
+ return len(p), nil
+}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index 6a70f7034d..e1e8fb2272 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -124,14 +124,16 @@ func (b *Reader) Peek(n int) ([]byte, error) {
if n < 0 {
return nil, ErrNegativeCount
}
- if n > len(b.buf) {
- return nil, ErrBufferFull
- }
- // 0 <= n <= len(b.buf)
- for b.w-b.r < n && b.err == nil {
+
+ for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
+ if n > len(b.buf) {
+ return b.buf[b.r:b.w], ErrBufferFull
+ }
+
+ // 0 <= n <= len(b.buf)
var err error
if avail := b.w - b.r; avail < n {
// not enough data in buffer
@@ -204,10 +206,18 @@ func (b *Reader) Read(p []byte) (n int, err error) {
}
return n, b.readErr()
}
- b.fill() // buffer is empty
- if b.r == b.w {
+ // One read.
+ // Do not use b.fill, which will loop.
+ b.r = 0
+ b.w = 0
+ n, b.err = b.rd.Read(b.buf)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ if n == 0 {
return 0, b.readErr()
}
+ b.w += n
}
// copy as much as we can
@@ -220,7 +230,7 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
-func (b *Reader) ReadByte() (c byte, err error) {
+func (b *Reader) ReadByte() (byte, error) {
b.lastRuneSize = -1
for b.r == b.w {
if b.err != nil {
@@ -228,13 +238,13 @@ func (b *Reader) ReadByte() (c byte, err error) {
}
b.fill() // buffer is empty
}
- c = b.buf[b.r]
+ c := b.buf[b.r]
b.r++
b.lastByte = int(c)
return c, nil
}
-// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
+// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
func (b *Reader) UnreadByte() error {
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
return ErrInvalidUnreadByte
@@ -264,7 +274,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
return 0, 0, b.readErr()
}
r, size = rune(b.buf[b.r]), 1
- if r >= 0x80 {
+ if r >= utf8.RuneSelf {
r, size = utf8.DecodeRune(b.buf[b.r:b.w])
}
b.r += size
@@ -273,7 +283,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
return r, size, nil
}
-// UnreadRune unreads the last rune. If the most recent read operation on
+// UnreadRune unreads the last rune. If the most recent read operation on
// the buffer was not a ReadRune, UnreadRune returns an error. (In this
// regard it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
@@ -395,12 +405,12 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
// For simple uses, a Scanner may be more convenient.
-func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
+func (b *Reader) ReadBytes(delim byte) ([]byte, error) {
// Use ReadSlice to look for array,
// accumulating full buffers.
var frag []byte
var full [][]byte
-
+ var err error
for {
var e error
frag, e = b.ReadSlice(delim)
@@ -442,10 +452,9 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// ReadString returns err != nil if and only if the returned data does not end in
// delim.
// For simple uses, a Scanner may be more convenient.
-func (b *Reader) ReadString(delim byte) (line string, err error) {
+func (b *Reader) ReadString(delim byte) (string, error) {
bytes, err := b.ReadBytes(delim)
- line = string(bytes)
- return line, err
+ return string(bytes), err
}
// WriteTo implements io.WriterTo.
@@ -548,11 +557,6 @@ func (b *Writer) Reset(w io.Writer) {
// Flush writes any buffered data to the underlying io.Writer.
func (b *Writer) Flush() error {
- err := b.flush()
- return err
-}
-
-func (b *Writer) flush() error {
if b.err != nil {
return b.err
}
@@ -595,7 +599,7 @@ func (b *Writer) Write(p []byte) (nn int, err error) {
} else {
n = copy(b.buf[b.n:], p)
b.n += n
- b.flush()
+ b.Flush()
}
nn += n
p = p[n:]
@@ -614,7 +618,7 @@ func (b *Writer) WriteByte(c byte) error {
if b.err != nil {
return b.err
}
- if b.Available() <= 0 && b.flush() != nil {
+ if b.Available() <= 0 && b.Flush() != nil {
return b.err
}
b.buf[b.n] = c
@@ -637,7 +641,7 @@ func (b *Writer) WriteRune(r rune) (size int, err error) {
}
n := b.Available()
if n < utf8.UTFMax {
- if b.flush(); b.err != nil {
+ if b.Flush(); b.err != nil {
return 0, b.err
}
n = b.Available()
@@ -662,7 +666,7 @@ func (b *Writer) WriteString(s string) (int, error) {
b.n += n
nn += n
s = s[n:]
- b.flush()
+ b.Flush()
}
if b.err != nil {
return nn, b.err
@@ -683,7 +687,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
var m int
for {
if b.Available() == 0 {
- if err1 := b.flush(); err1 != nil {
+ if err1 := b.Flush(); err1 != nil {
return n, err1
}
}
@@ -705,9 +709,9 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
}
}
if err == io.EOF {
- // If we filled the buffer exactly, flush pre-emptively.
+ // If we filled the buffer exactly, flush preemptively.
if b.Available() == 0 {
- err = b.flush()
+ err = b.Flush()
} else {
err = nil
}
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 666c44e15a..ef0f6c834e 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -673,8 +673,8 @@ func TestPeek(t *testing.T) {
if _, err := buf.Peek(-1); err != ErrNegativeCount {
t.Fatalf("want ErrNegativeCount got %v", err)
}
- if _, err := buf.Peek(32); err != ErrBufferFull {
- t.Fatalf("want ErrBufFull got %v", err)
+ if s, err := buf.Peek(32); string(s) != "abcdefghijklmnop" || err != ErrBufferFull {
+ t.Fatalf("want %q, ErrBufFull got %q, err=%v", "abcdefghijklmnop", string(s), err)
}
if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
@@ -1236,6 +1236,27 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
}
}
+func TestReadZero(t *testing.T) {
+ for _, size := range []int{100, 2} {
+ t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
+ r := io.MultiReader(strings.NewReader("abc"), &emptyThenNonEmptyReader{r: strings.NewReader("def"), n: 1})
+ br := NewReaderSize(r, size)
+ want := func(s string, wantErr error) {
+ p := make([]byte, 50)
+ n, err := br.Read(p)
+ if err != wantErr || n != len(s) || string(p[:n]) != s {
+ t.Fatalf("read(%d) = %q, %v, want %q, %v", len(p), string(p[:n]), err, s, wantErr)
+ }
+ t.Logf("read(%d) = %q, %v", len(p), string(p[:n]), err)
+ }
+ want("abc", nil)
+ want("", nil)
+ want("def", nil)
+ want("", io.EOF)
+ })
+ }
+}
+
func TestReaderReset(t *testing.T) {
r := NewReader(strings.NewReader("foo foo"))
buf := make([]byte, 3)
@@ -1475,7 +1496,7 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
}
for i := 0; i < b.N; i++ {
- r.Seek(0, 0)
+ r.Seek(0, io.SeekStart)
srcReader.Reset(onlyReader{r})
n, err := srcReader.WriteTo(ioutil.Discard)
if err != nil {
diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go
index 27a0f00459..9f741c9830 100644
--- a/libgo/go/bufio/scan.go
+++ b/libgo/go/bufio/scan.go
@@ -199,7 +199,6 @@ func (s *Scanner) Scan() bool {
s.buf = newBuf
s.end -= s.start
s.start = 0
- continue
}
// Finally we can read some input. Make sure we don't get stuck with
// a misbehaving Reader. Officially we don't need to do this, but let's
diff --git a/libgo/go/bufio/scan_test.go b/libgo/go/bufio/scan_test.go
index 07b1a56dc0..1bb1e88393 100644
--- a/libgo/go/bufio/scan_test.go
+++ b/libgo/go/bufio/scan_test.go
@@ -264,10 +264,6 @@ func testNoNewline(text string, lines []string, t *testing.T) {
}
}
-var noNewlineLines = []string{
- "abcdefghijklmn\nopqrstuvwxyz",
-}
-
// Test that the line splitter handles a final line without a newline.
func TestScanLineNoNewline(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz"
@@ -351,7 +347,7 @@ func TestSplitError(t *testing.T) {
// Test that an EOF is overridden by a user-generated scan error.
func TestErrAtEOF(t *testing.T) {
s := NewScanner(strings.NewReader("1 2 33"))
- // This spitter will fail on last entry, after s.err==EOF.
+ // This splitter will fail on last entry, after s.err==EOF.
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
advance, token, err = ScanWords(data, atEOF)
if len(token) > 1 {
diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go
index d63ad22c32..281de0b436 100644
--- a/libgo/go/builtin/builtin.go
+++ b/libgo/go/builtin/builtin.go
@@ -173,8 +173,8 @@ func cap(v Type) int
// specify a different capacity; it must be no smaller than the
// length, so make([]int, 0, 10) allocates a slice of length 0 and
// capacity 10.
-// Map: An initial allocation is made according to the size but the
-// resulting map has length 0. The size may be omitted, in which case
+// Map: An empty map is allocated with enough space to hold the
+// specified number of elements. The size may be omitted, in which case
// a small starting size is allocated.
// Channel: The channel's buffer is initialized with the specified
// buffer capacity. If zero, or the size is omitted, the channel is
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
index ddaba3bff3..196419dc3d 100644
--- a/libgo/go/bytes/buffer.go
+++ b/libgo/go/bytes/buffer.go
@@ -15,22 +15,25 @@ import (
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
- buf []byte // contents are the bytes buf[off : len(buf)]
- off int // read at &buf[off], write at &buf[len(buf)]
- runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
- bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation.
- lastRead readOp // last read operation, so that Unread* can work correctly.
+ buf []byte // contents are the bytes buf[off : len(buf)]
+ off int // read at &buf[off], write at &buf[len(buf)]
+ bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
+ lastRead readOp // last read operation, so that Unread* can work correctly.
}
// The readOp constants describe the last action performed on
-// the buffer, so that UnreadRune and UnreadByte can
-// check for invalid usage.
+// the buffer, so that UnreadRune and UnreadByte can check for
+// invalid usage. opReadRuneX constants are chosen such that
+// converted to int they correspond to the rune size that was read.
type readOp int
const (
- opInvalid readOp = iota // Non-read operation.
- opReadRune // Read rune.
- opRead // Any other read operation.
+ opRead readOp = -1 // Any other read operation.
+ opInvalid = 0 // Non-read operation.
+ opReadRune1 = 1 // Read rune of size 1.
+ opReadRune2 = 2 // Read rune of size 2.
+ opReadRune3 = 3 // Read rune of size 3.
+ opReadRune4 = 4 // Read rune of size 4.
)
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
@@ -44,7 +47,7 @@ var ErrTooLarge = errors.New("bytes.Buffer: too large")
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
// String returns the contents of the unread portion of the buffer
-// as a string. If the Buffer is a nil pointer, it returns "<nil>".
+// as a string. If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
if b == nil {
// Special case, useful in debugging.
@@ -145,7 +148,7 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
}
// MinRead is the minimum slice size passed to a Read call by
-// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
+// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512
@@ -246,13 +249,15 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
b.WriteByte(byte(r))
return 1, nil
}
- n = utf8.EncodeRune(b.runeBytes[0:], r)
- b.Write(b.runeBytes[0:n])
+ b.lastRead = opInvalid
+ m := b.grow(utf8.UTFMax)
+ n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
+ b.buf = b.buf[:m+n]
return n, nil
}
// Read reads the next len(p) bytes from the buffer or until the buffer
-// is drained. The return value n is the number of bytes read. If the
+// is drained. The return value n is the number of bytes read. If the
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err error) {
@@ -293,14 +298,14 @@ func (b *Buffer) Next(n int) []byte {
// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error io.EOF.
-func (b *Buffer) ReadByte() (c byte, err error) {
+func (b *Buffer) ReadByte() (byte, error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
return 0, io.EOF
}
- c = b.buf[b.off]
+ c := b.buf[b.off]
b.off++
b.lastRead = opRead
return c, nil
@@ -318,14 +323,15 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
b.Truncate(0)
return 0, 0, io.EOF
}
- b.lastRead = opReadRune
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
+ b.lastRead = opReadRune1
return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.buf[b.off:])
b.off += n
+ b.lastRead = readOp(n)
return r, n, nil
}
@@ -335,22 +341,21 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
- if b.lastRead != opReadRune {
+ if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
- b.lastRead = opInvalid
- if b.off > 0 {
- _, n := utf8.DecodeLastRune(b.buf[0:b.off])
- b.off -= n
+ if b.off >= int(b.lastRead) {
+ b.off -= int(b.lastRead)
}
+ b.lastRead = opInvalid
return nil
}
// UnreadByte unreads the last byte returned by the most recent
-// read operation. If write has happened since the last read, UnreadByte
+// read operation. If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() error {
- if b.lastRead != opReadRune && b.lastRead != opRead {
+ if b.lastRead == opInvalid {
return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
}
b.lastRead = opInvalid
@@ -400,7 +405,7 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
}
// NewBuffer creates and initializes a new Buffer using buf as its initial
-// contents. It is intended to prepare a Buffer to read existing data. It
+// contents. It is intended to prepare a Buffer to read existing data. It
// can also be used to size the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
//
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
index 7de17ae47e..b1b85f979a 100644
--- a/libgo/go/bytes/buffer_test.go
+++ b/libgo/go/bytes/buffer_test.go
@@ -514,6 +514,19 @@ func TestBufferGrowth(t *testing.T) {
}
}
+func BenchmarkWriteRune(b *testing.B) {
+ const n = 4 << 10
+ const r = '☺'
+ b.SetBytes(int64(n * utf8.RuneLen(r)))
+ buf := NewBuffer(make([]byte, n*utf8.UTFMax))
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ for i := 0; i < n; i++ {
+ buf.WriteRune(r)
+ }
+ }
+}
+
// From Issue 5154.
func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
buf := make([]byte, 1024)
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index b86824087e..406a38257a 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -83,35 +83,14 @@ func Contains(b, subslice []byte) bool {
return Index(b, subslice) != -1
}
-// 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 []byte) int {
- n := len(sep)
- if n == 0 {
- return 0
- }
- if n > len(s) {
- return -1
- }
- c := sep[0]
- if n == 1 {
- return IndexByte(s, c)
- }
- i := 0
- t := s[:len(s)-n+1]
- for i < len(t) {
- if t[i] != c {
- o := IndexByte(t[i:], c)
- if o < 0 {
- break
- }
- i += o
- }
- if Equal(s[i:i+n], sep) {
- return i
- }
- i++
- }
- return -1
+// ContainsAny reports whether any of the UTF-8-encoded Unicode code points in chars are within b.
+func ContainsAny(b []byte, chars string) bool {
+ return IndexAny(b, chars) >= 0
+}
+
+// ContainsRune reports whether the Unicode code point r is within b.
+func ContainsRune(b []byte, r rune) bool {
+ return IndexRune(b, r) >= 0
}
func indexBytePortable(s []byte, c byte) int {
@@ -151,27 +130,49 @@ func LastIndexByte(s []byte, c byte) int {
// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index of the first occurrence in s of the given rune.
// It returns -1 if rune is not present in s.
+// If r is utf8.RuneError, it returns the first instance of any
+// invalid UTF-8 byte sequence.
func IndexRune(s []byte, r rune) int {
- for i := 0; i < len(s); {
- r1, size := utf8.DecodeRune(s[i:])
- if r == r1 {
- return i
+ switch {
+ case 0 <= r && r < utf8.RuneSelf:
+ return IndexByte(s, byte(r))
+ case r == utf8.RuneError:
+ for i := 0; i < len(s); {
+ r1, n := utf8.DecodeRune(s[i:])
+ if r1 == utf8.RuneError {
+ return i
+ }
+ i += n
}
- i += size
+ return -1
+ case !utf8.ValidRune(r):
+ return -1
+ default:
+ var b [utf8.UTFMax]byte
+ n := utf8.EncodeRune(b[:], r)
+ return Index(s, b[:n])
}
- return -1
}
// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index of the first occurrence in s of any of the Unicode
-// code points in chars. It returns -1 if chars is empty or if there is no code
+// code points in chars. It returns -1 if chars is empty or if there is no code
// point in common.
func IndexAny(s []byte, chars string) int {
if len(chars) > 0 {
- var r rune
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i, c := range s {
+ if as.contains(c) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
var width int
for i := 0; i < len(s); i += width {
- r = rune(s[i])
+ r := rune(s[i])
if r < utf8.RuneSelf {
width = 1
} else {
@@ -188,16 +189,26 @@ func IndexAny(s []byte, chars string) int {
}
// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
-// points. It returns the byte index of the last occurrence in s of any of
-// the Unicode code points in chars. It returns -1 if chars is empty or if
+// points. It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars. It returns -1 if chars is empty or if
// there is no code point in common.
func LastIndexAny(s []byte, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := len(s) - 1; i >= 0; i-- {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i := len(s); i > 0; {
- r, size := utf8.DecodeLastRune(s[0:i])
+ r, size := utf8.DecodeLastRune(s[:i])
i -= size
- for _, ch := range chars {
- if r == ch {
+ for _, c := range chars {
+ if r == c {
return i
}
}
@@ -276,7 +287,7 @@ func Fields(s []byte) [][]byte {
// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s. If all code points in s satisfy f(c), or
+// returns a slice of subslices of s. If all code points in s satisfy f(c), or
// len(s) == 0, an empty slice is returned.
// FieldsFunc makes no guarantees about the order in which it calls f(c).
// If f does not return consistent results for a given c, FieldsFunc may crash.
@@ -352,12 +363,12 @@ func HasSuffix(s, suffix []byte) bool {
// Map returns a copy of the byte slice s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
-// dropped from the string with no replacement. The characters in s and the
+// dropped from the string with no replacement. The characters in s and the
// output are interpreted as UTF-8-encoded Unicode code points.
func Map(mapping func(r rune) rune, s []byte) []byte {
// In the worst case, the slice can grow when mapped, making
- // things unpleasant. But it's so rare we barge in assuming it's
- // fine. It could also shrink but that falls out naturally.
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
maxbytes := len(s) // length of b
nbytes := 0 // number of bytes encoded in b
b := make([]byte, maxbytes)
@@ -388,7 +399,20 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
}
// Repeat returns a new byte slice consisting of count copies of b.
+//
+// It panics if count is negative or if
+// the result of (len(b) * count) overflows.
func Repeat(b []byte, count int) []byte {
+ // Since we cannot return an error on overflow,
+ // we should panic if the repeat will generate
+ // an overflow.
+ // See Issue golang.org/issue/16237.
+ if count < 0 {
+ panic("bytes: negative Repeat count")
+ } else if count > 0 && len(b)*count/count != len(b) {
+ panic("bytes: Repeat count causes overflow")
+ }
+
nb := make([]byte, len(b)*count)
bp := copy(nb, b)
for bp < len(nb) {
@@ -409,20 +433,20 @@ func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
-func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
+func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
-func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToLower(r) }, s)
+func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
-func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
+func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToTitle(r) }, s)
}
// isSeparator reports whether the rune could mark a word boundary.
@@ -568,7 +592,43 @@ func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
return -1
}
+// asciiSet is a 32-byte value, where each bit represents the presence of a
+// given ASCII character in the set. The 128-bits of the lower 16 bytes,
+// starting with the least-significant bit of the lowest word to the
+// most-significant bit of the highest word, map to the full range of all
+// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
+// ensuring that any non-ASCII character will be reported as not in the set.
+type asciiSet [8]uint32
+
+// makeASCIISet creates a set of ASCII characters and reports whether all
+// characters in chars are ASCII.
+func makeASCIISet(chars string) (as asciiSet, ok bool) {
+ for i := 0; i < len(chars); i++ {
+ c := chars[i]
+ if c >= utf8.RuneSelf {
+ return as, false
+ }
+ as[c>>5] |= 1 << uint(c&31)
+ }
+ return as, true
+}
+
+// contains reports whether c is inside the set.
+func (as *asciiSet) contains(c byte) bool {
+ return (as[c>>5] & (1 << uint(c&31))) != 0
+}
+
func makeCutsetFunc(cutset string) func(r rune) bool {
+ if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+ return func(r rune) bool {
+ return r == rune(cutset[0])
+ }
+ }
+ if as, isASCII := makeASCIISet(cutset); isASCII {
+ return func(r rune) bool {
+ return r < utf8.RuneSelf && as.contains(byte(r))
+ }
+ }
return func(r rune) bool {
for _, c := range cutset {
if c == r {
@@ -697,7 +757,7 @@ func EqualFold(s, t []byte) bool {
return false
}
- // General case. SimpleFold(x) returns the next equivalent rune > x
+ // General case. SimpleFold(x) returns the next equivalent rune > x
// or wraps around to smaller values.
r := unicode.SimpleFold(sr)
for r != sr && r < tr {
@@ -709,6 +769,6 @@ func EqualFold(s, t []byte) bool {
return false
}
- // One string is empty. Are both?
+ // One string is empty. Are both?
return len(s) == len(t)
}
diff --git a/libgo/go/bytes/bytes_amd64.go b/libgo/go/bytes/bytes_amd64.go
new file mode 100644
index 0000000000..58a07efc58
--- /dev/null
+++ b/libgo/go/bytes/bytes_amd64.go
@@ -0,0 +1,117 @@
+// 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 bytes
+
+//go:noescape
+
+// 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 []byte) int // ../runtime/asm_$GOARCH.s
+func supportAVX2() bool // ../runtime/asm_$GOARCH.s
+
+var shortStringLen int
+
+func init() {
+ if supportAVX2() {
+ shortStringLen = 63
+ } else {
+ shortStringLen = 31
+ }
+}
+
+// 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 []byte) int {
+ n := len(sep)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if Equal(sep, s) {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // Too many means more that 1 error per 8 characters.
+ // Allow some errors in the beginning.
+ if fails > (i+16)/8 {
+ r := indexShortStr(s[i:], sep)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && Equal(s[:n], sep) {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && Equal(s[i-n:i], sep) {
+ return i - n
+ }
+ }
+ return -1
+}
+
+// primeRK is the prime base used in Rabin-Karp algorithm.
+const primeRK = 16777619
+
+// hashStr returns the hash and the appropriate multiplicative
+// factor for use in Rabin-Karp algorithm.
+func hashStr(sep []byte) (uint32, uint32) {
+ hash := uint32(0)
+ for i := 0; i < len(sep); i++ {
+ hash = hash*primeRK + uint32(sep[i])
+ }
+ var pow, sq uint32 = 1, primeRK
+ for i := len(sep); i > 0; i >>= 1 {
+ if i&1 != 0 {
+ pow *= sq
+ }
+ sq *= sq
+ }
+ return hash, pow
+}
diff --git a/libgo/go/bytes/bytes_decl.go b/libgo/go/bytes/bytes_decl.go
index b453f21aa4..df0614fed0 100644
--- a/libgo/go/bytes/bytes_decl.go
+++ b/libgo/go/bytes/bytes_decl.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/bytes/bytes_generic.go b/libgo/go/bytes/bytes_generic.go
new file mode 100644
index 0000000000..91baa22aa2
--- /dev/null
+++ b/libgo/go/bytes/bytes_generic.go
@@ -0,0 +1,41 @@
+// 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 !amd64,!s390x
+
+package bytes
+
+// TODO: implements short string optimization on non amd64 platforms
+// and get rid of bytes_amd64.go
+
+// 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 []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ if n > len(s) {
+ return -1
+ }
+ c := sep[0]
+ if n == 1 {
+ return IndexByte(s, c)
+ }
+ i := 0
+ t := s[:len(s)-n+1]
+ for i < len(t) {
+ if t[i] != c {
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ break
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
+ return i
+ }
+ i++
+ }
+ return -1
+}
diff --git a/libgo/go/bytes/bytes_s390x.go b/libgo/go/bytes/bytes_s390x.go
new file mode 100644
index 0000000000..a05ca47aa1
--- /dev/null
+++ b/libgo/go/bytes/bytes_s390x.go
@@ -0,0 +1,120 @@
+// 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 bytes
+
+//go:noescape
+
+// indexShortStr returns the index of the first instance of sep in s,
+// or -1 if sep is not present in s.
+// indexShortStr requires 2 <= len(sep) <= shortStringLen
+func indexShortStr(s, c []byte) int // ../runtime/asm_s390x.s
+
+// supportsVX reports whether the vector facility is available.
+// indexShortStr must not be called if the vector facility is not
+// available.
+func supportsVX() bool // ../runtime/asm_s390x.s
+
+var shortStringLen = -1
+
+func init() {
+ if supportsVX() {
+ shortStringLen = 64
+ }
+}
+
+// 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 []byte) int {
+ n := len(sep)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if Equal(sep, s) {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // Too many means more that 1 error per 8 characters.
+ // Allow some errors in the beginning.
+ if fails > (i+16)/8 {
+ r := indexShortStr(s[i:], sep)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && Equal(s[:n], sep) {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && Equal(s[i-n:i], sep) {
+ return i - n
+ }
+ }
+ return -1
+}
+
+// primeRK is the prime base used in Rabin-Karp algorithm.
+const primeRK = 16777619
+
+// hashStr returns the hash and the appropriate multiplicative
+// factor for use in Rabin-Karp algorithm.
+func hashStr(sep []byte) (uint32, uint32) {
+ hash := uint32(0)
+ for i := 0; i < len(sep); i++ {
+ hash = hash*primeRK + uint32(sep[i])
+ }
+ var pow, sq uint32 = 1, primeRK
+ for i := len(sep); i > 0; i >>= 1 {
+ if i&1 != 0 {
+ pow *= sq
+ }
+ sq *= sq
+ }
+ return hash, pow
+}
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index 8df62fcc6a..26eac5e08c 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -6,8 +6,11 @@ package bytes_test
import (
. "bytes"
+ "fmt"
+ "internal/testenv"
"math/rand"
"reflect"
+ "strings"
"testing"
"unicode"
"unicode/utf8"
@@ -47,32 +50,6 @@ type BinOpTest struct {
i int
}
-var equalTests = []struct {
- a, b []byte
- i int
-}{
- {[]byte(""), []byte(""), 0},
- {[]byte("a"), []byte(""), 1},
- {[]byte(""), []byte("a"), -1},
- {[]byte("abc"), []byte("abc"), 0},
- {[]byte("ab"), []byte("abc"), -1},
- {[]byte("abc"), []byte("ab"), 1},
- {[]byte("x"), []byte("ab"), 1},
- {[]byte("ab"), []byte("x"), -1},
- {[]byte("x"), []byte("a"), 1},
- {[]byte("b"), []byte("x"), -1},
- // test runtime·memeq's chunked implementation
- {[]byte("abcdefgh"), []byte("abcdefgh"), 0},
- {[]byte("abcdefghi"), []byte("abcdefghi"), 0},
- {[]byte("abcdefghi"), []byte("abcdefghj"), -1},
- // nil tests
- {nil, nil, 0},
- {[]byte(""), nil, 0},
- {nil, []byte(""), 0},
- {[]byte("a"), nil, 1},
- {nil, []byte("a"), -1},
-}
-
func TestEqual(t *testing.T) {
for _, tt := range compareTests {
eql := Equal(tt.a, tt.b)
@@ -113,7 +90,7 @@ func TestEqualExhaustive(t *testing.T) {
}
}
-// make sure Equal returns false for minimally different strings. The data
+// make sure Equal returns false for minimally different strings. The data
// is all zeros except for a single one in one location.
func TestNotEqual(t *testing.T) {
var size = 128
@@ -190,8 +167,12 @@ var indexAnyTests = []BinOpTest{
{"abc", "xyz", -1},
{"abc", "xcz", 2},
{"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"aRegExp*", ".(|)*+?^$[]", 7},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 4},
+ {"012\x80bcb\x80210", "\xffb", 3},
}
var lastIndexAnyTests = []BinOpTest{
@@ -203,18 +184,13 @@ var lastIndexAnyTests = []BinOpTest{
{"aaa", "a", 2},
{"abc", "xyz", -1},
{"abc", "ab", 1},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"a.RegExp*", ".(|)*+?^$[]", 8},
{dots + dots + dots, " ", -1},
-}
-
-var indexRuneTests = []BinOpTest{
- {"", "a", -1},
- {"", "☺", -1},
- {"foo", "☹", -1},
- {"foo", "o", 1},
- {"foo☺bar", "☺", 3},
- {"foo☺☻☹bar", "☹", 9},
+ {"012abcba210", "\xffb", 6},
+ {"012\x80bcb\x80210", "\xffb", 7},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -335,178 +311,282 @@ func TestIndexByteBig(t *testing.T) {
}
}
-func TestIndexRune(t *testing.T) {
- for _, tt := range indexRuneTests {
- a := []byte(tt.a)
- r, _ := utf8.DecodeRuneInString(tt.b)
- pos := IndexRune(a, r)
- if pos != tt.i {
- t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+// test a small index across all page offsets
+func TestIndexByteSmall(t *testing.T) {
+ b := make([]byte, 5015) // bigger than a page
+ // Make sure we find the correct byte even when straddling a page.
+ for i := 0; i <= len(b)-15; i++ {
+ for j := 0; j < 15; j++ {
+ b[i+j] = byte(100 + j)
+ }
+ for j := 0; j < 15; j++ {
+ p := IndexByte(b[i:i+15], byte(100+j))
+ if p != j {
+ t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 100+j, p)
+ }
+ }
+ for j := 0; j < 15; j++ {
+ b[i+j] = 0
+ }
+ }
+ // Make sure matches outside the slice never trigger.
+ for i := 0; i <= len(b)-15; i++ {
+ for j := 0; j < 15; j++ {
+ b[i+j] = 1
+ }
+ for j := 0; j < 15; j++ {
+ p := IndexByte(b[i:i+15], byte(0))
+ if p != -1 {
+ t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 0, p)
+ }
+ }
+ for j := 0; j < 15; j++ {
+ b[i+j] = 0
}
}
}
-var bmbuf []byte
-
-func BenchmarkIndexByte32(b *testing.B) { bmIndexByte(b, IndexByte, 32) }
-func BenchmarkIndexByte4K(b *testing.B) { bmIndexByte(b, IndexByte, 4<<10) }
-func BenchmarkIndexByte4M(b *testing.B) { bmIndexByte(b, IndexByte, 4<<20) }
-func BenchmarkIndexByte64M(b *testing.B) { bmIndexByte(b, IndexByte, 64<<20) }
-func BenchmarkIndexBytePortable32(b *testing.B) { bmIndexByte(b, IndexBytePortable, 32) }
-func BenchmarkIndexBytePortable4K(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<10) }
-func BenchmarkIndexBytePortable4M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<20) }
-func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) }
-
-func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
- if len(bmbuf) < n {
- bmbuf = make([]byte, n)
- }
- b.SetBytes(int64(n))
- buf := bmbuf[0:n]
- buf[n-1] = 'x'
- for i := 0; i < b.N; i++ {
- j := index(buf, 'x')
- if j != n-1 {
- b.Fatal("bad index", j)
+func TestIndexRune(t *testing.T) {
+ tests := []struct {
+ in string
+ rune rune
+ want int
+ }{
+ {"", 'a', -1},
+ {"", '☺', -1},
+ {"foo", '☹', -1},
+ {"foo", 'o', 1},
+ {"foo☺bar", '☺', 3},
+ {"foo☺☻☹bar", '☹', 9},
+ {"a A x", 'A', 2},
+ {"some_text=some_value", '=', 9},
+ {"☺a", 'a', 3},
+ {"a☻☺b", '☺', 4},
+
+ // RuneError should match any invalid UTF-8 byte sequence.
+ {"�", '�', 0},
+ {"\xff", '�', 0},
+ {"☻x�", '�', len("☻x")},
+ {"☻x\xe2\x98", '�', len("☻x")},
+ {"☻x\xe2\x98�", '�', len("☻x")},
+ {"☻x\xe2\x98x", '�', len("☻x")},
+
+ // Invalid rune values should never match.
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},
+ }
+ for _, tt := range tests {
+ if got := IndexRune([]byte(tt.in), tt.rune); got != tt.want {
+ t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)
}
}
- buf[n-1] = '\x00'
-}
-func BenchmarkEqual0(b *testing.B) {
- var buf [4]byte
- buf1 := buf[0:0]
- buf2 := buf[1:1]
- for i := 0; i < b.N; i++ {
- eq := Equal(buf1, buf2)
- if !eq {
- b.Fatal("bad equal")
- }
- }
-}
-
-func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) }
-func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) }
-func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) }
-func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) }
-func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) }
-func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) }
-func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) }
-func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) }
-func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) }
-func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) }
-func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) }
-func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) }
-func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) }
-func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) }
-func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) }
-func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) }
-
-func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
- if len(bmbuf) < 2*n {
- bmbuf = make([]byte, 2*n)
- }
- b.SetBytes(int64(n))
- buf1 := bmbuf[0:n]
- buf2 := bmbuf[n : 2*n]
- buf1[n-1] = 'x'
- buf2[n-1] = 'x'
- for i := 0; i < b.N; i++ {
- eq := equal(buf1, buf2)
- if !eq {
- b.Fatal("bad equal")
+ haystack := []byte("test世界")
+ allocs := testing.AllocsPerRun(1000, func() {
+ if i := IndexRune(haystack, 's'); i != 2 {
+ t.Fatalf("'s' at %d; want 2", i)
}
+ if i := IndexRune(haystack, '世'); i != 4 {
+ t.Fatalf("'世' at %d; want 4", i)
+ }
+ })
+ if allocs != 0 {
+ t.Errorf("expected no allocations, got %f", allocs)
}
- buf1[n-1] = '\x00'
- buf2[n-1] = '\x00'
}
-func BenchmarkIndex32(b *testing.B) { bmIndex(b, Index, 32) }
-func BenchmarkIndex4K(b *testing.B) { bmIndex(b, Index, 4<<10) }
-func BenchmarkIndex4M(b *testing.B) { bmIndex(b, Index, 4<<20) }
-func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) }
+var bmbuf []byte
-func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
- if len(bmbuf) < n {
- bmbuf = make([]byte, n)
+func valName(x int) string {
+ if s := x >> 20; s<<20 == x {
+ return fmt.Sprintf("%dM", s)
}
- b.SetBytes(int64(n))
- buf := bmbuf[0:n]
- buf[n-1] = 'x'
- for i := 0; i < b.N; i++ {
- j := index(buf, buf[n-7:])
- if j != n-7 {
- b.Fatal("bad index", j)
+ if s := x >> 10; s<<10 == x {
+ return fmt.Sprintf("%dK", s)
+ }
+ return fmt.Sprint(x)
+}
+
+func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
+ for _, n := range sizes {
+ if isRaceBuilder && n > 4<<10 {
+ continue
}
+ b.Run(valName(n), func(b *testing.B) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ f(b, n)
+ })
}
- buf[n-1] = '\x00'
}
-func BenchmarkIndexEasy32(b *testing.B) { bmIndexEasy(b, Index, 32) }
-func BenchmarkIndexEasy4K(b *testing.B) { bmIndexEasy(b, Index, 4<<10) }
-func BenchmarkIndexEasy4M(b *testing.B) { bmIndexEasy(b, Index, 4<<20) }
-func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) }
+var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
-func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
- if len(bmbuf) < n {
- bmbuf = make([]byte, n)
- }
- b.SetBytes(int64(n))
- buf := bmbuf[0:n]
- buf[n-1] = 'x'
- buf[n-7] = 'x'
- for i := 0; i < b.N; i++ {
- j := index(buf, buf[n-7:])
- if j != n-7 {
- b.Fatal("bad index", j)
+var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
+
+func BenchmarkIndexByte(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexByte(IndexByte))
+}
+
+func BenchmarkIndexBytePortable(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable))
+}
+
+func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ b.Fatal("bad index", j)
+ }
}
+ buf[n-1] = '\x00'
}
- buf[n-1] = '\x00'
- buf[n-7] = '\x00'
}
-func BenchmarkCount32(b *testing.B) { bmCount(b, Count, 32) }
-func BenchmarkCount4K(b *testing.B) { bmCount(b, Count, 4<<10) }
-func BenchmarkCount4M(b *testing.B) { bmCount(b, Count, 4<<20) }
-func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) }
+func BenchmarkIndexRune(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexRune(IndexRune))
+}
-func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
- if len(bmbuf) < n {
- bmbuf = make([]byte, n)
+func BenchmarkIndexRuneASCII(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune))
+}
+
+func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
}
- b.SetBytes(int64(n))
- buf := bmbuf[0:n]
- buf[n-1] = 'x'
- for i := 0; i < b.N; i++ {
- j := count(buf, buf[n-7:])
- if j != 1 {
- b.Fatal("bad count", j)
+}
+
+func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ utf8.EncodeRune(buf[n-3:], '世')
+ for i := 0; i < b.N; i++ {
+ j := index(buf, '世')
+ if j != n-3 {
+ b.Fatal("bad index", j)
+ }
}
+ buf[n-3] = '\x00'
+ buf[n-2] = '\x00'
+ buf[n-1] = '\x00'
}
- buf[n-1] = '\x00'
}
-func BenchmarkCountEasy32(b *testing.B) { bmCountEasy(b, Count, 32) }
-func BenchmarkCountEasy4K(b *testing.B) { bmCountEasy(b, Count, 4<<10) }
-func BenchmarkCountEasy4M(b *testing.B) { bmCountEasy(b, Count, 4<<20) }
-func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) }
+func BenchmarkEqual(b *testing.B) {
+ b.Run("0", func(b *testing.B) {
+ var buf [4]byte
+ buf1 := buf[0:0]
+ buf2 := buf[1:1]
+ for i := 0; i < b.N; i++ {
+ eq := Equal(buf1, buf2)
+ if !eq {
+ b.Fatal("bad equal")
+ }
+ }
+ })
-func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
- if len(bmbuf) < n {
- bmbuf = make([]byte, n)
- }
- b.SetBytes(int64(n))
- buf := bmbuf[0:n]
- buf[n-1] = 'x'
- buf[n-7] = 'x'
- for i := 0; i < b.N; i++ {
- j := count(buf, buf[n-7:])
- if j != 1 {
- b.Fatal("bad count", j)
+ sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20}
+ benchBytes(b, sizes, bmEqual(Equal))
+}
+
+func BenchmarkEqualPort(b *testing.B) {
+ sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20}
+ benchBytes(b, sizes, bmEqual(EqualPortable))
+}
+
+func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ if len(bmbuf) < 2*n {
+ bmbuf = make([]byte, 2*n)
+ }
+ buf1 := bmbuf[0:n]
+ buf2 := bmbuf[n : 2*n]
+ buf1[n-1] = 'x'
+ buf2[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ eq := equal(buf1, buf2)
+ if !eq {
+ b.Fatal("bad equal")
+ }
}
+ buf1[n-1] = '\x00'
+ buf2[n-1] = '\x00'
}
- buf[n-1] = '\x00'
- buf[n-7] = '\x00'
+}
+
+func BenchmarkIndex(b *testing.B) {
+ benchBytes(b, indexSizes, func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := Index(buf, buf[n-7:])
+ if j != n-7 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ })
+}
+
+func BenchmarkIndexEasy(b *testing.B) {
+ benchBytes(b, indexSizes, func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ buf[n-7] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := Index(buf, buf[n-7:])
+ if j != n-7 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ buf[n-7] = '\x00'
+ })
+}
+
+func BenchmarkCount(b *testing.B) {
+ benchBytes(b, indexSizes, func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := Count(buf, buf[n-7:])
+ if j != 1 {
+ b.Fatal("bad count", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ })
+}
+
+func BenchmarkCountEasy(b *testing.B) {
+ benchBytes(b, indexSizes, func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ buf[n-7] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := Count(buf, buf[n-7:])
+ if j != 1 {
+ b.Fatal("bad count", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ buf[n-7] = '\x00'
+ })
}
type ExplodeTest struct {
@@ -760,7 +840,7 @@ func TestMap(t *testing.T) {
// Run a couple of awful growth/shrinkage tests
a := tenRunes('a')
- // 1. Grow. This triggers two reallocations in Map.
+ // 1. Grow. This triggers two reallocations in Map.
maxRune := func(r rune) rune { return unicode.MaxRune }
m := Map(maxRune, []byte(a))
expect := tenRunes(unicode.MaxRune)
@@ -847,6 +927,54 @@ func TestRepeat(t *testing.T) {
}
}
+func repeat(b []byte, count int) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ switch v := r.(type) {
+ case error:
+ err = v
+ default:
+ err = fmt.Errorf("%s", v)
+ }
+ }
+ }()
+
+ Repeat(b, count)
+
+ return
+}
+
+// See Issue golang.org/issue/16237
+func TestRepeatCatchesOverflow(t *testing.T) {
+ tests := [...]struct {
+ s string
+ count int
+ errStr string
+ }{
+ 0: {"--", -2147483647, "negative"},
+ 1: {"", int(^uint(0) >> 1), ""},
+ 2: {"-", 10, ""},
+ 3: {"gopher", 0, ""},
+ 4: {"-", -1, "negative"},
+ 5: {"--", -102, "negative"},
+ 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
+ }
+
+ for i, tt := range tests {
+ err := repeat([]byte(tt.s), tt.count)
+ if tt.errStr == "" {
+ if err != nil {
+ t.Errorf("#%d panicked %v", i, err)
+ }
+ continue
+ }
+
+ if err == nil || !strings.Contains(err.Error(), tt.errStr) {
+ t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
+ }
+ }
+}
+
func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
@@ -909,6 +1037,9 @@ var trimTests = []TrimTest{
{"Trim", "* listitem", " *", "listitem"},
{"Trim", `"quote"`, `"`, "quote"},
{"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "\x80test\xff", "\xff", "test"},
+ {"Trim", " Ä  ", " ", "Ä "},
+ {"Trim", " Ä Ä°0", "0 ", "Ä Ä°"},
//empty string tests
{"Trim", "abba", "", "abba"},
{"Trim", "", "123", ""},
@@ -1207,6 +1338,57 @@ func TestContains(t *testing.T) {
}
}
+var ContainsAnyTests = []struct {
+ b []byte
+ substr string
+ expected bool
+}{
+ {[]byte(""), "", false},
+ {[]byte(""), "a", false},
+ {[]byte(""), "abc", false},
+ {[]byte("a"), "", false},
+ {[]byte("a"), "a", true},
+ {[]byte("aaa"), "a", true},
+ {[]byte("abc"), "xyz", false},
+ {[]byte("abc"), "xcz", true},
+ {[]byte("a☺b☻c☹d"), "uvw☻xyz", true},
+ {[]byte("aRegExp*"), ".(|)*+?^$[]", true},
+ {[]byte(dots + dots + dots), " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+ for _, ct := range ContainsAnyTests {
+ if ContainsAny(ct.b, ct.substr) != ct.expected {
+ t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+ ct.b, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
+
+var ContainsRuneTests = []struct {
+ b []byte
+ r rune
+ expected bool
+}{
+ {[]byte(""), 'a', false},
+ {[]byte("a"), 'a', true},
+ {[]byte("aaa"), 'a', true},
+ {[]byte("abc"), 'y', false},
+ {[]byte("abc"), 'c', true},
+ {[]byte("a☺b☻c☹d"), 'x', false},
+ {[]byte("a☺b☻c☹d"), '☻', true},
+ {[]byte("aRegExp*"), '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+ for _, ct := range ContainsRuneTests {
+ if ContainsRune(ct.b, ct.r) != ct.expected {
+ t.Errorf("ContainsRune(%q, %q) = %v, want %v",
+ ct.b, ct.r, !ct.expected, ct.expected)
+ }
+ }
+}
+
var makeFieldsInput = func() []byte {
x := make([]byte, 1<<20)
// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
@@ -1256,33 +1438,52 @@ func BenchmarkRepeat(b *testing.B) {
}
}
-func benchmarkBytesCompare(b *testing.B, n int) {
- var x = make([]byte, n)
- var y = make([]byte, n)
+func BenchmarkBytesCompare(b *testing.B) {
+ for n := 1; n <= 2048; n <<= 1 {
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ var x = make([]byte, n)
+ var y = make([]byte, n)
- for i := 0; i < n; i++ {
- x[i] = 'a'
+ for i := 0; i < n; i++ {
+ x[i] = 'a'
+ }
+
+ for i := 0; i < n; i++ {
+ y[i] = 'a'
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Compare(x, y)
+ }
+ })
}
+}
- for i := 0; i < n; i++ {
- y[i] = 'a'
+func BenchmarkIndexAnyASCII(b *testing.B) {
+ x := Repeat([]byte{'#'}, 4096) // Never matches set
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ IndexAny(x[:k], cs[:j])
+ }
+ })
+ }
}
+}
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- Compare(x, y)
- }
-}
-
-func BenchmarkBytesCompare1(b *testing.B) { benchmarkBytesCompare(b, 1) }
-func BenchmarkBytesCompare2(b *testing.B) { benchmarkBytesCompare(b, 2) }
-func BenchmarkBytesCompare4(b *testing.B) { benchmarkBytesCompare(b, 4) }
-func BenchmarkBytesCompare8(b *testing.B) { benchmarkBytesCompare(b, 8) }
-func BenchmarkBytesCompare16(b *testing.B) { benchmarkBytesCompare(b, 16) }
-func BenchmarkBytesCompare32(b *testing.B) { benchmarkBytesCompare(b, 32) }
-func BenchmarkBytesCompare64(b *testing.B) { benchmarkBytesCompare(b, 64) }
-func BenchmarkBytesCompare128(b *testing.B) { benchmarkBytesCompare(b, 128) }
-func BenchmarkBytesCompare256(b *testing.B) { benchmarkBytesCompare(b, 256) }
-func BenchmarkBytesCompare512(b *testing.B) { benchmarkBytesCompare(b, 512) }
-func BenchmarkBytesCompare1024(b *testing.B) { benchmarkBytesCompare(b, 1024) }
-func BenchmarkBytesCompare2048(b *testing.B) { benchmarkBytesCompare(b, 2048) }
+func BenchmarkTrimASCII(b *testing.B) {
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ x := Repeat([]byte(cs[:j]), k) // Always matches set
+ for i := 0; i < b.N; i++ {
+ Trim(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
diff --git a/libgo/go/bytes/compare_test.go b/libgo/go/bytes/compare_test.go
index f2d81d5310..35088a1b2e 100644
--- a/libgo/go/bytes/compare_test.go
+++ b/libgo/go/bytes/compare_test.go
@@ -62,7 +62,7 @@ func TestCompareBytes(t *testing.T) {
a := make([]byte, n+1)
b := make([]byte, n+1)
for len := 0; len < 128; len++ {
- // randomish but deterministic data. No 0 or 255.
+ // randomish but deterministic data. No 0 or 255.
for i := 0; i < len; i++ {
a[i] = byte(1 + 31*i%254)
b[i] = byte(1 + 31*i%254)
diff --git a/libgo/go/bytes/equal_test.go b/libgo/go/bytes/equal_test.go
index 1bf19a74b8..9fdead8a60 100644
--- a/libgo/go/bytes/equal_test.go
+++ b/libgo/go/bytes/equal_test.go
@@ -14,11 +14,11 @@ import (
)
// This file tests the situation where memeq is checking
-// data very near to a page boundary. We want to make sure
+// data very near to a page boundary. We want to make sure
// equal does not read across the boundary and cause a page
// fault where it shouldn't.
-// This test runs only on linux. The code being tested is
+// This test runs only on linux. The code being tested is
// not OS-specific, so it does not need to be tested on all
// operating systems.
diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go
index ad2dbc69b7..0d35a0dc9c 100644
--- a/libgo/go/bytes/example_test.go
+++ b/libgo/go/bytes/example_test.go
@@ -11,6 +11,7 @@ import (
"io"
"os"
"sort"
+ "unicode"
)
func ExampleBuffer() {
@@ -83,3 +84,205 @@ func ExampleTrimPrefix() {
fmt.Printf("Hello%s", b)
// Output: Hello, world!
}
+
+func ExampleFields() {
+ fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz ")))
+ // Output: Fields are: ["foo" "bar" "baz"]
+}
+
+func ExampleFieldsFunc() {
+ f := func(c rune) bool {
+ return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+ }
+ fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f))
+ // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
+func ExampleContains() {
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("")))
+ fmt.Println(bytes.Contains([]byte(""), []byte("")))
+ // Output:
+ // true
+ // false
+ // true
+ // true
+}
+
+func ExampleCount() {
+ fmt.Println(bytes.Count([]byte("cheese"), []byte("e")))
+ fmt.Println(bytes.Count([]byte("five"), []byte(""))) // before & after each rune
+ // Output:
+ // 3
+ // 5
+}
+
+func ExampleEqualFold() {
+ fmt.Println(bytes.EqualFold([]byte("Go"), []byte("go")))
+ // Output: true
+}
+
+func ExampleHasPrefix() {
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("")))
+ // Output:
+ // true
+ // false
+ // true
+}
+
+func ExampleHasSuffix() {
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("go")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("O")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("Ami")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("")))
+ // Output:
+ // true
+ // false
+ // false
+ // true
+}
+
+func ExampleIndex() {
+ fmt.Println(bytes.Index([]byte("chicken"), []byte("ken")))
+ fmt.Println(bytes.Index([]byte("chicken"), []byte("dmr")))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleIndexFunc() {
+ f := func(c rune) bool {
+ return unicode.Is(unicode.Han, c)
+ }
+ fmt.Println(bytes.IndexFunc([]byte("Hello, 世界"), f))
+ fmt.Println(bytes.IndexFunc([]byte("Hello, world"), f))
+ // Output:
+ // 7
+ // -1
+}
+
+func ExampleIndexAny() {
+ fmt.Println(bytes.IndexAny([]byte("chicken"), "aeiouy"))
+ fmt.Println(bytes.IndexAny([]byte("crwth"), "aeiouy"))
+ // Output:
+ // 2
+ // -1
+}
+
+func ExampleIndexRune() {
+ fmt.Println(bytes.IndexRune([]byte("chicken"), 'k'))
+ fmt.Println(bytes.IndexRune([]byte("chicken"), 'd'))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleLastIndex() {
+ fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
+ fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
+ fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("rodent")))
+ // Output:
+ // 0
+ // 3
+ // -1
+}
+
+func ExampleJoin() {
+ s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
+ fmt.Printf("%s", bytes.Join(s, []byte(", ")))
+ // Output: foo, bar, baz
+}
+
+func ExampleRepeat() {
+ fmt.Printf("ba%s", bytes.Repeat([]byte("na"), 2))
+ // Output: banana
+}
+
+func ExampleReplace() {
+ fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("k"), []byte("ky"), 2))
+ fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("oink"), []byte("moo"), -1))
+ // Output:
+ // oinky oinky oink
+ // moo moo moo
+}
+
+func ExampleSplit() {
+ fmt.Printf("%q\n", bytes.Split([]byte("a,b,c"), []byte(",")))
+ fmt.Printf("%q\n", bytes.Split([]byte("a man a plan a canal panama"), []byte("a ")))
+ fmt.Printf("%q\n", bytes.Split([]byte(" xyz "), []byte("")))
+ fmt.Printf("%q\n", bytes.Split([]byte(""), []byte("Bernardo O'Higgins")))
+ // Output:
+ // ["a" "b" "c"]
+ // ["" "man " "plan " "canal panama"]
+ // [" " "x" "y" "z" " "]
+ // [""]
+}
+
+func ExampleSplitN() {
+ fmt.Printf("%q\n", bytes.SplitN([]byte("a,b,c"), []byte(","), 2))
+ z := bytes.SplitN([]byte("a,b,c"), []byte(","), 0)
+ fmt.Printf("%q (nil = %v)\n", z, z == nil)
+ // Output:
+ // ["a" "b,c"]
+ // [] (nil = true)
+}
+
+func ExampleSplitAfter() {
+ fmt.Printf("%q\n", bytes.SplitAfter([]byte("a,b,c"), []byte(",")))
+ // Output: ["a," "b," "c"]
+}
+
+func ExampleSplitAfterN() {
+ fmt.Printf("%q\n", bytes.SplitAfterN([]byte("a,b,c"), []byte(","), 2))
+ // Output: ["a," "b,c"]
+}
+
+func ExampleTitle() {
+ fmt.Printf("%s", bytes.Title([]byte("her royal highness")))
+ // Output: Her Royal Highness
+}
+
+func ExampleToTitle() {
+ fmt.Printf("%s\n", bytes.ToTitle([]byte("loud noises")))
+ fmt.Printf("%s\n", bytes.ToTitle([]byte("хлеб")))
+ // Output:
+ // LOUD NOISES
+ // ХЛЕБ
+}
+
+func ExampleTrim() {
+ fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!! "), "! "))
+ // Output: ["Achtung! Achtung"]
+}
+
+func ExampleMap() {
+ rot13 := func(r rune) rune {
+ switch {
+ case r >= 'A' && r <= 'Z':
+ return 'A' + (r-'A'+13)%26
+ case r >= 'a' && r <= 'z':
+ return 'a' + (r-'a'+13)%26
+ }
+ return r
+ }
+ fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher...")))
+ // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
+}
+
+func ExampleTrimSpace() {
+ fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
+ // Output: a lone gopher
+}
+
+func ExampleToUpper() {
+ fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
+ // Output: GOPHER
+}
+
+func ExampleToLower() {
+ fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
+ // Output: gopher
+}
diff --git a/libgo/go/bytes/reader.go b/libgo/go/bytes/reader.go
index b89d1548f1..28cfc7a978 100644
--- a/libgo/go/bytes/reader.go
+++ b/libgo/go/bytes/reader.go
@@ -36,9 +36,6 @@ func (r *Reader) Len() int {
func (r *Reader) Size() int64 { return int64(len(r.s)) }
func (r *Reader) Read(b []byte) (n int, err error) {
- if len(b) == 0 {
- return 0, nil
- }
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
@@ -63,14 +60,14 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
return
}
-func (r *Reader) ReadByte() (b byte, err error) {
+func (r *Reader) ReadByte() (byte, error) {
r.prevRune = -1
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- b = r.s[r.i]
+ b := r.s[r.i]
r.i++
- return
+ return b, nil
}
func (r *Reader) UnreadByte() error {
@@ -111,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:
- abs = int64(r.i) + offset
- case 2:
+ case io.SeekCurrent:
+ abs = r.i + offset
+ case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("bytes.Reader.Seek: invalid whence")
@@ -146,5 +143,8 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
return
}
+// Reset resets the Reader to be reading from b.
+func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} }
+
// NewReader returns a new Reader reading from b.
func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
diff --git a/libgo/go/bytes/reader_test.go b/libgo/go/bytes/reader_test.go
index b929a28260..7b3034d4e0 100644
--- a/libgo/go/bytes/reader_test.go
+++ b/libgo/go/bytes/reader_test.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "os"
"sync"
"testing"
)
@@ -22,17 +21,18 @@ func TestReader(t *testing.T) {
n int
want string
wantpos int64
+ readerr error
seekerr string
}{
- {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
- {seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
- {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
- {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
- {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
- {seek: os.SEEK_SET, n: 5, want: "01234"},
- {seek: os.SEEK_CUR, n: 5, want: "56789"},
- {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+ {seek: io.SeekStart, off: 0, n: 20, want: "0123456789"},
+ {seek: io.SeekStart, off: 1, n: 1, want: "1"},
+ {seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"},
+ {seek: io.SeekStart, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+ {seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF},
+ {seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF},
+ {seek: io.SeekStart, n: 5, want: "01234"},
+ {seek: io.SeekCurrent, n: 5, want: "56789"},
+ {seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"},
}
for i, tt := range tests {
@@ -50,8 +50,8 @@ func TestReader(t *testing.T) {
}
buf := make([]byte, tt.n)
n, err := r.Read(buf)
- if err != nil {
- t.Errorf("%d. read = %v", i, err)
+ if err != tt.readerr {
+ t.Errorf("%d. read = %v; want %v", i, err, tt.readerr)
continue
}
got := string(buf[:n])
@@ -63,7 +63,7 @@ func TestReader(t *testing.T) {
func TestReadAfterBigSeek(t *testing.T) {
r := NewReader([]byte("0123456789"))
- if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil {
t.Fatal(err)
}
if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
@@ -174,7 +174,7 @@ func TestReaderLen(t *testing.T) {
t.Errorf("r.Len(): got %d, want %d", got, want)
}
if n, err := r.Read(make([]byte, 1)); err != nil || n != 1 {
- t.Errorf("Read failed: read %d %v", n, err)
+ t.Errorf("Read failed: read %d %v; want 1, nil", n, err)
}
if got, want := r.Len(), 0; got != want {
t.Errorf("r.Len(): got %d, want %d", got, want)
@@ -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{}) }},
}
@@ -256,3 +256,23 @@ func TestReaderLenSize(t *testing.T) {
t.Errorf("Size = %d; want 3", r.Size())
}
}
+
+func TestReaderReset(t *testing.T) {
+ r := NewReader([]byte("世界"))
+ if _, _, err := r.ReadRune(); err != nil {
+ t.Errorf("ReadRune: unexpected error: %v", err)
+ }
+
+ const want = "abcdef"
+ r.Reset([]byte(want))
+ if err := r.UnreadRune(); err == nil {
+ t.Errorf("UnreadRune: expected error, got nil")
+ }
+ buf, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("ReadAll: unexpected error: %v", err)
+ }
+ if got := string(buf); got != want {
+ t.Errorf("ReadAll: got %q, want %q", got, want)
+ }
+}
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index c3a24c2b76..8ce824196d 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -40,7 +40,7 @@ func sourceLine(n ast.Node) int {
}
// ReadGo populates f with information learned from reading the
-// Go source file with the given file name. It gathers the C preamble
+// Go source file with the given file name. It gathers the C preamble
// attached to the import "C" comment, a list of references to C.xxx,
// a list of exported functions, and the actual AST, to be rewritten and
// printed.
@@ -73,7 +73,7 @@ func (f *File) ReadGo(name string) {
}
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
+ if !ok || s.Path.Value != `"C"` {
continue
}
sawC = true
@@ -87,6 +87,7 @@ func (f *File) ReadGo(name string) {
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
f.Preamble += commentText(cg) + "\n"
+ f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
}
}
}
@@ -106,7 +107,7 @@ func (f *File) ReadGo(name string) {
ws := 0
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
+ if !ok || s.Path.Value != `"C"` {
d.Specs[ws] = spec
ws++
}
@@ -147,7 +148,7 @@ func commentText(g *ast.CommentGroup) string {
}
var pieces []string
for _, com := range g.List {
- c := string(com.Text)
+ c := com.Text
// Remove comment markers.
// The parser has given us exactly the comment text.
switch c[1] {
@@ -172,7 +173,7 @@ func (f *File) saveExprs(x interface{}, context string) {
f.saveRef(x, context)
}
case *ast.CallExpr:
- f.saveCall(x)
+ f.saveCall(x, context)
}
}
@@ -220,7 +221,7 @@ func (f *File) saveRef(n *ast.Expr, context string) {
}
// Save calls to C.xxx for later processing.
-func (f *File) saveCall(call *ast.CallExpr) {
+func (f *File) saveCall(call *ast.CallExpr, context string) {
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return
@@ -228,7 +229,8 @@ func (f *File) saveCall(call *ast.CallExpr) {
if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
return
}
- f.Calls = append(f.Calls, call)
+ c := &Call{Call: call, Deferred: context == "defer"}
+ f.Calls = append(f.Calls, c)
}
// If a function should be exported add it to ExpFunc.
@@ -242,11 +244,11 @@ func (f *File) saveExport(x interface{}, context string) {
return
}
for _, c := range n.Doc.List {
- if !strings.HasPrefix(string(c.Text), "//export ") {
+ if !strings.HasPrefix(c.Text, "//export ") {
continue
}
- name := strings.TrimSpace(string(c.Text[9:]))
+ name := strings.TrimSpace(c.Text[9:])
if name == "" {
error_(c.Pos(), "export missing name")
}
@@ -295,7 +297,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
// everything else just recurs
default:
- error_(token.NoPos, "unexpected type %T in walk", x, visit)
+ error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case nil:
@@ -401,7 +403,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
case *ast.GoStmt:
f.walk(n.Call, "expr", visit)
case *ast.DeferStmt:
- f.walk(n.Call, "expr", visit)
+ f.walk(n.Call, "defer", visit)
case *ast.ReturnStmt:
f.walk(n.Results, "expr", visit)
case *ast.BranchStmt:
@@ -447,7 +449,11 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
case *ast.ImportSpec:
case *ast.ValueSpec:
f.walk(&n.Type, "type", visit)
- f.walk(n.Values, "expr", visit)
+ if len(n.Names) == 2 && len(n.Values) == 1 {
+ f.walk(&n.Values[0], "as2", visit)
+ } else {
+ f.walk(n.Values, "expr", visit)
+ }
case *ast.TypeSpec:
f.walk(&n.Type, "type", visit)
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index bd38a5c153..85441e61c0 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -31,9 +31,9 @@ See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
"C? Go? Cgo!" for an introduction to using cgo:
https://golang.org/doc/articles/c_go_cgo.html.
-CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
-directives within these comments to tweak the behavior of the C or C++
-compiler. Values defined in multiple directives are concatenated
+CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo
+#cgo directives within these comments to tweak the behavior of the C, C++
+or Fortran compiler. Values defined in multiple directives are concatenated
together. The directive can include a list of build constraints limiting its
effect to systems satisfying one of the constraints
(see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
@@ -53,7 +53,9 @@ For example:
// #include <png.h>
import "C"
-When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
+The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
+
+When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
directives, not the environment variables, so that builds work in
@@ -62,10 +64,11 @@ unmodified environments.
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
directives in a package are concatenated and used to compile C++ files in that
-package. All the LDFLAGS directives in any package in the program are
-concatenated and used at link time. All the pkg-config directives are
-concatenated and sent to pkg-config simultaneously to add to each appropriate
-set of command-line flags.
+package. All the CPPFLAGS and FFLAGS directives in a package are concatenated
+and used to compile Fortran files in that package. All the LDFLAGS directives
+in any package in the program are concatenated and used at link time. All the
+pkg-config directives are concatenated and sent to pkg-config simultaneously
+to add to each appropriate set of command-line flags.
When the cgo directives are parsed, any occurrence of the string ${SRCDIR}
will be replaced by the absolute path to the directory containing the source
@@ -83,7 +86,8 @@ When the Go tool sees that one or more Go files use the special import
"C", it will look for other non-Go files in the directory and compile
them as part of the Go package. Any .c, .s, or .S files will be
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
-compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will
+compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
+compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
the C and C++ files will be recompiled. The default C and C++
compilers may be changed by the CC and CXX environment variables,
@@ -133,7 +137,7 @@ C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
-Go code can not refer to zero-sized fields that occur at the end of
+Go code cannot refer to zero-sized fields that occur at the end of
non-empty C structs. To get the address of such a field (which is the
only operation you can do with a zero-sized field) you must take the
address of the struct and add the size of the struct.
@@ -148,8 +152,9 @@ assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
- n, err := C.sqrt(-1)
+ n, err = C.sqrt(-1)
_, err := C.voidFunc()
+ var n, err = C.sqrt(1)
Calling C function pointers is currently not supported, however you can
declare Go variables which hold C function pointers and pass them
@@ -195,6 +200,13 @@ by making copies of the data. In pseudo-Go definitions:
// if C.free is needed).
func C.CString(string) *C.char
+ // Go []byte slice to C array
+ // The C array is allocated in the C heap using malloc.
+ // It is the caller's responsibility to arrange for it to be
+ // freed, such as by calling C.free (be sure to include stdlib.h
+ // if C.free is needed).
+ func C.CBytes([]byte) unsafe.Pointer
+
// C string to Go string
func C.GoString(*C.char) string
@@ -204,6 +216,13 @@ by making copies of the data. In pseudo-Go definitions:
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
+As a special case, C.malloc does not call the C library malloc directly
+but instead calls a Go helper function that wraps the C library malloc
+but guarantees never to return nil. If C's malloc indicates out of memory,
+the helper function crashes the program, like when Go itself runs out
+of memory. Because C.malloc cannot fail, it has no two-result form
+that returns errno.
+
C references to Go
Go functions can be exported for use by C code in the following way:
@@ -307,6 +326,9 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the
syscall package when bootstrapping a new target.
+ -srcdir directory
+ Find the Go input files, listed on the command line,
+ in directory.
-objdir directory
Put all generated files in directory.
-importpath string
@@ -501,7 +523,6 @@ file compiled by gcc, the file x.cgo2.c:
void
_cgo_be59f0f25121_Cfunc_puts(void *v)
{
- _cgo_wait_runtime_init_done();
struct {
char* p0;
int r;
@@ -510,8 +531,7 @@ file compiled by gcc, the file x.cgo2.c:
a->r = puts((void*)a->p0);
}
-It waits for Go runtime to be initialized (required for shared libraries),
-extracts the arguments from the pointer to _Cfunc_puts's argument
+It extracts the arguments from the pointer to _Cfunc_puts's argument
frame, invokes the system C function (in this case, puts), stores the
result in the frame, and returns.
@@ -529,8 +549,8 @@ linkage to the desired libraries. The main function is provided by
_cgo_main.c:
int main() { return 0; }
- void crosscall2(void(*fn)(void*, int), void *a, int c) { }
- void _cgo_wait_runtime_init_done() { }
+ void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
+ uintptr_t _cgo_wait_runtime_init_done() { }
void _cgo_allocate(void *a, int c) { }
void _cgo_panic(void *a, int c) { }
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index fb5049c1a1..5ea2d941ca 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -83,7 +83,7 @@ func (f *File) DiscardCgoDirectives() {
f.Preamble = strings.Join(linesOut, "\n")
}
-// addToFlag appends args to flag. All flags are later written out onto the
+// addToFlag appends args to flag. All flags are later written out onto the
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
@@ -99,7 +99,7 @@ func (p *Package) addToFlag(flag string, args []string) {
// Single quotes and double quotes are recognized to prevent splitting within the
// quoted region, and are removed from the resulting substrings. If a quote in s
// isn't closed err will be set and r will have the unclosed argument as the
-// last element. The backslash is used for escaping.
+// last element. The backslash is used for escaping.
//
// For example, the following string:
//
@@ -167,7 +167,23 @@ func (p *Package) Translate(f *File) {
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
- p.rewriteCalls(f)
+ if p.rewriteCalls(f) {
+ // Add `import _cgo_unsafe "unsafe"` as the first decl
+ // after the package statement.
+ imp := &ast.GenDecl{
+ Tok: token.IMPORT,
+ Specs: []ast.Spec{
+ &ast.ImportSpec{
+ Name: ast.NewIdent("_cgo_unsafe"),
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: `"unsafe"`,
+ },
+ },
+ },
+ }
+ f.AST.Decls = append([]ast.Decl{imp}, f.AST.Decls...)
+ }
p.rewriteRef(f)
}
@@ -236,7 +252,7 @@ func (p *Package) guessKinds(f *File) []*Name {
if isConst {
n.Kind = "const"
// Turn decimal into hex, just for consistency
- // with enum-derived constants. Otherwise
+ // with enum-derived constants. Otherwise
// in the cgo -godefs output half the constants
// are in hex and half are in whatever the #define used.
i, err := strconv.ParseInt(n.Define, 0, 64)
@@ -385,7 +401,7 @@ func (p *Package) guessKinds(f *File) []*Name {
if nerrors > 0 {
// Check if compiling the preamble by itself causes any errors,
// because the messages we've printed out so far aren't helpful
- // to users debugging preamble mistakes. See issue 8442.
+ // to users debugging preamble mistakes. See issue 8442.
preambleErrors := p.gccErrors([]byte(f.Preamble))
if len(preambleErrors) > 0 {
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
@@ -403,7 +419,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// being referred to as C.xxx.
func (p *Package) loadDWARF(f *File, names []*Name) {
// Extract the types from the DWARF section of an object
- // from a well-formed C program. Gcc only generates DWARF info
+ // from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
// preamble and hope the symbols we care about will be there.
// Instead, emit
@@ -413,6 +429,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
+ b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
for i, n := range names {
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
if n.Kind == "const" {
@@ -421,7 +438,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
// Apple's LLVM-based gcc does not include the enumeration
- // names and values in its DWARF debug output. In case we're
+ // names and values in its DWARF debug output. In case we're
// using such a gcc, create a data block initialized with the values.
// We can read them out of the object file.
fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
@@ -432,7 +449,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "\t0,\n")
}
}
- // for the last entry, we can not use 0, otherwise
+ // for the last entry, we cannot use 0, otherwise
// in case all __cgodebug_data is zero initialized,
// LLVM-based gcc will place the it in the __DATA.__common
// zero-filled section (our debug/macho doesn't support
@@ -578,10 +595,12 @@ func (p *Package) mangleName(n *Name) {
// rewriteCalls rewrites all calls that pass pointers to check that
// they follow the rules for passing pointers between Go and C.
-func (p *Package) rewriteCalls(f *File) {
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCalls(f *File) bool {
+ needsUnsafe := false
for _, call := range f.Calls {
// This is a call to C.xxx; set goname to "xxx".
- goname := call.Fun.(*ast.SelectorExpr).Sel.Name
+ goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
if goname == "malloc" {
continue
}
@@ -590,92 +609,190 @@ func (p *Package) rewriteCalls(f *File) {
// Probably a type conversion.
continue
}
- p.rewriteCall(f, call, name)
+ if p.rewriteCall(f, call, name) {
+ needsUnsafe = true
+ }
}
+ return needsUnsafe
}
-// rewriteCall rewrites one call to add pointer checks. We replace
-// each pointer argument x with _cgoCheckPointer(x).(T).
-func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
+// rewriteCall rewrites one call to add pointer checks.
+// If any pointer checks are required, we rewrite the call into a
+// function literal that calls _cgoCheckPointer for each pointer
+// argument and then calls the original function.
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
+ // Avoid a crash if the number of arguments is
+ // less than the number of parameters.
+ // This will be caught when the generated file is compiled.
+ if len(call.Call.Args) < len(name.FuncType.Params) {
+ return false
+ }
+
+ any := false
for i, param := range name.FuncType.Params {
- if len(call.Args) <= i {
- // Avoid a crash; this will be caught when the
- // generated file is compiled.
- return
- }
-
- // An untyped nil does not need a pointer check, and
- // when _cgoCheckPointer returns the untyped nil the
- // type assertion we are going to insert will fail.
- // Easier to just skip nil arguments.
- // TODO: Note that this fails if nil is shadowed.
- if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" {
- continue
+ if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
+ any = true
+ break
}
+ }
+ if !any {
+ return false
+ }
+
+ // We need to rewrite this call.
+ //
+ // We are going to rewrite C.f(p) to
+ // func (_cgo0 ptype) {
+ // _cgoCheckPointer(_cgo0)
+ // C.f(_cgo0)
+ // }(p)
+ // Using a function literal like this lets us do correct
+ // argument type checking, and works correctly if the call is
+ // deferred.
+ needsUnsafe := false
+ params := make([]*ast.Field, len(name.FuncType.Params))
+ nargs := make([]ast.Expr, len(name.FuncType.Params))
+ var stmts []ast.Stmt
+ for i, param := range name.FuncType.Params {
+ // params is going to become the parameters of the
+ // function literal.
+ // nargs is going to become the list of arguments made
+ // by the call within the function literal.
+ // nparam is the parameter of the function literal that
+ // corresponds to param.
- if !p.needsPointerCheck(f, param.Go) {
+ origArg := call.Call.Args[i]
+ nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
+ nargs[i] = nparam
+
+ // The Go version of the C type might use unsafe.Pointer,
+ // but the file might not import unsafe.
+ // Rewrite the Go type if necessary to use _cgo_unsafe.
+ ptype := p.rewriteUnsafe(param.Go)
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+
+ params[i] = &ast.Field{
+ Names: []*ast.Ident{nparam},
+ Type: ptype,
+ }
+
+ if !p.needsPointerCheck(f, param.Go, origArg) {
continue
}
+ // Run the cgo pointer checks on nparam.
+
+ // Change the function literal to call the real function
+ // with the parameter passed through _cgoCheckPointer.
c := &ast.CallExpr{
Fun: ast.NewIdent("_cgoCheckPointer"),
Args: []ast.Expr{
- call.Args[i],
+ nparam,
},
}
// Add optional additional arguments for an address
// expression.
- c.Args = p.checkAddrArgs(f, c.Args, call.Args[i])
-
- // _cgoCheckPointer returns interface{}.
- // We need to type assert that to the type we want.
- // If the Go version of this C type uses
- // unsafe.Pointer, we can't use a type assertion,
- // because the Go file might not import unsafe.
- // Instead we use a local variant of _cgoCheckPointer.
-
- var arg ast.Expr
- if n := p.unsafeCheckPointerName(param.Go); n != "" {
- c.Fun = ast.NewIdent(n)
- arg = c
- } else {
- // In order for the type assertion to succeed,
- // we need it to match the actual type of the
- // argument. The only type we have is the
- // type of the function parameter. We know
- // that the argument type must be assignable
- // to the function parameter type, or the code
- // would not compile, but there is nothing
- // requiring that the types be exactly the
- // same. Add a type conversion to the
- // argument so that the type assertion will
- // succeed.
- c.Args[0] = &ast.CallExpr{
- Fun: param.Go,
- Args: []ast.Expr{
- c.Args[0],
+ c.Args = p.checkAddrArgs(f, c.Args, origArg)
+
+ stmt := &ast.ExprStmt{
+ X: c,
+ }
+ stmts = append(stmts, stmt)
+ }
+
+ fcall := &ast.CallExpr{
+ Fun: call.Call.Fun,
+ Args: nargs,
+ }
+ ftype := &ast.FuncType{
+ Params: &ast.FieldList{
+ List: params,
+ },
+ }
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
+ }
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: rtype,
},
- }
+ },
+ }
+ }
- arg = &ast.TypeAssertExpr{
- X: c,
- Type: param.Go,
+ // There is a Ref pointing to the old call.Call.Fun.
+ for _, ref := range f.Ref {
+ if ref.Expr == &call.Call.Fun {
+ ref.Expr = &fcall.Fun
+
+ // If this call expects two results, we have to
+ // adjust the results of the function we generated.
+ if ref.Context == "call2" {
+ if ftype.Results == nil {
+ // An explicit void argument
+ // looks odd but it seems to
+ // be how cgo has worked historically.
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: ast.NewIdent("_Ctype_void"),
+ },
+ },
+ }
+ }
+ ftype.Results.List = append(ftype.Results.List,
+ &ast.Field{
+ Type: ast.NewIdent("error"),
+ })
}
}
+ }
- call.Args[i] = arg
+ var fbody ast.Stmt
+ if ftype.Results == nil {
+ fbody = &ast.ExprStmt{
+ X: fcall,
+ }
+ } else {
+ fbody = &ast.ReturnStmt{
+ Results: []ast.Expr{fcall},
+ }
+ }
+ call.Call.Fun = &ast.FuncLit{
+ Type: ftype,
+ Body: &ast.BlockStmt{
+ List: append(stmts, fbody),
+ },
}
+ call.Call.Lparen = token.NoPos
+ call.Call.Rparen = token.NoPos
+
+ return needsUnsafe
}
// needsPointerCheck returns whether the type t needs a pointer check.
// This is true if t is a pointer and if the value to which it points
// might contain a pointer.
-func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
+func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
+ // An untyped nil does not need a pointer check, and when
+ // _cgoCheckPointer returns the untyped nil the type assertion we
+ // are going to insert will fail. Easier to just skip nil arguments.
+ // TODO: Note that this fails if nil is shadowed.
+ if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
+ return false
+ }
+
return p.hasPointer(f, t, true)
}
-// hasPointer is used by needsPointerCheck. If top is true it returns
+// hasPointer is used by needsPointerCheck. If top is true it returns
// whether t is or contains a pointer that might point to a pointer.
// If top is false it returns whether t is or contains a pointer.
// f may be nil.
@@ -700,6 +817,11 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if !top {
return true
}
+ // Check whether this is a pointer to a C union (or class)
+ // type that contains a pointer.
+ if unionWithPointer[t.X] {
+ return true
+ }
return p.hasPointer(f, t.X, false)
case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
return true
@@ -732,7 +854,7 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if goTypes[t.Name] != nil {
return false
}
- // We can't figure out the type. Conservative
+ // We can't figure out the type. Conservative
// approach is to assume it has a pointer.
return true
case *ast.SelectorExpr:
@@ -750,7 +872,7 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
return p.hasPointer(f, name.Type.Go, top)
}
- // We can't figure out the type. Conservative
+ // We can't figure out the type. Conservative
// approach is to assume it has a pointer.
return true
default:
@@ -760,14 +882,14 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
}
// checkAddrArgs tries to add arguments to the call of
-// _cgoCheckPointer when the argument is an address expression. We
+// _cgoCheckPointer when the argument is an address expression. We
// pass true to mean that the argument is an address operation of
// something other than a slice index, which means that it's only
// necessary to check the specific element pointed to, not the entire
-// object. This is for &s.f, where f is a field in a struct. We can
+// object. This is for &s.f, where f is a field in a struct. We can
// pass a slice or array, meaning that we should check the entire
// slice or array but need not check any other part of the object.
-// This is for &s.a[i], where we need to check all of a. However, we
+// This is for &s.a[i], where we need to check all of a. However, we
// only pass the slice or array if we can refer to it without side
// effects.
func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
@@ -786,7 +908,7 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
index, ok := u.X.(*ast.IndexExpr)
if !ok {
// This is the address of something that is not an
- // index expression. We only need to examine the
+ // index expression. We only need to examine the
// single value to which it points.
// TODO: what if true is shadowed?
return append(args, ast.NewIdent("true"))
@@ -819,14 +941,17 @@ func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
func (p *Package) isType(t ast.Expr) bool {
switch t := t.(type) {
case *ast.SelectorExpr:
- if t.Sel.Name != "Pointer" {
- return false
- }
id, ok := t.X.(*ast.Ident)
if !ok {
return false
}
- return id.Name == "unsafe"
+ if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return true
+ }
+ if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
+ return true
+ }
+ return false
case *ast.Ident:
// TODO: This ignores shadowing.
switch t.Name {
@@ -850,60 +975,57 @@ func (p *Package) isType(t ast.Expr) bool {
return false
}
-// unsafeCheckPointerName is given the Go version of a C type. If the
-// type uses unsafe.Pointer, we arrange to build a version of
-// _cgoCheckPointer that returns that type. This avoids using a type
-// assertion to unsafe.Pointer in our copy of user code. We return
-// the name of the _cgoCheckPointer function we are going to build, or
-// the empty string if the type does not use unsafe.Pointer.
-func (p *Package) unsafeCheckPointerName(t ast.Expr) string {
- if !p.hasUnsafePointer(t) {
- return ""
- }
- var buf bytes.Buffer
- conf.Fprint(&buf, fset, t)
- s := buf.String()
- for i, t := range p.CgoChecks {
- if s == t {
- return p.unsafeCheckPointerNameIndex(i)
- }
- }
- p.CgoChecks = append(p.CgoChecks, s)
- return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
-}
-
-// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
-// t is the Go version of a C type, so we don't need to handle every case.
-// We only care about direct references, not references via typedefs.
-func (p *Package) hasUnsafePointer(t ast.Expr) bool {
+// rewriteUnsafe returns a version of t with references to unsafe.Pointer
+// rewritten to use _cgo_unsafe.Pointer instead.
+func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
switch t := t.(type) {
case *ast.Ident:
// We don't see a SelectorExpr for unsafe.Pointer;
// this is created by code in this file.
- return t.Name == "unsafe.Pointer"
+ if t.Name == "unsafe.Pointer" {
+ return ast.NewIdent("_cgo_unsafe.Pointer")
+ }
case *ast.ArrayType:
- return p.hasUnsafePointer(t.Elt)
+ t1 := p.rewriteUnsafe(t.Elt)
+ if t1 != t.Elt {
+ r := *t
+ r.Elt = t1
+ return &r
+ }
case *ast.StructType:
+ changed := false
+ fields := *t.Fields
+ fields.List = nil
for _, f := range t.Fields.List {
- if p.hasUnsafePointer(f.Type) {
- return true
+ ft := p.rewriteUnsafe(f.Type)
+ if ft == f.Type {
+ fields.List = append(fields.List, f)
+ } else {
+ fn := *f
+ fn.Type = ft
+ fields.List = append(fields.List, &fn)
+ changed = true
}
}
+ if changed {
+ r := *t
+ r.Fields = &fields
+ return &r
+ }
case *ast.StarExpr: // Pointer type.
- return p.hasUnsafePointer(t.X)
+ x1 := p.rewriteUnsafe(t.X)
+ if x1 != t.X {
+ r := *t
+ r.X = x1
+ return &r
+ }
}
- return false
-}
-
-// unsafeCheckPointerNameIndex returns the name to use for a
-// _cgoCheckPointer variant based on the index in the CgoChecks slice.
-func (p *Package) unsafeCheckPointerNameIndex(i int) string {
- return fmt.Sprintf("_cgoCheckPointer%d", i)
+ return t
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
// Go equivalents, now that we have figured out the meaning of all
-// the xxx. In *godefs mode, rewriteRef replaces the names
+// the xxx. In *godefs mode, rewriteRef replaces the names
// with full definitions instead of mangled names.
func (p *Package) rewriteRef(f *File) {
// Keep a list of all the functions, to remove the ones
@@ -926,7 +1048,7 @@ func (p *Package) rewriteRef(f *File) {
// Now that we have all the name types filled in,
// scan through the Refs to identify the ones that
- // are trying to do a ,err call. Also check that
+ // are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
if r.Name.Kind == "const" && r.Name.Const == "" {
@@ -984,7 +1106,7 @@ func (p *Package) rewriteRef(f *File) {
f.Name[fpName] = name
}
r.Name = name
- // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
// function is defined in out.go and simply returns its argument. See
// issue 7757.
expr = &ast.CallExpr{
@@ -1006,7 +1128,7 @@ func (p *Package) rewriteRef(f *File) {
if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
} else {
- error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
+ error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
}
case "type":
@@ -1086,6 +1208,10 @@ func (p *Package) gccMachine() []string {
return []string{"-m31"}
case "s390x":
return []string{"-m64"}
+ case "mips64", "mips64le":
+ return []string{"-mabi=64"}
+ case "mips", "mipsle":
+ return []string{"-mabi=32"}
}
return nil
}
@@ -1152,7 +1278,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
for i := range f.Symtab.Syms {
s := &f.Symtab.Syms[i]
if isDebugData(s.Name) {
- // Found it. Now find data section.
+ // Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
@@ -1179,7 +1305,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
for i := range symtab {
s := &symtab[i]
if isDebugData(s.Name) {
- // Found it. Now find data section.
+ // Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
@@ -1232,18 +1358,26 @@ func (p *Package) gccDefines(stdin []byte) string {
}
// gccErrors runs gcc over the C program stdin and returns
-// the errors that gcc prints. That is, this function expects
+// the errors that gcc prints. That is, this function expects
// gcc to fail.
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)
@@ -1279,8 +1413,7 @@ func runGcc(stdin []byte, args []string) (string, string) {
// with equivalent memory layout.
type typeConv struct {
// Cache of already-translated or in-progress types.
- m map[dwarf.Type]*Type
- typedef map[string]ast.Expr
+ m map[dwarf.Type]*Type
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
@@ -1307,6 +1440,10 @@ var tagGen int
var typedef = make(map[string]*Type)
var goIdent = make(map[string]*ast.Ident)
+// unionWithPointer is true for a Go type that represents a C union (or class)
+// that may contain a pointer. This is used for cgo pointer checking.
+var unionWithPointer = make(map[ast.Expr]bool)
+
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
@@ -1356,6 +1493,19 @@ func base(dt dwarf.Type) dwarf.Type {
return dt
}
+// unqual strips away qualifiers from a DWARF type.
+// In general we don't care about top-level qualifiers.
+func unqual(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ } else {
+ break
+ }
+ }
+ return dt
+}
+
// Map from dwarf text names to aliases we use in package "C".
var dwarfToName = map[string]string{
"long int": "long",
@@ -1372,7 +1522,7 @@ var dwarfToName = map[string]string{
const signedDelta = 64
-// String returns the current type representation. Format arguments
+// String returns the current type representation. Format arguments
// are assembled within this method so that any changes in mutable
// values are taken into account.
func (tr *TypeRepr) String() string {
@@ -1533,7 +1683,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
case 16:
t.Go = c.complex128
}
- if t.Align = t.Size; t.Align >= c.ptrSize {
+ if t.Align = t.Size / 2; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
@@ -1579,6 +1729,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
t.Go = c.goVoidPtr
t.C.Set("void*")
+ dq := dt.Type
+ for {
+ if d, ok := dq.(*dwarf.QualType); ok {
+ t.C.Set(d.Qual + " " + t.C.String())
+ dq = d.Type
+ } else {
+ break
+ }
+ }
break
}
@@ -1591,9 +1750,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType:
- // Ignore qualifier.
- t = c.Type(dt.Type, pos)
- c.m[dtype] = t
+ t1 := c.Type(dt.Type, pos)
+ t.Size = t1.Size
+ t.Align = t1.Align
+ t.Go = t1.Go
+ if unionWithPointer[t1.Go] {
+ unionWithPointer[t.Go] = true
+ }
+ t.EnumValues = nil
+ t.Typedef = ""
+ t.C.Set("%s "+dt.Qual, t1.C)
return t
case *dwarf.StructType:
@@ -1625,6 +1791,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
switch dt.Kind {
case "class", "union":
t.Go = c.Opaque(t.Size)
+ if c.dwarfHasPointer(dt, pos) {
+ unionWithPointer[t.Go] = true
+ }
if t.C.Empty() {
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
}
@@ -1667,6 +1836,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
goIdent[name.Name] = name
sub := c.Type(dt.Type, pos)
t.Go = name
+ if unionWithPointer[sub.Go] {
+ unionWithPointer[t.Go] = true
+ }
t.Size = sub.Size
t.Align = sub.Align
oldType := typedef[name.Name]
@@ -1797,7 +1969,7 @@ func isStructUnionClass(x ast.Expr) bool {
// FuncArg returns a Go type with the same memory layout as
// dtype when used as the type of a C function argument.
func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
- t := c.Type(dtype, pos)
+ t := c.Type(unqual(dtype), pos)
switch dt := dtype.(type) {
case *dwarf.ArrayType:
// Arrays are passed implicitly as pointers in C.
@@ -1812,7 +1984,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
}
case *dwarf.TypedefType:
// C has much more relaxed rules than Go for
- // implicit type conversions. When the parameter
+ // implicit type conversions. When the parameter
// is type T defined as *X, simulate a little of the
// laxness of C by making the argument *X instead of T.
if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
@@ -1827,9 +1999,12 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
return nil
}
- // Remember the C spelling, in case the struct
- // has __attribute__((unavailable)) on it. See issue 2888.
- t.Typedef = dt.Name
+ // For a struct/union/class, remember the C spelling,
+ // in case it has __attribute__((unavailable)).
+ // See issue 2888.
+ if isStructUnionClass(t.Go) {
+ t.Typedef = dt.Name
+ }
}
}
return t
@@ -1843,7 +2018,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
for i, f := range dtype.ParamType {
// gcc's DWARF generator outputs a single DotDotDotType parameter for
// function pointers that specify no parameters (e.g. void
- // (*__cgo_0)()). Treat this special case as void. This case is
+ // (*__cgo_0)()). Treat this special case as void. This case is
// invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
// legal).
if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
@@ -1858,7 +2033,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType, pos)
+ r = c.Type(unqual(dtype.ReturnType), pos)
gr = []*ast.Field{{Type: r.Go}}
}
return &FuncType{
@@ -1914,8 +2089,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
off := int64(0)
// Rename struct fields that happen to be named Go keywords into
- // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
- // be mangled. Any existing identifier that already has the same name on
+ // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
+ // be mangled. Any existing identifier that already has the same name on
// the C-side will cause the Go-mangled version to be prefixed with _.
// (e.g. in a struct with fields '_type' and 'type', the latter would be
// rendered as '__type' in Go).
@@ -1955,7 +2130,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
// In godefs mode, if this field is a C11
// anonymous union then treat the first field in the
- // union as the field in the struct. This handles
+ // union as the field in the struct. This handles
// cases like the glibc <sys/resource.h> file; see
// issue 6677.
if *godefs {
@@ -2025,7 +2200,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
// We can't permit that, because then the size of the Go
// struct will not be the same as the size of the C struct.
// Our only option in such a case is to remove the field,
- // which means that it can not be referenced from Go.
+ // which means that it cannot be referenced from Go.
for off > 0 && sizes[len(sizes)-1] == 0 {
n := len(sizes)
fld = fld[0 : n-1]
@@ -2045,6 +2220,44 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
return
}
+// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
+func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
+ switch dt := dt.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dt)
+ return false
+
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
+ *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
+ *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
+
+ return false
+
+ case *dwarf.ArrayType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.PtrType:
+ return true
+
+ case *dwarf.QualType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ if c.dwarfHasPointer(f.Type, pos) {
+ return true
+ }
+ }
+ return false
+
+ case *dwarf.TypedefType:
+ if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
+ return true
+ }
+ return c.dwarfHasPointer(dt.Type, pos)
+ }
+}
+
func upper(s string) string {
if s == "" {
return ""
@@ -2079,7 +2292,7 @@ func godefsFields(fld []*ast.Field) {
}
// fieldPrefix returns the prefix that should be removed from all the
-// field names when generating the C or Go code. For generated
+// field names when generating the C or Go code. For generated
// C, we leave the names as is (tv_sec, tv_usec), since that's what
// people are used to seeing in C. For generated Go code, such as
// package syscall's data structures, we drop a common prefix
@@ -2089,7 +2302,7 @@ func fieldPrefix(fld []*ast.Field) string {
for _, f := range fld {
for _, n := range f.Names {
// Ignore field names that don't have the prefix we're
- // looking for. It is common in C headers to have fields
+ // looking for. It is common in C headers to have fields
// named, say, _pad in an otherwise prefixed header.
// If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
// still want to remove the tv_ prefix.
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index aff616ea57..6d638f0644 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 6171b9d067..c91c830260 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -42,7 +42,6 @@ type Package struct {
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
- CgoChecks []string // see unsafeCheckPointerName
}
// A File collects information about a single Go input file.
@@ -52,7 +51,7 @@ type File struct {
Package string // Package name
Preamble string // C preamble (doc comment on import "C")
Ref []*Ref // all references to C.xxx in AST
- Calls []*ast.CallExpr // all calls to C.xxx in AST
+ Calls []*Call // all calls to C.xxx in AST
ExpFunc []*ExpFunc // exported functions for this file
Name map[string]*Name // map from Go name to Name
}
@@ -66,6 +65,12 @@ func nameKeys(m map[string]*Name) []string {
return ks
}
+// A Call refers to a call of a C.xxx function in the AST.
+type Call struct {
+ Call *ast.CallExpr
+ Deferred bool
+}
+
// A Ref refers to an expression of the form C.xxx in the AST.
type Ref struct {
Name *Name
@@ -144,6 +149,8 @@ var ptrSizeMap = map[string]int64{
"mipsn32": 4,
"mipso64": 8,
"mipsn64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc": 4,
@@ -166,6 +173,8 @@ var intSizeMap = map[string]int64{
"mipsn32": 4,
"mipso64": 8,
"mipsn64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc": 4,
@@ -191,6 +200,7 @@ var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+var srcDir = flag.String("srcdir", "", "source directory")
var objDir = flag.String("objdir", "", "object directory")
var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
@@ -208,9 +218,9 @@ func main() {
if *dynobj != "" {
// cgo -dynimport is essentially a separate helper command
- // built into the cgo binary. It scans a gcc-produced executable
+ // built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
- // imported libraries. The 'go build' rules for cgo prepare an
+ // imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
@@ -245,6 +255,12 @@ func main() {
goFiles := args[i:]
+ for _, arg := range args[:i] {
+ if arg == "-fsanitize=thread" {
+ tsanProlog = yesTsanProlog
+ }
+ }
+
p := newPackage(args[:i])
// Record CGO_LDFLAGS from the environment for external linking.
@@ -263,6 +279,9 @@ func main() {
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
for _, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f, err := os.Open(input)
if err != nil {
fatalf("%s", err)
@@ -274,6 +293,9 @@ func main() {
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f := new(File)
f.ReadGo(input)
f.DiscardCgoDirectives()
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index ca0ec0aaa2..e82ec375a2 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -19,7 +19,10 @@ import (
"strings"
)
-var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+var (
+ conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+ noSourceConf = printer.Config{Tabwidth: 8}
+)
// writeDefs creates output files to be compiled by gc and gcc.
func (p *Package) writeDefs() {
@@ -50,14 +53,16 @@ func (p *Package) writeDefs() {
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
- fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
+ fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done() { return 0; }\n")
+ fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
- // which provides these functions. We just need a prototype.
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
- fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
+ // which provides these functions. We just need a prototype.
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
+ fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
+ fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
}
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
@@ -93,7 +98,19 @@ func (p *Package) writeDefs() {
for _, name := range typedefNames {
def := typedef[name]
fmt.Fprintf(fgo2, "type %s ", name)
- conf.Fprint(fgo2, fset, def.Go)
+ // We don't have source info for these types, so write them out without source info.
+ // Otherwise types would look like:
+ //
+ // type _Ctype_struct_cb struct {
+ // //line :1
+ // on_test *[0]byte
+ // //line :1
+ // }
+ //
+ // Which is not useful. Moreover we never override source info,
+ // so subsequent source code uses the same source info.
+ // Moreover, empty file name makes compile emit no source debug info at all.
+ noSourceConf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
if *gccgo {
@@ -109,11 +126,11 @@ func (p *Package) writeDefs() {
fmt.Fprint(fgo2, goProlog)
}
- for i, t := range p.CgoChecks {
- n := p.unsafeCheckPointerNameIndex(i)
- fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
- fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
- fmt.Fprintf(fgo2, "}\n")
+ if fc != nil {
+ fmt.Fprintf(fc, "#line 1 \"cgo-generated-wrappers\"\n")
+ }
+ if fm != nil {
+ fmt.Fprintf(fm, "#line 1 \"cgo-generated-wrappers\"\n")
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@@ -173,10 +190,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)
}
}
@@ -187,6 +205,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)
}
@@ -331,11 +355,7 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- qual := ""
- if c := t.C.String(); c[len(c)-1] == '*' {
- qual = "const "
- }
- fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ fmt.Fprintf(&buf, "\t\t%s r;\n", t.C)
off += t.Size
}
if off%p.PtrSize != 0 {
@@ -350,7 +370,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
@@ -439,6 +459,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
}
@@ -458,6 +481,7 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
}
fmt.Fprint(fgo2, "\n")
+ fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
@@ -507,6 +531,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
// Gcc output starts with the preamble.
fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
+ fmt.Fprintf(fgcc, "%s\n", tsanProlog)
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
@@ -531,6 +556,7 @@ func fixGo(name string) string {
var isBuiltin = map[string]bool{
"_Cfunc_CString": true,
+ "_Cfunc_CBytes": true,
"_Cfunc_GoString": true,
"_Cfunc_GoStringN": true,
"_Cfunc_GoBytes": true,
@@ -555,6 +581,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 {
@@ -563,7 +590,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n")
if n.AddError {
- fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ fmt.Fprintf(fgcc, "\tint _cgo_errno;\n")
}
// We're trying to write a gcc struct that matches gc's layout.
// Use packed attribute to force no padding in this struct in case
@@ -573,31 +600,33 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Save the stack top for use below.
fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
}
+ tr := n.FuncType.Result
+ if tr != nil {
+ fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n")
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ }
fmt.Fprintf(fgcc, "\t")
- if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
- if c := t.C.String(); c[len(c)-1] == '*' {
+ if tr != nil {
+ fmt.Fprintf(fgcc, "r = ")
+ if c := tr.C.String(); c[len(c)-1] == '*' {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // We know the type params are correct, because
- // the Go equivalents had good type params.
- // However, our version of the type omits the magic
- // words const and volatile, which can provoke
- // C compiler warnings. Silence them by casting
- // all pointers to void*. (Eventually that will produce
- // other warnings.)
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(void*)")
- }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n")
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
@@ -606,18 +635,19 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "\ta->r = r;\n")
}
if n.AddError {
- fmt.Fprintf(fgcc, "\treturn errno;\n")
+ fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
}
-// Write out a wrapper for a function when using gccgo. This is a
-// simple wrapper that just calls the real function. We only need a
+// Write out a wrapper for a function when using gccgo. This is a
+// simple wrapper that just calls the real function. We only need a
// wrapper to support static functions in the prologue--without a
// 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 {
@@ -636,26 +666,36 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, ")\n")
fmt.Fprintf(fgcc, "{\n")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "return ")
+ fmt.Fprintf(fgcc, "r = ")
// Cast to void* to avoid warnings due to omitted qualifiers.
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // Cast to void* to avoid warnings due to omitted qualifiers.
+ fmt.Fprintf(fgcc, "p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "\treturn ")
+ // Cast to void* to avoid warnings due to omitted qualifiers
+ // and explicit incompatible struct types.
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
}
- fmt.Fprintf(fgcc, "p%d", i)
+ fmt.Fprintf(fgcc, "r;\n")
}
- fmt.Fprintf(fgcc, ");\n")
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
}
@@ -679,16 +719,20 @@ 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), void *, int);\n")
- fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\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 {
fn := exp.Func
// Construct a gcc struct matching the gc argument and
- // result frame. The gcc struct will be compiled with
+ // result frame. The gcc struct will be compiled with
// __attribute__((packed)) so all padding must be accounted
// for explicitly.
ctype := "struct {\n"
@@ -783,10 +827,11 @@ 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);\n", cPrefix, exp.ExpName)
+ 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_cgo_wait_runtime_init_done();\n")
+ fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
@@ -798,7 +843,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
if gccResult != "void" {
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
@@ -823,10 +871,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
- fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
// The indirect here is converting from a Go function pointer to a C function pointer.
- fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
+ fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
fmt.Fprintf(fgo2, "}\n")
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
@@ -915,6 +963,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
+ fmt.Fprintf(fgcc, "%s\n", tsanProlog)
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -983,13 +1032,17 @@ 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)
+ }
fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
fmt.Fprint(fgcc, "\t")
if resultCount > 0 {
- fmt.Fprint(fgcc, "return ")
+ fmt.Fprint(fgcc, "r = ")
}
fmt.Fprintf(fgcc, "%s(", goName)
if fn.Recv != nil {
@@ -1003,6 +1056,10 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "p%d", i)
})
fmt.Fprint(fgcc, ");\n")
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ if resultCount > 0 {
+ fmt.Fprint(fgcc, "\treturn r;\n")
+ }
fmt.Fprint(fgcc, "}\n")
// Dummy declaration for _cgo_main.c
@@ -1151,8 +1208,8 @@ var goTypes = map[string]*Type{
"uint64": {Size: 8, Align: 8, C: c("GoUint64")},
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
- "complex64": {Size: 8, Align: 8, C: c("GoComplex64")},
- "complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
+ "complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
+ "complex128": {Size: 16, Align: 8, C: c("GoComplex128")},
}
// Map an ast type to a Type.
@@ -1233,6 +1290,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
const gccProlog = `
+#line 1 "cgo-gcc-prolog"
/*
If x and y are not equal, the type will be invalid
(have a negative array count) and an inscrutable error will come
@@ -1257,7 +1315,39 @@ extern char* _cgo_topofstack(void);
#include <string.h>
`
+// Prologue defining TSAN functions in C.
+const noTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+`
+
+// This must match the TSAN code in runtime/cgo/libcgo.h.
+const yesTsanProlog = `
+#line 1 "cgo-tsan-prolog"
+#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+ __tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+ __tsan_release(&_cgo_sync);
+}
+`
+
+// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
+var tsanProlog = noTsanProlog
+
const builtinProlog = `
+#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t and size_t below */
/* Define intgo when compiling with GCC. */
@@ -1269,6 +1359,7 @@ _GoString_ GoString(char *p);
_GoString_ GoStringN(char *p, int l);
_GoBytes_ GoBytes(void *p, int n);
char *CString(_GoString_);
+void *CBytes(_GoBytes_);
void *_CMalloc(size_t);
`
@@ -1276,21 +1367,18 @@ 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)
+func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
//go:linkname _cgoCheckResult runtime.cgoCheckResult
func _cgoCheckResult(interface{})
`
const gccgoGoProlog = `
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
func _cgoCheckResult(interface{})
`
@@ -1324,7 +1412,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
@@ -1332,9 +1420,18 @@ func _Cfunc_CString(s string) *_Ctype_char {
}
`
+const cBytesDef = `
+func _Cfunc_CBytes(b []byte) unsafe.Pointer {
+ p := _cgo_cmalloc(uint64(len(b)))
+ pp := (*[1<<30]byte)(p)
+ copy(pp[:], b)
+ return p
+}
+`
+
const cMallocDef = `
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
- return _cgo_runtime_cmalloc(uintptr(n))
+ return _cgo_cmalloc(uint64(n))
}
`
@@ -1343,15 +1440,67 @@ var builtinDefs = map[string]string{
"GoStringN": goStringNDef,
"GoBytes": goBytesDef,
"CString": cStringDef,
+ "CBytes": cBytesDef,
"_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:linkname runtime_throw runtime.throw
+func runtime_throw(string)
+
+//go:cgo_unsafe_args
+func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
+ _cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
+ if r1 == nil {
+ runtime_throw("runtime: C malloc failed")
+ }
+ 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)
}
const cPrologGccgo = `
+#line 1 "cgo-c-prolog-gccgo"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -1380,6 +1529,12 @@ const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
return p;
}
+void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
+ char *p = malloc(b.__count);
+ memmove(p, b.__values, b.__count);
+ return p;
+}
+
struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
intgo len = (p != NULL) ? strlen(p) : 0;
return __go_byte_array_to_string(p, len);
@@ -1410,18 +1565,17 @@ typedef struct __go_empty_interface {
void *__object;
} Eface;
-extern Eface runtimeCgoCheckPointer(Eface, Slice)
+extern void runtimeCgoCheckPointer(Eface, Slice)
__asm__("runtime.cgoCheckPointer")
__attribute__((weak));
-extern Eface localCgoCheckPointer(Eface, Slice)
+extern void localCgoCheckPointer(Eface, Slice)
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
-Eface localCgoCheckPointer(Eface ptr, Slice args) {
+void localCgoCheckPointer(Eface ptr, Slice args) {
if(runtimeCgoCheckPointer) {
- return runtimeCgoCheckPointer(ptr, args);
+ runtimeCgoCheckPointer(ptr, args);
}
- return ptr;
}
extern void runtimeCgoCheckResult(Eface)
@@ -1444,6 +1598,7 @@ func (p *Package) gccExportHeaderProlog() string {
const gccExportHeaderProlog = `
/* Start of boilerplate cgo prologue. */
+#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
@@ -1497,6 +1652,7 @@ const gccExportHeaderEpilog = `
// We use weak declarations, and test the addresses, so that this code
// works with older versions of gccgo.
const gccgoExportFileProlog = `
+#line 1 "cgo-gccgo-export-file-prolog"
extern _Bool runtime_iscgo __attribute__ ((weak));
static void GoInit(void) __attribute__ ((constructor));
@@ -1505,5 +1661,5 @@ static void GoInit(void) {
runtime_iscgo = 1;
}
-extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
+extern __SIZE_TYPE__ _cgo_wait_runtime_init_done() __attribute__ ((weak));
`
diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go
index 3adb8e8783..4f5c48864e 100644
--- a/libgo/go/cmd/cgo/util.go
+++ b/libgo/go/cmd/cgo/util.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,6 +8,7 @@ import (
"bytes"
"fmt"
"go/token"
+ "io/ioutil"
"os"
"os/exec"
)
@@ -16,6 +17,43 @@ import (
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+ if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
+ // Some compilers have trouble with standard input.
+ // Others have trouble with -xc.
+ // Avoid both problems by writing a file with a .c extension.
+ f, err := ioutil.TempFile("", "cgo-gcc-input-")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ name := f.Name()
+ f.Close()
+ if err := ioutil.WriteFile(name+".c", stdin, 0666); err != nil {
+ os.Remove(name)
+ fatalf("%s", err)
+ }
+ defer os.Remove(name)
+ defer os.Remove(name + ".c")
+
+ // Build new argument list without -xc and trailing -.
+ new := append(argv[:i:i], argv[i+1:len(argv)-1]...)
+
+ // Since we are going to write the file to a temporary directory,
+ // we will need to add -I . explicitly to the command line:
+ // any #include "foo" before would have looked in the current
+ // directory as the directory "holding" standard input, but now
+ // the temporary directory holds the input.
+ // We've also run into compilers that reject "-I." but allow "-I", ".",
+ // so be sure to use two arguments.
+ // This matters mainly for people invoking cgo -godefs by hand.
+ new = append(new, "-I", ".")
+
+ // Finish argument list with path to C file.
+ new = append(new, name+".c")
+
+ argv = new
+ stdin = nil
+ }
+
p := exec.Command(argv[0], argv[1:]...)
p.Stdin = bytes.NewReader(stdin)
var bout, berr bytes.Buffer
@@ -30,6 +68,15 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
return
}
+func find(argv []string, target string) int {
+ for i, arg := range argv {
+ if arg == target {
+ return i
+ }
+ }
+ return -1
+}
+
func lineno(pos token.Pos) string {
return fset.Position(pos).String()
}
@@ -37,7 +84,7 @@ func lineno(pos token.Pos) string {
// Die with an error message.
func fatalf(msg string, args ...interface{}) {
// If we've already printed other errors, they might have
- // caused the fatal condition. Assume they're enough.
+ // caused the fatal condition. Assume they're enough.
if nerrors == 0 {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
}
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index c81bd40864..3d5dd2b397 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -1,1575 +1,1648 @@
-// Copyright 2011 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.
// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
-/*
-Go is a tool for managing Go source code.
-
-Usage:
-
- go command [arguments]
-
-The commands are:
-
- build compile packages and dependencies
- clean remove object files
- doc show documentation for package or symbol
- env print Go environment information
- fix run go tool fix on packages
- fmt run gofmt on package sources
- generate generate Go files by processing source
- get download and install packages and dependencies
- install compile and install packages and dependencies
- list list packages
- run compile and run Go program
- test test packages
- tool run specified go tool
- version print Go version
- vet run go tool vet on packages
-
-Use "go help [command]" for more information about a command.
-
-Additional help topics:
-
- c calling between Go and C
- buildmode description of build modes
- filetype file types
- gopath GOPATH environment variable
- environment environment variables
- importpath import path syntax
- packages description of package lists
- testflag description of testing flags
- testfunc description of testing functions
-
-Use "go help [topic]" for more information about that topic.
-
-
-Compile packages and dependencies
-
-Usage:
-
- go build [-o output] [-i] [build flags] [packages]
-
-Build compiles the packages named by the import paths,
-along with their dependencies, but it does not install the results.
-
-If the arguments to build are a list of .go files, build treats
-them as a list of source files specifying a single package.
-
-When compiling a single main package, build writes
-the resulting executable to an output file named after
-the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
-or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
-The '.exe' suffix is added when writing a Windows executable.
-
-When compiling multiple packages or a single non-main package,
-build compiles the packages but discards the resulting object,
-serving only as a check that the packages can be built.
-
-The -o flag, only allowed when compiling a single package,
-forces build to write the resulting executable or object
-to the named output file, instead of the default behavior described
-in the last two paragraphs.
-
-The -i flag installs the packages that are dependencies of the target.
-
-The build flags are shared by the build, clean, get, install, list, run,
-and test commands:
-
- -a
- force rebuilding of packages that are already up-to-date.
- -n
- print the commands but do not run them.
- -p n
- the number of programs, such as build commands or
- test binaries, that can be run in parallel.
- The default is the number of CPUs available, except
- on darwin/arm which defaults to 1.
- -race
- enable data race detection.
- Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
- -msan
- enable interoperation with memory sanitizer.
- Supported only on linux/amd64,
- and only with Clang/LLVM as the host C compiler.
- -v
- print the names of packages as they are compiled.
- -work
- print the name of the temporary work directory and
- do not delete it when exiting.
- -x
- print the commands.
-
- -asmflags 'flag list'
- arguments to pass on each go tool asm invocation.
- -buildmode mode
- build mode to use. See 'go help buildmode' for more.
- -compiler name
- name of compiler to use, as in runtime.Compiler (gccgo or gc).
- -gccgoflags 'arg list'
- arguments to pass on each gccgo compiler/linker invocation.
- -gcflags 'arg list'
- arguments to pass on each go tool compile invocation.
- -installsuffix suffix
- a suffix to use in the name of the package installation directory,
- in order to keep output separate from default builds.
- If using the -race flag, the install suffix is automatically set to race
- or, if set explicitly, has _race appended to it. Likewise for the -msan
- flag. Using a -buildmode option that requires non-default compile flags
- has a similar effect.
- -ldflags 'flag list'
- arguments to pass on each go tool link invocation.
- -linkshared
- link against shared libraries previously created with
- -buildmode=shared.
- -pkgdir dir
- install and load all packages from dir instead of the usual locations.
- For example, when building with a non-standard configuration,
- use -pkgdir to keep generated packages in a separate location.
- -tags 'tag list'
- a list of build tags to consider satisfied during the build.
- For more information about build tags, see the description of
- build constraints in the documentation for the go/build package.
- -toolexec 'cmd args'
- a program to use to invoke toolchain programs like vet and asm.
- For example, instead of running asm, the go command will run
- 'cmd args /path/to/asm <arguments for asm>'.
-
-The list flags accept a space-separated list of strings. To embed spaces
-in an element in the list, surround it with either single or double quotes.
-
-For more about specifying packages, see 'go help packages'.
-For more about where packages and binaries are installed,
-run 'go help gopath'.
-For more about calling between Go and C/C++, run 'go help c'.
-
-Note: Build adheres to certain conventions such as those described
-by 'go help gopath'. Not all projects can follow these conventions,
-however. Installations that have their own conventions or that use
-a separate software build system may choose to use lower-level
-invocations such as 'go tool compile' and 'go tool link' to avoid
-some of the overheads and design decisions of the build tool.
-
-See also: go install, go get, go clean.
-
-
-Remove object files
-
-Usage:
-
- go clean [-i] [-r] [-n] [-x] [build flags] [packages]
-
-Clean removes object files from package source directories.
-The go command builds most objects in a temporary directory,
-so go clean is mainly concerned with object files left by other
-tools or by manual invocations of go build.
-
-Specifically, clean removes the following files from each of the
-source directories corresponding to the import paths:
-
- _obj/ old object directory, left from Makefiles
- _test/ old test directory, left from Makefiles
- _testmain.go old gotest file, left from Makefiles
- test.out old test log, left from Makefiles
- build.out old test log, left from Makefiles
- *.[568ao] object files, left from Makefiles
-
- DIR(.exe) from go build
- DIR.test(.exe) from go test -c
- MAINFILE(.exe) from go build MAINFILE.go
- *.so from SWIG
-
-In the list, DIR represents the final path element of the
-directory, and MAINFILE is the base name of any Go source
-file in the directory that is not included when building
-the package.
-
-The -i flag causes clean to remove the corresponding installed
-archive or binary (what 'go install' would create).
-
-The -n flag causes clean to print the remove commands it would execute,
-but not run them.
-
-The -r flag causes clean to be applied recursively to all the
-dependencies of the packages named by the import paths.
-
-The -x flag causes clean to print remove commands as it executes them.
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Show documentation for package or symbol
-
-Usage:
-
- go doc [-u] [-c] [package|[package.]symbol[.method]]
-
-Doc prints the documentation comments associated with the item identified by its
-arguments (a package, const, func, type, var, or method) followed by a one-line
-summary of each of the first-level items "under" that item (package-level
-declarations for a package, methods for a type, etc.).
-
-Doc accepts zero, one, or two arguments.
-
-Given no arguments, that is, when run as
-
- go doc
-
-it prints the package documentation for the package in the current directory.
-If the package is a command (package main), the exported symbols of the package
-are elided from the presentation unless the -cmd flag is provided.
-
-When run with one argument, the argument is treated as a Go-syntax-like
-representation of the item to be documented. What the argument selects depends
-on what is installed in GOROOT and GOPATH, as well as the form of the argument,
-which is schematically one of these:
-
- go doc <pkg>
- go doc <sym>[.<method>]
- go doc [<pkg>.]<sym>[.<method>]
- go doc [<pkg>.][<sym>.]<method>
-
-The first item in this list matched by the argument is the one whose documentation
-is printed. (See the examples below.) However, if the argument starts with a capital
-letter it is assumed to identify a symbol or method in the current directory.
-
-For packages, the order of scanning is determined lexically in breadth-first order.
-That is, the package presented is the one that matches the search and is nearest
-the root and lexically first at its level of the hierarchy. The GOROOT tree is
-always scanned in its entirety before GOPATH.
-
-If there is no package specified or matched, the package in the current
-directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
-the current package.
-
-The package path must be either a qualified path or a proper suffix of a
-path. The go tool's usual package mechanism does not apply: package path
-elements like . and ... are not implemented by go doc.
-
-When run with two arguments, the first must be a full package path (not just a
-suffix), and the second is a symbol or symbol and method; this is similar to the
-syntax accepted by godoc:
-
- go doc <pkg> <sym>[.<method>]
-
-In all forms, when matching symbols, lower-case letters in the argument match
-either case but upper-case letters match exactly. This means that there may be
-multiple matches of a lower-case argument in a package if different symbols have
-different cases. If this occurs, documentation for all matches is printed.
-
-Examples:
- go doc
- Show documentation for current package.
- go doc Foo
- Show documentation for Foo in the current package.
- (Foo starts with a capital letter so it cannot match
- a package path.)
- go doc encoding/json
- Show documentation for the encoding/json package.
- go doc json
- Shorthand for encoding/json.
- go doc json.Number (or go doc json.number)
- Show documentation and method summary for json.Number.
- go doc json.Number.Int64 (or go doc json.number.int64)
- Show documentation for json.Number's Int64 method.
- go doc cmd/doc
- Show package docs for the doc command.
- go doc -cmd cmd/doc
- Show package docs and exported symbols within the doc command.
- go doc template.new
- Show documentation for html/template's New function.
- (html/template is lexically before text/template)
- go doc text/template.new # One argument
- Show documentation for text/template's New function.
- go doc text/template new # Two arguments
- Show documentation for text/template's New function.
-
- At least in the current tree, these invocations all print the
- documentation for json.Decoder's Decode method:
-
- go doc json.Decoder.Decode
- go doc json.decoder.decode
- go doc json.decode
- cd go/src/encoding/json; go doc decode
-
-Flags:
- -c
- Respect case when matching symbols.
- -cmd
- Treat a command (package main) like a regular package.
- Otherwise package main's exported symbols are hidden
- when showing the package's top-level documentation.
- -u
- Show documentation for unexported as well as exported
- symbols and methods.
-
-
-Print Go environment information
-
-Usage:
-
- go env [var ...]
-
-Env prints Go environment information.
-
-By default env prints information as a shell script
-(on Windows, a batch file). If one or more variable
-names is given as arguments, env prints the value of
-each named variable on its own line.
-
-
-Run go tool fix on packages
-
-Usage:
-
- go fix [packages]
-
-Fix runs the Go fix command on the packages named by the import paths.
-
-For more about fix, see 'go doc cmd/fix'.
-For more about specifying packages, see 'go help packages'.
-
-To run fix with specific options, run 'go tool fix'.
-
-See also: go fmt, go vet.
-
-
-Run gofmt on package sources
-
-Usage:
-
- go fmt [-n] [-x] [packages]
-
-Fmt runs the command 'gofmt -l -w' on the packages named
-by the import paths. It prints the names of the files that are modified.
-
-For more about gofmt, see 'go doc cmd/gofmt'.
-For more about specifying packages, see 'go help packages'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-To run gofmt with specific options, run gofmt itself.
-
-See also: go fix, go vet.
-
-
-Generate Go files by processing source
-
-Usage:
-
- go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]
-
-Generate runs commands described by directives within existing
-files. Those commands can run any process but the intent is to
-create or update Go source files, for instance by running yacc.
-
-Go generate is never run automatically by go build, go get, go test,
-and so on. It must be run explicitly.
-
-Go generate scans the file for directives, which are lines of
-the form,
-
- //go:generate command argument...
-
-(note: no leading spaces and no space in "//go") where command
-is the generator to be run, corresponding to an executable file
-that can be run locally. It must either be in the shell path
-(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
-command alias, described below.
-
-Note that go generate does not parse the file, so lines that look
-like directives in comments or multiline strings will be treated
-as directives.
-
-The arguments to the directive are space-separated tokens or
-double-quoted strings passed to the generator as individual
-arguments when it is run.
-
-Quoted strings use Go syntax and are evaluated before execution; a
-quoted string appears as a single argument to the generator.
-
-Go generate sets several variables when it runs the generator:
-
- $GOARCH
- The execution architecture (arm, amd64, etc.)
- $GOOS
- The execution operating system (linux, windows, etc.)
- $GOFILE
- The base name of the file.
- $GOLINE
- The line number of the directive in the source file.
- $GOPACKAGE
- The name of the package of the file containing the directive.
- $DOLLAR
- A dollar sign.
-
-Other than variable substitution and quoted-string evaluation, no
-special processing such as "globbing" is performed on the command
-line.
-
-As a last step before running the command, any invocations of any
-environment variables with alphanumeric names, such as $GOFILE or
-$HOME, are expanded throughout the command line. The syntax for
-variable expansion is $NAME on all operating systems. Due to the
-order of evaluation, variables are expanded even inside quoted
-strings. If the variable NAME is not set, $NAME expands to the
-empty string.
-
-A directive of the form,
-
- //go:generate -command xxx args...
-
-specifies, for the remainder of this source file only, that the
-string xxx represents the command identified by the arguments. This
-can be used to create aliases or to handle multiword generators.
-For example,
-
- //go:generate -command yacc go tool yacc
-
-specifies that the command "yacc" represents the generator
-"go tool yacc".
-
-Generate processes packages in the order given on the command line,
-one at a time. If the command line lists .go files, they are treated
-as a single package. Within a package, generate processes the
-source files in a package in file name order, one at a time. Within
-a source file, generate runs generators in the order they appear
-in the file, one at a time.
-
-If any generator returns an error exit status, "go generate" skips
-all further processing for that package.
-
-The generator is run in the package's source directory.
-
-Go generate accepts one specific flag:
-
- -run=""
- if non-empty, specifies a regular expression to select
- directives whose full original source text (excluding
- any trailing spaces and final newline) matches the
- expression.
-
-It also accepts the standard build flags including -v, -n, and -x.
-The -v flag prints the names of packages and files as they are
-processed.
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Download and install packages and dependencies
-
-Usage:
-
- go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]
-
-Get downloads and installs the packages named by the import paths,
-along with their dependencies.
-
-The -d flag instructs get to stop after downloading the packages; that is,
-it instructs get not to install the packages.
-
-The -f flag, valid only when -u is set, forces get -u not to verify that
-each package has been checked out from the source control repository
-implied by its import path. This can be useful if the source is a local fork
-of the original.
-
-The -fix flag instructs get to run the fix tool on the downloaded packages
-before resolving dependencies or building the code.
-
-The -insecure flag permits fetching from repositories and resolving
-custom domains using insecure schemes such as HTTP. Use with caution.
-
-The -t flag instructs get to also download the packages required to build
-the tests for the specified packages.
-
-The -u flag instructs get to use the network to update the named packages
-and their dependencies. By default, get uses the network to check out
-missing packages but does not use it to look for updates to existing packages.
-
-Get also accepts build flags to control the installation. See 'go help build'.
-
-When checking out a new package, get creates the target directory
-GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
-get uses the first one. See 'go help gopath'.
-
-When checking out or updating a package, get looks for a branch or tag
-that matches the locally installed version of Go. The most important
-rule is that if the local installation is running version "go1", get
-searches for a branch or tag named "go1". If no such version exists it
-retrieves the most recent version of the package.
-
-Unless vendoring support is disabled (see 'go help gopath'),
-when go get checks out or updates a Git repository,
-it also updates any git submodules referenced by the repository.
-
-Get never checks out or updates code stored in vendor directories.
-
-For more about specifying packages, see 'go help packages'.
-
-For more about how 'go get' finds source code to
-download, see 'go help importpath'.
-
-See also: go build, go install, go clean.
-
-
-Compile and install packages and dependencies
-
-Usage:
-
- go install [build flags] [packages]
-
-Install compiles and installs the packages named by the import paths,
-along with their dependencies.
-
-For more about the build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go get, go clean.
-
-
-List packages
-
-Usage:
-
- go list [-e] [-f format] [-json] [build flags] [packages]
-
-List lists the packages named by the import paths, one per line.
-
-The default output shows the package import path:
-
- bytes
- encoding/json
- github.com/gorilla/mux
- golang.org/x/net/html
-
-The -f flag specifies an alternate format for the list, using the
-syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. The struct being passed to the template is:
-
- type Package struct {
- Dir string // directory containing package sources
- ImportPath string // import path of package in dir
- ImportComment string // path in import comment on package statement
- Name string // package name
- Doc string // package documentation string
- Target string // install path
- Shlib string // the shared library that contains this package (only set when -linkshared)
- Goroot bool // is this package in the Go root?
- Standard bool // is this package part of the standard Go library?
- Stale bool // would 'go install' do anything for this package?
- Root string // Go root or Go path dir containing this package
-
- // Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go sources files that import "C"
- IgnoredGoFiles []string // .go sources ignored due to build constraints
- CFiles []string // .c source files
- CXXFiles []string // .cc, .cxx and .cpp source files
- MFiles []string // .m source files
- HFiles []string // .h, .hh, .hpp and .hxx source files
- SFiles []string // .s source files
- SwigFiles []string // .swig files
- SwigCXXFiles []string // .swigcxx files
- SysoFiles []string // .syso object files to add to archive
-
- // Cgo directives
- CgoCFLAGS []string // cgo: flags for C compiler
- CgoCPPFLAGS []string // cgo: flags for C preprocessor
- CgoCXXFLAGS []string // cgo: flags for C++ compiler
- CgoLDFLAGS []string // cgo: flags for linker
- CgoPkgConfig []string // cgo: pkg-config names
-
- // Dependency information
- Imports []string // import paths used by this package
- Deps []string // all (recursively) imported dependencies
-
- // Error information
- Incomplete bool // this package or a dependency has an error
- Error *PackageError // error loading package
- DepsErrors []*PackageError // errors loading dependencies
-
- TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
- XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
- }
-
-The error information, if any, is
-
- type PackageError struct {
- ImportStack []string // shortest path from package named on command line to this one
- Pos string // position of error (if present, file:line:col)
- Err string // the error itself
- }
-
-The template function "join" calls strings.Join.
-
-The template function "context" returns the build context, defined as:
-
- type Context struct {
- GOARCH string // target architecture
- GOOS string // target operating system
- GOROOT string // Go root
- GOPATH string // Go path
- CgoEnabled bool // whether cgo can be used
- UseAllFiles bool // use files regardless of +build lines, file names
- Compiler string // compiler to assume when computing target paths
- BuildTags []string // build constraints to match in +build lines
- ReleaseTags []string // releases the current release is compatible with
- InstallSuffix string // suffix to use in the name of the install dir
- }
-
-For more information about the meaning of these fields see the documentation
-for the go/build package's Context type.
-
-The -json flag causes the package data to be printed in JSON format
-instead of using the template format.
-
-The -e flag changes the handling of erroneous packages, those that
-cannot be found or are malformed. By default, the list command
-prints an error to standard error for each erroneous package and
-omits the packages from consideration during the usual printing.
-With the -e flag, the list command never prints errors to standard
-error and instead processes the erroneous packages with the usual
-printing. Erroneous packages will have a non-empty ImportPath and
-a non-nil Error field; other information may or may not be missing
-(zeroed).
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Compile and run Go program
-
-Usage:
-
- go run [build flags] [-exec xprog] gofiles... [arguments...]
-
-Run compiles and runs the main package comprising the named Go source files.
-A Go source file is defined to be a file ending in a literal ".go" suffix.
-
-By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
-If the -exec flag is given, 'go run' invokes the binary using xprog:
- 'xprog a.out arguments...'.
-If the -exec flag is not given, GOOS or GOARCH is different from the system
-default, and a program named go_$GOOS_$GOARCH_exec can be found
-on the current search path, 'go run' invokes the binary using that program,
-for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
-cross-compiled programs when a simulator or other execution method is
-available.
-
-For more about build flags, see 'go help build'.
-
-See also: go build.
-
-
-Test packages
-
-Usage:
-
- go test [build/test flags] [packages] [build/test flags & test binary flags]
-
-'Go test' automates testing the packages named by the import paths.
-It prints a summary of the test results in the format:
-
- ok archive/tar 0.011s
- FAIL archive/zip 0.022s
- ok compress/gzip 0.033s
- ...
-
-followed by detailed output for each failed package.
-
-'Go test' recompiles each package along with any files with names matching
-the file pattern "*_test.go".
-Files whose names begin with "_" (including "_test.go") or "." are ignored.
-These additional files can contain test functions, benchmark functions, and
-example functions. See 'go help testfunc' for more.
-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.
-
-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.
-
-The package is built in a temporary directory so it does not interfere with the
-non-test installation.
-
-In addition to the build flags, the flags handled by 'go test' itself are:
-
- -args
- Pass the remainder of the command line (everything after -args)
- to the test binary, uninterpreted and unchanged.
- Because this flag consumes the remainder of the command line,
- the package list (if present) must appear before this flag.
-
- -c
- Compile the test binary to pkg.test but do not run it
- (where pkg is the last element of the package's import path).
- The file name can be changed with the -o flag.
-
- -exec xprog
- Run the test binary using xprog. The behavior is the same as
- in 'go run'. See 'go help run' for details.
-
- -i
- Install packages that are dependencies of the test.
- Do not run the test.
-
- -o file
- Compile the test binary to the named file.
- The test still runs (unless -c or -i is specified).
-
-The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'. See 'go help testflag' for details.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-
-
-Run specified go tool
-
-Usage:
-
- go tool [-n] command [args...]
-
-Tool runs the go tool command identified by the arguments.
-With no arguments it prints the list of known tools.
-
-The -n flag causes tool to print the command that would be
-executed but not execute it.
-
-For more about each tool command, see 'go tool command -h'.
-
-
-Print Go version
-
-Usage:
-
- go version
-
-Version prints the Go version, as reported by runtime.Version.
-
-
-Run go tool vet on packages
-
-Usage:
-
- go vet [-n] [-x] [build flags] [packages]
-
-Vet runs the Go vet command on the packages named by the import paths.
-
-For more about vet, see 'go doc cmd/vet'.
-For more about specifying packages, see 'go help packages'.
-
-To run the vet tool with specific options, run 'go tool vet'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-For more about build flags, see 'go help build'.
-
-See also: go fmt, go fix.
-
-
-Calling between Go and C
-
-There are two different ways to call between Go and C/C++ code.
-
-The first is the cgo tool, which is part of the Go distribution. For
-information on how to use it see the cgo documentation (go doc cmd/cgo).
-
-The second is the SWIG program, which is a general tool for
-interfacing between languages. For information on SWIG see
-http://swig.org/. When running go build, any file with a .swig
-extension will be passed to SWIG. Any file with a .swigcxx extension
-will be passed to SWIG with the -c++ option.
-
-When either cgo or SWIG is used, go build will pass any .c, .m, .s,
-or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
-compiler. The CC or CXX environment variables may be set to determine
-the C or C++ compiler, respectively, to use.
-
-
-Description of build modes
-
-The 'go build' and 'go install' commands take a -buildmode argument which
-indicates which kind of object file is to be built. Currently supported values
-are:
-
- -buildmode=archive
- Build the listed non-main packages into .a files. Packages named
- main are ignored.
-
- -buildmode=c-archive
- Build the listed main package, plus all packages it imports,
- into a C archive file. The only callable symbols will be those
- functions exported using a cgo //export comment. Requires
- exactly one main package to be listed.
-
- -buildmode=c-shared
- Build the listed main packages, plus all packages that they
- import, into C shared libraries. The only callable symbols will
- be those functions exported using a cgo //export comment.
- Non-main packages are ignored.
-
- -buildmode=default
- Listed main packages are built into executables and listed
- non-main packages are built into .a files (the default
- behavior).
-
- -buildmode=shared
- Combine all the listed non-main packages into a single shared
- library that will be used when building with the -linkshared
- option. Packages named main are ignored.
-
- -buildmode=exe
- Build the listed main packages and everything they import into
- executables. Packages not named main are ignored.
-
- -buildmode=pie
- Build the listed main packages and everything they import into
- position independent executables (PIE). Packages not named
- main are ignored.
-
-
-File types
-
-The go command examines the contents of a restricted set of files
-in each directory. It identifies which files to examine based on
-the extension of the file name. These extensions are:
-
- .go
- Go source files.
- .c, .h
- C source files.
- If the package uses cgo or SWIG, these will be compiled with the
- OS-native compiler (typically gcc); otherwise they will
- trigger an error.
- .cc, .cpp, .cxx, .hh, .hpp, .hxx
- C++ source files. Only useful with cgo or SWIG, and always
- compiled with the OS-native compiler.
- .m
- Objective-C source files. Only useful with cgo, and always
- compiled with the OS-native compiler.
- .s, .S
- Assembler source files.
- If the package uses cgo or SWIG, these will be assembled with the
- OS-native assembler (typically gcc (sic)); otherwise they
- will be assembled with the Go assembler.
- .swig, .swigcxx
- SWIG definition files.
- .syso
- System object files.
-
-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.
-
-
-GOPATH environment variable
-
-The Go path is used to resolve import statements.
-It is implemented by and documented in the go/build package.
-
-The GOPATH environment variable lists places to look for Go code.
-On Unix, the value is a colon-separated string.
-On Windows, the value is a semicolon-separated string.
-On Plan 9, the value is a list.
-
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
-
-Each directory listed in GOPATH must have a prescribed structure:
-
-The src directory holds source code. The path below src
-determines the import path or executable name.
-
-The pkg directory holds installed package objects.
-As in the Go tree, each target operating system and
-architecture pair has its own subdirectory of pkg
-(pkg/GOOS_GOARCH).
-
-If DIR is a directory listed in the GOPATH, a package with
-source in DIR/src/foo/bar can be imported as "foo/bar" and
-has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
-
-The bin directory holds compiled commands.
-Each command is named for its source directory, but only
-the final element, not the entire path. That is, the
-command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
-so that you can add DIR/bin to your PATH to get at the
-installed commands. If the GOBIN environment variable is
-set, commands are installed to the directory it names instead
-of DIR/bin. GOBIN must be an absolute path.
-
-Here's an example directory layout:
-
- GOPATH=/home/user/gocode
-
- /home/user/gocode/
- src/
- foo/
- bar/ (go code in package bar)
- x.go
- quux/ (go code in package main)
- y.go
- bin/
- quux (installed command)
- pkg/
- linux_amd64/
- foo/
- bar.a (installed package object)
-
-Go searches each directory listed in GOPATH to find source code,
-but new packages are always downloaded into the first directory
-in the list.
-
-See https://golang.org/doc/code.html for an example.
-
-Internal Directories
-
-Code in or below a directory named "internal" is importable only
-by code in the directory tree rooted at the parent of "internal".
-Here's an extended version of the directory layout above:
-
- /home/user/gocode/
- src/
- crash/
- bang/ (go code in package bang)
- b.go
- foo/ (go code in package foo)
- f.go
- bar/ (go code in package bar)
- x.go
- internal/
- baz/ (go code in package baz)
- z.go
- quux/ (go code in package main)
- y.go
-
-
-The code in z.go is imported as "foo/internal/baz", but that
-import statement can only appear in source files in the subtree
-rooted at foo. The source files foo/f.go, foo/bar/x.go, and
-foo/quux/y.go can all import "foo/internal/baz", but the source file
-crash/bang/b.go cannot.
-
-See https://golang.org/s/go14internal for details.
-
-Vendor Directories
-
-Go 1.6 includes support for using local copies of external dependencies
-to satisfy imports of those dependencies, often referred to as vendoring.
-
-Code below a directory named "vendor" is importable only
-by code in the directory tree rooted at the parent of "vendor",
-and only using an import path that omits the prefix up to and
-including the vendor element.
-
-Here's the example from the previous section,
-but with the "internal" directory renamed to "vendor"
-and a new foo/vendor/crash/bang directory added:
-
- /home/user/gocode/
- src/
- crash/
- bang/ (go code in package bang)
- b.go
- foo/ (go code in package foo)
- f.go
- bar/ (go code in package bar)
- x.go
- vendor/
- crash/
- bang/ (go code in package bang)
- b.go
- baz/ (go code in package baz)
- z.go
- quux/ (go code in package main)
- y.go
-
-The same visibility rules apply as for internal, but the code
-in z.go is imported as "baz", not as "foo/vendor/baz".
-
-Code in vendor directories deeper in the source tree shadows
-code in higher directories. Within the subtree rooted at foo, an import
-of "crash/bang" resolves to "foo/vendor/crash/bang", not the
-top-level "crash/bang".
-
-Code in vendor directories is not subject to import path
-checking (see 'go help importpath').
-
-When 'go get' checks out or updates a git repository, it now also
-updates submodules.
-
-Vendor directories do not affect the placement of new repositories
-being checked out for the first time by 'go get': those are always
-placed in the main GOPATH, never in a vendor subtree.
-
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
-See https://golang.org/s/go15vendor for details.
-
-
-Environment variables
-
-The go command, and the tools it invokes, examine a few different
-environment variables. For many of these, you can see the default
-value of on your system by running 'go env NAME', where NAME is the
-name of the variable.
-
-General-purpose environment variables:
-
- GCCGO
- The gccgo command to run for 'go build -compiler=gccgo'.
- GOARCH
- The architecture, or processor, for which to compile code.
- Examples are amd64, 386, arm, ppc64.
- GOBIN
- The directory where 'go install' will install a command.
- GOOS
- The operating system for which to compile code.
- Examples are linux, darwin, windows, netbsd.
- GOPATH
- See 'go help gopath'.
- GORACE
- Options for the race detector.
- See https://golang.org/doc/articles/race_detector.html.
- GOROOT
- The root of the go tree.
-
-Environment variables for use with cgo:
-
- CC
- The command to use to compile C code.
- CGO_ENABLED
- Whether the cgo command is supported. Either 0 or 1.
- CGO_CFLAGS
- Flags that cgo will pass to the compiler when compiling
- C code.
- CGO_CPPFLAGS
- Flags that cgo will pass to the compiler when compiling
- C or C++ code.
- CGO_CXXFLAGS
- Flags that cgo will pass to the compiler when compiling
- C++ code.
- CGO_LDFLAGS
- Flags that cgo will pass to the compiler when linking.
- CXX
- The command to use to compile C++ code.
-
-Architecture-specific environment variables:
-
- GOARM
- For GOARCH=arm, the ARM architecture for which to compile.
- Valid values are 5, 6, 7.
- GO386
- For GOARCH=386, the floating point instruction set.
- Valid values are 387, sse2.
-
-Special-purpose environment variables:
-
- GOROOT_FINAL
- The root of the installed Go tree, when it is
- installed in a location other than where it is built.
- File names in stack traces are rewritten from GOROOT to
- GOROOT_FINAL.
- GO15VENDOREXPERIMENT
- Set to 0 to disable vendoring semantics.
- GO_EXTLINK_ENABLED
- Whether the linker should use external linking mode
- when using -linkmode=auto with code that uses cgo.
- Set to 0 to disable external linking mode, 1 to enable it.
-
-
-Import path syntax
-
-An import path (see 'go help packages') denotes a package
-stored in the local file system. In general, an import path denotes
-either a standard package (such as "unicode/utf8") or a package
-found in one of the work spaces (see 'go help gopath').
-
-Relative import paths
-
-An import path beginning with ./ or ../ is called a relative path.
-The toolchain supports relative import paths as a shortcut in two ways.
-
-First, a relative path can be used as a shorthand on the command line.
-If you are working in the directory containing the code imported as
-"unicode" and want to run the tests for "unicode/utf8", you can type
-"go test ./utf8" instead of needing to specify the full path.
-Similarly, in the reverse situation, "go test .." will test "unicode" from
-the "unicode/utf8" directory. Relative patterns are also allowed, like
-"go test ./..." to test all subdirectories. See 'go help packages' for details
-on the pattern syntax.
-
-Second, if you are compiling a Go program not in a work space,
-you can use a relative path in an import statement in that program
-to refer to nearby code also not in a work space.
-This makes it easy to experiment with small multipackage programs
-outside of the usual work spaces, but such programs cannot be
-installed with "go install" (there is no work space in which to install them),
-so they are rebuilt from scratch each time they are built.
-To avoid ambiguity, Go programs cannot use relative import paths
-within a work space.
-
-Remote import paths
-
-Certain import paths also
-describe how to obtain the source code for the package using
-a revision control system.
-
-A few common code hosting sites have special syntax:
-
- Bitbucket (Git, Mercurial)
-
- import "bitbucket.org/user/project"
- import "bitbucket.org/user/project/sub/directory"
-
- GitHub (Git)
-
- import "github.com/user/project"
- import "github.com/user/project/sub/directory"
-
- Google Code Project Hosting (Git, Mercurial, Subversion)
-
- import "code.google.com/p/project"
- import "code.google.com/p/project/sub/directory"
-
- import "code.google.com/p/project.subrepository"
- import "code.google.com/p/project.subrepository/sub/directory"
-
- Launchpad (Bazaar)
-
- import "launchpad.net/project"
- import "launchpad.net/project/series"
- import "launchpad.net/project/series/sub/directory"
-
- import "launchpad.net/~user/project/branch"
- import "launchpad.net/~user/project/branch/sub/directory"
-
- IBM DevOps Services (Git)
-
- import "hub.jazz.net/git/user/project"
- import "hub.jazz.net/git/user/project/sub/directory"
-
-For code hosted on other servers, import paths may either be qualified
-with the version control type, or the go tool can dynamically fetch
-the import path over https/http and discover where the code resides
-from a <meta> tag in the HTML.
-
-To declare the code location, an import path of the form
-
- repository.vcs/path
-
-specifies the given repository, with or without the .vcs suffix,
-using the named version control system, and then the path inside
-that repository. The supported version control systems are:
-
- Bazaar .bzr
- Git .git
- Mercurial .hg
- Subversion .svn
-
-For example,
-
- import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at
-example.org/user/foo or foo.hg, and
-
- import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at
-example.org/repo or repo.git.
-
-When a version control system supports multiple protocols,
-each is tried in turn when downloading. For example, a Git
-download tries https://, then git+ssh://.
-
-If the import path is not a known code hosting site and also lacks a
-version control qualifier, the go tool attempts to fetch the import
-over https/http and looks for a <meta> tag in the document's HTML
-<head>.
-
-The meta tag has the form:
-
- <meta name="go-import" content="import-prefix vcs repo-root">
-
-The import-prefix is the import path corresponding to the repository
-root. It must be a prefix or an exact match of the package being
-fetched with "go get". If it's not an exact match, another http
-request is made at the prefix to verify the <meta> tags match.
-
-The meta tag should appear as early in the file as possible.
-In particular, it should appear before any raw JavaScript or CSS,
-to avoid confusing the go command's restricted parser.
-
-The vcs is one of "git", "hg", "svn", etc,
-
-The repo-root is the root of the version control system
-containing a scheme and not containing a .vcs qualifier.
-
-For example,
-
- import "example.org/pkg/foo"
-
-will result in the following requests:
-
- https://example.org/pkg/foo?go-get=1 (preferred)
- http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure)
-
-If that page contains the meta tag
-
- <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
-
-the go tool will verify that https://example.org/?go-get=1 contains the
-same meta tag and then git clone https://code.org/r/p/exproj into
-GOPATH/src/example.org.
-
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
-
-The go command attempts to download the version of the
-package appropriate for the Go release being used.
-Run 'go help get' for more.
-
-Import path checking
-
-When the custom import path feature described above redirects to a
-known code hosting site, each of the resulting packages has two possible
-import paths, using the custom domain or the known hosting site.
-
-A package statement is said to have an "import comment" if it is immediately
-followed (before the next newline) by a comment of one of these two forms:
-
- package math // import "path"
- package math /* import "path" * /
-
-The go command will refuse to install a package with an import comment
-unless it is being referred to by that import path. In this way, import comments
-let package authors make sure the custom import path is used and not a
-direct path to the underlying code hosting site.
-
-If vendoring is enabled (see 'go help gopath'), then import path checking is
-disabled for code found within vendor trees. This makes it possible to copy
-code into alternate locations in vendor trees without needing to update import
-comments.
-
-See https://golang.org/s/go14customimport for details.
-
-
-Description of package lists
-
-Many commands apply to a set of packages:
-
- go action [packages]
-
-Usually, [packages] is a list of import paths.
-
-An import path that is a rooted path or that begins with
-a . or .. element is interpreted as a file system path and
-denotes the package in that directory.
-
-Otherwise, the import path P denotes the package found in
-the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
-
-If no import paths are given, the action applies to the
-package in the current directory.
-
-There are four reserved names for paths that should not be used
-for packages to be built with the go tool:
-
-- "main" denotes the top-level package in a stand-alone executable.
-
-- "all" expands to all package directories found in all the GOPATH
-trees. For example, 'go list all' lists all the packages on the local
-system.
-
-- "std" is like all but expands to just the packages in the standard
-Go library.
-
-- "cmd" expands to the Go repository's commands and their
-internal libraries.
-
-An import path is a pattern if it includes one or more "..." wildcards,
-each of which can match any string, including the empty string and
-strings containing slashes. Such a pattern expands to all package
-directories found in the GOPATH trees with names matching the
-patterns. As a special case, x/... matches x as well as x's subdirectories.
-For example, net/... expands to net and packages in its subdirectories.
-
-An import path can also name a package to be downloaded from
-a remote repository. Run 'go help importpath' for details.
-
-Every package in a program must have a unique import path.
-By convention, this is arranged by starting each path with a
-unique prefix that belongs to you. For example, paths used
-internally at Google all begin with 'google', and paths
-denoting remote repositories begin with the path to the code,
-such as 'github.com/user/repo'.
-
-Packages in a program need not have unique package names,
-but there are two reserved package names with special meaning.
-The name main indicates a command, not a library.
-Commands are built into binaries and cannot be imported.
-The name documentation indicates documentation for
-a non-Go program in the directory. Files in package documentation
-are ignored by the go command.
-
-As a special case, if the package list is a list of .go files from a
-single directory, the command is applied to a single synthesized
-package made up of exactly those files, ignoring any build constraints
-in those files and ignoring any other files in the directory.
-
-Directory and file names that begin with "." or "_" are ignored
-by the go tool, as are directories named "testdata".
-
-
-Description of testing flags
-
-The 'go test' command takes both flags that apply to 'go test' itself
-and flags that apply to the resulting test binary.
-
-Several of the flags control profiling and write an execution profile
-suitable for "go tool pprof"; run "go tool pprof -h" for more
-information. The --alloc_space, --alloc_objects, and --show_bytes
-options of pprof control how the information is presented.
-
-The following flags are recognized by the 'go test' command and
-control the execution of any test:
-
- -bench regexp
- Run benchmarks matching the regular expression.
- By default, no benchmarks run. To run all benchmarks,
- use '-bench .' or '-bench=.'.
-
- -benchmem
- Print memory allocation statistics for benchmarks.
-
- -benchtime t
- Run enough iterations of each benchmark to take t, specified
- as a time.Duration (for example, -benchtime 1h30s).
- The default is 1 second (1s).
-
- -blockprofile block.out
- Write a goroutine blocking profile to the specified file
- when all tests are complete.
- Writes test binary as -c would.
-
- -blockprofilerate n
- Control the detail provided in goroutine blocking profiles by
- calling runtime.SetBlockProfileRate with n.
- See 'go doc runtime.SetBlockProfileRate'.
- The profiler aims to sample, on average, one blocking event every
- n nanoseconds the program spends blocked. By default,
- if -test.blockprofile is set without this flag, all blocking events
- are recorded, equivalent to -test.blockprofilerate=1.
-
- -count n
- Run each test and benchmark n times (default 1).
- If -cpu is set, run n times for each GOMAXPROCS value.
- Examples are always run once.
-
- -cover
- Enable coverage analysis.
-
- -covermode set,count,atomic
- Set the mode for coverage analysis for the package[s]
- being tested. The default is "set" unless -race is enabled,
- in which case it is "atomic".
- The values:
- set: bool: does this statement run?
- count: int: how many times does this statement run?
- atomic: int: count, but correct in multithreaded tests;
- significantly more expensive.
- Sets -cover.
-
- -coverpkg pkg1,pkg2,pkg3
- Apply coverage analysis in each test to the given list of packages.
- The default is for each test to analyze only the package being tested.
- Packages are specified as import paths.
- Sets -cover.
-
- -coverprofile cover.out
- Write a coverage profile to the file after all tests have passed.
- Sets -cover.
-
- -cpu 1,2,4
- Specify a list of GOMAXPROCS values for which the tests or
- benchmarks should be executed. The default is the current value
- of GOMAXPROCS.
-
- -cpuprofile cpu.out
- Write a CPU profile to the specified file before exiting.
- Writes test binary as -c would.
-
- -memprofile mem.out
- Write a memory profile to the file after all tests have passed.
- Writes test binary as -c would.
-
- -memprofilerate n
- Enable more precise (and expensive) memory profiles by setting
- runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
- To profile all memory allocations, use -test.memprofilerate=1
- and pass --alloc_space flag to the pprof tool.
-
- -outputdir directory
- Place output files from profiling in the specified directory,
- by default the directory in which "go test" is running.
-
- -parallel n
- Allow parallel execution of test functions that call t.Parallel.
- The value of this flag is the maximum number of tests to run
- simultaneously; by default, it is set to the value of GOMAXPROCS.
- Note that -parallel only applies within a single test binary.
- The 'go test' command may run tests for different packages
- in parallel as well, according to the setting of the -p flag
- (see 'go help build').
-
- -run regexp
- Run only those tests and examples matching the regular
- expression.
-
- -short
- Tell long-running tests to shorten their run time.
- It is off by default but set during all.bash so that installing
- the Go tree can run a sanity check but not spend time running
- exhaustive tests.
-
- -timeout t
- If a test runs longer than t, panic.
- The default is 10 minutes (10m).
-
- -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
- text from Log and Logf calls even if the test succeeds.
-
-Each of these flags is also recognized with an optional 'test.' prefix,
-as in -test.v. When invoking the generated test binary (the result of
-'go test -c') directly, however, the prefix is mandatory.
-
-The 'go test' command rewrites or removes recognized flags,
-as appropriate, both before and after the optional package list,
-before invoking the test binary.
-
-For instance, the command
-
- go test -v -myflag testdata -cpuprofile=prof.out -x
-
-will compile the test binary and then run it as
-
- pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
-
-(The -x flag is removed because it applies only to the go command's
-execution, not to the test itself.)
-
-The test flags that generate profiles (other than for coverage) also
-leave the test binary in pkg.test for use when analyzing the profiles.
-
-When 'go test' runs a test binary, it does so from within the
-corresponding package's source code directory. Depending on the test,
-it may be necessary to do the same when invoking a generated test
-binary directly.
-
-The command-line package list, if present, must appear before any
-flag not known to the go test command. Continuing the example above,
-the package list would have to appear before -myflag, but could appear
-on either side of -v.
-
-To keep an argument for a test binary from being interpreted as a
-known flag or a package name, use -args (see 'go help test') which
-passes the remainder of the command line through to the test binary
-uninterpreted and unaltered.
-
-For instance, the command
-
- go test -v -args -x -v
-
-will compile the test binary and then run it as
-
- pkg.test -test.v -x -v
-
-Similarly,
-
- go test -args math
-
-will compile the test binary and then run it as
-
- pkg.test math
-
-In the first example, the -x and the second -v are passed through to the
-test binary unchanged and with no effect on the go command itself.
-In the second example, the argument math is passed through to the test
-binary, instead of being interpreted as the package list.
-
-
-Description of testing functions
-
-The 'go test' command expects to find test, benchmark, and example functions
-in the "*_test.go" files corresponding to the package under test.
-
-A test function is one named TestXXX (where XXX is any alphanumeric string
-not starting with a lower case letter) and should have the signature,
-
- func TestXXX(t *testing.T) { ... }
-
-A benchmark function is one named BenchmarkXXX and should have the signature,
-
- func BenchmarkXXX(b *testing.B) { ... }
-
-An example function is similar to a test function but, instead of using
-*testing.T to report success or failure, prints output to os.Stdout.
-That output is compared against the function's "Output:" comment, which
-must be the last comment in the function body (see example below). An
-example with no such comment, or with no text after "Output:" is compiled
-but not executed.
-
-Godoc displays the body of ExampleXXX to demonstrate the use
-of the function, constant, or variable XXX. An example of a method M with
-receiver type T or *T is named ExampleT_M. There may be multiple examples
-for a given function, constant, or variable, distinguished by a trailing _xxx,
-where xxx is a suffix not beginning with an upper case letter.
-
-Here is an example of an example:
-
- func ExamplePrintln() {
- Println("The output of\nthis example.")
- // Output: The output of
- // this example.
- }
-
-The entire test file is presented as the example when it contains a single
-example function, at least one other function, type, variable, or constant
-declaration, and no test or benchmark functions.
-
-See the documentation of the testing package for more information.
-
-
-*/
+// Go is a tool for managing Go source code.
+//
+// Usage:
+//
+// go command [arguments]
+//
+// The commands are:
+//
+// build compile packages and dependencies
+// clean remove object files
+// doc show documentation for package or symbol
+// env print Go environment information
+// bug start a bug report
+// fix run go tool fix on packages
+// fmt run gofmt on package sources
+// generate generate Go files by processing source
+// get download and install packages and dependencies
+// install compile and install packages and dependencies
+// list list packages
+// run compile and run Go program
+// test test packages
+// tool run specified go tool
+// version print Go version
+// vet run go tool vet on packages
+//
+// Use "go help [command]" for more information about a command.
+//
+// Additional help topics:
+//
+// c calling between Go and C
+// buildmode description of build modes
+// filetype file types
+// gopath GOPATH environment variable
+// environment environment variables
+// importpath import path syntax
+// packages description of package lists
+// testflag description of testing flags
+// testfunc description of testing functions
+//
+// Use "go help [topic]" for more information about that topic.
+//
+//
+// Compile packages and dependencies
+//
+// Usage:
+//
+// go build [-o output] [-i] [build flags] [packages]
+//
+// Build compiles the packages named by the import paths,
+// along with their dependencies, but it does not install the results.
+//
+// If the arguments to build are a list of .go files, build treats
+// them as a list of source files specifying a single package.
+//
+// When compiling a single main package, build writes
+// the resulting executable to an output file named after
+// the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
+// or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
+// The '.exe' suffix is added when writing a Windows executable.
+//
+// When compiling multiple packages or a single non-main package,
+// build compiles the packages but discards the resulting object,
+// serving only as a check that the packages can be built.
+//
+// When compiling packages, build ignores files that end in '_test.go'.
+//
+// The -o flag, only allowed when compiling a single package,
+// forces build to write the resulting executable or object
+// to the named output file, instead of the default behavior described
+// in the last two paragraphs.
+//
+// The -i flag installs the packages that are dependencies of the target.
+//
+// The build flags are shared by the build, clean, get, install, list, run,
+// and test commands:
+//
+// -a
+// force rebuilding of packages that are already up-to-date.
+// -n
+// print the commands but do not run them.
+// -p n
+// the number of programs, such as build commands or
+// test binaries, that can be run in parallel.
+// The default is the number of CPUs available.
+// -race
+// enable data race detection.
+// Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
+// -msan
+// enable interoperation with memory sanitizer.
+// Supported only on linux/amd64,
+// and only with Clang/LLVM as the host C compiler.
+// -v
+// print the names of packages as they are compiled.
+// -work
+// print the name of the temporary work directory and
+// do not delete it when exiting.
+// -x
+// print the commands.
+//
+// -asmflags 'flag list'
+// arguments to pass on each go tool asm invocation.
+// -buildmode mode
+// build mode to use. See 'go help buildmode' for more.
+// -compiler name
+// name of compiler to use, as in runtime.Compiler (gccgo or gc).
+// -gccgoflags 'arg list'
+// arguments to pass on each gccgo compiler/linker invocation.
+// -gcflags 'arg list'
+// arguments to pass on each go tool compile invocation.
+// -installsuffix suffix
+// a suffix to use in the name of the package installation directory,
+// in order to keep output separate from default builds.
+// If using the -race flag, the install suffix is automatically set to race
+// or, if set explicitly, has _race appended to it. Likewise for the -msan
+// flag. Using a -buildmode option that requires non-default compile flags
+// has a similar effect.
+// -ldflags 'flag list'
+// arguments to pass on each go tool link invocation.
+// -linkshared
+// link against shared libraries previously created with
+// -buildmode=shared.
+// -pkgdir dir
+// install and load all packages from dir instead of the usual locations.
+// For example, when building with a non-standard configuration,
+// use -pkgdir to keep generated packages in a separate location.
+// -tags 'tag list'
+// a list of build tags to consider satisfied during the build.
+// For more information about build tags, see the description of
+// build constraints in the documentation for the go/build package.
+// -toolexec 'cmd args'
+// a program to use to invoke toolchain programs like vet and asm.
+// For example, instead of running asm, the go command will run
+// 'cmd args /path/to/asm <arguments for asm>'.
+//
+// The list flags accept a space-separated list of strings. To embed spaces
+// in an element in the list, surround it with either single or double quotes.
+//
+// For more about specifying packages, see 'go help packages'.
+// For more about where packages and binaries are installed,
+// run 'go help gopath'.
+// For more about calling between Go and C/C++, run 'go help c'.
+//
+// Note: Build adheres to certain conventions such as those described
+// by 'go help gopath'. Not all projects can follow these conventions,
+// however. Installations that have their own conventions or that use
+// a separate software build system may choose to use lower-level
+// invocations such as 'go tool compile' and 'go tool link' to avoid
+// some of the overheads and design decisions of the build tool.
+//
+// See also: go install, go get, go clean.
+//
+//
+// Remove object files
+//
+// Usage:
+//
+// go clean [-i] [-r] [-n] [-x] [build flags] [packages]
+//
+// Clean removes object files from package source directories.
+// The go command builds most objects in a temporary directory,
+// so go clean is mainly concerned with object files left by other
+// tools or by manual invocations of go build.
+//
+// Specifically, clean removes the following files from each of the
+// source directories corresponding to the import paths:
+//
+// _obj/ old object directory, left from Makefiles
+// _test/ old test directory, left from Makefiles
+// _testmain.go old gotest file, left from Makefiles
+// test.out old test log, left from Makefiles
+// build.out old test log, left from Makefiles
+// *.[568ao] object files, left from Makefiles
+//
+// DIR(.exe) from go build
+// DIR.test(.exe) from go test -c
+// MAINFILE(.exe) from go build MAINFILE.go
+// *.so from SWIG
+//
+// In the list, DIR represents the final path element of the
+// directory, and MAINFILE is the base name of any Go source
+// file in the directory that is not included when building
+// the package.
+//
+// The -i flag causes clean to remove the corresponding installed
+// archive or binary (what 'go install' would create).
+//
+// The -n flag causes clean to print the remove commands it would execute,
+// but not run them.
+//
+// The -r flag causes clean to be applied recursively to all the
+// dependencies of the packages named by the import paths.
+//
+// The -x flag causes clean to print remove commands as it executes them.
+//
+// For more about build flags, see 'go help build'.
+//
+// For more about specifying packages, see 'go help packages'.
+//
+//
+// Show documentation for package or symbol
+//
+// Usage:
+//
+// go doc [-u] [-c] [package|[package.]symbol[.method]]
+//
+// Doc prints the documentation comments associated with the item identified by its
+// arguments (a package, const, func, type, var, or method) followed by a one-line
+// summary of each of the first-level items "under" that item (package-level
+// declarations for a package, methods for a type, etc.).
+//
+// Doc accepts zero, one, or two arguments.
+//
+// Given no arguments, that is, when run as
+//
+// go doc
+//
+// it prints the package documentation for the package in the current directory.
+// If the package is a command (package main), the exported symbols of the package
+// are elided from the presentation unless the -cmd flag is provided.
+//
+// When run with one argument, the argument is treated as a Go-syntax-like
+// representation of the item to be documented. What the argument selects depends
+// on what is installed in GOROOT and GOPATH, as well as the form of the argument,
+// which is schematically one of these:
+//
+// go doc <pkg>
+// go doc <sym>[.<method>]
+// go doc [<pkg>.]<sym>[.<method>]
+// go doc [<pkg>.][<sym>.]<method>
+//
+// The first item in this list matched by the argument is the one whose documentation
+// is printed. (See the examples below.) However, if the argument starts with a capital
+// letter it is assumed to identify a symbol or method in the current directory.
+//
+// For packages, the order of scanning is determined lexically in breadth-first order.
+// That is, the package presented is the one that matches the search and is nearest
+// the root and lexically first at its level of the hierarchy. The GOROOT tree is
+// always scanned in its entirety before GOPATH.
+//
+// If there is no package specified or matched, the package in the current
+// directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
+// the current package.
+//
+// The package path must be either a qualified path or a proper suffix of a
+// path. The go tool's usual package mechanism does not apply: package path
+// elements like . and ... are not implemented by go doc.
+//
+// When run with two arguments, the first must be a full package path (not just a
+// suffix), and the second is a symbol or symbol and method; this is similar to the
+// syntax accepted by godoc:
+//
+// go doc <pkg> <sym>[.<method>]
+//
+// In all forms, when matching symbols, lower-case letters in the argument match
+// either case but upper-case letters match exactly. This means that there may be
+// multiple matches of a lower-case argument in a package if different symbols have
+// different cases. If this occurs, documentation for all matches is printed.
+//
+// Examples:
+// go doc
+// Show documentation for current package.
+// go doc Foo
+// Show documentation for Foo in the current package.
+// (Foo starts with a capital letter so it cannot match
+// a package path.)
+// go doc encoding/json
+// Show documentation for the encoding/json package.
+// go doc json
+// Shorthand for encoding/json.
+// go doc json.Number (or go doc json.number)
+// Show documentation and method summary for json.Number.
+// go doc json.Number.Int64 (or go doc json.number.int64)
+// Show documentation for json.Number's Int64 method.
+// go doc cmd/doc
+// Show package docs for the doc command.
+// go doc -cmd cmd/doc
+// Show package docs and exported symbols within the doc command.
+// go doc template.new
+// Show documentation for html/template's New function.
+// (html/template is lexically before text/template)
+// go doc text/template.new # One argument
+// Show documentation for text/template's New function.
+// go doc text/template new # Two arguments
+// Show documentation for text/template's New function.
+//
+// At least in the current tree, these invocations all print the
+// documentation for json.Decoder's Decode method:
+//
+// go doc json.Decoder.Decode
+// go doc json.decoder.decode
+// go doc json.decode
+// cd go/src/encoding/json; go doc decode
+//
+// Flags:
+// -c
+// Respect case when matching symbols.
+// -cmd
+// Treat a command (package main) like a regular package.
+// Otherwise package main's exported symbols are hidden
+// when showing the package's top-level documentation.
+// -u
+// Show documentation for unexported as well as exported
+// symbols and methods.
+//
+//
+// Print Go environment information
+//
+// Usage:
+//
+// go env [var ...]
+//
+// Env prints Go environment information.
+//
+// By default env prints information as a shell script
+// (on Windows, a batch file). If one or more variable
+// names is given as arguments, env prints the value of
+// each named variable on its own line.
+//
+//
+// Start a bug report
+//
+// Usage:
+//
+// go bug
+//
+// Bug opens the default browser and starts a new bug report.
+// The report includes useful system information.
+//
+//
+// Run go tool fix on packages
+//
+// Usage:
+//
+// go fix [packages]
+//
+// Fix runs the Go fix command on the packages named by the import paths.
+//
+// For more about fix, see 'go doc cmd/fix'.
+// For more about specifying packages, see 'go help packages'.
+//
+// To run fix with specific options, run 'go tool fix'.
+//
+// See also: go fmt, go vet.
+//
+//
+// Run gofmt on package sources
+//
+// Usage:
+//
+// go fmt [-n] [-x] [packages]
+//
+// Fmt runs the command 'gofmt -l -w' on the packages named
+// by the import paths. It prints the names of the files that are modified.
+//
+// For more about gofmt, see 'go doc cmd/gofmt'.
+// For more about specifying packages, see 'go help packages'.
+//
+// The -n flag prints commands that would be executed.
+// The -x flag prints commands as they are executed.
+//
+// To run gofmt with specific options, run gofmt itself.
+//
+// See also: go fix, go vet.
+//
+//
+// Generate Go files by processing source
+//
+// Usage:
+//
+// go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]
+//
+// Generate runs commands described by directives within existing
+// files. Those commands can run any process but the intent is to
+// create or update Go source files.
+//
+// Go generate is never run automatically by go build, go get, go test,
+// and so on. It must be run explicitly.
+//
+// Go generate scans the file for directives, which are lines of
+// the form,
+//
+// //go:generate command argument...
+//
+// (note: no leading spaces and no space in "//go") where command
+// is the generator to be run, corresponding to an executable file
+// that can be run locally. It must either be in the shell path
+// (gofmt), a fully qualified path (/usr/you/bin/mytool), or a
+// command alias, described below.
+//
+// Note that go generate does not parse the file, so lines that look
+// like directives in comments or multiline strings will be treated
+// as directives.
+//
+// The arguments to the directive are space-separated tokens or
+// double-quoted strings passed to the generator as individual
+// arguments when it is run.
+//
+// Quoted strings use Go syntax and are evaluated before execution; a
+// quoted string appears as a single argument to the generator.
+//
+// Go generate sets several variables when it runs the generator:
+//
+// $GOARCH
+// The execution architecture (arm, amd64, etc.)
+// $GOOS
+// The execution operating system (linux, windows, etc.)
+// $GOFILE
+// The base name of the file.
+// $GOLINE
+// The line number of the directive in the source file.
+// $GOPACKAGE
+// The name of the package of the file containing the directive.
+// $DOLLAR
+// A dollar sign.
+//
+// Other than variable substitution and quoted-string evaluation, no
+// special processing such as "globbing" is performed on the command
+// line.
+//
+// As a last step before running the command, any invocations of any
+// environment variables with alphanumeric names, such as $GOFILE or
+// $HOME, are expanded throughout the command line. The syntax for
+// variable expansion is $NAME on all operating systems. Due to the
+// order of evaluation, variables are expanded even inside quoted
+// strings. If the variable NAME is not set, $NAME expands to the
+// empty string.
+//
+// A directive of the form,
+//
+// //go:generate -command xxx args...
+//
+// specifies, for the remainder of this source file only, that the
+// string xxx represents the command identified by the arguments. This
+// can be used to create aliases or to handle multiword generators.
+// For example,
+//
+// //go:generate -command foo go tool foo
+//
+// specifies that the command "foo" represents the generator
+// "go tool foo".
+//
+// Generate processes packages in the order given on the command line,
+// one at a time. If the command line lists .go files, they are treated
+// as a single package. Within a package, generate processes the
+// source files in a package in file name order, one at a time. Within
+// a source file, generate runs generators in the order they appear
+// in the file, one at a time.
+//
+// If any generator returns an error exit status, "go generate" skips
+// all further processing for that package.
+//
+// The generator is run in the package's source directory.
+//
+// Go generate accepts one specific flag:
+//
+// -run=""
+// if non-empty, specifies a regular expression to select
+// directives whose full original source text (excluding
+// any trailing spaces and final newline) matches the
+// expression.
+//
+// It also accepts the standard build flags including -v, -n, and -x.
+// The -v flag prints the names of packages and files as they are
+// processed.
+// The -n flag prints commands that would be executed.
+// The -x flag prints commands as they are executed.
+//
+// For more about build flags, see 'go help build'.
+//
+// For more about specifying packages, see 'go help packages'.
+//
+//
+// Download and install packages and dependencies
+//
+// Usage:
+//
+// go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]
+//
+// Get downloads the packages named by the import paths, along with their
+// dependencies. It then installs the named packages, like 'go install'.
+//
+// The -d flag instructs get to stop after downloading the packages; that is,
+// it instructs get not to install the packages.
+//
+// The -f flag, valid only when -u is set, forces get -u not to verify that
+// each package has been checked out from the source control repository
+// implied by its import path. This can be useful if the source is a local fork
+// of the original.
+//
+// The -fix flag instructs get to run the fix tool on the downloaded packages
+// before resolving dependencies or building the code.
+//
+// The -insecure flag permits fetching from repositories and resolving
+// custom domains using insecure schemes such as HTTP. Use with caution.
+//
+// The -t flag instructs get to also download the packages required to build
+// the tests for the specified packages.
+//
+// The -u flag instructs get to use the network to update the named packages
+// and their dependencies. By default, get uses the network to check out
+// missing packages but does not use it to look for updates to existing packages.
+//
+// The -v flag enables verbose progress and debug output.
+//
+// Get also accepts build flags to control the installation. See 'go help build'.
+//
+// When checking out a new package, get creates the target directory
+// GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
+// get uses the first one. For more details see: 'go help gopath'.
+//
+// When checking out or updating a package, get looks for a branch or tag
+// that matches the locally installed version of Go. The most important
+// rule is that if the local installation is running version "go1", get
+// searches for a branch or tag named "go1". If no such version exists it
+// retrieves the most recent version of the package.
+//
+// When go get checks out or updates a Git repository,
+// it also updates any git submodules referenced by the repository.
+//
+// Get never checks out or updates code stored in vendor directories.
+//
+// For more about specifying packages, see 'go help packages'.
+//
+// For more about how 'go get' finds source code to
+// download, see 'go help importpath'.
+//
+// See also: go build, go install, go clean.
+//
+//
+// Compile and install packages and dependencies
+//
+// Usage:
+//
+// go install [build flags] [packages]
+//
+// Install compiles and installs the packages named by the import paths,
+// along with their dependencies.
+//
+// For more about the build flags, see 'go help build'.
+// For more about specifying packages, see 'go help packages'.
+//
+// See also: go build, go get, go clean.
+//
+//
+// List packages
+//
+// Usage:
+//
+// go list [-e] [-f format] [-json] [build flags] [packages]
+//
+// List lists the packages named by the import paths, one per line.
+//
+// The default output shows the package import path:
+//
+// bytes
+// encoding/json
+// github.com/gorilla/mux
+// golang.org/x/net/html
+//
+// The -f flag specifies an alternate format for the list, using the
+// syntax of package template. The default output is equivalent to -f
+// '{{.ImportPath}}'. The struct being passed to the template is:
+//
+// type Package struct {
+// Dir string // directory containing package sources
+// ImportPath string // import path of package in dir
+// ImportComment string // path in import comment on package statement
+// Name string // package name
+// Doc string // package documentation string
+// Target string // install path
+// Shlib string // the shared library that contains this package (only set when -linkshared)
+// Goroot bool // is this package in the Go root?
+// Standard bool // is this package part of the standard Go library?
+// 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)
+// CgoFiles []string // .go sources files that import "C"
+// IgnoredGoFiles []string // .go sources ignored due to build constraints
+// CFiles []string // .c source files
+// CXXFiles []string // .cc, .cxx and .cpp source files
+// MFiles []string // .m source files
+// HFiles []string // .h, .hh, .hpp and .hxx source files
+// FFiles []string // .f, .F, .for and .f90 Fortran source files
+// SFiles []string // .s source files
+// SwigFiles []string // .swig files
+// SwigCXXFiles []string // .swigcxx files
+// SysoFiles []string // .syso object files to add to archive
+// TestGoFiles []string // _test.go files in package
+// XTestGoFiles []string // _test.go files outside package
+//
+// // Cgo directives
+// CgoCFLAGS []string // cgo: flags for C compiler
+// CgoCPPFLAGS []string // cgo: flags for C preprocessor
+// CgoCXXFLAGS []string // cgo: flags for C++ compiler
+// CgoFFLAGS []string // cgo: flags for Fortran compiler
+// CgoLDFLAGS []string // cgo: flags for linker
+// CgoPkgConfig []string // cgo: pkg-config names
+//
+// // Dependency information
+// Imports []string // import paths used by this package
+// Deps []string // all (recursively) imported dependencies
+// TestImports []string // imports from TestGoFiles
+// XTestImports []string // imports from XTestGoFiles
+//
+// // Error information
+// Incomplete bool // this package or a dependency has an error
+// Error *PackageError // error loading package
+// DepsErrors []*PackageError // errors loading dependencies
+// }
+//
+// Packages stored in vendor directories report an ImportPath that includes the
+// path to the vendor directory (for example, "d/vendor/p" instead of "p"),
+// so that the ImportPath uniquely identifies a given copy of a package.
+// The Imports, Deps, TestImports, and XTestImports lists also contain these
+// expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+//
+// The error information, if any, is
+//
+// type PackageError struct {
+// ImportStack []string // shortest path from package named on command line to this one
+// Pos string // position of error (if present, file:line:col)
+// Err string // the error itself
+// }
+//
+// The template function "join" calls strings.Join.
+//
+// The template function "context" returns the build context, defined as:
+//
+// type Context struct {
+// GOARCH string // target architecture
+// GOOS string // target operating system
+// GOROOT string // Go root
+// GOPATH string // Go path
+// CgoEnabled bool // whether cgo can be used
+// UseAllFiles bool // use files regardless of +build lines, file names
+// Compiler string // compiler to assume when computing target paths
+// BuildTags []string // build constraints to match in +build lines
+// ReleaseTags []string // releases the current release is compatible with
+// InstallSuffix string // suffix to use in the name of the install dir
+// }
+//
+// For more information about the meaning of these fields see the documentation
+// for the go/build package's Context type.
+//
+// The -json flag causes the package data to be printed in JSON format
+// instead of using the template format.
+//
+// The -e flag changes the handling of erroneous packages, those that
+// cannot be found or are malformed. By default, the list command
+// prints an error to standard error for each erroneous package and
+// omits the packages from consideration during the usual printing.
+// With the -e flag, the list command never prints errors to standard
+// error and instead processes the erroneous packages with the usual
+// printing. Erroneous packages will have a non-empty ImportPath and
+// a non-nil Error field; other information may or may not be missing
+// (zeroed).
+//
+// For more about build flags, see 'go help build'.
+//
+// For more about specifying packages, see 'go help packages'.
+//
+//
+// Compile and run Go program
+//
+// Usage:
+//
+// go run [build flags] [-exec xprog] gofiles... [arguments...]
+//
+// Run compiles and runs the main package comprising the named Go source files.
+// A Go source file is defined to be a file ending in a literal ".go" suffix.
+//
+// By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+// If the -exec flag is given, 'go run' invokes the binary using xprog:
+// 'xprog a.out arguments...'.
+// If the -exec flag is not given, GOOS or GOARCH is different from the system
+// default, and a program named go_$GOOS_$GOARCH_exec can be found
+// on the current search path, 'go run' invokes the binary using that program,
+// for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+// cross-compiled programs when a simulator or other execution method is
+// available.
+//
+// For more about build flags, see 'go help build'.
+//
+// See also: go build.
+//
+//
+// Test packages
+//
+// Usage:
+//
+// go test [build/test flags] [packages] [build/test flags & test binary flags]
+//
+// 'Go test' automates testing the packages named by the import paths.
+// It prints a summary of the test results in the format:
+//
+// ok archive/tar 0.011s
+// FAIL archive/zip 0.022s
+// ok compress/gzip 0.033s
+// ...
+//
+// followed by detailed output for each failed package.
+//
+// 'Go test' recompiles each package along with any files with names matching
+// the file pattern "*_test.go".
+// Files whose names begin with "_" (including "_test.go") or "." are ignored.
+// These additional files can contain test functions, benchmark functions, and
+// example functions. See 'go help testfunc' for more.
+// 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.
+//
+// The package is built in a temporary directory so it does not interfere with the
+// non-test installation.
+//
+// In addition to the build flags, the flags handled by 'go test' itself are:
+//
+// -args
+// Pass the remainder of the command line (everything after -args)
+// to the test binary, uninterpreted and unchanged.
+// Because this flag consumes the remainder of the command line,
+// the package list (if present) must appear before this flag.
+//
+// -c
+// Compile the test binary to pkg.test but do not run it
+// (where pkg is the last element of the package's import path).
+// The file name can be changed with the -o flag.
+//
+// -exec xprog
+// Run the test binary using xprog. The behavior is the same as
+// in 'go run'. See 'go help run' for details.
+//
+// -i
+// Install packages that are dependencies of the test.
+// Do not run the test.
+//
+// -o file
+// Compile the test binary to the named file.
+// The test still runs (unless -c or -i is specified).
+//
+// The test binary also accepts flags that control execution of the test; these
+// flags are also accessible by 'go test'. See 'go help testflag' for details.
+//
+// For more about build flags, see 'go help build'.
+// For more about specifying packages, see 'go help packages'.
+//
+// See also: go build, go vet.
+//
+//
+// Run specified go tool
+//
+// Usage:
+//
+// go tool [-n] command [args...]
+//
+// Tool runs the go tool command identified by the arguments.
+// With no arguments it prints the list of known tools.
+//
+// The -n flag causes tool to print the command that would be
+// executed but not execute it.
+//
+// For more about each tool command, see 'go tool command -h'.
+//
+//
+// Print Go version
+//
+// Usage:
+//
+// go version
+//
+// Version prints the Go version, as reported by runtime.Version.
+//
+//
+// Run go tool vet on packages
+//
+// Usage:
+//
+// go vet [-n] [-x] [build flags] [packages]
+//
+// Vet runs the Go vet command on the packages named by the import paths.
+//
+// For more about vet, see 'go doc cmd/vet'.
+// For more about specifying packages, see 'go help packages'.
+//
+// To run the vet tool with specific options, run 'go tool vet'.
+//
+// The -n flag prints commands that would be executed.
+// The -x flag prints commands as they are executed.
+//
+// For more about build flags, see 'go help build'.
+//
+// See also: go fmt, go fix.
+//
+//
+// Calling between Go and C
+//
+// There are two different ways to call between Go and C/C++ code.
+//
+// The first is the cgo tool, which is part of the Go distribution. For
+// information on how to use it see the cgo documentation (go doc cmd/cgo).
+//
+// The second is the SWIG program, which is a general tool for
+// interfacing between languages. For information on SWIG see
+// http://swig.org/. When running go build, any file with a .swig
+// extension will be passed to SWIG. Any file with a .swigcxx extension
+// will be passed to SWIG with the -c++ option.
+//
+// When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+// or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+// compiler. The CC or CXX environment variables may be set to determine
+// the C or C++ compiler, respectively, to use.
+//
+//
+// Description of build modes
+//
+// The 'go build' and 'go install' commands take a -buildmode argument which
+// indicates which kind of object file is to be built. Currently supported values
+// are:
+//
+// -buildmode=archive
+// Build the listed non-main packages into .a files. Packages named
+// main are ignored.
+//
+// -buildmode=c-archive
+// Build the listed main package, plus all packages it imports,
+// into a C archive file. The only callable symbols will be those
+// functions exported using a cgo //export comment. Requires
+// exactly one main package to be listed.
+//
+// -buildmode=c-shared
+// Build the listed main packages, plus all packages that they
+// import, into C shared libraries. The only callable symbols will
+// be those functions exported using a cgo //export comment.
+// Non-main packages are ignored.
+//
+// -buildmode=default
+// Listed main packages are built into executables and listed
+// non-main packages are built into .a files (the default
+// behavior).
+//
+// -buildmode=shared
+// Combine all the listed non-main packages into a single shared
+// library that will be used when building with the -linkshared
+// option. Packages named main are ignored.
+//
+// -buildmode=exe
+// Build the listed main packages and everything they import into
+// executables. Packages not named main are ignored.
+//
+// -buildmode=pie
+// Build the listed main packages and everything they import into
+// position independent executables (PIE). Packages not named
+// main are ignored.
+//
+// -buildmode=plugin
+// Build the listed main packages, plus all packages that they
+// import, into a Go plugin. Packages not named main are ignored.
+//
+//
+// File types
+//
+// The go command examines the contents of a restricted set of files
+// in each directory. It identifies which files to examine based on
+// the extension of the file name. These extensions are:
+//
+// .go
+// Go source files.
+// .c, .h
+// C source files.
+// If the package uses cgo or SWIG, these will be compiled with the
+// OS-native compiler (typically gcc); otherwise they will
+// trigger an error.
+// .cc, .cpp, .cxx, .hh, .hpp, .hxx
+// C++ source files. Only useful with cgo or SWIG, and always
+// compiled with the OS-native compiler.
+// .m
+// Objective-C source files. Only useful with cgo, and always
+// compiled with the OS-native compiler.
+// .s, .S
+// Assembler source files.
+// If the package uses cgo or SWIG, these will be assembled with the
+// OS-native assembler (typically gcc (sic)); otherwise they
+// will be assembled with the Go assembler.
+// .swig, .swigcxx
+// SWIG definition files.
+// .syso
+// System object files.
+//
+// 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. 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
+//
+// The Go path is used to resolve import statements.
+// It is implemented by and documented in the go/build package.
+//
+// The GOPATH environment variable lists places to look for Go code.
+// On Unix, the value is a colon-separated string.
+// On Windows, the value is a semicolon-separated string.
+// On Plan 9, the value is a list.
+//
+// If the environment variable is unset, GOPATH defaults
+// to a subdirectory named "go" in the user's home directory
+// ($HOME/go on Unix, %USERPROFILE%\go on Windows),
+// unless that directory holds a Go distribution.
+// Run "go env GOPATH" to see the current GOPATH.
+//
+// See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
+//
+// Each directory listed in GOPATH must have a prescribed structure:
+//
+// The src directory holds source code. The path below src
+// determines the import path or executable name.
+//
+// The pkg directory holds installed package objects.
+// As in the Go tree, each target operating system and
+// architecture pair has its own subdirectory of pkg
+// (pkg/GOOS_GOARCH).
+//
+// If DIR is a directory listed in the GOPATH, a package with
+// source in DIR/src/foo/bar can be imported as "foo/bar" and
+// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+//
+// The bin directory holds compiled commands.
+// Each command is named for its source directory, but only
+// the final element, not the entire path. That is, the
+// command with source in DIR/src/foo/quux is installed into
+// DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
+// so that you can add DIR/bin to your PATH to get at the
+// installed commands. If the GOBIN environment variable is
+// set, commands are installed to the directory it names instead
+// of DIR/bin. GOBIN must be an absolute path.
+//
+// Here's an example directory layout:
+//
+// GOPATH=/home/user/go
+//
+// /home/user/go/
+// src/
+// foo/
+// bar/ (go code in package bar)
+// x.go
+// quux/ (go code in package main)
+// y.go
+// bin/
+// quux (installed command)
+// pkg/
+// linux_amd64/
+// foo/
+// bar.a (installed package object)
+//
+// Go searches each directory listed in GOPATH to find source code,
+// but new packages are always downloaded into the first directory
+// in the list.
+//
+// See https://golang.org/doc/code.html for an example.
+//
+// Internal Directories
+//
+// Code in or below a directory named "internal" is importable only
+// by code in the directory tree rooted at the parent of "internal".
+// Here's an extended version of the directory layout above:
+//
+// /home/user/go/
+// src/
+// crash/
+// bang/ (go code in package bang)
+// b.go
+// foo/ (go code in package foo)
+// f.go
+// bar/ (go code in package bar)
+// x.go
+// internal/
+// baz/ (go code in package baz)
+// z.go
+// quux/ (go code in package main)
+// y.go
+//
+//
+// The code in z.go is imported as "foo/internal/baz", but that
+// import statement can only appear in source files in the subtree
+// rooted at foo. The source files foo/f.go, foo/bar/x.go, and
+// foo/quux/y.go can all import "foo/internal/baz", but the source file
+// crash/bang/b.go cannot.
+//
+// See https://golang.org/s/go14internal for details.
+//
+// Vendor Directories
+//
+// Go 1.6 includes support for using local copies of external dependencies
+// to satisfy imports of those dependencies, often referred to as vendoring.
+//
+// Code below a directory named "vendor" is importable only
+// by code in the directory tree rooted at the parent of "vendor",
+// and only using an import path that omits the prefix up to and
+// including the vendor element.
+//
+// Here's the example from the previous section,
+// but with the "internal" directory renamed to "vendor"
+// and a new foo/vendor/crash/bang directory added:
+//
+// /home/user/go/
+// src/
+// crash/
+// bang/ (go code in package bang)
+// b.go
+// foo/ (go code in package foo)
+// f.go
+// bar/ (go code in package bar)
+// x.go
+// vendor/
+// crash/
+// bang/ (go code in package bang)
+// b.go
+// baz/ (go code in package baz)
+// z.go
+// quux/ (go code in package main)
+// y.go
+//
+// The same visibility rules apply as for internal, but the code
+// in z.go is imported as "baz", not as "foo/vendor/baz".
+//
+// Code in vendor directories deeper in the source tree shadows
+// code in higher directories. Within the subtree rooted at foo, an import
+// of "crash/bang" resolves to "foo/vendor/crash/bang", not the
+// top-level "crash/bang".
+//
+// Code in vendor directories is not subject to import path
+// checking (see 'go help importpath').
+//
+// When 'go get' checks out or updates a git repository, it now also
+// updates submodules.
+//
+// Vendor directories do not affect the placement of new repositories
+// being checked out for the first time by 'go get': those are always
+// placed in the main GOPATH, never in a vendor subtree.
+//
+// See https://golang.org/s/go15vendor for details.
+//
+//
+// Environment variables
+//
+// The go command, and the tools it invokes, examine a few different
+// environment variables. For many of these, you can see the default
+// value of on your system by running 'go env NAME', where NAME is the
+// name of the variable.
+//
+// General-purpose environment variables:
+//
+// GCCGO
+// The gccgo command to run for 'go build -compiler=gccgo'.
+// GOARCH
+// The architecture, or processor, for which to compile code.
+// Examples are amd64, 386, arm, ppc64.
+// GOBIN
+// The directory where 'go install' will install a command.
+// GOOS
+// The operating system for which to compile code.
+// Examples are linux, darwin, windows, netbsd.
+// GOPATH
+// For more details see: 'go help gopath'.
+// GORACE
+// Options for the race detector.
+// See https://golang.org/doc/articles/race_detector.html.
+// GOROOT
+// The root of the go tree.
+//
+// Environment variables for use with cgo:
+//
+// CC
+// The command to use to compile C code.
+// CGO_ENABLED
+// Whether the cgo command is supported. Either 0 or 1.
+// CGO_CFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// C code.
+// CGO_CPPFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// C or C++ code.
+// CGO_CXXFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// C++ code.
+// CGO_FFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// Fortran code.
+// CGO_LDFLAGS
+// Flags that cgo will pass to the compiler when linking.
+// CXX
+// The command to use to compile C++ code.
+// PKG_CONFIG
+// Path to pkg-config tool.
+//
+// Architecture-specific environment variables:
+//
+// GOARM
+// For GOARCH=arm, the ARM architecture for which to compile.
+// Valid values are 5, 6, 7.
+// GO386
+// For GOARCH=386, the floating point instruction set.
+// Valid values are 387, sse2.
+//
+// Special-purpose environment variables:
+//
+// GOROOT_FINAL
+// The root of the installed Go tree, when it is
+// installed in a location other than where it is built.
+// File names in stack traces are rewritten from GOROOT to
+// GOROOT_FINAL.
+// GO_EXTLINK_ENABLED
+// Whether the linker should use external linking mode
+// when using -linkmode=auto with code that uses cgo.
+// Set to 0 to disable external linking mode, 1 to enable it.
+// GIT_ALLOW_PROTOCOL
+// Defined by Git. A colon-separated list of schemes that are allowed to be used
+// with git fetch/clone. If set, any scheme not explicitly mentioned will be
+// considered insecure by 'go get'.
+//
+//
+// Import path syntax
+//
+// An import path (see 'go help packages') denotes a package stored in the local
+// file system. In general, an import path denotes either a standard package (such
+// as "unicode/utf8") or a package found in one of the work spaces (For more
+// details see: 'go help gopath').
+//
+// Relative import paths
+//
+// An import path beginning with ./ or ../ is called a relative path.
+// The toolchain supports relative import paths as a shortcut in two ways.
+//
+// First, a relative path can be used as a shorthand on the command line.
+// If you are working in the directory containing the code imported as
+// "unicode" and want to run the tests for "unicode/utf8", you can type
+// "go test ./utf8" instead of needing to specify the full path.
+// Similarly, in the reverse situation, "go test .." will test "unicode" from
+// the "unicode/utf8" directory. Relative patterns are also allowed, like
+// "go test ./..." to test all subdirectories. See 'go help packages' for details
+// on the pattern syntax.
+//
+// Second, if you are compiling a Go program not in a work space,
+// you can use a relative path in an import statement in that program
+// to refer to nearby code also not in a work space.
+// This makes it easy to experiment with small multipackage programs
+// outside of the usual work spaces, but such programs cannot be
+// installed with "go install" (there is no work space in which to install them),
+// so they are rebuilt from scratch each time they are built.
+// To avoid ambiguity, Go programs cannot use relative import paths
+// within a work space.
+//
+// Remote import paths
+//
+// Certain import paths also
+// describe how to obtain the source code for the package using
+// a revision control system.
+//
+// A few common code hosting sites have special syntax:
+//
+// Bitbucket (Git, Mercurial)
+//
+// import "bitbucket.org/user/project"
+// import "bitbucket.org/user/project/sub/directory"
+//
+// GitHub (Git)
+//
+// import "github.com/user/project"
+// import "github.com/user/project/sub/directory"
+//
+// Launchpad (Bazaar)
+//
+// import "launchpad.net/project"
+// import "launchpad.net/project/series"
+// import "launchpad.net/project/series/sub/directory"
+//
+// import "launchpad.net/~user/project/branch"
+// import "launchpad.net/~user/project/branch/sub/directory"
+//
+// IBM DevOps Services (Git)
+//
+// import "hub.jazz.net/git/user/project"
+// import "hub.jazz.net/git/user/project/sub/directory"
+//
+// For code hosted on other servers, import paths may either be qualified
+// with the version control type, or the go tool can dynamically fetch
+// the import path over https/http and discover where the code resides
+// from a <meta> tag in the HTML.
+//
+// To declare the code location, an import path of the form
+//
+// repository.vcs/path
+//
+// specifies the given repository, with or without the .vcs suffix,
+// using the named version control system, and then the path inside
+// that repository. The supported version control systems are:
+//
+// Bazaar .bzr
+// Git .git
+// Mercurial .hg
+// Subversion .svn
+//
+// For example,
+//
+// import "example.org/user/foo.hg"
+//
+// denotes the root directory of the Mercurial repository at
+// example.org/user/foo or foo.hg, and
+//
+// import "example.org/repo.git/foo/bar"
+//
+// denotes the foo/bar directory of the Git repository at
+// example.org/repo or repo.git.
+//
+// When a version control system supports multiple protocols,
+// each is tried in turn when downloading. For example, a Git
+// download tries https://, then git+ssh://.
+//
+// By default, downloads are restricted to known secure protocols
+// (e.g. https, ssh). To override this setting for Git downloads, the
+// GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
+// 'go help environment').
+//
+// If the import path is not a known code hosting site and also lacks a
+// version control qualifier, the go tool attempts to fetch the import
+// over https/http and looks for a <meta> tag in the document's HTML
+// <head>.
+//
+// The meta tag has the form:
+//
+// <meta name="go-import" content="import-prefix vcs repo-root">
+//
+// The import-prefix is the import path corresponding to the repository
+// root. It must be a prefix or an exact match of the package being
+// fetched with "go get". If it's not an exact match, another http
+// request is made at the prefix to verify the <meta> tags match.
+//
+// The meta tag should appear as early in the file as possible.
+// In particular, it should appear before any raw JavaScript or CSS,
+// to avoid confusing the go command's restricted parser.
+//
+// The vcs is one of "git", "hg", "svn", etc,
+//
+// The repo-root is the root of the version control system
+// containing a scheme and not containing a .vcs qualifier.
+//
+// For example,
+//
+// import "example.org/pkg/foo"
+//
+// will result in the following requests:
+//
+// https://example.org/pkg/foo?go-get=1 (preferred)
+// http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure)
+//
+// If that page contains the meta tag
+//
+// <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+//
+// the go tool will verify that https://example.org/?go-get=1 contains the
+// same meta tag and then git clone https://code.org/r/p/exproj into
+// GOPATH/src/example.org.
+//
+// New downloaded packages are written to the first directory listed in the GOPATH
+// environment variable (For more details see: 'go help gopath').
+//
+// The go command attempts to download the version of the
+// package appropriate for the Go release being used.
+// Run 'go help get' for more.
+//
+// Import path checking
+//
+// When the custom import path feature described above redirects to a
+// known code hosting site, each of the resulting packages has two possible
+// import paths, using the custom domain or the known hosting site.
+//
+// A package statement is said to have an "import comment" if it is immediately
+// followed (before the next newline) by a comment of one of these two forms:
+//
+// package math // import "path"
+// package math /* import "path" */
+//
+// The go command will refuse to install a package with an import comment
+// unless it is being referred to by that import path. In this way, import comments
+// let package authors make sure the custom import path is used and not a
+// direct path to the underlying code hosting site.
+//
+// Import path checking is disabled for code found within vendor trees.
+// This makes it possible to copy code into alternate locations in vendor trees
+// without needing to update import comments.
+//
+// See https://golang.org/s/go14customimport for details.
+//
+//
+// Description of package lists
+//
+// Many commands apply to a set of packages:
+//
+// go action [packages]
+//
+// Usually, [packages] is a list of import paths.
+//
+// An import path that is a rooted path or that begins with
+// a . or .. element is interpreted as a file system path and
+// denotes the package in that directory.
+//
+// Otherwise, the import path P denotes the package found in
+// the directory DIR/src/P for some DIR listed in the GOPATH
+// environment variable (For more details see: 'go help gopath').
+//
+// If no import paths are given, the action applies to the
+// package in the current directory.
+//
+// There are four reserved names for paths that should not be used
+// for packages to be built with the go tool:
+//
+// - "main" denotes the top-level package in a stand-alone executable.
+//
+// - "all" expands to all package directories found in all the GOPATH
+// trees. For example, 'go list all' lists all the packages on the local
+// system.
+//
+// - "std" is like all but expands to just the packages in the standard
+// Go library.
+//
+// - "cmd" expands to the Go repository's commands and their
+// internal libraries.
+//
+// Import paths beginning with "cmd/" only match source code in
+// the Go repository.
+//
+// An import path is a pattern if it includes one or more "..." wildcards,
+// each of which can match any string, including the empty string and
+// strings containing slashes. Such a pattern expands to all package
+// directories found in the GOPATH trees with names matching the
+// patterns. As a special case, x/... matches x as well as x's subdirectories.
+// For example, net/... expands to net and packages in its subdirectories.
+//
+// An import path can also name a package to be downloaded from
+// a remote repository. Run 'go help importpath' for details.
+//
+// Every package in a program must have a unique import path.
+// By convention, this is arranged by starting each path with a
+// unique prefix that belongs to you. For example, paths used
+// internally at Google all begin with 'google', and paths
+// denoting remote repositories begin with the path to the code,
+// such as 'github.com/user/repo'.
+//
+// Packages in a program need not have unique package names,
+// but there are two reserved package names with special meaning.
+// The name main indicates a command, not a library.
+// Commands are built into binaries and cannot be imported.
+// The name documentation indicates documentation for
+// a non-Go program in the directory. Files in package documentation
+// are ignored by the go command.
+//
+// As a special case, if the package list is a list of .go files from a
+// single directory, the command is applied to a single synthesized
+// package made up of exactly those files, ignoring any build constraints
+// in those files and ignoring any other files in the directory.
+//
+// Directory and file names that begin with "." or "_" are ignored
+// by the go tool, as are directories named "testdata".
+//
+//
+// Description of testing flags
+//
+// The 'go test' command takes both flags that apply to 'go test' itself
+// and flags that apply to the resulting test binary.
+//
+// Several of the flags control profiling and write an execution profile
+// suitable for "go tool pprof"; run "go tool pprof -h" for more
+// information. The --alloc_space, --alloc_objects, and --show_bytes
+// options of pprof control how the information is presented.
+//
+// The following flags are recognized by the 'go test' command and
+// control the execution of any test:
+//
+// -bench regexp
+// Run (sub)benchmarks matching a regular expression.
+// The given regular expression is split into smaller ones by
+// top-level '/', where each must match the corresponding part of a
+// benchmark's identifier.
+// By default, no benchmarks run. To run all benchmarks,
+// use '-bench .' or '-bench=.'.
+//
+// -benchtime t
+// Run enough iterations of each benchmark to take t, specified
+// as a time.Duration (for example, -benchtime 1h30s).
+// The default is 1 second (1s).
+//
+// -count n
+// Run each test and benchmark n times (default 1).
+// If -cpu is set, run n times for each GOMAXPROCS value.
+// Examples are always run once.
+//
+// -cover
+// Enable coverage analysis.
+//
+// -covermode set,count,atomic
+// Set the mode for coverage analysis for the package[s]
+// being tested. The default is "set" unless -race is enabled,
+// in which case it is "atomic".
+// The values:
+// set: bool: does this statement run?
+// count: int: how many times does this statement run?
+// atomic: int: count, but correct in multithreaded tests;
+// significantly more expensive.
+// Sets -cover.
+//
+// -coverpkg pkg1,pkg2,pkg3
+// Apply coverage analysis in each test to the given list of packages.
+// The default is for each test to analyze only the package being tested.
+// Packages are specified as import paths.
+// Sets -cover.
+//
+// -cpu 1,2,4
+// Specify a list of GOMAXPROCS values for which the tests or
+// benchmarks should be executed. The default is the current value
+// of GOMAXPROCS.
+//
+// -parallel n
+// Allow parallel execution of test functions that call t.Parallel.
+// The value of this flag is the maximum number of tests to run
+// simultaneously; by default, it is set to the value of GOMAXPROCS.
+// Note that -parallel only applies within a single test binary.
+// The 'go test' command may run tests for different packages
+// in parallel as well, according to the setting of the -p flag
+// (see 'go help build').
+//
+// -run regexp
+// Run only those tests and examples matching the regular expression.
+// For tests the regular expression is split into smaller ones by
+// top-level '/', where each must match the corresponding part of a
+// test's identifier.
+//
+// -short
+// Tell long-running tests to shorten their run time.
+// It is off by default but set during all.bash so that installing
+// the Go tree can run a sanity check but not spend time running
+// exhaustive tests.
+//
+// -timeout t
+// If a test runs longer than t, panic.
+// The default is 10 minutes (10m).
+//
+// -v
+// Verbose output: log all tests as they are run. Also print all
+// text from Log and Logf calls even if the test succeeds.
+//
+// The following flags are also recognized by 'go test' and can be used to
+// profile the tests during execution:
+//
+// -benchmem
+// Print memory allocation statistics for benchmarks.
+//
+// -blockprofile block.out
+// Write a goroutine blocking profile to the specified file
+// when all tests are complete.
+// Writes test binary as -c would.
+//
+// -blockprofilerate n
+// Control the detail provided in goroutine blocking profiles by
+// calling runtime.SetBlockProfileRate with n.
+// See 'go doc runtime.SetBlockProfileRate'.
+// The profiler aims to sample, on average, one blocking event every
+// n nanoseconds the program spends blocked. By default,
+// if -test.blockprofile is set without this flag, all blocking events
+// are recorded, equivalent to -test.blockprofilerate=1.
+//
+// -coverprofile cover.out
+// Write a coverage profile to the file after all tests have passed.
+// Sets -cover.
+//
+// -cpuprofile cpu.out
+// Write a CPU profile to the specified file before exiting.
+// Writes test binary as -c would.
+//
+// -memprofile mem.out
+// Write a memory profile to the file after all tests have passed.
+// Writes test binary as -c would.
+//
+// -memprofilerate n
+// Enable more precise (and expensive) memory profiles by setting
+// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+// To profile all memory allocations, use -test.memprofilerate=1
+// and pass --alloc_space flag to the pprof tool.
+//
+// -mutexprofile mutex.out
+// Write a mutex contention profile to the specified file
+// when all tests are complete.
+// Writes test binary as -c would.
+//
+// -mutexprofilefraction n
+// Sample 1 in n stack traces of goroutines holding a
+// contended mutex.
+//
+// -outputdir directory
+// Place output files from profiling in the specified directory,
+// by default the directory in which "go test" is running.
+//
+// -trace trace.out
+// Write an execution trace to the specified file before exiting.
+//
+// Each of these flags is also recognized with an optional 'test.' prefix,
+// as in -test.v. When invoking the generated test binary (the result of
+// 'go test -c') directly, however, the prefix is mandatory.
+//
+// The 'go test' command rewrites or removes recognized flags,
+// as appropriate, both before and after the optional package list,
+// before invoking the test binary.
+//
+// For instance, the command
+//
+// go test -v -myflag testdata -cpuprofile=prof.out -x
+//
+// will compile the test binary and then run it as
+//
+// pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
+//
+// (The -x flag is removed because it applies only to the go command's
+// execution, not to the test itself.)
+//
+// The test flags that generate profiles (other than for coverage) also
+// leave the test binary in pkg.test for use when analyzing the profiles.
+//
+// When 'go test' runs a test binary, it does so from within the
+// corresponding package's source code directory. Depending on the test,
+// it may be necessary to do the same when invoking a generated test
+// binary directly.
+//
+// The command-line package list, if present, must appear before any
+// flag not known to the go test command. Continuing the example above,
+// the package list would have to appear before -myflag, but could appear
+// on either side of -v.
+//
+// To keep an argument for a test binary from being interpreted as a
+// known flag or a package name, use -args (see 'go help test') which
+// passes the remainder of the command line through to the test binary
+// uninterpreted and unaltered.
+//
+// For instance, the command
+//
+// go test -v -args -x -v
+//
+// will compile the test binary and then run it as
+//
+// pkg.test -test.v -x -v
+//
+// Similarly,
+//
+// go test -args math
+//
+// will compile the test binary and then run it as
+//
+// pkg.test math
+//
+// In the first example, the -x and the second -v are passed through to the
+// test binary unchanged and with no effect on the go command itself.
+// In the second example, the argument math is passed through to the test
+// binary, instead of being interpreted as the package list.
+//
+//
+// Description of testing functions
+//
+// The 'go test' command expects to find test, benchmark, and example functions
+// in the "*_test.go" files corresponding to the package under test.
+//
+// A test function is one named TestXXX (where XXX is any alphanumeric string
+// not starting with a lower case letter) and should have the signature,
+//
+// func TestXXX(t *testing.T) { ... }
+//
+// A benchmark function is one named BenchmarkXXX and should have the signature,
+//
+// func BenchmarkXXX(b *testing.B) { ... }
+//
+// An example function is similar to a test function but, instead of using
+// *testing.T to report success or failure, prints output to os.Stdout.
+// If the last comment in the function starts with "Output:" then the output
+// is compared exactly against the comment (see examples below). If the last
+// comment begins with "Unordered output:" then the output is compared to the
+// comment, however the order of the lines is ignored. An example with no such
+// comment is compiled but not executed. An example with no text after
+// "Output:" is compiled, executed, and expected to produce no output.
+//
+// Godoc displays the body of ExampleXXX to demonstrate the use
+// of the function, constant, or variable XXX. An example of a method M with
+// receiver type T or *T is named ExampleT_M. There may be multiple examples
+// for a given function, constant, or variable, distinguished by a trailing _xxx,
+// where xxx is a suffix not beginning with an upper case letter.
+//
+// Here is an example of an example:
+//
+// func ExamplePrintln() {
+// Println("The output of\nthis example.")
+// // Output: The output of
+// // this example.
+// }
+//
+// Here is another example where the ordering of the output is ignored:
+//
+// func ExamplePerm() {
+// for _, value := range Perm(4) {
+// fmt.Println(value)
+// }
+//
+// // Unordered output: 4
+// // 2
+// // 1
+// // 3
+// // 0
+// }
+//
+// The entire test file is presented as the example when it contains a single
+// example function, at least one other function, type, variable, or constant
+// declaration, and no test or benchmark functions.
+//
+// See the documentation of the testing package for more information.
+//
+//
package main
diff --git a/libgo/go/cmd/go/bootstrap.go b/libgo/go/cmd/go/bootstrap.go
index 1686df77af..2148d12685 100644
--- a/libgo/go/cmd/go/bootstrap.go
+++ b/libgo/go/cmd/go/bootstrap.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -36,3 +36,6 @@ func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadClose
func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
panic("unreachable")
}
+
+func queryEscape(s string) string { panic("unreachable") }
+func openBrowser(url string) bool { panic("unreachable") }
diff --git a/libgo/go/cmd/go/bug.go b/libgo/go/cmd/go/bug.go
new file mode 100644
index 0000000000..658f6dabd9
--- /dev/null
+++ b/libgo/go/cmd/go/bug.go
@@ -0,0 +1,212 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+var cmdBug = &Command{
+ Run: runBug,
+ UsageLine: "bug",
+ Short: "start a bug report",
+ Long: `
+Bug opens the default browser and starts a new bug report.
+The report includes useful system information.
+ `,
+}
+
+func init() {
+ cmdBug.Flag.BoolVar(&buildV, "v", false, "")
+}
+
+func runBug(cmd *Command, args []string) {
+ var buf bytes.Buffer
+ buf.WriteString(bugHeader)
+ inspectGoVersion(&buf)
+ fmt.Fprint(&buf, "#### System details\n\n")
+ fmt.Fprintln(&buf, "```")
+ fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
+ env := newEnv
+ env = append(env, extraEnvVars()...)
+ for _, e := range env {
+ // Hide the TERM environment variable from "go bug".
+ // See issue #18128
+ if e.name != "TERM" {
+ fmt.Fprintf(&buf, "%s=\"%s\"\n", e.name, e.value)
+ }
+ }
+ printGoDetails(&buf)
+ printOSDetails(&buf)
+ printCDetails(&buf)
+ fmt.Fprintln(&buf, "```")
+
+ body := buf.String()
+ url := "https://github.com/golang/go/issues/new?body=" + queryEscape(body)
+ if !openBrowser(url) {
+ fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
+ fmt.Print(body)
+ }
+}
+
+const bugHeader = `Please answer these questions before submitting your issue. Thanks!
+
+#### What did you do?
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+A link on play.golang.org is best.
+
+
+#### What did you expect to see?
+
+
+#### What did you see instead?
+
+
+`
+
+func printGoDetails(w io.Writer) {
+ printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
+ printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
+}
+
+func printOSDetails(w io.Writer) {
+ switch runtime.GOOS {
+ case "darwin":
+ printCmdOut(w, "uname -v: ", "uname", "-v")
+ printCmdOut(w, "", "sw_vers")
+ case "linux":
+ printCmdOut(w, "uname -sr: ", "uname", "-sr")
+ printCmdOut(w, "", "lsb_release", "-a")
+ printGlibcVersion(w)
+ case "openbsd", "netbsd", "freebsd", "dragonfly":
+ printCmdOut(w, "uname -v: ", "uname", "-v")
+ case "solaris":
+ out, err := ioutil.ReadFile("/etc/release")
+ if err == nil {
+ fmt.Fprintf(w, "/etc/release: %s\n", out)
+ } else {
+ if buildV {
+ fmt.Printf("failed to read /etc/release: %v\n", err)
+ }
+ }
+ }
+}
+
+func printCDetails(w io.Writer) {
+ printCmdOut(w, "lldb --version: ", "lldb", "--version")
+ cmd := exec.Command("gdb", "--version")
+ out, err := cmd.Output()
+ if err == nil {
+ // There's apparently no combination of command line flags
+ // to get gdb to spit out its version without the license and warranty.
+ // Print up to the first newline.
+ fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
+ } else {
+ if buildV {
+ fmt.Printf("failed to run gdb --version: %v\n", err)
+ }
+ }
+}
+
+func inspectGoVersion(w io.Writer) {
+ data, err := httpGET("https://golang.org/VERSION?m=text")
+ if err != nil {
+ if buildV {
+ fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
+ }
+ return
+ }
+
+ // golang.org/VERSION currently returns a whitespace-free string,
+ // but just in case, protect against that changing.
+ // Similarly so for runtime.Version.
+ release := string(bytes.TrimSpace(data))
+ vers := strings.TrimSpace(runtime.Version())
+
+ if vers == release {
+ // Up to date
+ return
+ }
+
+ // Devel version or outdated release. Either way, this request is apropos.
+ fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
+}
+
+// printCmdOut prints the output of running the given command.
+// It ignores failures; 'go bug' is best effort.
+func printCmdOut(w io.Writer, prefix, path string, args ...string) {
+ cmd := exec.Command(path, args...)
+ out, err := cmd.Output()
+ if err != nil {
+ if buildV {
+ fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
+ }
+ return
+ }
+ fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
+}
+
+// firstLine returns the first line of a given byte slice.
+func firstLine(buf []byte) []byte {
+ idx := bytes.IndexByte(buf, '\n')
+ if idx > 0 {
+ buf = buf[:idx]
+ }
+ return bytes.TrimSpace(buf)
+}
+
+// printGlibcVersion prints information about the glibc version.
+// It ignores failures.
+func printGlibcVersion(w io.Writer) {
+ tempdir := os.TempDir()
+ if tempdir == "" {
+ return
+ }
+ src := []byte(`int main() {}`)
+ srcfile := filepath.Join(tempdir, "go-bug.c")
+ outfile := filepath.Join(tempdir, "go-bug")
+ err := ioutil.WriteFile(srcfile, src, 0644)
+ if err != nil {
+ return
+ }
+ defer os.Remove(srcfile)
+ cmd := exec.Command("gcc", "-o", outfile, srcfile)
+ if _, err = cmd.CombinedOutput(); err != nil {
+ return
+ }
+ defer os.Remove(outfile)
+
+ cmd = exec.Command("ldd", outfile)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return
+ }
+ re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
+ m := re.FindStringSubmatch(string(out))
+ if m == nil {
+ return
+ }
+ cmd = exec.Command(m[1])
+ out, err = cmd.Output()
+ if err != nil {
+ return
+ }
+ fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
+
+ // print another line (the one containing version string) in case of musl libc
+ if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
+ fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
+ }
+}
diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go
index 864fb87901..f2d11f43f1 100644
--- a/libgo/go/cmd/go/build.go
+++ b/libgo/go/cmd/go/build.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -48,6 +48,8 @@ When compiling multiple packages or a single non-main package,
build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
+When compiling packages, build ignores files that end in '_test.go'.
+
The -o flag, only allowed when compiling a single package,
forces build to write the resulting executable or object
to the named output file, instead of the default behavior described
@@ -65,8 +67,7 @@ and test commands:
-p n
the number of programs, such as build commands or
test binaries, that can be run in parallel.
- The default is the number of CPUs available, except
- on darwin/arm which defaults to 1.
+ The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
@@ -145,17 +146,6 @@ func init() {
addBuildFlags(cmdBuild)
addBuildFlags(cmdInstall)
-
- if buildContext.GOOS == "darwin" {
- switch buildContext.GOARCH {
- case "arm", "arm64":
- // darwin/arm cannot run multiple tests simultaneously.
- // Parallelism is limited in go_darwin_arm_exec, but
- // also needs to be limited here so go test std does not
- // timeout tests that waiting to run.
- buildP = 1
- }
- }
}
// Flags set by multiple commands.
@@ -352,6 +342,18 @@ func buildModeInit() {
}
return p
}
+ switch platform {
+ case "darwin/arm", "darwin/arm64":
+ codegenArg = "-shared"
+ default:
+ switch goos {
+ case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ // Use -shared so that the result is
+ // suitable for inclusion in a PIE or
+ // shared library.
+ codegenArg = "-shared"
+ }
+ }
exeSuffix = ".a"
ldBuildmode = "c-archive"
case "c-shared":
@@ -374,6 +376,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"
}
@@ -385,7 +390,7 @@ func buildModeInit() {
fatalf("-buildmode=pie not supported by gccgo")
} else {
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le",
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386":
codegenArg = "-shared"
default:
@@ -399,7 +404,7 @@ func buildModeInit() {
codegenArg = "-fPIC"
} else {
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
default:
fatalf("-buildmode=shared not supported on %s\n", platform)
}
@@ -409,6 +414,21 @@ func buildModeInit() {
fatalf("-buildmode=shared and -o not supported together")
}
ldBuildmode = "shared"
+ case "plugin":
+ pkgsFilter = pkgsMain
+ if gccgo {
+ codegenArg = "-fPIC"
+ } else {
+ switch platform {
+ case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
+ "android/amd64", "android/arm", "android/arm64", "android/386":
+ default:
+ fatalf("-buildmode=plugin not supported on %s\n", platform)
+ }
+ codegenArg = "-dynlink"
+ }
+ exeSuffix = ".so"
+ ldBuildmode = "plugin"
default:
fatalf("buildmode=%s not supported", buildBuildmode)
}
@@ -417,7 +437,7 @@ func buildModeInit() {
codegenArg = "-fPIC"
} else {
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1")
default:
fatalf("-linkshared not supported on %s\n", platform)
@@ -434,10 +454,13 @@ func buildModeInit() {
buildAsmflags = append(buildAsmflags, codegenArg)
buildGcflags = append(buildGcflags, codegenArg)
}
- if buildContext.InstallSuffix != "" {
- buildContext.InstallSuffix += "_"
+ // Don't alter InstallSuffix when modifying default codegen args.
+ if buildBuildmode != "default" || buildLinkshared {
+ if buildContext.InstallSuffix != "" {
+ buildContext.InstallSuffix += "_"
+ }
+ buildContext.InstallSuffix += codegenArg[1:]
}
- buildContext.InstallSuffix += codegenArg[1:]
}
}
@@ -454,6 +477,11 @@ func runBuild(cmd *Command, args []string) {
*buildO += exeSuffix
}
+ // Special case -o /dev/null by not writing at all.
+ if *buildO == os.DevNull {
+ *buildO = ""
+ }
+
// sanity check some often mis-used options
switch buildContext.Compiler {
case "gccgo":
@@ -483,6 +511,7 @@ func runBuild(cmd *Command, args []string) {
p := pkgs[0]
p.target = *buildO
p.Stale = true // must build - not up to date
+ p.StaleReason = "build -o flag in use"
a := b.action(modeInstall, depMode, p)
b.do(a)
return
@@ -525,7 +554,7 @@ func isMetaPackage(name string) bool {
}
// libname returns the filename to use for the shared library when using
-// -buildmode=shared. The rules we use are:
+// -buildmode=shared. The rules we use are:
// Use arguments for special 'meta' packages:
// std --> libstd.so
// std cmd --> libstd,cmd.so
@@ -581,6 +610,10 @@ func libname(args []string, pkgs []*Package) (string, error) {
}
func runInstall(cmd *Command, args []string) {
+ installPackages(args, false)
+}
+
+func installPackages(args []string, forGet bool) {
if gobin != "" && !filepath.IsAbs(gobin) {
fatalf("cannot install, GOBIN must be an absolute path")
}
@@ -600,7 +633,7 @@ func runInstall(cmd *Command, args []string) {
errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
default:
errorf("go install: no install location for directory %s outside GOPATH\n"+
- "\tFor more details see: go help gopath", p.Dir)
+ "\tFor more details see: 'go help gopath'", p.Dir)
}
}
}
@@ -608,6 +641,8 @@ func runInstall(cmd *Command, args []string) {
var b builder
b.init()
+ // Set the behavior for `go get` to not error on packages with test files only.
+ b.testFilesOnlyOK = forGet
var a *action
if buildBuildmode == "shared" {
if libName, err := libname(args, pkgs); err != nil {
@@ -681,6 +716,7 @@ var (
func init() {
goarch = buildContext.GOARCH
goos = buildContext.GOOS
+
if goos == "windows" {
exeSuffix = ".exe"
}
@@ -694,8 +730,11 @@ type builder struct {
work string // the temporary work directory (ends in filepath.Separator)
actionCache map[cacheKey]*action // a cache of already-constructed actions
mkdirCache map[string]bool // a cache of created directories
+ flagCache map[string]bool // a cache of supported compiler flags
print func(args ...interface{}) (int, error)
+ testFilesOnlyOK bool // do not error if the packages only have test files
+
output sync.Mutex
scriptDir string // current directory in printed script
@@ -795,7 +834,7 @@ func goFilesPackage(gofiles []string) *Package {
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or
- // command directory. So that local imports resolve
+ // command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
@@ -853,6 +892,7 @@ func goFilesPackage(gofiles []string) *Package {
pkg.Target = pkg.target
pkg.Stale = true
+ pkg.StaleReason = "files named on command line"
computeStale(pkg)
return pkg
@@ -957,7 +997,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// If we are not doing a cross-build, then record the binary we'll
// generate for cgo as a dependency of the build of any package
// using cgo, to make sure we do not overwrite the binary while
- // a package is using it. If this is a cross-build, then the cgo we
+ // a package is using it. If this is a cross-build, then the cgo we
// are writing is not the cgo we need to use.
if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && !buildMSan && reqStdPkgSrc {
if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
@@ -993,7 +1033,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
}
if p.local && p.target == "" {
- // Imported via local path. No permanent target.
+ // Imported via local path. No permanent target.
mode = modeBuild
}
work := p.pkgdir
@@ -1041,7 +1081,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// the name will show up in ps listings. If the caller has specified
// a name, use that instead of a.out. The binary is generated
// in an otherwise empty subdirectory named exe to avoid
- // naming conflicts. The only possible conflict is if we were
+ // naming conflicts. The only possible conflict is if we were
// to create a top-level package named exe.
name := "a.out"
if p.exeName != "" {
@@ -1227,14 +1267,22 @@ func allArchiveActions(root *action) []*action {
// do runs the action graph rooted at root.
func (b *builder) do(root *action) {
+ /* Commented out for gccgo, which does not have osArchSupportsCgo.
+
+ if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok && buildContext.Compiler == "gc" {
+ fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
+ os.Exit(2)
+ }
+ */
+
// Build list of all actions, assigning depth-first post-order priority.
// The original implementation here was a true queue
// (using a channel) but it had the effect of getting
// distracted by low-level leaf actions to the detriment
- // of completing higher-level actions. The order of
+ // of completing higher-level actions. The order of
// work does not matter much to overall execution time,
// but when running "go test std" it is nice to see each test
- // results as soon as possible. The priorities assigned
+ // results as soon as possible. The priorities assigned
// ensure that, all else being equal, the execution prefers
// to do what it would have done first in a simple depth-first
// dependency order traversal.
@@ -1273,6 +1321,8 @@ func (b *builder) do(root *action) {
if err != nil {
if err == errPrintedOutput {
setExitStatus(2)
+ } else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK {
+ // Ignore the "no buildable Go source files" error for a package with only test files.
} else {
errorf("%s", err)
}
@@ -1331,18 +1381,15 @@ func (b *builder) do(root *action) {
wg.Wait()
}
-// hasString reports whether s appears in the list of strings.
-func hasString(strings []string, s string) bool {
- for _, t := range strings {
- if s == t {
- return true
- }
- }
- return false
-}
-
// build is the action for building a single package or command.
func (b *builder) build(a *action) (err error) {
+ // Return an error for binary-only package.
+ // We only reach this if isStale believes the binary form is
+ // either not present or not usable.
+ if a.p.BinaryOnly {
+ return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.p.ImportPath)
+ }
+
// Return an error if the package has CXX files but it's not using
// cgo nor SWIG, since the CXX files can only be processed by cgo
// and SWIG.
@@ -1355,8 +1402,14 @@ func (b *builder) build(a *action) (err error) {
return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.MFiles, ","))
}
+ // Same as above for Fortran files
+ if len(a.p.FFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+ return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
+ a.p.ImportPath, strings.Join(a.p.FFiles, ","))
+ }
+
defer func() {
- if err != nil && err != errPrintedOutput {
+ if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.p.TestGoFiles) > 0) {
err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
}
}()
@@ -1387,7 +1440,7 @@ func (b *builder) build(a *action) (err error) {
}
}
- var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+ var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.p.GoFiles...)
cgofiles = append(cgofiles, a.p.CgoFiles...)
@@ -1409,7 +1462,7 @@ func (b *builder) build(a *action) (err error) {
if err != nil {
return err
}
- cgofiles = append(cgofiles, outGo...)
+ objdirCgofiles = append(objdirCgofiles, outGo...)
cfiles = append(cfiles, outC...)
cxxfiles = append(cxxfiles, outCXX...)
}
@@ -1421,6 +1474,8 @@ func (b *builder) build(a *action) (err error) {
// cgo and non-cgo worlds, so it necessarily has files in both.
// In that case gcc only gets the gcc_* files.
var gccfiles []string
+ gccfiles = append(gccfiles, cfiles...)
+ cfiles = nil
if a.p.Standard && a.p.ImportPath == "runtime/cgo" {
filter := func(files, nongcc, gcc []string) ([]string, []string) {
for _, f := range files {
@@ -1432,11 +1487,9 @@ func (b *builder) build(a *action) (err error) {
}
return nongcc, gcc
}
- cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles)
sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
} else {
- gccfiles = append(cfiles, sfiles...)
- cfiles = nil
+ gccfiles = append(gccfiles, sfiles...)
sfiles = nil
}
@@ -1444,7 +1497,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
- outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles)
+ outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
if err != nil {
return err
}
@@ -1542,17 +1595,17 @@ func (b *builder) build(a *action) (err error) {
}
// Assemble .s files.
- for _, file := range sfiles {
- out := file[:len(file)-len(".s")] + ".o"
- if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
+ if len(sfiles) > 0 {
+ ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
+ if err != nil {
return err
}
- objects = append(objects, out)
+ objects = append(objects, ofiles...)
}
// NOTE(rsc): On Windows, it is critically important that the
// gcc-compiled objects (cgoObjects) be listed after the ordinary
- // objects in the archive. I do not know why this is.
+ // objects in the archive. I do not know why this is.
// https://golang.org/issue/2601
objects = append(objects, cgoObjects...)
@@ -1586,23 +1639,62 @@ func (b *builder) build(a *action) (err error) {
return nil
}
+// pkgconfigCmd returns a pkg-config binary name
+// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist.
+func (b *builder) pkgconfigCmd() string {
+ return envList("PKG_CONFIG", defaultPkgConfig)[0]
+}
+
+// splitPkgConfigOutput parses the pkg-config output into a slice of
+// flags. pkg-config always uses \ to escape special characters.
+func splitPkgConfigOutput(out []byte) []string {
+ if len(out) == 0 {
+ return nil
+ }
+ var flags []string
+ flag := make([]byte, len(out))
+ r, w := 0, 0
+ for r < len(out) {
+ switch out[r] {
+ case ' ', '\t', '\r', '\n':
+ if w > 0 {
+ flags = append(flags, string(flag[:w]))
+ }
+ w = 0
+ case '\\':
+ r++
+ fallthrough
+ default:
+ if r < len(out) {
+ flag[w] = out[r]
+ w++
+ }
+ }
+ r++
+ }
+ if w > 0 {
+ flags = append(flags, string(flag[:w]))
+ }
+ return flags
+}
+
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte
- out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
- cflags = strings.Fields(string(out))
+ cflags = splitPkgConfigOutput(out)
}
- out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
@@ -1643,7 +1735,7 @@ func (b *builder) install(a *action) (err error) {
perm := os.FileMode(0666)
if a1.link {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
default:
perm = 0777
}
@@ -1658,7 +1750,7 @@ func (b *builder) install(a *action) (err error) {
}
// remove object dir to keep the amount of
- // garbage down in a large build. On an operating system
+ // garbage down in a large build. On an operating system
// with aggressive buffering, cleaning incrementally like
// this keeps the intermediate objects from hitting the disk.
if !buildWork {
@@ -1803,7 +1895,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil && toolIsWindows {
// Windows does not allow deletion of a binary file
- // while it is executing. Try to move it out of the way.
+ // while it is executing. Try to move it out of the way.
// If the move fails, which is likely, we'll try again the
// next time we do an install of this binary.
if err := os.Rename(dst, dst+"~"); err == nil {
@@ -1933,7 +2025,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
// The output is expected to contain references to 'dir', usually
// the source directory for the package that has failed to build.
// showOutput rewrites mentions of dir with a relative path to dir
-// when the relative path is shorter. This is usually more pleasant.
+// when the relative path is shorter. This is usually more pleasant.
// For example, if fmt doesn't compile and we are in src/html,
// the output is
//
@@ -1991,7 +2083,7 @@ func relPaths(paths []string) []string {
// errPrintedOutput is a special error indicating that a command failed
// but that it generated output as well, and that output has already
// been printed, so there's no point showing 'exit status 1' or whatever
-// the wait status was. The main executor, builder.do, knows not to
+// the wait status was. The main executor, builder.do, knows not to
// print this error.
var errPrintedOutput = errors.New("already printed output - no need to show error")
@@ -2060,7 +2152,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
err := cmd.Run()
// cmd.Run will fail on Unix if some other process has the binary
- // we want to run open for writing. This can happen here because
+ // we want to run open for writing. This can happen here because
// we build and install the cgo command and then run it.
// If another command was kicked off while we were writing the
// cgo binary, the child process for that command may be holding
@@ -2072,27 +2164,27 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
// The answer is that running a command is fork and exec.
// A child forked while the cgo fd is open inherits that fd.
// Until the child has called exec, it holds the fd open and the
- // kernel will not let us run cgo. Even if the child were to close
+ // kernel will not let us run cgo. Even if the child were to close
// the fd explicitly, it would still be open from the time of the fork
// until the time of the explicit close, and the race would remain.
//
// On Unix systems, this results in ETXTBSY, which formats
// as "text file busy". Rather than hard-code specific error cases,
- // we just look for that string. If this happens, sleep a little
- // and try again. We let this happen three times, with increasing
+ // we just look for that string. If this happens, sleep a little
+ // and try again. We let this happen three times, with increasing
// sleep lengths: 100+200+400 ms = 0.7 seconds.
//
// An alternate solution might be to split the cmd.Run into
// separate cmd.Start and cmd.Wait, and then use an RWLock
// to make sure that copyFile only executes when no cmd.Start
- // call is in progress. However, cmd.Start (really syscall.forkExec)
+ // call is in progress. However, cmd.Start (really syscall.forkExec)
// only guarantees that when it returns, the exec is committed to
- // happen and succeed. It uses a close-on-exec file descriptor
+ // happen and succeed. It uses a close-on-exec file descriptor
// itself to determine this, so we know that when cmd.Start returns,
// at least one close-on-exec file descriptor has been closed.
// However, we cannot be sure that all of them have been closed,
// so the program might still encounter ETXTBSY even with such
- // an RWLock. The race window would be smaller, perhaps, but not
+ // an RWLock. The race window would be smaller, perhaps, but not
// guaranteed to be gone.
//
// Sleeping when we observe the race seems to be the most reliable
@@ -2142,7 +2234,7 @@ func (b *builder) mkdir(dir string) error {
b.exec.Lock()
defer b.exec.Unlock()
// We can be a little aggressive about being
- // sure directories exist. Skip repeated calls.
+ // sure directories exist. Skip repeated calls.
if b.mkdirCache[dir] {
return nil
}
@@ -2180,14 +2272,13 @@ func mkAbs(dir, f string) string {
type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
- // The compiler runs in the directory dir.
gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
- // asm runs the assembler in a specific directory on a specific file
- // to generate the named output file.
- asm(b *builder, p *Package, obj, ofile, sfile string) error
+ // asm runs the assembler in a specific directory on specific files
+ // and returns a list of named output files.
+ asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error)
// pkgpath builds an appropriate path for a temporary package file.
pkgpath(basedir string, p *Package) string
// pack runs the archive packer in a specific directory to create
@@ -2224,8 +2315,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return "", nil, noCompiler()
}
-func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- return noCompiler()
+func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
+ return nil, noCompiler()
}
func (noToolchain) pkgpath(basedir string, p *Package) string {
@@ -2282,7 +2373,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
- extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+ extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
@@ -2307,14 +2398,6 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
}
}
- for _, path := range p.Imports {
- if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
- gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
- } else if strings.HasPrefix(path, "vendor/") {
- gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
- }
- }
-
args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
if ofile == archive {
args = append(args, "-pack")
@@ -2330,15 +2413,27 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return ofile, output, err
}
-func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(goroot, "pkg", "include")
- sfile = mkAbs(p.Dir, sfile)
- args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
- if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
- return err
+ args := []interface{}{buildToolExec, tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
+ if p.ImportPath == "runtime" && goarch == "386" {
+ for _, arg := range buildAsmflags {
+ if arg == "-dynlink" {
+ args = append(args, "-D=GOBUILDMODE_shared=1")
+ }
+ }
}
- return nil
+ var ofiles []string
+ for _, sfile := range sfiles {
+ ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+ ofiles = append(ofiles, ofile)
+ a := append(args, "-o", ofile, mkAbs(p.Dir, sfile))
+ if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil {
+ return nil, err
+ }
+ }
+ return ofiles, nil
}
// toolVerify checks that the command line args writes the same output file
@@ -2381,8 +2476,10 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
// The archive file should have been created by the compiler.
// Since it used to not work that way, verify.
- if _, err := os.Stat(absAfile); err != nil {
- fatalf("os.Stat of archive file failed: %v", err)
+ if !buildN {
+ if _, err := os.Stat(absAfile); err != nil {
+ fatalf("os.Stat of archive file failed: %v", err)
+ }
}
if buildN || buildX {
@@ -2494,6 +2591,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
if root.p.omitDWARF {
ldflags = append(ldflags, "-w")
}
+ if buildBuildmode == "plugin" {
+ pluginpath := root.p.ImportPath
+ if pluginpath == "command-line-arguments" {
+ pluginpath = "plugin/unnamed-" + root.p.buildID
+ }
+ ldflags = append(ldflags, "-pluginpath", pluginpath)
+ }
// If the user has not specified the -extld option, then specify the
// appropriate linker. In case of C++ code, use the compiler named
@@ -2594,6 +2698,55 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
if p.localPrefix != "" {
gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
}
+ savedirs := []string{}
+ for _, incdir := range importArgs {
+ if incdir != "-I" {
+ savedirs = append(savedirs, incdir)
+ }
+ }
+
+ for _, path := range p.Imports {
+ // If this is a new vendor path, add it to the list of importArgs
+ if i := strings.LastIndex(path, "/vendor"); i >= 0 {
+ for _, dir := range savedirs {
+ // Check if the vendor path is already included in dir
+ if strings.HasSuffix(dir, path[:i+len("/vendor")]) {
+ continue
+ }
+ // Make sure this vendor path is not already in the list for importArgs
+ vendorPath := dir + "/" + path[:i+len("/vendor")]
+ for _, imp := range importArgs {
+ if imp == "-I" {
+ continue
+ }
+ // This vendorPath is already in the list
+ if imp == vendorPath {
+ goto nextSuffixPath
+ }
+ }
+ // New vendorPath not yet in the importArgs list, so add it
+ importArgs = append(importArgs, "-I", vendorPath)
+ nextSuffixPath:
+ }
+ } else if strings.HasPrefix(path, "vendor/") {
+ for _, dir := range savedirs {
+ // Make sure this vendor path is not already in the list for importArgs
+ vendorPath := dir + "/" + path[len("/vendor"):]
+ for _, imp := range importArgs {
+ if imp == "-I" {
+ continue
+ }
+ if imp == vendorPath {
+ goto nextPrefixPath
+ }
+ }
+ // This vendor path is needed and not already in the list, so add it
+ importArgs = append(importArgs, "-I", vendorPath)
+ nextPrefixPath:
+ }
+ }
+ }
+
args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
@@ -2603,15 +2756,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
return ofile, output, err
}
-func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- sfile = mkAbs(p.Dir, sfile)
- defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
- if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
- defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
+ var ofiles []string
+ for _, sfile := range sfiles {
+ ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+ ofiles = append(ofiles, ofile)
+ sfile = mkAbs(p.Dir, sfile)
+ defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
+ if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+ }
+ defs = tools.maybePIC(defs)
+ defs = append(defs, b.gccArchArgs()...)
+ err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+ if err != nil {
+ return nil, err
+ }
}
- defs = tools.maybePIC(defs)
- defs = append(defs, b.gccArchArgs()...)
- return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+ return ofiles, nil
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -2629,7 +2791,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
}
-func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (tools gccgoToolchain) link(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string, buildmode, desc string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
apackagePathsSeen := make(map[string]bool)
@@ -2638,8 +2800,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
- cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
- objc := len(root.p.MFiles) > 0
+ cxx := false
+ objc := false
+ fortran := false
+ if root.p != nil {
+ cxx = len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
+ objc = len(root.p.MFiles) > 0
+ fortran = len(root.p.FFiles) > 0
+ }
readCgoFlags := func(flagsFile string) error {
flags, err := ioutil.ReadFile(flagsFile)
@@ -2686,11 +2854,11 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
}
newarchive := newa.Name()
- err = b.run(b.work, root.p.ImportPath, nil, "ar", "x", newarchive, "_cgo_flags")
+ err = b.run(b.work, desc, nil, "ar", "x", newarchive, "_cgo_flags")
if err != nil {
return "", err
}
- err = b.run(".", root.p.ImportPath, nil, "ar", "d", newarchive, "_cgo_flags")
+ err = b.run(".", desc, nil, "ar", "d", newarchive, "_cgo_flags")
if err != nil {
return "", err
}
@@ -2727,7 +2895,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
if !apackagePathsSeen[a.p.ImportPath] {
apackagePathsSeen[a.p.ImportPath] = true
target := a.target
- if len(a.p.CgoFiles) > 0 {
+ if len(a.p.CgoFiles) > 0 || a.p.usesSwig() {
target, err = readAndRemoveCgoFlags(target)
if err != nil {
return
@@ -2777,6 +2945,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
if len(a.p.MFiles) > 0 {
objc = true
}
+ if len(a.p.FFiles) > 0 {
+ fortran = true
+ }
}
for i, o := range ofiles {
@@ -2793,7 +2964,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
ldflags = append(ldflags, cgoldflags...)
ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
- ldflags = append(ldflags, root.p.CgoLDFLAGS...)
+ if root.p != nil {
+ ldflags = append(ldflags, root.p.CgoLDFLAGS...)
+ }
ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
@@ -2808,7 +2981,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
}
var realOut string
- switch ldBuildmode {
+ switch buildmode {
case "exe":
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
@@ -2824,7 +2997,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
// initialization code.
//
// The user remains responsible for linking against
- // -lgo -lpthread -lm in the final link. We can't use
+ // -lgo -lpthread -lm in the final link. We can't use
// -r to pick them up because we can't combine
// split-stack and non-split-stack code in a single -r
// link, and libgo picks up non-split-stack code from
@@ -2843,12 +3016,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
case "c-shared":
ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
+ case "shared":
+ ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
default:
- fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
+ fatalf("-buildmode=%s not supported for gccgo", buildmode)
}
- switch ldBuildmode {
+ switch buildmode {
case "exe", "c-shared":
if cxx {
ldflags = append(ldflags, "-lstdc++")
@@ -2856,43 +3031,40 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
if objc {
ldflags = append(ldflags, "-lobjc")
}
+ if fortran {
+ fc := os.Getenv("FC")
+ if fc == "" {
+ fc = "gfortran"
+ }
+ // support gfortran out of the box and let others pass the correct link options
+ // via CGO_LDFLAGS
+ if strings.Contains(fc, "gfortran") {
+ ldflags = append(ldflags, "-lgfortran")
+ }
+ }
}
- if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+ if err := b.run(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
return err
}
- switch ldBuildmode {
+ switch buildmode {
case "c-archive":
- if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
+ if err := b.run(".", desc, nil, "ar", "rc", realOut, out); err != nil {
return err
}
}
return nil
}
+func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.p.ImportPath)
+}
+
func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
- args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"}
- for _, a := range toplevelactions {
- args = append(args, a.target)
- }
- args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
- shlibs := []string{}
- for _, a := range allactions {
- if strings.HasSuffix(a.target, ".so") {
- shlibs = append(shlibs, a.target)
- }
- }
- for _, shlib := range shlibs {
- args = append(
- args,
- "-L"+filepath.Dir(shlib),
- "-Wl,-rpath="+filepath.Dir(shlib),
- "-l"+strings.TrimSuffix(
- strings.TrimPrefix(filepath.Base(shlib), "lib"),
- ".so"))
- }
- return b.run(".", out, nil, tools.linker(), args, buildGccgoflags)
+ fakeRoot := &action{}
+ fakeRoot.deps = toplevelactions
+ return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
}
func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -2915,7 +3087,7 @@ func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile stri
// maybePIC adds -fPIC to the list of arguments if needed.
func (tools gccgoToolchain) maybePIC(args []string) []string {
switch buildBuildmode {
- case "c-shared", "shared":
+ case "c-shared", "shared", "plugin":
args = append(args, "-fPIC")
}
return args
@@ -2950,10 +3122,25 @@ func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) er
return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
}
+// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
+func (b *builder) gfortran(p *Package, out string, flags []string, ffile string) error {
+ return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir))
+}
+
// ccompile runs the given C or C++ compiler and creates an object from a single source file.
-func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
+func (b *builder) ccompile(p *Package, outfile string, flags []string, file string, compiler []string) error {
file = mkAbs(p.Dir, file)
- return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file)
+ desc := p.ImportPath
+ output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
+ if len(output) > 0 {
+ b.showOutput(p.Dir, desc, b.processOutput(output))
+ if err != nil {
+ err = errPrintedOutput
+ } else if os.Getenv("GO_BUILDER_NAME") != "" {
+ return errors.New("C compiler warning promoted to error on Go builders")
+ }
+ }
+ return err
}
// gccld runs the gcc linker to create an executable from a set of object files.
@@ -2979,6 +3166,11 @@ func (b *builder) gxxCmd(objdir string) []string {
return b.ccompilerCmd("CXX", defaultCXX, objdir)
}
+// gfortranCmd returns a gfortran command line prefix.
+func (b *builder) gfortranCmd(objdir string) []string {
+ return b.ccompilerCmd("FC", "gfortran", objdir)
+}
+
// ccompilerCmd returns a command line prefix for the given environment
// variable and using the default command when the variable is empty.
func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
@@ -3016,6 +3208,17 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// disable word wrapping in error messages
a = append(a, "-fmessage-length=0")
+ // Tell gcc not to include the work directory in object files.
+ if b.gccSupportsFlag("-fdebug-prefix-map=a=b") {
+ a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build")
+ }
+
+ // Tell gcc not to include flags in object files, which defeats the
+ // point of -fdebug-prefix-map above.
+ if b.gccSupportsFlag("-gno-record-gcc-switches") {
+ a = append(a, "-gno-record-gcc-switches")
+ }
+
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See https://golang.org/issue/3253.
@@ -3030,19 +3233,24 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is
// not supported by all compilers.
func (b *builder) gccSupportsNoPie() bool {
- if goos != "linux" {
- // On some BSD platforms, error messages from the
- // compiler make it to the console despite cmd.Std*
- // all being nil. As -no-pie is only required on linux
- // systems so far, we only test there.
- return false
+ return b.gccSupportsFlag("-no-pie")
+}
+
+// gccSupportsFlag checks to see if the compiler supports a flag.
+func (b *builder) gccSupportsFlag(flag string) bool {
+ b.exec.Lock()
+ defer b.exec.Unlock()
+ if b, ok := b.flagCache[flag]; ok {
+ return b
}
- src := filepath.Join(b.work, "trivial.c")
- if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
- return false
+ if b.flagCache == nil {
+ src := filepath.Join(b.work, "trivial.c")
+ if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+ return false
+ }
+ b.flagCache = make(map[string]bool)
}
- cmdArgs := b.gccCmd(b.work)
- cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c")
+ cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c")
if buildN || buildX {
b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
if buildN {
@@ -3051,9 +3259,11 @@ func (b *builder) gccSupportsNoPie() bool {
}
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
cmd.Dir = b.work
- cmd.Env = envForDir(cmd.Dir, os.Environ())
+ cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ()))
out, err := cmd.CombinedOutput()
- return err == nil && !bytes.Contains(out, []byte("unrecognized"))
+ supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+ b.flagCache[flag] = supported
+ return supported
}
// gccArchArgs returns arguments to pass to gcc based on the architecture.
@@ -3065,6 +3275,12 @@ func (b *builder) gccArchArgs() []string {
return []string{"-m64"}
case "arm":
return []string{"-marm"} // not thumb
+ case "s390x":
+ return []string{"-m64", "-march=z196"}
+ case "mips64", "mips64le":
+ return []string{"-mabi=64"}
+ case "mips", "mipsle":
+ return []string{"-mabi=32", "-march=mips32"}
}
return nil
}
@@ -3079,25 +3295,23 @@ func envList(key, def string) []string {
return strings.Fields(v)
}
-// Return the flags to use when invoking the C or C++ compilers, or cgo.
-func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
- var defaults string
- if def {
- defaults = "-g -O2"
- }
+// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
+func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
+ defaults := "-g -O2"
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
return
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
- _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
+func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+ p := a.p
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p)
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
// If we are compiling Objective-C code, then we need to link against libobjc
@@ -3105,7 +3319,20 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
}
- if buildMSan && p.ImportPath != "runtime/cgo" {
+ // Likewise for Fortran, except there are many Fortran compilers.
+ // Support gfortran out of the box and let others pass the correct link options
+ // via CGO_LDFLAGS
+ if len(ffiles) > 0 {
+ fc := os.Getenv("FC")
+ if fc == "" {
+ fc = "gfortran"
+ }
+ if strings.Contains(fc, "gfortran") {
+ cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
+ }
+ }
+
+ if buildMSan {
cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
}
@@ -3113,20 +3340,33 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
+ // If we have cgo files in the object directory, then copy any
+ // other cgo files into the object directory, and pass a
+ // -srcdir option to cgo.
+ var srcdirarg []string
+ if len(objdirCgofiles) > 0 {
+ for _, fn := range cgofiles {
+ if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil {
+ return nil, nil, err
+ }
+ }
+ cgofiles = append(cgofiles, objdirCgofiles...)
+ srcdirarg = []string{"-srcdir", obj}
+ }
+
// cgo
// TODO: CGO_FLAGS?
gofiles := []string{obj + "_cgo_gotypes.go"}
- cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
+ cfiles := []string{"_cgo_export.c"}
for _, fn := range cgofiles {
f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
gofiles = append(gofiles, obj+f+"cgo1.go")
cfiles = append(cfiles, f+"cgo2.c")
}
- defunC := obj + "_cgo_defun.c"
- cgoflags := []string{}
// TODO: make cgo not depend on $GOARCH?
+ cgoflags := []string{}
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
@@ -3163,154 +3403,166 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
- // cc _cgo_defun.c
- _, gccgo := buildToolchain.(gccgoToolchain)
- if gccgo {
- defunObj := obj + "_cgo_defun.o"
- if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
- return nil, nil, err
- }
- outObj = append(outObj, defunObj)
- }
-
// gcc
- var linkobj []string
-
- var bareLDFLAGS []string
- // When linking relocatable objects, various flags need to be
- // filtered out as they are inapplicable and can cause some linkers
- // to fail.
- for i := 0; i < len(cgoLDFLAGS); i++ {
- f := cgoLDFLAGS[i]
- switch {
- // skip "-lc" or "-l somelib"
- case strings.HasPrefix(f, "-l"):
- if f == "-l" {
- i++
- }
- // skip "-framework X" on Darwin
- case goos == "darwin" && f == "-framework":
- i++
- // skip "*.{dylib,so,dll}"
- case strings.HasSuffix(f, ".dylib"),
- strings.HasSuffix(f, ".so"),
- strings.HasSuffix(f, ".dll"):
- // Remove any -fsanitize=foo flags.
- // Otherwise the compiler driver thinks that we are doing final link
- // and links sanitizer runtime into the object file. But we are not doing
- // the final link, we will link the resulting object file again. And
- // so the program ends up with two copies of sanitizer runtime.
- // See issue 8788 for details.
- case strings.HasPrefix(f, "-fsanitize="):
- continue
- // runpath flags not applicable unless building a shared
- // object or executable; see issue 12115 for details. This
- // is necessary as Go currently does not offer a way to
- // specify the set of LDFLAGS that only apply to shared
- // objects.
- case strings.HasPrefix(f, "-Wl,-rpath"):
- if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
- // Skip following argument to -rpath* too.
- i++
- }
- default:
- bareLDFLAGS = append(bareLDFLAGS, f)
- }
- }
-
- var staticLibs []string
- if goos == "windows" {
- // libmingw32 and libmingwex have some inter-dependencies,
- // so must use linker groups.
- staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
- }
-
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
for _, cfile := range cfiles {
ofile := obj + cfile[:len(cfile)-1] + "o"
if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
- if !strings.HasSuffix(ofile, "_cgo_main.o") {
- outObj = append(outObj, ofile)
- }
+ outObj = append(outObj, ofile)
}
for _, file := range gccfiles {
- ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
+ base := filepath.Base(file)
+ ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
for _, file := range gxxfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
- ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
for _, file := range mfiles {
// Append .o to the file, just in case the pkg has file.c and file.m
- ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
- linkobj = append(linkobj, p.SysoFiles...)
- dynobj := obj + "_cgo_.o"
- pie := (goarch == "arm" && goos == "linux") || goos == "android"
- if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
- cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+ fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
+ for _, file := range ffiles {
+ // Append .o to the file, just in case the pkg has file.c and file.f
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
+ if err := b.gfortran(p, ofile, fflags, file); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, ofile)
}
- if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
- return nil, nil, err
+
+ switch buildToolchain.(type) {
+ case gcToolchain:
+ importGo := obj + "_cgo_import.go"
+ if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
+ return nil, nil, err
+ }
+ outGo = append(outGo, importGo)
+
+ ofile := obj + "_all.o"
+ if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil {
+ return nil, nil, err
+ }
+ outObj = []string{ofile}
+
+ case gccgoToolchain:
+ defunC := obj + "_cgo_defun.c"
+ defunObj := obj + "_cgo_defun.o"
+ if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, defunObj)
+
+ default:
+ noCompiler()
}
- if pie { // but we don't need -pie for normal cgo programs
- cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+
+ return outGo, outObj, nil
+}
+
+// dynimport creates a Go source file named importGo containing
+// //go:cgo_import_dynamic directives for each symbol or library
+// dynamically imported by the object files outObj.
+func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
+ cfile := obj + "_cgo_main.c"
+ ofile := obj + "_cgo_main.o"
+ if err := b.gcc(p, ofile, cflags, cfile); err != nil {
+ return err
}
- if _, ok := buildToolchain.(gccgoToolchain); ok {
- // we don't use dynimport when using gccgo.
- return outGo, outObj, nil
+ linkobj := stringList(ofile, outObj, p.SysoFiles)
+ dynobj := obj + "_cgo_.o"
+
+ // we need to use -pie for Linux/ARM to get accurate imported sym
+ ldflags := cgoLDFLAGS
+ if (goarch == "arm" && goos == "linux") || goos == "android" {
+ ldflags = append(ldflags, "-pie")
+ }
+ if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil {
+ return err
}
// cgo -dynimport
- importGo := obj + "_cgo_import.go"
- cgoflags = []string{}
+ var cgoflags []string
if p.Standard && p.ImportPath == "runtime/cgo" {
- cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
+ cgoflags = []string{"-dynlinker"} // record path to dynamic linker
}
- if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
- return nil, nil, err
- }
- outGo = append(outGo, importGo)
+ return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+}
- ofile := obj + "_all.o"
- var gccObjs, nonGccObjs []string
- for _, f := range outObj {
- if strings.HasSuffix(f, ".o") {
- gccObjs = append(gccObjs, f)
- } else {
- nonGccObjs = append(nonGccObjs, f)
+// collect partially links the object files outObj into a single
+// relocatable object file named ofile.
+func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []string) error {
+ // When linking relocatable objects, various flags need to be
+ // filtered out as they are inapplicable and can cause some linkers
+ // to fail.
+ var ldflags []string
+ for i := 0; i < len(cgoLDFLAGS); i++ {
+ f := cgoLDFLAGS[i]
+ switch {
+ // skip "-lc" or "-l somelib"
+ case strings.HasPrefix(f, "-l"):
+ if f == "-l" {
+ i++
+ }
+ // skip "-framework X" on Darwin
+ case goos == "darwin" && f == "-framework":
+ i++
+ // skip "*.{dylib,so,dll,o,a}"
+ case strings.HasSuffix(f, ".dylib"),
+ strings.HasSuffix(f, ".so"),
+ strings.HasSuffix(f, ".dll"),
+ strings.HasSuffix(f, ".o"),
+ strings.HasSuffix(f, ".a"):
+ // Remove any -fsanitize=foo flags.
+ // Otherwise the compiler driver thinks that we are doing final link
+ // and links sanitizer runtime into the object file. But we are not doing
+ // the final link, we will link the resulting object file again. And
+ // so the program ends up with two copies of sanitizer runtime.
+ // See issue 8788 for details.
+ case strings.HasPrefix(f, "-fsanitize="):
+ continue
+ // runpath flags not applicable unless building a shared
+ // object or executable; see issue 12115 for details. This
+ // is necessary as Go currently does not offer a way to
+ // specify the set of LDFLAGS that only apply to shared
+ // objects.
+ case strings.HasPrefix(f, "-Wl,-rpath"):
+ if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
+ // Skip following argument to -rpath* too.
+ i++
+ }
+ default:
+ ldflags = append(ldflags, f)
}
}
- ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
+
+ ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
if b.gccSupportsNoPie() {
ldflags = append(ldflags, "-no-pie")
@@ -3319,16 +3571,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// We are creating an object file, so we don't want a build ID.
ldflags = b.disableBuildID(ldflags)
- if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
- return nil, nil, err
- }
-
- // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
- // must be processed before the gcc-generated objects.
- // Put it first. https://golang.org/issue/2601
- outObj = stringList(nonGccObjs, ofile)
-
- return outGo, outObj, nil
+ return b.gccld(p, ofile, ldflags, outObj)
}
// Run SWIG on all SWIG input files.
@@ -3437,6 +3680,13 @@ func (b *builder) swigVersionCheck() error {
return swigCheck
}
+// Find the value to pass for the -intgosize option to swig.
+var (
+ swigIntSizeOnce sync.Once
+ swigIntSize string
+ swigIntSizeError error
+)
+
// This code fails to build if sizeof(int) <= 32
const swigIntSizeCode = `
package main
@@ -3444,8 +3694,8 @@ const i int = 1 << 32
`
// Determine the size of int on the target system for the -intgosize option
-// of swig >= 2.0.9
-func (b *builder) swigIntSize(obj string) (intsize string, err error) {
+// of swig >= 2.0.9. Run only once.
+func (b *builder) swigDoIntSize(obj string) (intsize string, err error) {
if buildN {
return "$INTBITS", nil
}
@@ -3463,9 +3713,18 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
return "64", nil
}
+// Determine the size of int on the target system for the -intgosize option
+// of swig >= 2.0.9.
+func (b *builder) swigIntSize(obj string) (intsize string, err error) {
+ swigIntSizeOnce.Do(func() {
+ swigIntSize, swigIntSizeError = b.swigDoIntSize(obj)
+ })
+ return swigIntSize, swigIntSizeError
+}
+
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
@@ -3528,17 +3787,17 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
}
- return obj + goFile, obj + gccBase + gccExt, nil
+ return goFile, obj + gccBase + gccExt, nil
}
// disableBuildID adjusts a linker command line to avoid creating a
// build ID when creating an object file rather than an executable or
-// shared library. Some systems, such as Ubuntu, always add
+// shared library. Some systems, such as Ubuntu, always add
// --build-id to every link, but we don't want a build ID when we are
-// producing an object file. On some of those system a plain -r (not
+// producing an object file. On some of those system a plain -r (not
// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
-// plain -r. I don't know how to turn off --build-id when using clang
-// other than passing a trailing --build-id=none. So that is what we
+// plain -r. I don't know how to turn off --build-id when using clang
+// other than passing a trailing --build-id=none. So that is what we
// do, but only on systems likely to support it, which is to say,
// systems that normally use gold or the GNU linker.
func (b *builder) disableBuildID(ldflags []string) []string {
@@ -3577,7 +3836,11 @@ func instrumentInit() {
return
}
if buildRace && buildMSan {
- fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously", flag.Args()[0])
+ fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
+ os.Exit(2)
+ }
+ if buildMSan && (goos != "linux" || goarch != "amd64") {
+ fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", goos, goarch)
os.Exit(2)
}
if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
diff --git a/libgo/go/cmd/go/build_test.go b/libgo/go/cmd/go/build_test.go
new file mode 100644
index 0000000000..79bbd54591
--- /dev/null
+++ b/libgo/go/cmd/go/build_test.go
@@ -0,0 +1,44 @@
+// 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 (
+ "os"
+ "reflect"
+ "testing"
+)
+
+func TestRemoveDevNull(t *testing.T) {
+ fi, err := os.Lstat(os.DevNull)
+ if err != nil {
+ t.Skip(err)
+ }
+ if fi.Mode().IsRegular() {
+ t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
+ }
+ mayberemovefile(os.DevNull)
+ _, err = os.Lstat(os.DevNull)
+ if err != nil {
+ t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
+ }
+}
+
+func TestSplitPkgConfigOutput(t *testing.T) {
+ for _, test := range []struct {
+ in []byte
+ want []string
+ }{
+ {[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
+ {[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
+ {[]byte(`broken flag\`), []string{"broken", "flag"}},
+ {[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
+ {[]byte(" \r\n "), nil},
+ } {
+ got := splitPkgConfigOutput(test.in)
+ if !reflect.DeepEqual(got, test.want) {
+ t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/clean.go b/libgo/go/cmd/go/clean.go
index 16054a5b5b..7b07150743 100644
--- a/libgo/go/cmd/go/clean.go
+++ b/libgo/go/cmd/go/clean.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/context.go b/libgo/go/cmd/go/context.go
index 68e518259f..94cd54d00d 100644
--- a/libgo/go/cmd/go/context.go
+++ b/libgo/go/cmd/go/context.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -26,6 +26,7 @@ func newContext(c *build.Context) *Context {
GOARCH: c.GOARCH,
GOOS: c.GOOS,
GOROOT: c.GOROOT,
+ GOPATH: c.GOPATH,
CgoEnabled: c.CgoEnabled,
UseAllFiles: c.UseAllFiles,
Compiler: c.Compiler,
diff --git a/libgo/go/cmd/go/discovery.go b/libgo/go/cmd/go/discovery.go
index f6992e9e93..b60eaef739 100644
--- a/libgo/go/cmd/go/discovery.go
+++ b/libgo/go/cmd/go/discovery.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/doc.go b/libgo/go/cmd/go/doc.go
index 9b8b8dfc24..829983950f 100644
--- a/libgo/go/cmd/go/doc.go
+++ b/libgo/go/cmd/go/doc.go
@@ -1,7 +1,9 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
+//go:generate ./mkalldocs.sh
+
package main
var cmdDoc = &Command{
diff --git a/libgo/go/cmd/go/env.go b/libgo/go/cmd/go/env.go
index 24f612756b..31710b7e6d 100644
--- a/libgo/go/cmd/go/env.go
+++ b/libgo/go/cmd/go/env.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -33,11 +33,6 @@ func mkEnv() []envVar {
var b builder
b.init()
- vendorExpValue := "0"
- if go15VendorExperiment {
- vendorExpValue = "1"
- }
-
env := []envVar{
{"GOARCH", goarch},
{"GOBIN", gobin},
@@ -45,24 +40,34 @@ func mkEnv() []envVar {
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
- {"GOPATH", os.Getenv("GOPATH")},
+ {"GOPATH", buildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
- {"GO15VENDOREXPERIMENT", vendorExpValue},
// disable escape codes in clang errors
{"TERM", "dumb"},
}
- if goos != "plan9" {
- cmd := b.gccCmd(".")
- env = append(env, envVar{"CC", cmd[0]})
- env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
- cmd = b.gxxCmd(".")
- env = append(env, envVar{"CXX", cmd[0]})
+ if gccgoBin != "" {
+ env = append(env, envVar{"GCCGO", gccgoBin})
+ } else {
+ env = append(env, envVar{"GCCGO", gccgoName})
+ }
+
+ switch goarch {
+ case "arm":
+ env = append(env, envVar{"GOARM", os.Getenv("GOARM")})
+ case "386":
+ env = append(env, envVar{"GO386", os.Getenv("GO386")})
}
+ cmd := b.gccCmd(".")
+ env = append(env, envVar{"CC", cmd[0]})
+ env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
+ cmd = b.gxxCmd(".")
+ env = append(env, envVar{"CXX", cmd[0]})
+
if buildContext.CgoEnabled {
env = append(env, envVar{"CGO_ENABLED", "1"})
} else {
@@ -81,8 +86,24 @@ func findEnv(env []envVar, name string) string {
return ""
}
+// extraEnvVars returns environment variables that should not leak into child processes.
+func extraEnvVars() []envVar {
+ var b builder
+ b.init()
+ cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
+ return []envVar{
+ {"PKG_CONFIG", b.pkgconfigCmd()},
+ {"CGO_CFLAGS", strings.Join(cflags, " ")},
+ {"CGO_CPPFLAGS", strings.Join(cppflags, " ")},
+ {"CGO_CXXFLAGS", strings.Join(cxxflags, " ")},
+ {"CGO_FFLAGS", strings.Join(fflags, " ")},
+ {"CGO_LDFLAGS", strings.Join(ldflags, " ")},
+ }
+}
+
func runEnv(cmd *Command, args []string) {
- env := mkEnv()
+ env := newEnv
+ env = append(env, extraEnvVars()...)
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
diff --git a/libgo/go/cmd/go/fix.go b/libgo/go/cmd/go/fix.go
index 94fd22e3c2..3af7adb4e1 100644
--- a/libgo/go/cmd/go/fix.go
+++ b/libgo/go/cmd/go/fix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/go/fmt.go b/libgo/go/cmd/go/fmt.go
index 57c02ad264..4ed7722575 100644
--- a/libgo/go/cmd/go/fmt.go
+++ b/libgo/go/cmd/go/fmt.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/go/generate.go b/libgo/go/cmd/go/generate.go
index cb54018bab..2d92a0c100 100644
--- a/libgo/go/cmd/go/generate.go
+++ b/libgo/go/cmd/go/generate.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -14,10 +14,8 @@ import (
"os/exec"
"path/filepath"
"regexp"
- "runtime"
"strconv"
"strings"
- "unicode"
)
var cmdGenerate = &Command{
@@ -27,7 +25,7 @@ var cmdGenerate = &Command{
Long: `
Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
-create or update Go source files, for instance by running yacc.
+create or update Go source files.
Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly.
@@ -90,10 +88,10 @@ string xxx represents the command identified by the arguments. This
can be used to create aliases or to handle multiword generators.
For example,
- //go:generate -command yacc go tool yacc
+ //go:generate -command foo go tool foo
-specifies that the command "yacc" represents the generator
-"go tool yacc".
+specifies that the command "foo" represents the generator
+"go tool foo".
Generate processes packages in the order given on the command line,
one at a time. If the command line lists .go files, they are treated
@@ -138,6 +136,8 @@ func init() {
}
func runGenerate(cmd *Command, args []string) {
+ ignoreImports = true
+
if generateRunFlag != "" {
var err error
generateRunRE, err = regexp.Compile(generateRunFlag)
@@ -277,8 +277,8 @@ func isGoGenerate(buf []byte) bool {
// single go:generate command.
func (g *Generator) setEnv() {
g.env = []string{
- "GOARCH=" + runtime.GOARCH,
- "GOOS=" + runtime.GOOS,
+ "GOARCH=" + buildContext.GOARCH,
+ "GOOS=" + buildContext.GOOS,
"GOFILE=" + g.file,
"GOLINE=" + strconv.Itoa(g.lineNum),
"GOPACKAGE=" + g.pkg,
@@ -371,17 +371,6 @@ func (g *Generator) expandVar(word string) string {
return os.Getenv(word)
}
-// identLength returns the length of the identifier beginning the string.
-func (g *Generator) identLength(word string) int {
- for i, r := range word {
- if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
- continue
- }
- return i
- }
- return len(word)
-}
-
// setShorthand installs a new shorthand as defined by a -command directive.
func (g *Generator) setShorthand(words []string) {
// Create command shorthand.
diff --git a/libgo/go/cmd/go/generate_test.go b/libgo/go/cmd/go/generate_test.go
index ba0669278e..dd116e6cc6 100644
--- a/libgo/go/cmd/go/generate_test.go
+++ b/libgo/go/cmd/go/generate_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go
index a298049a9d..6fb4235068 100644
--- a/libgo/go/cmd/go/get.go
+++ b/libgo/go/cmd/go/get.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -19,8 +19,8 @@ var cmdGet = &Command{
UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
-Get downloads and installs the packages named by the import paths,
-along with their dependencies.
+Get downloads the packages named by the import paths, along with their
+dependencies. It then installs the named packages, like 'go install'.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
@@ -43,11 +43,13 @@ The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
+The -v flag enables verbose progress and debug output.
+
Get also accepts build flags to control the installation. See 'go help build'.
-When checking out a new package, get creates the target directory
+When checking out a new package, get creates the target directory
GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
-get uses the first one. See 'go help gopath'.
+get uses the first one. For more details see: 'go help gopath'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
@@ -55,8 +57,7 @@ rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.
-Unless vendoring support is disabled (see 'go help gopath'),
-when go get checks out or updates a Git repository,
+When go get checks out or updates a Git repository,
it also updates any git submodules referenced by the repository.
Get never checks out or updates code stored in vendor directories.
@@ -97,13 +98,31 @@ func runGet(cmd *Command, args []string) {
os.Setenv("GIT_TERMINAL_PROMPT", "0")
}
+ // Disable any ssh connection pooling by Git.
+ // If a Git subprocess forks a child into the background to cache a new connection,
+ // that child keeps stdout/stderr open. After the Git subprocess exits,
+ // os /exec expects to be able to read from the stdout/stderr pipe
+ // until EOF to get all the data that the Git subprocess wrote before exiting.
+ // The EOF doesn't come until the child exits too, because the child
+ // is holding the write end of the pipe.
+ // This is unfortunate, but it has come up at least twice
+ // (see golang.org/issue/13453 and golang.org/issue/16104)
+ // and confuses users when it does.
+ // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
+ // assume they know what they are doing and don't step on it.
+ // But default to turning off ControlMaster.
+ if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
+ os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
+ }
+
// Phase 1. Download/update.
var stk importStack
mode := 0
if *getT {
mode |= getTestDeps
}
- for _, arg := range downloadPaths(args) {
+ args = downloadPaths(args)
+ for _, arg := range args {
download(arg, nil, &stk, mode)
}
exitIfErrors()
@@ -112,13 +131,21 @@ func runGet(cmd *Command, args []string) {
// Code we downloaded and all code that depends on it
// needs to be evicted from the package cache so that
- // the information will be recomputed. Instead of keeping
+ // the information will be recomputed. Instead of keeping
// track of the reverse dependency information, evict
// everything.
for name := range packageCache {
delete(packageCache, name)
}
+ // In order to rebuild packages information completely,
+ // we need to clear commands cache. Command packages are
+ // referring to evicted packages from the package cache.
+ // This leads to duplicated loads of the standard packages.
+ for name := range cmdCache {
+ delete(cmdCache, name)
+ }
+
args = importPaths(args)
packagesForBuild(args)
@@ -130,11 +157,11 @@ func runGet(cmd *Command, args []string) {
return
}
- runInstall(cmd, args)
+ installPackages(args, true)
}
// downloadPaths prepares the list of paths to pass to download.
-// It expands ... patterns that can be expanded. If there is no match
+// It expands ... patterns that can be expanded. If there is no match
// for a particular pattern, downloadPaths leaves it in the result list,
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
@@ -145,7 +172,7 @@ func downloadPaths(args []string) []string {
if strings.Contains(a, "...") {
var expand []string
// Use matchPackagesInFS to avoid printing
- // warnings. They will be printed by the
+ // warnings. They will be printed by the
// eventual call to importPaths instead.
if build.IsLocalImport(a) {
expand = matchPackagesInFS(a)
@@ -170,7 +197,7 @@ var downloadCache = map[string]bool{}
// downloadRootCache records the version control repository
// root directories we have already considered during the download.
-// For example, all the packages in the code.google.com/p/codesearch repo
+// For example, all the packages in the github.com/google/codesearch repo
// share the same root (the directory for that path), and we only need
// to run the hg commands to consider each repository once.
var downloadRootCache = map[string]bool{}
@@ -178,6 +205,10 @@ var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, parent *Package, stk *importStack, mode int) {
+ if mode&useVendor != 0 {
+ // Caller is responsible for expanding vendor paths.
+ panic("internal error: download mode has useVendor set")
+ }
load := func(path string, mode int) *Package {
if parent == nil {
return loadPackage(path, stk)
@@ -228,16 +259,6 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
stk.pop()
return
}
-
- // Warn that code.google.com is shutting down. We
- // issue the warning here because this is where we
- // have the import stack.
- if strings.HasPrefix(p.ImportPath, "code.google.com") {
- fmt.Fprintf(os.Stderr, "warning: code.google.com is shutting down; import path %v will stop working\n", p.ImportPath)
- if len(*stk) > 1 {
- fmt.Fprintf(os.Stderr, "warning: package %v\n", strings.Join(*stk, "\n\timports "))
- }
- }
stk.pop()
args := []string{arg}
@@ -298,32 +319,42 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
}
// Process dependencies, now that we know what they are.
- for _, path := range p.Imports {
+ imports := p.Imports
+ if mode&getTestDeps != 0 {
+ // Process test dependencies when -t is specified.
+ // (But don't get test dependencies for test dependencies:
+ // we always pass mode 0 to the recursive calls below.)
+ imports = stringList(imports, p.TestImports, p.XTestImports)
+ }
+ for i, path := range imports {
if path == "C" {
continue
}
- // Don't get test dependencies recursively.
- // Imports is already vendor-expanded.
- download(path, p, stk, 0)
- }
- if mode&getTestDeps != 0 {
- // Process test dependencies when -t is specified.
- // (Don't get test dependencies for test dependencies.)
- // We pass useVendor here because p.load does not
- // vendor-expand TestImports and XTestImports.
- // The call to loadImport inside download needs to do that.
- for _, path := range p.TestImports {
- if path == "C" {
- continue
- }
- download(path, p, stk, useVendor)
+ // Fail fast on import naming full vendor path.
+ // Otherwise expand path as needed for test imports.
+ // Note that p.Imports can have additional entries beyond p.build.Imports.
+ orig := path
+ if i < len(p.build.Imports) {
+ orig = p.build.Imports[i]
}
- for _, path := range p.XTestImports {
- if path == "C" {
- continue
+ if j, ok := findVendor(orig); ok {
+ stk.push(path)
+ err := &PackageError{
+ ImportStack: stk.copy(),
+ Err: "must be imported as " + path[j+len("vendor/"):],
}
- download(path, p, stk, useVendor)
+ stk.pop()
+ errorf("%s", err)
+ continue
+ }
+ // If this is a test import, apply vendor lookup now.
+ // We cannot pass useVendor to download, because
+ // download does caching based on the value of path,
+ // so it must be the fully qualified path already.
+ if i >= len(p.Imports) {
+ path = vendoredImportPath(p, path)
}
+ download(path, p, stk, 0)
}
if isWildcard {
@@ -347,8 +378,8 @@ func downloadPackage(p *Package) error {
}
if p.build.SrcRoot != "" {
- // Directory exists. Look for checkout along path to src.
- vcs, rootPath, err = vcsForDir(p)
+ // Directory exists. Look for checkout along path to src.
+ vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
if err != nil {
return err
}
@@ -356,7 +387,7 @@ func downloadPackage(p *Package) error {
// Double-check where it came from.
if *getU && vcs.remoteRepo != nil {
- dir := filepath.Join(p.build.SrcRoot, rootPath)
+ dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir)
if err != nil {
return err
@@ -371,7 +402,7 @@ func downloadPackage(p *Package) error {
repo = resolved
}
}
- if remote != repo && p.ImportComment != "" {
+ if remote != repo && rr.isCustom {
return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
}
}
@@ -391,19 +422,23 @@ func downloadPackage(p *Package) error {
}
if p.build.SrcRoot == "" {
- // Package not found. Put in first directory of $GOPATH.
+ // Package not found. Put in first directory of $GOPATH.
list := filepath.SplitList(buildContext.GOPATH)
if len(list) == 0 {
- return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
+ return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
- if list[0] == goroot {
- return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
+ if filepath.Clean(list[0]) == filepath.Clean(goroot) {
+ return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
+ }
+ if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
+ return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
}
+ p.build.Root = list[0]
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
}
- root := filepath.Join(p.build.SrcRoot, rootPath)
+ root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil
@@ -422,17 +457,25 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("%s exists but is not a directory", meta)
}
if err != nil {
- // Metadata directory does not exist. Prepare to checkout new copy.
+ // Metadata directory does not exist. Prepare to checkout new copy.
// Some version control tools require the target directory not to exist.
// We require that too, just to avoid stepping on existing work.
if _, err := os.Stat(root); err == nil {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
}
+
+ _, err := os.Stat(p.build.Root)
+ gopathExisted := err == nil
+
// Some version control tools require the parent of the target to exist.
parent, _ := filepath.Split(root)
if err = os.MkdirAll(parent, 0777); err != nil {
return err
}
+ if buildV && !gopathExisted && p.build.Root == buildContext.GOPATH {
+ fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
+ }
+
if err = vcs.create(root, repo); err != nil {
return err
}
diff --git a/libgo/go/cmd/go/go11.go b/libgo/go/cmd/go/go11.go
index 8a434dfed1..7e383f4b5b 100644
--- a/libgo/go/cmd/go/go11.go
+++ b/libgo/go/cmd/go/go11.go
@@ -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.
diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go
index 39e0f3e56d..fa78578d12 100644
--- a/libgo/go/cmd/go/go_test.go
+++ b/libgo/go/cmd/go/go_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -6,7 +6,6 @@ package main_test
import (
"bytes"
- "flag"
"fmt"
"go/build"
"go/format"
@@ -50,6 +49,17 @@ func init() {
// many linux/arm machines are too slow to run
// the full set of external tests.
skipExternal = true
+ case "mips", "mipsle", "mips64", "mips64le":
+ // Also slow.
+ skipExternal = true
+ if testenv.Builder() != "" {
+ // On the builders, skip the cmd/go
+ // tests. They're too slow and already
+ // covered by other ports. There's
+ // nothing os/arch specific in the
+ // tests.
+ canRun = false
+ }
}
case "freebsd":
switch runtime.GOARCH {
@@ -67,8 +77,6 @@ func init() {
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
- flag.Parse()
-
if canRun {
args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
if race.Enabled {
@@ -99,6 +107,14 @@ func TestMain(m *testing.M) {
// Don't let these environment variables confuse the test.
os.Unsetenv("GOBIN")
os.Unsetenv("GOPATH")
+ os.Unsetenv("GIT_ALLOW_PROTOCOL")
+ if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
+ // On some systems the default C compiler is ccache.
+ // Setting HOME to a non-existent directory will break
+ // those systems. Set CCACHE_DIR to cope. Issue 17668.
+ os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
+ }
+ os.Setenv("HOME", "/test-go-home-does-not-exist")
r := m.Run()
@@ -109,7 +125,7 @@ func TestMain(m *testing.M) {
os.Exit(r)
}
-// The length of an mtime tick on this system. This is an estimate of
+// The length of an mtime tick on this system. This is an estimate of
// how long we need to sleep to ensure that the mtime of two files is
// different.
// We used to try to be clever but that didn't always work (see golang.org/issue/12205).
@@ -181,7 +197,7 @@ func (tg *testgoData) pwd() string {
return wd
}
-// cd changes the current directory to the named directory. Note that
+// cd changes the current directory to the named directory. Note that
// using this means that the test must not be run in parallel with any
// other tests.
func (tg *testgoData) cd(dir string) {
@@ -325,7 +341,7 @@ func (tg *testgoData) getStderr() string {
}
// doGrepMatch looks for a regular expression in a buffer, and returns
-// whether it is found. The regular expression is matched against
+// whether it is found. The regular expression is matched against
// each line separately, as with the grep command.
func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
if !tg.ran {
@@ -341,7 +357,7 @@ func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
}
// doGrep looks for a regular expression in a buffer and fails if it
-// is not found. The name argument is the name of the output we are
+// is not found. The name argument is the name of the output we are
// searching, "output" or "error". The msg argument is logged on
// failure.
func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
@@ -375,7 +391,7 @@ func (tg *testgoData) grepBoth(match, msg string) {
}
// doGrepNot looks for a regular expression in a buffer and fails if
-// it is found. The name and msg arguments are as for doGrep.
+// it is found. The name and msg arguments are as for doGrep.
func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
if tg.doGrepMatch(match, b) {
tg.t.Log(msg)
@@ -421,18 +437,6 @@ func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
return c
}
-// grepCountStdout returns the number of times a regexp is seen in
-// standard output.
-func (tg *testgoData) grepCountStdout(match string) int {
- return tg.doGrepCount(match, &tg.stdout)
-}
-
-// grepCountStderr returns the number of times a regexp is seen in
-// standard error.
-func (tg *testgoData) grepCountStderr(match string) int {
- return tg.doGrepCount(match, &tg.stderr)
-}
-
// grepCountBoth returns the number of times a regexp is seen in both
// standard output and standard error.
func (tg *testgoData) grepCountBoth(match string) int {
@@ -440,8 +444,8 @@ func (tg *testgoData) grepCountBoth(match string) int {
}
// creatingTemp records that the test plans to create a temporary file
-// or directory. If the file or directory exists already, it will be
-// removed. When the test completes, the file or directory will be
+// or directory. If the file or directory exists already, it will be
+// removed. When the test completes, the file or directory will be
// removed if it exists.
func (tg *testgoData) creatingTemp(path string) {
if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {
@@ -457,7 +461,7 @@ func (tg *testgoData) creatingTemp(path string) {
tg.temps = append(tg.temps, path)
}
-// makeTempdir makes a temporary directory for a run of testgo. If
+// makeTempdir makes a temporary directory for a run of testgo. If
// the temporary directory was already created, this does nothing.
func (tg *testgoData) makeTempdir() {
if tg.tempdir == "" {
@@ -501,6 +505,16 @@ func (tg *testgoData) path(name string) string {
return filepath.Join(tg.tempdir, name)
}
+// mustExist fails if path does not exist.
+func (tg *testgoData) mustExist(path string) {
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ tg.t.Fatalf("%s does not exist but should", path)
+ }
+ tg.t.Fatalf("%s stat failed: %v", path, err)
+ }
+}
+
// mustNotExist fails if path exists.
func (tg *testgoData) mustNotExist(path string) {
if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
@@ -536,32 +550,43 @@ func (tg *testgoData) wantArchive(path string) {
}
}
-// isStale returns whether pkg is stale.
-func (tg *testgoData) isStale(pkg string) bool {
- tg.run("list", "-f", "{{.Stale}}", pkg)
- switch v := strings.TrimSpace(tg.getStdout()); v {
- case "true":
- return true
- case "false":
- return false
- default:
- tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
- panic("unreachable")
+// isStale reports whether pkg is stale, and why
+func (tg *testgoData) isStale(pkg string) (bool, string) {
+ tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)
+ v := strings.TrimSpace(tg.getStdout())
+ f := strings.SplitN(v, ":", 2)
+ if len(f) == 2 {
+ switch f[0] {
+ case "true":
+ return true, f[1]
+ case "false":
+ return false, f[1]
+ }
}
+ tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
+ panic("unreachable")
}
// wantStale fails with msg if pkg is not stale.
-func (tg *testgoData) wantStale(pkg, msg string) {
- if !tg.isStale(pkg) {
+func (tg *testgoData) wantStale(pkg, reason, msg string) {
+ stale, why := tg.isStale(pkg)
+ if !stale {
tg.t.Fatal(msg)
}
+ if reason == "" && why != "" || !strings.Contains(why, reason) {
+ tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
+ }
}
// wantNotStale fails with msg if pkg is stale.
-func (tg *testgoData) wantNotStale(pkg, msg string) {
- if tg.isStale(pkg) {
+func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
+ stale, why := tg.isStale(pkg)
+ if stale {
tg.t.Fatal(msg)
}
+ if reason == "" && why != "" || !strings.Contains(why, reason) {
+ tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)
+ }
}
// cleanup cleans up a test that runs testgo.
@@ -581,32 +606,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() {
@@ -644,6 +643,7 @@ func TestProgramNameInCrashMessages(t *testing.T) {
func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.runFail("test", "./testdata/src/badtest/...")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
@@ -720,7 +720,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
tg.tempFile("d1/src/p1/p1.go", `package p1`)
tg.setenv("GOPATH", tg.path("d1"))
tg.run("install", "-a", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
tg.sleep()
// Changing mtime and content of runtime/internal/sys/sys.go
@@ -729,28 +729,28 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go"
restore := addNL(sys)
defer restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
// But changing runtime/internal/sys/zversion.go should have an effect:
// that's how we tell when we flip from one release to another.
zversion := runtime.GOROOT() + "/src/runtime/internal/sys/zversion.go"
restore = addNL(zversion)
defer restore()
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
addNL(zversion)
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with new release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
// Restore to "old" release.
restore()
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with old release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
// Everything is out of date. Rebuild to leave things in a better state.
tg.run("install", "std")
@@ -759,6 +759,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
func TestGoListStandard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.cd(runtime.GOROOT() + "/src")
tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
stdout := tg.getStdout()
@@ -783,6 +784,7 @@ func TestGoListStandard(t *testing.T) {
func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/mycmd"))
@@ -833,8 +835,8 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
- tg.wantNotStale("p2", "./testgo list claims p2 is stale, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
+ tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly")
tg.sleep()
if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil {
t.Fatal(err)
@@ -843,12 +845,12 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
} else {
tg.must(f.Close())
}
- tg.wantStale("p2", "./testgo list claims p2 is NOT stale, incorrectly")
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly")
+ tg.wantStale("p2", "newer source file", "./testgo list claims p2 is NOT stale, incorrectly")
+ tg.wantStale("p1", "stale dependency", "./testgo list claims p1 is NOT stale, incorrectly")
tg.run("install", "p1")
- tg.wantNotStale("p2", "./testgo list claims p2 is stale after reinstall, incorrectly")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after reinstall, incorrectly")
+ tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
}
func TestGoInstallDetectsRemovedFiles(t *testing.T) {
@@ -862,18 +864,19 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
package mypkg`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mypkg")
- tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly")
+ tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mypkg/z.go")))
- tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
+ tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mypkg/y.go")))
- tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
+ tg.wantStale("mypkg", "build ID mismatch", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
}
func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mypkg/x.go", `package mypkg`)
tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
tg.setenv("GOPATH", tg.path("."))
@@ -931,13 +934,13 @@ func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
package main`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mycmd")
- tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly")
+ tg.wantNotStale("mycmd", "", "./testgo list mypkg claims mycmd is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mycmd/z.go")))
- tg.wantNotStale("mycmd", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
+ tg.wantNotStale("mycmd", "", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mycmd/y.go")))
- tg.wantStale("mycmd", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
+ tg.wantStale("mycmd", "build ID mismatch", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
}
func testLocalRun(tg *testgoData, exepath, local, match string) {
@@ -1030,6 +1033,7 @@ func copyBad(tg *testgoData) {
func TestBadImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
copyBad(tg)
testLocalEasy(tg, badDirName)
}
@@ -1059,14 +1063,14 @@ func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
- tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal")
+ tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
- tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
+ tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
}
func TestRunInternal(t *testing.T) {
@@ -1076,7 +1080,7 @@ func TestRunInternal(t *testing.T) {
tg.setenv("GOPATH", dir)
tg.run("run", filepath.Join(dir, "src/run/good.go"))
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
- tg.grepStderr("use of internal package not allowed", "unexpected error for run/bad.go")
+ tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
}
func testMove(t *testing.T, vcs, url, base, config string) {
@@ -1105,8 +1109,8 @@ func testMove(t *testing.T, vcs, url, base, config string) {
}
if vcs == "git" {
// git will ask for a username and password when we
- // run go get -d -f -u. An empty username and
- // password will work. Prevent asking by setting
+ // run go get -d -f -u. An empty username and
+ // password will work. Prevent asking by setting
// GIT_ASKPASS.
tg.creatingTemp("sink" + exeSuffix)
tg.tempFile("src/sink/sink.go", `package main; func main() {}`)
@@ -1178,7 +1182,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 {
@@ -1193,11 +1197,55 @@ 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)
}
+func TestIssue16471(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("."))
+ tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755))
+ tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952")
+ tg.runFail("get", "-u", "rsc.io/go-get-issue-10952")
+ tg.grepStderr("rsc.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/zombiezen/go-get-issue-10952", "did not detect updated import path")
+}
+
+// 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 = "rsc.io/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 {
@@ -1217,7 +1265,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")
@@ -1226,14 +1273,6 @@ func TestGetGitDefaultBranch(t *testing.T) {
tg.grepStdout(`\* another-branch`, "not on correct default branch")
}
-func TestDisallowedCSourceFiles(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.runFail("build", "badc")
- tg.grepStderr("C source files not allowed", "go test did not say C source files not allowed")
-}
-
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1266,11 +1305,23 @@ func TestRelativeImportsGoTestDashI(t *testing.T) {
func TestRelativeImportsInCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
files, err := filepath.Glob("./testdata/testimport/*.go")
tg.must(err)
tg.run(append([]string{"test"}, files...)...)
}
+func TestNonCanonicalImportPaths(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "canonical/d")
+ tg.grepStderr("package canonical/d", "did not report canonical/d")
+ tg.grepStderr("imports canonical/b", "did not report canonical/b")
+ tg.grepStderr("imports canonical/a/: non-canonical", "did not report canonical/a/")
+}
+
func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1316,9 +1367,6 @@ func TestInstallIntoGOPATH(t *testing.T) {
// Issue 12407
func TestBuildOutputToDevNull(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping because /dev/null is a regular file on plan9")
- }
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
@@ -1337,19 +1385,35 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
tg.sleep()
tg.run("test", "main_test")
tg.run("install", "main_test")
- tg.wantNotStale("main_test", "after go install, main listed as stale")
+ tg.wantNotStale("main_test", "", "after go install, main listed as stale")
tg.run("test", "main_test")
}
+// The runtime version string takes one of two forms:
+// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
+// Determine whether we are in a released copy by
+// inspecting the version.
+var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
+
// Issue 12690
func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+
+ // Make sure the packages below are not stale.
+ tg.run("install", "runtime", "os", "io")
+
goroot := runtime.GOROOT()
tg.setenv("GOROOT", goroot+"/")
- tg.wantNotStale("runtime", "with trailing slash in GOROOT, runtime listed as stale")
- tg.wantNotStale("os", "with trailing slash in GOROOT, os listed as stale")
- tg.wantNotStale("io", "with trailing slash in GOROOT, io listed as stale")
+
+ want := ""
+ if isGoRelease {
+ want = "standard package in Go release distribution"
+ }
+
+ tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale")
+ tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale")
+ tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale")
}
// With $GOBIN set, binaries get installed to $GOBIN.
@@ -1397,28 +1461,6 @@ func TestInstallToGOBINCommandLinePackage(t *testing.T) {
tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld")
}
-func TestGodocInstalls(t *testing.T) {
- testenv.MustHaveExternalNetwork(t)
-
- // godoc installs into GOBIN
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempDir("gobin")
- tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GOBIN", tg.path("gobin"))
- tg.run("get", "golang.org/x/tools/cmd/godoc")
- tg.wantExecutable(tg.path("gobin/godoc"), "did not install godoc to $GOBIN")
- tg.unsetenv("GOBIN")
-
- // godoc installs into GOROOT
- goroot := runtime.GOROOT()
- tg.setenv("GOROOT", goroot)
- tg.check(os.RemoveAll(filepath.Join(goroot, "bin", "godoc")))
- tg.run("install", "golang.org/x/tools/cmd/godoc")
- tg.wantExecutable(filepath.Join(goroot, "bin", "godoc"), "did not install godoc to $GOROOT/bin")
-}
-
func TestGoGetNonPkg(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1435,6 +1477,17 @@ func TestGoGetNonPkg(t *testing.T) {
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
}
+func TestGoGetTestOnlyPkg(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.tempDir("gopath")
+ tg.setenv("GOPATH", tg.path("gopath"))
+ tg.run("get", "golang.org/x/tour/content")
+ tg.run("get", "-t", "golang.org/x/tour/content")
+}
+
func TestInstalls(t *testing.T) {
if testing.Short() {
t.Skip("don't install into GOROOT in short mode")
@@ -1508,7 +1561,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
defer tg.cleanup()
tg.parallel()
tg.run("test", "errors", "errors", "errors", "errors", "errors")
- if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 {
+ if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {
t.Error("go test errors errors errors errors errors tested the same package multiple times")
}
}
@@ -1516,6 +1569,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
func TestGoListHasAConsistentOrder(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
first := tg.getStdout()
tg.run("list", "std")
@@ -1527,6 +1581,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) {
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
tg.grepStdoutNot("cmd/", "go list std shows commands")
}
@@ -1534,10 +1589,11 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "cmd")
out := strings.TrimSpace(tg.getStdout())
for _, line := range strings.Split(out, "\n") {
- if strings.Index(line, "cmd/") == -1 {
+ if !strings.Contains(line, "cmd/") {
t.Error("go list cmd shows non-commands")
break
}
@@ -1547,6 +1603,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
func TestGoListDedupsPackages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("list", "xtestonly", "./testdata/src/xtestonly/...")
got := strings.TrimSpace(tg.getStdout())
@@ -1560,6 +1617,7 @@ func TestGoListDedupsPackages(t *testing.T) {
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
@@ -1569,6 +1627,7 @@ func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
func TestGOROOTSearchFailureReporting(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
@@ -1578,6 +1637,7 @@ func TestGOROOTSearchFailureReporting(t *testing.T) {
func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1590,6 +1650,7 @@ func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1602,6 +1663,7 @@ func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1610,42 +1672,122 @@ func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
}
}
-// Test missing GOPATH is reported.
-func TestMissingGOPATHIsReported(t *testing.T) {
+func homeEnvName() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "USERPROFILE"
+ case "plan9":
+ return "home"
+ default:
+ return "HOME"
+ }
+}
+
+func TestDefaultGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.setenv("GOPATH", "")
- tg.runFail("install", "foo/quxx")
- if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 {
- t.Error(`go install foo/quxx expected error: ($GOPATH not set)`)
- }
+ tg.parallel()
+ tg.tempDir("home/go")
+ tg.setenv(homeEnvName(), tg.path("home"))
+
+ tg.run("env", "GOPATH")
+ tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
+
+ tg.setenv("GOROOT", tg.path("home/go"))
+ tg.run("env", "GOPATH")
+ tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
+
+ tg.setenv("GOROOT", tg.path("home/go")+"/")
+ tg.run("env", "GOPATH")
+ tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
}
-// Issue 4186. go get cannot be used to download packages to $GOROOT.
-// Test that without GOPATH set, go get should fail.
-func TestWithoutGOPATHGoGetFails(t *testing.T) {
+func TestDefaultGOPATHGet(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
- tg.parallel()
- tg.tempDir("src")
tg.setenv("GOPATH", "")
- tg.setenv("GOROOT", tg.path("."))
- tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
+ tg.tempDir("home")
+ tg.setenv(homeEnvName(), tg.path("home"))
+
+ // warn for creating directory
+ tg.run("get", "-v", "github.com/golang/example/hello")
+ tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
+
+ // no warning if directory already exists
+ tg.must(os.RemoveAll(tg.path("home/go")))
+ tg.tempDir("home/go")
+ tg.run("get", "github.com/golang/example/hello")
+ tg.grepStderrNot(".", "expected no output on standard error")
+
+ // error if $HOME/go is a file
+ tg.must(os.RemoveAll(tg.path("home/go")))
+ tg.tempFile("home/go", "")
+ tg.runFail("get", "github.com/golang/example/hello")
+ tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
+}
+
+func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", "")
+ tg.tempDir("home")
+ tg.setenv(homeEnvName(), tg.path("home"))
+
+ tg.runFail("install", "github.com/golang/example/hello")
+ tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
}
-// Test that with GOPATH=$GOROOT, go get should fail.
-func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
+// Issue 4186. go get cannot be used to download packages to $GOROOT.
+// Test that without GOPATH set, go get should fail.
+func TestGoGetIntoGOROOT(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
+
+ // Fails because GOROOT=GOPATH
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOROOT", tg.path("."))
- tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+ tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
+
+ // Fails because GOROOT=GOPATH after cleaning.
+ tg.setenv("GOPATH", tg.path(".")+"/")
+ tg.setenv("GOROOT", tg.path("."))
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+ tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
+
+ tg.setenv("GOPATH", tg.path("."))
+ tg.setenv("GOROOT", tg.path(".")+"/")
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+ tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
+
+ // Fails because GOROOT=$HOME/go so default GOPATH unset.
+ tg.tempDir("home/go")
+ tg.setenv(homeEnvName(), tg.path("home"))
+ tg.setenv("GOPATH", "")
+ tg.setenv("GOROOT", tg.path("home/go"))
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
+
+ tg.setenv(homeEnvName(), tg.path("home")+"/")
+ tg.setenv("GOPATH", "")
+ tg.setenv("GOROOT", tg.path("home/go"))
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
+
+ tg.setenv(homeEnvName(), tg.path("home"))
+ tg.setenv("GOPATH", "")
+ tg.setenv("GOROOT", tg.path("home/go")+"/")
+ tg.runFail("get", "-d", "github.com/golang/example/hello")
+ tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
}
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
@@ -1657,13 +1799,14 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
func main() {
println(extern)
}`)
- tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go"))
- tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`)
+ tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go"))
+ tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)
}
func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "errors")
@@ -1673,12 +1816,33 @@ func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
}
+func TestGoTestMutexprofileLeavesBinaryBehind(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.makeTempdir()
+ tg.cd(tg.path("."))
+ tg.run("test", "-mutexprofile", "errors.prof", "errors")
+ tg.wantExecutable("errors.test"+exeSuffix, "go test -mutexprofile did not create errors.test")
+}
+
+func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.makeTempdir()
+ tg.cd(tg.path("."))
+ tg.run("test", "-mutexprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
+ tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test")
+}
+
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1697,6 +1861,16 @@ func TestGoTestDashOWritesBinary(t *testing.T) {
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
}
+func TestGoTestDashIDashOWritesBinary(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
+ tg.grepBothNot("PASS|FAIL", "test should not have run")
+ tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
+}
+
// Issue 4568.
func TestSymlinksList(t *testing.T) {
switch runtime.GOOS {
@@ -1706,6 +1880,7 @@ func TestSymlinksList(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempDir("src")
tg.must(os.Symlink(tg.path("."), tg.path("src/dir1")))
tg.tempFile("src/dir1/p.go", "package p")
@@ -1726,7 +1901,7 @@ func TestSymlinksVendor(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.setenv("GO15VENDOREXPERIMENT", "1")
+ // TODO: tg.parallel()
tg.tempDir("gopath/src/dir1/vendor/v")
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
@@ -1744,6 +1919,27 @@ func TestSymlinksVendor(t *testing.T) {
tg.run("install")
}
+// Issue 15201.
+func TestSymlinksVendor15201(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("skipping symlink test on %s", runtime.GOOS)
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempDir("gopath/src/x/y/_vendor/src/x")
+ tg.must(os.Symlink("../../..", tg.path("gopath/src/x/y/_vendor/src/x/y")))
+ tg.tempFile("gopath/src/x/y/w/w.go", "package w\nimport \"x/y/z\"\n")
+ tg.must(os.Symlink("../_vendor/src", tg.path("gopath/src/x/y/w/vendor")))
+ tg.tempFile("gopath/src/x/y/z/z.go", "package z\n")
+
+ tg.setenv("GOPATH", tg.path("gopath/src/x/y/_vendor")+string(filepath.ListSeparator)+tg.path("gopath"))
+ tg.cd(tg.path("gopath/src"))
+ tg.run("list", "./...")
+}
+
func TestSymlinksInternal(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
@@ -1835,9 +2031,7 @@ func TestCaseCollisions(t *testing.T) {
// Issue 8181.
func TestGoGetDashTIssue8181(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test that uses network in short mode")
- }
+ testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
@@ -1846,14 +2040,12 @@ func TestGoGetDashTIssue8181(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b")
tg.run("list", "...")
- tg.grepStdout("x/build/cmd/cl", "missing expected x/build/cmd/cl")
+ tg.grepStdout("x/build/gerrit", "missing expected x/build/gerrit")
}
func TestIssue11307(t *testing.T) {
// go get -u was not working except in checkout directory
- if testing.Short() {
- t.Skip("skipping test that uses network in short mode")
- }
+ testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
@@ -1879,7 +2071,9 @@ func TestShadowingLogic(t *testing.T) {
}
// The output will have makeImportValid applies, but we only
// bother to deal with characters we might reasonably see.
- pwdForwardSlash = strings.Replace(pwdForwardSlash, ":", "_", -1)
+ for _, r := range " :" {
+ pwdForwardSlash = strings.Replace(pwdForwardSlash, string(r), "_", -1)
+ }
want := "(_" + pwdForwardSlash + "/testdata/shadow/root1/src/math) (" + filepath.Join(runtime.GOROOT(), "src", "math") + ")"
if strings.TrimSpace(tg.getStdout()) != want {
t.Error("shadowed math is not shadowed; looking for", want)
@@ -2001,16 +2195,93 @@ func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
checkCoverage(tg, data)
}
-func TestCoverageWithCgo(t *testing.T) {
+func TestCoverageImportMainLoop(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+ tg.runFail("test", "-cover", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+}
+
+func TestTestEmpty(t *testing.T) {
+ if !canRace {
+ t.Skip("no race detector")
+ }
+
+ wd, _ := os.Getwd()
+ testdata := filepath.Join(wd, "testdata")
+
+ for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", testdata)
+ tg.cd(filepath.Join(testdata, "src/empty/"+dir))
+ tg.run("test", "-cover", "-coverpkg=.", "-race")
+ })
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func TestTestRaceInstall(t *testing.T) {
+ if !canRace {
+ t.Skip("no race detector")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+
+ tg.tempDir("pkg")
+ pkgdir := tg.path("pkg")
+ tg.run("install", "-race", "-pkgdir="+pkgdir, "std")
+ tg.run("test", "-race", "-pkgdir="+pkgdir, "-i", "-v", "empty/pkg")
+ if tg.getStderr() != "" {
+ t.Error("go test -i -race: rebuilds cached packages")
+ }
+}
+
+func TestBuildDryRunWithCgo(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
- tg.run("test", "-short", "-cover", "./testdata/cgocover")
- data := tg.getStdout() + tg.getStderr()
- checkCoverage(tg, data)
+ tg.tempFile("foo.go", `package main
+
+/*
+#include <limits.h>
+*/
+import "C"
+
+func main() {
+ println(C.INT_MAX)
+}`)
+ tg.run("build", "-n", tg.path("foo.go"))
+ tg.grepStderrNot(`os.Stat .* no such file or directory`, "unexpected stat of archive file")
+}
+
+func TestCoverageWithCgo(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+
+ for _, dir := range []string{"cgocover", "cgocover2", "cgocover3", "cgocover4"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "-short", "-cover", dir)
+ data := tg.getStdout() + tg.getStderr()
+ checkCoverage(tg, data)
+ })
+ }
}
func TestCgoDependsOnSyscall(t *testing.T) {
@@ -2073,10 +2344,57 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
tg.run("build", "origin")
}
+func TestCgoPkgConfig(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ tg.run("env", "PKG_CONFIG")
+ pkgConfig := strings.TrimSpace(tg.getStdout())
+ if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
+ t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
+ }
+
+ // OpenBSD's pkg-config is strict about whitespace and only
+ // supports backslash-escaped whitespace. It does not support
+ // quotes, which the normal freedesktop.org pkg-config does
+ // support. See http://man.openbsd.org/pkg-config.1
+ tg.tempFile("foo.pc", `
+Name: foo
+Description: The foo library
+Version: 1.0.0
+Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
+`)
+ tg.tempFile("foo.go", `package main
+
+/*
+#cgo pkg-config: foo
+int value() {
+ return DEFINED_FROM_PKG_CONFIG;
+}
+*/
+import "C"
+import "os"
+
+func main() {
+ if C.value() != 42 {
+ println("value() =", C.value(), "wanted 42")
+ os.Exit(1)
+ }
+}
+`)
+ tg.setenv("PKG_CONFIG_PATH", tg.path("."))
+ tg.run("run", tg.path("foo.go"))
+}
+
// "go test -c -test.bench=XXX errors" should not hang
func TestIssue6480(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-c", "-test.bench=XXX", "errors")
@@ -2106,10 +2424,38 @@ func main() { C.f() }`)
tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
}
-func TestListTemplateCanUseContextFunction(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.run("list", "-f", "GOARCH: {{context.GOARCH}}")
+func TestListTemplateContextFunction(t *testing.T) {
+ t.Parallel()
+ for _, tt := range []struct {
+ v string
+ want string
+ }{
+ {"GOARCH", runtime.GOARCH},
+ {"GOOS", runtime.GOOS},
+ {"GOROOT", filepath.Clean(runtime.GOROOT())},
+ {"GOPATH", os.Getenv("GOPATH")},
+ {"CgoEnabled", ""},
+ {"UseAllFiles", ""},
+ {"Compiler", ""},
+ {"BuildTags", ""},
+ {"ReleaseTags", ""},
+ {"InstallSuffix", ""},
+ } {
+ tt := tt
+ t.Run(tt.v, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tmpl := "{{context." + tt.v + "}}"
+ tg.run("list", "-f", tmpl)
+ if tt.want == "" {
+ return
+ }
+ if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
+ t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
+ }
+ })
+ }
}
// cmd/go: "go test" should fail if package does not build
@@ -2123,7 +2469,7 @@ func TestIssue7108(t *testing.T) {
// cmd/go: go test -a foo does not rebuild regexp.
func TestIssue6844(t *testing.T) {
if testing.Short() {
- t.Skip("don't rebuild the standard libary in short mode")
+ t.Skip("don't rebuild the standard library in short mode")
}
tg := testgo(t)
@@ -2267,6 +2613,20 @@ func TestGoGenerateEnv(t *testing.T) {
}
}
+func TestGoGenerateBadImports(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping because windows has no echo command")
+ }
+
+ // This package has an invalid import causing an import cycle,
+ // but go generate is supposed to still run.
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("generate", "gencycle")
+ tg.grepStdout("hello world", "go generate gencycle did not run generator")
+}
+
func TestGoGetCustomDomainWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -2295,8 +2655,7 @@ func TestGoVetWithExternalTests(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
- tg.setenv("GOPATH", tg.path("."))
- tg.run("get", "golang.org/x/tools/cmd/vet")
+ tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "vetpkg")
tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf")
@@ -2308,8 +2667,7 @@ func TestGoVetWithTags(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
- tg.setenv("GOPATH", tg.path("."))
- tg.run("get", "golang.org/x/tools/cmd/vet")
+ tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "-tags", "tagtest", "vetpkg")
tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
@@ -2330,6 +2688,11 @@ func TestGoGetRscIoToolstash(t *testing.T) {
// Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
func TestGoGetHTTPS404(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ switch runtime.GOOS {
+ case "darwin", "linux", "freebsd":
+ default:
+ t.Skipf("test case does not work on %s", runtime.GOOS)
+ }
tg := testgo(t)
defer tg.cleanup()
@@ -2338,22 +2701,243 @@ func TestGoGetHTTPS404(t *testing.T) {
tg.run("get", "bazil.org/fuse/fs/fstestutil")
}
-// Test that you can not import a main package.
-func TestIssue4210(t *testing.T) {
+// Test that you cannot import a main package.
+// See golang.org/issue/4210 and golang.org/issue/17475.
+func TestImportMain(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
+
+ // Importing package main from that package main's test should work.
tg.tempFile("src/x/main.go", `package main
var X int
func main() {}`)
- tg.tempFile("src/y/main.go", `package main
- import "fmt"
+ tg.tempFile("src/x/main_test.go", `package main_test
import xmain "x"
- func main() {
- fmt.Println(xmain.X)
- }`)
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.creatingTemp("x")
+ tg.run("build", "x")
+ tg.run("test", "x")
+
+ // Importing package main from another package should fail.
+ tg.tempFile("src/p1/p.go", `package p1
+ import xmain "x"
+ var _ = xmain.X
+ `)
+ tg.runFail("build", "p1")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even in that package's test.
+ tg.tempFile("src/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/p2/p_test.go", `package p2
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p2")
+ tg.runFail("test", "p2")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package's test is an xtest.
+ tg.tempFile("src/p3/p.go", `package p
+ `)
+ tg.tempFile("src/p3/p_test.go", `package p_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p3")
+ tg.runFail("test", "p3")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main
+ tg.tempFile("src/p4/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p4/p_test.go", `package main
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p4" + exeSuffix)
+ tg.run("build", "p4")
+ tg.runFail("test", "p4")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main using an xtest.
+ tg.tempFile("src/p5/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p5/p_test.go", `package main_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p5" + exeSuffix)
+ tg.run("build", "p5")
+ tg.runFail("test", "p5")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+}
+
+// Test that you cannot use a local import in a package
+// accessed by a non-local import (found in a GOPATH/GOROOT).
+// See golang.org/issue/17475.
+func TestImportLocal(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+
+ tg.tempFile("src/dir/x/x.go", `package x
+ var X int
+ `)
tg.setenv("GOPATH", tg.path("."))
- tg.runFail("build", "y")
- tg.grepBoth("is a program", `did not find expected error message ("is a program")`)
+ tg.run("build", "dir/x")
+
+ // Ordinary import should work.
+ tg.tempFile("src/dir/p0/p.go", `package p0
+ import "dir/x"
+ var _ = x.X
+ `)
+ tg.run("build", "dir/p0")
+
+ // Relative import should not.
+ tg.tempFile("src/dir/p1/p.go", `package p1
+ import "../x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/p1")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/dir/p2/p_test.go", `package p2
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/p2/p_test.go", `package p2_test
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import starting with ./ should not work either.
+ tg.tempFile("src/dir/d.go", `package dir
+ import "./x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/d.go", `package dir
+ `)
+ tg.tempFile("src/dir/d_test.go", `package dir
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/d_test.go", `package dir_test
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import plain ".." should not work.
+ tg.tempFile("src/dir/x/y/y.go", `package dir
+ import ".."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/y/y.go", `package y
+ `)
+ tg.tempFile("src/dir/x/y/y_test.go", `package y
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an x test.
+ tg.tempFile("src/dir/x/y/y_test.go", `package y_test
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import "." should not work.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ import "."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x_test
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
}
func TestGoGetInsecure(t *testing.T) {
@@ -2365,7 +2949,7 @@ func TestGoGetInsecure(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.failSSH()
- const repo = "wh3rd.net/git.git"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
// Try go get -d of HTTP-only repo (should fail).
tg.runFail("get", "-d", repo)
@@ -2409,27 +2993,11 @@ func TestGoGetInsecureCustomDomain(t *testing.T) {
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- const repo = "wh3rd.net/repo"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
tg.runFail("get", "-d", repo)
tg.run("get", "-d", "-insecure", repo)
}
-func TestIssue10193(t *testing.T) {
- t.Skip("depends on code.google.com")
- testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("hg"); err != nil {
- t.Skip("skipping because hg binary not found")
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempDir("src")
- tg.setenv("GOPATH", tg.path("."))
- tg.runFail("get", "code.google.com/p/rsc/pdf")
- tg.grepStderr("is shutting down", "missed warning about code.google.com")
-}
-
func TestGoRunDirs(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -2442,6 +3010,7 @@ func TestGoRunDirs(t *testing.T) {
func TestGoInstallPkgdir(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
pkg := tg.path(".")
@@ -2480,6 +3049,27 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
}
}
+func TestGoTestRaceFailures(t *testing.T) {
+ if !canRace {
+ t.Skip("skipping because race detector not supported")
+ }
+
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+
+ tg.run("test", "testrace")
+
+ tg.runFail("test", "-race", "testrace")
+ tg.grepStdout("FAIL: TestRace", "TestRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+
+ tg.runFail("test", "-race", "testrace", "-run", "XXX", "-bench", ".")
+ tg.grepStdout("FAIL: BenchmarkRace", "BenchmarkRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+}
+
func TestGoTestImportErrorStack(t *testing.T) {
const out = `package testdep/p1 (test)
imports testdep/p2
@@ -2744,6 +3334,7 @@ func TestIssue13655(t *testing.T) {
// For issue 14337.
func TestParallelTest(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
const testSrc = `package package_test
@@ -2759,3 +3350,426 @@ func TestParallelTest(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
}
+
+func TestCgoConsistentResults(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+ switch runtime.GOOS {
+ case "freebsd":
+ testenv.SkipFlaky(t, 15405)
+ case "solaris":
+ testenv.SkipFlaky(t, 13247)
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ exe1 := tg.path("cgotest1" + exeSuffix)
+ exe2 := tg.path("cgotest2" + exeSuffix)
+ tg.run("build", "-o", exe1, "cgotest")
+ tg.run("build", "-x", "-o", exe2, "cgotest")
+ b1, err := ioutil.ReadFile(exe1)
+ tg.must(err)
+ b2, err := ioutil.ReadFile(exe2)
+ tg.must(err)
+
+ if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) {
+ t.Skip("skipping because C compiler does not support -fdebug-prefix-map")
+ }
+ if !bytes.Equal(b1, b2) {
+ t.Error("building cgotest twice did not produce the same output")
+ }
+}
+
+// Issue 14444: go get -u .../ duplicate loads errors
+func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "-u", ".../")
+ tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
+}
+
+// Issue 17119 more duplicate load errors
+func TestIssue17119(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "dupload")
+ tg.grepBothNot("duplicate load|internal error", "internal error")
+}
+
+func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.runFail("test", "-run", "^$", "-bench", ".", "./testdata/src/benchfatal")
+ tg.grepBothNot("^ok", "test passed unexpectedly")
+ tg.grepBoth("FAIL.*benchfatal", "test did not run everything")
+}
+
+func TestBinaryOnlyPackages(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+
+ tg.tempFile("src/p1/p1.go", `//go:binary-only-package
+
+ package p1
+ `)
+ tg.wantStale("p1", "cannot access install target", "p1 is binary-only but has no binary, should be stale")
+ tg.runFail("install", "p1")
+ tg.grepStderr("missing or invalid package binary", "did not report attempt to compile binary-only package")
+
+ tg.tempFile("src/p1/p1.go", `
+ package p1
+ import "fmt"
+ func F(b bool) { fmt.Printf("hello from p1\n"); if b { F(false) } }
+ `)
+ tg.run("install", "p1")
+ os.Remove(tg.path("src/p1/p1.go"))
+ tg.mustNotExist(tg.path("src/p1/p1.go"))
+
+ tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great
+
+ package p2
+ import "p1"
+ func F() { p1.F(true) }
+ `)
+ tg.runFail("install", "p2")
+ 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()
+ `)
+ tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (first)")
+ tg.run("install", "-x", "p1") // no-op, up to date
+ tg.grepBothNot("/compile", "should not have run compiler")
+ tg.run("install", "p2") // does not rebuild p1 (or else p2 will fail)
+ tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
+
+ // changes to the non-source-code do not matter,
+ // and only one file needs the special comment.
+ tg.tempFile("src/p1/missing2.go", `
+ package p1
+ func H()
+ `)
+ tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (second)")
+ tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
+
+ tg.tempFile("src/p3/p3.go", `
+ package main
+ import (
+ "p1"
+ "p2"
+ )
+ func main() {
+ p1.F(false)
+ p2.F()
+ }
+ `)
+ tg.run("install", "p3")
+
+ tg.run("run", tg.path("src/p3/p3.go"))
+ tg.grepStdout("hello from p1", "did not see message from p1")
+
+ tg.tempFile("src/p4/p4.go", `package main`)
+ tg.tempFile("src/p4/p4not.go", `//go:binary-only-package
+
+ // +build asdf
+
+ package main
+ `)
+ tg.run("list", "-f", "{{.BinaryOnly}}", "p4")
+ tg.grepStdout("false", "did not see BinaryOnly=false for p4")
+}
+
+// Issue 16050.
+func TestAlwaysLinkSysoFiles(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempDir("src/syso")
+ tg.tempFile("src/syso/a.syso", ``)
+ tg.tempFile("src/syso/b.go", `package syso`)
+ tg.setenv("GOPATH", tg.path("."))
+
+ // We should see the .syso file regardless of the setting of
+ // CGO_ENABLED.
+
+ tg.setenv("CGO_ENABLED", "1")
+ tg.run("list", "-f", "{{.SysoFiles}}", "syso")
+ tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")
+
+ tg.setenv("CGO_ENABLED", "0")
+ tg.run("list", "-f", "{{.SysoFiles}}", "syso")
+ tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
+}
+
+// Issue 16120.
+func TestGenerateUsesBuildContext(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("this test won't run under Windows")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempDir("src/gen")
+ tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")
+ tg.setenv("GOPATH", tg.path("."))
+
+ tg.setenv("GOOS", "linux")
+ tg.setenv("GOARCH", "amd64")
+ tg.run("generate", "gen")
+ tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")
+
+ tg.setenv("GOOS", "darwin")
+ tg.setenv("GOARCH", "386")
+ tg.run("generate", "gen")
+ tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
+}
+
+// Issue 14450: go get -u .../ tried to import not downloaded package
+func TestGoGetUpdateWithWildcard(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ const aPkgImportPath = "github.com/tmwh/go-get-issue-14450/a"
+ tg.run("get", aPkgImportPath)
+ tg.run("get", "-u", ".../")
+ tg.grepStderrNot("cannot find package", "did not update packages given wildcard path")
+
+ var expectedPkgPaths = []string{
+ "src/github.com/tmwh/go-get-issue-14450/b",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/c",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/d",
+ }
+
+ for _, importPath := range expectedPkgPaths {
+ _, err := os.Stat(tg.path(importPath))
+ tg.must(err)
+ }
+ const notExpectedPkgPath = "src/github.com/tmwh/go-get-issue-14450-c-dependency/e"
+ tg.mustNotExist(tg.path(notExpectedPkgPath))
+}
+
+func TestGoEnv(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOARCH", "arm")
+ tg.run("env", "GOARCH")
+ tg.grepStdout("^arm$", "GOARCH not honored")
+
+ tg.run("env", "GCCGO")
+ tg.grepStdout(".", "GCCGO unexpectedly empty")
+
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")
+
+ tg.setenv("CGO_CFLAGS", "-foobar")
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")
+
+ tg.setenv("CC", "gcc -fmust -fgo -ffaster")
+ tg.run("env", "CC")
+ tg.grepStdout("gcc", "CC not found")
+ tg.run("env", "GOGCCFLAGS")
+ tg.grepStdout("-ffaster", "CC arguments not found")
+}
+
+const (
+ noMatchesPattern = `(?m)^ok.*\[no tests to run\]`
+ okPattern = `(?m)^ok`
+)
+
+func TestMatchesNoTests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoTestsDoesNotOverrideBuildFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "-run", "ThisWillNotMatch", "syntaxerror")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesNoBenchmarksIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", "ThisWillNotMatch", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyExampleIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Example", "testdata/example1_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyTestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Test", "testdata/standalone_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoTestsWithSubtests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsMatch(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsDoesNotOverrideFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.runFail("test", "-run", "TestThatFails/ThisWillNotMatch", "testdata/standalone_fail_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesOnlySubtestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub", "testdata/standalone_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoSubtestsParallel(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/ThisWillNotMatch", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/Nested", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+// Issue 18845
+func TestBenchTimeout(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
+}
+
+func TestLinkXImportPathEscape(t *testing.T) {
+ // golang.org/issue/16710
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ exe := "./linkx" + exeSuffix
+ tg.creatingTemp(exe)
+ tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked", "my.pkg/main")
+ out, err := exec.Command(exe).CombinedOutput()
+ if err != nil {
+ tg.t.Fatal(err)
+ }
+ if string(out) != "linkXworked\n" {
+ tg.t.Log(string(out))
+ tg.t.Fatal(`incorrect output: expected "linkXworked\n"`)
+ }
+}
+
+// Issue 18044.
+func TestLdBindNow(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("LD_BIND_NOW", "1")
+ tg.run("help")
+}
+
+// Issue 18225.
+// This is really a cmd/asm issue but this is a convenient place to test it.
+func TestConcurrentAsm(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ asm := `DATA ·constants<>+0x0(SB)/8,$0
+GLOBL ·constants<>(SB),8,$8
+`
+ tg.tempFile("go/src/p/a.s", asm)
+ tg.tempFile("go/src/p/b.s", asm)
+ tg.tempFile("go/src/p/p.go", `package p`)
+ tg.setenv("GOPATH", tg.path("go"))
+ tg.run("build", "p")
+}
+
+// Issue 18778.
+func TestDotDotDotOutsideGOPATH(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempFile("pkgs/a.go", `package x`)
+ tg.tempFile("pkgs/a_test.go", `package x_test
+import "testing"
+func TestX(t *testing.T) {}`)
+
+ tg.tempFile("pkgs/a/a.go", `package a`)
+ tg.tempFile("pkgs/a/a_test.go", `package a_test
+import "testing"
+func TestA(t *testing.T) {}`)
+
+ tg.cd(tg.path("pkgs"))
+ tg.run("build", "./...")
+ tg.run("test", "./...")
+ tg.run("list", "./...")
+ tg.grepStdout("pkgs$", "expected package not listed")
+ tg.grepStdout("pkgs/a", "expected package not listed")
+}
diff --git a/libgo/go/cmd/go/go_unix_test.go b/libgo/go/cmd/go/go_unix_test.go
index 0d85859e7e..c445a2ec73 100644
--- a/libgo/go/cmd/go/go_unix_test.go
+++ b/libgo/go/cmd/go/go_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/cmd/go/go_windows_test.go b/libgo/go/cmd/go/go_windows_test.go
index 53d695cccc..d8d04aaf49 100644
--- a/libgo/go/cmd/go/go_windows_test.go
+++ b/libgo/go/cmd/go/go_windows_test.go
@@ -5,6 +5,7 @@
package main
import (
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -45,7 +46,7 @@ func TestAbsolutePath(t *testing.T) {
noVolume := file[len(filepath.VolumeName(file)):]
wrongPath := filepath.Join(dir, noVolume)
- output, err := exec.Command("go", "build", noVolume).CombinedOutput()
+ output, err := exec.Command(testenv.GoToolPath(t), "build", noVolume).CombinedOutput()
if err == nil {
t.Fatal("build should fail")
}
diff --git a/libgo/go/cmd/go/help.go b/libgo/go/cmd/go/help.go
index d8e7efedb3..0c663ad463 100644
--- a/libgo/go/cmd/go/help.go
+++ b/libgo/go/cmd/go/help.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -42,7 +42,7 @@ denotes the package in that directory.
Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
+environment variable (For more details see: 'go help gopath').
If no import paths are given, the action applies to the
package in the current directory.
@@ -62,6 +62,9 @@ Go library.
- "cmd" expands to the Go repository's commands and their
internal libraries.
+Import paths beginning with "cmd/" only match source code in
+the Go repository.
+
An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
@@ -102,10 +105,10 @@ var helpImportPath = &Command{
Short: "import path syntax",
Long: `
-An import path (see 'go help packages') denotes a package
-stored in the local file system. In general, an import path denotes
-either a standard package (such as "unicode/utf8") or a package
-found in one of the work spaces (see 'go help gopath').
+An import path (see 'go help packages') denotes a package stored in the local
+file system. In general, an import path denotes either a standard package (such
+as "unicode/utf8") or a package found in one of the work spaces (For more
+details see: 'go help gopath').
Relative import paths
@@ -149,14 +152,6 @@ A few common code hosting sites have special syntax:
import "github.com/user/project"
import "github.com/user/project/sub/directory"
- Google Code Project Hosting (Git, Mercurial, Subversion)
-
- import "code.google.com/p/project"
- import "code.google.com/p/project/sub/directory"
-
- import "code.google.com/p/project.subrepository"
- import "code.google.com/p/project.subrepository/sub/directory"
-
Launchpad (Bazaar)
import "launchpad.net/project"
@@ -205,6 +200,11 @@ When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries https://, then git+ssh://.
+By default, downloads are restricted to known secure protocols
+(e.g. https, ssh). To override this setting for Git downloads, the
+GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
+'go help environment').
+
If the import path is not a known code hosting site and also lacks a
version control qualifier, the go tool attempts to fetch the import
over https/http and looks for a <meta> tag in the document's HTML
@@ -245,8 +245,8 @@ the go tool will verify that https://example.org/?go-get=1 contains the
same meta tag and then git clone https://code.org/r/p/exproj into
GOPATH/src/example.org.
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
+New downloaded packages are written to the first directory listed in the GOPATH
+environment variable (For more details see: 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
@@ -269,10 +269,9 @@ unless it is being referred to by that import path. In this way, import comments
let package authors make sure the custom import path is used and not a
direct path to the underlying code hosting site.
-If vendoring is enabled (see 'go help gopath'), then import path checking is
-disabled for code found within vendor trees. This makes it possible to copy
-code into alternate locations in vendor trees without needing to update import
-comments.
+Import path checking is disabled for code found within vendor trees.
+This makes it possible to copy code into alternate locations in vendor trees
+without needing to update import comments.
See https://golang.org/s/go14customimport for details.
`,
@@ -290,8 +289,13 @@ On Unix, the value is a colon-separated string.
On Windows, the value is a semicolon-separated string.
On Plan 9, the value is a list.
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
+If the environment variable is unset, GOPATH defaults
+to a subdirectory named "go" in the user's home directory
+($HOME/go on Unix, %USERPROFILE%\go on Windows),
+unless that directory holds a Go distribution.
+Run "go env GOPATH" to see the current GOPATH.
+
+See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
Each directory listed in GOPATH must have a prescribed structure:
@@ -319,9 +323,9 @@ of DIR/bin. GOBIN must be an absolute path.
Here's an example directory layout:
- GOPATH=/home/user/gocode
+ GOPATH=/home/user/go
- /home/user/gocode/
+ /home/user/go/
src/
foo/
bar/ (go code in package bar)
@@ -347,7 +351,7 @@ Code in or below a directory named "internal" is importable only
by code in the directory tree rooted at the parent of "internal".
Here's an extended version of the directory layout above:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -385,7 +389,7 @@ Here's the example from the previous section,
but with the "internal" directory renamed to "vendor"
and a new foo/vendor/crash/bang directory added:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -421,12 +425,6 @@ Vendor directories do not affect the placement of new repositories
being checked out for the first time by 'go get': those are always
placed in the main GOPATH, never in a vendor subtree.
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
See https://golang.org/s/go15vendor for details.
`,
}
@@ -454,7 +452,7 @@ General-purpose environment variables:
The operating system for which to compile code.
Examples are linux, darwin, windows, netbsd.
GOPATH
- See 'go help gopath'.
+ For more details see: 'go help gopath'.
GORACE
Options for the race detector.
See https://golang.org/doc/articles/race_detector.html.
@@ -476,10 +474,15 @@ Environment variables for use with cgo:
CGO_CXXFLAGS
Flags that cgo will pass to the compiler when compiling
C++ code.
+ CGO_FFLAGS
+ Flags that cgo will pass to the compiler when compiling
+ Fortran code.
CGO_LDFLAGS
Flags that cgo will pass to the compiler when linking.
CXX
The command to use to compile C++ code.
+ PKG_CONFIG
+ Path to pkg-config tool.
Architecture-specific environment variables:
@@ -497,12 +500,14 @@ Special-purpose environment variables:
installed in a location other than where it is built.
File names in stack traces are rewritten from GOROOT to
GOROOT_FINAL.
- GO15VENDOREXPERIMENT
- Set to 0 to disable vendoring semantics.
GO_EXTLINK_ENABLED
Whether the linker should use external linking mode
when using -linkmode=auto with code that uses cgo.
Set to 0 to disable external linking mode, 1 to enable it.
+ GIT_ALLOW_PROTOCOL
+ Defined by Git. A colon-separated list of schemes that are allowed to be used
+ with git fetch/clone. If set, any scheme not explicitly mentioned will be
+ considered insecure by 'go get'.
`,
}
@@ -540,7 +545,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.
`,
}
@@ -586,5 +599,9 @@ are:
Build the listed main packages and everything they import into
position independent executables (PIE). Packages not named
main are ignored.
+
+ -buildmode=plugin
+ Build the listed main packages, plus all packages that they
+ import, into a Go plugin. Packages not named main are ignored.
`,
}
diff --git a/libgo/go/cmd/go/http.go b/libgo/go/cmd/go/http.go
index 3a6f19db84..dcb4e9fea5 100644
--- a/libgo/go/cmd/go/http.go
+++ b/libgo/go/cmd/go/http.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -12,6 +12,7 @@
package main
import (
+ "cmd/internal/browser"
"crypto/tls"
"fmt"
"io"
@@ -30,8 +31,9 @@ var httpClient = http.DefaultClient
// when we're connecting to https servers that might not be there
// or might be using self-signed certificates.
var impatientInsecureHTTPClient = &http.Client{
- Timeout: time.Duration(5 * time.Second),
+ Timeout: 5 * time.Second,
Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
@@ -113,3 +115,6 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
return urlStr, res.Body, nil
}
+
+func queryEscape(s string) string { return url.QueryEscape(s) }
+func openBrowser(url string) bool { return browser.Open(url) }
diff --git a/libgo/go/cmd/go/list.go b/libgo/go/cmd/go/list.go
index 8f741a636b..2f240834b2 100644
--- a/libgo/go/cmd/go/list.go
+++ b/libgo/go/cmd/go/list.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -41,7 +41,10 @@ syntax of package template. The default output is equivalent to -f
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
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)
@@ -51,33 +54,40 @@ syntax of package template. The default output is equivalent to -f
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
+ FFiles []string // .f, .F, .for and .f90 Fortran source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
+ TestGoFiles []string // _test.go files in package
+ XTestGoFiles []string // _test.go files outside package
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
+ CgoFFLAGS []string // cgo: flags for Fortran compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
- Imports []string // import paths used by this package
- Deps []string // all (recursively) imported dependencies
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+ TestImports []string // imports from TestGoFiles
+ XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
-
- TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
- XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
}
+Packages stored in vendor directories report an ImportPath that includes the
+path to the vendor directory (for example, "d/vendor/p" instead of "p"),
+so that the ImportPath uniquely identifies a given copy of a package.
+The Imports, Deps, TestImports, and XTestImports lists also contain these
+expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+
The error information, if any, is
type PackageError struct {
diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go
index f9b979da7f..d80ff2da5f 100644
--- a/libgo/go/cmd/go/main.go
+++ b/libgo/go/cmd/go/main.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -79,6 +79,7 @@ var commands = []*Command{
cmdClean,
cmdDoc,
cmdEnv,
+ cmdBug,
cmdFix,
cmdFmt,
cmdGenerate,
@@ -114,6 +115,7 @@ func setExitStatus(n int) {
}
var origEnv []string
+var newEnv []envVar
func main() {
_ = go11tag
@@ -134,7 +136,7 @@ func main() {
// Diagnose common mistake: GOPATH==GOROOT.
// This setting is equivalent to not setting GOPATH at all,
// which is not what most people want when they do it.
- if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
@@ -146,7 +148,7 @@ func main() {
os.Exit(2)
}
if !filepath.IsAbs(p) {
- fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
+ fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
os.Exit(2)
}
}
@@ -163,7 +165,8 @@ func main() {
// but in practice there might be skew
// This makes sure we all agree.
origEnv = os.Environ()
- for _, env := range mkEnv() {
+ newEnv = mkEnv()
+ for _, env := range newEnv {
if os.Getenv(env.name) != env.value {
os.Setenv(env.name, env.value)
}
@@ -214,15 +217,7 @@ var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
-var documentationTemplate = `// 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.
-
-// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
-// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
-
-/*
-{{range .}}{{if .Short}}{{.Short | capitalize}}
+var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
@@ -231,9 +226,39 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reser
{{end}}{{.Long | trim}}
-{{end}}*/
-package main
-`
+{{end}}`
+
+// commentWriter writes a Go comment to the underlying io.Writer,
+// using line comment form (//).
+type commentWriter struct {
+ W io.Writer
+ wroteSlashes bool // Wrote "//" at the beginning of the current line.
+}
+
+func (c *commentWriter) Write(p []byte) (int, error) {
+ var n int
+ for i, b := range p {
+ if !c.wroteSlashes {
+ s := "//"
+ if b != '\n' {
+ s = "// "
+ }
+ if _, err := io.WriteString(c.W, s); err != nil {
+ return n, err
+ }
+ c.wroteSlashes = true
+ }
+ n0, err := c.W.Write(p[i : i+1])
+ n += n0
+ if err != nil {
+ return n, err
+ }
+ if b == '\n' {
+ c.wroteSlashes = false
+ }
+ }
+ return len(p), nil
+}
// An errWriter wraps a writer, recording whether a write error occurred.
type errWriter struct {
@@ -310,10 +335,18 @@ func help(args []string) {
// 'go help documentation' generates doc.go.
if arg == "documentation" {
+ fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
+ fmt.Println("// Use of this source code is governed by a BSD-style")
+ fmt.Println("// license that can be found in the LICENSE file.")
+ fmt.Println()
+ fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
+ fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
+ fmt.Println()
buf := new(bytes.Buffer)
printUsage(buf)
usage := &Command{Long: buf.String()}
- tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
+ tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
+ fmt.Println("package main")
return
}
@@ -339,7 +372,7 @@ func importPathsNoDotExpansion(args []string) []string {
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
- // in command-line arguments. Handles .\... and so on.
+ // in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
@@ -403,8 +436,6 @@ func errorf(format string, args ...interface{}) {
setExitStatus(1)
}
-var logf = log.Printf
-
func exitIfErrors() {
if exitStatus != 0 {
exit()
@@ -428,19 +459,6 @@ func run(cmdargs ...interface{}) {
}
}
-func runOut(dir string, cmdargs ...interface{}) []byte {
- cmdline := stringList(cmdargs...)
- cmd := exec.Command(cmdline[0], cmdline[1:]...)
- cmd.Dir = dir
- out, err := cmd.CombinedOutput()
- if err != nil {
- os.Stderr.Write(out)
- errorf("%v", err)
- out = nil
- }
- return out
-}
-
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
@@ -472,7 +490,7 @@ NextVar:
}
// matchPattern(pattern)(name) reports whether
-// name matches pattern. Pattern is a limited glob
+// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
@@ -629,7 +647,7 @@ func matchPackages(pattern string) []string {
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
-// at the given directory. There are ... in the pattern too.
+// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
diff --git a/libgo/go/cmd/go/match_test.go b/libgo/go/cmd/go/match_test.go
index 38b9b115e7..e0ad562384 100644
--- a/libgo/go/cmd/go/match_test.go
+++ b/libgo/go/cmd/go/match_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/note.go b/libgo/go/cmd/go/note.go
index f846eeb62b..fae9536d13 100644
--- a/libgo/go/cmd/go/note.go
+++ b/libgo/go/cmd/go/note.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -71,7 +71,7 @@ func readELFNote(filename, name string, typ int32) ([]byte, error) {
var elfGoNote = []byte("Go\x00\x00")
// The Go build ID is stored in a note described by an ELF PT_NOTE prog
-// header. The caller has already opened filename, to get f, and read
+// header. The caller has already opened filename, to get f, and read
// at least 4 kB out, in data.
func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
// Assume the note content is in the data, already read.
@@ -110,7 +110,7 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string,
// or even the first few megabytes of the file
// due to differences in note segment placement;
// in that case, extract the note data manually.
- _, err = f.Seek(int64(p.Off), 0)
+ _, err = f.Seek(int64(p.Off), io.SeekStart)
if err != nil {
return "", err
}
diff --git a/libgo/go/cmd/go/note_test.go b/libgo/go/cmd/go/note_test.go
index 811734b377..2ee013faf3 100644
--- a/libgo/go/cmd/go/note_test.go
+++ b/libgo/go/cmd/go/note_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -47,8 +47,6 @@ func testNoteReading(t *testing.T) {
t.Skipf("skipping - no cgo, so assuming external linking not available")
case runtime.GOOS == "linux" && (runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"):
t.Skipf("skipping - external linking not supported, golang.org/issue/11184")
- case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64le" || runtime.GOARCH == "mips64"):
- t.Skipf("skipping - external linking not supported, golang.org/issue/12560")
case runtime.GOOS == "openbsd" && runtime.GOARCH == "arm":
t.Skipf("skipping - external linking not supported, golang.org/issue/10619")
case runtime.GOOS == "plan9":
diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go
index 373dade962..f0dc95670f 100644
--- a/libgo/go/cmd/go/pkg.go
+++ b/libgo/go/cmd/go/pkg.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -24,11 +24,13 @@ import (
"unicode"
)
+var ignoreImports bool // control whether we ignore imports in packages
+
// A Package describes a single package found in a directory.
type Package struct {
// Note: These fields are part of the go command's public API.
- // See list.go. It is okay to add fields, but not to change or
- // remove existing ones. Keep in sync with list.go
+ // See list.go. It is okay to add fields, but not to change or
+ // remove existing ones. Keep in sync with list.go
Dir string `json:",omitempty"` // directory containing package sources
ImportPath string `json:",omitempty"` // import path of package in dir
ImportComment string `json:",omitempty"` // path in import comment on package statement
@@ -39,8 +41,10 @@ type Package struct {
Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
+ StaleReason string `json:",omitempty"` // why is Stale true?
Root string `json:",omitempty"` // Go root or Go path dir containing this package
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
+ BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
// Source files
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -50,6 +54,7 @@ type Package struct {
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
MFiles []string `json:",omitempty"` // .m source files
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+ FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
SFiles []string `json:",omitempty"` // .s source files
SwigFiles []string `json:",omitempty"` // .swig files
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
@@ -59,6 +64,7 @@ type Package struct {
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
+ CgoFFLAGS []string `json:",omitempty"` // cgo: flags for Fortran compiler
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
@@ -88,7 +94,6 @@ type Package struct {
target string // installed file for this package (may be executable)
fake bool // synthesized package
external bool // synthesized external test package
- forceBuild bool // this package must be rebuilt
forceLibrary bool // this package is a library (even if named "main")
cmdline bool // defined by files listed on command line
local bool // imported via local path (./ or ../)
@@ -151,6 +156,8 @@ func (p *Package) copyBuild(pp *build.Package) {
p.Doc = pp.Doc
p.Root = pp.Root
p.ConflictDir = pp.ConflictDir
+ p.BinaryOnly = pp.BinaryOnly
+
// TODO? Target
p.Goroot = pp.Goroot
if buildContext.Compiler == "gccgo" {
@@ -165,6 +172,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.CXXFiles = pp.CXXFiles
p.MFiles = pp.MFiles
p.HFiles = pp.HFiles
+ p.FFiles = pp.FFiles
p.SFiles = pp.SFiles
p.SwigFiles = pp.SwigFiles
p.SwigCXXFiles = pp.SwigCXXFiles
@@ -174,11 +182,18 @@ func (p *Package) copyBuild(pp *build.Package) {
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
- p.Imports = pp.Imports
+ // We modify p.Imports in place, so make copy now.
+ p.Imports = make([]string, len(pp.Imports))
+ copy(p.Imports, pp.Imports)
p.TestGoFiles = pp.TestGoFiles
p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports
+ if ignoreImports {
+ p.Imports = nil
+ p.TestImports = nil
+ p.XTestImports = nil
+ }
}
// isStandardImportPath reports whether $GOROOT/src/path should be considered
@@ -209,7 +224,7 @@ func (p *PackageError) Error() string {
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
}
if p.Pos != "" {
- // Omit import stack. The full path to the file where the error
+ // Omit import stack. The full path to the file where the error
// is the most important thing.
return p.Pos + ": " + p.Err
}
@@ -267,18 +282,9 @@ func reloadPackage(arg string, stk *importStack) *Package {
return loadPackage(arg, stk)
}
-// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1.
-// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0.
-// In Go 1.7 the variable will stop having any effect.
-// The variable is obnoxiously long so that years from now when people find it in
-// their profiles and wonder what it does, there is some chance that a web search
-// might answer the question.
-// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0"
-
// dirToImportPath returns the pseudo-import path we use for a package
-// outside the Go path. It begins with _/ and then contains the full path
-// to the directory. If the package lives in c:\home\gopher\my\pkg then
+// outside the Go path. It begins with _/ and then contains the full path
+// to the directory. If the package lives in c:\home\gopher\my\pkg then
// the pseudo-import path is _/c_/home/gopher/my/pkg.
// Using a pseudo-import path like this makes the ./ imports no longer
// a special case, so that all the code to deal with ordinary imports works
@@ -341,62 +347,98 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
importPath = path
}
- if p := packageCache[importPath]; p != nil {
- if perr := disallowInternal(srcDir, p, stk); perr != p {
- return perr
+ p := packageCache[importPath]
+ if p != nil {
+ p = reusePackage(p, stk)
+ } else {
+ p = new(Package)
+ p.local = isLocal
+ p.ImportPath = importPath
+ packageCache[importPath] = p
+
+ // Load package.
+ // Import always returns bp != nil, even if an error occurs,
+ // in order to return partial information.
+ //
+ // TODO: After Go 1, decide when to pass build.AllowBinary here.
+ // See issue 3268 for mistakes to avoid.
+ buildMode := build.ImportComment
+ if mode&useVendor == 0 || path != origPath {
+ // Not vendoring, or we already found the vendored path.
+ buildMode |= build.IgnoreVendor
}
- if mode&useVendor != 0 {
- if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
- }
+ bp, err := buildContext.Import(path, srcDir, buildMode)
+ bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+ !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
+ err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
+ }
+ p.load(stk, bp, err)
+ if p.Error != nil && p.Error.Pos == "" {
+ p = setErrorPos(p, importPos)
}
- return reusePackage(p, stk)
- }
-
- p := new(Package)
- p.local = isLocal
- p.ImportPath = importPath
- packageCache[importPath] = p
- // Load package.
- // Import always returns bp != nil, even if an error occurs,
- // in order to return partial information.
- //
- // TODO: After Go 1, decide when to pass build.AllowBinary here.
- // See issue 3268 for mistakes to avoid.
- buildMode := build.ImportComment
- if !go15VendorExperiment || mode&useVendor == 0 || path != origPath {
- // Not vendoring, or we already found the vendored path.
- buildMode |= build.IgnoreVendor
- }
- bp, err := buildContext.Import(path, srcDir, buildMode)
- bp.ImportPath = importPath
- if gobin != "" {
- bp.BinDir = gobin
- }
- if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
- (!go15VendorExperiment || (!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/"))) {
- err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
- }
- p.load(stk, bp, err)
- if p.Error != nil && p.Error.Pos == "" && len(importPos) > 0 {
- pos := importPos[0]
- pos.Filename = shortPath(pos.Filename)
- p.Error.Pos = pos.String()
+ if origPath != cleanImport(origPath) {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
+ }
+ p.Incomplete = true
+ }
}
+ // Checked on every import because the rules depend on the code doing the importing.
if perr := disallowInternal(srcDir, p, stk); perr != p {
- return perr
+ return setErrorPos(perr, importPos)
}
if mode&useVendor != 0 {
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
+ return setErrorPos(perr, importPos)
}
}
+ if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("import %q is a program, not an importable package", path),
+ }
+ return setErrorPos(&perr, importPos)
+ }
+
+ if p.local && parent != nil && !parent.local {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("local import %q in non-local package", path),
+ }
+ return setErrorPos(&perr, importPos)
+ }
+
+ return p
+}
+
+func setErrorPos(p *Package, importPos []token.Position) *Package {
+ if len(importPos) > 0 {
+ pos := importPos[0]
+ pos.Filename = shortPath(pos.Filename)
+ p.Error.Pos = pos.String()
+ }
return p
}
+func cleanImport(path string) string {
+ orig := path
+ path = pathpkg.Clean(path)
+ if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
+ path = "./" + path
+ }
+ return path
+}
+
var isDirCache = map[string]bool{}
func isDir(path string) bool {
@@ -416,19 +458,32 @@ func isDir(path string) bool {
// x/vendor/path, vendor/path, or else stay path if none of those exist.
// vendoredImportPath returns the expanded path or, if no expansion is found, the original.
func vendoredImportPath(parent *Package, path string) (found string) {
- if parent == nil || parent.Root == "" || !go15VendorExperiment {
+ if parent == nil || parent.Root == "" {
return path
}
dir := filepath.Clean(parent.Dir)
root := filepath.Join(parent.Root, "src")
- if !hasFilePathPrefix(dir, root) {
+ if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
// Look for symlinks before reporting error.
dir = expandPath(dir)
root = expandPath(root)
}
- if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {
- fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
+
+ if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.local && filepath.Join(root, parent.ImportPath) != dir {
+ fatalf("unexpected directory layout:\n"+
+ " import path: %s\n"+
+ " root: %s\n"+
+ " dir: %s\n"+
+ " expand root: %s\n"+
+ " expand dir: %s\n"+
+ " separator: %s",
+ parent.ImportPath,
+ filepath.Join(parent.Root, "src"),
+ filepath.Clean(parent.Dir),
+ root,
+ dir,
+ string(filepath.Separator))
}
vpath := "vendor/" + path
@@ -445,6 +500,12 @@ func vendoredImportPath(parent *Package, path string) (found string) {
}
targ := filepath.Join(dir[:i], vpath)
if isDir(targ) && hasGoFiles(targ) {
+ importPath := parent.ImportPath
+ if importPath == "command-line-arguments" {
+ // If parent.ImportPath is 'command-line-arguments'.
+ // set to relative directory to root (also chopped root directory)
+ importPath = dir[len(root)+1:]
+ }
// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
// We know the import path for parent's dir.
// We chopped off some number of path elements and
@@ -454,14 +515,14 @@ func vendoredImportPath(parent *Package, path string) (found string) {
// (actually the same number of bytes) from parent's import path
// and then append /vendor/path.
chopped := len(dir) - i
- if chopped == len(parent.ImportPath)+1 {
+ if chopped == len(importPath)+1 {
// We walked up from c:\gopath\src\foo\bar
// and found c:\gopath\src\vendor\path.
// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
// Use "vendor/path" without any prefix.
return vpath
}
- return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath
+ return importPath[:len(importPath)-chopped] + "/" + vpath
}
}
return path
@@ -482,7 +543,7 @@ func hasGoFiles(dir string) bool {
}
// reusePackage reuses package p to satisfy the import at the top
-// of the import stack stk. If this use causes an import loop,
+// of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop.
func reusePackage(p *Package, stk *importStack) *Package {
// We use p.imports==nil to detect a package that
@@ -520,6 +581,19 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
return p
}
+ // The generated 'testmain' package is allowed to access testing/internal/...,
+ // as if it were generated into the testing directory tree
+ // (it's actually in a temporary directory outside any Go tree).
+ // This cleans up a former kludge in passing functionality to the testing package.
+ if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
+ return p
+ }
+
+ // We can't check standard packages with gccgo.
+ if buildContext.Compiler == "gccgo" && p.Standard {
+ return p
+ }
+
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -528,7 +602,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
return p
}
- // Check for "internal" element: four cases depending on begin of string and/or end of string.
+ // Check for "internal" element: three cases depending on begin of string and/or end of string.
i, ok := findInternal(p.ImportPath)
if !ok {
return p
@@ -565,7 +639,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
// If there isn't one, findInternal returns ok=false.
// Otherwise, findInternal returns ok=true and the index of the "internal".
func findInternal(path string) (index int, ok bool) {
- // Four cases, depending on internal at start/end of string or not.
+ // Three cases, depending on internal at start/end of string or not.
// The order matters: we must return the index of the final element,
// because the final one produces the most restrictive requirement
// on the importer.
@@ -584,10 +658,6 @@ func findInternal(path string) (index int, ok bool) {
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
- if !go15VendorExperiment {
- return p
- }
-
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -667,7 +737,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
// findVendor looks for the last non-terminating "vendor" path element in the given import path.
// If there isn't one, findVendor returns ok=false.
-// Otherwise, findInternal returns ok=true and the index of the "vendor".
+// Otherwise, findVendor returns ok=true and the index of the "vendor".
//
// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
// not the vendored copy of an import "" (the empty import path).
@@ -691,31 +761,28 @@ type targetDir int
const (
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
- toBin // GOROOT/bin
stalePath // the old import path; fail to build
)
// goTools is a map of Go program import path to install target directory.
var goTools = map[string]targetDir{
- "cmd/addr2line": toTool,
- "cmd/api": toTool,
- "cmd/asm": toTool,
- "cmd/compile": toTool,
- "cmd/cgo": toTool,
- "cmd/cover": toTool,
- "cmd/dist": toTool,
- "cmd/doc": toTool,
- "cmd/fix": toTool,
- "cmd/link": toTool,
- "cmd/newlink": toTool,
- "cmd/nm": toTool,
- "cmd/objdump": toTool,
- "cmd/pack": toTool,
- "cmd/pprof": toTool,
- "cmd/trace": toTool,
- "cmd/vet": toTool,
- "cmd/yacc": toTool,
- "golang.org/x/tools/cmd/godoc": toBin,
+ "cmd/addr2line": toTool,
+ "cmd/api": toTool,
+ "cmd/asm": toTool,
+ "cmd/compile": toTool,
+ "cmd/cgo": toTool,
+ "cmd/cover": toTool,
+ "cmd/dist": toTool,
+ "cmd/doc": toTool,
+ "cmd/fix": toTool,
+ "cmd/link": toTool,
+ "cmd/newlink": toTool,
+ "cmd/nm": toTool,
+ "cmd/objdump": toTool,
+ "cmd/pack": toTool,
+ "cmd/pprof": toTool,
+ "cmd/trace": toTool,
+ "cmd/vet": toTool,
"code.google.com/p/go.tools/cmd/cover": stalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath,
@@ -729,7 +796,7 @@ func expandScanner(err error) error {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
- // its own line. It will also show all the errors
+ // its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
@@ -766,6 +833,13 @@ var cgoSyscallExclude = map[string]bool{
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
p.copyBuild(bp)
+ // When using gccgo the go/build package will not be able to
+ // find a standard package. It would be nicer to not get that
+ // error, but go/build doesn't know stdpkg.
+ if runtime.Compiler == "gccgo" && err != nil && p.Standard {
+ err = nil
+ }
+
// The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this.
p.localPrefix = dirToImportPath(p.Dir)
@@ -783,7 +857,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
useBindir := p.Name == "main"
if !p.Standard {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
useBindir = false
}
}
@@ -802,12 +876,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
- if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
- // Override BinDir.
- // This is from a subrepo but installs to $GOROOT/bin
- // by default anyway (like godoc).
- p.target = filepath.Join(gorootBin, elem)
- } else if p.build.BinDir != "" {
+ if p.build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.target = filepath.Join(p.build.BinDir, elem)
if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
@@ -863,11 +932,25 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
importPaths = append(importPaths, "syscall")
}
- // Currently build modes c-shared, pie, and -linkshared force
- // external linking mode, and external linking mode forces an
- // import of runtime/cgo.
- if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) {
- importPaths = append(importPaths, "runtime/cgo")
+ if buildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
+ // Currently build modes c-shared, pie (on systems that do not
+ // support PIE with internal linking mode), plugin, and
+ // -linkshared force external linking mode, as of course does
+ // -ldflags=-linkmode=external. External linking mode forces
+ // an import of runtime/cgo.
+ pieCgo := buildBuildmode == "pie" && (buildContext.GOOS != "linux" || buildContext.GOARCH != "amd64")
+ linkmodeExternal := false
+ for i, a := range buildLdflags {
+ if a == "-linkmode=external" {
+ linkmodeExternal = true
+ }
+ if a == "-linkmode" && i+1 < len(buildLdflags) && buildLdflags[i+1] == "external" {
+ linkmodeExternal = true
+ }
+ }
+ if buildBuildmode == "c-shared" || buildBuildmode == "plugin" || pieCgo || buildLinkshared || linkmodeExternal {
+ importPaths = append(importPaths, "runtime/cgo")
+ }
}
// Everything depends on runtime, except runtime, its internal
@@ -930,6 +1013,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
p.CXXFiles,
p.MFiles,
p.HFiles,
+ p.FFiles,
p.SFiles,
p.SysoFiles,
p.SwigFiles,
@@ -948,6 +1032,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]*Package)
+ save := func(path string, p1 *Package) {
+ // The same import path could produce an error or not,
+ // depending on what tries to import it.
+ // Prefer to record entries with errors, so we can report them.
+ p0 := deps[path]
+ if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
+ deps[path] = p1
+ }
+ }
+
for i, path := range importPaths {
if path == "C" {
continue
@@ -956,28 +1050,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if !reqStdPkgSrc && p1.Standard {
continue
}
- if p1.Name == "main" {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("import %q is a program, not an importable package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- if p1.local {
- if !p.local && p.Error == nil {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("local import %q in non-local package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- }
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
@@ -994,15 +1066,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if i < len(p.Imports) {
p.Imports[i] = path
}
- deps[path] = p1
+
+ save(path, p1)
imports = append(imports, p1)
for _, dep := range p1.deps {
- // The same import path could produce an error or not,
- // depending on what tries to import it.
- // Prefer to record entries with errors, so we can report them.
- if deps[dep.ImportPath] == nil || dep.Error != nil {
- deps[dep.ImportPath] = dep
- }
+ save(dep.ImportPath, dep)
}
if p1.Incomplete {
p.Incomplete = true
@@ -1032,6 +1100,20 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
p.Target = p.target
+ // If cgo is not enabled, ignore cgo supporting sources
+ // just as we ignore go files containing import "C".
+ if !buildContext.CgoEnabled {
+ p.CFiles = nil
+ p.CXXFiles = nil
+ p.MFiles = nil
+ p.SwigFiles = nil
+ p.SwigCXXFiles = nil
+ // Note that SFiles are okay (they go to the Go assembler)
+ // and HFiles are okay (they might be used by the SFiles).
+ // Also Sysofiles are okay (they might not contain object
+ // code; see issue #16050).
+ }
+
// The gc toolchain only permits C source files with cgo.
if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" {
p.Error = &PackageError{
@@ -1054,7 +1136,15 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
}
- computeBuildID(p)
+ if p.BinaryOnly {
+ // For binary-only package, use build ID from supplied package binary.
+ buildID, err := readBuildID(p)
+ if err == nil {
+ p.buildID = buildID
+ }
+ } else {
+ computeBuildID(p)
+ }
return p
}
@@ -1094,7 +1184,7 @@ func packageList(roots []*Package) []*Package {
// at the named pkgs (command-line arguments).
func computeStale(pkgs ...*Package) {
for _, p := range packageList(pkgs) {
- p.Stale = isStale(p)
+ p.Stale, p.StaleReason = isStale(p)
}
}
@@ -1240,7 +1330,7 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
// an explicit data comparison. Specifically, we build a list of the
// inputs to the build, compute its SHA1 hash, and record that as the
// ``build ID'' in the generated object. At the next build, we can
-// recompute the buid ID and compare it to the one in the generated
+// recompute the build ID and compare it to the one in the generated
// object. If they differ, the list of inputs has changed, so the object
// is out of date and must be rebuilt.
//
@@ -1365,40 +1455,50 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
// standard library, even in release versions. This makes
// 'go build -tags netgo' work, among other things.
-// isStale reports whether package p needs to be rebuilt.
-func isStale(p *Package) bool {
+// isStale reports whether package p needs to be rebuilt,
+// along with the reason why.
+func isStale(p *Package) (bool, string) {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
// fake, builtin package
- return false
+ return false, "builtin package"
}
if p.Error != nil {
- return true
+ return true, "errors loading package"
+ }
+ if p.Stale {
+ return true, p.StaleReason
}
- // A package without Go sources means we only found
- // the installed .a file. Since we don't know how to rebuild
- // it, it can't be stale, even if -a is set. This enables binary-only
- // distributions of Go packages, although such binaries are
- // only useful with the specific version of the toolchain that
- // created them.
- if len(p.gofiles) == 0 && !p.usesSwig() {
- return false
+ // If this is a package with no source code, it cannot be rebuilt.
+ // If the binary is missing, we mark the package stale so that
+ // if a rebuild is needed, that rebuild attempt will produce a useful error.
+ // (Some commands, such as 'go list', do not attempt to rebuild.)
+ if p.BinaryOnly {
+ if p.target == "" {
+ // Fail if a build is attempted.
+ return true, "no source code for package, but no install target"
+ }
+ if _, err := os.Stat(p.target); err != nil {
+ // Fail if a build is attempted.
+ return true, "no source code for package, but cannot access install target: " + err.Error()
+ }
+ return false, "no source code for package"
}
// If the -a flag is given, rebuild everything.
if buildA {
- return true
+ return true, "build -a flag in use"
}
- // If there's no install target or it's already marked stale, we have to rebuild.
- if p.target == "" || p.Stale {
- return true
+ // If there's no install target, we have to rebuild.
+ if p.target == "" {
+ return true, "no install target"
}
// Package is stale if completely unbuilt.
fi, err := os.Stat(p.target)
if err != nil {
- return true
+ return true, "cannot stat install target"
}
// Package is stale if the expected build ID differs from the
@@ -1411,13 +1511,13 @@ func isStale(p *Package) bool {
// See issue 8290 and issue 10702.
targetBuildID, err := readBuildID(p)
if err == nil && targetBuildID != p.buildID {
- return true
+ return true, "build ID mismatch"
}
// Package is stale if a dependency is.
for _, p1 := range p.deps {
if p1.Stale {
- return true
+ return true, "stale dependency"
}
}
@@ -1440,7 +1540,7 @@ func isStale(p *Package) bool {
// install is to run make.bash, which will remove the old package archives
// before rebuilding.)
if p.Standard && isGoRelease {
- return false
+ return false, "standard package in Go release distribution"
}
// Time-based staleness.
@@ -1455,14 +1555,14 @@ func isStale(p *Package) bool {
// Package is stale if a dependency is, or if a dependency is newer.
for _, p1 := range p.deps {
if p1.target != "" && olderThan(p1.target) {
- return true
+ return true, "newer dependency"
}
}
// As a courtesy to developers installing new versions of the compiler
// frequently, define that packages are stale if they are
// older than the compiler, and commands if they are older than
- // the linker. This heuristic will not work if the binaries are
+ // the linker. This heuristic will not work if the binaries are
// back-dated, as some binary distributions may do, but it does handle
// a very common case.
// See issue 3036.
@@ -1474,10 +1574,10 @@ func isStale(p *Package) bool {
// taken care of above (at least when the installed Go is a released version).
if p.Root != goroot {
if olderThan(buildToolchain.compiler()) {
- return true
+ return true, "newer compiler"
}
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
- return true
+ return true, "newer linker"
}
}
@@ -1519,14 +1619,14 @@ func isStale(p *Package) bool {
// to test for write access, and then skip GOPATH roots we don't have write
// access to. But hopefully we can just use the mtimes always.
- srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
+ srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
- return true
+ return true, "newer source file"
}
}
- return false
+ return false, ""
}
// computeBuildID computes the build ID for p, leaving it in p.buildID.
@@ -1556,7 +1656,7 @@ func computeBuildID(p *Package) {
// Include the content of runtime/internal/sys/zversion.go in the hash
// for package runtime. This will give package runtime a
// different build ID in each Go release.
- if p.Standard && p.ImportPath == "runtime/internal/sys" {
+ if p.Standard && p.ImportPath == "runtime/internal/sys" && buildContext.Compiler != "gccgo" {
data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
if err != nil {
fatalf("go: %s", err)
@@ -1584,7 +1684,7 @@ var cwd, _ = os.Getwd()
var cmdCache = map[string]*Package{}
// loadPackage is like loadImport but is used for command-line arguments,
-// not for paths found in import statements. In addition to ordinary import paths,
+// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *importStack) *Package {
@@ -1648,7 +1748,7 @@ func loadPackage(arg string, stk *importStack) *Package {
// command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist),
// then packages prints an error and does not include that
-// package in the results. However, if errors occur trying
+// package in the results. However, if errors occur trying
// to load dependencies of a named package, the named
// package is still returned, with p.Incomplete = true
// and details in p.DepsErrors.
diff --git a/libgo/go/cmd/go/pkg_test.go b/libgo/go/cmd/go/pkg_test.go
index 1e7ca2c6fe..fba13636cd 100644
--- a/libgo/go/cmd/go/pkg_test.go
+++ b/libgo/go/cmd/go/pkg_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -161,9 +161,12 @@ func TestSharedLibName(t *testing.T) {
}
oldGopath := buildContext.GOPATH
defer func() {
- os.RemoveAll(tmpGopath)
buildContext.GOPATH = oldGopath
os.Chdir(cwd)
+ err := os.RemoveAll(tmpGopath)
+ if err != nil {
+ t.Error(err)
+ }
}()
root := filepath.Join(tmpGopath, "src", data.rootedAt)
err = os.MkdirAll(root, 0755)
diff --git a/libgo/go/cmd/go/run.go b/libgo/go/cmd/go/run.go
index bf10f4f3e9..18387b5eaf 100644
--- a/libgo/go/cmd/go/run.go
+++ b/libgo/go/cmd/go/run.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -128,7 +128,7 @@ func runRun(cmd *Command, args []string) {
}
// runProgram is the action for running a binary that has already
-// been compiled. We ignore exit status.
+// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
diff --git a/libgo/go/cmd/go/tag_test.go b/libgo/go/cmd/go/tag_test.go
index ffe218c7b6..6649bd6195 100644
--- a/libgo/go/cmd/go/tag_test.go
+++ b/libgo/go/cmd/go/tag_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/go/test.go b/libgo/go/cmd/go/test.go
index 1cf5892058..12990feb43 100644
--- a/libgo/go/cmd/go/test.go
+++ b/libgo/go/cmd/go/test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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.
@@ -125,32 +128,18 @@ control the execution of any test:
const testFlag2 = `
-bench regexp
- Run benchmarks matching the regular expression.
+ Run (sub)benchmarks matching a regular expression.
+ The given regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ benchmark's identifier.
By default, no benchmarks run. To run all benchmarks,
use '-bench .' or '-bench=.'.
- -benchmem
- Print memory allocation statistics for benchmarks.
-
-benchtime t
Run enough iterations of each benchmark to take t, specified
as a time.Duration (for example, -benchtime 1h30s).
The default is 1 second (1s).
- -blockprofile block.out
- Write a goroutine blocking profile to the specified file
- when all tests are complete.
- Writes test binary as -c would.
-
- -blockprofilerate n
- Control the detail provided in goroutine blocking profiles by
- calling runtime.SetBlockProfileRate with n.
- See 'go doc runtime.SetBlockProfileRate'.
- The profiler aims to sample, on average, one blocking event every
- n nanoseconds the program spends blocked. By default,
- if -test.blockprofile is set without this flag, all blocking events
- are recorded, equivalent to -test.blockprofilerate=1.
-
-count n
Run each test and benchmark n times (default 1).
If -cpu is set, run n times for each GOMAXPROCS value.
@@ -176,33 +165,11 @@ const testFlag2 = `
Packages are specified as import paths.
Sets -cover.
- -coverprofile cover.out
- Write a coverage profile to the file after all tests have passed.
- Sets -cover.
-
-cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value
of GOMAXPROCS.
- -cpuprofile cpu.out
- Write a CPU profile to the specified file before exiting.
- Writes test binary as -c would.
-
- -memprofile mem.out
- Write a memory profile to the file after all tests have passed.
- Writes test binary as -c would.
-
- -memprofilerate n
- Enable more precise (and expensive) memory profiles by setting
- runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
- To profile all memory allocations, use -test.memprofilerate=1
- and pass --alloc_space flag to the pprof tool.
-
- -outputdir directory
- Place output files from profiling in the specified directory,
- by default the directory in which "go test" is running.
-
-parallel n
Allow parallel execution of test functions that call t.Parallel.
The value of this flag is the maximum number of tests to run
@@ -213,8 +180,10 @@ const testFlag2 = `
(see 'go help build').
-run regexp
- Run only those tests and examples matching the regular
- expression.
+ Run only those tests and examples matching the regular expression.
+ For tests the regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ test's identifier.
-short
Tell long-running tests to shorten their run time.
@@ -226,14 +195,64 @@ const testFlag2 = `
If a test runs longer than t, panic.
The default is 10 minutes (10m).
- -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
text from Log and Logf calls even if the test succeeds.
+The following flags are also recognized by 'go test' and can be used to
+profile the tests during execution:
+
+ -benchmem
+ Print memory allocation statistics for benchmarks.
+
+ -blockprofile block.out
+ Write a goroutine blocking profile to the specified file
+ when all tests are complete.
+ Writes test binary as -c would.
+
+ -blockprofilerate n
+ Control the detail provided in goroutine blocking profiles by
+ calling runtime.SetBlockProfileRate with n.
+ See 'go doc runtime.SetBlockProfileRate'.
+ The profiler aims to sample, on average, one blocking event every
+ n nanoseconds the program spends blocked. By default,
+ if -test.blockprofile is set without this flag, all blocking events
+ are recorded, equivalent to -test.blockprofilerate=1.
+
+ -coverprofile cover.out
+ Write a coverage profile to the file after all tests have passed.
+ Sets -cover.
+
+ -cpuprofile cpu.out
+ Write a CPU profile to the specified file before exiting.
+ Writes test binary as -c would.
+
+ -memprofile mem.out
+ Write a memory profile to the file after all tests have passed.
+ Writes test binary as -c would.
+
+ -memprofilerate n
+ Enable more precise (and expensive) memory profiles by setting
+ runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+ To profile all memory allocations, use -test.memprofilerate=1
+ and pass --alloc_space flag to the pprof tool.
+
+ -mutexprofile mutex.out
+ Write a mutex contention profile to the specified file
+ when all tests are complete.
+ Writes test binary as -c would.
+
+ -mutexprofilefraction n
+ Sample 1 in n stack traces of goroutines holding a
+ contended mutex.
+
+ -outputdir directory
+ Place output files from profiling in the specified directory,
+ by default the directory in which "go test" is running.
+
+ -trace trace.out
+ Write an execution trace to the specified file before exiting.
+
Each of these flags is also recognized with an optional 'test.' prefix,
as in -test.v. When invoking the generated test binary (the result of
'go test -c') directly, however, the prefix is mandatory.
@@ -256,7 +275,7 @@ execution, not to the test itself.)
The test flags that generate profiles (other than for coverage) also
leave the test binary in pkg.test for use when analyzing the profiles.
-When 'go test' runs a test binary, it does so from within the
+When 'go test' runs a test binary, it does so from within the
corresponding package's source code directory. Depending on the test,
it may be necessary to do the same when invoking a generated test
binary directly.
@@ -311,10 +330,12 @@ A benchmark function is one named BenchmarkXXX and should have the signature,
An example function is similar to a test function but, instead of using
*testing.T to report success or failure, prints output to os.Stdout.
-That output is compared against the function's "Output:" comment, which
-must be the last comment in the function body (see example below). An
-example with no such comment, or with no text after "Output:" is compiled
-but not executed.
+If the last comment in the function starts with "Output:" then the output
+is compared exactly against the comment (see examples below). If the last
+comment begins with "Unordered output:" then the output is compared to the
+comment, however the order of the lines is ignored. An example with no such
+comment is compiled but not executed. An example with no text after
+"Output:" is compiled, executed, and expected to produce no output.
Godoc displays the body of ExampleXXX to demonstrate the use
of the function, constant, or variable XXX. An example of a method M with
@@ -330,6 +351,20 @@ Here is an example of an example:
// this example.
}
+Here is another example where the ordering of the output is ignored:
+
+ func ExamplePerm() {
+ for _, value := range Perm(4) {
+ fmt.Println(value)
+ }
+
+ // Unordered output: 4
+ // 2
+ // 1
+ // 3
+ // 0
+ }
+
The entire test file is presented as the example when it contains a single
example function, at least one other function, type, variable, or constant
declaration, and no test or benchmark functions.
@@ -359,9 +394,9 @@ var (
var testMainDeps = map[string]bool{
// Dependencies for testmain.
- "testing": true,
- "regexp": true,
- "os": true,
+ "testing": true,
+ "testing/internal/testdeps": true,
+ "os": true,
}
func runTest(cmd *Command, args []string) {
@@ -388,7 +423,7 @@ func runTest(cmd *Command, args []string) {
}
// If a test timeout was given and is parseable, set our kill timeout
- // to that timeout plus one minute. This is a backup alarm in case
+ // to that timeout plus one minute. This is a backup alarm in case
// the test wedges with a goroutine spinning and its background
// timer does not get a chance to fire.
if dt, err := time.ParseDuration(testTimeout); err == nil && dt > 0 {
@@ -410,6 +445,11 @@ func runTest(cmd *Command, args []string) {
testStreamOutput = len(pkgArgs) == 0 || testBench ||
(testShowPass && (len(pkgs) == 1 || buildP == 1))
+ // For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier.
+ if buildI && testO != "" {
+ testC = true
+ }
+
var b builder
b.init()
@@ -495,7 +535,8 @@ func runTest(cmd *Command, args []string) {
continue
}
p.Stale = true // rebuild
- p.fake = true // do not warn about rebuild
+ p.StaleReason = "rebuild for coverage"
+ p.fake = true // do not warn about rebuild
p.coverMode = testCoverMode
var coverFiles []string
coverFiles = append(coverFiles, p.GoFiles...)
@@ -507,6 +548,10 @@ func runTest(cmd *Command, args []string) {
// Prepare build + run + print actions for all packages being tested.
for _, p := range pkgs {
+ // sync/atomic import is inserted by the cover tool. See #18486
+ if testCover && testCoverMode == "atomic" {
+ ensureImport(p, "sync/atomic")
+ }
buildTest, runTest, printTest, err := b.test(p)
if err != nil {
str := err.Error()
@@ -598,6 +643,23 @@ func runTest(cmd *Command, args []string) {
b.do(root)
}
+// ensures that package p imports the named package.
+func ensureImport(p *Package, pkg string) {
+ for _, d := range p.deps {
+ if d.Name == pkg {
+ return
+ }
+ }
+
+ a := loadPackage(pkg, &importStack{})
+ if a.Error != nil {
+ fatalf("load %s: %v", pkg, a.Error)
+ }
+ computeStale(a)
+
+ p.imports = append(p.imports, a)
+}
+
func contains(x []string, s string) bool {
for _, t := range x {
if t == s {
@@ -700,7 +762,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// the usual place in the temporary tree, because then
// other tests will see it as the real package.
// Instead we make a _test directory under the import path
- // and then repeat the import path there. We tell the
+ // and then repeat the import path there. We tell the
// compiler and linker to look in that _test directory first.
//
// That is, if the package under test is unicode/utf8,
@@ -738,6 +800,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
ptest.fake = true
ptest.forceLibrary = true
ptest.Stale = true
+ ptest.StaleReason = "rebuild for test"
ptest.build = new(build.Package)
*ptest.build = *p.build
m := map[string][]token.Position{}
@@ -837,7 +900,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if err != nil {
return nil, nil, nil, err
}
- if len(ptest.GoFiles) > 0 {
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
pmain.imports = append(pmain.imports, ptest)
t.ImportTest = true
}
@@ -864,9 +927,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if buildContext.GOOS == "darwin" {
if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
- t.NeedCgo = true
+ t.IsIOS = true
+ t.NeedOS = true
}
}
+ if t.TestMain == nil {
+ t.NeedOS = true
+ }
for _, cp := range pmain.imports {
if len(cp.coverVars) > 0 {
@@ -1019,6 +1086,7 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) {
p.target = ""
p.fake = true
p.Stale = true
+ p.StaleReason = "depends on package being tested"
}
}
@@ -1064,6 +1132,8 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
return coverVars
}
+var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
+
// runTest is the action for running a test binary.
func (b *builder) runTest(a *action) error {
args := stringList(findExecCmd(), a.deps[0].target, testArgs)
@@ -1154,10 +1224,14 @@ func (b *builder) runTest(a *action) error {
out := buf.Bytes()
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
if err == nil {
+ norun := ""
if testShowPass {
a.testOutput.Write(out)
}
- fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s\n", a.p.ImportPath, t, coveragePercentage(out))
+ if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
+ norun = " [no tests to run]"
+ }
+ fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s%s\n", a.p.ImportPath, t, coveragePercentage(out), norun)
return nil
}
@@ -1218,11 +1292,11 @@ func (b *builder) notest(a *action) error {
return nil
}
-// isTestMain tells whether fn is a TestMain(m *testing.M) function.
-func isTestMain(fn *ast.FuncDecl) bool {
- if fn.Name.String() != "TestMain" ||
- fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
- fn.Type.Params == nil ||
+// isTestFunc tells whether fn has the type of a testing function. arg
+// specifies the parameter type we look for: B, M or T.
+func isTestFunc(fn *ast.FuncDecl, arg string) bool {
+ if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+ fn.Type.Params.List == nil ||
len(fn.Type.Params.List) != 1 ||
len(fn.Type.Params.List[0].Names) > 1 {
return false
@@ -1234,10 +1308,11 @@ func isTestMain(fn *ast.FuncDecl) bool {
// We can't easily check that the type is *testing.M
// because we don't know how testing has been imported,
// but at least check that it's *M or *something.M.
- if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
+ // Same applies for B and T.
+ if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
return true
}
- if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
+ if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
return true
}
return false
@@ -1305,7 +1380,8 @@ type testFuncs struct {
NeedTest bool
ImportXtest bool
NeedXtest bool
- NeedCgo bool
+ NeedOS bool
+ IsIOS bool
Cover []coverInfo
}
@@ -1334,9 +1410,10 @@ func (t *testFuncs) Tested() string {
}
type testFunc struct {
- Package string // imported package name (_test or _xtest)
- Name string // function name
- Output string // output, for examples
+ Package string // imported package name (_test or _xtest)
+ Name string // function name
+ Output string // output, for examples
+ Unordered bool // output is allowed to be unordered.
}
var testFileSet = token.NewFileSet()
@@ -1356,49 +1433,60 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
}
name := n.Name.String()
switch {
- case isTestMain(n):
+ case name == "TestMain" && isTestFunc(n, "M"):
if t.TestMain != nil {
return errors.New("multiple definitions of TestMain")
}
- t.TestMain = &testFunc{pkg, name, ""}
+ t.TestMain = &testFunc{pkg, name, "", false}
*doImport, *seen = true, true
case isTest(name, "Test"):
- t.Tests = append(t.Tests, testFunc{pkg, name, ""})
+ err := checkTestFunc(n, "T")
+ if err != nil {
+ return err
+ }
+ t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
*doImport, *seen = true, true
case isTest(name, "Benchmark"):
- t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
+ err := checkTestFunc(n, "B")
+ if err != nil {
+ return err
+ }
+ t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
*doImport, *seen = true, true
}
}
ex := doc.Examples(f)
- sort.Sort(byOrder(ex))
+ sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
for _, e := range ex {
*doImport = true // import test file whether executed or not
if e.Output == "" && !e.EmptyOutput {
// Don't run examples with no output.
continue
}
- t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
+ t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
*seen = true
}
return nil
}
-type byOrder []*doc.Example
-
-func (x byOrder) Len() int { return len(x) }
-func (x byOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byOrder) Less(i, j int) bool { return x[i].Order < x[j].Order }
+func checkTestFunc(fn *ast.FuncDecl, arg string) error {
+ if !isTestFunc(fn, arg) {
+ name := fn.Name.String()
+ pos := testFileSet.Position(fn.Pos())
+ return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
+ }
+ return nil
+}
var testmainTmpl = template.Must(template.New("main").Parse(`
package main
import (
-{{if not .TestMain}}
+{{if .NeedOS}}
"os"
{{end}}
- "regexp"
"testing"
+ "testing/internal/testdeps"
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
@@ -1410,8 +1498,10 @@ import (
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
{{end}}
-{{if .NeedCgo}}
+{{if .IsIOS}}
+ "os/signal"
_ "runtime/cgo"
+ "syscall"
{{end}}
)
@@ -1429,24 +1519,10 @@ var benchmarks = []testing.InternalBenchmark{
var examples = []testing.InternalExample{
{{range .Examples}}
- {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
+ {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
{{end}}
}
-var matchPat string
-var matchRe *regexp.Regexp
-
-func matchString(pat, str string) (result bool, err error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = regexp.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
{{if .CoverEnabled}}
// Only updated by init functions, so no need for atomicity.
@@ -1487,6 +1563,32 @@ func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts
{{end}}
func main() {
+{{if .IsIOS}}
+ // Send a SIGUSR2, which will be intercepted by LLDB to
+ // tell the test harness that installation was successful.
+ // See misc/ios/go_darwin_arm_exec.go.
+ signal.Notify(make(chan os.Signal), syscall.SIGUSR2)
+ syscall.Kill(0, syscall.SIGUSR2)
+ signal.Reset(syscall.SIGUSR2)
+
+ // The first argument supplied to an iOS test is an offset
+ // suffix for the current working directory.
+ // Process it here, and remove it from os.Args.
+ const hdr = "cwdSuffix="
+ if len(os.Args) < 2 || len(os.Args[1]) <= len(hdr) || os.Args[1][:len(hdr)] != hdr {
+ panic("iOS test not passed a working directory suffix")
+ }
+ suffix := os.Args[1][len(hdr):]
+ dir, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ if err := os.Chdir(dir + "/" + suffix); err != nil {
+ panic(err)
+ }
+ os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
+{{end}}
+
{{if .CoverEnabled}}
testing.RegisterCover(testing.Cover{
Mode: {{printf "%q" .CoverMode}},
@@ -1495,7 +1597,7 @@ func main() {
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
- m := testing.MainStart(matchString, tests, benchmarks, examples)
+ m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
{{else}}
diff --git a/libgo/go/cmd/go/testdata/dep_test.go b/libgo/go/cmd/go/testdata/dep_test.go
index 0c53ac4f96..ac39a5bb1c 100644
--- a/libgo/go/cmd/go/testdata/dep_test.go
+++ b/libgo/go/cmd/go/testdata/dep_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/testdata/example1_test.go b/libgo/go/cmd/go/testdata/example1_test.go
index ec7092e972..87e6c0acfa 100644
--- a/libgo/go/cmd/go/testdata/example1_test.go
+++ b/libgo/go/cmd/go/testdata/example1_test.go
@@ -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.
diff --git a/libgo/go/cmd/go/testdata/example2_test.go b/libgo/go/cmd/go/testdata/example2_test.go
index 1e0e80b80f..5d13426005 100644
--- a/libgo/go/cmd/go/testdata/example2_test.go
+++ b/libgo/go/cmd/go/testdata/example2_test.go
@@ -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.
diff --git a/libgo/go/cmd/go/testdata/failssh/ssh b/libgo/go/cmd/go/testdata/failssh/ssh
new file mode 100644
index 0000000000..ecdbef95dd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/failssh/ssh
@@ -0,0 +1,2 @@
+#!/bin/sh
+exit 1
diff --git a/libgo/go/cmd/go/testdata/generate/test1.go b/libgo/go/cmd/go/testdata/generate/test1.go
index 1f05734f04..168cfb74fb 100644
--- a/libgo/go/cmd/go/testdata/generate/test1.go
+++ b/libgo/go/cmd/go/testdata/generate/test1.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/testdata/generate/test2.go b/libgo/go/cmd/go/testdata/generate/test2.go
index ef1a3d9515..829244a166 100644
--- a/libgo/go/cmd/go/testdata/generate/test2.go
+++ b/libgo/go/cmd/go/testdata/generate/test2.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/testdata/generate/test3.go b/libgo/go/cmd/go/testdata/generate/test3.go
index 3d6a8a5c74..e950da591a 100644
--- a/libgo/go/cmd/go/testdata/generate/test3.go
+++ b/libgo/go/cmd/go/testdata/generate/test3.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/testdata/generate/test4.go b/libgo/go/cmd/go/testdata/generate/test4.go
index a7631c4a45..6dae0486eb 100644
--- a/libgo/go/cmd/go/testdata/generate/test4.go
+++ b/libgo/go/cmd/go/testdata/generate/test4.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/cmd/go/testdata/src/badc/x.c b/libgo/go/cmd/go/testdata/src/badc/x.c
new file mode 100644
index 0000000000..f6cbf6924d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badc/x.c
@@ -0,0 +1 @@
+// C code!
diff --git a/libgo/go/cmd/go/testdata/src/benchfatal/x_test.go b/libgo/go/cmd/go/testdata/src/benchfatal/x_test.go
new file mode 100644
index 0000000000..8d3a5deced
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/benchfatal/x_test.go
@@ -0,0 +1,7 @@
+package benchfatal
+
+import "testing"
+
+func BenchmarkThatCallsFatal(b *testing.B) {
+ b.Fatal("called by benchmark")
+}
diff --git a/libgo/go/cmd/go/testdata/src/canonical/a/a.go b/libgo/go/cmd/go/testdata/src/canonical/a/a.go
new file mode 100644
index 0000000000..486cc4843f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/a/a.go
@@ -0,0 +1,3 @@
+package a
+
+import _ "c"
diff --git a/libgo/go/cmd/go/testdata/src/canonical/a/vendor/c/c.go b/libgo/go/cmd/go/testdata/src/canonical/a/vendor/c/c.go
new file mode 100644
index 0000000000..7f96c221c2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/a/vendor/c/c.go
@@ -0,0 +1 @@
+package c
diff --git a/libgo/go/cmd/go/testdata/src/canonical/b/b.go b/libgo/go/cmd/go/testdata/src/canonical/b/b.go
new file mode 100644
index 0000000000..ce0f4ce303
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/b/b.go
@@ -0,0 +1,3 @@
+package b
+
+import _ "canonical/a/"
diff --git a/libgo/go/cmd/go/testdata/src/canonical/d/d.go b/libgo/go/cmd/go/testdata/src/canonical/d/d.go
new file mode 100644
index 0000000000..ef7dd7dd46
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/d/d.go
@@ -0,0 +1,3 @@
+package d
+
+import _ "canonical/b"
diff --git a/libgo/go/cmd/go/testdata/cgocover/p.go b/libgo/go/cmd/go/testdata/src/cgocover/p.go
index a6a3891cd4..a6a3891cd4 100644
--- a/libgo/go/cmd/go/testdata/cgocover/p.go
+++ b/libgo/go/cmd/go/testdata/src/cgocover/p.go
diff --git a/libgo/go/cmd/go/testdata/cgocover/p_test.go b/libgo/go/cmd/go/testdata/src/cgocover/p_test.go
index a8f057e358..a8f057e358 100644
--- a/libgo/go/cmd/go/testdata/cgocover/p_test.go
+++ b/libgo/go/cmd/go/testdata/src/cgocover/p_test.go
diff --git a/libgo/go/cmd/go/testdata/src/cgocover2/p.go b/libgo/go/cmd/go/testdata/src/cgocover2/p.go
new file mode 100644
index 0000000000..a6a3891cd4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover2/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go
new file mode 100644
index 0000000000..f4790d2367
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover2"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover3/p.go b/libgo/go/cmd/go/testdata/src/cgocover3/p.go
new file mode 100644
index 0000000000..a6a3891cd4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go b/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go
new file mode 100644
index 0000000000..97d0e0f098
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover3"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go b/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/cgocover4/p.go b/libgo/go/cmd/go/testdata/src/cgocover4/p.go
new file mode 100644
index 0000000000..a6a3891cd4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go
new file mode 100644
index 0000000000..fd9bae743c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover4"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/dupload/dupload.go b/libgo/go/cmd/go/testdata/src/dupload/dupload.go
new file mode 100644
index 0000000000..2f078525b9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/dupload.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "dupload/p2"
+ _ "p"
+)
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/dupload/p/p.go b/libgo/go/cmd/go/testdata/src/dupload/p/p.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go b/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go
new file mode 100644
index 0000000000..8a80979b4e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go
@@ -0,0 +1,3 @@
+package p2
+
+import _ "dupload/vendor/p"
diff --git a/libgo/go/cmd/go/testdata/src/dupload/vendor/p/p.go b/libgo/go/cmd/go/testdata/src/dupload/vendor/p/p.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/vendor/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
new file mode 100644
index 0000000000..9b64e8e1a2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
new file mode 100644
index 0000000000..9b64e8e1a2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/test/test_test.go b/libgo/go/cmd/go/testdata/src/empty/test/test_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/test/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go
new file mode 100644
index 0000000000..9b64e8e1a2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go
new file mode 100644
index 0000000000..9b64e8e1a2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go b/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go
new file mode 100644
index 0000000000..600afd93e9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go
@@ -0,0 +1,5 @@
+//go:generate echo hello world
+
+package gencycle
+
+import _ "gencycle"
diff --git a/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go b/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go
new file mode 100644
index 0000000000..bf019076dd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go
@@ -0,0 +1,5 @@
+package main
+
+import _ "importmain/test"
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/importmain/test/test.go b/libgo/go/cmd/go/testdata/src/importmain/test/test.go
new file mode 100644
index 0000000000..56e5404079
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/test/test.go
@@ -0,0 +1 @@
+package test
diff --git a/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go b/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go
new file mode 100644
index 0000000000..2268a8267e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go
@@ -0,0 +1,6 @@
+package test_test
+
+import "testing"
+import _ "importmain/ismain"
+
+func TestCase(t *testing.T) {}
diff --git a/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go b/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go
new file mode 100644
index 0000000000..c3e8de1276
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "my.pkg"
+
+func main() {
+ println(pkg.Text)
+}
diff --git a/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go b/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go
new file mode 100644
index 0000000000..17702a680b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go
@@ -0,0 +1,3 @@
+package pkg
+
+var Text = "unset"
diff --git a/libgo/go/cmd/go/testdata/src/testrace/race_test.go b/libgo/go/cmd/go/testdata/src/testrace/race_test.go
new file mode 100644
index 0000000000..264dcf0d8a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testrace/race_test.go
@@ -0,0 +1,29 @@
+package testrace
+
+import "testing"
+
+func TestRace(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
+
+func BenchmarkRace(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_benchmark_test.go b/libgo/go/cmd/go/testdata/standalone_benchmark_test.go
new file mode 100644
index 0000000000..4850f98d80
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_benchmark_test.go
@@ -0,0 +1,6 @@
+package standalone_benchmark
+
+import "testing"
+
+func Benchmark(b *testing.B) {
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go b/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go
new file mode 100644
index 0000000000..ac483f9e0c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go
@@ -0,0 +1,8 @@
+package standalone_fail_sub_test
+
+import "testing"
+
+func TestThatFails(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+ t.Fail()
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go b/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go
new file mode 100644
index 0000000000..d326de0a5a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go
@@ -0,0 +1,14 @@
+package standalone_parallel_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ ch := make(chan bool, 1)
+ t.Run("Sub", func(t *testing.T) {
+ t.Parallel()
+ <-ch
+ t.Run("Nested", func(t *testing.T) {})
+ })
+ // Ensures that Sub will finish after its t.Run call already returned.
+ ch <- true
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_sub_test.go b/libgo/go/cmd/go/testdata/standalone_sub_test.go
new file mode 100644
index 0000000000..f6c31db9c8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_sub_test.go
@@ -0,0 +1,7 @@
+package standalone_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+}
diff --git a/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
new file mode 100644
index 0000000000..d662e55ee5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
@@ -0,0 +1,39 @@
+// 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 linux
+
+// This test is run by src/cmd/dist/test.go (cmd_go_test_terminal),
+// and not by cmd/go's tests. This is because this test requires that
+// that it be called with its stdout and stderr being a terminal.
+// dist doesn't run `cmd/go test` against this test directory if
+// dist's stdout/stderr aren't terminals.
+//
+// See issue 18153.
+
+package p
+
+import (
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// isTerminal reports whether fd is a terminal.
+func isTerminal(fd uintptr) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
+
+func TestIsTerminal(t *testing.T) {
+ if !isTerminal(1) {
+ t.Errorf("stdout is not a terminal")
+ }
+ if !isTerminal(2) {
+ t.Errorf("stderr is not a terminal")
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/timeoutbench_test.go b/libgo/go/cmd/go/testdata/timeoutbench_test.go
new file mode 100644
index 0000000000..57a8888299
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/timeoutbench_test.go
@@ -0,0 +1,10 @@
+package timeoutbench_test
+
+import (
+ "testing"
+ "time"
+)
+
+func BenchmarkSleep1s(b *testing.B) {
+ time.Sleep(1 * time.Second)
+}
diff --git a/libgo/go/cmd/go/testflag.go b/libgo/go/cmd/go/testflag.go
index 873df1ffc3..fa53bfcdf0 100644
--- a/libgo/go/cmd/go/testflag.go
+++ b/libgo/go/cmd/go/testflag.go
@@ -50,6 +50,8 @@ var testFlagDefn = []*testFlagSpec{
{name: "memprofilerate", passToTest: true},
{name: "blockprofile", passToTest: true},
{name: "blockprofilerate", passToTest: true},
+ {name: "mutexprofile", passToTest: true},
+ {name: "mutexprofilefraction", passToTest: true},
{name: "outputdir", passToTest: true},
{name: "parallel", passToTest: true},
{name: "run", passToTest: true},
@@ -149,9 +151,11 @@ func testFlags(args []string) (packageNames, passToTest []string) {
testBench = true
case "timeout":
testTimeout = value
- case "blockprofile", "cpuprofile", "memprofile", "trace":
+ case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
testProfile = true
testNeedBinary = true
+ case "trace":
+ testProfile = true
case "coverpkg":
testCover = true
if value == "" {
diff --git a/libgo/go/cmd/go/testgo.go b/libgo/go/cmd/go/testgo.go
index 01923f74bd..e507f34be6 100644
--- a/libgo/go/cmd/go/testgo.go
+++ b/libgo/go/cmd/go/testgo.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/cmd/go/tool.go b/libgo/go/cmd/go/tool.go
index 9a552d6ec0..6e2c68fbf5 100644
--- a/libgo/go/cmd/go/tool.go
+++ b/libgo/go/cmd/go/tool.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -66,7 +66,7 @@ func tool(toolName string) string {
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
- setExitStatus(3)
+ setExitStatus(2)
exit()
}
return toolPath
diff --git a/libgo/go/cmd/go/vcs.go b/libgo/go/cmd/go/vcs.go
index 342edee50d..fcdce220a7 100644
--- a/libgo/go/cmd/go/vcs.go
+++ b/libgo/go/cmd/go/vcs.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -41,7 +41,7 @@ type vcsCmd struct {
resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
}
-var isSecureScheme = map[string]bool{
+var defaultSecureScheme = map[string]bool{
"https": true,
"git+ssh": true,
"bzr+ssh": true,
@@ -55,7 +55,25 @@ func (v *vcsCmd) isSecure(repo string) bool {
// If repo is not a URL, it's not secure.
return false
}
- return isSecureScheme[u.Scheme]
+ return v.isSecureScheme(u.Scheme)
+}
+
+func (v *vcsCmd) isSecureScheme(scheme string) bool {
+ switch v.cmd {
+ case "git":
+ // GIT_ALLOW_PROTOCOL is an environment variable defined by Git. It is a
+ // colon-separated list of schemes that are allowed to be used with git
+ // fetch/clone. Any scheme not mentioned will be considered insecure.
+ if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" {
+ for _, s := range strings.Split(allow, ":") {
+ if s == scheme {
+ return true
+ }
+ }
+ return false
+ }
+ }
+ return defaultSecureScheme[scheme]
}
// A tagCmd describes a command to list available tags
@@ -93,7 +111,7 @@ var vcsHg = &vcsCmd{
downloadCmd: []string{"pull"},
// We allow both tag and branch names as 'tags'
- // for selecting a version. This lets people have
+ // for selecting a version. This lets people have
// a go.release.r60 branch and a go1 branch
// and make changes in both, without constantly
// editing .hgtags.
@@ -171,10 +189,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)
@@ -253,7 +271,7 @@ func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string
return "", fmt.Errorf("unable to parse output of bzr info")
}
out = out[:i]
- return strings.TrimSpace(string(out)), nil
+ return strings.TrimSpace(out), nil
}
// vcsSvn describes how to use Subversion.
@@ -294,7 +312,7 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error
return "", fmt.Errorf("unable to parse output of svn info")
}
out = out[:i]
- return strings.TrimSpace(string(out)), nil
+ return strings.TrimSpace(out), nil
}
func (v *vcsCmd) String() string {
@@ -383,9 +401,6 @@ func (v *vcsCmd) ping(scheme, repo string) error {
// The parent of dir must exist; dir must not.
func (v *vcsCmd) create(dir, repo string) error {
for _, cmd := range v.createCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
- continue
- }
if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
return err
}
@@ -396,9 +411,6 @@ func (v *vcsCmd) create(dir, repo string) error {
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
for _, cmd := range v.downloadCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
- continue
- }
if err := v.run(dir, cmd); err != nil {
return err
}
@@ -445,9 +457,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
if tag == "" && v.tagSyncDefault != nil {
for _, cmd := range v.tagSyncDefault {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
- continue
- }
if err := v.run(dir, cmd); err != nil {
return err
}
@@ -456,9 +465,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
}
for _, cmd := range v.tagSyncCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
- continue
- }
if err := v.run(dir, cmd, "tag", tag); err != nil {
return err
}
@@ -479,15 +485,14 @@ type vcsPath struct {
regexp *regexp.Regexp // cached compiled form of re
}
-// vcsForDir inspects dir and its parents to determine the
+// vcsFromDir inspects dir and its parents to determine the
// version control system and code repository to use.
// On return, root is the import path
-// corresponding to the root of the repository
-// (thus root is a prefix of importPath).
-func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
+// corresponding to the root of the repository.
+func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
- dir := filepath.Clean(p.Dir)
- srcRoot := filepath.Clean(p.build.SrcRoot)
+ dir = filepath.Clean(dir)
+ srcRoot = filepath.Clean(srcRoot)
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
@@ -495,8 +500,8 @@ func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
origDir := dir
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
- if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
- return vcs, dir[len(srcRoot)+1:], nil
+ if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
+ return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
}
}
@@ -523,6 +528,9 @@ type repoRoot struct {
// root is the import path corresponding to the root of the
// repository
root string
+
+ // isCustom is true for custom import paths (those defined by HTML meta tags)
+ isCustom bool
}
var httpPrefixRE = regexp.MustCompile(`^https?:`)
@@ -625,7 +633,7 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcs.scheme {
- if security == secure && !isSecureScheme[scheme] {
+ if security == secure && !vcs.isSecureScheme(scheme) {
continue
}
if vcs.ping(scheme, match["repo"]) == nil {
@@ -674,10 +682,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
// Find the matched meta import.
mmi, err := matchGoImport(imports, importPath)
if err != nil {
- if err != errNoMatch {
+ if _, ok := err.(ImportMismatchError); !ok {
return nil, fmt.Errorf("parse %s: %v", urlStr, err)
}
- return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)
}
if buildV {
log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
@@ -708,9 +716,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
}
rr := &repoRoot{
- vcs: vcsByCmd(mmi.VCS),
- repo: mmi.RepoRoot,
- root: mmi.Prefix,
+ vcs: vcsByCmd(mmi.VCS),
+ repo: mmi.RepoRoot,
+ root: mmi.Prefix,
+ isCustom: true,
}
if rr.vcs == nil {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
@@ -777,27 +786,57 @@ type metaImport struct {
Prefix, VCS, RepoRoot string
}
-// errNoMatch is returned from matchGoImport when there's no applicable match.
-var errNoMatch = errors.New("no import match")
+func splitPathHasPrefix(path, prefix []string) bool {
+ if len(path) < len(prefix) {
+ return false
+ }
+ for i, p := range prefix {
+ if path[i] != p {
+ return false
+ }
+ }
+ return true
+}
+
+// A ImportMismatchError is returned where metaImport/s are present
+// but none match our import path.
+type ImportMismatchError struct {
+ importPath string
+ mismatches []string // the meta imports that were discarded for not matching our importPath
+}
+
+func (m ImportMismatchError) Error() string {
+ formattedStrings := make([]string, len(m.mismatches))
+ for i, pre := range m.mismatches {
+ formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath)
+ }
+ return strings.Join(formattedStrings, ", ")
+}
// matchGoImport returns the metaImport from imports matching importPath.
// An error is returned if there are multiple matches.
// errNoMatch is returned if none match.
-func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+func matchGoImport(imports []metaImport, importPath string) (metaImport, error) {
match := -1
+ imp := strings.Split(importPath, "/")
+
+ errImportMismatch := ImportMismatchError{importPath: importPath}
for i, im := range imports {
- if !strings.HasPrefix(importPath, im.Prefix) {
+ pre := strings.Split(im.Prefix, "/")
+
+ if !splitPathHasPrefix(imp, pre) {
+ errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
continue
}
+
if match != -1 {
- err = fmt.Errorf("multiple meta tags match import path %q", importPath)
- return
+ return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
}
match = i
}
+
if match == -1 {
- err = errNoMatch
- return
+ return metaImport{}, errImportMismatch
}
return imports[match], nil
}
@@ -815,20 +854,6 @@ func expand(match map[string]string, s string) string {
// and import paths referring to a fully-qualified importPath
// containing a VCS type (foo.com/repo.git/dir)
var vcsPaths = []*vcsPath{
- // Google Code - new syntax
- {
- prefix: "code.google.com/",
- re: `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
- repo: "https://{root}",
- check: googleCodeVCS,
- },
-
- // Google Code - old syntax
- {
- re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
- check: oldGoogleCode,
- },
-
// Github
{
prefix: "github.com/",
@@ -863,6 +888,14 @@ 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}",
+ },
+
// General syntax for any server.
// Must be last.
{
@@ -911,45 +944,6 @@ func noVCSSuffix(match map[string]string) error {
return nil
}
-var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
-
-// googleCodeVCS determines the version control system for
-// a code.google.com repository, by scraping the project's
-// /source/checkout page.
-func googleCodeVCS(match map[string]string) error {
- if err := noVCSSuffix(match); err != nil {
- return err
- }
- data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
- if err != nil {
- return err
- }
-
- if m := googleCheckout.FindSubmatch(data); m != nil {
- if vcs := vcsByCmd(string(m[1])); vcs != nil {
- // Subversion requires the old URLs.
- // TODO: Test.
- if vcs == vcsSvn {
- if match["subrepo"] != "" {
- return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
- }
- match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
- }
- match["vcs"] = vcs.cmd
- return nil
- }
- }
-
- return fmt.Errorf("unable to detect version control system for code.google.com/ path")
-}
-
-// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
-// It prints an error giving the equivalent new path.
-func oldGoogleCode(match map[string]string) error {
- return fmt.Errorf("invalid Google Code import path: use %s instead",
- expand(match, "code.google.com/p/{project}{path}"))
-}
-
// bitbucketVCS determines the version control system for a
// Bitbucket repository, by using the Bitbucket API.
func bitbucketVCS(match map[string]string) error {
diff --git a/libgo/go/cmd/go/vcs_test.go b/libgo/go/cmd/go/vcs_test.go
index a90c2061ed..c73f5d0e85 100644
--- a/libgo/go/cmd/go/vcs_test.go
+++ b/libgo/go/cmd/go/vcs_test.go
@@ -1,11 +1,16 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
+ "errors"
"internal/testenv"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
"testing"
)
@@ -18,20 +23,6 @@ func TestRepoRootForImportPath(t *testing.T) {
path string
want *repoRoot
}{
- /*{
- "code.google.com/p/go",
- &repoRoot{
- vcs: vcsHg,
- repo: "https://code.google.com/p/go",
- },
- },
- {
- "code.google.com/r/go",
- &repoRoot{
- vcs: vcsHg,
- repo: "https://code.google.com/r/go",
- },
- },*/
{
"github.com/golang/groupcache",
&repoRoot{
@@ -96,6 +87,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",
+ },
+ },
+ {
+ "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",
@@ -142,6 +166,49 @@ func TestRepoRootForImportPath(t *testing.T) {
}
}
+// Test that vcsFromDir correctly inspects a given directory and returns the right VCS and root.
+func TestFromDir(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "vcstest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempDir)
+
+ for j, vcs := range vcsList {
+ dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
+ if j&1 == 0 {
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ err := os.MkdirAll(filepath.Dir(dir), 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f, err := os.Create(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
+ }
+
+ want := repoRoot{
+ vcs: vcs,
+ root: path.Join("example.com", vcs.name),
+ }
+ var got repoRoot
+ got.vcs, got.root, err = vcsFromDir(dir, tempDir)
+ if err != nil {
+ t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
+ continue
+ }
+ if got.vcs.name != want.vcs.name || got.root != want.root {
+ t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root)
+ }
+ }
+}
+
func TestIsSecure(t *testing.T) {
tests := []struct {
vcs *vcsCmd
@@ -173,3 +240,143 @@ func TestIsSecure(t *testing.T) {
}
}
}
+
+func TestIsSecureGitAllowProtocol(t *testing.T) {
+ tests := []struct {
+ vcs *vcsCmd
+ url string
+ secure bool
+ }{
+ // Same as TestIsSecure to verify same behavior.
+ {vcsGit, "http://example.com/foo.git", false},
+ {vcsGit, "https://example.com/foo.git", true},
+ {vcsBzr, "http://example.com/foo.bzr", false},
+ {vcsBzr, "https://example.com/foo.bzr", true},
+ {vcsSvn, "http://example.com/svn", false},
+ {vcsSvn, "https://example.com/svn", true},
+ {vcsHg, "http://example.com/foo.hg", false},
+ {vcsHg, "https://example.com/foo.hg", true},
+ {vcsGit, "user@server:path/to/repo.git", false},
+ {vcsGit, "user@server:", false},
+ {vcsGit, "server:repo.git", false},
+ {vcsGit, "server:path/to/repo.git", false},
+ {vcsGit, "example.com:path/to/repo.git", false},
+ {vcsGit, "path/that/contains/a:colon/repo.git", false},
+ {vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
+ // New behavior.
+ {vcsGit, "ssh://user@example.com/foo.git", false},
+ {vcsGit, "foo://example.com/bar.git", true},
+ {vcsHg, "foo://example.com/bar.hg", false},
+ {vcsSvn, "foo://example.com/svn", false},
+ {vcsBzr, "foo://example.com/bar.bzr", false},
+ }
+
+ defer os.Unsetenv("GIT_ALLOW_PROTOCOL")
+ os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo")
+ for _, test := range tests {
+ secure := test.vcs.isSecure(test.url)
+ if secure != test.secure {
+ t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
+ }
+ }
+}
+
+func TestMatchGoImport(t *testing.T) {
+ tests := []struct {
+ imports []metaImport
+ path string
+ mi metaImport
+ err error
+ }{
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo",
+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo/",
+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo",
+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/fooa",
+ mi: metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo/bar",
+ err: errors.New("should not be allowed to create nested repo"),
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo/bar/baz",
+ err: errors.New("should not be allowed to create nested repo"),
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo/bar/baz/qux",
+ err: errors.New("should not be allowed to create nested repo"),
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com/user/foo/bar/baz/",
+ err: errors.New("should not be allowed to create nested repo"),
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "example.com",
+ err: errors.New("pathologically short path"),
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "different.example.com/user/foo",
+ err: errors.New("meta tags do not match import path"),
+ },
+ }
+
+ for _, test := range tests {
+ mi, err := matchGoImport(test.imports, test.path)
+ if mi != test.mi {
+ t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
+ }
+
+ got := err
+ want := test.err
+ if (got == nil) != (want == nil) {
+ t.Errorf("unexpected error; got %v, want %v", got, want)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/vendor_test.go b/libgo/go/cmd/go/vendor_test.go
index 006a8c9d3f..deec02e341 100644
--- a/libgo/go/cmd/go/vendor_test.go
+++ b/libgo/go/cmd/go/vendor_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -20,7 +20,6 @@ func TestVendorImports(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
want := `
vend [vend/vendor/p r]
@@ -51,7 +50,6 @@ func TestVendorBuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("build", "vend/x")
}
@@ -59,7 +57,6 @@ func TestVendorRun(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
tg.run("run", "hello.go")
tg.grepStdout("hello, world", "missing hello world output")
@@ -74,7 +71,6 @@ func TestVendorGOPATH(t *testing.T) {
}
gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower)
tg.setenv("GOPATH", gopath)
- tg.setenv("GO15VENDOREXPERIMENT", "1")
cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper)
tg.cd(cd)
tg.run("run", "hello.go")
@@ -85,7 +81,6 @@ func TestVendorTest(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
tg.run("test", "-v")
tg.grepStdout("TestMsgInternal", "missing use in internal test")
@@ -96,7 +91,6 @@ func TestVendorInvalid(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "vend/x/invalid")
tg.grepStderr("must be imported as foo", "missing vendor import error")
@@ -106,7 +100,6 @@ func TestVendorImportError(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "vend/x/vendor/p/p")
@@ -173,7 +166,6 @@ func TestVendorGet(t *testing.T) {
package p
const C = 1`)
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(tg.path("src/v"))
tg.run("run", "m.go")
tg.run("test")
@@ -192,11 +184,46 @@ func TestVendorGetUpdate(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
}
+func TestVendorGetU(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
+}
+
+func TestVendorGetTU(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "-t", "-u", "github.com/rsc/go-get-issue-11864/...")
+}
+
+func TestVendorGetBadVendor(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ for _, suffix := range []string{"bad/imp", "bad/imp2", "bad/imp3", "..."} {
+ t.Run(suffix, func(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.runFail("get", "-t", "-u", "github.com/rsc/go-get-issue-18219/"+suffix)
+ tg.grepStderr("must be imported as", "did not find error about vendor import")
+ tg.mustNotExist(tg.path("src/github.com/rsc/vendor"))
+ })
+ }
+}
+
func TestGetSubmodules(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -204,16 +231,15 @@ func TestGetSubmodules(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "-d", "github.com/rsc/go-get-issue-12612")
tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612")
+ tg.mustExist(tg.path("src/github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git"))
}
func TestVendorCache(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "p")
tg.grepStderr("must be imported as x", "did not fail to build p")
}
@@ -225,7 +251,6 @@ func TestVendorTest2(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
// build -i should work
@@ -244,6 +269,32 @@ func TestVendorTest2(t *testing.T) {
tg.run("test", "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2")
}
+func TestVendorTest3(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "github.com/clsung/go-vendor-issue-14613")
+
+ tg.run("build", "-o", tg.path("a.out"), "-i", "github.com/clsung/go-vendor-issue-14613")
+
+ // test folder should work
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613")
+ tg.run("test", "github.com/clsung/go-vendor-issue-14613")
+
+ // test with specified _test.go should work too
+ tg.cd(filepath.Join(tg.path("."), "src"))
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor_test.go")
+ tg.run("test", "github.com/clsung/go-vendor-issue-14613/vendor_test.go")
+
+ // test with imported and not used
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go")
+ tg.runFail("test", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go")
+ tg.grepStderr("imported and not used:", `should say "imported and not used"`)
+}
+
func TestVendorList(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -251,7 +302,6 @@ func TestVendorList(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t")
@@ -272,7 +322,6 @@ func TestVendor12156(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p"))
tg.runFail("build", "p.go")
tg.grepStderrNot("panic", "panicked")
diff --git a/libgo/go/cmd/go/version.go b/libgo/go/cmd/go/version.go
index a41f4a7361..3045f350d7 100644
--- a/libgo/go/cmd/go/version.go
+++ b/libgo/go/cmd/go/version.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/go/vet.go b/libgo/go/cmd/go/vet.go
index 81b978e8da..8e296c8572 100644
--- a/libgo/go/cmd/go/vet.go
+++ b/libgo/go/cmd/go/vet.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/cmd/gofmt/doc.go b/libgo/go/cmd/gofmt/doc.go
index 9d0cd32862..8b22f03f65 100644
--- a/libgo/go/cmd/gofmt/doc.go
+++ b/libgo/go/cmd/gofmt/doc.go
@@ -32,7 +32,8 @@ The flags are:
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
- with gofmt's version.
+ with gofmt's version. If an error occurred during overwriting,
+ the original file is restored from an automatic backup.
Debugging support:
-cpuprofile filename
@@ -98,3 +99,5 @@ This may result in changes that are incompatible with earlier versions of Go.
package main
// BUG(rsc): The implementation of -r is a bit slow.
+// BUG(gri): If -w fails, the restored original file may not have some of the
+// original file attributes.
diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go
index cfebeffe4a..e1ef0ddb83 100644
--- a/libgo/go/cmd/gofmt/gofmt.go
+++ b/libgo/go/cmd/gofmt/gofmt.go
@@ -18,6 +18,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"runtime/pprof"
"strings"
)
@@ -55,7 +56,6 @@ func report(err error) {
func usage() {
fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
flag.PrintDefaults()
- os.Exit(2)
}
func initParserMode() {
@@ -73,13 +73,19 @@ func isGoFile(f os.FileInfo) bool {
// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
+ var perm os.FileMode = 0644
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ return err
+ }
in = f
+ perm = fi.Mode().Perm()
}
src, err := ioutil.ReadAll(in)
@@ -117,7 +123,17 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
- err = ioutil.WriteFile(filename, res, 0644)
+ // make a temporary backup before overwriting original
+ bakname, err := backupFile(filename+".", src, perm)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(filename, res, perm)
+ if err != nil {
+ os.Rename(bakname, filename)
+ return err
+ }
+ err = os.Remove(bakname)
if err != nil {
return err
}
@@ -143,7 +159,9 @@ func visitFile(path string, f os.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, false)
}
- if err != nil {
+ // Don't complain if a file was deleted in the meantime (i.e.
+ // the directory changed concurrently while running gofmt).
+ if err != nil && !os.IsNotExist(err) {
report(err)
}
return nil
@@ -234,3 +252,36 @@ func diff(b1, b2 []byte) (data []byte, err error) {
return
}
+
+const chmodSupported = runtime.GOOS != "windows"
+
+// backupFile writes data to a new file named filename<number> with permissions perm,
+// with <number randomly chosen such that the file name is unique. backupFile returns
+// the chosen file name.
+func backupFile(filename string, data []byte, perm os.FileMode) (string, error) {
+ // create backup file
+ f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
+ if err != nil {
+ return "", err
+ }
+ bakname := f.Name()
+ if chmodSupported {
+ err = f.Chmod(perm)
+ if err != nil {
+ f.Close()
+ os.Remove(bakname)
+ return bakname, err
+ }
+ }
+
+ // write data to backup file
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+
+ return bakname, err
+}
diff --git a/libgo/go/cmd/gofmt/gofmt_test.go b/libgo/go/cmd/gofmt/gofmt_test.go
index d1edb7bcc1..b7ca9e8d11 100644
--- a/libgo/go/cmd/gofmt/gofmt_test.go
+++ b/libgo/go/cmd/gofmt/gofmt_test.go
@@ -159,7 +159,7 @@ func TestCRLF(t *testing.T) {
if err != nil {
t.Error(err)
}
- if bytes.Index(data, []byte("\r\n")) < 0 {
+ if !bytes.Contains(data, []byte("\r\n")) {
t.Errorf("%s contains no CR/LF's", input)
}
@@ -167,7 +167,20 @@ func TestCRLF(t *testing.T) {
if err != nil {
t.Error(err)
}
- if bytes.Index(data, []byte("\r")) >= 0 {
+ if bytes.Contains(data, []byte("\r")) {
t.Errorf("%s contains CR's", golden)
}
}
+
+func TestBackupFile(t *testing.T) {
+ dir, err := ioutil.TempDir("", "gofmt_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ name, err := backupFile(filepath.Join(dir, "foo.go"), []byte(" package main"), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Created: %s", name)
+}
diff --git a/libgo/go/cmd/gofmt/internal.go b/libgo/go/cmd/gofmt/internal.go
index f764b10ebb..cbc6983b61 100644
--- a/libgo/go/cmd/gofmt/internal.go
+++ b/libgo/go/cmd/gofmt/internal.go
@@ -28,9 +28,9 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
) {
// Try as whole source file.
file, err = parser.ParseFile(fset, filename, src, parserMode)
- // If there's no error, return. If the error is that the source file didn't begin with a
+ // If there's no error, return. If the error is that the source file didn't begin with a
// package line and source fragments are ok, fall through to
- // try as a source fragment. Stop and return on any other error.
+ // try as a source fragment. Stop and return on any other error.
if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
return
}
@@ -59,7 +59,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
// If this is a statement list, make it a source file
// by inserting a package clause and turning the list
- // into a function body. This handles expressions too.
+ // into a function body. This handles expressions too.
// Insert using a ;, not a newline, so that the line numbers
// in fsrc match the ones in src. Add an extra '\n' before the '}'
// to make sure comments are flushed before the '}'.
diff --git a/libgo/go/cmd/gofmt/rewrite.go b/libgo/go/cmd/gofmt/rewrite.go
index 069f96622c..550492bf29 100644
--- a/libgo/go/cmd/gofmt/rewrite.go
+++ b/libgo/go/cmd/gofmt/rewrite.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -158,7 +158,7 @@ func isWildcard(s string) bool {
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
- // Wildcard matches any expression. If it appears multiple
+ // Wildcard matches any expression. If it appears multiple
// times in the pattern, it must match the same expression
// each time.
if m != nil && pattern.IsValid() && pattern.Type() == identType {
diff --git a/libgo/go/cmd/gofmt/simplify.go b/libgo/go/cmd/gofmt/simplify.go
index 69f7bf23c0..1a0e8174af 100644
--- a/libgo/go/cmd/gofmt/simplify.go
+++ b/libgo/go/cmd/gofmt/simplify.go
@@ -10,56 +10,40 @@ import (
"reflect"
)
-type simplifier struct {
- hasDotImport bool // package file contains: import . "some/import/path"
-}
+type simplifier struct{}
-func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+func (s simplifier) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.CompositeLit:
// array, slice, and map composite literals may be simplified
outer := n
- var eltType ast.Expr
+ var keyType, eltType ast.Expr
switch typ := outer.Type.(type) {
case *ast.ArrayType:
eltType = typ.Elt
case *ast.MapType:
+ keyType = typ.Key
eltType = typ.Value
}
if eltType != nil {
+ var ktyp reflect.Value
+ if keyType != nil {
+ ktyp = reflect.ValueOf(keyType)
+ }
typ := reflect.ValueOf(eltType)
for i, x := range outer.Elts {
px := &outer.Elts[i]
// look at value of indexed/named elements
if t, ok := x.(*ast.KeyValueExpr); ok {
+ if keyType != nil {
+ s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key)
+ }
x = t.Value
px = &t.Value
}
- ast.Walk(s, x) // simplify x
- // if the element is a composite literal and its literal type
- // matches the outer literal's element type exactly, the inner
- // literal type may be omitted
- if inner, ok := x.(*ast.CompositeLit); ok {
- if match(nil, typ, reflect.ValueOf(inner.Type)) {
- inner.Type = nil
- }
- }
- // if the outer literal's element type is a pointer type *T
- // and the element is & of a composite literal of type T,
- // the inner &T may be omitted.
- if ptr, ok := eltType.(*ast.StarExpr); ok {
- if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
- if inner, ok := addr.X.(*ast.CompositeLit); ok {
- if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
- inner.Type = nil // drop T
- *px = inner // drop &
- }
- }
- }
- }
+ s.simplifyLiteral(typ, eltType, x, px)
}
-
// node was simplified - stop walk (there are no subnodes to simplify)
return nil
}
@@ -68,10 +52,13 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
// a slice expression of the form: s[a:len(s)]
// can be simplified to: s[a:]
// if s is "simple enough" (for now we only accept identifiers)
- if n.Max != nil || s.hasDotImport {
+ //
+ // Note: This may not be correct because len may have been redeclared in another
+ // file belonging to the same package. However, this is extremely unlikely
+ // and so far (April 2016, after years of supporting this rewrite feature)
+ // has never come up, so let's keep it working as is (see also #15153).
+ if n.Max != nil {
// - 3-index slices always require the 2nd and 3rd index
- // - if dot imports are present, we cannot be certain that an
- // unresolved "len" identifier refers to the predefined len()
break
}
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
@@ -112,26 +99,43 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
return s
}
+func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
+ ast.Walk(s, x) // simplify x
+
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.ValueOf(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := astType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
+}
+
func isBlank(x ast.Expr) bool {
ident, ok := x.(*ast.Ident)
return ok && ident.Name == "_"
}
func simplify(f *ast.File) {
- var s simplifier
-
- // determine if f contains dot imports
- for _, imp := range f.Imports {
- if imp.Name != nil && imp.Name.Name == "." {
- s.hasDotImport = true
- break
- }
- }
-
// remove empty declarations such as "const ()", etc
removeEmptyDeclGroups(f)
- ast.Walk(&s, f)
+ var s simplifier
+ ast.Walk(s, f)
}
func removeEmptyDeclGroups(f *ast.File) {
diff --git a/libgo/go/cmd/gofmt/testdata/composites.golden b/libgo/go/cmd/gofmt/testdata/composites.golden
index fc9c98e625..a06a69d096 100644
--- a/libgo/go/cmd/gofmt/testdata/composites.golden
+++ b/libgo/go/cmd/gofmt/testdata/composites.golden
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
{},
{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
+
+var _ = map[*T]*T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
diff --git a/libgo/go/cmd/gofmt/testdata/composites.input b/libgo/go/cmd/gofmt/testdata/composites.input
index fc7598af99..9d28ac7ed3 100644
--- a/libgo/go/cmd/gofmt/testdata/composites.input
+++ b/libgo/go/cmd/gofmt/testdata/composites.input
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
T{},
T{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ T{1, 2}: T2{3, 4},
+ T{5, 6}: T2{7, 8},
+}
+
+var _ = map[*T]*T2{
+ &T{1, 2}: &T2{3, 4},
+ &T{5, 6}: &T2{7, 8},
+}
diff --git a/libgo/go/cmd/gofmt/testdata/emptydecl.golden b/libgo/go/cmd/gofmt/testdata/emptydecl.golden
new file mode 100644
index 0000000000..33d6435e0a
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/emptydecl.golden
@@ -0,0 +1,14 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
+package main
+
+// Keep this declaration
+var ()
+
+const (
+// Keep this declaration
+)
+
+func main() {}
diff --git a/libgo/go/cmd/gofmt/testdata/emptydecl.input b/libgo/go/cmd/gofmt/testdata/emptydecl.input
new file mode 100644
index 0000000000..4948a61f0d
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/emptydecl.input
@@ -0,0 +1,16 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
+package main
+
+// Keep this declaration
+var ()
+
+const (
+// Keep this declaration
+)
+
+type ()
+
+func main() {} \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/testdata/ranges.golden b/libgo/go/cmd/gofmt/testdata/ranges.golden
new file mode 100644
index 0000000000..506b3a035a
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/ranges.golden
@@ -0,0 +1,30 @@
+//gofmt -s
+
+// Test cases for range simplification.
+package p
+
+func _() {
+ for a, b = range x {
+ }
+ for a = range x {
+ }
+ for _, b = range x {
+ }
+ for range x {
+ }
+
+ for a = range x {
+ }
+ for range x {
+ }
+
+ for a, b := range x {
+ }
+ for a := range x {
+ }
+ for _, b := range x {
+ }
+
+ for a := range x {
+ }
+}
diff --git a/libgo/go/cmd/gofmt/testdata/ranges.input b/libgo/go/cmd/gofmt/testdata/ranges.input
new file mode 100644
index 0000000000..df5f8333c2
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/ranges.input
@@ -0,0 +1,20 @@
+//gofmt -s
+
+// Test cases for range simplification.
+package p
+
+func _() {
+ for a, b = range x {}
+ for a, _ = range x {}
+ for _, b = range x {}
+ for _, _ = range x {}
+
+ for a = range x {}
+ for _ = range x {}
+
+ for a, b := range x {}
+ for a, _ := range x {}
+ for _, b := range x {}
+
+ for a := range x {}
+}
diff --git a/libgo/go/cmd/gofmt/testdata/slices2.golden b/libgo/go/cmd/gofmt/testdata/slices2.golden
deleted file mode 100644
index ab657004e6..0000000000
--- a/libgo/go/cmd/gofmt/testdata/slices2.golden
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
- a [10]byte
- b [20]float32
- s []int
- t struct {
- s []byte
- }
-
- _ = a[0:]
- _ = a[1:10]
- _ = a[2:len(a)]
- _ = a[3:(len(a))]
- _ = a[len(a) : len(a)-1]
- _ = a[0:len(b)]
-
- _ = a[:]
- _ = a[:10]
- _ = a[:len(a)]
- _ = a[:(len(a))]
- _ = a[:len(a)-1]
- _ = a[:len(b)]
-
- _ = s[0:]
- _ = s[1:10]
- _ = s[2:len(s)]
- _ = s[3:(len(s))]
- _ = s[len(a) : len(s)-1]
- _ = s[0:len(b)]
-
- _ = s[:]
- _ = s[:10]
- _ = s[:len(s)]
- _ = s[:(len(s))]
- _ = s[:len(s)-1]
- _ = s[:len(b)]
-
- _ = t.s[0:]
- _ = t.s[1:10]
- _ = t.s[2:len(t.s)]
- _ = t.s[3:(len(t.s))]
- _ = t.s[len(a) : len(t.s)-1]
- _ = t.s[0:len(b)]
-
- _ = t.s[:]
- _ = t.s[:10]
- _ = t.s[:len(t.s)]
- _ = t.s[:(len(t.s))]
- _ = t.s[:len(t.s)-1]
- _ = t.s[:len(b)]
-)
-
-func _() {
- s := s[0:len(s)]
- _ = s
-}
diff --git a/libgo/go/cmd/gofmt/testdata/slices2.input b/libgo/go/cmd/gofmt/testdata/slices2.input
deleted file mode 100644
index ab657004e6..0000000000
--- a/libgo/go/cmd/gofmt/testdata/slices2.input
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
- a [10]byte
- b [20]float32
- s []int
- t struct {
- s []byte
- }
-
- _ = a[0:]
- _ = a[1:10]
- _ = a[2:len(a)]
- _ = a[3:(len(a))]
- _ = a[len(a) : len(a)-1]
- _ = a[0:len(b)]
-
- _ = a[:]
- _ = a[:10]
- _ = a[:len(a)]
- _ = a[:(len(a))]
- _ = a[:len(a)-1]
- _ = a[:len(b)]
-
- _ = s[0:]
- _ = s[1:10]
- _ = s[2:len(s)]
- _ = s[3:(len(s))]
- _ = s[len(a) : len(s)-1]
- _ = s[0:len(b)]
-
- _ = s[:]
- _ = s[:10]
- _ = s[:len(s)]
- _ = s[:(len(s))]
- _ = s[:len(s)-1]
- _ = s[:len(b)]
-
- _ = t.s[0:]
- _ = t.s[1:10]
- _ = t.s[2:len(t.s)]
- _ = t.s[3:(len(t.s))]
- _ = t.s[len(a) : len(t.s)-1]
- _ = t.s[0:len(b)]
-
- _ = t.s[:]
- _ = t.s[:10]
- _ = t.s[:len(t.s)]
- _ = t.s[:(len(t.s))]
- _ = t.s[:len(t.s)-1]
- _ = t.s[:len(b)]
-)
-
-func _() {
- s := s[0:len(s)]
- _ = s
-}
diff --git a/libgo/go/cmd/gofmt/testdata/stdin5.golden b/libgo/go/cmd/gofmt/testdata/stdin5.golden
new file mode 100644
index 0000000000..31ce6b2485
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin5.golden
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i := 5 // Line comment without newline. \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/testdata/stdin5.input b/libgo/go/cmd/gofmt/testdata/stdin5.input
new file mode 100644
index 0000000000..0a7c97d180
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin5.input
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i :=5// Line comment without newline. \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/testdata/stdin6.golden b/libgo/go/cmd/gofmt/testdata/stdin6.golden
new file mode 100644
index 0000000000..ffcea8011b
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin6.golden
@@ -0,0 +1,19 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f := func(hat, tail string) {
+
+ fmt.Println(hat+`
+foo
+
+
+`+tail,
+ "more",
+ "and more")
+ }
diff --git a/libgo/go/cmd/gofmt/testdata/stdin6.input b/libgo/go/cmd/gofmt/testdata/stdin6.input
new file mode 100644
index 0000000000..78330020c6
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin6.input
@@ -0,0 +1,21 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f:=func( hat, tail string){
+
+
+
+ fmt. Println ( hat+ `
+foo
+
+
+`+ tail ,
+ "more" ,
+ "and more" )
+ }
diff --git a/libgo/go/cmd/gofmt/testdata/stdin7.golden b/libgo/go/cmd/gofmt/testdata/stdin7.golden
new file mode 100644
index 0000000000..bbac7133c8
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin7.golden
@@ -0,0 +1,19 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f := func(hat, tail string) {
+
+ fmt.Println(hat+`
+ foo
+
+
+ `+tail,
+ "more",
+ "and more")
+ }
diff --git a/libgo/go/cmd/gofmt/testdata/stdin7.input b/libgo/go/cmd/gofmt/testdata/stdin7.input
new file mode 100644
index 0000000000..fd772a3c4e
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin7.input
@@ -0,0 +1,21 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f:=func( hat, tail string){
+
+
+
+ fmt. Println ( hat+ `
+ foo
+
+
+ `+ tail ,
+ "more" ,
+ "and more" )
+ }
diff --git a/libgo/go/cmd/internal/browser/browser.go b/libgo/go/cmd/internal/browser/browser.go
new file mode 100644
index 0000000000..897086f471
--- /dev/null
+++ b/libgo/go/cmd/internal/browser/browser.go
@@ -0,0 +1,46 @@
+// 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 browser provides utilities for interacting with users' browsers.
+package browser
+
+import (
+ "os"
+ "os/exec"
+ "runtime"
+)
+
+// Commands returns a list of possible commands to use to open a url.
+func Commands() [][]string {
+ var cmds [][]string
+ if exe := os.Getenv("BROWSER"); exe != "" {
+ cmds = append(cmds, []string{exe})
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ cmds = append(cmds, []string{"/usr/bin/open"})
+ case "windows":
+ cmds = append(cmds, []string{"cmd", "/c", "start"})
+ default:
+ cmds = append(cmds, []string{"xdg-open"})
+ }
+ cmds = append(cmds,
+ []string{"chrome"},
+ []string{"google-chrome"},
+ []string{"chromium"},
+ []string{"firefox"},
+ )
+ return cmds
+}
+
+// Open tries to open url in a browser and reports whether it succeeded.
+func Open(url string) bool {
+ for _, args := range Commands() {
+ cmd := exec.Command(args[0], append(args[1:], url)...)
+ if cmd.Start() == nil {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go
index 6897957270..42788443bc 100644
--- a/libgo/go/compress/bzip2/bzip2.go
+++ b/libgo/go/compress/bzip2/bzip2.go
@@ -27,9 +27,8 @@ type reader struct {
blockCRC uint32
wantBlockCRC uint32
setupDone bool // true if we have parsed the bzip2 header.
- blockSize int // blockSize in bytes, i.e. 900 * 1024.
+ blockSize int // blockSize in bytes, i.e. 900 * 1000.
eof bool
- buf []byte // stores Burrows-Wheeler transformed data.
c [256]uint // the `C' array for the inverse BWT.
tt []uint32 // mirrors the `tt' array in the bzip2 source and contains the P array in the upper 24 bits.
tPos uint32 // Index of the next output byte in tt.
@@ -76,7 +75,7 @@ func (bz2 *reader) setup(needMagic bool) error {
}
bz2.fileCRC = 0
- bz2.blockSize = 100 * 1024 * (int(level) - '0')
+ bz2.blockSize = 100 * 1000 * (level - '0')
if bz2.blockSize > len(bz2.tt) {
bz2.tt = make([]uint32, bz2.blockSize)
}
@@ -294,7 +293,7 @@ func (bz2 *reader) readBlock() (err error) {
if c >= numHuffmanTrees {
return StructuralError("tree index too large")
}
- treeIndexes[i] = uint8(mtfTreeDecoder.Decode(c))
+ treeIndexes[i] = mtfTreeDecoder.Decode(c)
}
// The list of symbols for the move-to-front transform is taken from
@@ -319,6 +318,9 @@ func (bz2 *reader) readBlock() (err error) {
length := br.ReadBits(5)
for j := range lengths {
for {
+ if length < 1 || length > 20 {
+ return StructuralError("Huffman length out of range")
+ }
if !br.ReadBit() {
break
}
@@ -328,9 +330,6 @@ func (bz2 *reader) readBlock() (err error) {
length++
}
}
- if length < 0 || length > 20 {
- return StructuralError("Huffman length out of range")
- }
lengths[j] = uint8(length)
}
huffmanTrees[i], err = newHuffmanTree(lengths)
@@ -400,7 +399,7 @@ func (bz2 *reader) readBlock() (err error) {
return StructuralError("repeats past end of block")
}
for i := 0; i < repeat; i++ {
- b := byte(mtf.First())
+ b := mtf.First()
bz2.tt[bufIndex] = uint32(b)
bz2.c[b]++
bufIndex++
@@ -421,7 +420,7 @@ func (bz2 *reader) readBlock() (err error) {
// it's always referenced with a run-length of 1. Thus 0
// doesn't need to be encoded and we have |v-1| in the next
// line.
- b := byte(mtf.Decode(int(v - 1)))
+ b := mtf.Decode(int(v - 1))
if bufIndex >= bz2.blockSize {
return StructuralError("data exceeds block size")
}
diff --git a/libgo/go/compress/bzip2/bzip2_test.go b/libgo/go/compress/bzip2/bzip2_test.go
index 7293d4e3be..95fb189585 100644
--- a/libgo/go/compress/bzip2/bzip2_test.go
+++ b/libgo/go/compress/bzip2/bzip2_test.go
@@ -6,418 +6,233 @@ package bzip2
import (
"bytes"
- "encoding/base64"
"encoding/hex"
+ "fmt"
"io"
"io/ioutil"
"testing"
)
-func TestBitReader(t *testing.T) {
- buf := bytes.NewReader([]byte{0xaa})
- br := newBitReader(buf)
- if n := br.ReadBits(1); n != 1 {
- t.Errorf("read 1 wrong")
- }
- if n := br.ReadBits(1); n != 0 {
- t.Errorf("read 2 wrong")
- }
- if n := br.ReadBits(1); n != 1 {
- t.Errorf("read 3 wrong")
- }
- if n := br.ReadBits(1); n != 0 {
- t.Errorf("read 4 wrong")
- }
-}
-
-func TestBitReaderLarge(t *testing.T) {
- buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
- br := newBitReader(buf)
- if n := br.ReadBits(32); n != 0x12345678 {
- t.Errorf("got: %x want: %x", n, 0x12345678)
- }
-}
-
-func readerFromHex(s string) io.Reader {
- data, err := hex.DecodeString(s)
+func mustDecodeHex(s string) []byte {
+ b, err := hex.DecodeString(s)
if err != nil {
- panic("readerFromHex: bad input")
+ panic(err)
}
- return bytes.NewReader(data)
+ return b
}
-func decompressHex(s string) (out []byte, err error) {
- r := NewReader(readerFromHex(s))
- return ioutil.ReadAll(r)
-}
-
-func TestHelloWorldBZ2(t *testing.T) {
- out, err := decompressHex(helloWorldBZ2Hex)
- if err != nil {
- t.Errorf("error from Read: %s", err)
- return
- }
-
- if !bytes.Equal(helloWorld, out) {
- t.Errorf("got %x, want %x", out, helloWorld)
- }
-}
-
-func TestConcat(t *testing.T) {
- out, err := decompressHex(helloWorldBZ2Hex + helloWorldBZ2Hex)
+func mustLoadFile(f string) []byte {
+ b, err := ioutil.ReadFile(f)
if err != nil {
- t.Errorf("error from Read: %s", err)
- return
- }
-
- hello2 := bytes.Repeat(helloWorld, 2)
- if !bytes.Equal(hello2, out) {
- t.Errorf("got %x, want %x", out, hello2)
+ panic(err)
+ }
+ return b
+}
+
+func trim(b []byte) string {
+ const limit = 1024
+ if len(b) < limit {
+ return fmt.Sprintf("%q", b)
+ }
+ return fmt.Sprintf("%q...", b[:limit])
+}
+
+func TestReader(t *testing.T) {
+ var vectors = []struct {
+ desc string
+ input []byte
+ output []byte
+ fail bool
+ }{{
+ desc: "hello world",
+ input: mustDecodeHex("" +
+ "425a68393141592653594eece83600000251800010400006449080200031064c" +
+ "4101a7a9a580bb9431f8bb9229c28482776741b0",
+ ),
+ output: []byte("hello world\n"),
+ }, {
+ desc: "concatenated files",
+ input: mustDecodeHex("" +
+ "425a68393141592653594eece83600000251800010400006449080200031064c" +
+ "4101a7a9a580bb9431f8bb9229c28482776741b0425a68393141592653594eec" +
+ "e83600000251800010400006449080200031064c4101a7a9a580bb9431f8bb92" +
+ "29c28482776741b0",
+ ),
+ output: []byte("hello world\nhello world\n"),
+ }, {
+ desc: "32B zeros",
+ input: mustDecodeHex("" +
+ "425a6839314159265359b5aa5098000000600040000004200021008283177245" +
+ "385090b5aa5098",
+ ),
+ output: make([]byte, 32),
+ }, {
+ desc: "1MiB zeros",
+ input: mustDecodeHex("" +
+ "425a683931415926535938571ce50008084000c0040008200030cc0529a60806" +
+ "c4201e2ee48a70a12070ae39ca",
+ ),
+ output: make([]byte, 1<<20),
+ }, {
+ desc: "random data",
+ input: mustLoadFile("testdata/pass-random1.bz2"),
+ output: mustLoadFile("testdata/pass-random1.bin"),
+ }, {
+ desc: "random data - full symbol range",
+ input: mustLoadFile("testdata/pass-random2.bz2"),
+ output: mustLoadFile("testdata/pass-random2.bin"),
+ }, {
+ desc: "random data - uses RLE1 stage",
+ input: mustDecodeHex("" +
+ "425a6839314159265359d992d0f60000137dfe84020310091c1e280e100e0428" +
+ "01099210094806c0110002e70806402000546034000034000000f28300000320" +
+ "00d3403264049270eb7a9280d308ca06ad28f6981bee1bf8160727c7364510d7" +
+ "3a1e123083421b63f031f63993a0f40051fbf177245385090d992d0f60",
+ ),
+ output: mustDecodeHex("" +
+ "92d5652616ac444a4a04af1a8a3964aca0450d43d6cf233bd03233f4ba92f871" +
+ "9e6c2a2bd4f5f88db07ecd0da3a33b263483db9b2c158786ad6363be35d17335" +
+ "ba",
+ ),
+ }, {
+ desc: "1MiB sawtooth",
+ input: mustLoadFile("testdata/pass-sawtooth.bz2"),
+ output: func() []byte {
+ b := make([]byte, 1<<20)
+ for i := range b {
+ b[i] = byte(i)
+ }
+ return b
+ }(),
+ }, {
+ desc: "RLE2 buffer overrun - issue 5747",
+ input: mustLoadFile("testdata/fail-issue5747.bz2"),
+ fail: true,
+ }, {
+ desc: "out-of-range selector - issue 8363",
+ input: mustDecodeHex("" +
+ "425a68393141592653594eece83600000251800010400006449080200031064c" +
+ "4101a7a9a580bb943117724538509000000000",
+ ),
+ fail: true,
+ }, {
+ desc: "bad block size - issue 13941",
+ input: mustDecodeHex("" +
+ "425a683131415926535936dc55330063ffc0006000200020a40830008b0008b8" +
+ "bb9229c28481b6e2a998",
+ ),
+ fail: true,
+ }, {
+ desc: "bad huffman delta",
+ input: mustDecodeHex("" +
+ "425a6836314159265359b1f7404b000000400040002000217d184682ee48a70a" +
+ "12163ee80960",
+ ),
+ fail: true,
+ }}
+
+ for i, v := range vectors {
+ rd := NewReader(bytes.NewReader(v.input))
+ buf, err := ioutil.ReadAll(rd)
+
+ if fail := bool(err != nil); fail != v.fail {
+ if fail {
+ t.Errorf("test %d (%s), unexpected failure: %v", i, v.desc, err)
+ } else {
+ t.Errorf("test %d (%s), unexpected success", i, v.desc)
+ }
+ }
+ if !v.fail && !bytes.Equal(buf, v.output) {
+ t.Errorf("test %d (%s), output mismatch:\ngot %s\nwant %s", i, v.desc, trim(buf), trim(v.output))
+ }
}
}
-func testZeros(t *testing.T, inHex string, n int) {
- out, err := decompressHex(inHex)
- if err != nil {
- t.Errorf("error from Read: %s", err)
- return
- }
-
- expected := make([]byte, n)
-
- if !bytes.Equal(expected, out) {
- allZeros := true
- for _, b := range out {
- if b != 0 {
- allZeros = false
- break
+func TestBitReader(t *testing.T) {
+ var vectors = []struct {
+ nbits uint // Number of bits to read
+ value int // Expected output value (0 for error)
+ fail bool // Expected operation failure?
+ }{
+ {nbits: 1, value: 1},
+ {nbits: 1, value: 0},
+ {nbits: 1, value: 1},
+ {nbits: 5, value: 11},
+ {nbits: 32, value: 0x12345678},
+ {nbits: 15, value: 14495},
+ {nbits: 3, value: 6},
+ {nbits: 6, value: 13},
+ {nbits: 1, fail: true},
+ }
+
+ rd := bytes.NewReader([]byte{0xab, 0x12, 0x34, 0x56, 0x78, 0x71, 0x3f, 0x8d})
+ br := newBitReader(rd)
+ for i, v := range vectors {
+ val := br.ReadBits(v.nbits)
+ if fail := bool(br.err != nil); fail != v.fail {
+ if fail {
+ t.Errorf("test %d, unexpected failure: ReadBits(%d) = %v", i, v.nbits, br.err)
+ } else {
+ t.Errorf("test %d, unexpected success: ReadBits(%d) = nil", i, v.nbits)
}
}
- t.Errorf("incorrect result, got %d bytes (allZeros: %t)", len(out), allZeros)
+ if !v.fail && val != v.value {
+ t.Errorf("test %d, mismatching value: ReadBits(%d) = %d, want %d", i, v.nbits, val, v.value)
+ }
}
}
-func Test32Zeros(t *testing.T) {
- testZeros(t, thirtyTwoZerosBZ2Hex, 32)
-}
-
-func Test1MBZeros(t *testing.T) {
- testZeros(t, oneMBZerosBZ2Hex, 1024*1024)
-}
-
-func testRandomData(t *testing.T, compressedHex, uncompressedHex string) {
- out, err := decompressHex(compressedHex)
- if err != nil {
- t.Errorf("error from Read: %s", err)
- return
+func TestMTF(t *testing.T) {
+ var vectors = []struct {
+ idx int // Input index
+ sym uint8 // Expected output symbol
+ }{
+ {idx: 1, sym: 1}, // [1 0 2 3 4]
+ {idx: 0, sym: 1}, // [1 0 2 3 4]
+ {idx: 1, sym: 0}, // [0 1 2 3 4]
+ {idx: 4, sym: 4}, // [4 0 1 2 3]
+ {idx: 1, sym: 0}, // [0 4 1 2 3]
}
- expected, _ := hex.DecodeString(uncompressedHex)
-
- if !bytes.Equal(out, expected) {
- t.Errorf("incorrect result\ngot: %x\nwant: %x", out, expected)
+ mtf := newMTFDecoderWithRange(5)
+ for i, v := range vectors {
+ sym := mtf.Decode(v.idx)
+ t.Log(mtf)
+ if sym != v.sym {
+ t.Errorf("test %d, symbol mismatch: Decode(%d) = %d, want %d", i, v.idx, sym, v.sym)
+ }
}
}
-func TestRandomData1(t *testing.T) {
- testRandomData(t, randBZ2Hex, randHex)
-}
-
-func TestRandomData2(t *testing.T) {
- // This test involves several repeated bytes in the output, but they
- // should trigger RLE decoding.
- testRandomData(t, rand2BZ2Hex, rand2Hex)
-}
-
-func TestRandomData3(t *testing.T) {
- // This test uses the full range of symbols.
- testRandomData(t, rand3BZ2Hex, rand3Hex)
-}
-
-func Test1MBSawtooth(t *testing.T) {
- out, err := decompressHex(oneMBSawtoothBZ2Hex)
+func benchmarkDecode(b *testing.B, compressed []byte) {
+ // Determine the uncompressed size of testfile.
+ uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
if err != nil {
- t.Errorf("error from Read: %s", err)
- return
- }
-
- expected := make([]byte, 1024*1024)
-
- for i := range expected {
- expected[i] = byte(i)
- }
-
- if !bytes.Equal(out, expected) {
- t.Error("incorrect result")
+ b.Fatal(err)
}
-}
-
-const helloWorldBZ2Hex = "425a68393141592653594eece83600000251800010400006449080200031064c4101a7a9a580bb9431f8bb9229c28482776741b0"
-var helloWorld = []byte("hello world\n")
+ b.SetBytes(uncompressedSize)
+ b.ReportAllocs()
+ b.ResetTimer()
-const thirtyTwoZerosBZ2Hex = "425a6839314159265359b5aa5098000000600040000004200021008283177245385090b5aa5098"
-const oneMBZerosBZ2Hex = "425a683931415926535938571ce50008084000c0040008200030cc0529a60806c4201e2ee48a70a12070ae39ca"
-
-const randBZ2Hex = "425a6839314159265359905d990d0001957fffffffffffafffffffffffffffffbfff6fffdfffffffffffffffffffffffffffffc002b6dd75676ed5b77720098320d11a64626981323d4da47a83131a13d09e8040f534cd4f4d27a464d193008cd09804601347a980026350c9886234d36864193d1351b44c136919e90340d26127a4cd264c32023009898981310c0344c340027a8303427a99a04c00003534c230d034f5006468d268cf54d36a3009a69a62626261311b40026013d34201a6934c9a604c98ca6c8460989fa9346234d30d3469a2604fd4131a7aa6d0046043d4c62098479269e89e835190d018d4c046001a11e801a0264792321932308c43a130688c260d46686804cd01a9e80981193684c6a68c00000004c4c20c04627a4c0000260003400d04c0681a01334026009a6f48041466132581ec5212b081d96b0effc16543e2228b052fcd30f2567ee8d970e0f10aabca68dd8270591c376cfc1baae0dba00aaff2d6caf6b211322c997cc18eaee5927f75185336bf907021324c71626c1dd20e22b9b0977f05d0f901eaa51db9fbaf7c603b4c87bc82890e6dd7e61d0079e27ec050dd788fd958152061cd01e222f9547cb9efc465d775b6fc98bac7d387bffd151ae09dadf19494f7a638e2eae58e550faba5fe6820ea520eb986096de4e527d80def3ba625e71fbefdcf7e7844e0a25d29b52dcd1344fca083737d42692aab38d230485f3c8ed54c2ed31f15cf0270c8143765b10b92157233fa1dfe0d7ce8ffe70b8b8f7250071701dfe9f1c94de362c9031455951c93eb098a6b50ee45c6131fefc3b6f9643e21f4adc59497138e246f5c57d834aa67c4f10d8bd8b3908d8130dd7388409c299a268eab3664fa4907c5c31574874bd8d388a4ab22b339660804e53e1b8d05867d40e3082560608d35d5d2c6054e8bab23da28f61f83efd41d25529ad6ea15fb50505cacfabb0902166427354ca3830a2c8415f21b19e592690fbe447020d685a4bcd16ecc4ff1a1c0e572627d0ef6265c008a43fc243240541061ed7840606be466d1c0dac2c53250ed567507d926c844154560d631960c65e15157829b2c7f16859f111a3a8cb72bf24ffa57a680c3be67b1be67c8dd8aea73ac2437a78df5b686d427080ebc01bd30b71a49f6ea31dc0f08e4849e38face96717690239538bc08b6cc5aa8d467cb9c36aa83d40ac7e58bddbfa185b22065e89a86c0145569d9e23726651aec49e31588d70f40fe9a4449dcf4f89eac220171e9c938e803dc195679651004b79ad33cc0c13aeeba5941b33ffeeb8fbe16e76c7811445c67b4269c90479433ddf9e8ed1d00c166b6c17217fb22c3ef1b0c1c7e28e185446a111c37f1ea6c07a59fbcc6546ecc6968d36ba58bc5489a5640647e426b0c39350cb6f07d5dc7a717648c4ec7f841467597ae1f65f408fd2d9940a4b1b860b3c9ae351dcae0b4425f7e8538710f2e40b7f70d13b51ac05ccc6ecda8264a88cad2d721d18132a9b9110a9e759c2483c77dcefc7e464ec88588174cb0c9abff93230ea0bed8decdd8ed8bfe2b5df0a253803678df04fab44c03b9ab7cc97d6e6d6fd0c4c840ce0efc498436f453bbb181603459471f2b588724592b222ec990614db530e10cadd84705621cfdd9261fa44a5f5806a2d74b575056b3c915255c65678f9c16e6dc00a99180fef1a840aff0e842ac02731080cc92782538360a60a727991013984da4fad95f79d5030677b7528d076b2483685fca4429edf804682fdc110dfc2f7c30e23e20a72e039108a0ad6fdee2f76985a4b4be4f5afc6101bf9d5042b657a05dc914e1424241766434"
-const randHex = "c95138082bdf2b9bfa5b1072b23f729735d42c785eeb94320fb14c265b9c2ca421d01a3db986df1ac2acde5a0e6bf955d6f95e61261540905928e195f1a66644cc7f37281744fff4dc6df35566a494c41a8167151950eb74f5fc45f85ad0e5ed28b49adfe218aa7ec1707e8e1d55825f61f72beda3b4c006b8c9188d7336a5d875329b1b58c27cc4e89ecbae02c7712400c39dd131d2c6de82e2863da51d472bdfb21ecce62cc9cf769ed28aedc7583d755da45a0d90874bda269dd53283a9bdfd05f95fc8e9a304bb338ea1a2111894678c18134f17d31a15d9bfc1237894650f3e715e2548639ecbddb845cfe4a46a7b3a3c540f48629488e8c869f1e9f3f4c552243a8105b20eb8e264994214349dae83b165fd6c2a5b8e83fce09fc0a80d3281c8d53a9a08095bd19cbc1388df23975646ed259e003d39261ee68cbece8bcf32971f7fe7e588e8ba8f5e8597909abaea693836a79a1964050ed910a45a0f13a58cd2d3ae18992c5b23082407fd920d0bf01e33118a017bb5e39f44931346845af52128f7965206759433a346034ea481671f501280067567619f5ecef6cded077f92ed7f3b3ce8e308c80f34ba06939e9303f91b4318c8c1dd4cc223c1f057ac0c91211c629cd30e46ee9ec1d9fd493086b7bc2bc83e33f08749a5d430b0ed4f79d70f481940c9b0930b16321886a0df4fa5a1465d5208c7d3494a7987d9a5e42aa256f0c9523947f8318d0ef0af3d59a45cfc2418d0785c9a548b32b81e7de18be7d55a69a4c156bbb3d7579c0ac8e9c72b24646e54b0d0e8725f8f49fb44ae3c6b9d0287be118586255a90a4a83483ed0328518037e52aa959c5748ed83e13023e532306be98b8288da306bbb040bcf5d92176f84a9306dc6b274b040370b61d71fde58dd6d20e6fee348eae0c54bd0a5a487b2d005f329794f2a902c296af0a4c1f638f63292a1fa18e006c1b1838636f4de71c73635b25660d32e88a0917e1a5677f6a02ca65585b82cbd99fb4badbfa97a585da1e6cadf6737b4ec6ca33f245d66ee6a9fae6785d69b003c17b9fc6ec34fe5824ab8caae5e8e14dc6f9e116e7bf4a60c04388783c8ae929e1b46b3ef3bbe81b38f2fa6da771bf39dfba2374d3d2ed356b8e2c42081d885a91a3afb2f31986d2f9873354c48cf5448492c32e62385af423aa4f83db6d1b2669650379a1134b0a04cbca0862d6f9743c791cbb527d36cd5d1f0fc7f503831c8bd1b7a0ef8ae1a5ed1155dfdd9e32b6bb33138112d3d476b802179cb85a2a6c354ccfed2f31604fbd8d6ec4baf9f1c8454f72c6588c06a7df3178c43a6970bfa02dd6f74cb5ec3b63f9eddaa17db5cbf27fac6de8e57c384afd0954179f7b5690c3bee42abc4fa79b4b12101a9cf5f0b9aecdda945def0bd04163237247d3539850e123fe18139f316fa0256d5bd2faa8"
-
-const oneMBSawtoothBZ2Hex = "425a683931415926535971931ea00006ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe007de00000000000000024c00130001300000000000000000000000000000000000000000000000000000000126000980009800000000000000000000000000000000000000000000000000000000930004c0004c000000000000000000000000000000000000000000000000000000004980026000260000000000000000000000000000000000000000000000000000000009aaaaa0000000000000000000000000000000000000000000000000000000000000000498002600026000000000000000000000000000000000000000000000000000000007fc42271980d044c0a822607411304a08982d044c1a82260f411308a08984d044c2a82261741130ca08986d044c3a82261f411310a08988d044c4a822627411314a0898ad044c5a82262f411318a0898cd044c6a82263741131ca0898ed044c7a82263f411320a08990d044c8a822647411324a08992d044c9a82264f411328a08994d044caa82265741132ca08996d044cba82265f411330a08998d044cca822667411334a0899ad044cda82266f411338a0899cd044cea82267741133ca0899ed044cfa82267f411340a089a0d044d0a822687411344a089a2d044d1a82268f411348a089a4d044d2a82269741134ca089a6d044d3a82269f411350a089a8d044d4a8226a7411354a089aad044d5a8226af411358a089acd044d6a8226b741135ca089aed044d7a8226bf411360a089b0d044d8a8226c7411364a089b2d044d9a8226cf411368a089b4d044daa8226d741136ca089b6d044dba8226df411370a089b8d044dca8226e7411374a089bad044dda8226ef411378a089bcd044dea8226f741137ca089bed044dfa8226ff411380a089c0d044e0a822707411384a089c2d044e1a82270f411388a089c4d044e2a82271741138ca089c59089c69089c71089c79089c81089c89089c91089c99089ca1089ca9089cb1089cb9089cc1089cc9089cd1089cd9089ce1089ce9089cf1089cf9089d01089d09089d11089d19089d21089d29089d31089d39089d41089d49089d51089d59089d61089d69089d71089d79089d81089d89089d91089d99089da1089da9089db1089db9089dc1089dc9089dd1089dd9089de1089de9089df1089df9089e01089e09089e11089e19089e21089e29089e31089e39089e41089e49089e51089e59089e61089e69089e71089e79089e81089e89089e91089e99089ea1089ea9089eb1089eb9089ec1089ec9089ed1089ed9089ee1089ee9089ef1089ef9089f01089f09089f11089f19089f21089f29089f31089f39089f41089f49089f51089f59089f61089f69089f71089f79089f81089f89089f91089f99089fa1089fa9089fb1089fb9089fc1089fc9089fd1089fd9089fe1089fe9089ff1089ff98a0ac9329acf23ba884804fdd3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0034f800000000000024c00130001300000000000000000000000000000000000000000000000000000000126000980009800000000000000000000000000000000000000000000000000000000930004c0004c000000000000000000000000000000000000000000000000000000004980026000260000000000000000000000000000000000000000000000000000000024c0013000130000000000000000000000000000000000000000000000000000000002955540000000000000000000000000000000000000000000000000000000000000001ff108c00846024230221181908c108460a4230621183908c20846124230a21185908c308461a4230e21187908c40846224231221189908c508462a423162118b908c60846324231a2118d908c708463a4231e2118f908c80846424232221191908c908464a4232621193908ca0846524232a21195908cb08465a4232e21197908cc0846624233221199908cd08466a423362119b908ce0846724233a2119d908cf08467a4233e2119f908d008468242342211a1908d108468a42346211a3908d20846924234a211a5908d308469a4234e211a7908d40846a242352211a9908d50846aa42356211ab908d60846b24235a211ad908d70846ba4235e211af908d80846c242362211b1908d90846ca42366211b3908da0846d24236a211b5908db0846da4236e211b7908dc0846e242372211b9908dd0846ea42376211bb908de0846f24237a211bd908df0846fa4237e211bf908e008470242382211c1908e108470a42386211c3908e20847124238a211c5908e2f8c211c6c8471d211c7c84721211c8c84725211c9c84729211cac8472d211cbc84731211ccc84735211cdc84739211cec8473d211cfc84741211d0c84745211d1c84749211d2c8474d211d3c84751211d4c84755211d5c84759211d6c8475d211d7c84761211d8c84765211d9c84769211dac8476d211dbc84771211dcc84775211ddc84779211dec8477d211dfc84781211e0c84785211e1c84789211e2c8478d211e3c84791211e4c84795211e5c84799211e6c8479d211e7c847a1211e8c847a5211e9c847a9211eac847ad211ebc847b1211ecc847b5211edc847b9211eec847bd211efc847c1211f0c847c5211f1c847c9211f2c847cd211f3c847d1211f4c847d5211f5c847d9211f6c847dd211f7c847e1211f8c847e5211f9c847e9211fac847ed211fbc847f1211fcc847f5211fdc847f9211fec847fd211ff8bb9229c284803a8b6248"
-
-const rand2BZ2Hex = "425a6839314159265359d992d0f60000137dfe84020310091c1e280e100e042801099210094806c0110002e70806402000546034000034000000f2830000032000d3403264049270eb7a9280d308ca06ad28f6981bee1bf8160727c7364510d73a1e123083421b63f031f63993a0f40051fbf177245385090d992d0f60"
-const rand2Hex = "92d5652616ac444a4a04af1a8a3964aca0450d43d6cf233bd03233f4ba92f8719e6c2a2bd4f5f88db07ecd0da3a33b263483db9b2c158786ad6363be35d17335ba"
-
-const rand3BZ2Hex = "425a68393141592653593be669d00000327ffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffc002b3b2b1b6e2bae400004c00132300004c0d268c004c08c0130026001a008683234c0684c34008c230261a04c0260064d07a8d00034000d27a1268c9931a8d327a3427a41faa69ea0da264c1a34219326869b51b49a6469a3268c689fa53269a62794687a9a68f5189994c9e487a8f534fd49a3d34043629e8c93d04da4f4648d30d4f44d3234c4d3023d0840680984d309934c234d3131a000640984f536a6132601300130130c8d00d04d1841ea7a8d31a02609b40023460010c01a34d4c1a0d04d3069306810034d0d0d4c0046130d034d0131a9a64d321804c68003400098344c13000991808c0001a00000000098004d3d4da4604c47a13012140aadf8d673c922c607ef6212a8c0403adea4b28aee578900e653b9cdeb8d11e6b838815f3ebaad5a01c5408d84a332170aff8734d4e06612d3c2889f31925fb89e33561f5100ae89b1f7047102e729373d3667e58d73aaa80fa7be368a1cc2dadd81d81ec8e1b504bd772ca31d03649269b01ceddaca07bf3d4eba24de141be3f86f93601e03714c0f64654671684f9f9528626fd4e1b76753dc0c54b842486b8d59d8ab314e86ca818e7a1f079463cbbd70d9b79b283c7edc419406311022e4be98c2c1374df9cdde2d008ce1d00e5f06ad1024baf555631f70831fc1023034e62be7c4bcb648caf276963ffa20e96bb50377fe1c113da0db4625b50741c35a058edb009c6ee5dbf93b8a6b060eec568180e8db791b82aab96cbf4326ca98361461379425ba8dcc347be670bdba7641883e5526ae3d833f6e9cb9bac9557747c79e206151072f7f0071dff3880411846f66bf4075c7462f302b53cb3400a74cf35652ad5641ed33572fd54e7ed7f85f58a0acba89327e7c6be5c58cb71528b99df2431f1d0358f8d28d81d95292da631fb06701decabb205fac59ff0fb1df536afc681eece6ea658c4d9eaa45f1342aa1ff70bdaff2ddaf25ec88c22f12829a0553db1ec2505554cb17d7b282e213a5a2aa30431ded2bce665bb199d023840832fedb2c0c350a27291407ff77440792872137df281592e82076a05c64c345ffb058c64f7f7c207ef78420b7010520610f17e302cc4dfcfaef72a0ed091aab4b541eb0531bbe941ca2f792bf7b31ca6162882b68054a8470115bc2c19f2df2023f7800432b39b04d3a304e8085ba3f1f0ca5b1ba4d38d339e6084de979cdea6d0e244c6c9fa0366bd890621e3d30846f5e8497e21597b8f29bbf52c961a485dfbea647600da0fc1f25ce4d203a8352ece310c39073525044e7ac46acf2ed9120bae1b4f6f02364abfe343f80b290983160c103557af1c68416480d024cc31b6c06cfec011456f1e95c420a12b48b1c3fe220c2879a982fb099948ac440db844b9a112a5188c7783fd3b19593290785f908d95c9db4b280bafe89c1313aeec24772046d9bc089645f0d182a21184e143823c5f52de50e5d7e98d3d7ab56f5413bbccd1415c9bcff707def475b643fb7f29842582104d4cc1dbaaca8f10a2f44273c339e0984f2b1e06ab2f0771db01fafa8142298345f3196f23e5847bda024034b6f59b11c29e981c881456e40d211929fd4f766200258aad8212016322bd5c605790dcfdf1bd2a93d99c9b8f498722d311d7eae7ff420496a31804c55f4759a7b13aaaf5f7ce006c3a8a998897d5e0a504398c2b627852545baf440798bcc5cc049357cf3f17d9771e4528a1af3d77dc794a11346e1bdf5efe37a405b127b4c43b616d61fbc5dc914e14240ef99a7400"
-const rand3Hex = "1744b384d68c042371244e13500d4bfb98c6244e3d71a5b700224420b59c593553f33bd786e3d0ce31626f511bc985f59d1a88aa38ba8ad6218d306abee60dd9172540232b95be1af146c69e72e5fde667a090dc3f93bdc5c5af0ab80acdbaa7a505f628c59dc0247b31a439cacf5010a94376d71521df08c178b02fb96fdb1809144ea38c68536187c53201fea8631fb0a880b4451ccdca7cc61f6aafca21cc7449d920599db61789ac3b1e164b3390124f95022aeea39ccca3ec1053f4fa10de2978e2861ea58e477085c2220021a0927aa94c5d0006b5055abba340e4f9eba22e969978dfd18e278a8b89d877328ae34268bc0174cfe211954c0036f078025217d1269fac1932a03b05a0b616012271bbe1fb554171c7a59b196d8a4479f45a77931b5d97aaf6c0c673cbe597b79b96e2a0c1eae2e66e46ccc8c85798e23ffe972ebdaa3f6caea243c004e60321eb47cd79137d78fd0613be606feacc5b3637bdc96a89c13746db8cad886f3ccf912b2178c823bcac395f06d28080269bdca2debf3419c66c690fd1adcfbd53e32e79443d7a42511a84cb22ca94fffad9149275a075b2f8ae0b021dcde9bf62b102db920733b897560518b06e1ad7f4b03458493ddaa7f4fa2c1609f7a1735aeeb1b3e2cea3ab45fc376323cc91873b7e9c90d07c192e38d3f5dfc9bfab1fd821c854da9e607ea596c391c7ec4161c6c4493929a8176badaa5a5af7211c623f29643a937677d3df0da9266181b7c4da5dd40376db677fe8f4a1dc456adf6f33c1e37cec471dd318c2647644fe52f93707a77da7d1702380a80e14cc0fdce7bf2eed48a529090bae0388ee277ce6c7018c5fb00b88362554362205c641f0d0fab94fd5b8357b5ff08b207fee023709bc126ec90cfb17c006754638f8186aaeb1265e80be0c1189ec07d01d5f6f96cb9ce82744147d18490de7dc72862f42f024a16968891a356f5e7e0e695d8c933ba5b5e43ad4c4ade5399bc2cae9bb6189b7870d7f22956194d277f28b10e01c10c6ffe3e065f7e2d6d056aa790db5649ca84dc64c35566c0af1b68c32b5b7874aaa66467afa44f40e9a0846a07ae75360a641dd2acc69d93219b2891f190621511e62a27f5e4fbe641ece1fa234fc7e9a74f48d2a760d82160d9540f649256b169d1fed6fbefdc491126530f3cbad7913e19fbd7aa53b1e243fbf28d5f38c10ebd77c8b986775975cc1d619efb27cdcd733fa1ca36cffe9c0a33cc9f02463c91a886601fd349efee85ef1462065ef9bd2c8f533220ad93138b8382d5938103ab25b2d9af8ae106e1211eb9b18793fba033900c809c02cd6d17e2f3e6fc84dae873411f8e87c3f0a8f1765b7825d185ce3730f299c3028d4a62da9ee95c2b870fb70c79370d485f9d5d9acb78926d20444033d960524d2776dc31988ec7c0dbf23b9905d"
-
-const (
- digits = iota
- twain
- random
-)
-
-var testfiles = []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.bz2",
- // Twain is Mark Twain's classic English novel.
- twain: "testdata/Mark.Twain-Tom.Sawyer.txt.bz2",
- // 16KB of random data from /dev/urandom
- random: "testdata/random.data.bz2",
-}
-
-func benchmarkDecode(b *testing.B, testfile int) {
- compressed, err := ioutil.ReadFile(testfiles[testfile])
- if err != nil {
- b.Fatal(err)
- }
- b.SetBytes(int64(len(compressed)))
for i := 0; i < b.N; i++ {
r := bytes.NewReader(compressed)
io.Copy(ioutil.Discard, NewReader(r))
}
}
-func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
-func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
-func BenchmarkDecodeRand(b *testing.B) { benchmarkDecode(b, random) }
-
-func TestBufferOverrun(t *testing.T) {
- // Tests https://golang.org/issue/5747.
- buffer := bytes.NewReader([]byte(bufferOverrunBase64))
- decoder := base64.NewDecoder(base64.StdEncoding, buffer)
- decompressor := NewReader(decoder)
- // This shouldn't panic.
- ioutil.ReadAll(decompressor)
-}
-
-func TestOutOfRangeSelector(t *testing.T) {
- // Tests https://golang.org/issue/8363.
- buffer := bytes.NewReader(outOfRangeSelector)
- decompressor := NewReader(buffer)
- // This shouldn't panic.
- ioutil.ReadAll(decompressor)
+func BenchmarkDecodeDigits(b *testing.B) {
+ digits := mustLoadFile("testdata/e.txt.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, digits)
}
-
-func TestMTF(t *testing.T) {
- mtf := newMTFDecoderWithRange(5)
-
- // 0 1 2 3 4
- expect := byte(1)
- x := mtf.Decode(1)
- if x != expect {
- t.Errorf("expected %v, got %v", expect, x)
- }
-
- // 1 0 2 3 4
- x = mtf.Decode(0)
- if x != expect {
- t.Errorf("expected %v, got %v", expect, x)
- }
-
- // 1 0 2 3 4
- expect = byte(0)
- x = mtf.Decode(1)
- if x != expect {
- t.Errorf("expected %v, got %v", expect, x)
- }
-
- // 0 1 2 3 4
- expect = byte(4)
- x = mtf.Decode(4)
- if x != expect {
- t.Errorf("expected %v, got %v", expect, x)
- }
-
- // 4 0 1 2 3
- expect = byte(0)
- x = mtf.Decode(1)
- if x != expect {
- t.Errorf("expected %v, got %v", expect, x)
- }
+func BenchmarkDecodeTwain(b *testing.B) {
+ twain := mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, twain)
}
-
-var bufferOverrunBase64 string = `
-QlpoNTFBWSZTWTzyiGcACMP/////////////////////////////////3/7f3///
-////4N/fCZODak2Xo44GIHZgkGzDRbFAuwAAKoFV7T6AO6qwA6APb6s2rOoAkAAD
-oACUoDtndh0iQAPkAAAAaPWihQoCgr5t97Obju21ChQB0NBm3RbA7apXrRoBooAA
-AhA+IAHWl2Us3O7t9yieb3udvd76+4+fd33nd3HO1bVvfcGRne6+3vfPvfc++995
-w7k973eJhasLVec970tzDNXdX28LoPXZ3H3K9z0s5ufWAfes49d5594c3dUYtI+2
-+h1dvtpRa+uvrVEAG9bl893RVEN7cWvroSqWjPMGgAQi7Gq8TJSgKKdjKFBIB9Ae
-LqWxleu715eXe7ml9e5098Z6G1vr7t1QZ6ot76YzPd3j7333t2ql2Chm7XrA9ICQ
-VF77z3rVBWqkSXtlfb099hyezAr6USbGpICTSCFAaqHrKo+tUnm32rpE4Ue+t2mj
-bKUeipEqwc93EdhhTwmQpOhhesC9iqDSPNTWYNSnUtBdm1nsA0nqqNd7OWwDXtFL
-ONmmA6Ubke26I9UblvWIPR5VOWOnctai443URunnDy77uVC59OfRvezlDu33Z7Ly
-3NNuuHW63088xu3t3NHZhkZbG7tXRlj00qOtbaXTJUUdspTbABR9R6EUwQAEAAAA
-EMEwRpoAAAABMmhoAAjBNNAaCMhponpoGpgJpk9TEyp6niGKZkAaAEfqMQ09U80p
-+pMGSCKngIAAAAgAAg0AAJhGgABGCEaaTyTKeNI1PE0wkj01GajMSNPSZGnqbU9T
-anlPUNAHqGQ0DQAMg9TamgAAYRU/IAAICAmjQJgjQBMEwp5DTSaaYmhTeqfplPID
-U1T9TynoU82pT1NPU/VP0j1NHqRpk9TTR7SnqaNNGmmQAaAD1Aeo0PSAAAAaaBiK
-eBAQBGgIABGQA0AmBNNBoaAgaJmpglPEyYap6npiTT0agGjJjUaaDTQAAAAAAM1A
-9QAaAAAADU8iEAQAEyAJk0NNNJgIZTJ5E00YSemiaZNGm1MpGNJ+lPU9qm9U2RDM
-oY0EzJB6h6nqDID1NMBDDRpo1AGNAjCMmhkMgaYSJIgAAAQyAAEyBoATECCNhTT0
-U/IZAmCM1DSTxkzUE8p6NDaGiZGJqntTFHvUyU9qPQp7Kn5GgKNPU9QAGg9QAAA3
-wz0Pk/g/m/m9P9H4vxv2+dH3gCS8nhbbbbbYxtgNsBsG0m2MbG0NNtsbYNsaY0wb
-bBibGmm22mxptNpsaGNDTY02JsG0MY0xg2MaYNNDbGwG0L5vsK/F9DO+EAA447Kq
-p7Wdf6Y+5c20T7DfHyMXIzRKrZexw72uiQI+y55vOe52xpqbCLC2uR20JdER7Zvr
-7ufuKb6zhiBxLuj0eA27v8RpMLucw9Ohwcizi2wrpt+yU1FdpM7ZYPcwS3XTef+A
-Wzjxwhdrgw3aH1LeC1eZW900x8V9Nv4hTPXp4l067P/4ANVZFF/imOe/d5bdueam
-/DFFokQWnFaU+ZqLBCM+d0PialJQWnLqRQZk/KhfbbYc2pCUTgffcSYbrCM1N+8l
-HU6gSz+h2GJXs+tbrNviL83M97X0vcTn/F82P8wen8/3/h3sHY+sf9CSej9ThYTV
-3lQ+FUHpfpGD4kv7dYMV995dpDX/y3xR8FoXx1bjUxBTNxuutwQ/h/Eedn9wpn6w
-E3+ND8YhN1HSriIxRE/6uFyMv6/oC6Elarw3aHMMqHJkGiiz6tejmvnYLQa+Qm6G
-deZ7jXTZV6NlpocgDnRdimS06bTYSkvPAL/xoWNLkX6N6VljU0dfKSBmm2uZE/xu
-sutQ1EdP7GdjhglIq4xlOFUFEQpmX+xx7R8y6c0GSAaqusOjNZwxZRudOvmXm1tZ
-T+YnbeB2ir9eiHNrtJNSLD/J/WDyuQpwBUtLKo0krccY/wIILP7f86teb9Z/9oyz
-OX05qEWbObfhpRw+9+rCvp/35ML8KX3aHaI0n+tudbFRsV5FLW+Oa8ruLN4peyVL
-DWjTHrXNthq/s7zAJYMeFJZkZt5mT9rfpH+5g3nc+piOSZ+J5nHtOnKI7Ff8Xl+j
-0t76XTNucCHQ6whav1OHdF53TY5wuv5OzvrdnxoId8fTyUvERr0ERINu/8XxZZ5f
-B5/kTZ8bBO0wv54Jp+ED/GQI8lZHzIQCP3vfQhwnCTj9TvITic7P4mYLDbH3fyzR
-i+6EajCcpXLWSGf+ZXkOrWspDWDhXtEKas0v3UqWksqgY1rTj45krX4KihN+daXs
-pZl5WPlta5p06CX6Xm2SfzqkMw12/3ix1bpnnZ+kFeBNX7A+E9zzG6OZaN78GOpl
-9Ht/eZn9PqWdav852zr0zqkDK2H5IjdvNah+b1YVGdQGzwR4Nw+f13yEKnV+y66W
-djfq7zWp7m5w+hzfv+Ly8O7oet5Vvd8/wQvO7qzOZ2vjf9X8Tj8PnMb/nc/nKqRR
-+ml4UEhOOwfCeJEEI109CMYSh91iAJqPjMyH6KjrPD7W25llZVcREYNCTg6htbQt
-M38wYoquCWP6tdKYlVIv14xTNUeUf4El/FunCf6csZkmv+9tfWx7t59wuKIa3saU
-tZs9M+3HFOZtz3OLg/Unoaj9BYazYqA78xBU9tZzrtmF/rQL9CGJt90o/oYnSfcS
-SL3haaw351LXWQ1XOsv1SmH3v6ymuxEpPPnEDmBELaTYsvvMIWJsmPZFFww++Kd7
-s/Jo0JFeUU7uNtI+gVosAIpVVuWfI/9tOIycz7I5Z7zjV+NR2OuZbYtW5F08KX4o
-2k/xuJIchcNFPtxPfw9dkDgscRbMckyFMrzuZ3IvrcGzk0J6iI5ytrv37bGpAXMz
-WK9mMMPebepNevmLjjo/QWoM968Sjv7ldlPS5AinHcXwsFv6dmmh8lJt7UOJWoKu
-lMD1cB2ksIGpMdv8iuqR42Rn/kn+17BhhUZcwDBaUXVdX6bKW7fxlUYbq+mlqIcf
-a9v8HF87M9ANbi9bq9onf9TD7nQ6Xf6vZci8TBPX+/GI0He6j31fTVQYW+NsQxvO
-J8xrx+e58CCLQNjxeIyPt+F+qk/QMiXw+LyxGVkV/XcGQT9X03jSDP6beJ5QG1JW
-9Q3qLv/YixWI7gPV9Mrhf2oRYTc/9KLFRhkE3SjKOTKuSSBKQ24fI+hEznamH71D
-66Hwez8/0et7AtTv9zvamv2OD5He6fMV4k+ePl6+qPfO5CdHtK+eCDZL5+4f5yrl
-gTcRFiq8fXbc5IaI5fbbc1KMM/2T0Mr7+Hwaco6FtXm0fmhCgTZRqY4pKiEIfmaz
-QwHNOOCrtMJ2VwsyMumt7xsOolGnizRev6lILH43qPcczQM7Gc5zRin80YvFt1Qm
-h/57Z0auR2h0fuX50MBO4XQ+26y5l6v4j902R66c0j3z2KHstKQ04J/h6LbuNQE4
-D6cu/lyfK69DxxX8wb8XaQkMUcJdo1LzqUGDAb3Kfn/A3P/JYc99MO9qv67+SxWb
-wYTyqKdWTd+1KbR/Rcn0Io5zI/QquX7FA1bxfMytjQ/X+l0fh0Pf+Hx97meH4fQL
-7/T8/sdTm9Tn8nELvedyhydLlPPTScINdXyLIq9wgIJr4fWPbp9ZhFh/56fdSgOG
-HDXg+gkXsN2Rddr4HQ5P3u+RhLzmSjhzoqY5EsPC4QvRlX9JXjB84rPV5USR66qa
-/kjw4156GJnzoXtydKJE53t6PHfZWO+3ujsfI6iAdshc7OFzGXiZB9PtItKodhYq
-nABkTKdcpu4+TOpf9h5piX5slsaBjkeTnj/Ba02ilboQfcDVigxrYn/iTH5ySWUW
-/lHtg78s5UZM8sErwhNe3N3w+6ZOMnU+5i86/xFNtqZfDdXTGy1H3PzGbdtZXYT+
-Ixx2vpwBYzbPVYHxKosM5rPiVmcTllI9nuoSfeh9ib4foFWauOpvdmhBDqpTpKTX
-u8EO2l2Z195G2RIV7TlKSxGWjR5sl/nALu1uzBeLd9zpSujzMTd1uTX9Qk/Q1S+r
-vaW6bm8qqPO4jb6Wx6XIkm321nrIF6Ae25d1+Dpv/P5G4NoLd2j6/EtENC3FeR5z
-oo7bA+tI8yEQRhiF0z1FlJXLD5ZbhNNWQm/j/IbzRfh8JtOFZU7ruShLvHXysW9S
-9V909tr9jn8/E/Hb5N/1NVNHnZu2HIUvJvHJiHd2ucmeI9PWUMnppmE65GQ5E9xV
-ZRlGEH0X85EvmHyEupkMrCC0oMv9RCq+/H8gcfpe00Hs/S+regT5p58cyYomh93v
-qvuw/A06BE/wzJESuYbN9pqYpoXqXFemW1NksHEJ2w+PYMJ27WJyD5FpaXB85VaW
-qMOhDfO8E3QdH8ybyKt/UgI8/tDGpFbyOlaVdIv1FXJhoLp8soAA4Djg6/KZ066N
-ZFYuS8WdjpSZGP4/Lw+1yaXlzNznc/k2uHe2uXP3uFuPcHx+Dm44utxldoO1uBPy
-+jzOs14+MIgOjOHMVNqAbMd8fUedLlhJMCfMtm4uz01enLNKcMrtLlPIR37Yukh1
-YEMXYpm7eU4XU+j+Jj3pDyaXtXs+p1fWfTN/cy9/Oxs4umUXQ4uHh1kObtayDJ56
-/QMxiHobjHNKuKfMxsrYEwN+QVIyVjAwMDYuMjQ1AAA9IwJniiBLRkZDAAAXt0Ja
-aDQxQVkmU1lZtwytAACLf///////////////////+//////v//////////bv78//
-/+AXO133uwO2xB2UxIvbKXrCqCoURUBL2ytFI82AFdcOwMhVTHtk5rD3szEVNYD4
-aIQINCaMRoTaSn7SbSMJiYmEwieTEp+psqbMCp+VNPaFNpqbBNR7UmanlPUeKfqm
-j1PU0/VPU08o9Q9EeKHlPJtKbYqeTCYhN6U9T1NH6mp+lPyoGNTI/Knkyg1MggAg
-CaMEyQnqZoaaRtRtJpppppoDaTR6hpphGh6mmgHpMQBpkGTTEAAaAAAA00AZDag0
-ADIBkGgABqemiRNTI0k8aU0PRGRoAZlP0UAAAGgAAAyAADQaAAAaAAAAAAAAAAAA
-AaAAAAM0kgRBJ5MlPFP1Gj0jTTTUaekxNAbUGjTQMgaZANNAAAAaAADTQAAAAAAA
-ANAA0AAANADQ0QAAAAAAAAAaGgAAAAAAABoA0AAA0AAAAAAAAAAAAANAAAAAkSEI
-aTRpomp5DUxNNDTJPTKaep6T09Kemmo2JG0aTQ9ENogaaGhkABo0NHqaBoDTI0DC
-Gj0gNAMhoDQ9QMQNAGQAaDDwyMPIMlbG1vhRBTFo6JksSupgpAjPbY0ec02IGXjb
-eS+FBsh01+O4ZOaD+srUZCFaT4DRjVDLx7uKIsFtESIDUg1ZkhyCSYov05C00MtR
-BdNNa/AYPGOQZWcs+VegXOPrkushFbZ3mBoRD6WamClkpBaHZrUhUl02bIfRXX4w
-b3/9cW9nHDVxh2qFBxqgRKfmq7/Jc/tdJk05nVrGbckGVy2PnIy30CDhpWmqrSot
-K2bOnX0NbP1iy2cd0Na0ZmbRstm4MzMzbbMySTd35F7f+zPP8DC+NJLYcakkkkRd
-NZlupJt3OMFoDAD2g+N3FAMCydhIpoRHRQAdFI5nNg4ugEXHCYxkMyGCwtaJmial
-y0IMlpSYYM/weXNJAhFqS0GNmvaPEtYGjbvaucMdklOTmBX1vfVAkTYB1uXCSK64
-UNIixOqRKLuRCFtqIQtgwqaFrCkIYbbewErWABa+VGADWsJXJjfx5SJViLuwiGXq
-Ru6vCuwmU5CJiJz3UiBpmLv0r2wskxUhY4tzPVGQ9RMXJl65eLSNwZVwaSyGZ9Cm
-A3jztQUUpFeUryBTskW95iVwRMFrhBCwZBAFJBZvhMEMNoDJJlUoIhQkAkjbExp2
-YZio+ZYeAZUwmH1qUbdQixmxf0+61+aVgJ1hwxsO1yG3hFx4pfjc09ITVht0pG8u
-FtVFhPa1KE0gTRUSVXywkITucqk0Waz5Fs6qJpVHYdNrbYRFxnFsQGY1qmsTLjK6
-4QX5Rddo6krM/Bx9CqIAKq4CzVQYHrmIAd2EBhYmwVYwLvhzKIUrc2EirnGIvyuD
-O4YZDSwsVTA0BpVvUOjDErkCraBoSutcKwUSSLGhVvNYHLz3klgZD++wWsa/swLw
-gvNDY2De+sncOv8X2lq4HD95ZdwPuTIMXCwSbg4RrIqv+L0y6F17pqDecyQYPEj3
-iN/0BBeWZlJAyBMi5U3Q1zAlsK8IlDhaXGmvZrgISq5CfNjmUgxDeMggOKqxu4sI
-OrilS49Lkl1J3u3GjXTuH+rX+4ccyFAQnizCpPClcY77F59j63S6fr5vr+y99tuO
-7Ox7Wg/ljwhdyaK4xMmXczeJbx7x07htJNtC4xcQfAtvzeznLrN6MN/ILIBOI65I
-qIA2D5fHHj1XN4aN6TvOjWDaSbSWqxCSCvXUpzkNJAkWXAuTwF8k5uSJvQj/rVo0
-hAhEMEIYkCRGx9AX+byIuXWlLMbbVeliHNUL5AQYmNwLFu4SkmGD+UWtBMyVHQOQ
-ss0ggoVKSKOBUgnVS6ljt7WE1qXqJJ4QA1pEwYNLEaguEE1LtPNoVr5WzjbSbWPk
-V9OW3y9IneUDLoIV5pAkEFTEFGFVjeTFxtpzBBfGgycBxVCdz8eESBIzsamRchAa
-TQunQH8DHnpfod9QuAuRvc7JBlKUCYmCjMvynLcxIFohxCaYrDvGw4QbXZB7oWQ7
-hpoGlz23ayDfB8NrRRzdilsEQyQniu9ASLQg7RrGZnoTr1ai12IbCEUCGdFq03P5
-nBnRFAGmisQGcyykV9gKtcVMWLhCuVmXg86dndn7slUpRNSSEAU20oaWIm1maFTu
-E0DT4gTbg0nuhjtz3kNOz+i7sBm0bkXjxQWuLqlZEmp60ZTyRZJDUqKSEKg6hqcy
-ERxdU22CSNOO10RYUUiDVpKhPNdKTOIE1thp02sBNoNTFSht8WJtaBQ09qN3jd5r
-dOLX4IA5fevRyCCzDgRXfV4wzik4KROjmxmTMglBySlIMEzcXehnDXCRiZSlvwA2
-0YsIOROcm4UrIRFxJHctJH7OdN5u1aHVHb5UaLHpv48NgmFRE56KTSoaWunqm2st
-S0mrAdOiqcR12PWVbdVRJKcQ0DQuhwlAPcRtpxN3D4kbXJjToSYJIFw406G2CSaK
-jQMIJPZGlQmgyFhoCSzeGS1VSq5SKKQQxs5RqKUcVUNY57YUETb4mXzV84SPngKi
-nsce0mXByZq5BKUA9puHZWLNwQIYuDaJUNgG+E01E3pDYVNLKYQ0hsVesgV5gZY0
-htDsRdGtm0+iGnkN6+Ea9YJtUZNAkx2GgSoix12nTW0avTUfxR3oYcpvZ7IdtABE
-UhBcjG4qZtDZsS1JQHys243vhLaDTSvvTeBiJA2tmokqECTBcSOCAGkAxMKlVAva
-4IsLRaBBqhxDbcGtgdw03mFcLUaFuhtKuuEIEkUleJQwby/zwu9uvvZK4xTV+ECM
-a8lmzxKmqkBggYK1+xPdbmJclm6tSZhE/OSJtCEjs+unJIQkT9hCWgBJqGMS07Eh
-AJNmBiuVEVdTyjkIJkavuZmx2sJF13htgEZUCC23lZFOE6gWbM9WyYNJTM8yCQrb
-0Sx3OQvBML5cRATAQkSQkAJOAhoxpQkNi4ZiEVDbdtJAME0RXNDXGHA3M3Q0mm1o
-IEwbWpaM1DQCSMbGRCAu3iRIQiT6RlBpT1n3tfwvUXz3gIVlx3mEximY/kZW1kNG
-sgEJIrBisaEoGYPJ+1CQUYFBw+eGEHJQBpNHjErXUJY2iWHQ30hXwFBuMSxQ2lB5
-bg+/LX3euG6HsHUB1lFvBvaiaBrITVwkCTa1d0s9CHZCiDZjbWReKyrpPE2oSa7o
-LPrR4BJvys9ttjUpzETSSMxh8vsr9dXTwKBtK+1xCTGDQmNIaE29HmHdS5GSxpya
-MismcAUSEgSxHBrKtgsZzduG7vHZn16l3kFkVITtENIzS2JsiBwFTDlhgexsjBHv
-5HXOYxHBzoSDCcPZ0ctvkY9aS5XpoQuFYkGJgCsqjJZeUMNUEpDSbKcnUc1PifIA
-CbR2UoXawBlspkEBr9HBfvUi/MUakZVOf1WKYrqSaIXce62JOyhJLq3qJBloTA0F
-VbILEtM+heFmNRCFt70GJrExVJri0ArYbCRbADSGDBpBXxxb/6fo+s3C7uaL7RjM
-LV2IQBNrAJrKFeJwTsPnxbAsemirUx2lk1kaxschzdK4TQNJN5wQnolIFg401OZ4
-2na11LnT3lR+1k1TMJhiAjXMk0F1ooHnYlt9LKfJ3ZIOmeY+2l9bUQHWFNGyEyfj
-EAcu3kpGLq0Ez7XOS+EpAASRQTAYMATfVQibHLTT30zG732+pNe9za1JNt8sNJYn
-RjWuJ6jL5ILV0rcd9vT7X9fObvcXitpvJ2XBJE+PhX2HaTkyWeF9pwnlQNrTe9hV
-tzhA+ihZrDrHNmLcQjZbnv/IMubqq8egxY80t5n6vZ6U5TR6U9uZJvai1xtqAyCR
-NWkW52m00rDTEuO6BA4q2RHDWwbETF55rRsWLIgNW9qJCyMHPbTM/dMBmWMQSMxz
-4M2pRzt47SICxA327UqSCEERqMFybmYi3nUxePtLgHYplqRiw4ynMbXd/kiQ0LE0
-PKJSSCXA42ymziCpAxNWflzpzQdJZusahRFr6t6m+4p273/Taj7k+hZyNgBAgXAY
-8F7pTts6orLb8IA6o4TOwkwQYmKvKu9VwMrE7+GUhVIAgY9a8DyQMiDBkEAwh7S1
-KgCBfao8DK1CwSS8Z3WjL5MEgt93z2koUQCD/YxMBppiCMp7SDVSmkkIHptfGpeh
-t+M13Ccv1tavIASFiaQl6rBz3K4N3DSGwNkCibrvEAC0fQirOWnc4NVbcLKpFG1l
-NQXF/eqdT79wq1Mvlap3QSCLhcD2D3fCkKVWid4aSjtp9FOX1Uaf7P9eT93zd9Sv
-mj2yNLRUGzyI/0oONNSzmmkvJ5Cq2X2CdldIWMGZO57RJ8oyATAWTQmRmNkfh0Sx
-uuR/J9oUsomVy1AEntc0dlPivkqBkBqrxU3j5PnWkaI3ZRGc0gg9spCQEISh4xEU
-pMhVrnmDQLfLP8Ouqpx917MAw7hkjQk6BJFTAbXDsz3LSHIxo/gB8qrA1vbvdZZh
-LtR0frJdfdppX8nAQX/TAxOQ8+H6yw8a9i7/zJEfSYIhop59N/fhcWW2F14cj2Xc
-fyHaZ04lTO4uPnly91jwuFPaREuZVp8AxImIhlkxkAN61tWdWG7tEbaCgszh6VIz
-ThFnHo2Vi8SQXPrXCN7J9Tc9ZYiAYqoThV/u6SYsea5aZL8deOvKBQCgZZuIxX1z
-4EnfcqG176vY4VqMBIC4pMJz0WcHJYqN+j7BiwGoMBwExrIdTB7q4XIFLotcIpS0
-1MqyVsesvoQq7WObmGQXdMliMirSLcDuSx8Qy+4pIBgGDIyMp1qbonnGdcHYvU8S
-O0A8s/iua5oFdNZTWvbVI4FUH9sKcLiB3/fIAF+sB4n8q6L+UCfmbPcAo/crQ6b3
-HqhDBMY9J0q/jdz9GNYZ/1fbXdkUqAQKFePhtzJDRBZba27+LPQNMCcrHMq06F1T
-4QmLmkHt7LxB2pAczUO+T2O9bHEw/HWw+dYf2MoRDUw=
-`
-
-var outOfRangeSelector = []byte{
- 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
- 0x53, 0x59, 0x4e, 0xec, 0xe8, 0x36, 0x00, 0x00,
- 0x02, 0x51, 0x80, 0x00, 0x10, 0x40, 0x00, 0x06,
- 0x44, 0x90, 0x80, 0x20, 0x00, 0x31, 0x06, 0x4c,
- 0x41, 0x01, 0xa7, 0xa9, 0xa5, 0x80, 0xbb, 0x94,
- 0x31, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00,
- 0x00, 0x00, 0x00,
+func BenchmarkDecodeRand(b *testing.B) {
+ random := mustLoadFile("testdata/random.data.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, random)
}
diff --git a/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2 b/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2
index 0bd61a6d4e..eac2b0571b 100644
--- a/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2
+++ b/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/fail-issue5747.bz2 b/libgo/go/compress/bzip2/testdata/fail-issue5747.bz2
new file mode 100644
index 0000000000..2bf2b6ad99
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/fail-issue5747.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/pass-random1.bin b/libgo/go/compress/bzip2/testdata/pass-random1.bin
new file mode 100644
index 0000000000..6e178792e1
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/pass-random1.bin
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/pass-random1.bz2 b/libgo/go/compress/bzip2/testdata/pass-random1.bz2
new file mode 100644
index 0000000000..f6a9dc7166
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/pass-random1.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/pass-random2.bin b/libgo/go/compress/bzip2/testdata/pass-random2.bin
new file mode 100644
index 0000000000..f152d40064
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/pass-random2.bin
@@ -0,0 +1 @@
+’Õe&¬DJJ¯Š9d¬ E CÖÏ#;Ð23ôº’øqžl*+Ôõø°~Í ££;&4ƒÛ›,‡†­cc¾5Ñs5º \ No newline at end of file
diff --git a/libgo/go/compress/bzip2/testdata/pass-random2.bz2 b/libgo/go/compress/bzip2/testdata/pass-random2.bz2
new file mode 100644
index 0000000000..91ef775ccd
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/pass-random2.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/pass-sawtooth.bz2 b/libgo/go/compress/bzip2/testdata/pass-sawtooth.bz2
new file mode 100644
index 0000000000..579a3782b6
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/pass-sawtooth.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/random.data.bz2 b/libgo/go/compress/bzip2/testdata/random.data.bz2
new file mode 100644
index 0000000000..1ef2300166
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/random.data.bz2
Binary files differ
diff --git a/libgo/go/compress/flate/copy.go b/libgo/go/compress/flate/copy.go
deleted file mode 100644
index a3200a8f49..0000000000
--- a/libgo/go/compress/flate/copy.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-// forwardCopy is like the built-in copy function except that it always goes
-// forward from the start, even if the dst and src overlap.
-// It is equivalent to:
-// for i := 0; i < n; i++ {
-// mem[dst+i] = mem[src+i]
-// }
-func forwardCopy(mem []byte, dst, src, n int) {
- if dst <= src {
- copy(mem[dst:dst+n], mem[src:src+n])
- return
- }
- for {
- if dst >= src+n {
- copy(mem[dst:dst+n], mem[src:src+n])
- return
- }
- // There is some forward overlap. The destination
- // will be filled with a repeated pattern of mem[src:src+k].
- // We copy one instance of the pattern here, then repeat.
- // Each time around this loop k will double.
- k := dst - src
- copy(mem[dst:dst+k], mem[src:src+k])
- n -= k
- dst += k
- }
-}
diff --git a/libgo/go/compress/flate/copy_test.go b/libgo/go/compress/flate/copy_test.go
deleted file mode 100644
index 2011b1547c..0000000000
--- a/libgo/go/compress/flate/copy_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "testing"
-)
-
-func TestForwardCopy(t *testing.T) {
- testCases := []struct {
- dst0, dst1 int
- src0, src1 int
- want string
- }{
- {0, 9, 0, 9, "012345678"},
- {0, 5, 4, 9, "45678"},
- {4, 9, 0, 5, "01230"},
- {1, 6, 3, 8, "34567"},
- {3, 8, 1, 6, "12121"},
- {0, 9, 3, 6, "345"},
- {3, 6, 0, 9, "012"},
- {1, 6, 0, 9, "00000"},
- {0, 4, 7, 8, "7"},
- {0, 1, 6, 8, "6"},
- {4, 4, 6, 9, ""},
- {2, 8, 6, 6, ""},
- {0, 0, 0, 0, ""},
- }
- for _, tc := range testCases {
- b := []byte("0123456789")
- n := tc.dst1 - tc.dst0
- if tc.src1-tc.src0 < n {
- n = tc.src1 - tc.src0
- }
- forwardCopy(b, tc.dst0, tc.src0, n)
- got := string(b[tc.dst0 : tc.dst0+n])
- if got != tc.want {
- t.Errorf("dst=b[%d:%d], src=b[%d:%d]: got %q, want %q",
- tc.dst0, tc.dst1, tc.src0, tc.src1, got, tc.want)
- }
- // Check that the bytes outside of dst[:n] were not modified.
- for i, x := range b {
- if i >= tc.dst0 && i < tc.dst0+n {
- continue
- }
- if int(x) != '0'+i {
- t.Errorf("dst=b[%d:%d], src=b[%d:%d]: copy overrun at b[%d]: got '%c', want '%c'",
- tc.dst0, tc.dst1, tc.src0, tc.src1, i, x, '0'+i)
- }
- }
- }
-}
diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go
index 169a0c7b2e..4d6a5357d8 100644
--- a/libgo/go/compress/flate/deflate.go
+++ b/libgo/go/compress/flate/deflate.go
@@ -13,59 +13,81 @@ import (
const (
NoCompression = 0
BestSpeed = 1
- fastCompression = 3
BestCompression = 9
DefaultCompression = -1
- logWindowSize = 15
- windowSize = 1 << logWindowSize
- windowMask = windowSize - 1
- logMaxOffsetSize = 15 // Standard DEFLATE
- minMatchLength = 3 // The smallest match that the compressor looks for
- maxMatchLength = 258 // The longest match for the compressor
- minOffsetSize = 1 // The shortest offset that makes any sense
-
- // The maximum number of tokens we put into a single flat block, just to
+
+ // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman
+ // entropy encoding. This mode is useful in compressing data that has
+ // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4)
+ // that lacks an entropy encoder. Compression gains are achieved when
+ // certain bytes in the input stream occur more frequently than others.
+ //
+ // Note that HuffmanOnly produces a compressed output that is
+ // RFC 1951 compliant. That is, any valid DEFLATE decompressor will
+ // continue to be able to decompress this output.
+ HuffmanOnly = -2
+)
+
+const (
+ logWindowSize = 15
+ windowSize = 1 << logWindowSize
+ windowMask = windowSize - 1
+
+ // The LZ77 step produces a sequence of literal tokens and <length, offset>
+ // pair tokens. The offset is also known as distance. The underlying wire
+ // format limits the range of lengths and offsets. For example, there are
+ // 256 legitimate lengths: those in the range [3, 258]. This package's
+ // compressor uses a higher minimum match length, enabling optimizations
+ // such as finding matches via 32-bit loads and compares.
+ baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
+ minMatchLength = 4 // The smallest match length that the compressor actually emits
+ maxMatchLength = 258 // The largest match length
+ baseMatchOffset = 1 // The smallest match offset
+ maxMatchOffset = 1 << 15 // The largest match offset
+
+ // The maximum number of tokens we put into a single flate block, just to
// stop things from getting too large.
maxFlateBlockTokens = 1 << 14
maxStoreBlockSize = 65535
- hashBits = 17
+ hashBits = 17 // After 17 performance degrades
hashSize = 1 << hashBits
hashMask = (1 << hashBits) - 1
- hashShift = (hashBits + minMatchLength - 1) / minMatchLength
maxHashOffset = 1 << 24
skipNever = math.MaxInt32
)
type compressionLevel struct {
- good, lazy, nice, chain, fastSkipHashing int
+ level, good, lazy, nice, chain, fastSkipHashing int
}
var levels = []compressionLevel{
- {}, // 0
- // For levels 1-3 we don't bother trying with lazy matches
- {3, 0, 8, 4, 4},
- {3, 0, 16, 8, 5},
- {3, 0, 32, 32, 6},
+ {0, 0, 0, 0, 0, 0}, // NoCompression.
+ {1, 0, 0, 0, 0, 0}, // BestSpeed uses a custom algorithm; see deflatefast.go.
+ // For levels 2-3 we don't bother trying with lazy matches.
+ {2, 4, 0, 16, 8, 5},
+ {3, 4, 0, 32, 32, 6},
// Levels 4-9 use increasingly more lazy matching
// and increasingly stringent conditions for "good enough".
- {4, 4, 16, 16, skipNever},
- {8, 16, 32, 32, skipNever},
- {8, 16, 128, 128, skipNever},
- {8, 32, 128, 256, skipNever},
- {32, 128, 258, 1024, skipNever},
- {32, 258, 258, 4096, skipNever},
+ {4, 4, 4, 16, 16, skipNever},
+ {5, 8, 16, 32, 32, skipNever},
+ {6, 8, 16, 128, 128, skipNever},
+ {7, 8, 32, 128, 256, skipNever},
+ {8, 32, 128, 258, 1024, skipNever},
+ {9, 32, 258, 258, 4096, skipNever},
}
type compressor struct {
compressionLevel
- w *huffmanBitWriter
+ w *huffmanBitWriter
+ bulkHasher func([]byte, []uint32)
// compression algorithm
- fill func(*compressor, []byte) int // copy data to window
- step func(*compressor) // process window
- sync bool // requesting flush
+ fill func(*compressor, []byte) int // copy data to window
+ step func(*compressor) // process window
+ sync bool // requesting flush
+ bestSpeed *deflateFast // Encoder for BestSpeed
// Input hash chains
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
@@ -73,8 +95,8 @@ type compressor struct {
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
// with the same hash value.
chainHead int
- hashHead []int
- hashPrev []int
+ hashHead [hashSize]uint32
+ hashPrev [windowSize]uint32
hashOffset int
// input window: unprocessed data is window[index:windowEnd]
@@ -90,9 +112,12 @@ type compressor struct {
// deflate state
length int
offset int
- hash int
+ hash uint32
maxInsertIndex int
err error
+
+ // hashMatch must be able to contain hashes for the maximum match length.
+ hashMatch [maxMatchLength - 1]uint32
}
func (d *compressor) fillDeflate(b []byte) int {
@@ -111,16 +136,19 @@ func (d *compressor) fillDeflate(b []byte) int {
delta := d.hashOffset - 1
d.hashOffset -= delta
d.chainHead -= delta
- for i, v := range d.hashPrev {
- if v > delta {
- d.hashPrev[i] -= delta
+
+ // Iterate over slices instead of arrays to avoid copying
+ // the entire table onto the stack (Issue #18625).
+ for i, v := range d.hashPrev[:] {
+ if int(v) > delta {
+ d.hashPrev[i] = uint32(int(v) - delta)
} else {
d.hashPrev[i] = 0
}
}
- for i, v := range d.hashHead {
- if v > delta {
- d.hashHead[i] -= delta
+ for i, v := range d.hashHead[:] {
+ if int(v) > delta {
+ d.hashHead[i] = uint32(int(v) - delta)
} else {
d.hashHead[i] = 0
}
@@ -132,19 +160,74 @@ func (d *compressor) fillDeflate(b []byte) int {
return n
}
-func (d *compressor) writeBlock(tokens []token, index int, eof bool) error {
- if index > 0 || eof {
+func (d *compressor) writeBlock(tokens []token, index int) error {
+ if index > 0 {
var window []byte
if d.blockStart <= index {
window = d.window[d.blockStart:index]
}
d.blockStart = index
- d.w.writeBlock(tokens, eof, window)
+ d.w.writeBlock(tokens, false, window)
return d.w.err
}
return nil
}
+// fillWindow will fill the current window with the supplied
+// dictionary and calculate all hashes.
+// This is much faster than doing a full encode.
+// Should only be used after a reset.
+func (d *compressor) fillWindow(b []byte) {
+ // Do not fill window if we are in store-only mode.
+ if d.compressionLevel.level < 2 {
+ return
+ }
+ if d.index != 0 || d.windowEnd != 0 {
+ panic("internal error: fillWindow called with stale data")
+ }
+
+ // If we are given too much, cut it.
+ if len(b) > windowSize {
+ b = b[len(b)-windowSize:]
+ }
+ // Add all to window.
+ n := copy(d.window, b)
+
+ // Calculate 256 hashes at the time (more L1 cache hits)
+ loops := (n + 256 - minMatchLength) / 256
+ for j := 0; j < loops; j++ {
+ index := j * 256
+ end := index + 256 + minMatchLength - 1
+ if end > n {
+ end = n
+ }
+ toCheck := d.window[index:end]
+ dstSize := len(toCheck) - minMatchLength + 1
+
+ if dstSize <= 0 {
+ continue
+ }
+
+ dst := d.hashMatch[:dstSize]
+ d.bulkHasher(toCheck, dst)
+ var newH uint32
+ for i, val := range dst {
+ di := i + index
+ newH = val
+ hh := &d.hashHead[newH&hashMask]
+ // Get previous value with the same hash.
+ // Our chain should point to the previous value.
+ d.hashPrev[di&windowMask] = *hh
+ // Set the head of the hash chain to us.
+ *hh = uint32(di + d.hashOffset)
+ }
+ d.hash = newH
+ }
+ // Update window information.
+ d.windowEnd = n
+ d.index = n
+}
+
// Try to find a match starting at index whose length is greater than prevSize.
// We only look at chainCount possibilities before giving up.
func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
@@ -168,20 +251,15 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
tries >>= 2
}
- w0 := win[pos]
- w1 := win[pos+1]
wEnd := win[pos+length]
+ wPos := win[pos:]
minIndex := pos - windowSize
for i := prevHead; tries > 0; tries-- {
- if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
- // The hash function ensures that if win[i] and win[i+1] match, win[i+2] matches
+ if wEnd == win[i+length] {
+ n := matchLen(win[i:], wPos, minMatchLook)
- n := 3
- for pos+n < len(win) && win[i+n] == win[pos+n] {
- n++
- }
- if n > length && (n > 3 || pos-i <= 4096) {
+ if n > length && (n > minMatchLength || pos-i <= 4096) {
length = n
offset = pos - i
ok = true
@@ -196,7 +274,8 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
// hashPrev[i & windowMask] has already been overwritten, so stop now.
break
}
- if i = d.hashPrev[i&windowMask] - d.hashOffset; i < minIndex || i < 0 {
+ i = int(d.hashPrev[i&windowMask]) - d.hashOffset
+ if i < minIndex || i < 0 {
break
}
}
@@ -211,9 +290,85 @@ func (d *compressor) writeStoredBlock(buf []byte) error {
return d.w.err
}
+const hashmul = 0x1e35a7bd
+
+// hash4 returns a hash representation of the first 4 bytes
+// of the supplied slice.
+// The caller must ensure that len(b) >= 4.
+func hash4(b []byte) uint32 {
+ return ((uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24) * hashmul) >> (32 - hashBits)
+}
+
+// bulkHash4 will compute hashes using the same
+// algorithm as hash4
+func bulkHash4(b []byte, dst []uint32) {
+ if len(b) < minMatchLength {
+ return
+ }
+ hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+ dst[0] = (hb * hashmul) >> (32 - hashBits)
+ end := len(b) - minMatchLength + 1
+ for i := 1; i < end; i++ {
+ hb = (hb << 8) | uint32(b[i+3])
+ dst[i] = (hb * hashmul) >> (32 - hashBits)
+ }
+}
+
+// matchLen returns the number of matching bytes in a and b
+// up to length 'max'. Both slices must be at least 'max'
+// bytes in size.
+func matchLen(a, b []byte, max int) int {
+ a = a[:max]
+ b = b[:len(a)]
+ for i, av := range a {
+ if b[i] != av {
+ return i
+ }
+ }
+ return max
+}
+
+// encSpeed will compress and store the currently added data,
+// if enough has been accumulated or we at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) encSpeed() {
+ // We only compress if we have maxStoreBlockSize.
+ if d.windowEnd < maxStoreBlockSize {
+ if !d.sync {
+ return
+ }
+
+ // Handle small sizes.
+ if d.windowEnd < 128 {
+ switch {
+ case d.windowEnd == 0:
+ return
+ case d.windowEnd <= 16:
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ default:
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+ d.err = d.w.err
+ }
+ d.windowEnd = 0
+ d.bestSpeed.reset()
+ return
+ }
+
+ }
+ // Encode the block.
+ d.tokens = d.bestSpeed.encode(d.tokens[:0], d.window[:d.windowEnd])
+
+ // If we removed less than 1/16th, Huffman compress the block.
+ if len(d.tokens) > d.windowEnd-(d.windowEnd>>4) {
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+ } else {
+ d.w.writeBlockDynamic(d.tokens, false, d.window[:d.windowEnd])
+ }
+ d.err = d.w.err
+ d.windowEnd = 0
+}
+
func (d *compressor) initDeflate() {
- d.hashHead = make([]int, hashSize)
- d.hashPrev = make([]int, windowSize)
d.window = make([]byte, 2*windowSize)
d.hashOffset = 1
d.tokens = make([]token, 0, maxFlateBlockTokens+1)
@@ -223,6 +378,7 @@ func (d *compressor) initDeflate() {
d.index = 0
d.hash = 0
d.chainHead = -1
+ d.bulkHasher = bulkHash4
}
func (d *compressor) deflate() {
@@ -232,7 +388,7 @@ func (d *compressor) deflate() {
d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
if d.index < d.maxInsertIndex {
- d.hash = int(d.window[d.index])<<hashShift + int(d.window[d.index+1])
+ d.hash = hash4(d.window[d.index : d.index+minMatchLength])
}
Loop:
@@ -256,7 +412,7 @@ Loop:
d.byteAvailable = false
}
if len(d.tokens) > 0 {
- if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
+ if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
return
}
d.tokens = d.tokens[:0]
@@ -266,10 +422,11 @@ Loop:
}
if d.index < d.maxInsertIndex {
// Update the hash
- d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
- d.chainHead = d.hashHead[d.hash]
- d.hashPrev[d.index&windowMask] = d.chainHead
- d.hashHead[d.hash] = d.index + d.hashOffset
+ d.hash = hash4(d.window[d.index : d.index+minMatchLength])
+ hh := &d.hashHead[d.hash&hashMask]
+ d.chainHead = int(*hh)
+ d.hashPrev[d.index&windowMask] = uint32(d.chainHead)
+ *hh = uint32(d.index + d.hashOffset)
}
prevLength := d.length
prevOffset := d.offset
@@ -293,9 +450,9 @@ Loop:
// There was a match at the previous step, and the current match is
// not better. Output the previous match.
if d.fastSkipHashing != skipNever {
- d.tokens = append(d.tokens, matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)))
+ d.tokens = append(d.tokens, matchToken(uint32(d.length-baseMatchLength), uint32(d.offset-baseMatchOffset)))
} else {
- d.tokens = append(d.tokens, matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)))
+ d.tokens = append(d.tokens, matchToken(uint32(prevLength-baseMatchLength), uint32(prevOffset-baseMatchOffset)))
}
// Insert in the hash table all strings up to the end of the match.
// index and index-1 are already inserted. If there is not enough
@@ -310,12 +467,13 @@ Loop:
}
for d.index++; d.index < newIndex; d.index++ {
if d.index < d.maxInsertIndex {
- d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
+ d.hash = hash4(d.window[d.index : d.index+minMatchLength])
// Get previous value with the same hash.
// Our chain should point to the previous value.
- d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
+ hh := &d.hashHead[d.hash&hashMask]
+ d.hashPrev[d.index&windowMask] = *hh
// Set the head of the hash chain to us.
- d.hashHead[d.hash] = d.index + d.hashOffset
+ *hh = uint32(d.index + d.hashOffset)
}
}
if d.fastSkipHashing == skipNever {
@@ -327,12 +485,12 @@ Loop:
// item into the table.
d.index += d.length
if d.index < d.maxInsertIndex {
- d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
+ d.hash = hash4(d.window[d.index : d.index+minMatchLength])
}
}
if len(d.tokens) == maxFlateBlockTokens {
// The block includes the current character
- if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
+ if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
return
}
d.tokens = d.tokens[:0]
@@ -345,7 +503,7 @@ Loop:
}
d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
if len(d.tokens) == maxFlateBlockTokens {
- if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
+ if d.err = d.writeBlock(d.tokens, i+1); d.err != nil {
return
}
d.tokens = d.tokens[:0]
@@ -366,23 +524,43 @@ func (d *compressor) fillStore(b []byte) int {
}
func (d *compressor) store() {
- if d.windowEnd > 0 {
+ if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ d.windowEnd = 0
}
+}
+
+// storeHuff compresses and stores the currently added data
+// when the d.window is full or we are at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) storeHuff() {
+ if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
+ return
+ }
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+ d.err = d.w.err
d.windowEnd = 0
}
func (d *compressor) write(b []byte) (n int, err error) {
+ if d.err != nil {
+ return 0, d.err
+ }
n = len(b)
- b = b[d.fill(d, b):]
for len(b) > 0 {
d.step(d)
b = b[d.fill(d, b):]
+ if d.err != nil {
+ return 0, d.err
+ }
}
- return n, d.err
+ return n, nil
}
func (d *compressor) syncFlush() error {
+ if d.err != nil {
+ return d.err
+ }
d.sync = true
d.step(d)
if d.err == nil {
@@ -402,56 +580,53 @@ func (d *compressor) init(w io.Writer, level int) (err error) {
d.window = make([]byte, maxStoreBlockSize)
d.fill = (*compressor).fillStore
d.step = (*compressor).store
+ case level == HuffmanOnly:
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillStore
+ d.step = (*compressor).storeHuff
+ case level == BestSpeed:
+ d.compressionLevel = levels[level]
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillStore
+ d.step = (*compressor).encSpeed
+ d.bestSpeed = newDeflateFast()
+ d.tokens = make([]token, maxStoreBlockSize)
case level == DefaultCompression:
level = 6
fallthrough
- case 1 <= level && level <= 9:
+ case 2 <= level && level <= 9:
d.compressionLevel = levels[level]
d.initDeflate()
d.fill = (*compressor).fillDeflate
d.step = (*compressor).deflate
default:
- return fmt.Errorf("flate: invalid compression level %d: want value in range [-1, 9]", level)
+ return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
}
return nil
}
-var zeroes [32]int
-var bzeroes [256]byte
-
func (d *compressor) reset(w io.Writer) {
d.w.reset(w)
d.sync = false
d.err = nil
- switch d.compressionLevel.chain {
- case 0:
- // level was NoCompression.
- for i := range d.window {
- d.window[i] = 0
- }
+ switch d.compressionLevel.level {
+ case NoCompression:
+ d.windowEnd = 0
+ case BestSpeed:
d.windowEnd = 0
+ d.tokens = d.tokens[:0]
+ d.bestSpeed.reset()
default:
d.chainHead = -1
- for s := d.hashHead; len(s) > 0; {
- n := copy(s, zeroes[:])
- s = s[n:]
+ for i := range d.hashHead {
+ d.hashHead[i] = 0
}
- for s := d.hashPrev; len(s) > 0; s = s[len(zeroes):] {
- copy(s, zeroes[:])
+ for i := range d.hashPrev {
+ d.hashPrev[i] = 0
}
d.hashOffset = 1
-
d.index, d.windowEnd = 0, 0
- for s := d.window; len(s) > 0; {
- n := copy(s, bzeroes[:])
- s = s[n:]
- }
d.blockStart, d.byteAvailable = 0, false
-
- d.tokens = d.tokens[:maxFlateBlockTokens+1]
- for i := 0; i <= maxFlateBlockTokens; i++ {
- d.tokens[i] = 0
- }
d.tokens = d.tokens[:0]
d.length = minMatchLength - 1
d.offset = 0
@@ -461,6 +636,9 @@ func (d *compressor) reset(w io.Writer) {
}
func (d *compressor) close() error {
+ if d.err != nil {
+ return d.err
+ }
d.sync = true
d.step(d)
if d.err != nil {
@@ -477,10 +655,13 @@ func (d *compressor) close() error {
// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
// higher levels typically run slower but compress more. Level 0
// (NoCompression) does not attempt any compression; it only adds the
-// necessary DEFLATE framing. Level -1 (DefaultCompression) uses the default
-// compression level.
+// necessary DEFLATE framing.
+// Level -1 (DefaultCompression) uses the default compression level.
+// Level -2 (HuffmanOnly) will use Huffman compression only, giving
+// a very fast compression for all types of input, but sacrificing considerable
+// compression efficiency.
//
-// If level is in the range [-1, 9] then the error returned will be nil.
+// If level is in the range [-2, 9] then the error returned will be nil.
// Otherwise the error returned will be non-nil.
func NewWriter(w io.Writer, level int) (*Writer, error) {
var dw Writer
@@ -491,34 +672,28 @@ func NewWriter(w io.Writer, level int) (*Writer, error) {
}
// NewWriterDict is like NewWriter but initializes the new
-// Writer with a preset dictionary. The returned Writer behaves
+// Writer with a preset dictionary. The returned Writer behaves
// as if the dictionary had been written to it without producing
-// any compressed output. The compressed data written to w
+// any compressed output. The compressed data written to w
// can only be decompressed by a Reader initialized with the
// same dictionary.
func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
- dw := &dictWriter{w, false}
+ dw := &dictWriter{w}
zw, err := NewWriter(dw, level)
if err != nil {
return nil, err
}
- zw.Write(dict)
- zw.Flush()
- dw.enabled = true
+ zw.d.fillWindow(dict)
zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method.
return zw, err
}
type dictWriter struct {
- w io.Writer
- enabled bool
+ w io.Writer
}
func (w *dictWriter) Write(b []byte) (n int, err error) {
- if w.enabled {
- return w.w.Write(b)
- }
- return len(b), nil
+ return w.w.Write(b)
}
// A Writer takes data written to it and writes the compressed
@@ -534,10 +709,12 @@ func (w *Writer) Write(data []byte) (n int, err error) {
return w.d.write(data)
}
-// Flush flushes any pending compressed data to the underlying writer.
+// Flush flushes any pending data to the underlying writer.
// It is useful mainly in compressed network protocols, to ensure that
// a remote reader has enough data to reconstruct a packet.
// Flush does not return until the data has been written.
+// Calling Flush when there is no pending data still causes the Writer
+// to emit a sync marker of at least 4 bytes.
// If the underlying writer returns an error, Flush returns that error.
//
// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
@@ -556,14 +733,11 @@ func (w *Writer) Close() error {
// the result of NewWriter or NewWriterDict called with dst
// and w's level and dictionary.
func (w *Writer) Reset(dst io.Writer) {
- if dw, ok := w.d.w.w.(*dictWriter); ok {
+ if dw, ok := w.d.w.writer.(*dictWriter); ok {
// w was created with NewWriterDict
dw.w = dst
w.d.reset(dw)
- dw.enabled = false
- w.Write(w.dict)
- w.Flush()
- dw.enabled = true
+ w.d.fillWindow(w.dict)
} else {
// w was created with NewWriter
w.d.reset(dst)
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
index 72bc6652c8..fbea761721 100644
--- a/libgo/go/compress/flate/deflate_test.go
+++ b/libgo/go/compress/flate/deflate_test.go
@@ -6,11 +6,13 @@ package flate
import (
"bytes"
+ "errors"
"fmt"
"internal/testenv"
"io"
"io/ioutil"
"reflect"
+ "runtime/debug"
"sync"
"testing"
)
@@ -42,10 +44,10 @@ var deflateTests = []*deflateTest{
{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
[]byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
},
- {[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
- {[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
- {[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
- {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+ {[]byte{}, 2, []byte{1, 0, 0, 255, 255}},
+ {[]byte{0x11}, 2, []byte{18, 4, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x12}, 2, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 2, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
@@ -80,6 +82,32 @@ func largeDataChunk() []byte {
return result
}
+func TestBulkHash4(t *testing.T) {
+ for _, x := range deflateTests {
+ y := x.out
+ if len(y) < minMatchLength {
+ continue
+ }
+ y = append(y, y...)
+ for j := 4; j < len(y); j++ {
+ y := y[:j]
+ dst := make([]uint32, len(y)-minMatchLength+1)
+ for i := range dst {
+ dst[i] = uint32(i + 100)
+ }
+ bulkHash4(y, dst)
+ for i, got := range dst {
+ want := hash4(y[i:])
+ if got != want && got == uint32(i)+100 {
+ t.Errorf("Len:%d Index:%d, want 0x%08x but not modified", len(y), i, want)
+ } else if got != want {
+ t.Errorf("Len:%d Index:%d, got 0x%08x want:0x%08x", len(y), i, got, want)
+ }
+ }
+ }
+ }
+}
+
func TestDeflate(t *testing.T) {
for _, h := range deflateTests {
var buf bytes.Buffer
@@ -91,7 +119,7 @@ func TestDeflate(t *testing.T) {
w.Write(h.in)
w.Close()
if !bytes.Equal(buf.Bytes(), h.out) {
- t.Errorf("Deflate(%d, %x) = %x, want %x", h.level, h.in, buf.Bytes(), h.out)
+ t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out)
}
}
}
@@ -247,7 +275,7 @@ func testSync(t *testing.T, level int, input []byte, name string) {
// not necessarily the case: the write Flush may emit
// some extra framing bits that are not necessary
// to process to obtain the first half of the uncompressed
- // data. The test ran correctly most of the time, because
+ // data. The test ran correctly most of the time, because
// the background goroutine had usually read even
// those extra bits by now, but it's not a useful thing to
// check.
@@ -289,6 +317,9 @@ func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name str
t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
return
}
+ if limit > 0 {
+ t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len())
+ }
r := NewReader(&buffer)
out, err := ioutil.ReadAll(r)
if err != nil {
@@ -303,15 +334,18 @@ func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name str
testSync(t, level, input, name)
}
-func testToFromWithLimit(t *testing.T, input []byte, name string, limit [10]int) {
+func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) {
for i := 0; i < 10; i++ {
testToFromWithLevelAndLimit(t, i, input, name, limit[i])
}
+ // Test HuffmanCompression
+ testToFromWithLevelAndLimit(t, -2, input, name, limit[10])
}
func TestDeflateInflate(t *testing.T) {
+ t.Parallel()
for i, h := range deflateInflateTests {
- testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [10]int{})
+ testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{})
}
}
@@ -327,23 +361,24 @@ func TestReverseBits(t *testing.T) {
type deflateInflateStringTest struct {
filename string
label string
- limit [10]int
+ limit [11]int
}
var deflateInflateStringTests = []deflateInflateStringTest{
{
"../testdata/e.txt",
"2.718281828...",
- [...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790},
+ [...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683},
},
{
"../testdata/Mark.Twain-Tom.Sawyer.txt",
"Mark.Twain-Tom.Sawyer",
- [...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295},
+ [...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295, 233460},
},
}
func TestDeflateInflateString(t *testing.T) {
+ t.Parallel()
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
@@ -431,6 +466,7 @@ func TestRegression2508(t *testing.T) {
}
func TestWriterReset(t *testing.T) {
+ t.Parallel()
for level := 0; level <= 9; level++ {
if testing.Short() && level > 1 {
break
@@ -457,6 +493,18 @@ func TestWriterReset(t *testing.T) {
// DeepEqual doesn't compare functions.
w.d.fill, wref.d.fill = nil, nil
w.d.step, wref.d.step = nil, nil
+ w.d.bulkHasher, wref.d.bulkHasher = nil, nil
+ w.d.bestSpeed, wref.d.bestSpeed = nil, nil
+ // hashMatch is always overwritten when used.
+ copy(w.d.hashMatch[:], wref.d.hashMatch[:])
+ if len(w.d.tokens) != 0 {
+ t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens))
+ }
+ // As long as the length is 0, we don't care about the content.
+ w.d.tokens = wref.d.tokens
+
+ // We don't care if there are values in the window, as long as it is at d.index is 0
+ w.d.window = wref.d.window
if !reflect.DeepEqual(w, wref) {
t.Errorf("level %d Writer not reset after Reset", level)
}
@@ -481,7 +529,7 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
w.Write(b)
}
w.Close()
- out1 := buf.String()
+ out1 := buf.Bytes()
buf2 := new(bytes.Buffer)
w.Reset(buf2)
@@ -489,10 +537,361 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
w.Write(b)
}
w.Close()
- out2 := buf2.String()
+ out2 := buf2.Bytes()
- if out1 != out2 {
- t.Errorf("got %q, expected %q", out2, out1)
+ if len(out1) != len(out2) {
+ t.Errorf("got %d, expected %d bytes", len(out2), len(out1))
+ return
+ }
+ if !bytes.Equal(out1, out2) {
+ mm := 0
+ for i, b := range out1[:len(out2)] {
+ if b != out2[i] {
+ t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b)
+ }
+ mm++
+ if mm == 10 {
+ t.Fatal("Stopping")
+ }
+ }
}
t.Logf("got %d bytes", len(out1))
}
+
+// TestBestSpeed tests that round-tripping through deflate and then inflate
+// recovers the original input. The Write sizes are near the thresholds in the
+// compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
+// (65535).
+func TestBestSpeed(t *testing.T) {
+ t.Parallel()
+ abc := make([]byte, 128)
+ for i := range abc {
+ abc[i] = byte(i)
+ }
+ abcabc := bytes.Repeat(abc, 131072/len(abc))
+ var want []byte
+
+ testCases := [][]int{
+ {65536, 0},
+ {65536, 1},
+ {65536, 1, 256},
+ {65536, 1, 65536},
+ {65536, 14},
+ {65536, 15},
+ {65536, 16},
+ {65536, 16, 256},
+ {65536, 16, 65536},
+ {65536, 127},
+ {65536, 128},
+ {65536, 128, 256},
+ {65536, 128, 65536},
+ {65536, 129},
+ {65536, 65536, 256},
+ {65536, 65536, 65536},
+ }
+
+ for i, tc := range testCases {
+ for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} {
+ tc[0] = firstN
+ outer:
+ for _, flush := range []bool{false, true} {
+ buf := new(bytes.Buffer)
+ want = want[:0]
+
+ w, err := NewWriter(buf, BestSpeed)
+ if err != nil {
+ t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err)
+ continue
+ }
+ for _, n := range tc {
+ want = append(want, abcabc[:n]...)
+ if _, err := w.Write(abcabc[:n]); err != nil {
+ t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err)
+ continue outer
+ }
+ if !flush {
+ continue
+ }
+ if err := w.Flush(); err != nil {
+ t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err)
+ continue outer
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err)
+ continue
+ }
+
+ r := NewReader(buf)
+ got, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err)
+ continue
+ }
+ r.Close()
+
+ if !bytes.Equal(got, want) {
+ t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush)
+ continue
+ }
+ }
+ }
+ }
+}
+
+var errIO = errors.New("IO error")
+
+// failWriter fails with errIO exactly at the nth call to Write.
+type failWriter struct{ n int }
+
+func (w *failWriter) Write(b []byte) (int, error) {
+ w.n--
+ if w.n == -1 {
+ return 0, errIO
+ }
+ return len(b), nil
+}
+
+func TestWriterPersistentError(t *testing.T) {
+ t.Parallel()
+ d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt")
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+ d = d[:10000] // Keep this test short
+
+ zw, err := NewWriter(nil, DefaultCompression)
+ if err != nil {
+ t.Fatalf("NewWriter: %v", err)
+ }
+
+ // Sweep over the threshold at which an error is returned.
+ // The variable i makes it such that the ith call to failWriter.Write will
+ // return errIO. Since failWriter errors are not persistent, we must ensure
+ // that flate.Writer errors are persistent.
+ for i := 0; i < 1000; i++ {
+ fw := &failWriter{i}
+ zw.Reset(fw)
+
+ _, werr := zw.Write(d)
+ cerr := zw.Close()
+ if werr != errIO && werr != nil {
+ t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO)
+ }
+ if cerr != errIO && fw.n < 0 {
+ t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO)
+ }
+ if fw.n >= 0 {
+ // At this point, the failure threshold was sufficiently high enough
+ // that we wrote the whole stream without any errors.
+ return
+ }
+ }
+}
+
+func TestBestSpeedMatch(t *testing.T) {
+ t.Parallel()
+ cases := []struct {
+ previous, current []byte
+ t, s, want int32
+ }{{
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 6,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{2, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 3,
+ }, {
+ previous: []byte{0, 0, 0, 1, 1},
+ current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 2,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 0,
+ want: 4,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2, 3, 4, 5, 2, 2},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -7,
+ s: 4,
+ want: 5,
+ }, {
+ previous: []byte{9, 9, 9, 9, 9},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 0,
+ want: 0,
+ }, {
+ previous: []byte{9, 9, 9, 9, 9},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: 0,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -5,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: 0,
+ s: 1,
+ want: 3,
+ }, {
+ previous: []byte{3, 4, 5},
+ current: []byte{3, 4, 5},
+ t: -3,
+ s: 0,
+ want: 3,
+ }, {
+ previous: make([]byte, 1000),
+ current: make([]byte, 1000),
+ t: -1000,
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: -200,
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: 0,
+ s: 1,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, maxMatchLength-4),
+ current: make([]byte, 500),
+ t: -(maxMatchLength - 4),
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: -200,
+ s: 400,
+ want: 100,
+ }, {
+ previous: make([]byte, 10),
+ current: make([]byte, 500),
+ t: 200,
+ s: 400,
+ want: 100,
+ }}
+ for i, c := range cases {
+ e := deflateFast{prev: c.previous}
+ got := e.matchLen(c.s, c.t, c.current)
+ if got != c.want {
+ t.Errorf("Test %d: match length, want %d, got %d", i, c.want, got)
+ }
+ }
+}
+
+func TestBestSpeedMaxMatchOffset(t *testing.T) {
+ t.Parallel()
+ const abc, xyz = "abcdefgh", "stuvwxyz"
+ for _, matchBefore := range []bool{false, true} {
+ for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} {
+ for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ {
+ report := func(desc string, err error) {
+ t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v",
+ matchBefore, extra, offsetAdj, desc, err)
+ }
+
+ offset := maxMatchOffset + offsetAdj
+
+ // Make src to be a []byte of the form
+ // "%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1)
+ // where:
+ // zeros0 is approximately maxMatchOffset zeros.
+ // xyzMaybe is either xyz or the empty string.
+ // zeros1 is between 0 and 30 zeros.
+ // The difference between the two abc's will be offset, which
+ // is maxMatchOffset plus or minus a small adjustment.
+ src := make([]byte, offset+len(abc)+extra)
+ copy(src, abc)
+ if !matchBefore {
+ copy(src[offset-len(xyz):], xyz)
+ }
+ copy(src[offset:], abc)
+
+ buf := new(bytes.Buffer)
+ w, err := NewWriter(buf, BestSpeed)
+ if err != nil {
+ report("NewWriter: ", err)
+ continue
+ }
+ if _, err := w.Write(src); err != nil {
+ report("Write: ", err)
+ continue
+ }
+ if err := w.Close(); err != nil {
+ report("Writer.Close: ", err)
+ continue
+ }
+
+ r := NewReader(buf)
+ dst, err := ioutil.ReadAll(r)
+ r.Close()
+ if err != nil {
+ report("ReadAll: ", err)
+ continue
+ }
+
+ if !bytes.Equal(dst, src) {
+ report("", fmt.Errorf("bytes differ after round-tripping"))
+ continue
+ }
+ }
+ }
+ }
+}
+
+func TestMaxStackSize(t *testing.T) {
+ // This test must not run in parallel with other tests as debug.SetMaxStack
+ // affects all goroutines.
+ n := debug.SetMaxStack(1 << 16)
+ defer debug.SetMaxStack(n)
+
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ b := make([]byte, 1<<20)
+ for level := HuffmanOnly; level <= BestCompression; level++ {
+ // Run in separate goroutine to increase probability of stack regrowth.
+ wg.Add(1)
+ go func(level int) {
+ defer wg.Done()
+ zw, err := NewWriter(ioutil.Discard, level)
+ if err != nil {
+ t.Errorf("level %d, NewWriter() = %v, want nil", level, err)
+ }
+ if n, err := zw.Write(b); n != len(b) || err != nil {
+ t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b))
+ }
+ if err := zw.Close(); err != nil {
+ t.Errorf("level %d, Close() = %v, want nil", level, err)
+ }
+ zw.Reset(ioutil.Discard)
+ }(level)
+ }
+}
diff --git a/libgo/go/compress/flate/deflatefast.go b/libgo/go/compress/flate/deflatefast.go
new file mode 100644
index 0000000000..08298b76bb
--- /dev/null
+++ b/libgo/go/compress/flate/deflatefast.go
@@ -0,0 +1,285 @@
+// 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 flate
+
+// This encoding algorithm, which prioritizes speed over output size, is
+// based on Snappy's LZ77-style encoder: github.com/golang/snappy
+
+const (
+ tableBits = 14 // Bits used in the table.
+ tableSize = 1 << tableBits // Size of the table.
+ tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
+)
+
+func load32(b []byte, i int32) uint32 {
+ b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func load64(b []byte, i int32) uint64 {
+ b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ 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
+}
+
+func hash(u uint32) uint32 {
+ return (u * 0x1e35a7bd) >> tableShift
+}
+
+// These constants are defined by the Snappy implementation so that its
+// assembly implementation can fast-path some 16-bytes-at-a-time copies. They
+// aren't necessary in the pure Go implementation, as we don't use those same
+// optimizations, but using the same thresholds doesn't really hurt.
+const (
+ inputMargin = 16 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+)
+
+type tableEntry struct {
+ val uint32 // Value at destination
+ offset int32
+}
+
+// deflateFast maintains the table for matches,
+// and the previous byte block for cross block matching.
+type deflateFast struct {
+ table [tableSize]tableEntry
+ prev []byte // Previous block, zero length if unknown.
+ cur int32 // Current match offset.
+}
+
+func newDeflateFast() *deflateFast {
+ return &deflateFast{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}
+}
+
+// encode encodes a block given in src and appends tokens
+// to dst and returns the result.
+func (e *deflateFast) encode(dst []token, src []byte) []token {
+ // Ensure that e.cur doesn't wrap.
+ if e.cur > 1<<30 {
+ e.resetAll()
+ }
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ e.cur += maxStoreBlockSize
+ e.prev = e.prev[:0]
+ return emitLiteral(dst, src)
+ }
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := int32(0)
+ s := int32(0)
+ cv := load32(src, s)
+ nextHash := hash(cv)
+
+ for {
+ // Copied from the C++ snappy implementation:
+ //
+ // Heuristic match skipping: If 32 bytes are scanned with no matches
+ // found, start looking only at every other byte. If 32 more bytes are
+ // scanned (or skipped), look at every third byte, etc.. When a match
+ // is found, immediately go back to looking at every byte. This is a
+ // small loss (~5% performance, ~0.1% density) for compressible data
+ // due to more bookkeeping, but for non-compressible data (such as
+ // JPEG) it's a huge win since the compressor quickly "realizes" the
+ // data is incompressible and doesn't bother looking for matches
+ // everywhere.
+ //
+ // The "skip" variable keeps track of how many bytes there are since
+ // the last match; dividing it by 32 (ie. right-shifting by five) gives
+ // the number of bytes to move ahead for each iteration.
+ skip := int32(32)
+
+ nextS := s
+ var candidate tableEntry
+ for {
+ s = nextS
+ bytesBetweenHashLookups := skip >> 5
+ nextS = s + bytesBetweenHashLookups
+ skip += bytesBetweenHashLookups
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidate = e.table[nextHash&tableMask]
+ now := load32(src, nextS)
+ e.table[nextHash&tableMask] = tableEntry{offset: s + e.cur, val: cv}
+ nextHash = hash(now)
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || cv != candidate.val {
+ // Out of range or not matched.
+ cv = now
+ continue
+ }
+ break
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+ dst = emitLiteral(dst, src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+
+ // Extend the 4-byte match as long as possible.
+ //
+ s += 4
+ t := candidate.offset - e.cur + 4
+ l := e.matchLen(s, t, src)
+
+ // matchToken is flate's equivalent of Snappy's emitCopy. (length,offset)
+ dst = append(dst, matchToken(uint32(l+4-baseMatchLength), uint32(s-t-baseMatchOffset)))
+ s += l
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s. If
+ // another emitCopy is not our next move, also calculate nextHash
+ // at s+1. At least on GOARCH=amd64, these three hash calculations
+ // are faster as one load64 call (with some shifts) instead of
+ // three load32 calls.
+ x := load64(src, s-1)
+ prevHash := hash(uint32(x))
+ e.table[prevHash&tableMask] = tableEntry{offset: e.cur + s - 1, val: uint32(x)}
+ x >>= 8
+ currHash := hash(uint32(x))
+ candidate = e.table[currHash&tableMask]
+ e.table[currHash&tableMask] = tableEntry{offset: e.cur + s, val: uint32(x)}
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || uint32(x) != candidate.val {
+ cv = uint32(x >> 8)
+ nextHash = hash(cv)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ dst = emitLiteral(dst, src[nextEmit:])
+ }
+ e.cur += int32(len(src))
+ e.prev = e.prev[:len(src)]
+ copy(e.prev, src)
+ return dst
+}
+
+func emitLiteral(dst []token, lit []byte) []token {
+ for _, v := range lit {
+ dst = append(dst, literalToken(uint32(v)))
+ }
+ return dst
+}
+
+// matchLen returns the match length between src[s:] and src[t:].
+// t can be negative to indicate the match is starting in e.prev.
+// We assume that src[s-4:s] and src[t-4:t] already match.
+func (e *deflateFast) matchLen(s, t int32, src []byte) int32 {
+ s1 := int(s) + maxMatchLength - 4
+ if s1 > len(src) {
+ s1 = len(src)
+ }
+
+ // If we are inside the current block
+ if t >= 0 {
+ b := src[t:]
+ a := src[s:s1]
+ b = b[:len(a)]
+ // Extend the match to be as long as possible.
+ for i := range a {
+ if a[i] != b[i] {
+ return int32(i)
+ }
+ }
+ return int32(len(a))
+ }
+
+ // We found a match in the previous block.
+ tp := int32(len(e.prev)) + t
+ if tp < 0 {
+ return 0
+ }
+
+ // Extend the match to be as long as possible.
+ a := src[s:s1]
+ b := e.prev[tp:]
+ if len(b) > len(a) {
+ b = b[:len(a)]
+ }
+ a = a[:len(b)]
+ for i := range b {
+ if a[i] != b[i] {
+ return int32(i)
+ }
+ }
+
+ // If we reached our limit, we matched everything we are
+ // allowed to in the previous block and we return.
+ n := int32(len(b))
+ if int(s+n) == s1 {
+ return n
+ }
+
+ // Continue looking for more matches in the current block.
+ a = src[s+n : s1]
+ b = src[:len(a)]
+ for i := range a {
+ if a[i] != b[i] {
+ return int32(i) + n
+ }
+ }
+ return int32(len(a)) + n
+}
+
+// Reset resets the encoding history.
+// This ensures that no matches are made to the previous block.
+func (e *deflateFast) reset() {
+ e.prev = e.prev[:0]
+ // Bump the offset, so all matches will fail distance check.
+ e.cur += maxMatchOffset
+
+ // Protect against e.cur wraparound.
+ if e.cur > 1<<30 {
+ e.resetAll()
+ }
+}
+
+// resetAll resets the deflateFast struct and is only called in rare
+// situations to prevent integer overflow. It manually resets each field
+// to avoid causing large stack growth.
+//
+// See https://golang.org/issue/18636.
+func (e *deflateFast) resetAll() {
+ // This is equivalent to:
+ // *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ e.cur = maxStoreBlockSize
+ e.prev = e.prev[:0]
+ for i := range e.table {
+ e.table[i] = tableEntry{}
+ }
+}
diff --git a/libgo/go/compress/flate/dict_decoder.go b/libgo/go/compress/flate/dict_decoder.go
new file mode 100644
index 0000000000..71c75a065e
--- /dev/null
+++ b/libgo/go/compress/flate/dict_decoder.go
@@ -0,0 +1,184 @@
+// 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 flate
+
+// dictDecoder implements the LZ77 sliding dictionary as used in decompression.
+// LZ77 decompresses data through sequences of two forms of commands:
+//
+// * Literal insertions: Runs of one or more symbols are inserted into the data
+// stream as is. This is accomplished through the writeByte method for a
+// single symbol, or combinations of writeSlice/writeMark for multiple symbols.
+// Any valid stream must start with a literal insertion if no preset dictionary
+// is used.
+//
+// * Backward copies: Runs of one or more symbols are copied from previously
+// emitted data. Backward copies come as the tuple (dist, length) where dist
+// determines how far back in the stream to copy from and length determines how
+// many bytes to copy. Note that it is valid for the length to be greater than
+// the distance. Since LZ77 uses forward copies, that situation is used to
+// perform a form of run-length encoding on repeated runs of symbols.
+// The writeCopy and tryWriteCopy are used to implement this command.
+//
+// For performance reasons, this implementation performs little to no sanity
+// checks about the arguments. As such, the invariants documented for each
+// method call must be respected.
+type dictDecoder struct {
+ hist []byte // Sliding window history
+
+ // Invariant: 0 <= rdPos <= wrPos <= len(hist)
+ wrPos int // Current output position in buffer
+ rdPos int // Have emitted hist[:rdPos] already
+ full bool // Has a full window length been written yet?
+}
+
+// init initializes dictDecoder to have a sliding window dictionary of the given
+// size. If a preset dict is provided, it will initialize the dictionary with
+// the contents of dict.
+func (dd *dictDecoder) init(size int, dict []byte) {
+ *dd = dictDecoder{hist: dd.hist}
+
+ if cap(dd.hist) < size {
+ dd.hist = make([]byte, size)
+ }
+ dd.hist = dd.hist[:size]
+
+ if len(dict) > len(dd.hist) {
+ dict = dict[len(dict)-len(dd.hist):]
+ }
+ dd.wrPos = copy(dd.hist, dict)
+ if dd.wrPos == len(dd.hist) {
+ dd.wrPos = 0
+ dd.full = true
+ }
+ dd.rdPos = dd.wrPos
+}
+
+// histSize reports the total amount of historical data in the dictionary.
+func (dd *dictDecoder) histSize() int {
+ if dd.full {
+ return len(dd.hist)
+ }
+ return dd.wrPos
+}
+
+// availRead reports the number of bytes that can be flushed by readFlush.
+func (dd *dictDecoder) availRead() int {
+ return dd.wrPos - dd.rdPos
+}
+
+// availWrite reports the available amount of output buffer space.
+func (dd *dictDecoder) availWrite() int {
+ return len(dd.hist) - dd.wrPos
+}
+
+// writeSlice returns a slice of the available buffer to write data to.
+//
+// This invariant will be kept: len(s) <= availWrite()
+func (dd *dictDecoder) writeSlice() []byte {
+ return dd.hist[dd.wrPos:]
+}
+
+// writeMark advances the writer pointer by cnt.
+//
+// This invariant must be kept: 0 <= cnt <= availWrite()
+func (dd *dictDecoder) writeMark(cnt int) {
+ dd.wrPos += cnt
+}
+
+// writeByte writes a single byte to the dictionary.
+//
+// This invariant must be kept: 0 < availWrite()
+func (dd *dictDecoder) writeByte(c byte) {
+ dd.hist[dd.wrPos] = c
+ dd.wrPos++
+}
+
+// writeCopy copies a string at a given (dist, length) to the output.
+// This returns the number of bytes copied and may be less than the requested
+// length if the available space in the output buffer is too small.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) writeCopy(dist, length int) int {
+ dstBase := dd.wrPos
+ dstPos := dstBase
+ srcPos := dstPos - dist
+ endPos := dstPos + length
+ if endPos > len(dd.hist) {
+ endPos = len(dd.hist)
+ }
+
+ // Copy non-overlapping section after destination position.
+ //
+ // This section is non-overlapping in that the copy length for this section
+ // is always less than or equal to the backwards distance. This can occur
+ // if a distance refers to data that wraps-around in the buffer.
+ // Thus, a backwards copy is performed here; that is, the exact bytes in
+ // the source prior to the copy is placed in the destination.
+ if srcPos < 0 {
+ srcPos += len(dd.hist)
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:])
+ srcPos = 0
+ }
+
+ // Copy possibly overlapping section before destination position.
+ //
+ // This section can overlap if the copy length for this section is larger
+ // than the backwards distance. This is allowed by LZ77 so that repeated
+ // strings can be succinctly represented using (dist, length) pairs.
+ // Thus, a forwards copy is performed here; that is, the bytes copied is
+ // possibly dependent on the resulting bytes in the destination as the copy
+ // progresses along. This is functionally equivalent to the following:
+ //
+ // for i := 0; i < endPos-dstPos; i++ {
+ // dd.hist[dstPos+i] = dd.hist[srcPos+i]
+ // }
+ // dstPos = endPos
+ //
+ for dstPos < endPos {
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+ }
+
+ dd.wrPos = dstPos
+ return dstPos - dstBase
+}
+
+// tryWriteCopy tries to copy a string at a given (distance, length) to the
+// output. This specialized version is optimized for short distances.
+//
+// This method is designed to be inlined for performance reasons.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) tryWriteCopy(dist, length int) int {
+ dstPos := dd.wrPos
+ endPos := dstPos + length
+ if dstPos < dist || endPos > len(dd.hist) {
+ return 0
+ }
+ dstBase := dstPos
+ srcPos := dstPos - dist
+
+ // Copy possibly overlapping section before destination position.
+loop:
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+ if dstPos < endPos {
+ goto loop // Avoid for-loop so that this function can be inlined
+ }
+
+ dd.wrPos = dstPos
+ return dstPos - dstBase
+}
+
+// readFlush returns a slice of the historical buffer that is ready to be
+// emitted to the user. The data returned by readFlush must be fully consumed
+// before calling any other dictDecoder methods.
+func (dd *dictDecoder) readFlush() []byte {
+ toRead := dd.hist[dd.rdPos:dd.wrPos]
+ dd.rdPos = dd.wrPos
+ if dd.wrPos == len(dd.hist) {
+ dd.wrPos, dd.rdPos = 0, 0
+ dd.full = true
+ }
+ return toRead
+}
diff --git a/libgo/go/compress/flate/dict_decoder_test.go b/libgo/go/compress/flate/dict_decoder_test.go
new file mode 100644
index 0000000000..9275cff791
--- /dev/null
+++ b/libgo/go/compress/flate/dict_decoder_test.go
@@ -0,0 +1,139 @@
+// 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 flate
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+func TestDictDecoder(t *testing.T) {
+ const (
+ abc = "ABC\n"
+ fox = "The quick brown fox jumped over the lazy dog!\n"
+ poem = "The Road Not Taken\nRobert Frost\n" +
+ "\n" +
+ "Two roads diverged in a yellow wood,\n" +
+ "And sorry I could not travel both\n" +
+ "And be one traveler, long I stood\n" +
+ "And looked down one as far as I could\n" +
+ "To where it bent in the undergrowth;\n" +
+ "\n" +
+ "Then took the other, as just as fair,\n" +
+ "And having perhaps the better claim,\n" +
+ "Because it was grassy and wanted wear;\n" +
+ "Though as for that the passing there\n" +
+ "Had worn them really about the same,\n" +
+ "\n" +
+ "And both that morning equally lay\n" +
+ "In leaves no step had trodden black.\n" +
+ "Oh, I kept the first for another day!\n" +
+ "Yet knowing how way leads on to way,\n" +
+ "I doubted if I should ever come back.\n" +
+ "\n" +
+ "I shall be telling this with a sigh\n" +
+ "Somewhere ages and ages hence:\n" +
+ "Two roads diverged in a wood, and I-\n" +
+ "I took the one less traveled by,\n" +
+ "And that has made all the difference.\n"
+ )
+
+ var poemRefs = []struct {
+ dist int // Backward distance (0 if this is an insertion)
+ length int // Length of copy or insertion
+ }{
+ {0, 38}, {33, 3}, {0, 48}, {79, 3}, {0, 11}, {34, 5}, {0, 6}, {23, 7},
+ {0, 8}, {50, 3}, {0, 2}, {69, 3}, {34, 5}, {0, 4}, {97, 3}, {0, 4},
+ {43, 5}, {0, 6}, {7, 4}, {88, 7}, {0, 12}, {80, 3}, {0, 2}, {141, 4},
+ {0, 1}, {196, 3}, {0, 3}, {157, 3}, {0, 6}, {181, 3}, {0, 2}, {23, 3},
+ {77, 3}, {28, 5}, {128, 3}, {110, 4}, {70, 3}, {0, 4}, {85, 6}, {0, 2},
+ {182, 6}, {0, 4}, {133, 3}, {0, 7}, {47, 5}, {0, 20}, {112, 5}, {0, 1},
+ {58, 3}, {0, 8}, {59, 3}, {0, 4}, {173, 3}, {0, 5}, {114, 3}, {0, 4},
+ {92, 5}, {0, 2}, {71, 3}, {0, 2}, {76, 5}, {0, 1}, {46, 3}, {96, 4},
+ {130, 4}, {0, 3}, {360, 3}, {0, 3}, {178, 5}, {0, 7}, {75, 3}, {0, 3},
+ {45, 6}, {0, 6}, {299, 6}, {180, 3}, {70, 6}, {0, 1}, {48, 3}, {66, 4},
+ {0, 3}, {47, 5}, {0, 9}, {325, 3}, {0, 1}, {359, 3}, {318, 3}, {0, 2},
+ {199, 3}, {0, 1}, {344, 3}, {0, 3}, {248, 3}, {0, 10}, {310, 3}, {0, 3},
+ {93, 6}, {0, 3}, {252, 3}, {157, 4}, {0, 2}, {273, 5}, {0, 14}, {99, 4},
+ {0, 1}, {464, 4}, {0, 2}, {92, 4}, {495, 3}, {0, 1}, {322, 4}, {16, 4},
+ {0, 3}, {402, 3}, {0, 2}, {237, 4}, {0, 2}, {432, 4}, {0, 1}, {483, 5},
+ {0, 2}, {294, 4}, {0, 2}, {306, 3}, {113, 5}, {0, 1}, {26, 4}, {164, 3},
+ {488, 4}, {0, 1}, {542, 3}, {248, 6}, {0, 5}, {205, 3}, {0, 8}, {48, 3},
+ {449, 6}, {0, 2}, {192, 3}, {328, 4}, {9, 5}, {433, 3}, {0, 3}, {622, 25},
+ {615, 5}, {46, 5}, {0, 2}, {104, 3}, {475, 10}, {549, 3}, {0, 4}, {597, 8},
+ {314, 3}, {0, 1}, {473, 6}, {317, 5}, {0, 1}, {400, 3}, {0, 3}, {109, 3},
+ {151, 3}, {48, 4}, {0, 4}, {125, 3}, {108, 3}, {0, 2},
+ }
+
+ var got, want bytes.Buffer
+ var dd dictDecoder
+ dd.init(1<<11, nil)
+
+ var writeCopy = func(dist, length int) {
+ for length > 0 {
+ cnt := dd.tryWriteCopy(dist, length)
+ if cnt == 0 {
+ cnt = dd.writeCopy(dist, length)
+ }
+
+ length -= cnt
+ if dd.availWrite() == 0 {
+ got.Write(dd.readFlush())
+ }
+ }
+ }
+ var writeString = func(str string) {
+ for len(str) > 0 {
+ cnt := copy(dd.writeSlice(), str)
+ str = str[cnt:]
+ dd.writeMark(cnt)
+ if dd.availWrite() == 0 {
+ got.Write(dd.readFlush())
+ }
+ }
+ }
+
+ writeString(".")
+ want.WriteByte('.')
+
+ str := poem
+ for _, ref := range poemRefs {
+ if ref.dist == 0 {
+ writeString(str[:ref.length])
+ } else {
+ writeCopy(ref.dist, ref.length)
+ }
+ str = str[ref.length:]
+ }
+ want.WriteString(poem)
+
+ writeCopy(dd.histSize(), 33)
+ want.Write(want.Bytes()[:33])
+
+ writeString(abc)
+ writeCopy(len(abc), 59*len(abc))
+ want.WriteString(strings.Repeat(abc, 60))
+
+ writeString(fox)
+ writeCopy(len(fox), 9*len(fox))
+ want.WriteString(strings.Repeat(fox, 10))
+
+ writeString(".")
+ writeCopy(1, 9)
+ want.WriteString(strings.Repeat(".", 10))
+
+ writeString(strings.ToUpper(poem))
+ writeCopy(len(poem), 7*len(poem))
+ want.WriteString(strings.Repeat(strings.ToUpper(poem), 8))
+
+ writeCopy(dd.histSize(), 10)
+ want.Write(want.Bytes()[want.Len()-dd.histSize():][:10])
+
+ got.Write(dd.readFlush())
+ if got.String() != want.String() {
+ t.Errorf("final string mismatch:\ngot %q\nwant %q", got.String(), want.String())
+ }
+}
diff --git a/libgo/go/compress/flate/example_test.go b/libgo/go/compress/flate/example_test.go
new file mode 100644
index 0000000000..3d44dde7ae
--- /dev/null
+++ b/libgo/go/compress/flate/example_test.go
@@ -0,0 +1,245 @@
+// 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 flate_test
+
+import (
+ "bytes"
+ "compress/flate"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strings"
+ "sync"
+)
+
+// In performance critical applications, Reset can be used to discard the
+// current compressor or decompressor state and reinitialize them quickly
+// by taking advantage of previously allocated memory.
+func Example_reset() {
+ proverbs := []string{
+ "Don't communicate by sharing memory, share memory by communicating.\n",
+ "Concurrency is not parallelism.\n",
+ "The bigger the interface, the weaker the abstraction.\n",
+ "Documentation is for users.\n",
+ }
+
+ var r strings.Reader
+ var b bytes.Buffer
+ buf := make([]byte, 32<<10)
+
+ zw, err := flate.NewWriter(nil, flate.DefaultCompression)
+ if err != nil {
+ log.Fatal(err)
+ }
+ zr := flate.NewReader(nil)
+
+ for _, s := range proverbs {
+ r.Reset(s)
+ b.Reset()
+
+ // Reset the compressor and encode from some input stream.
+ zw.Reset(&b)
+ if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
+ log.Fatal(err)
+ }
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Reset the decompressor and decode to some output stream.
+ if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
+ log.Fatal(err)
+ }
+ if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ // Output:
+ // Don't communicate by sharing memory, share memory by communicating.
+ // Concurrency is not parallelism.
+ // The bigger the interface, the weaker the abstraction.
+ // Documentation is for users.
+}
+
+// A preset dictionary can be used to improve the compression ratio.
+// The downside to using a dictionary is that the compressor and decompressor
+// must agree in advance what dictionary to use.
+func Example_dictionary() {
+ // The dictionary is a string of bytes. When compressing some input data,
+ // the compressor will attempt to substitute substrings with matches found
+ // in the dictionary. As such, the dictionary should only contain substrings
+ // that are expected to be found in the actual data stream.
+ const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
+
+ // The data to compress should (but is not required to) contain frequent
+ // substrings that match those in the dictionary.
+ const data = `<?xml version="1.0"?>
+<book>
+ <meta name="title" content="The Go Programming Language"/>
+ <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+ <meta name="published" content="2015-10-26"/>
+ <meta name="isbn" content="978-0134190440"/>
+ <data>...</data>
+</book>
+`
+
+ var b bytes.Buffer
+
+ // Compress the data using the specially crafted dictionary.
+ zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
+ log.Fatal(err)
+ }
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // The decompressor must use the same dictionary as the compressor.
+ // Otherwise, the input may appear as corrupted.
+ fmt.Println("Decompressed output using the dictionary:")
+ zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println()
+
+ // Substitute all of the bytes in the dictionary with a '#' to visually
+ // demonstrate the approximate effectiveness of using a preset dictionary.
+ fmt.Println("Substrings matched by the dictionary are marked with #:")
+ hashDict := []byte(dict)
+ for i := range hashDict {
+ hashDict[i] = '#'
+ }
+ zr = flate.NewReaderDict(&b, hashDict)
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Decompressed output using the dictionary:
+ // <?xml version="1.0"?>
+ // <book>
+ // <meta name="title" content="The Go Programming Language"/>
+ // <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+ // <meta name="published" content="2015-10-26"/>
+ // <meta name="isbn" content="978-0134190440"/>
+ // <data>...</data>
+ // </book>
+ //
+ // Substrings matched by the dictionary are marked with #:
+ // #####################
+ // ######
+ // ############title###########The Go Programming Language"/#
+ // ############authors###########Alan Donovan and Brian Kernighan"/#
+ // ############published###########2015-10-26"/#
+ // ############isbn###########978-0134190440"/#
+ // ######...</#####
+ // </#####
+}
+
+// DEFLATE is suitable for transmitting compressed data across the network.
+func Example_synchronization() {
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ // Use io.Pipe to simulate a network connection.
+ // A real network application should take care to properly close the
+ // underlying connection.
+ rp, wp := io.Pipe()
+
+ // Start a goroutine to act as the transmitter.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ zw, err := flate.NewWriter(wp, flate.BestSpeed)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ b := make([]byte, 256)
+ for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
+ // We use a simple framing format where the first byte is the
+ // message length, followed the message itself.
+ b[0] = uint8(copy(b[1:], m))
+
+ if _, err := zw.Write(b[:1+len(m)]); err != nil {
+ log.Fatal(err)
+ }
+
+ // Flush ensures that the receiver can read all data sent so far.
+ if err := zw.Flush(); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ // Start a goroutine to act as the receiver.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ zr := flate.NewReader(rp)
+
+ b := make([]byte, 256)
+ for {
+ // Read the message length.
+ // This is guaranteed to return for every corresponding
+ // Flush and Close on the transmitter side.
+ if _, err := io.ReadFull(zr, b[:1]); err != nil {
+ if err == io.EOF {
+ break // The transmitter closed the stream
+ }
+ log.Fatal(err)
+ }
+
+ // Read the message content.
+ n := int(b[0])
+ if _, err := io.ReadFull(zr, b[:n]); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Received %d bytes: %s\n", n, b[:n])
+ }
+ fmt.Println()
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ // Output:
+ // Received 1 bytes: A
+ // Received 4 bytes: long
+ // Received 4 bytes: time
+ // Received 3 bytes: ago
+ // Received 2 bytes: in
+ // Received 1 bytes: a
+ // Received 6 bytes: galaxy
+ // Received 4 bytes: far,
+ // Received 3 bytes: far
+ // Received 7 bytes: away...
+}
diff --git a/libgo/go/compress/flate/flate_test.go b/libgo/go/compress/flate/flate_test.go
index 341d807131..1e45077bd5 100644
--- a/libgo/go/compress/flate/flate_test.go
+++ b/libgo/go/compress/flate/flate_test.go
@@ -272,3 +272,82 @@ func TestTruncatedStreams(t *testing.T) {
}
}
}
+
+// Verify that flate.Reader.Read returns (n, io.EOF) instead
+// of (n, nil) + (0, io.EOF) when possible.
+//
+// This helps net/http.Transport reuse HTTP/1 connections more
+// aggressively.
+//
+// See https://github.com/google/go-github/pull/317 for background.
+func TestReaderEarlyEOF(t *testing.T) {
+ t.Parallel()
+ testSizes := []int{
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 100, 1000, 10000, 100000,
+ 128, 1024, 16384, 131072,
+
+ // Testing multiples of windowSize triggers the case
+ // where Read will fail to return an early io.EOF.
+ windowSize * 1, windowSize * 2, windowSize * 3,
+ }
+
+ var maxSize int
+ for _, n := range testSizes {
+ if maxSize < n {
+ maxSize = n
+ }
+ }
+
+ readBuf := make([]byte, 40)
+ data := make([]byte, maxSize)
+ for i := range data {
+ data[i] = byte(i)
+ }
+
+ for _, sz := range testSizes {
+ if testing.Short() && sz > windowSize {
+ continue
+ }
+ for _, flush := range []bool{true, false} {
+ earlyEOF := true // Do we expect early io.EOF?
+
+ var buf bytes.Buffer
+ w, _ := NewWriter(&buf, 5)
+ w.Write(data[:sz])
+ if flush {
+ // If a Flush occurs after all the actual data, the flushing
+ // semantics dictate that we will observe a (0, io.EOF) since
+ // Read must return data before it knows that the stream ended.
+ w.Flush()
+ earlyEOF = false
+ }
+ w.Close()
+
+ r := NewReader(&buf)
+ for {
+ n, err := r.Read(readBuf)
+ if err == io.EOF {
+ // If the availWrite == windowSize, then that means that the
+ // previous Read returned because the write buffer was full
+ // and it just so happened that the stream had no more data.
+ // This situation is rare, but unavoidable.
+ if r.(*decompressor).dict.availWrite() == windowSize {
+ earlyEOF = false
+ }
+
+ if n == 0 && earlyEOF {
+ t.Errorf("On size:%d flush:%v, Read() = (0, io.EOF), want (n, io.EOF)", sz, flush)
+ }
+ if n != 0 && !earlyEOF {
+ t.Errorf("On size:%d flush:%v, Read() = (%d, io.EOF), want (0, io.EOF)", sz, flush, n)
+ }
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go
index 616440412e..6cd6281249 100644
--- a/libgo/go/compress/flate/huffman_bit_writer.go
+++ b/libgo/go/compress/flate/huffman_bit_writer.go
@@ -6,7 +6,6 @@ package flate
import (
"io"
- "math"
)
const (
@@ -22,6 +21,17 @@ const (
// The number of codegen codes.
codegenCodeCount = 19
badCode = 255
+
+ // bufferFlushSize indicates the buffer size
+ // after which bytes are flushed to the writer.
+ // Should preferably be a multiple of 6, since
+ // we accumulate 6 bytes between writes to the buffer.
+ bufferFlushSize = 240
+
+ // bufferSize is the actual output byte buffer size.
+ // It must have additional headroom for a flush
+ // which can contain up to 8 bytes.
+ bufferSize = bufferFlushSize + 8
)
// The number of extra bits needed by length code X - LENGTH_CODES_START.
@@ -67,17 +77,21 @@ var offsetBase = []uint32{
var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
type huffmanBitWriter struct {
- w io.Writer
+ // writer is the underlying writer.
+ // Do not use it directly; use the write method, which ensures
+ // that Write errors are sticky.
+ writer io.Writer
+
// Data waiting to be written is bytes[0:nbytes]
// and then the low nbits of bits.
- bits uint32
- nbits uint32
- bytes [64]byte
+ bits uint64
+ nbits uint
+ bytes [bufferSize]byte
+ codegenFreq [codegenCodeCount]int32
nbytes int
literalFreq []int32
offsetFreq []int32
codegen []uint8
- codegenFreq []int32
literalEncoding *huffmanEncoder
offsetEncoding *huffmanEncoder
codegenEncoding *huffmanEncoder
@@ -86,58 +100,20 @@ type huffmanBitWriter struct {
func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
return &huffmanBitWriter{
- w: w,
+ writer: w,
literalFreq: make([]int32, maxNumLit),
offsetFreq: make([]int32, offsetCodeCount),
codegen: make([]uint8, maxNumLit+offsetCodeCount+1),
- codegenFreq: make([]int32, codegenCodeCount),
literalEncoding: newHuffmanEncoder(maxNumLit),
- offsetEncoding: newHuffmanEncoder(offsetCodeCount),
codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+ offsetEncoding: newHuffmanEncoder(offsetCodeCount),
}
}
func (w *huffmanBitWriter) reset(writer io.Writer) {
- w.w = writer
+ w.writer = writer
w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
- w.bytes = [64]byte{}
- for i := range w.codegen {
- w.codegen[i] = 0
- }
- for _, s := range [...][]int32{w.literalFreq, w.offsetFreq, w.codegenFreq} {
- for i := range s {
- s[i] = 0
- }
- }
- for _, enc := range [...]*huffmanEncoder{
- w.literalEncoding,
- w.offsetEncoding,
- w.codegenEncoding} {
- for i := range enc.code {
- enc.code[i] = 0
- }
- for i := range enc.codeBits {
- enc.codeBits[i] = 0
- }
- }
-}
-
-func (w *huffmanBitWriter) flushBits() {
- if w.err != nil {
- w.nbits = 0
- return
- }
- bits := w.bits
- w.bits >>= 16
- w.nbits -= 16
- n := w.nbytes
- w.bytes[n] = byte(bits)
- w.bytes[n+1] = byte(bits >> 8)
- if n += 2; n >= len(w.bytes) {
- _, w.err = w.w.Write(w.bytes[0:])
- n = 0
- }
- w.nbytes = n
+ w.bytes = [bufferSize]byte{}
}
func (w *huffmanBitWriter) flush() {
@@ -146,26 +122,52 @@ func (w *huffmanBitWriter) flush() {
return
}
n := w.nbytes
- if w.nbits > 8 {
+ for w.nbits != 0 {
w.bytes[n] = byte(w.bits)
w.bits >>= 8
- w.nbits -= 8
- n++
- }
- if w.nbits > 0 {
- w.bytes[n] = byte(w.bits)
- w.nbits = 0
+ if w.nbits > 8 { // Avoid underflow
+ w.nbits -= 8
+ } else {
+ w.nbits = 0
+ }
n++
}
w.bits = 0
- _, w.err = w.w.Write(w.bytes[0:n])
+ w.write(w.bytes[:n])
w.nbytes = 0
}
-func (w *huffmanBitWriter) writeBits(b, nb int32) {
- w.bits |= uint32(b) << w.nbits
- if w.nbits += uint32(nb); w.nbits >= 16 {
- w.flushBits()
+func (w *huffmanBitWriter) write(b []byte) {
+ if w.err != nil {
+ return
+ }
+ _, w.err = w.writer.Write(b)
+}
+
+func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
+ if w.err != nil {
+ return
+ }
+ w.bits |= uint64(b) << w.nbits
+ w.nbits += nb
+ if w.nbits >= 48 {
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ n := w.nbytes
+ bytes := w.bytes[n : n+6]
+ bytes[0] = byte(bits)
+ bytes[1] = byte(bits >> 8)
+ bytes[2] = byte(bits >> 16)
+ bytes[3] = byte(bits >> 24)
+ bytes[4] = byte(bits >> 32)
+ bytes[5] = byte(bits >> 40)
+ n += 6
+ if n >= bufferFlushSize {
+ w.write(w.bytes[:n])
+ n = 0
+ }
+ w.nbytes = n
}
}
@@ -174,23 +176,21 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
return
}
n := w.nbytes
- if w.nbits == 8 {
- w.bytes[n] = byte(w.bits)
- w.nbits = 0
- n++
- }
- if w.nbits != 0 {
+ if w.nbits&7 != 0 {
w.err = InternalError("writeBytes with unfinished bits")
return
}
+ for w.nbits != 0 {
+ w.bytes[n] = byte(w.bits)
+ w.bits >>= 8
+ w.nbits -= 8
+ n++
+ }
if n != 0 {
- _, w.err = w.w.Write(w.bytes[0:n])
- if w.err != nil {
- return
- }
+ w.write(w.bytes[:n])
}
w.nbytes = 0
- _, w.err = w.w.Write(bytes)
+ w.write(bytes)
}
// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
@@ -200,11 +200,12 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
// The result is written into the codegen array, and the frequencies
// of each code is written into the codegenFreq array.
// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
-// information. Code badCode is an end marker
+// information. Code badCode is an end marker
//
// numLiterals The number of literals in literalEncoding
// numOffsets The number of offsets in offsetEncoding
-func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
+// litenc, offenc The literal and offset encoder to use
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) {
for i := range w.codegenFreq {
w.codegenFreq[i] = 0
}
@@ -213,9 +214,16 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
// This is fine because the output is always shorter than the input used
// so far.
codegen := w.codegen // cache
- // Copy the concatenated code sizes to codegen. Put a marker at the end.
- copy(codegen[0:numLiterals], w.literalEncoding.codeBits)
- copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+ // Copy the concatenated code sizes to codegen. Put a marker at the end.
+ cgnl := codegen[:numLiterals]
+ for i := range cgnl {
+ cgnl[i] = uint8(litEnc.codes[i].len)
+ }
+
+ cgnl = codegen[numLiterals : numLiterals+numOffsets]
+ for i := range cgnl {
+ cgnl[i] = uint8(offEnc.codes[i].len)
+ }
codegen[numLiterals+numOffsets] = badCode
size := codegen[0]
@@ -284,11 +292,71 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
codegen[outIndex] = badCode
}
-func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
+ numCodegens = len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ header := 3 + 5 + 5 + 4 + (3 * numCodegens) +
+ w.codegenEncoding.bitLength(w.codegenFreq[:]) +
+ int(w.codegenFreq[16])*2 +
+ int(w.codegenFreq[17])*3 +
+ int(w.codegenFreq[18])*7
+ size = header +
+ litEnc.bitLength(w.literalFreq) +
+ offEnc.bitLength(w.offsetFreq) +
+ extraBits
+
+ return size, numCodegens
+}
+
+// fixedSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) fixedSize(extraBits int) int {
+ return 3 +
+ fixedLiteralEncoding.bitLength(w.literalFreq) +
+ fixedOffsetEncoding.bitLength(w.offsetFreq) +
+ extraBits
+}
+
+// storedSize calculates the stored size, including header.
+// The function returns the size in bits and whether the block
+// fits inside a single block.
+func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) {
+ if in == nil {
+ return 0, false
+ }
+ if len(in) <= maxStoreBlockSize {
+ return (len(in) + 5) * 8, true
+ }
+ return 0, false
+}
+
+func (w *huffmanBitWriter) writeCode(c hcode) {
if w.err != nil {
return
}
- w.writeBits(int32(code.code[literal]), int32(code.codeBits[literal]))
+ w.bits |= uint64(c.code) << w.nbits
+ w.nbits += uint(c.len)
+ if w.nbits >= 48 {
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ n := w.nbytes
+ bytes := w.bytes[n : n+6]
+ bytes[0] = byte(bits)
+ bytes[1] = byte(bits >> 8)
+ bytes[2] = byte(bits >> 16)
+ bytes[3] = byte(bits >> 24)
+ bytes[4] = byte(bits >> 32)
+ bytes[5] = byte(bits >> 40)
+ n += 6
+ if n >= bufferFlushSize {
+ w.write(w.bytes[:n])
+ n = 0
+ }
+ w.nbytes = n
+ }
}
// Write the header of a dynamic Huffman block to the output stream.
@@ -310,7 +378,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
w.writeBits(int32(numCodegens-4), 4)
for i := 0; i < numCodegens; i++ {
- value := w.codegenEncoding.codeBits[codegenOrder[i]]
+ value := uint(w.codegenEncoding.codes[codegenOrder[i]].len)
w.writeBits(int32(value), 3)
}
@@ -321,8 +389,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
if codeWord == badCode {
break
}
- // The low byte contains the actual code to generate.
- w.writeCode(w.codegenEncoding, uint32(codeWord))
+ w.writeCode(w.codegenEncoding.codes[uint32(codeWord)])
switch codeWord {
case 16:
@@ -367,10 +434,113 @@ func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
w.writeBits(value, 3)
}
+// writeBlock will write a block of tokens with the smallest encoding.
+// The original input can be supplied, and if the huffman encoded data
+// is larger than the original bytes, the data will be written as a
+// stored block.
+// If the input is nil, the tokens will always be Huffman encoded.
func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
if w.err != nil {
return
}
+
+ tokens = append(tokens, endBlockMarker)
+ numLiterals, numOffsets := w.indexTokens(tokens)
+
+ var extraBits int
+ storedSize, storable := w.storedSize(input)
+ if storable {
+ // We only bother calculating the costs of the extra bits required by
+ // the length of offset fields (which will be the same for both fixed
+ // and dynamic encoding), if we need to compare those two encodings
+ // against stored encoding.
+ for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+ // First eight length codes have extra size = 0.
+ extraBits += int(w.literalFreq[lengthCode]) * int(lengthExtraBits[lengthCode-lengthCodesStart])
+ }
+ for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+ // First four offset codes have extra size = 0.
+ extraBits += int(w.offsetFreq[offsetCode]) * int(offsetExtraBits[offsetCode])
+ }
+ }
+
+ // Figure out smallest code.
+ // Fixed Huffman baseline.
+ var literalEncoding = fixedLiteralEncoding
+ var offsetEncoding = fixedOffsetEncoding
+ var size = w.fixedSize(extraBits)
+
+ // Dynamic Huffman?
+ var numCodegens int
+
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+ dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
+
+ if dynamicSize < size {
+ size = dynamicSize
+ literalEncoding = w.literalEncoding
+ offsetEncoding = w.offsetEncoding
+ }
+
+ // Stored bytes?
+ if storable && storedSize < size {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+
+ // Huffman.
+ if literalEncoding == fixedLiteralEncoding {
+ w.writeFixedHeader(eof)
+ } else {
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ }
+
+ // Write the tokens.
+ w.writeTokens(tokens, literalEncoding.codes, offsetEncoding.codes)
+}
+
+// writeBlockDynamic encodes a block using a dynamic Huffman table.
+// This should be used if the symbols used have a disproportionate
+// histogram distribution.
+// If input is supplied and the compression savings are below 1/16th of the
+// input size the block is stored.
+func (w *huffmanBitWriter) writeBlockDynamic(tokens []token, eof bool, input []byte) {
+ if w.err != nil {
+ return
+ }
+
+ tokens = append(tokens, endBlockMarker)
+ numLiterals, numOffsets := w.indexTokens(tokens)
+
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+ size, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, 0)
+
+ // Store bytes, if we don't get a reasonable improvement.
+ if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+
+ // Write Huffman table.
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+
+ // Write the tokens.
+ w.writeTokens(tokens, w.literalEncoding.codes, w.offsetEncoding.codes)
+}
+
+// indexTokens indexes a slice of tokens, and updates
+// literalFreq and offsetFreq, and generates literalEncoding
+// and offsetEncoding.
+// The number of literal and offset tokens is returned.
+func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets int) {
for i := range w.literalFreq {
w.literalFreq[i] = 0
}
@@ -378,29 +548,24 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
w.offsetFreq[i] = 0
}
- n := len(tokens)
- tokens = tokens[0 : n+1]
- tokens[n] = endBlockMarker
-
for _, t := range tokens {
- switch t.typ() {
- case literalType:
+ if t < matchType {
w.literalFreq[t.literal()]++
- case matchType:
- length := t.length()
- offset := t.offset()
- w.literalFreq[lengthCodesStart+lengthCode(length)]++
- w.offsetFreq[offsetCode(offset)]++
+ continue
}
+ length := t.length()
+ offset := t.offset()
+ w.literalFreq[lengthCodesStart+lengthCode(length)]++
+ w.offsetFreq[offsetCode(offset)]++
}
// get the number of literals
- numLiterals := len(w.literalFreq)
+ numLiterals = len(w.literalFreq)
for w.literalFreq[numLiterals-1] == 0 {
numLiterals--
}
// get the number of offsets
- numOffsets := len(w.offsetFreq)
+ numOffsets = len(w.offsetFreq)
for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
numOffsets--
}
@@ -410,108 +575,137 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
w.offsetFreq[0] = 1
numOffsets = 1
}
-
w.literalEncoding.generate(w.literalFreq, 15)
w.offsetEncoding.generate(w.offsetFreq, 15)
+ return
+}
- storedBytes := 0
- if input != nil {
- storedBytes = len(input)
+// writeTokens writes a slice of tokens to the output.
+// codes for literal and offset encoding must be supplied.
+func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
+ if w.err != nil {
+ return
}
- var extraBits int64
- var storedSize int64 = math.MaxInt64
- if storedBytes <= maxStoreBlockSize && input != nil {
- storedSize = int64((storedBytes + 5) * 8)
- // We only bother calculating the costs of the extra bits required by
- // the length of offset fields (which will be the same for both fixed
- // and dynamic encoding), if we need to compare those two encodings
- // against stored encoding.
- for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
- // First eight length codes have extra size = 0.
- extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart])
+ for _, t := range tokens {
+ if t < matchType {
+ w.writeCode(leCodes[t.literal()])
+ continue
}
- for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
- // First four offset codes have extra size = 0.
- extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode])
+ // Write the length
+ length := t.length()
+ lengthCode := lengthCode(length)
+ w.writeCode(leCodes[lengthCode+lengthCodesStart])
+ extraLengthBits := uint(lengthExtraBits[lengthCode])
+ if extraLengthBits > 0 {
+ extraLength := int32(length - lengthBase[lengthCode])
+ w.writeBits(extraLength, extraLengthBits)
+ }
+ // Write the offset
+ offset := t.offset()
+ offsetCode := offsetCode(offset)
+ w.writeCode(oeCodes[offsetCode])
+ extraOffsetBits := uint(offsetExtraBits[offsetCode])
+ if extraOffsetBits > 0 {
+ extraOffset := int32(offset - offsetBase[offsetCode])
+ w.writeBits(extraOffset, extraOffsetBits)
}
}
+}
- // Figure out smallest code.
- // Fixed Huffman baseline.
- var size = int64(3) +
- fixedLiteralEncoding.bitLength(w.literalFreq) +
- fixedOffsetEncoding.bitLength(w.offsetFreq) +
- extraBits
- var literalEncoding = fixedLiteralEncoding
- var offsetEncoding = fixedOffsetEncoding
+// huffOffset is a static offset encoder used for huffman only encoding.
+// It can be reused since we will not be encoding offset values.
+var huffOffset *huffmanEncoder
- // Dynamic Huffman?
- var numCodegens int
+func init() {
+ w := newHuffmanBitWriter(nil)
+ w.offsetFreq[0] = 1
+ huffOffset = newHuffmanEncoder(offsetCodeCount)
+ huffOffset.generate(w.offsetFreq, 15)
+}
- // Generate codegen and codegenFrequencies, which indicates how to encode
- // the literalEncoding and the offsetEncoding.
- w.generateCodegen(numLiterals, numOffsets)
- w.codegenEncoding.generate(w.codegenFreq, 7)
- numCodegens = len(w.codegenFreq)
- for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
- numCodegens--
+// writeBlockHuff encodes a block of bytes as either
+// Huffman encoded literals or uncompressed bytes if the
+// results only gains very little from compression.
+func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
+ if w.err != nil {
+ return
}
- dynamicHeader := int64(3+5+5+4+(3*numCodegens)) +
- w.codegenEncoding.bitLength(w.codegenFreq) +
- int64(extraBits) +
- int64(w.codegenFreq[16]*2) +
- int64(w.codegenFreq[17]*3) +
- int64(w.codegenFreq[18]*7)
- dynamicSize := dynamicHeader +
- w.literalEncoding.bitLength(w.literalFreq) +
- w.offsetEncoding.bitLength(w.offsetFreq)
- if dynamicSize < size {
- size = dynamicSize
- literalEncoding = w.literalEncoding
- offsetEncoding = w.offsetEncoding
+ // Clear histogram
+ for i := range w.literalFreq {
+ w.literalFreq[i] = 0
}
- // Stored bytes?
- if storedSize < size {
- w.writeStoredHeader(storedBytes, eof)
- w.writeBytes(input[0:storedBytes])
+ // Add everything as literals
+ histogram(input, w.literalFreq)
+
+ w.literalFreq[endBlockMarker] = 1
+
+ const numLiterals = endBlockMarker + 1
+ const numOffsets = 1
+
+ w.literalEncoding.generate(w.literalFreq, 15)
+
+ // Figure out smallest code.
+ // Always use dynamic Huffman or Store
+ var numCodegens int
+
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+ size, numCodegens := w.dynamicSize(w.literalEncoding, huffOffset, 0)
+
+ // Store bytes, if we don't get a reasonable improvement.
+ if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
return
}
// Huffman.
- if literalEncoding == fixedLiteralEncoding {
- w.writeFixedHeader(eof)
- } else {
- w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
- }
- for _, t := range tokens {
- switch t.typ() {
- case literalType:
- w.writeCode(literalEncoding, t.literal())
- break
- case matchType:
- // Write the length
- length := t.length()
- lengthCode := lengthCode(length)
- w.writeCode(literalEncoding, lengthCode+lengthCodesStart)
- extraLengthBits := int32(lengthExtraBits[lengthCode])
- if extraLengthBits > 0 {
- extraLength := int32(length - lengthBase[lengthCode])
- w.writeBits(extraLength, extraLengthBits)
- }
- // Write the offset
- offset := t.offset()
- offsetCode := offsetCode(offset)
- w.writeCode(offsetEncoding, offsetCode)
- extraOffsetBits := int32(offsetExtraBits[offsetCode])
- if extraOffsetBits > 0 {
- extraOffset := int32(offset - offsetBase[offsetCode])
- w.writeBits(extraOffset, extraOffsetBits)
- }
- break
- default:
- panic("unknown token type: " + string(t))
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ encoding := w.literalEncoding.codes[:257]
+ n := w.nbytes
+ for _, t := range input {
+ // Bitwriting inlined, ~30% speedup
+ c := encoding[t]
+ w.bits |= uint64(c.code) << w.nbits
+ w.nbits += uint(c.len)
+ if w.nbits < 48 {
+ continue
+ }
+ // Store 6 bytes
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ bytes := w.bytes[n : n+6]
+ bytes[0] = byte(bits)
+ bytes[1] = byte(bits >> 8)
+ bytes[2] = byte(bits >> 16)
+ bytes[3] = byte(bits >> 24)
+ bytes[4] = byte(bits >> 32)
+ bytes[5] = byte(bits >> 40)
+ n += 6
+ if n < bufferFlushSize {
+ continue
+ }
+ w.write(w.bytes[:n])
+ if w.err != nil {
+ return // Return early in the event of write failures
}
+ n = 0
+ }
+ w.nbytes = n
+ w.writeCode(encoding[endBlockMarker])
+}
+
+// histogram accumulates a histogram of b in h.
+//
+// len(h) must be >= 256, and h's elements must be all zeroes.
+func histogram(b []byte, h []int32) {
+ h = h[:256]
+ for _, t := range b {
+ h[t]++
}
}
diff --git a/libgo/go/compress/flate/huffman_bit_writer_test.go b/libgo/go/compress/flate/huffman_bit_writer_test.go
new file mode 100644
index 0000000000..882d3abec1
--- /dev/null
+++ b/libgo/go/compress/flate/huffman_bit_writer_test.go
@@ -0,0 +1,366 @@
+// 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 flate
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var update = flag.Bool("update", false, "update reference files")
+
+// TestBlockHuff tests huffman encoding against reference files
+// to detect possible regressions.
+// If encoding/bit allocation changes you can regenerate these files
+// by using the -update flag.
+func TestBlockHuff(t *testing.T) {
+ // determine input files
+ match, err := filepath.Glob("testdata/huffman-*.in")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, in := range match {
+ out := in // for files where input and output are identical
+ if strings.HasSuffix(in, ".in") {
+ out = in[:len(in)-len(".in")] + ".golden"
+ }
+ testBlockHuff(t, in, out)
+ }
+}
+
+func testBlockHuff(t *testing.T, in, out string) {
+ all, err := ioutil.ReadFile(in)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var buf bytes.Buffer
+ bw := newHuffmanBitWriter(&buf)
+ bw.writeBlockHuff(false, all)
+ bw.flush()
+ got := buf.Bytes()
+
+ want, err := ioutil.ReadFile(out)
+ if err != nil && !*update {
+ t.Error(err)
+ return
+ }
+
+ t.Logf("Testing %q", in)
+ if !bytes.Equal(got, want) {
+ if *update {
+ if in != out {
+ t.Logf("Updating %q", out)
+ if err := ioutil.WriteFile(out, got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ // in == out: don't accidentally destroy input
+ t.Errorf("WARNING: -update did not rewrite input file %s", in)
+ }
+
+ t.Errorf("%q != %q (see %q)", in, out, in+".got")
+ if err := ioutil.WriteFile(in+".got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ t.Log("Output ok")
+
+ // Test if the writer produces the same output after reset.
+ buf.Reset()
+ bw.reset(&buf)
+ bw.writeBlockHuff(false, all)
+ bw.flush()
+ got = buf.Bytes()
+ if !bytes.Equal(got, want) {
+ t.Errorf("after reset %q != %q (see %q)", in, out, in+".reset.got")
+ if err := ioutil.WriteFile(in+".reset.got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ t.Log("Reset ok")
+ testWriterEOF(t, "huff", huffTest{input: in}, true)
+}
+
+type huffTest struct {
+ tokens []token
+ input string // File name of input data matching the tokens.
+ want string // File name of data with the expected output with input available.
+ wantNoInput string // File name of the expected output when no input is available.
+}
+
+const ml = 0x7fc00000 // Maximum length token. Used to reduce the size of writeBlockTests
+
+var writeBlockTests = []huffTest{
+ {
+ input: "testdata/huffman-null-max.in",
+ want: "testdata/huffman-null-max.%s.expect",
+ wantNoInput: "testdata/huffman-null-max.%s.expect-noinput",
+ tokens: []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, 0x0, 0x0},
+ },
+ {
+ input: "testdata/huffman-pi.in",
+ want: "testdata/huffman-pi.%s.expect",
+ wantNoInput: "testdata/huffman-pi.%s.expect-noinput",
+ tokens: []token{0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x38, 0x39, 0x37, 0x39, 0x33, 0x32, 0x33, 0x38, 0x34, 0x36, 0x32, 0x36, 0x34, 0x33, 0x33, 0x38, 0x33, 0x32, 0x37, 0x39, 0x35, 0x30, 0x32, 0x38, 0x38, 0x34, 0x31, 0x39, 0x37, 0x31, 0x36, 0x39, 0x33, 0x39, 0x39, 0x33, 0x37, 0x35, 0x31, 0x30, 0x35, 0x38, 0x32, 0x30, 0x39, 0x37, 0x34, 0x39, 0x34, 0x34, 0x35, 0x39, 0x32, 0x33, 0x30, 0x37, 0x38, 0x31, 0x36, 0x34, 0x30, 0x36, 0x32, 0x38, 0x36, 0x32, 0x30, 0x38, 0x39, 0x39, 0x38, 0x36, 0x32, 0x38, 0x30, 0x33, 0x34, 0x38, 0x32, 0x35, 0x33, 0x34, 0x32, 0x31, 0x31, 0x37, 0x30, 0x36, 0x37, 0x39, 0x38, 0x32, 0x31, 0x34, 0x38, 0x30, 0x38, 0x36, 0x35, 0x31, 0x33, 0x32, 0x38, 0x32, 0x33, 0x30, 0x36, 0x36, 0x34, 0x37, 0x30, 0x39, 0x33, 0x38, 0x34, 0x34, 0x36, 0x30, 0x39, 0x35, 0x35, 0x30, 0x35, 0x38, 0x32, 0x32, 0x33, 0x31, 0x37, 0x32, 0x35, 0x33, 0x35, 0x39, 0x34, 0x30, 0x38, 0x31, 0x32, 0x38, 0x34, 0x38, 0x31, 0x31, 0x31, 0x37, 0x34, 0x4040007e, 0x34, 0x31, 0x30, 0x32, 0x37, 0x30, 0x31, 0x39, 0x33, 0x38, 0x35, 0x32, 0x31, 0x31, 0x30, 0x35, 0x35, 0x35, 0x39, 0x36, 0x34, 0x34, 0x36, 0x32, 0x32, 0x39, 0x34, 0x38, 0x39, 0x35, 0x34, 0x39, 0x33, 0x30, 0x33, 0x38, 0x31, 0x40400012, 0x32, 0x38, 0x38, 0x31, 0x30, 0x39, 0x37, 0x35, 0x36, 0x36, 0x35, 0x39, 0x33, 0x33, 0x34, 0x34, 0x36, 0x40400047, 0x37, 0x35, 0x36, 0x34, 0x38, 0x32, 0x33, 0x33, 0x37, 0x38, 0x36, 0x37, 0x38, 0x33, 0x31, 0x36, 0x35, 0x32, 0x37, 0x31, 0x32, 0x30, 0x31, 0x39, 0x30, 0x39, 0x31, 0x34, 0x4040001a, 0x35, 0x36, 0x36, 0x39, 0x32, 0x33, 0x34, 0x36, 0x404000b2, 0x36, 0x31, 0x30, 0x34, 0x35, 0x34, 0x33, 0x32, 0x36, 0x40400032, 0x31, 0x33, 0x33, 0x39, 0x33, 0x36, 0x30, 0x37, 0x32, 0x36, 0x30, 0x32, 0x34, 0x39, 0x31, 0x34, 0x31, 0x32, 0x37, 0x33, 0x37, 0x32, 0x34, 0x35, 0x38, 0x37, 0x30, 0x30, 0x36, 0x36, 0x30, 0x36, 0x33, 0x31, 0x35, 0x35, 0x38, 0x38, 0x31, 0x37, 0x34, 0x38, 0x38, 0x31, 0x35, 0x32, 0x30, 0x39, 0x32, 0x30, 0x39, 0x36, 0x32, 0x38, 0x32, 0x39, 0x32, 0x35, 0x34, 0x30, 0x39, 0x31, 0x37, 0x31, 0x35, 0x33, 0x36, 0x34, 0x33, 0x36, 0x37, 0x38, 0x39, 0x32, 0x35, 0x39, 0x30, 0x33, 0x36, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x30, 0x35, 0x33, 0x30, 0x35, 0x34, 0x38, 0x38, 0x32, 0x30, 0x34, 0x36, 0x36, 0x35, 0x32, 0x31, 0x33, 0x38, 0x34, 0x31, 0x34, 0x36, 0x39, 0x35, 0x31, 0x39, 0x34, 0x31, 0x35, 0x31, 0x31, 0x36, 0x30, 0x39, 0x34, 0x33, 0x33, 0x30, 0x35, 0x37, 0x32, 0x37, 0x30, 0x33, 0x36, 0x35, 0x37, 0x35, 0x39, 0x35, 0x39, 0x31, 0x39, 0x35, 0x33, 0x30, 0x39, 0x32, 0x31, 0x38, 0x36, 0x31, 0x31, 0x37, 0x404000e9, 0x33, 0x32, 0x40400009, 0x39, 0x33, 0x31, 0x30, 0x35, 0x31, 0x31, 0x38, 0x35, 0x34, 0x38, 0x30, 0x37, 0x4040010e, 0x33, 0x37, 0x39, 0x39, 0x36, 0x32, 0x37, 0x34, 0x39, 0x35, 0x36, 0x37, 0x33, 0x35, 0x31, 0x38, 0x38, 0x35, 0x37, 0x35, 0x32, 0x37, 0x32, 0x34, 0x38, 0x39, 0x31, 0x32, 0x32, 0x37, 0x39, 0x33, 0x38, 0x31, 0x38, 0x33, 0x30, 0x31, 0x31, 0x39, 0x34, 0x39, 0x31, 0x32, 0x39, 0x38, 0x33, 0x33, 0x36, 0x37, 0x33, 0x33, 0x36, 0x32, 0x34, 0x34, 0x30, 0x36, 0x35, 0x36, 0x36, 0x34, 0x33, 0x30, 0x38, 0x36, 0x30, 0x32, 0x31, 0x33, 0x39, 0x34, 0x39, 0x34, 0x36, 0x33, 0x39, 0x35, 0x32, 0x32, 0x34, 0x37, 0x33, 0x37, 0x31, 0x39, 0x30, 0x37, 0x30, 0x32, 0x31, 0x37, 0x39, 0x38, 0x40800099, 0x37, 0x30, 0x32, 0x37, 0x37, 0x30, 0x35, 0x33, 0x39, 0x32, 0x31, 0x37, 0x31, 0x37, 0x36, 0x32, 0x39, 0x33, 0x31, 0x37, 0x36, 0x37, 0x35, 0x40800232, 0x37, 0x34, 0x38, 0x31, 0x40400006, 0x36, 0x36, 0x39, 0x34, 0x30, 0x404001e7, 0x30, 0x30, 0x30, 0x35, 0x36, 0x38, 0x31, 0x32, 0x37, 0x31, 0x34, 0x35, 0x32, 0x36, 0x33, 0x35, 0x36, 0x30, 0x38, 0x32, 0x37, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x33, 0x34, 0x32, 0x37, 0x35, 0x37, 0x37, 0x38, 0x39, 0x36, 0x40400129, 0x33, 0x36, 0x33, 0x37, 0x31, 0x37, 0x38, 0x37, 0x32, 0x31, 0x34, 0x36, 0x38, 0x34, 0x34, 0x30, 0x39, 0x30, 0x31, 0x32, 0x32, 0x34, 0x39, 0x35, 0x33, 0x34, 0x33, 0x30, 0x31, 0x34, 0x36, 0x35, 0x34, 0x39, 0x35, 0x38, 0x35, 0x33, 0x37, 0x31, 0x30, 0x35, 0x30, 0x37, 0x39, 0x404000ca, 0x36, 0x40400153, 0x38, 0x39, 0x32, 0x33, 0x35, 0x34, 0x404001c9, 0x39, 0x35, 0x36, 0x31, 0x31, 0x32, 0x31, 0x32, 0x39, 0x30, 0x32, 0x31, 0x39, 0x36, 0x30, 0x38, 0x36, 0x34, 0x30, 0x33, 0x34, 0x34, 0x31, 0x38, 0x31, 0x35, 0x39, 0x38, 0x31, 0x33, 0x36, 0x32, 0x39, 0x37, 0x37, 0x34, 0x40400074, 0x30, 0x39, 0x39, 0x36, 0x30, 0x35, 0x31, 0x38, 0x37, 0x30, 0x37, 0x32, 0x31, 0x31, 0x33, 0x34, 0x39, 0x40800000, 0x38, 0x33, 0x37, 0x32, 0x39, 0x37, 0x38, 0x30, 0x34, 0x39, 0x39, 0x404002da, 0x39, 0x37, 0x33, 0x31, 0x37, 0x33, 0x32, 0x38, 0x4040018a, 0x36, 0x33, 0x31, 0x38, 0x35, 0x40400301, 0x404002e8, 0x34, 0x35, 0x35, 0x33, 0x34, 0x36, 0x39, 0x30, 0x38, 0x33, 0x30, 0x32, 0x36, 0x34, 0x32, 0x35, 0x32, 0x32, 0x33, 0x30, 0x404002e3, 0x40400267, 0x38, 0x35, 0x30, 0x33, 0x35, 0x32, 0x36, 0x31, 0x39, 0x33, 0x31, 0x31, 0x40400212, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x33, 0x31, 0x33, 0x37, 0x38, 0x33, 0x38, 0x37, 0x35, 0x32, 0x38, 0x38, 0x36, 0x35, 0x38, 0x37, 0x35, 0x33, 0x33, 0x32, 0x30, 0x38, 0x33, 0x38, 0x31, 0x34, 0x32, 0x30, 0x36, 0x40400140, 0x4040012b, 0x31, 0x34, 0x37, 0x33, 0x30, 0x33, 0x35, 0x39, 0x4080032e, 0x39, 0x30, 0x34, 0x32, 0x38, 0x37, 0x35, 0x35, 0x34, 0x36, 0x38, 0x37, 0x33, 0x31, 0x31, 0x35, 0x39, 0x35, 0x40400355, 0x33, 0x38, 0x38, 0x32, 0x33, 0x35, 0x33, 0x37, 0x38, 0x37, 0x35, 0x4080037f, 0x39, 0x4040013a, 0x31, 0x40400148, 0x38, 0x30, 0x35, 0x33, 0x4040018a, 0x32, 0x32, 0x36, 0x38, 0x30, 0x36, 0x36, 0x31, 0x33, 0x30, 0x30, 0x31, 0x39, 0x32, 0x37, 0x38, 0x37, 0x36, 0x36, 0x31, 0x31, 0x31, 0x39, 0x35, 0x39, 0x40400237, 0x36, 0x40800124, 0x38, 0x39, 0x33, 0x38, 0x30, 0x39, 0x35, 0x32, 0x35, 0x37, 0x32, 0x30, 0x31, 0x30, 0x36, 0x35, 0x34, 0x38, 0x35, 0x38, 0x36, 0x33, 0x32, 0x37, 0x4040009a, 0x39, 0x33, 0x36, 0x31, 0x35, 0x33, 0x40400220, 0x4080015c, 0x32, 0x33, 0x30, 0x33, 0x30, 0x31, 0x39, 0x35, 0x32, 0x30, 0x33, 0x35, 0x33, 0x30, 0x31, 0x38, 0x35, 0x32, 0x40400171, 0x40400075, 0x33, 0x36, 0x32, 0x32, 0x35, 0x39, 0x39, 0x34, 0x31, 0x33, 0x40400254, 0x34, 0x39, 0x37, 0x32, 0x31, 0x37, 0x404000de, 0x33, 0x34, 0x37, 0x39, 0x31, 0x33, 0x31, 0x35, 0x31, 0x35, 0x35, 0x37, 0x34, 0x38, 0x35, 0x37, 0x32, 0x34, 0x32, 0x34, 0x35, 0x34, 0x31, 0x35, 0x30, 0x36, 0x39, 0x4040013f, 0x38, 0x32, 0x39, 0x35, 0x33, 0x33, 0x31, 0x31, 0x36, 0x38, 0x36, 0x31, 0x37, 0x32, 0x37, 0x38, 0x40400337, 0x39, 0x30, 0x37, 0x35, 0x30, 0x39, 0x4040010d, 0x37, 0x35, 0x34, 0x36, 0x33, 0x37, 0x34, 0x36, 0x34, 0x39, 0x33, 0x39, 0x33, 0x31, 0x39, 0x32, 0x35, 0x35, 0x30, 0x36, 0x30, 0x34, 0x30, 0x30, 0x39, 0x4040026b, 0x31, 0x36, 0x37, 0x31, 0x31, 0x33, 0x39, 0x30, 0x30, 0x39, 0x38, 0x40400335, 0x34, 0x30, 0x31, 0x32, 0x38, 0x35, 0x38, 0x33, 0x36, 0x31, 0x36, 0x30, 0x33, 0x35, 0x36, 0x33, 0x37, 0x30, 0x37, 0x36, 0x36, 0x30, 0x31, 0x30, 0x34, 0x40400172, 0x38, 0x31, 0x39, 0x34, 0x32, 0x39, 0x4080041e, 0x404000ef, 0x4040028b, 0x37, 0x38, 0x33, 0x37, 0x34, 0x404004a8, 0x38, 0x32, 0x35, 0x35, 0x33, 0x37, 0x40800209, 0x32, 0x36, 0x38, 0x4040002e, 0x34, 0x30, 0x34, 0x37, 0x404001d1, 0x34, 0x404004b5, 0x4040038d, 0x38, 0x34, 0x404003a8, 0x36, 0x40c0031f, 0x33, 0x33, 0x31, 0x33, 0x36, 0x37, 0x37, 0x30, 0x32, 0x38, 0x39, 0x38, 0x39, 0x31, 0x35, 0x32, 0x40400062, 0x35, 0x32, 0x31, 0x36, 0x32, 0x30, 0x35, 0x36, 0x39, 0x36, 0x40400411, 0x30, 0x35, 0x38, 0x40400477, 0x35, 0x40400498, 0x35, 0x31, 0x31, 0x40400209, 0x38, 0x32, 0x34, 0x33, 0x30, 0x30, 0x33, 0x35, 0x35, 0x38, 0x37, 0x36, 0x34, 0x30, 0x32, 0x34, 0x37, 0x34, 0x39, 0x36, 0x34, 0x37, 0x33, 0x32, 0x36, 0x33, 0x4040043e, 0x39, 0x39, 0x32, 0x4040044b, 0x34, 0x32, 0x36, 0x39, 0x40c002c5, 0x37, 0x404001d6, 0x34, 0x4040053d, 0x4040041d, 0x39, 0x33, 0x34, 0x31, 0x37, 0x404001ad, 0x31, 0x32, 0x4040002a, 0x34, 0x4040019e, 0x31, 0x35, 0x30, 0x33, 0x30, 0x32, 0x38, 0x36, 0x31, 0x38, 0x32, 0x39, 0x37, 0x34, 0x35, 0x35, 0x35, 0x37, 0x30, 0x36, 0x37, 0x34, 0x40400135, 0x35, 0x30, 0x35, 0x34, 0x39, 0x34, 0x35, 0x38, 0x404001c5, 0x39, 0x40400051, 0x35, 0x36, 0x404001ec, 0x37, 0x32, 0x31, 0x30, 0x37, 0x39, 0x40400159, 0x33, 0x30, 0x4040010a, 0x33, 0x32, 0x31, 0x31, 0x36, 0x35, 0x33, 0x34, 0x34, 0x39, 0x38, 0x37, 0x32, 0x30, 0x32, 0x37, 0x4040011b, 0x30, 0x32, 0x33, 0x36, 0x34, 0x4040022e, 0x35, 0x34, 0x39, 0x39, 0x31, 0x31, 0x39, 0x38, 0x40400418, 0x34, 0x4040011b, 0x35, 0x33, 0x35, 0x36, 0x36, 0x33, 0x36, 0x39, 0x40400450, 0x32, 0x36, 0x35, 0x404002e4, 0x37, 0x38, 0x36, 0x32, 0x35, 0x35, 0x31, 0x404003da, 0x31, 0x37, 0x35, 0x37, 0x34, 0x36, 0x37, 0x32, 0x38, 0x39, 0x30, 0x39, 0x37, 0x37, 0x37, 0x37, 0x40800453, 0x30, 0x30, 0x30, 0x404005fd, 0x37, 0x30, 0x404004df, 0x36, 0x404003e9, 0x34, 0x39, 0x31, 0x4040041e, 0x40400297, 0x32, 0x31, 0x34, 0x37, 0x37, 0x32, 0x33, 0x35, 0x30, 0x31, 0x34, 0x31, 0x34, 0x40400643, 0x33, 0x35, 0x36, 0x404004af, 0x31, 0x36, 0x31, 0x33, 0x36, 0x31, 0x31, 0x35, 0x37, 0x33, 0x35, 0x32, 0x35, 0x40400504, 0x33, 0x34, 0x4040005b, 0x31, 0x38, 0x4040047b, 0x38, 0x34, 0x404005e7, 0x33, 0x33, 0x32, 0x33, 0x39, 0x30, 0x37, 0x33, 0x39, 0x34, 0x31, 0x34, 0x33, 0x33, 0x33, 0x34, 0x35, 0x34, 0x37, 0x37, 0x36, 0x32, 0x34, 0x40400242, 0x32, 0x35, 0x31, 0x38, 0x39, 0x38, 0x33, 0x35, 0x36, 0x39, 0x34, 0x38, 0x35, 0x35, 0x36, 0x32, 0x30, 0x39, 0x39, 0x32, 0x31, 0x39, 0x32, 0x32, 0x32, 0x31, 0x38, 0x34, 0x32, 0x37, 0x4040023e, 0x32, 0x404000ba, 0x36, 0x38, 0x38, 0x37, 0x36, 0x37, 0x31, 0x37, 0x39, 0x30, 0x40400055, 0x30, 0x40800106, 0x36, 0x36, 0x404003e7, 0x38, 0x38, 0x36, 0x32, 0x37, 0x32, 0x404006dc, 0x31, 0x37, 0x38, 0x36, 0x30, 0x38, 0x35, 0x37, 0x40400073, 0x33, 0x408002fc, 0x37, 0x39, 0x37, 0x36, 0x36, 0x38, 0x31, 0x404002bd, 0x30, 0x30, 0x39, 0x35, 0x33, 0x38, 0x38, 0x40400638, 0x33, 0x404006a5, 0x30, 0x36, 0x38, 0x30, 0x30, 0x36, 0x34, 0x32, 0x32, 0x35, 0x31, 0x32, 0x35, 0x32, 0x4040057b, 0x37, 0x33, 0x39, 0x32, 0x40400297, 0x40400474, 0x34, 0x408006b3, 0x38, 0x36, 0x32, 0x36, 0x39, 0x34, 0x35, 0x404001e5, 0x34, 0x31, 0x39, 0x36, 0x35, 0x32, 0x38, 0x35, 0x30, 0x40400099, 0x4040039c, 0x31, 0x38, 0x36, 0x33, 0x404001be, 0x34, 0x40800154, 0x32, 0x30, 0x33, 0x39, 0x4040058b, 0x34, 0x35, 0x404002bc, 0x32, 0x33, 0x37, 0x4040042c, 0x36, 0x40400510, 0x35, 0x36, 0x40400638, 0x37, 0x31, 0x39, 0x31, 0x37, 0x32, 0x38, 0x40400171, 0x37, 0x36, 0x34, 0x36, 0x35, 0x37, 0x35, 0x37, 0x33, 0x39, 0x40400101, 0x33, 0x38, 0x39, 0x40400748, 0x38, 0x33, 0x32, 0x36, 0x34, 0x35, 0x39, 0x39, 0x35, 0x38, 0x404006a7, 0x30, 0x34, 0x37, 0x38, 0x404001de, 0x40400328, 0x39, 0x4040002d, 0x36, 0x34, 0x30, 0x37, 0x38, 0x39, 0x35, 0x31, 0x4040008e, 0x36, 0x38, 0x33, 0x4040012f, 0x32, 0x35, 0x39, 0x35, 0x37, 0x30, 0x40400468, 0x38, 0x32, 0x32, 0x404002c8, 0x32, 0x4040061b, 0x34, 0x30, 0x37, 0x37, 0x32, 0x36, 0x37, 0x31, 0x39, 0x34, 0x37, 0x38, 0x40400319, 0x38, 0x32, 0x36, 0x30, 0x31, 0x34, 0x37, 0x36, 0x39, 0x39, 0x30, 0x39, 0x404004e8, 0x30, 0x31, 0x33, 0x36, 0x33, 0x39, 0x34, 0x34, 0x33, 0x4040027f, 0x33, 0x30, 0x40400105, 0x32, 0x30, 0x33, 0x34, 0x39, 0x36, 0x32, 0x35, 0x32, 0x34, 0x35, 0x31, 0x37, 0x404003b5, 0x39, 0x36, 0x35, 0x31, 0x34, 0x33, 0x31, 0x34, 0x32, 0x39, 0x38, 0x30, 0x39, 0x31, 0x39, 0x30, 0x36, 0x35, 0x39, 0x32, 0x40400282, 0x37, 0x32, 0x32, 0x31, 0x36, 0x39, 0x36, 0x34, 0x36, 0x40400419, 0x4040007a, 0x35, 0x4040050e, 0x34, 0x40800565, 0x38, 0x40400559, 0x39, 0x37, 0x4040057b, 0x35, 0x34, 0x4040049d, 0x4040023e, 0x37, 0x4040065a, 0x38, 0x34, 0x36, 0x38, 0x31, 0x33, 0x4040008c, 0x36, 0x38, 0x33, 0x38, 0x36, 0x38, 0x39, 0x34, 0x32, 0x37, 0x37, 0x34, 0x31, 0x35, 0x35, 0x39, 0x39, 0x31, 0x38, 0x35, 0x4040005a, 0x32, 0x34, 0x35, 0x39, 0x35, 0x33, 0x39, 0x35, 0x39, 0x34, 0x33, 0x31, 0x404005b7, 0x37, 0x40400012, 0x36, 0x38, 0x30, 0x38, 0x34, 0x35, 0x404002e7, 0x37, 0x33, 0x4040081e, 0x39, 0x35, 0x38, 0x34, 0x38, 0x36, 0x35, 0x33, 0x38, 0x404006e8, 0x36, 0x32, 0x404000f2, 0x36, 0x30, 0x39, 0x404004b6, 0x36, 0x30, 0x38, 0x30, 0x35, 0x31, 0x32, 0x34, 0x33, 0x38, 0x38, 0x34, 0x4040013a, 0x4040000b, 0x34, 0x31, 0x33, 0x4040030f, 0x37, 0x36, 0x32, 0x37, 0x38, 0x40400341, 0x37, 0x31, 0x35, 0x4040059b, 0x33, 0x35, 0x39, 0x39, 0x37, 0x37, 0x30, 0x30, 0x31, 0x32, 0x39, 0x40400472, 0x38, 0x39, 0x34, 0x34, 0x31, 0x40400277, 0x36, 0x38, 0x35, 0x35, 0x4040005f, 0x34, 0x30, 0x36, 0x33, 0x404008e6, 0x32, 0x30, 0x37, 0x32, 0x32, 0x40400158, 0x40800203, 0x34, 0x38, 0x31, 0x35, 0x38, 0x40400205, 0x404001fe, 0x4040027a, 0x40400298, 0x33, 0x39, 0x34, 0x35, 0x32, 0x32, 0x36, 0x37, 0x40c00496, 0x38, 0x4040058a, 0x32, 0x31, 0x404002ea, 0x32, 0x40400387, 0x35, 0x34, 0x36, 0x36, 0x36, 0x4040051b, 0x32, 0x33, 0x39, 0x38, 0x36, 0x34, 0x35, 0x36, 0x404004c4, 0x31, 0x36, 0x33, 0x35, 0x40800253, 0x40400811, 0x37, 0x404008ad, 0x39, 0x38, 0x4040045e, 0x39, 0x33, 0x36, 0x33, 0x34, 0x4040075b, 0x37, 0x34, 0x33, 0x32, 0x34, 0x4040047b, 0x31, 0x35, 0x30, 0x37, 0x36, 0x404004bb, 0x37, 0x39, 0x34, 0x35, 0x31, 0x30, 0x39, 0x4040003e, 0x30, 0x39, 0x34, 0x30, 0x404006a6, 0x38, 0x38, 0x37, 0x39, 0x37, 0x31, 0x30, 0x38, 0x39, 0x33, 0x404008f0, 0x36, 0x39, 0x31, 0x33, 0x36, 0x38, 0x36, 0x37, 0x32, 0x4040025b, 0x404001fe, 0x35, 0x4040053f, 0x40400468, 0x40400801, 0x31, 0x37, 0x39, 0x32, 0x38, 0x36, 0x38, 0x404008cc, 0x38, 0x37, 0x34, 0x37, 0x4080079e, 0x38, 0x32, 0x34, 0x4040097a, 0x38, 0x4040025b, 0x37, 0x31, 0x34, 0x39, 0x30, 0x39, 0x36, 0x37, 0x35, 0x39, 0x38, 0x404006ef, 0x33, 0x36, 0x35, 0x40400134, 0x38, 0x31, 0x4040005c, 0x40400745, 0x40400936, 0x36, 0x38, 0x32, 0x39, 0x4040057e, 0x38, 0x37, 0x32, 0x32, 0x36, 0x35, 0x38, 0x38, 0x30, 0x40400611, 0x35, 0x40400249, 0x34, 0x32, 0x37, 0x30, 0x34, 0x37, 0x37, 0x35, 0x35, 0x4040081e, 0x33, 0x37, 0x39, 0x36, 0x34, 0x31, 0x34, 0x35, 0x31, 0x35, 0x32, 0x404005fd, 0x32, 0x33, 0x34, 0x33, 0x36, 0x34, 0x35, 0x34, 0x404005de, 0x34, 0x34, 0x34, 0x37, 0x39, 0x35, 0x4040003c, 0x40400523, 0x408008e6, 0x34, 0x31, 0x4040052a, 0x33, 0x40400304, 0x35, 0x32, 0x33, 0x31, 0x40800841, 0x31, 0x36, 0x36, 0x31, 0x404008b2, 0x35, 0x39, 0x36, 0x39, 0x35, 0x33, 0x36, 0x32, 0x33, 0x31, 0x34, 0x404005ff, 0x32, 0x34, 0x38, 0x34, 0x39, 0x33, 0x37, 0x31, 0x38, 0x37, 0x31, 0x31, 0x30, 0x31, 0x34, 0x35, 0x37, 0x36, 0x35, 0x34, 0x40400761, 0x30, 0x32, 0x37, 0x39, 0x39, 0x33, 0x34, 0x34, 0x30, 0x33, 0x37, 0x34, 0x32, 0x30, 0x30, 0x37, 0x4040093f, 0x37, 0x38, 0x35, 0x33, 0x39, 0x30, 0x36, 0x32, 0x31, 0x39, 0x40800299, 0x40400345, 0x38, 0x34, 0x37, 0x408003d2, 0x38, 0x33, 0x33, 0x32, 0x31, 0x34, 0x34, 0x35, 0x37, 0x31, 0x40400284, 0x40400776, 0x34, 0x33, 0x35, 0x30, 0x40400928, 0x40400468, 0x35, 0x33, 0x31, 0x39, 0x31, 0x30, 0x34, 0x38, 0x34, 0x38, 0x31, 0x30, 0x30, 0x35, 0x33, 0x37, 0x30, 0x36, 0x404008bc, 0x4080059d, 0x40800781, 0x31, 0x40400559, 0x37, 0x4040031b, 0x35, 0x404007ec, 0x4040040c, 0x36, 0x33, 0x408007dc, 0x34, 0x40400971, 0x4080034e, 0x408003f5, 0x38, 0x4080052d, 0x40800887, 0x39, 0x40400187, 0x39, 0x31, 0x404008ce, 0x38, 0x31, 0x34, 0x36, 0x37, 0x35, 0x31, 0x4040062b, 0x31, 0x32, 0x33, 0x39, 0x40c001a9, 0x39, 0x30, 0x37, 0x31, 0x38, 0x36, 0x34, 0x39, 0x34, 0x32, 0x33, 0x31, 0x39, 0x36, 0x31, 0x35, 0x36, 0x404001ec, 0x404006bc, 0x39, 0x35, 0x40400926, 0x40400469, 0x4040011b, 0x36, 0x30, 0x33, 0x38, 0x40400a25, 0x4040016f, 0x40400384, 0x36, 0x32, 0x4040045a, 0x35, 0x4040084c, 0x36, 0x33, 0x38, 0x39, 0x33, 0x37, 0x37, 0x38, 0x37, 0x404008c5, 0x404000f8, 0x39, 0x37, 0x39, 0x32, 0x30, 0x37, 0x37, 0x33, 0x404005d7, 0x32, 0x31, 0x38, 0x32, 0x35, 0x36, 0x404007df, 0x36, 0x36, 0x404006d6, 0x34, 0x32, 0x4080067e, 0x36, 0x404006e6, 0x34, 0x34, 0x40400024, 0x35, 0x34, 0x39, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x40400ab3, 0x408003e4, 0x32, 0x30, 0x31, 0x34, 0x39, 0x404004d2, 0x38, 0x35, 0x30, 0x37, 0x33, 0x40400599, 0x36, 0x36, 0x36, 0x30, 0x40400194, 0x32, 0x34, 0x33, 0x34, 0x30, 0x40400087, 0x30, 0x4040076b, 0x38, 0x36, 0x33, 0x40400956, 0x404007e4, 0x4040042b, 0x40400174, 0x35, 0x37, 0x39, 0x36, 0x32, 0x36, 0x38, 0x35, 0x36, 0x40400140, 0x35, 0x30, 0x38, 0x40400523, 0x35, 0x38, 0x37, 0x39, 0x36, 0x39, 0x39, 0x40400711, 0x35, 0x37, 0x34, 0x40400a18, 0x38, 0x34, 0x30, 0x404008b3, 0x31, 0x34, 0x35, 0x39, 0x31, 0x4040078c, 0x37, 0x30, 0x40400234, 0x30, 0x31, 0x40400be7, 0x31, 0x32, 0x40400c74, 0x30, 0x404003c3, 0x33, 0x39, 0x40400b2a, 0x40400112, 0x37, 0x31, 0x35, 0x404003b0, 0x34, 0x32, 0x30, 0x40800bf2, 0x39, 0x40400bc2, 0x30, 0x37, 0x40400341, 0x40400795, 0x40400aaf, 0x40400c62, 0x32, 0x31, 0x40400960, 0x32, 0x35, 0x31, 0x4040057b, 0x40400944, 0x39, 0x32, 0x404001b2, 0x38, 0x32, 0x36, 0x40400b66, 0x32, 0x40400278, 0x33, 0x32, 0x31, 0x35, 0x37, 0x39, 0x31, 0x39, 0x38, 0x34, 0x31, 0x34, 0x4080087b, 0x39, 0x31, 0x36, 0x34, 0x408006e8, 0x39, 0x40800b58, 0x404008db, 0x37, 0x32, 0x32, 0x40400321, 0x35, 0x404008a4, 0x40400141, 0x39, 0x31, 0x30, 0x404000bc, 0x40400c5b, 0x35, 0x32, 0x38, 0x30, 0x31, 0x37, 0x40400231, 0x37, 0x31, 0x32, 0x40400914, 0x38, 0x33, 0x32, 0x40400373, 0x31, 0x40400589, 0x30, 0x39, 0x33, 0x35, 0x33, 0x39, 0x36, 0x35, 0x37, 0x4040064b, 0x31, 0x30, 0x38, 0x33, 0x40400069, 0x35, 0x31, 0x4040077a, 0x40400d5a, 0x31, 0x34, 0x34, 0x34, 0x32, 0x31, 0x30, 0x30, 0x40400202, 0x30, 0x33, 0x4040019c, 0x31, 0x31, 0x30, 0x33, 0x40400c81, 0x40400009, 0x40400026, 0x40c00602, 0x35, 0x31, 0x36, 0x404005d9, 0x40800883, 0x4040092a, 0x35, 0x40800c42, 0x38, 0x35, 0x31, 0x37, 0x31, 0x34, 0x33, 0x37, 0x40400605, 0x4040006d, 0x31, 0x35, 0x35, 0x36, 0x35, 0x30, 0x38, 0x38, 0x404003b9, 0x39, 0x38, 0x39, 0x38, 0x35, 0x39, 0x39, 0x38, 0x32, 0x33, 0x38, 0x404001cf, 0x404009ba, 0x33, 0x4040016c, 0x4040043e, 0x404009c3, 0x38, 0x40800e05, 0x33, 0x32, 0x40400107, 0x35, 0x40400305, 0x33, 0x404001ca, 0x39, 0x4040041b, 0x39, 0x38, 0x4040087d, 0x34, 0x40400cb8, 0x37, 0x4040064b, 0x30, 0x37, 0x404000e5, 0x34, 0x38, 0x31, 0x34, 0x31, 0x40400539, 0x38, 0x35, 0x39, 0x34, 0x36, 0x31, 0x40400bc9, 0x38, 0x30},
+ },
+ {
+ input: "testdata/huffman-rand-1k.in",
+ want: "testdata/huffman-rand-1k.%s.expect",
+ wantNoInput: "testdata/huffman-rand-1k.%s.expect-noinput",
+ tokens: []token{0xf8, 0x8b, 0x96, 0x76, 0x48, 0xd, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xd, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa, 0x64, 0xb, 0xe0, 0x23, 0x29, 0xbd, 0xf7, 0xe7, 0x83, 0x3c, 0xfb, 0xdf, 0xb3, 0xae, 0x4f, 0xa4, 0x47, 0x55, 0x99, 0xde, 0x2f, 0x96, 0x6e, 0x1c, 0x43, 0x4c, 0x87, 0xe2, 0x7c, 0xd9, 0x5f, 0x4c, 0x7c, 0xe8, 0x90, 0x3, 0xdb, 0x30, 0x95, 0xd6, 0x22, 0xc, 0x47, 0xb8, 0x4d, 0x6b, 0xbd, 0x24, 0x11, 0xab, 0x2c, 0xd7, 0xbe, 0x6e, 0x7a, 0xd6, 0x8, 0xa3, 0x98, 0xd8, 0xdd, 0x15, 0x6a, 0xfa, 0x93, 0x30, 0x1, 0x25, 0x1d, 0xa2, 0x74, 0x86, 0x4b, 0x6a, 0x95, 0xe8, 0xe1, 0x4e, 0xe, 0x76, 0xb9, 0x49, 0xa9, 0x5f, 0xa0, 0xa6, 0x63, 0x3c, 0x7e, 0x7e, 0x20, 0x13, 0x4f, 0xbb, 0x66, 0x92, 0xb8, 0x2e, 0xa4, 0xfa, 0x48, 0xcb, 0xae, 0xb9, 0x3c, 0xaf, 0xd3, 0x1f, 0xe1, 0xd5, 0x8d, 0x42, 0x6d, 0xf0, 0xfc, 0x8c, 0xc, 0x0, 0xde, 0x40, 0xab, 0x8b, 0x47, 0x97, 0x4e, 0xa8, 0xcf, 0x8e, 0xdb, 0xa6, 0x8b, 0x20, 0x9, 0x84, 0x7a, 0x66, 0xe5, 0x98, 0x29, 0x2, 0x95, 0xe6, 0x38, 0x32, 0x60, 0x3, 0xe3, 0x9a, 0x1e, 0x54, 0xe8, 0x63, 0x80, 0x48, 0x9c, 0xe7, 0x63, 0x33, 0x6e, 0xa0, 0x65, 0x83, 0xfa, 0xc6, 0xba, 0x7a, 0x43, 0x71, 0x5, 0xf5, 0x68, 0x69, 0x85, 0x9c, 0xba, 0x45, 0xcd, 0x6b, 0xb, 0x19, 0xd1, 0xbb, 0x7f, 0x70, 0x85, 0x92, 0xd1, 0xb4, 0x64, 0x82, 0xb1, 0xe4, 0x62, 0xc5, 0x3c, 0x46, 0x1f, 0x92, 0x31, 0x1c, 0x4e, 0x41, 0x77, 0xf7, 0xe7, 0x87, 0xa2, 0xf, 0x6e, 0xe8, 0x92, 0x3, 0x6b, 0xa, 0xe7, 0xa9, 0x3b, 0x11, 0xda, 0x66, 0x8a, 0x29, 0xda, 0x79, 0xe1, 0x64, 0x8d, 0xe3, 0x54, 0xd4, 0xf5, 0xef, 0x64, 0x87, 0x3b, 0xf4, 0xc2, 0xf4, 0x71, 0x13, 0xa9, 0xe9, 0xe0, 0xa2, 0x6, 0x14, 0xab, 0x5d, 0xa7, 0x96, 0x0, 0xd6, 0xc3, 0xcc, 0x57, 0xed, 0x39, 0x6a, 0x25, 0xcd, 0x76, 0xea, 0xba, 0x3a, 0xf2, 0xa1, 0x95, 0x5d, 0xe5, 0x71, 0xcf, 0x9c, 0x62, 0x9e, 0x6a, 0xfa, 0xd5, 0x31, 0xd1, 0xa8, 0x66, 0x30, 0x33, 0xaa, 0x51, 0x17, 0x13, 0x82, 0x99, 0xc8, 0x14, 0x60, 0x9f, 0x4d, 0x32, 0x6d, 0xda, 0x19, 0x26, 0x21, 0xdc, 0x7e, 0x2e, 0x25, 0x67, 0x72, 0xca, 0xf, 0x92, 0xcd, 0xf6, 0xd6, 0xcb, 0x97, 0x8a, 0x33, 0x58, 0x73, 0x70, 0x91, 0x1d, 0xbf, 0x28, 0x23, 0xa3, 0xc, 0xf1, 0x83, 0xc3, 0xc8, 0x56, 0x77, 0x68, 0xe3, 0x82, 0xba, 0xb9, 0x57, 0x56, 0x57, 0x9c, 0xc3, 0xd6, 0x14, 0x5, 0x3c, 0xb1, 0xaf, 0x93, 0xc8, 0x8a, 0x57, 0x7f, 0x53, 0xfa, 0x2f, 0xaa, 0x6e, 0x66, 0x83, 0xfa, 0x33, 0xd1, 0x21, 0xab, 0x1b, 0x71, 0xb4, 0x7c, 0xda, 0xfd, 0xfb, 0x7f, 0x20, 0xab, 0x5e, 0xd5, 0xca, 0xfd, 0xdd, 0xe0, 0xee, 0xda, 0xba, 0xa8, 0x27, 0x99, 0x97, 0x69, 0xc1, 0x3c, 0x82, 0x8c, 0xa, 0x5c, 0x2d, 0x5b, 0x88, 0x3e, 0x34, 0x35, 0x86, 0x37, 0x46, 0x79, 0xe1, 0xaa, 0x19, 0xfb, 0xaa, 0xde, 0x15, 0x9, 0xd, 0x1a, 0x57, 0xff, 0xb5, 0xf, 0xf3, 0x2b, 0x5a, 0x6a, 0x4d, 0x19, 0x77, 0x71, 0x45, 0xdf, 0x4f, 0xb3, 0xec, 0xf1, 0xeb, 0x18, 0x53, 0x3e, 0x3b, 0x47, 0x8, 0x9a, 0x73, 0xa0, 0x5c, 0x8c, 0x5f, 0xeb, 0xf, 0x3a, 0xc2, 0x43, 0x67, 0xb4, 0x66, 0x67, 0x80, 0x58, 0xe, 0xc1, 0xec, 0x40, 0xd4, 0x22, 0x94, 0xca, 0xf9, 0xe8, 0x92, 0xe4, 0x69, 0x38, 0xbe, 0x67, 0x64, 0xca, 0x50, 0xc7, 0x6, 0x67, 0x42, 0x6e, 0xa3, 0xf0, 0xb7, 0x6c, 0xf2, 0xe8, 0x5f, 0xb1, 0xaf, 0xe7, 0xdb, 0xbb, 0x77, 0xb5, 0xf8, 0xcb, 0x8, 0xc4, 0x75, 0x7e, 0xc0, 0xf9, 0x1c, 0x7f, 0x3c, 0x89, 0x2f, 0xd2, 0x58, 0x3a, 0xe2, 0xf8, 0x91, 0xb6, 0x7b, 0x24, 0x27, 0xe9, 0xae, 0x84, 0x8b, 0xde, 0x74, 0xac, 0xfd, 0xd9, 0xb7, 0x69, 0x2a, 0xec, 0x32, 0x6f, 0xf0, 0x92, 0x84, 0xf1, 0x40, 0xc, 0x8a, 0xbc, 0x39, 0x6e, 0x2e, 0x73, 0xd4, 0x6e, 0x8a, 0x74, 0x2a, 0xdc, 0x60, 0x1f, 0xa3, 0x7, 0xde, 0x75, 0x8b, 0x74, 0xc8, 0xfe, 0x63, 0x75, 0xf6, 0x3d, 0x63, 0xac, 0x33, 0x89, 0xc3, 0xf0, 0xf8, 0x2d, 0x6b, 0xb4, 0x9e, 0x74, 0x8b, 0x5c, 0x33, 0xb4, 0xca, 0xa8, 0xe4, 0x99, 0xb6, 0x90, 0xa1, 0xef, 0xf, 0xd3, 0x61, 0xb2, 0xc6, 0x1a, 0x94, 0x7c, 0x44, 0x55, 0xf4, 0x45, 0xff, 0x9e, 0xa5, 0x5a, 0xc6, 0xa0, 0xe8, 0x2a, 0xc1, 0x8d, 0x6f, 0x34, 0x11, 0xb9, 0xbe, 0x4e, 0xd9, 0x87, 0x97, 0x73, 0xcf, 0x3d, 0x23, 0xae, 0xd5, 0x1a, 0x5e, 0xae, 0x5d, 0x6a, 0x3, 0xf9, 0x22, 0xd, 0x10, 0xd9, 0x47, 0x69, 0x15, 0x3f, 0xee, 0x52, 0xa3, 0x8, 0xd2, 0x3c, 0x51, 0xf4, 0xf8, 0x9d, 0xe4, 0x98, 0x89, 0xc8, 0x67, 0x39, 0xd5, 0x5e, 0x35, 0x78, 0x27, 0xe8, 0x3c, 0x80, 0xae, 0x79, 0x71, 0xd2, 0x93, 0xf4, 0xaa, 0x51, 0x12, 0x1c, 0x4b, 0x1b, 0xe5, 0x6e, 0x15, 0x6f, 0xe4, 0xbb, 0x51, 0x9b, 0x45, 0x9f, 0xf9, 0xc4, 0x8c, 0x2a, 0xfb, 0x1a, 0xdf, 0x55, 0xd3, 0x48, 0x93, 0x27, 0x1, 0x26, 0xc2, 0x6b, 0x55, 0x6d, 0xa2, 0xfb, 0x84, 0x8b, 0xc9, 0x9e, 0x28, 0xc2, 0xef, 0x1a, 0x24, 0xec, 0x9b, 0xae, 0xbd, 0x60, 0xe9, 0x15, 0x35, 0xee, 0x42, 0xa4, 0x33, 0x5b, 0xfa, 0xf, 0xb6, 0xf7, 0x1, 0xa6, 0x2, 0x4c, 0xca, 0x90, 0x58, 0x3a, 0x96, 0x41, 0xe7, 0xcb, 0x9, 0x8c, 0xdb, 0x85, 0x4d, 0xa8, 0x89, 0xf3, 0xb5, 0x8e, 0xfd, 0x75, 0x5b, 0x4f, 0xed, 0xde, 0x3f, 0xeb, 0x38, 0xa3, 0xbe, 0xb0, 0x73, 0xfc, 0xb8, 0x54, 0xf7, 0x4c, 0x30, 0x67, 0x2e, 0x38, 0xa2, 0x54, 0x18, 0xba, 0x8, 0xbf, 0xf2, 0x39, 0xd5, 0xfe, 0xa5, 0x41, 0xc6, 0x66, 0x66, 0xba, 0x81, 0xef, 0x67, 0xe4, 0xe6, 0x3c, 0xc, 0xca, 0xa4, 0xa, 0x79, 0xb3, 0x57, 0x8b, 0x8a, 0x75, 0x98, 0x18, 0x42, 0x2f, 0x29, 0xa3, 0x82, 0xef, 0x9f, 0x86, 0x6, 0x23, 0xe1, 0x75, 0xfa, 0x8, 0xb1, 0xde, 0x17, 0x4a},
+ },
+ {
+ input: "testdata/huffman-rand-limit.in",
+ want: "testdata/huffman-rand-limit.%s.expect",
+ wantNoInput: "testdata/huffman-rand-limit.%s.expect-noinput",
+ tokens: []token{0x61, 0x51c00000, 0xa, 0xf8, 0x8b, 0x96, 0x76, 0x48, 0xa, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xa, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa},
+ },
+ {
+ input: "testdata/huffman-shifts.in",
+ want: "testdata/huffman-shifts.%s.expect",
+ wantNoInput: "testdata/huffman-shifts.%s.expect-noinput",
+ tokens: []token{0x31, 0x30, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x52400001, 0xd, 0xa, 0x32, 0x33, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7f400001},
+ },
+ {
+ input: "testdata/huffman-text-shift.in",
+ want: "testdata/huffman-text-shift.%s.expect",
+ wantNoInput: "testdata/huffman-text-shift.%s.expect-noinput",
+ tokens: []token{0x2f, 0x2f, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x32, 0x30, 0x30, 0x39, 0x54, 0x68, 0x47, 0x6f, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x2e, 0x41, 0x6c, 0x6c, 0x40800016, 0x72, 0x72, 0x76, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x55, 0x6f, 0x66, 0x74, 0x68, 0x69, 0x6f, 0x75, 0x72, 0x63, 0x63, 0x6f, 0x64, 0x69, 0x67, 0x6f, 0x76, 0x72, 0x6e, 0x64, 0x62, 0x79, 0x42, 0x53, 0x44, 0x2d, 0x74, 0x79, 0x6c, 0x40400020, 0x6c, 0x69, 0x63, 0x6e, 0x74, 0x68, 0x74, 0x63, 0x6e, 0x62, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x74, 0x68, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x66, 0x69, 0x6c, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x63, 0x6b, 0x67, 0x6d, 0x69, 0x6e, 0x4040000a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x6f, 0x22, 0x4040000c, 0x66, 0x75, 0x6e, 0x63, 0x6d, 0x69, 0x6e, 0x28, 0x29, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x72, 0x62, 0x3d, 0x6d, 0x6b, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x2c, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x5f, 0x3a, 0x3d, 0x6f, 0x2e, 0x43, 0x72, 0x74, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x40800021, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58, 0x78, 0x79, 0x7a, 0x21, 0x22, 0x23, 0xc2, 0xa4, 0x25, 0x26, 0x2f, 0x3f, 0x22},
+ },
+ {
+ input: "testdata/huffman-text.in",
+ want: "testdata/huffman-text.%s.expect",
+ wantNoInput: "testdata/huffman-text.%s.expect-noinput",
+ tokens: []token{0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x4080001e, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x42, 0x53, 0x44, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x40800036, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x4040000f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x22, 0x6f, 0x73, 0x22, 0x4040000e, 0x66, 0x75, 0x6e, 0x63, 0x4080001b, 0x28, 0x29, 0x20, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x61, 0x72, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x65, 0x2c, 0x20, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x20, 0x5f, 0x20, 0x3a, 0x3d, 0x20, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x61, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x61, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x4080002a, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa},
+ },
+ {
+ input: "testdata/huffman-zero.in",
+ want: "testdata/huffman-zero.%s.expect",
+ wantNoInput: "testdata/huffman-zero.%s.expect-noinput",
+ tokens: []token{0x30, ml, 0x4b800000},
+ },
+ {
+ input: "",
+ want: "",
+ wantNoInput: "testdata/null-long-match.%s.expect-noinput",
+ tokens: []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, 0x41400000},
+ },
+}
+
+// TestWriteBlock tests if the writeBlock encoding has changed.
+// To update the reference files use the "-update" flag on the test.
+func TestWriteBlock(t *testing.T) {
+ for _, test := range writeBlockTests {
+ testBlock(t, test, "wb")
+ }
+}
+
+// TestWriteBlockDynamic tests if the writeBlockDynamic encoding has changed.
+// To update the reference files use the "-update" flag on the test.
+func TestWriteBlockDynamic(t *testing.T) {
+ for _, test := range writeBlockTests {
+ testBlock(t, test, "dyn")
+ }
+}
+
+// testBlock tests a block against its references,
+// or regenerate the references, if "-update" flag is set.
+func testBlock(t *testing.T, test huffTest, ttype string) {
+ if test.want != "" {
+ test.want = fmt.Sprintf(test.want, ttype)
+ }
+ test.wantNoInput = fmt.Sprintf(test.wantNoInput, ttype)
+ if *update {
+ if test.input != "" {
+ t.Logf("Updating %q", test.want)
+ input, err := ioutil.ReadFile(test.input)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ f, err := os.Create(test.want)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer f.Close()
+ bw := newHuffmanBitWriter(f)
+ writeToType(t, ttype, bw, test.tokens, input)
+ }
+
+ t.Logf("Updating %q", test.wantNoInput)
+ f, err := os.Create(test.wantNoInput)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer f.Close()
+ bw := newHuffmanBitWriter(f)
+ writeToType(t, ttype, bw, test.tokens, nil)
+ return
+ }
+
+ if test.input != "" {
+ t.Logf("Testing %q", test.want)
+ input, err := ioutil.ReadFile(test.input)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ want, err := ioutil.ReadFile(test.want)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var buf bytes.Buffer
+ bw := newHuffmanBitWriter(&buf)
+ writeToType(t, ttype, bw, test.tokens, input)
+
+ got := buf.Bytes()
+ if !bytes.Equal(got, want) {
+ t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+".got")
+ if err := ioutil.WriteFile(test.want+".got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ }
+ t.Log("Output ok")
+
+ // Test if the writer produces the same output after reset.
+ buf.Reset()
+ bw.reset(&buf)
+ writeToType(t, ttype, bw, test.tokens, input)
+ bw.flush()
+ got = buf.Bytes()
+ if !bytes.Equal(got, want) {
+ t.Errorf("reset: writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+".reset.got")
+ if err := ioutil.WriteFile(test.want+".reset.got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ t.Log("Reset ok")
+ testWriterEOF(t, "wb", test, true)
+ }
+ t.Logf("Testing %q", test.wantNoInput)
+ wantNI, err := ioutil.ReadFile(test.wantNoInput)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var buf bytes.Buffer
+ bw := newHuffmanBitWriter(&buf)
+ writeToType(t, ttype, bw, test.tokens, nil)
+
+ got := buf.Bytes()
+ if !bytes.Equal(got, wantNI) {
+ t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.wantNoInput, test.wantNoInput+".got")
+ if err := ioutil.WriteFile(test.want+".got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ } else if got[0]&1 == 1 {
+ t.Error("got unexpected EOF")
+ return
+ }
+
+ t.Log("Output ok")
+
+ // Test if the writer produces the same output after reset.
+ buf.Reset()
+ bw.reset(&buf)
+ writeToType(t, ttype, bw, test.tokens, nil)
+ bw.flush()
+ got = buf.Bytes()
+ if !bytes.Equal(got, wantNI) {
+ t.Errorf("reset: writeBlock did not yield expected result for file %q without input. See %q", test.want, test.want+".reset.got")
+ if err := ioutil.WriteFile(test.want+".reset.got", got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ t.Log("Reset ok")
+ testWriterEOF(t, "wb", test, false)
+}
+
+func writeToType(t *testing.T, ttype string, bw *huffmanBitWriter, tok []token, input []byte) {
+ switch ttype {
+ case "wb":
+ bw.writeBlock(tok, false, input)
+ case "dyn":
+ bw.writeBlockDynamic(tok, false, input)
+ default:
+ panic("unknown test type")
+ }
+
+ if bw.err != nil {
+ t.Error(bw.err)
+ return
+ }
+
+ bw.flush()
+ if bw.err != nil {
+ t.Error(bw.err)
+ return
+ }
+}
+
+// testWriterEOF tests if the written block contains an EOF marker.
+func testWriterEOF(t *testing.T, ttype string, test huffTest, useInput bool) {
+ if useInput && test.input == "" {
+ return
+ }
+ var input []byte
+ if useInput {
+ var err error
+ input, err = ioutil.ReadFile(test.input)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ }
+ var buf bytes.Buffer
+ bw := newHuffmanBitWriter(&buf)
+ switch ttype {
+ case "wb":
+ bw.writeBlock(test.tokens, true, input)
+ case "dyn":
+ bw.writeBlockDynamic(test.tokens, true, input)
+ case "huff":
+ bw.writeBlockHuff(true, input)
+ default:
+ panic("unknown test type")
+ }
+ if bw.err != nil {
+ t.Error(bw.err)
+ return
+ }
+
+ bw.flush()
+ if bw.err != nil {
+ t.Error(bw.err)
+ return
+ }
+ b := buf.Bytes()
+ if len(b) == 0 {
+ t.Error("no output received")
+ return
+ }
+ if b[0]&1 != 1 {
+ t.Errorf("block not marked with EOF for input %q", test.input)
+ return
+ }
+ t.Log("EOF ok")
+}
diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go
index 50ec79c940..bdcbd823b0 100644
--- a/libgo/go/compress/flate/huffman_code.go
+++ b/libgo/go/compress/flate/huffman_code.go
@@ -9,9 +9,17 @@ import (
"sort"
)
+// hcode is a huffman code with a bit code and bit length.
+type hcode struct {
+ code, len uint16
+}
+
type huffmanEncoder struct {
- codeBits []uint8
- code []uint16
+ codes []hcode
+ freqcache []literalNode
+ bitCount [17]int32
+ lns byLiteral // stored to avoid repeated allocation in generate
+ lfs byFreq // stored to avoid repeated allocation in generate
}
type literalNode struct {
@@ -39,21 +47,26 @@ type levelInfo struct {
needed int32
}
+// set sets the code and length of an hcode.
+func (h *hcode) set(code uint16, length uint16) {
+ h.len = length
+ h.code = code
+}
+
func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
func newHuffmanEncoder(size int) *huffmanEncoder {
- return &huffmanEncoder{make([]uint8, size), make([]uint16, size)}
+ return &huffmanEncoder{codes: make([]hcode, size)}
}
// Generates a HuffmanCode corresponding to the fixed literal table
func generateFixedLiteralEncoding() *huffmanEncoder {
h := newHuffmanEncoder(maxNumLit)
- codeBits := h.codeBits
- code := h.code
+ codes := h.codes
var ch uint16
for ch = 0; ch < maxNumLit; ch++ {
var bits uint16
- var size uint8
+ var size uint16
switch {
case ch < 144:
// size 8, 000110000 .. 10111111
@@ -75,19 +88,16 @@ func generateFixedLiteralEncoding() *huffmanEncoder {
bits = ch + 192 - 280
size = 8
}
- codeBits[ch] = size
- code[ch] = reverseBits(bits, size)
+ codes[ch] = hcode{code: reverseBits(bits, byte(size)), len: size}
}
return h
}
func generateFixedOffsetEncoding() *huffmanEncoder {
h := newHuffmanEncoder(30)
- codeBits := h.codeBits
- code := h.code
- for ch := uint16(0); ch < 30; ch++ {
- codeBits[ch] = 5
- code[ch] = reverseBits(ch, 5)
+ codes := h.codes
+ for ch := range codes {
+ codes[ch] = hcode{code: reverseBits(uint16(ch), 5), len: 5}
}
return h
}
@@ -95,11 +105,11 @@ func generateFixedOffsetEncoding() *huffmanEncoder {
var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
-func (h *huffmanEncoder) bitLength(freq []int32) int64 {
- var total int64
+func (h *huffmanEncoder) bitLength(freq []int32) int {
+ var total int
for i, f := range freq {
if f != 0 {
- total += int64(f) * int64(h.codeBits[i])
+ total += int(f) * int(h.codes[i].len)
}
}
return total
@@ -113,7 +123,7 @@ const maxBitsLimit = 16
// The cases of 0, 1, and 2 literals are handled by special case code.
//
// list An array of the literals with non-zero frequencies
-// and their associated frequencies. The array is in order of increasing
+// and their associated frequencies. The array is in order of increasing
// frequency, and has as its last element a special element with frequency
// MaxInt32
// maxBits The maximum number of bits that should be used to encode any literal.
@@ -128,7 +138,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
list = list[0 : n+1]
list[n] = maxNode()
- // The tree can't have greater depth than n - 1, no matter what. This
+ // The tree can't have greater depth than n - 1, no matter what. This
// saves a little bit of work in some small cases
if maxBits > n-1 {
maxBits = n - 1
@@ -197,7 +207,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
if l.needed--; l.needed == 0 {
// We've done everything we need to do for this level.
- // Continue calculating one level up. Fill in nextPairFreq
+ // Continue calculating one level up. Fill in nextPairFreq
// of that level with the sum of the two nodes we've just calculated on
// this level.
if l.level == maxBits {
@@ -220,7 +230,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
panic("leafCounts[maxBits][maxBits] != n")
}
- bitCount := make([]int32, maxBits+1)
+ bitCount := h.bitCount[:maxBits+1]
bits := 1
counts := &leafCounts[maxBits]
for level := maxBits; level > 0; level-- {
@@ -246,10 +256,10 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN
// code, code + 1, .... The code values are
// assigned in literal order (not frequency order).
chunk := list[len(list)-int(bits):]
- sortByLiteral(chunk)
+
+ h.lns.sort(chunk)
for _, node := range chunk {
- h.codeBits[node.literal] = uint8(n)
- h.code[node.literal] = reverseBits(code, uint8(n))
+ h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)}
code++
}
list = list[0 : len(list)-int(bits)]
@@ -261,7 +271,13 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN
// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
// maxBits The maximum number of bits to use for any literal.
func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
- list := make([]literalNode, len(freq)+1)
+ if h.freqcache == nil {
+ // Allocate a reusable buffer with the longest possible frequency table.
+ // Possible lengths are codegenCodeCount, offsetCodeCount and maxNumLit.
+ // The largest of these is maxNumLit, so we allocate for that case.
+ h.freqcache = make([]literalNode, maxNumLit+1)
+ }
+ list := h.freqcache[:len(freq)+1]
// Number of non-zero literals
count := 0
// Set list to be the set of all non-zero literals and their frequencies
@@ -270,23 +286,23 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
list[count] = literalNode{uint16(i), f}
count++
} else {
- h.codeBits[i] = 0
+ list[count] = literalNode{}
+ h.codes[i].len = 0
}
}
- // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
- h.codeBits = h.codeBits[0:len(freq)]
- list = list[0:count]
+ list[len(freq)] = literalNode{}
+
+ list = list[:count]
if count <= 2 {
- // Handle the small cases here, because they are awkward for the general case code. With
+ // Handle the small cases here, because they are awkward for the general case code. With
// two or fewer literals, everything has bit length 1.
for i, node := range list {
// "list" is in order of increasing literal value.
- h.codeBits[node.literal] = 1
- h.code[node.literal] = uint16(i)
+ h.codes[node.literal].set(uint16(i), 1)
}
return
}
- sortByFreq(list)
+ h.lfs.sort(list)
// Get the number of literals for each bit count
bitCount := h.bitCounts(list, maxBits)
@@ -294,30 +310,35 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
h.assignEncodingAndSize(bitCount, list)
}
-type literalNodeSorter struct {
- a []literalNode
- less func(i, j int) bool
+type byLiteral []literalNode
+
+func (s *byLiteral) sort(a []literalNode) {
+ *s = byLiteral(a)
+ sort.Sort(s)
}
-func (s literalNodeSorter) Len() int { return len(s.a) }
+func (s byLiteral) Len() int { return len(s) }
-func (s literalNodeSorter) Less(i, j int) bool {
- return s.less(i, j)
+func (s byLiteral) Less(i, j int) bool {
+ return s[i].literal < s[j].literal
}
-func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }
+func (s byLiteral) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func sortByFreq(a []literalNode) {
- s := &literalNodeSorter{a, func(i, j int) bool {
- if a[i].freq == a[j].freq {
- return a[i].literal < a[j].literal
- }
- return a[i].freq < a[j].freq
- }}
+type byFreq []literalNode
+
+func (s *byFreq) sort(a []literalNode) {
+ *s = byFreq(a)
sort.Sort(s)
}
-func sortByLiteral(a []literalNode) {
- s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
- sort.Sort(s)
+func (s byFreq) Len() int { return len(s) }
+
+func (s byFreq) Less(i, j int) bool {
+ if s[i].freq == s[j].freq {
+ return s[i].literal < s[j].literal
+ }
+ return s[i].freq < s[j].freq
}
+
+func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
index 42261e9b61..9a8c4fc455 100644
--- a/libgo/go/compress/flate/inflate.go
+++ b/libgo/go/compress/flate/inflate.go
@@ -15,8 +15,7 @@ import (
)
const (
- maxCodeLen = 16 // max length of Huffman code
- maxHist = 32768 // max history required
+ maxCodeLen = 16 // max length of Huffman code
// The next three numbers come from the RFC section 3.2.7, with the
// additional proviso in section 3.2.5 which implies that distance codes
// 30 and 31 should never occur in compressed data.
@@ -115,7 +114,7 @@ type huffmanDecoder struct {
// trees are permitted.
func (h *huffmanDecoder) init(bits []int) bool {
// Sanity enables additional runtime tests during Huffman
- // table construction. It's intended to be used during
+ // table construction. It's intended to be used during
// development to supplement the currently ad-hoc unit tests.
const sanity = false
@@ -162,7 +161,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
// Check that the coding is complete (i.e., that we've
// assigned all 2-to-the-max possible bit sequences).
// Exception: To be compatible with zlib, we also need to
- // accept degenerate single-code codings. See also
+ // accept degenerate single-code codings. See also
// TestDegenerateHuffmanCoding.
if code != 1<<uint(max) && !(code == 1 && max == 1) {
return false
@@ -200,7 +199,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
if n <= huffmanChunkBits {
for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
// We should never need to overwrite
- // an existing chunk. Also, 0 is
+ // an existing chunk. Also, 0 is
// never a valid chunk, because the
// lower 4 "count" bits should be
// between 1 and 15.
@@ -230,7 +229,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
if sanity {
// Above we've sanity checked that we never overwrote
- // an existing entry. Here we additionally check that
+ // an existing entry. Here we additionally check that
// we filled the tables completely.
for i, chunk := range h.chunks {
if chunk == 0 {
@@ -268,7 +267,6 @@ type decompressor struct {
// Input source.
r Reader
roffset int64
- woffset int64
// Input bits, in top of b.
b uint32
@@ -282,34 +280,24 @@ type decompressor struct {
codebits *[numCodes]int
// Output history, buffer.
- hist *[maxHist]byte
- hp int // current output position in buffer
- hw int // have written hist[0:hw] already
- hfull bool // buffer has filled at least once
+ dict dictDecoder
// Temporary buffer (avoids repeated allocation).
buf [4]byte
// Next step in the decompression,
// and decompression state.
- step func(*decompressor)
- final bool
- err error
- toRead []byte
- hl, hd *huffmanDecoder
- copyLen int
- copyDist int
+ step func(*decompressor)
+ stepState int
+ final bool
+ err error
+ toRead []byte
+ hl, hd *huffmanDecoder
+ copyLen int
+ copyDist int
}
func (f *decompressor) nextBlock() {
- if f.final {
- if f.hw != f.hp {
- f.flush((*decompressor).nextBlock)
- return
- }
- f.err = io.EOF
- return
- }
for f.nb < 1+2 {
if f.err = f.moreBits(); f.err != nil {
return
@@ -347,12 +335,18 @@ func (f *decompressor) Read(b []byte) (int, error) {
if len(f.toRead) > 0 {
n := copy(b, f.toRead)
f.toRead = f.toRead[n:]
+ if len(f.toRead) == 0 {
+ return n, f.err
+ }
return n, nil
}
if f.err != nil {
return 0, f.err
}
f.step(f)
+ if f.err != nil && len(f.toRead) == 0 {
+ f.toRead = f.dict.readFlush() // Flush what's left in case of error
+ }
}
}
@@ -478,10 +472,24 @@ func (f *decompressor) readHuffman() error {
// Decode a single Huffman block from f.
// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
+// and the distance values, respectively. If hd == nil, using the
// fixed distance encoding associated with fixed Huffman blocks.
func (f *decompressor) huffmanBlock() {
- for {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
v, err := f.huffSym(f.hl)
if err != nil {
f.err = err
@@ -491,17 +499,16 @@ func (f *decompressor) huffmanBlock() {
var length int
switch {
case v < 256:
- f.hist[f.hp] = byte(v)
- f.hp++
- if f.hp == len(f.hist) {
- // After the flush, continue this loop.
- f.flush((*decompressor).huffmanBlock)
+ f.dict.writeByte(byte(v))
+ if f.dict.availWrite() == 0 {
+ f.toRead = f.dict.readFlush()
+ f.step = (*decompressor).huffmanBlock
+ f.stepState = stateInit
return
}
- continue
+ goto readLiteral
case v == 256:
- // Done with huffman block; read next block.
- f.step = (*decompressor).nextBlock
+ f.finishBlock()
return
// otherwise, reference to older data
case v < 265:
@@ -581,61 +588,33 @@ func (f *decompressor) huffmanBlock() {
return
}
- // Copy history[-dist:-dist+length] into output.
- if dist > len(f.hist) {
- f.err = InternalError("bad history distance")
- return
- }
-
// No check on length; encoding can be prescient.
- if !f.hfull && dist > f.hp {
+ if dist > f.dict.histSize() {
f.err = CorruptInputError(f.roffset)
return
}
f.copyLen, f.copyDist = length, dist
- if f.copyHist() {
- return
- }
+ goto copyHistory
}
-}
-// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself.
-// It reports whether the f.hist buffer is full.
-func (f *decompressor) copyHist() bool {
- p := f.hp - f.copyDist
- if p < 0 {
- p += len(f.hist)
- }
- for f.copyLen > 0 {
- n := f.copyLen
- if x := len(f.hist) - f.hp; n > x {
- n = x
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
}
- if x := len(f.hist) - p; n > x {
- n = x
- }
- forwardCopy(f.hist[:], f.hp, p, n)
- p += n
- f.hp += n
- f.copyLen -= n
- if f.hp == len(f.hist) {
- // After flush continue copying out of history.
- f.flush((*decompressor).copyHuff)
- return true
- }
- if p == len(f.hist) {
- p = 0
- }
- }
- return false
-}
+ f.copyLen -= cnt
-func (f *decompressor) copyHuff() {
- if f.copyHist() {
- return
+ if f.dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = f.dict.readFlush()
+ f.step = (*decompressor).huffmanBlock // We need to continue this work
+ f.stepState = stateDict
+ return
+ }
+ goto readLiteral
}
- f.huffmanBlock()
}
// Copy a single uncompressed data block from input to output.
@@ -663,8 +642,8 @@ func (f *decompressor) dataBlock() {
}
if n == 0 {
- // 0-length block means sync
- f.flush((*decompressor).nextBlock)
+ f.toRead = f.dict.readFlush()
+ f.finishBlock()
return
}
@@ -675,44 +654,39 @@ func (f *decompressor) dataBlock() {
// copyData copies f.copyLen bytes from the underlying reader into f.hist.
// It pauses for reads when f.hist is full.
func (f *decompressor) copyData() {
- n := f.copyLen
- for n > 0 {
- m := len(f.hist) - f.hp
- if m > n {
- m = n
- }
- m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
- f.roffset += int64(m)
- if err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- f.err = err
- return
- }
- n -= m
- f.hp += m
- if f.hp == len(f.hist) {
- f.copyLen = n
- f.flush((*decompressor).copyData)
- return
+ buf := f.dict.writeSlice()
+ if len(buf) > f.copyLen {
+ buf = buf[:f.copyLen]
+ }
+
+ cnt, err := io.ReadFull(f.r, buf)
+ f.roffset += int64(cnt)
+ f.copyLen -= cnt
+ f.dict.writeMark(cnt)
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
}
+ f.err = err
+ return
}
- f.step = (*decompressor).nextBlock
-}
-func (f *decompressor) setDict(dict []byte) {
- if len(dict) > len(f.hist) {
- // Will only remember the tail.
- dict = dict[len(dict)-len(f.hist):]
+ if f.dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = f.dict.readFlush()
+ f.step = (*decompressor).copyData
+ return
}
+ f.finishBlock()
+}
- f.hp = copy(f.hist[:], dict)
- if f.hp == len(f.hist) {
- f.hp = 0
- f.hfull = true
+func (f *decompressor) finishBlock() {
+ if f.final {
+ if f.dict.availRead() > 0 {
+ f.toRead = f.dict.readFlush()
+ }
+ f.err = io.EOF
}
- f.hw = f.hp
+ f.step = (*decompressor).nextBlock
}
func (f *decompressor) moreBits() error {
@@ -760,19 +734,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
}
}
-// Flush any buffered output to the underlying writer.
-func (f *decompressor) flush(step func(*decompressor)) {
- f.toRead = f.hist[f.hw:f.hp]
- f.woffset += int64(f.hp - f.hw)
- f.hw = f.hp
- if f.hp == len(f.hist) {
- f.hp = 0
- f.hw = 0
- f.hfull = true
- }
- f.step = step
-}
-
func makeReader(r io.Reader) Reader {
if rr, ok := r.(Reader); ok {
return rr
@@ -805,12 +766,10 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
r: makeReader(r),
bits: f.bits,
codebits: f.codebits,
- hist: f.hist,
+ dict: f.dict,
step: (*decompressor).nextBlock,
}
- if dict != nil {
- f.setDict(dict)
- }
+ f.dict.init(maxMatchOffset, dict)
return nil
}
@@ -827,17 +786,17 @@ func NewReader(r io.Reader) io.ReadCloser {
var f decompressor
f.r = makeReader(r)
- f.hist = new([maxHist]byte)
f.bits = new([maxNumLit + maxNumDist]int)
f.codebits = new([numCodes]int)
f.step = (*decompressor).nextBlock
+ f.dict.init(maxMatchOffset, nil)
return &f
}
// NewReaderDict is like NewReader but initializes the reader
-// with a preset dictionary. The returned Reader behaves as if
+// with a preset dictionary. The returned Reader behaves as if
// the uncompressed data stream started with the given dictionary,
-// which has already been read. NewReaderDict is typically used
+// which has already been read. NewReaderDict is typically used
// to read data compressed by NewWriterDict.
//
// The ReadCloser returned by NewReader also implements Resetter.
@@ -846,10 +805,9 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
var f decompressor
f.r = makeReader(r)
- f.hist = new([maxHist]byte)
f.bits = new([maxNumLit + maxNumDist]int)
f.codebits = new([numCodes]int)
f.step = (*decompressor).nextBlock
- f.setDict(dict)
+ f.dict.init(maxMatchOffset, dict)
return &f
}
diff --git a/libgo/go/compress/flate/inflate_test.go b/libgo/go/compress/flate/inflate_test.go
index 9f25d30b35..951decd775 100644
--- a/libgo/go/compress/flate/inflate_test.go
+++ b/libgo/go/compress/flate/inflate_test.go
@@ -7,6 +7,8 @@ package flate
import (
"bytes"
"io"
+ "io/ioutil"
+ "strings"
"testing"
)
@@ -37,3 +39,60 @@ func TestReset(t *testing.T) {
}
}
}
+
+func TestReaderTruncated(t *testing.T) {
+ vectors := []struct{ input, output string }{
+ {"\x00", ""},
+ {"\x00\f", ""},
+ {"\x00\f\x00", ""},
+ {"\x00\f\x00\xf3\xff", ""},
+ {"\x00\f\x00\xf3\xffhello", "hello"},
+ {"\x00\f\x00\xf3\xffhello, world", "hello, world"},
+ {"\x02", ""},
+ {"\xf2H\xcd", "He"},
+ {"\xf2H͙0a\u0084\t", "Hel\x90\x90\x90\x90\x90"},
+ {"\xf2H͙0a\u0084\t\x00", "Hel\x90\x90\x90\x90\x90"},
+ }
+
+ for i, v := range vectors {
+ r := strings.NewReader(v.input)
+ zr := NewReader(r)
+ b, err := ioutil.ReadAll(zr)
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("test %d, error mismatch: got %v, want io.ErrUnexpectedEOF", i, err)
+ }
+ if string(b) != v.output {
+ t.Errorf("test %d, output mismatch: got %q, want %q", i, b, v.output)
+ }
+ }
+}
+
+func TestResetDict(t *testing.T) {
+ dict := []byte("the lorem fox")
+ ss := []string{
+ "lorem ipsum izzle fo rizzle",
+ "the quick brown fox jumped over",
+ }
+
+ deflated := make([]bytes.Buffer, len(ss))
+ for i, s := range ss {
+ w, _ := NewWriterDict(&deflated[i], DefaultCompression, dict)
+ w.Write([]byte(s))
+ w.Close()
+ }
+
+ inflated := make([]bytes.Buffer, len(ss))
+
+ f := NewReader(nil)
+ for i := range inflated {
+ f.(Resetter).Reset(&deflated[i], dict)
+ io.Copy(&inflated[i], f)
+ }
+ f.Close()
+
+ for i, s := range ss {
+ if s != inflated[i].String() {
+ t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s)
+ }
+ }
+}
diff --git a/libgo/go/compress/flate/reader_test.go b/libgo/go/compress/flate/reader_test.go
index bd8873239d..b0a16ce18b 100644
--- a/libgo/go/compress/flate/reader_test.go
+++ b/libgo/go/compress/flate/reader_test.go
@@ -22,75 +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
-)
+var levelTests = []struct {
+ name string
+ level int
+}{
+ {"Huffman", HuffmanOnly},
+ {"Speed", BestSpeed},
+ {"Default", DefaultCompression},
+ {"Compression", BestCompression},
+}
-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 BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) }
-func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) }
-func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) }
-func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) }
-func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) }
-func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) }
-func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) }
-func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) }
-func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) }
+var sizes = []struct {
+ name string
+ n int
+}{
+ {"1e4", 1e4},
+ {"1e5", 1e5},
+ {"1e6", 1e6},
+}
+
+func doBench(b *testing.B, f func(b *testing.B, buf []byte, level, n int)) {
+ for _, suite := range suites {
+ buf, err := ioutil.ReadFile(suite.file)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if len(buf) == 0 {
+ b.Fatalf("test file %q has no data", suite.file)
+ }
+ for _, l := range levelTests {
+ for _, s := range sizes {
+ b.Run(suite.name+"/"+l.name+"/"+s.name, func(b *testing.B) {
+ f(b, buf, l.level, s.n)
+ })
+ }
+ }
+ }
+}
diff --git a/libgo/go/compress/flate/reverse_bits.go b/libgo/go/compress/flate/reverse_bits.go
index c1a02720d1..6b222900c1 100644
--- a/libgo/go/compress/flate/reverse_bits.go
+++ b/libgo/go/compress/flate/reverse_bits.go
@@ -44,5 +44,5 @@ func reverseUint16(v uint16) uint16 {
}
func reverseBits(number uint16, bitLength byte) uint16 {
- return reverseUint16(number << uint8(16-bitLength))
+ return reverseUint16(number << (16 - bitLength))
}
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect b/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect
new file mode 100644
index 0000000000..c08165143f
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect-noinput
new file mode 100644
index 0000000000..c08165143f
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.golden b/libgo/go/compress/flate/testdata/huffman-null-max.golden
new file mode 100644
index 0000000000..db422ca398
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.in b/libgo/go/compress/flate/testdata/huffman-null-max.in
new file mode 100644
index 0000000000..5dfddf075b
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.in
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect b/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect
new file mode 100644
index 0000000000..c08165143f
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect-noinput
new file mode 100644
index 0000000000..c08165143f
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-null-max.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect b/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect
new file mode 100644
index 0000000000..e4396ac6fe
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect-noinput
new file mode 100644
index 0000000000..e4396ac6fe
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.golden b/libgo/go/compress/flate/testdata/huffman-pi.golden
new file mode 100644
index 0000000000..23d8f7f98b
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.in b/libgo/go/compress/flate/testdata/huffman-pi.in
new file mode 100644
index 0000000000..efaed43431
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.in
@@ -0,0 +1 @@
+3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180 \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.wb.expect b/libgo/go/compress/flate/testdata/huffman-pi.wb.expect
new file mode 100644
index 0000000000..e4396ac6fe
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-pi.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-pi.wb.expect-noinput
new file mode 100644
index 0000000000..e4396ac6fe
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-pi.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect b/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect
new file mode 100644
index 0000000000..09dc798ee3
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput
new file mode 100644
index 0000000000..0c24742fde
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.golden b/libgo/go/compress/flate/testdata/huffman-rand-1k.golden
new file mode 100644
index 0000000000..09dc798ee3
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.in b/libgo/go/compress/flate/testdata/huffman-rand-1k.in
new file mode 100644
index 0000000000..ce038ebb5b
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.in
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect b/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect
new file mode 100644
index 0000000000..09dc798ee3
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput
new file mode 100644
index 0000000000..0c24742fde
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect b/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect
new file mode 100644
index 0000000000..2d6527934e
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput
new file mode 100644
index 0000000000..2d6527934e
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.golden b/libgo/go/compress/flate/testdata/huffman-rand-limit.golden
new file mode 100644
index 0000000000..57e59322e9
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.in b/libgo/go/compress/flate/testdata/huffman-rand-limit.in
new file mode 100644
index 0000000000..fb5b1be619
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.in
@@ -0,0 +1,4 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ø‹–vH
+…”%€¯Âþè ë†É·ÅÞê}‹ç>ÚßÿlsÞÌçmIGH°èžò1YÞ4´[åà 0ˆ[|]o#©
+¼-#¾Ùíul™ßýpfæîÙ±žnƒYÕÔ€Y˜w‰C8ɯ02š F=gn×ržN!OÆàÔ{¥ö›kÜ*“w(ý´bÚ ç«kQC9/ ’lu>ô5ýC.÷¤uÚê›
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect b/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect
new file mode 100644
index 0000000000..881e59c9ab
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput
new file mode 100644
index 0000000000..881e59c9ab
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-max.golden b/libgo/go/compress/flate/testdata/huffman-rand-max.golden
new file mode 100644
index 0000000000..47d53c89c0
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-max.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-rand-max.in b/libgo/go/compress/flate/testdata/huffman-rand-max.in
new file mode 100644
index 0000000000..8418633d2a
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-rand-max.in
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect b/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect
new file mode 100644
index 0000000000..7812c1c62d
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect-noinput
new file mode 100644
index 0000000000..7812c1c62d
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.golden b/libgo/go/compress/flate/testdata/huffman-shifts.golden
new file mode 100644
index 0000000000..f5133778e1
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.in b/libgo/go/compress/flate/testdata/huffman-shifts.in
new file mode 100644
index 0000000000..7c7a50d158
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.in
@@ -0,0 +1,2 @@
+101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
+232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323 \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect b/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect
new file mode 100644
index 0000000000..7812c1c62d
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect-noinput
new file mode 100644
index 0000000000..7812c1c62d
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-shifts.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect b/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect
new file mode 100644
index 0000000000..71ce3aeb75
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput
new file mode 100644
index 0000000000..71ce3aeb75
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.golden b/libgo/go/compress/flate/testdata/huffman-text-shift.golden
new file mode 100644
index 0000000000..ff023114bb
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.in b/libgo/go/compress/flate/testdata/huffman-text-shift.in
new file mode 100644
index 0000000000..cc5c3ad69d
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.in
@@ -0,0 +1,14 @@
+//Copyright2009ThGoAuthor.Allrightrrvd.
+//UofthiourccodigovrndbyBSD-tyl
+//licnthtcnbfoundinthLICENSEfil.
+
+pckgmin
+
+import"o"
+
+funcmin(){
+ vrb=mk([]byt,65535)
+ f,_:=o.Crt("huffmn-null-mx.in")
+ f.Writ(b)
+}
+ABCDEFGHIJKLMNOPQRSTUVXxyz!"#¤%&/?" \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect b/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect
new file mode 100644
index 0000000000..71ce3aeb75
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect-noinput
new file mode 100644
index 0000000000..71ce3aeb75
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text-shift.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-text.dyn.expect b/libgo/go/compress/flate/testdata/huffman-text.dyn.expect
new file mode 100644
index 0000000000..d448727c32
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.dyn.expect
@@ -0,0 +1 @@
+Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ׶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-text.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-text.dyn.expect-noinput
new file mode 100644
index 0000000000..d448727c32
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.dyn.expect-noinput
@@ -0,0 +1 @@
+Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ׶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-text.golden b/libgo/go/compress/flate/testdata/huffman-text.golden
new file mode 100644
index 0000000000..6d34c61fe0
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.golden
@@ -0,0 +1,3 @@
+ÀAKó0ðóx¾ÃŸžZØÚñ¾LPØaÎ!‚x™âADÒöI–&#I‹EüîþšÇp]¢LÆ¿íö¯Fðp˜² 1Õ88‡h“¢$‰³ô5SÓà- ‚F66!…)v‚.ô›0„Y¢—í…ûóÃ&åÅ SÓÀÙN|d£2:åÑ
+t˜|ë‘àùéxz9Ÿ ­“š‰éªº‹£²ž‰ÉŽ×3Š
+&&=ù£²¾¬ðôšUD‹=Fu‘òã³]²¬q³ÛýßUL+½Æîö©>FQYÊÂLZÊoüäÜfTßµõEÅ´Òõ{´Yʶbúeú \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-text.in b/libgo/go/compress/flate/testdata/huffman-text.in
new file mode 100644
index 0000000000..73398b98b5
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.in
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+ var b = make([]byte, 65535)
+ f, _ := os.Create("huffman-null-max.in")
+ f.Write(b)
+}
diff --git a/libgo/go/compress/flate/testdata/huffman-text.wb.expect b/libgo/go/compress/flate/testdata/huffman-text.wb.expect
new file mode 100644
index 0000000000..d448727c32
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.wb.expect
@@ -0,0 +1 @@
+Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ׶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-text.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-text.wb.expect-noinput
new file mode 100644
index 0000000000..d448727c32
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-text.wb.expect-noinput
@@ -0,0 +1 @@
+Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ׶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect b/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect
new file mode 100644
index 0000000000..830348a79a
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect-noinput b/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect-noinput
new file mode 100644
index 0000000000..830348a79a
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.golden b/libgo/go/compress/flate/testdata/huffman-zero.golden
new file mode 100644
index 0000000000..5abdbaff9a
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.golden
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.in b/libgo/go/compress/flate/testdata/huffman-zero.in
new file mode 100644
index 0000000000..349be0e6ec
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.in
@@ -0,0 +1 @@
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.wb.expect b/libgo/go/compress/flate/testdata/huffman-zero.wb.expect
new file mode 100644
index 0000000000..dbe401c54c
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.wb.expect
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/huffman-zero.wb.expect-noinput b/libgo/go/compress/flate/testdata/huffman-zero.wb.expect-noinput
new file mode 100644
index 0000000000..dbe401c54c
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/huffman-zero.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/null-long-match.dyn.expect-noinput b/libgo/go/compress/flate/testdata/null-long-match.dyn.expect-noinput
new file mode 100644
index 0000000000..8b92d9fc20
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/null-long-match.dyn.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/testdata/null-long-match.wb.expect-noinput b/libgo/go/compress/flate/testdata/null-long-match.wb.expect-noinput
new file mode 100644
index 0000000000..8b92d9fc20
--- /dev/null
+++ b/libgo/go/compress/flate/testdata/null-long-match.wb.expect-noinput
Binary files differ
diff --git a/libgo/go/compress/flate/token.go b/libgo/go/compress/flate/token.go
index c485939d34..ae01391f9c 100644
--- a/libgo/go/compress/flate/token.go
+++ b/libgo/go/compress/flate/token.go
@@ -75,9 +75,6 @@ func matchToken(xlength uint32, xoffset uint32) token {
return token(matchType + xlength<<lengthShift + xoffset)
}
-// Returns the type of a token
-func (t token) typ() uint32 { return uint32(t) & typeMask }
-
// Returns the literal of a literal token
func (t token) literal() uint32 { return uint32(t - literalType) }
diff --git a/libgo/go/compress/flate/writer_test.go b/libgo/go/compress/flate/writer_test.go
index 58431774e0..c4d36aa37e 100644
--- a/libgo/go/compress/flate/writer_test.go
+++ b/libgo/go/compress/flate/writer_test.go
@@ -5,56 +5,171 @@
package flate
import (
+ "bytes"
+ "fmt"
+ "io"
"io/ioutil"
+ "math/rand"
"runtime"
"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
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
+ buf0 = nil
w, err := NewWriter(ioutil.Discard, level)
if err != nil {
b.Fatal(err)
}
- w.Write(buf1)
- w.Close()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ w.Reset(ioutil.Discard)
+ w.Write(buf1)
+ w.Close()
+ }
+ })
+}
+
+// errorWriter is a writer that fails after N writes.
+type errorWriter struct {
+ N int
+}
+
+func (e *errorWriter) Write(b []byte) (int, error) {
+ if e.N <= 0 {
+ return 0, io.ErrClosedPipe
}
+ e.N--
+ return len(b), nil
}
-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 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) }
+// Test if errors from the underlying writer is passed upwards.
+func TestWriteError(t *testing.T) {
+ t.Parallel()
+ buf := new(bytes.Buffer)
+ n := 65536
+ if !testing.Short() {
+ n *= 4
+ }
+ for i := 0; i < n; i++ {
+ fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
+ }
+ in := buf.Bytes()
+ // We create our own buffer to control number of writes.
+ copyBuffer := make([]byte, 128)
+ for l := 0; l < 10; l++ {
+ for fail := 1; fail <= 256; fail *= 2 {
+ // Fail after 'fail' writes
+ ew := &errorWriter{N: fail}
+ w, err := NewWriter(ew, l)
+ if err != nil {
+ t.Fatalf("NewWriter: level %d: %v", l, err)
+ }
+ n, err := io.CopyBuffer(w, struct{ io.Reader }{bytes.NewBuffer(in)}, copyBuffer)
+ if err == nil {
+ t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
+ }
+ n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
+ if n2 != 0 {
+ t.Fatal("Level", l, "Expected 0 length write, got", n)
+ }
+ if err == nil {
+ t.Fatal("Level", l, "Expected an error")
+ }
+ err = w.Flush()
+ if err == nil {
+ t.Fatal("Level", l, "Expected an error on flush")
+ }
+ err = w.Close()
+ if err == nil {
+ t.Fatal("Level", l, "Expected an error on close")
+ }
+
+ w.Reset(ioutil.Discard)
+ n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
+ if err != nil {
+ t.Fatal("Level", l, "Got unexpected error after reset:", err)
+ }
+ if n2 == 0 {
+ t.Fatal("Level", l, "Got 0 length write, expected > 0")
+ }
+ if testing.Short() {
+ return
+ }
+ }
+ }
+}
+
+// Test if two runs produce identical results
+// even when writing different sizes to the Writer.
+func TestDeterministic(t *testing.T) {
+ t.Parallel()
+ 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) {
+ t.Parallel()
+ // Test so much we cross a good number of block boundaries.
+ var length = maxStoreBlockSize*30 + 500
+ if testing.Short() {
+ length /= 10
+ }
+
+ // Create a random, but compressible stream.
+ rng := rand.New(rand.NewSource(1))
+ t1 := make([]byte, length)
+ for i := range t1 {
+ t1[i] = byte(rng.Int63() & 7)
+ }
+
+ // Do our first encode.
+ var b1 bytes.Buffer
+ br := bytes.NewBuffer(t1)
+ w, err := NewWriter(&b1, i)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Use a very small prime sized buffer.
+ cbuf := make([]byte, 787)
+ _, err = io.CopyBuffer(w, struct{ io.Reader }{br}, cbuf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Close()
+
+ // We choose a different buffer size,
+ // bigger than a maximum block, and also a prime.
+ var b2 bytes.Buffer
+ cbuf = make([]byte, 81761)
+ br2 := bytes.NewBuffer(t1)
+ w2, err := NewWriter(&b2, i)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = io.CopyBuffer(w2, struct{ io.Reader }{br2}, cbuf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ w2.Close()
+
+ b1b := b1.Bytes()
+ b2b := b2.Bytes()
+
+ if !bytes.Equal(b1b, b2b) {
+ t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
+ }
+}
diff --git a/libgo/go/compress/gzip/example_test.go b/libgo/go/compress/gzip/example_test.go
new file mode 100644
index 0000000000..4764bcb090
--- /dev/null
+++ b/libgo/go/compress/gzip/example_test.go
@@ -0,0 +1,130 @@
+// 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 gzip_test
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "time"
+)
+
+func Example_writerReader() {
+ var buf bytes.Buffer
+ zw := gzip.NewWriter(&buf)
+
+ // Setting the Header fields is optional.
+ zw.Name = "a-new-hope.txt"
+ zw.Comment = "an epic space opera by George Lucas"
+ zw.ModTime = time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC)
+
+ _, err := zw.Write([]byte("A long time ago in a galaxy far, far away..."))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ zr, err := gzip.NewReader(&buf)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())
+
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Name: a-new-hope.txt
+ // Comment: an epic space opera by George Lucas
+ // ModTime: 1977-05-25 00:00:00 +0000 UTC
+ //
+ // A long time ago in a galaxy far, far away...
+}
+
+func ExampleReader_Multistream() {
+ var buf bytes.Buffer
+ zw := gzip.NewWriter(&buf)
+
+ var files = []struct {
+ name string
+ comment string
+ modTime time.Time
+ data string
+ }{
+ {"file-1.txt", "file-header-1", time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC), "Hello Gophers - 1"},
+ {"file-2.txt", "file-header-2", time.Date(2007, time.March, 2, 4, 5, 6, 1, time.UTC), "Hello Gophers - 2"},
+ }
+
+ for _, file := range files {
+ zw.Name = file.name
+ zw.Comment = file.comment
+ zw.ModTime = file.modTime
+
+ if _, err := zw.Write([]byte(file.data)); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ zw.Reset(&buf)
+ }
+
+ zr, err := gzip.NewReader(&buf)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for {
+ zr.Multistream(false)
+ fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())
+
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Print("\n\n")
+
+ err = zr.Reset(&buf)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Name: file-1.txt
+ // Comment: file-header-1
+ // ModTime: 2006-02-01 03:04:05 +0000 UTC
+ //
+ // Hello Gophers - 1
+ //
+ // Name: file-2.txt
+ // Comment: file-header-2
+ // ModTime: 2007-03-02 04:05:06 +0000 UTC
+ //
+ // Hello Gophers - 2
+}
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
index 3d331454a6..8bd750bd8b 100644
--- a/libgo/go/compress/gzip/gunzip.go
+++ b/libgo/go/compress/gzip/gunzip.go
@@ -9,8 +9,8 @@ package gzip
import (
"bufio"
"compress/flate"
+ "encoding/binary"
"errors"
- "hash"
"hash/crc32"
"io"
"time"
@@ -27,13 +27,6 @@ const (
flagComment = 1 << 4
)
-func makeReader(r io.Reader) flate.Reader {
- if rr, ok := r.(flate.Reader); ok {
- return rr
- }
- return bufio.NewReader(r)
-}
-
var (
// ErrChecksum is returned when reading GZIP data that has an invalid checksum.
ErrChecksum = errors.New("gzip: invalid checksum")
@@ -41,6 +34,16 @@ var (
ErrHeader = errors.New("gzip: invalid header")
)
+var le = binary.LittleEndian
+
+// noEOF converts io.EOF to io.ErrUnexpectedEOF.
+func noEOF(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
+
// The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the Writer and Reader structs.
//
@@ -58,23 +61,22 @@ type Header struct {
// uncompressed data from a gzip-format compressed file.
//
// In general, a gzip file can be a concatenation of gzip files,
-// each with its own header. Reads from the Reader
+// each with its own header. Reads from the Reader
// return the concatenation of the uncompressed data of each.
// Only the first header is recorded in the Reader fields.
//
// Gzip files store a length and checksum of the uncompressed data.
// The Reader will return a ErrChecksum when Read
// reaches the end of the uncompressed data if it does not
-// have the expected length or checksum. Clients should treat data
+// have the expected length or checksum. Clients should treat data
// returned by Read as tentative until they receive the io.EOF
// marking the end of the data.
type Reader struct {
Header // valid after NewReader or Reader.Reset
r flate.Reader
decompressor io.ReadCloser
- digest hash.Hash32
- size uint32
- flg byte
+ digest uint32 // CRC-32, IEEE polynomial (section 8)
+ size uint32 // Uncompressed size (section 2.3.1)
buf [512]byte
err error
multistream bool
@@ -89,10 +91,7 @@ type Reader struct {
// The Reader.Header fields will be valid in the Reader returned.
func NewReader(r io.Reader) (*Reader, error) {
z := new(Reader)
- z.r = makeReader(r)
- z.multistream = true
- z.digest = crc32.NewIEEE()
- if err := z.readHeader(true); err != nil {
+ if err := z.Reset(r); err != nil {
return nil, err
}
return z, nil
@@ -102,16 +101,17 @@ func NewReader(r io.Reader) (*Reader, error) {
// result of its original state from NewReader, but reading from r instead.
// This permits reusing a Reader rather than allocating a new one.
func (z *Reader) Reset(r io.Reader) error {
- z.r = makeReader(r)
- if z.digest == nil {
- z.digest = crc32.NewIEEE()
+ *z = Reader{
+ decompressor: z.decompressor,
+ multistream: true,
+ }
+ if rr, ok := r.(flate.Reader); ok {
+ z.r = rr
} else {
- z.digest.Reset()
+ z.r = bufio.NewReader(r)
}
- z.size = 0
- z.err = nil
- z.multistream = true
- return z.readHeader(true)
+ z.Header, z.err = z.readHeader()
+ return z.err
}
// Multistream controls whether the reader supports multistream files.
@@ -134,14 +134,13 @@ func (z *Reader) Multistream(ok bool) {
z.multistream = ok
}
-// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
-func get4(p []byte) uint32 {
- return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
-}
-
+// readString reads a NUL-terminated string from z.r.
+// It treats the bytes read as being encoded as ISO 8859-1 (Latin-1) and
+// will output a string encoded using UTF-8.
+// This method always updates z.digest with the data read.
func (z *Reader) readString() (string, error) {
var err error
- needconv := false
+ needConv := false
for i := 0; ; i++ {
if i >= len(z.buf) {
return "", ErrHeader
@@ -151,159 +150,143 @@ func (z *Reader) readString() (string, error) {
return "", err
}
if z.buf[i] > 0x7f {
- needconv = true
+ needConv = true
}
if z.buf[i] == 0 {
- // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
- if needconv {
+ // Digest covers the NUL terminator.
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:i+1])
+
+ // Strings are ISO 8859-1, Latin-1 (RFC 1952, section 2.3.1).
+ if needConv {
s := make([]rune, 0, i)
- for _, v := range z.buf[0:i] {
+ for _, v := range z.buf[:i] {
s = append(s, rune(v))
}
return string(s), nil
}
- return string(z.buf[0:i]), nil
+ return string(z.buf[:i]), nil
}
}
}
-func (z *Reader) read2() (uint32, error) {
- _, err := io.ReadFull(z.r, z.buf[0:2])
- if err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return 0, err
- }
- return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
-}
-
-func (z *Reader) readHeader(save bool) error {
- _, err := io.ReadFull(z.r, z.buf[0:10])
- if err != nil {
- // RFC1952 section 2.2 says the following:
+// readHeader reads the GZIP header according to section 2.3.1.
+// This method does not set z.err.
+func (z *Reader) readHeader() (hdr Header, err error) {
+ if _, err = io.ReadFull(z.r, z.buf[:10]); err != nil {
+ // RFC 1952, section 2.2, says the following:
// A gzip file consists of a series of "members" (compressed data sets).
//
// Other than this, the specification does not clarify whether a
// "series" is defined as "one or more" or "zero or more". To err on the
// side of caution, Go interprets this to mean "zero or more".
// Thus, it is okay to return io.EOF here.
- return err
+ return hdr, err
}
if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
- return ErrHeader
+ return hdr, ErrHeader
}
- z.flg = z.buf[3]
- if save {
- z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0)
- // z.buf[8] is xfl, ignored
- z.OS = z.buf[9]
+ flg := z.buf[3]
+ if t := int64(le.Uint32(z.buf[4:8])); t > 0 {
+ // Section 2.3.1, the zero value for MTIME means that the
+ // modified time is not set.
+ hdr.ModTime = time.Unix(t, 0)
}
- z.digest.Reset()
- z.digest.Write(z.buf[0:10])
+ // z.buf[8] is XFL and is currently ignored.
+ hdr.OS = z.buf[9]
+ z.digest = crc32.ChecksumIEEE(z.buf[:10])
- if z.flg&flagExtra != 0 {
- n, err := z.read2()
- if err != nil {
- return err
+ if flg&flagExtra != 0 {
+ if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+ return hdr, noEOF(err)
}
- data := make([]byte, n)
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:2])
+ data := make([]byte, le.Uint16(z.buf[:2]))
if _, err = io.ReadFull(z.r, data); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return err
- }
- if save {
- z.Extra = data
+ return hdr, noEOF(err)
}
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, data)
+ hdr.Extra = data
}
var s string
- if z.flg&flagName != 0 {
+ if flg&flagName != 0 {
if s, err = z.readString(); err != nil {
- return err
- }
- if save {
- z.Name = s
+ return hdr, err
}
+ hdr.Name = s
}
- if z.flg&flagComment != 0 {
+ if flg&flagComment != 0 {
if s, err = z.readString(); err != nil {
- return err
- }
- if save {
- z.Comment = s
+ return hdr, err
}
+ hdr.Comment = s
}
- if z.flg&flagHdrCrc != 0 {
- n, err := z.read2()
- if err != nil {
- return err
+ if flg&flagHdrCrc != 0 {
+ if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+ return hdr, noEOF(err)
}
- sum := z.digest.Sum32() & 0xFFFF
- if n != sum {
- return ErrHeader
+ digest := le.Uint16(z.buf[:2])
+ if digest != uint16(z.digest) {
+ return hdr, ErrHeader
}
}
- z.digest.Reset()
+ z.digest = 0
if z.decompressor == nil {
z.decompressor = flate.NewReader(z.r)
} else {
z.decompressor.(flate.Resetter).Reset(z.r, nil)
}
- return nil
+ return hdr, nil
}
+// Read implements io.Reader, reading uncompressed bytes from its underlying Reader.
func (z *Reader) Read(p []byte) (n int, err error) {
if z.err != nil {
return 0, z.err
}
- if len(p) == 0 {
- return 0, nil
- }
- n, err = z.decompressor.Read(p)
- z.digest.Write(p[0:n])
+ n, z.err = z.decompressor.Read(p)
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
z.size += uint32(n)
- if n != 0 || err != io.EOF {
- z.err = err
- return
+ if z.err != io.EOF {
+ // In the normal case we return here.
+ return n, z.err
}
- // Finished file; check checksum + size.
- if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- z.err = err
- return 0, err
+ // Finished file; check checksum and size.
+ if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
+ z.err = noEOF(err)
+ return n, z.err
}
- crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
- sum := z.digest.Sum32()
- if sum != crc32 || isize != z.size {
+ digest := le.Uint32(z.buf[:4])
+ size := le.Uint32(z.buf[4:8])
+ if digest != z.digest || size != z.size {
z.err = ErrChecksum
- return 0, z.err
+ return n, z.err
}
+ z.digest, z.size = 0, 0
- // File is ok; is there another?
+ // File is ok; check if there is another.
if !z.multistream {
- return 0, io.EOF
+ return n, io.EOF
}
+ z.err = nil // Remove io.EOF
- if err = z.readHeader(false); err != nil {
- z.err = err
- return
+ if _, z.err = z.readHeader(); z.err != nil {
+ return n, z.err
}
- // Yes. Reset and read from it.
- z.digest.Reset()
- z.size = 0
+ // Read from next file, if necessary.
+ if n > 0 {
+ return n, nil
+ }
return z.Read(p)
}
// Close closes the Reader. It does not close the underlying io.Reader.
+// In order for the GZIP checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
func (z *Reader) Close() error { return z.decompressor.Close() }
diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go
index 007d9585ce..fdea0c5d5f 100644
--- a/libgo/go/compress/gzip/gunzip_test.go
+++ b/libgo/go/compress/gzip/gunzip_test.go
@@ -36,6 +36,17 @@ var gunzipTests = []gunzipTest{
},
nil,
},
+ {
+ "",
+ "empty - with no file name",
+ "",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88,
+ 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ nil,
+ },
{ // has 1 non-empty fixed huffman block
"hello.txt",
"hello.txt",
@@ -281,49 +292,122 @@ var gunzipTests = []gunzipTest{
},
ErrChecksum,
},
+ {
+ "f1l3n4m3.tXt",
+ "header with all fields used",
+ "",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x1e, 0x70, 0xf0, 0xf9, 0x4a,
+ 0x00, 0xaa, 0x09, 0x00, 0x7a, 0x7a, 0x05, 0x00,
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x31, 0x6c,
+ 0x33, 0x6e, 0x34, 0x6d, 0x33, 0x2e, 0x74, 0x58,
+ 0x74, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+ 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+ 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
+ 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+ 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
+ 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+ 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+ 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,
+ 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+ 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+ 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
+ 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee,
+ 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
+ 0xff, 0x00, 0x92, 0xfd, 0x01, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ },
+ nil,
+ },
+ {
+ "",
+ "truncated gzip file amid raw-block",
+ "hello",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x0c, 0x00, 0xf3, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ },
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "",
+ "truncated gzip file amid fixed-block",
+ "He",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xf2, 0x48, 0xcd,
+ },
+ io.ErrUnexpectedEOF,
+ },
}
func TestDecompressor(t *testing.T) {
+ // Keep resetting this reader.
+ // It is intended behavior that Reader.Reset can be called on a zero-value
+ // Reader and be the equivalent as if NewReader was used instead.
+ r1 := new(Reader)
+
b := new(bytes.Buffer)
for _, tt := range gunzipTests {
+ // Test NewReader.
in := bytes.NewReader(tt.gzip)
- gzip, err := NewReader(in)
+ r2, err := NewReader(in)
if err != nil {
- t.Errorf("%s: NewReader: %s", tt.name, err)
+ t.Errorf("%s: NewReader: %s", tt.desc, err)
continue
}
- defer gzip.Close()
- if tt.name != gzip.Name {
- t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ defer r2.Close()
+ if tt.name != r2.Name {
+ t.Errorf("%s: got name %s", tt.desc, r2.Name)
}
b.Reset()
- n, err := io.Copy(b, gzip)
+ n, err := io.Copy(b, r2)
if err != tt.err {
- t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
}
s := b.String()
if s != tt.raw {
- t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
}
- // Test Reader Reset.
+ // Test Reader.Reset.
in = bytes.NewReader(tt.gzip)
- err = gzip.Reset(in)
+ err = r1.Reset(in)
if err != nil {
- t.Errorf("%s: Reset: %s", tt.name, err)
+ t.Errorf("%s: Reset: %s", tt.desc, err)
continue
}
- if tt.name != gzip.Name {
- t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ if tt.name != r1.Name {
+ t.Errorf("%s: got name %s", tt.desc, r1.Name)
}
b.Reset()
- n, err = io.Copy(b, gzip)
+ n, err = io.Copy(b, r1)
if err != tt.err {
- t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
}
s = b.String()
if s != tt.raw {
- t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
}
}
}
@@ -356,20 +440,6 @@ func TestIssue6550(t *testing.T) {
}
}
-func TestInitialReset(t *testing.T) {
- var r Reader
- if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil {
- t.Error(err)
- }
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, &r); err != nil {
- t.Error(err)
- }
- if s := buf.String(); s != gunzipTests[1].raw {
- t.Errorf("got %q want %q", s, gunzipTests[1].raw)
- }
-}
-
func TestMultistreamFalse(t *testing.T) {
// Find concatenation test.
var tt gunzipTest
@@ -411,7 +481,7 @@ Found:
}
func TestNilStream(t *testing.T) {
- // Go liberally interprets RFC1952 section 2.2 to mean that a gzip file
+ // Go liberally interprets RFC 1952 section 2.2 to mean that a gzip file
// consist of zero or more members. Thus, we test that a nil stream is okay.
_, err := NewReader(bytes.NewReader(nil))
if err != io.EOF {
diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go
index 4d945e47fe..aafb442a66 100644
--- a/libgo/go/compress/gzip/gzip.go
+++ b/libgo/go/compress/gzip/gzip.go
@@ -8,9 +8,9 @@ import (
"compress/flate"
"errors"
"fmt"
- "hash"
"hash/crc32"
"io"
+ "time"
)
// These constants are copied from the flate package, so that code that imports
@@ -20,6 +20,7 @@ const (
BestSpeed = flate.BestSpeed
BestCompression = flate.BestCompression
DefaultCompression = flate.DefaultCompression
+ HuffmanOnly = flate.HuffmanOnly
)
// A Writer is an io.WriteCloser.
@@ -30,8 +31,8 @@ type Writer struct {
level int
wroteHeader bool
compressor *flate.Writer
- digest hash.Hash32
- size uint32
+ digest uint32 // CRC-32, IEEE polynomial (section 8)
+ size uint32 // Uncompressed size (section 2.3.1)
closed bool
buf [10]byte
err error
@@ -53,11 +54,11 @@ func NewWriter(w io.Writer) *Writer {
// NewWriterLevel is like NewWriter but specifies the compression level instead
// of assuming DefaultCompression.
//
-// The compression level can be DefaultCompression, NoCompression, or any
-// integer value between BestSpeed and BestCompression inclusive. The error
-// returned will be nil if the level is valid.
+// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
+// or any integer value between BestSpeed and BestCompression inclusive.
+// The error returned will be nil if the level is valid.
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
- if level < DefaultCompression || level > BestCompression {
+ if level < HuffmanOnly || level > BestCompression {
return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
}
z := new(Writer)
@@ -66,12 +67,6 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
}
func (z *Writer) init(w io.Writer, level int) {
- digest := z.digest
- if digest != nil {
- digest.Reset()
- } else {
- digest = crc32.NewIEEE()
- }
compressor := z.compressor
if compressor != nil {
compressor.Reset(w)
@@ -82,7 +77,6 @@ func (z *Writer) init(w io.Writer, level int) {
},
w: w,
level: level,
- digest: digest,
compressor: compressor,
}
}
@@ -95,26 +89,13 @@ func (z *Writer) Reset(w io.Writer) {
z.init(w, z.level)
}
-// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
-func put2(p []byte, v uint16) {
- p[0] = uint8(v >> 0)
- p[1] = uint8(v >> 8)
-}
-
-func put4(p []byte, v uint32) {
- p[0] = uint8(v >> 0)
- p[1] = uint8(v >> 8)
- p[2] = uint8(v >> 16)
- p[3] = uint8(v >> 24)
-}
-
// writeBytes writes a length-prefixed byte slice to z.w.
func (z *Writer) writeBytes(b []byte) error {
if len(b) > 0xffff {
return errors.New("gzip.Write: Extra data is too large")
}
- put2(z.buf[0:2], uint16(len(b)))
- _, err := z.w.Write(z.buf[0:2])
+ le.PutUint16(z.buf[:2], uint16(len(b)))
+ _, err := z.w.Write(z.buf[:2])
if err != nil {
return err
}
@@ -149,7 +130,7 @@ func (z *Writer) writeString(s string) (err error) {
}
// GZIP strings are NUL-terminated.
z.buf[0] = 0
- _, err = z.w.Write(z.buf[0:1])
+ _, err = z.w.Write(z.buf[:1])
return err
}
@@ -163,10 +144,7 @@ func (z *Writer) Write(p []byte) (int, error) {
// Write the GZIP header lazily.
if !z.wroteHeader {
z.wroteHeader = true
- z.buf[0] = gzipID1
- z.buf[1] = gzipID2
- z.buf[2] = gzipDeflate
- z.buf[3] = 0
+ z.buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate}
if z.Extra != nil {
z.buf[3] |= 0x04
}
@@ -176,16 +154,18 @@ func (z *Writer) Write(p []byte) (int, error) {
if z.Comment != "" {
z.buf[3] |= 0x10
}
- put4(z.buf[4:8], uint32(z.ModTime.Unix()))
+ if z.ModTime.After(time.Unix(0, 0)) {
+ // Section 2.3.1, the zero value for MTIME means that the
+ // modified time is not set.
+ le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
+ }
if z.level == BestCompression {
z.buf[8] = 2
} else if z.level == BestSpeed {
z.buf[8] = 4
- } else {
- z.buf[8] = 0
}
z.buf[9] = z.OS
- n, z.err = z.w.Write(z.buf[0:10])
+ n, z.err = z.w.Write(z.buf[:10])
if z.err != nil {
return n, z.err
}
@@ -212,7 +192,7 @@ func (z *Writer) Write(p []byte) (int, error) {
}
}
z.size += uint32(len(p))
- z.digest.Write(p)
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
n, z.err = z.compressor.Write(p)
return n, z.err
}
@@ -262,8 +242,8 @@ func (z *Writer) Close() error {
if z.err != nil {
return z.err
}
- put4(z.buf[0:4], z.digest.Sum32())
- put4(z.buf[4:8], z.size)
- _, z.err = z.w.Write(z.buf[0:8])
+ le.PutUint32(z.buf[:4], z.digest)
+ le.PutUint32(z.buf[4:8], z.size)
+ _, z.err = z.w.Write(z.buf[:8])
return z.err
}
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
index 09271b24e9..865c529f55 100644
--- a/libgo/go/compress/gzip/gzip_test.go
+++ b/libgo/go/compress/gzip/gzip_test.go
@@ -8,6 +8,7 @@ import (
"bufio"
"bytes"
"io/ioutil"
+ "reflect"
"testing"
"time"
)
@@ -24,6 +25,9 @@ func TestEmpty(t *testing.T) {
if err != nil {
t.Fatalf("NewReader: %v", err)
}
+ if want := (Header{OS: 255}); !reflect.DeepEqual(r.Header, want) {
+ t.Errorf("Header mismatch:\ngot %#v\nwant %#v", r.Header, want)
+ }
b, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("ReadAll: %v", err)
diff --git a/libgo/go/compress/gzip/issue14937_test.go b/libgo/go/compress/gzip/issue14937_test.go
new file mode 100644
index 0000000000..30c1390dfd
--- /dev/null
+++ b/libgo/go/compress/gzip/issue14937_test.go
@@ -0,0 +1,68 @@
+package gzip
+
+import (
+ "internal/testenv"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+// TestGZIPFilesHaveZeroMTimes checks that every .gz file in the tree
+// has a zero MTIME. This is a requirement for the Debian maintainers
+// to be able to have deterministic packages.
+//
+// See https://golang.org/issue/14937.
+func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
+ // To avoid spurious false positives due to untracked GZIP files that
+ // may be in the user's GOROOT (Issue 18604), we only run this test on
+ // the builders, which should have a clean checkout of the tree.
+ if testenv.Builder() == "" {
+ t.Skip("skipping test on non-builder")
+ }
+ goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
+ if err != nil {
+ t.Fatal("error evaluating GOROOT: ", err)
+ }
+ var files []string
+ err = filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() && strings.HasSuffix(path, ".gz") {
+ files = append(files, path)
+ }
+ return nil
+ })
+ if err != nil {
+ if os.IsNotExist(err) {
+ t.Skipf("skipping: GOROOT directory not found: %s", runtime.GOROOT())
+ }
+ t.Fatal("error collecting list of .gz files in GOROOT: ", err)
+ }
+ if len(files) == 0 {
+ t.Fatal("expected to find some .gz files under GOROOT")
+ }
+ for _, path := range files {
+ checkZeroMTime(t, path)
+ }
+}
+
+func checkZeroMTime(t *testing.T, path string) {
+ f, err := os.Open(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer f.Close()
+ gz, err := NewReader(f)
+ if err != nil {
+ t.Errorf("cannot read gzip file %s: %s", path, err)
+ return
+ }
+ defer gz.Close()
+ if !gz.ModTime.IsZero() {
+ t.Errorf("gzip file %s has non-zero mtime (%s)", path, gz.ModTime)
+ }
+}
diff --git a/libgo/go/compress/gzip/testdata/issue6550.gz b/libgo/go/compress/gzip/testdata/issue6550.gz
index 57972b6366..82b4af1026 100644
--- a/libgo/go/compress/gzip/testdata/issue6550.gz
+++ b/libgo/go/compress/gzip/testdata/issue6550.gz
Binary files differ
diff --git a/libgo/go/compress/lzw/reader_test.go b/libgo/go/compress/lzw/reader_test.go
index c3a5c3a0aa..6b9f9a3da7 100644
--- a/libgo/go/compress/lzw/reader_test.go
+++ b/libgo/go/compress/lzw/reader_test.go
@@ -6,8 +6,10 @@ package lzw
import (
"bytes"
+ "fmt"
"io"
"io/ioutil"
+ "math"
"runtime"
"strconv"
"strings"
@@ -118,42 +120,37 @@ func TestReader(t *testing.T) {
}
}
-func benchmarkDecoder(b *testing.B, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkDecoder(b *testing.B) {
+ buf, err := ioutil.ReadFile("../testdata/e.txt")
if err != nil {
b.Fatal(err)
}
- if len(buf0) == 0 {
+ if len(buf) == 0 {
b.Fatalf("test file has no data")
}
- compressed := new(bytes.Buffer)
- w := NewWriter(compressed, LSB, 8)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
- }
- w.Write(buf0)
- }
- w.Close()
- buf1 := compressed.Bytes()
- buf0, compressed, w = nil, nil, nil
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
- }
-}
-
-func BenchmarkDecoder1e4(b *testing.B) {
- benchmarkDecoder(b, 1e4)
-}
-func BenchmarkDecoder1e5(b *testing.B) {
- benchmarkDecoder(b, 1e5)
-}
-
-func BenchmarkDecoder1e6(b *testing.B) {
- benchmarkDecoder(b, 1e6)
+ for e := 4; e <= 6; e++ {
+ n := int(math.Pow10(e))
+ b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+ b.StopTimer()
+ b.SetBytes(int64(n))
+ buf0 := buf
+ compressed := new(bytes.Buffer)
+ w := NewWriter(compressed, LSB, 8)
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ w.Write(buf0)
+ }
+ w.Close()
+ buf1 := compressed.Bytes()
+ buf0, compressed, w = nil, nil, nil
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
+ }
+ })
+ }
}
diff --git a/libgo/go/compress/lzw/writer.go b/libgo/go/compress/lzw/writer.go
index 7367c29651..6ddb335f31 100644
--- a/libgo/go/compress/lzw/writer.go
+++ b/libgo/go/compress/lzw/writer.go
@@ -119,7 +119,7 @@ func (e *encoder) incHi() error {
if err := e.write(e, clear); err != nil {
return err
}
- e.width = uint(e.litWidth) + 1
+ e.width = e.litWidth + 1
e.hi = clear + 1
e.overflow = clear << 1
for i := range e.table {
diff --git a/libgo/go/compress/lzw/writer_test.go b/libgo/go/compress/lzw/writer_test.go
index 66d761727f..4979f8b352 100644
--- a/libgo/go/compress/lzw/writer_test.go
+++ b/libgo/go/compress/lzw/writer_test.go
@@ -5,9 +5,11 @@
package lzw
import (
+ "fmt"
"internal/testenv"
"io"
"io/ioutil"
+ "math"
"os"
"runtime"
"testing"
@@ -122,41 +124,34 @@ func TestSmallLitWidth(t *testing.T) {
}
}
-func benchmarkEncoder(b *testing.B, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkEncoder(b *testing.B) {
+ buf, err := ioutil.ReadFile("../testdata/e.txt")
if err != nil {
b.Fatal(err)
}
- if len(buf0) == 0 {
+ if len(buf) == 0 {
b.Fatalf("test file has no data")
}
- buf1 := make([]byte, n)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
+
+ for e := 4; e <= 6; e++ {
+ n := int(math.Pow10(e))
+ buf0 := buf
+ buf1 := make([]byte, n)
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ copy(buf1[i:], buf0)
}
- copy(buf1[i:], buf0)
- }
- buf0 = nil
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- w := NewWriter(ioutil.Discard, LSB, 8)
- w.Write(buf1)
- w.Close()
+ buf0 = nil
+ runtime.GC()
+ b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+ b.SetBytes(int64(n))
+ for i := 0; i < b.N; i++ {
+ w := NewWriter(ioutil.Discard, LSB, 8)
+ w.Write(buf1)
+ w.Close()
+ }
+ })
}
}
-
-func BenchmarkEncoder1e4(b *testing.B) {
- benchmarkEncoder(b, 1e4)
-}
-
-func BenchmarkEncoder1e5(b *testing.B) {
- benchmarkEncoder(b, 1e5)
-}
-
-func BenchmarkEncoder1e6(b *testing.B) {
- benchmarkEncoder(b, 1e6)
-}
diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go
index 78ea7043bc..2efa193035 100644
--- a/libgo/go/compress/zlib/reader.go
+++ b/libgo/go/compress/zlib/reader.go
@@ -62,7 +62,8 @@ type Resetter interface {
// NewReader creates a new ReadCloser.
// Reads from the returned ReadCloser read and decompress data from r.
-// The implementation buffers input and may read more data than necessary from r.
+// If r does not implement io.ByteReader, the decompressor may read more
+// data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when done.
//
// The ReadCloser returned by NewReader also implements Resetter.
@@ -84,19 +85,17 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
return z, nil
}
-func (z *reader) Read(p []byte) (n int, err error) {
+func (z *reader) Read(p []byte) (int, error) {
if z.err != nil {
return 0, z.err
}
- if len(p) == 0 {
- return 0, nil
- }
- n, err = z.decompressor.Read(p)
+ var n int
+ n, z.err = z.decompressor.Read(p)
z.digest.Write(p[0:n])
- if n != 0 || err != io.EOF {
- z.err = err
- return
+ if z.err != io.EOF {
+ // In the normal case we return here.
+ return n, z.err
}
// Finished file; check checksum.
@@ -105,20 +104,22 @@ func (z *reader) Read(p []byte) (n int, err error) {
err = io.ErrUnexpectedEOF
}
z.err = err
- return 0, err
+ return n, z.err
}
// ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != z.digest.Sum32() {
z.err = ErrChecksum
- return 0, z.err
+ return n, z.err
}
- return
+ return n, io.EOF
}
// 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 {
+ if z.err != nil && z.err != io.EOF {
return z.err
}
z.err = z.decompressor.Close()
@@ -126,36 +127,42 @@ func (z *reader) Close() error {
}
func (z *reader) Reset(r io.Reader, dict []byte) error {
+ *z = reader{decompressor: z.decompressor}
if fr, ok := r.(flate.Reader); ok {
z.r = fr
} else {
z.r = bufio.NewReader(r)
}
- _, err := io.ReadFull(z.r, z.scratch[0:2])
- if err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
+
+ // Read the header (RFC 1950 section 2.2.).
+ _, z.err = io.ReadFull(z.r, z.scratch[0:2])
+ if z.err != nil {
+ if z.err == io.EOF {
+ z.err = io.ErrUnexpectedEOF
}
- return err
+ return z.err
}
h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
- return ErrHeader
+ z.err = ErrHeader
+ return z.err
}
haveDict := z.scratch[1]&0x20 != 0
if haveDict {
- _, err = io.ReadFull(z.r, z.scratch[0:4])
- if err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
+ _, z.err = io.ReadFull(z.r, z.scratch[0:4])
+ if z.err != nil {
+ if z.err == io.EOF {
+ z.err = io.ErrUnexpectedEOF
}
- return err
+ return z.err
}
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != adler32.Checksum(dict) {
- return ErrDictionary
+ z.err = ErrDictionary
+ return z.err
}
}
+
if z.decompressor == nil {
if haveDict {
z.decompressor = flate.NewReaderDict(z.r, dict)
diff --git a/libgo/go/compress/zlib/reader_test.go b/libgo/go/compress/zlib/reader_test.go
index 449f4460bc..7e27aecb47 100644
--- a/libgo/go/compress/zlib/reader_test.go
+++ b/libgo/go/compress/zlib/reader_test.go
@@ -121,22 +121,42 @@ var zlibTests = []zlibTest{
},
ErrDictionary,
},
+ {
+ "truncated zlib stream amid raw-block",
+ "hello",
+ []byte{
+ 0x78, 0x9c, 0x00, 0x0c, 0x00, 0xf3, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ },
+ nil,
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "truncated zlib stream amid fixed-block",
+ "He",
+ []byte{
+ 0x78, 0x9c, 0xf2, 0x48, 0xcd,
+ },
+ nil,
+ io.ErrUnexpectedEOF,
+ },
}
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range zlibTests {
in := bytes.NewReader(tt.compressed)
- zlib, err := NewReaderDict(in, tt.dict)
+ zr, err := NewReaderDict(in, tt.dict)
if err != nil {
if err != tt.err {
t.Errorf("%s: NewReader: %s", tt.desc, err)
}
continue
}
- defer zlib.Close()
+ defer zr.Close()
+
+ // Read and verify correctness of data.
b.Reset()
- n, err := io.Copy(b, zlib)
+ n, err := io.Copy(b, zr)
if err != nil {
if err != tt.err {
t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
@@ -147,5 +167,13 @@ func TestDecompressor(t *testing.T) {
if s != tt.raw {
t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
}
+
+ // Check for sticky errors.
+ if n, err := zr.Read([]byte{0}); n != 0 || err != io.EOF {
+ t.Errorf("%s: Read() = (%d, %v), want (0, io.EOF)", tt.desc, n, err)
+ }
+ if err := zr.Close(); err != nil {
+ t.Errorf("%s: Close() = %v, want nil", tt.desc, err)
+ }
}
}
diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go
index 3b4313a8be..1620c00c52 100644
--- a/libgo/go/compress/zlib/writer.go
+++ b/libgo/go/compress/zlib/writer.go
@@ -19,6 +19,7 @@ const (
BestSpeed = flate.BestSpeed
BestCompression = flate.BestCompression
DefaultCompression = flate.DefaultCompression
+ HuffmanOnly = flate.HuffmanOnly
)
// A Writer takes data written to it and writes the compressed
@@ -47,9 +48,9 @@ func NewWriter(w io.Writer) *Writer {
// NewWriterLevel is like NewWriter but specifies the compression level instead
// of assuming DefaultCompression.
//
-// The compression level can be DefaultCompression, NoCompression, or any
-// integer value between BestSpeed and BestCompression inclusive. The error
-// returned will be nil if the level is valid.
+// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
+// or any integer value between BestSpeed and BestCompression inclusive.
+// The error returned will be nil if the level is valid.
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
return NewWriterLevelDict(w, level, nil)
}
@@ -60,7 +61,7 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
// The dictionary may be nil. If not, its contents should not be modified until
// the Writer is closed.
func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
- if level < DefaultCompression || level > BestCompression {
+ if level < HuffmanOnly || level > BestCompression {
return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
}
return &Writer{
@@ -99,7 +100,7 @@ func (z *Writer) writeHeader() (err error) {
// The next bit, FDICT, is set if a dictionary is given.
// The final five FCHECK bits form a mod-31 checksum.
switch z.level {
- case 0, 1:
+ case -2, 0, 1:
z.scratch[1] = 0 << 6
case 2, 3, 4, 5:
z.scratch[1] = 1 << 6
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
index dd94165520..d501974078 100644
--- a/libgo/go/compress/zlib/writer_test.go
+++ b/libgo/go/compress/zlib/writer_test.go
@@ -147,6 +147,7 @@ func TestWriter(t *testing.T) {
tag := fmt.Sprintf("#%d", i)
testLevelDict(t, tag, b, DefaultCompression, "")
testLevelDict(t, tag, b, NoCompression, "")
+ testLevelDict(t, tag, b, HuffmanOnly, "")
for level := BestSpeed; level <= BestCompression; level++ {
testLevelDict(t, tag, b, level, "")
}
@@ -157,6 +158,7 @@ func TestWriterBig(t *testing.T) {
for i, fn := range filenames {
testFileLevelDict(t, fn, DefaultCompression, "")
testFileLevelDict(t, fn, NoCompression, "")
+ testFileLevelDict(t, fn, HuffmanOnly, "")
for level := BestSpeed; level <= BestCompression; level++ {
testFileLevelDict(t, fn, level, "")
if level >= 1 && testing.Short() && testenv.Builder() == "" {
@@ -174,6 +176,7 @@ func TestWriterDict(t *testing.T) {
for i, fn := range filenames {
testFileLevelDict(t, fn, DefaultCompression, dictionary)
testFileLevelDict(t, fn, NoCompression, dictionary)
+ testFileLevelDict(t, fn, HuffmanOnly, dictionary)
for level := BestSpeed; level <= BestCompression; level++ {
testFileLevelDict(t, fn, level, dictionary)
if level >= 1 && testing.Short() && testenv.Builder() == "" {
@@ -191,8 +194,10 @@ func TestWriterReset(t *testing.T) {
for _, fn := range filenames {
testFileLevelDictReset(t, fn, NoCompression, nil)
testFileLevelDictReset(t, fn, DefaultCompression, nil)
+ testFileLevelDictReset(t, fn, HuffmanOnly, nil)
testFileLevelDictReset(t, fn, NoCompression, []byte(dictionary))
testFileLevelDictReset(t, fn, DefaultCompression, []byte(dictionary))
+ testFileLevelDictReset(t, fn, HuffmanOnly, []byte(dictionary))
if testing.Short() {
break
}
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
index c467a11910..7110c513f0 100644
--- a/libgo/go/container/heap/heap.go
+++ b/libgo/go/container/heap/heap.go
@@ -25,7 +25,7 @@ import "sort"
// !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
//
// Note that Push and Pop in this interface are for package heap's
-// implementation to call. To add and remove things from the heap,
+// implementation to call. To add and remove things from the heap,
// use heap.Push and heap.Pop.
type Interface interface {
sort.Interface
@@ -83,8 +83,9 @@ func Remove(h Interface, i int) interface{} {
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log(n)) where n = h.Len().
func Fix(h Interface, i int) {
- down(h, i, h.Len())
- up(h, i)
+ if !down(h, i, h.Len()) {
+ up(h, i)
+ }
}
func up(h Interface, j int) {
@@ -98,7 +99,8 @@ func up(h Interface, j int) {
}
}
-func down(h Interface, i, n int) {
+func down(h Interface, i0, n int) bool {
+ i := i0
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
@@ -114,4 +116,5 @@ func down(h Interface, i, n int) {
h.Swap(i, j)
i = j
}
+ return i > i0
}
diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go
index b3d054c5f3..d41110422e 100644
--- a/libgo/go/container/heap/heap_test.go
+++ b/libgo/go/container/heap/heap_test.go
@@ -173,7 +173,7 @@ func TestRemove2(t *testing.T) {
func BenchmarkDup(b *testing.B) {
const n = 10000
- h := make(myHeap, n)
+ h := make(myHeap, 0, n)
for i := 0; i < b.N; i++ {
for j := 0; j < n; j++ {
Push(&h, 0) // all elements are the same
diff --git a/libgo/go/container/list/list_test.go b/libgo/go/container/list/list_test.go
index 4d8bfc2bf0..99e006f39f 100755
--- a/libgo/go/container/list/list_test.go
+++ b/libgo/go/container/list/list_test.go
@@ -271,7 +271,7 @@ func TestMove(t *testing.T) {
l.MoveBefore(e2, e4)
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
- e1, e2, e3, e4 = e1, e3, e2, e4
+ e2, e3 = e3, e2
l.MoveBefore(e4, e1)
checkListPointers(t, l, []*Element{e4, e1, e2, e3})
@@ -279,11 +279,11 @@ func TestMove(t *testing.T) {
l.MoveAfter(e4, e1)
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
- e1, e2, e3, e4 = e1, e4, e2, e3
+ e2, e3, e4 = e4, e2, e3
l.MoveAfter(e2, e3)
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
- e1, e2, e3, e4 = e1, e3, e2, e4
+ e2, e3 = e3, e2
}
// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
@@ -326,7 +326,7 @@ func TestInsertAfterUnknownMark(t *testing.T) {
}
// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
-func TestMoveUnkownMark(t *testing.T) {
+func TestMoveUnknownMark(t *testing.T) {
var l1 List
e1 := l1.PushBack(1)
diff --git a/libgo/go/context/benchmark_test.go b/libgo/go/context/benchmark_test.go
new file mode 100644
index 0000000000..b79232704e
--- /dev/null
+++ b/libgo/go/context/benchmark_test.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ . "context"
+ "fmt"
+ "testing"
+)
+
+func BenchmarkContextCancelTree(b *testing.B) {
+ depths := []int{1, 10, 100, 1000}
+ for _, d := range depths {
+ b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) {
+ b.Run("Root=Background", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ buildContextTree(Background(), d)
+ }
+ })
+ b.Run("Root=OpenCanceler", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ctx, cancel := WithCancel(Background())
+ buildContextTree(ctx, d)
+ cancel()
+ }
+ })
+ b.Run("Root=ClosedCanceler", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ctx, cancel := WithCancel(Background())
+ cancel()
+ buildContextTree(ctx, d)
+ }
+ })
+ })
+ }
+}
+
+func buildContextTree(root Context, depth int) {
+ for d := 0; d < depth; d++ {
+ root, _ = WithCancel(root)
+ }
+}
diff --git a/libgo/go/context/context.go b/libgo/go/context/context.go
new file mode 100644
index 0000000000..0aa7c24df9
--- /dev/null
+++ b/libgo/go/context/context.go
@@ -0,0 +1,479 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package context defines the Context type, which carries deadlines,
+// cancelation signals, and other request-scoped values across API boundaries
+// and between processes.
+//
+// Incoming requests to a server should create a Context, and outgoing
+// calls to servers should accept a Context. The chain of function
+// calls between them must propagate the Context, optionally replacing
+// it with a derived Context created using WithCancel, WithDeadline,
+// WithTimeout, or WithValue. When a Context is canceled, all
+// Contexts derived from it are also canceled.
+//
+// The WithCancel, WithDeadline, and WithTimeout functions take a
+// Context (the parent) and return a derived Context (the child) and a
+// CancelFunc. Calling the CancelFunc cancels the child and its
+// children, removes the parent's reference to the child, and stops
+// any associated timers. Failing to call the CancelFunc leaks the
+// child and its children until the parent is canceled or the timer
+// fires. The go vet tool checks that CancelFuncs are used on all
+// control-flow paths.
+//
+// Programs that use Contexts should follow these rules to keep interfaces
+// consistent across packages and enable static analysis tools to check context
+// propagation:
+//
+// Do not store Contexts inside a struct type; instead, pass a Context
+// explicitly to each function that needs it. The Context should be the first
+// parameter, typically named ctx:
+//
+// func DoSomething(ctx context.Context, arg Arg) error {
+// // ... use ctx ...
+// }
+//
+// Do not pass a nil Context, even if a function permits it. Pass context.TODO
+// if you are unsure about which Context to use.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The same Context may be passed to functions running in different goroutines;
+// Contexts are safe for simultaneous use by multiple goroutines.
+//
+// See https://blog.golang.org/context for example code for a server that uses
+// Contexts.
+package context
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "sync"
+ "time"
+)
+
+// A Context carries a deadline, a cancelation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context interface {
+ // Deadline returns the time when work done on behalf of this context
+ // should be canceled. Deadline returns ok==false when no deadline is
+ // set. Successive calls to Deadline return the same results.
+ Deadline() (deadline time.Time, ok bool)
+
+ // Done returns a channel that's closed when work done on behalf of this
+ // context should be canceled. Done may return nil if this context can
+ // never be canceled. Successive calls to Done return the same value.
+ //
+ // WithCancel arranges for Done to be closed when cancel is called;
+ // WithDeadline arranges for Done to be closed when the deadline
+ // expires; WithTimeout arranges for Done to be closed when the timeout
+ // elapses.
+ //
+ // Done is provided for use in select statements:
+ //
+ // // Stream generates values with DoSomething and sends them to out
+ // // until DoSomething returns an error or ctx.Done is closed.
+ // func Stream(ctx context.Context, out chan<- Value) error {
+ // for {
+ // v, err := DoSomething(ctx)
+ // if err != nil {
+ // return err
+ // }
+ // select {
+ // case <-ctx.Done():
+ // return ctx.Err()
+ // case out <- v:
+ // }
+ // }
+ // }
+ //
+ // See https://blog.golang.org/pipelines for more examples of how to use
+ // a Done channel for cancelation.
+ Done() <-chan struct{}
+
+ // Err returns a non-nil error value after Done is closed. Err returns
+ // Canceled if the context was canceled or DeadlineExceeded if the
+ // context's deadline passed. No other values for Err are defined.
+ // After Done is closed, successive calls to Err return the same value.
+ Err() error
+
+ // Value returns the value associated with this context for key, or nil
+ // if no value is associated with key. Successive calls to Value with
+ // the same key returns the same result.
+ //
+ // Use context values only for request-scoped data that transits
+ // processes and API boundaries, not for passing optional parameters to
+ // functions.
+ //
+ // A key identifies a specific value in a Context. Functions that wish
+ // to store values in Context typically allocate a key in a global
+ // variable then use that key as the argument to context.WithValue and
+ // Context.Value. A key can be any type that supports equality;
+ // packages should define keys as an unexported type to avoid
+ // collisions.
+ //
+ // Packages that define a Context key should provide type-safe accessors
+ // for the values stored using that key:
+ //
+ // // Package user defines a User type that's stored in Contexts.
+ // package user
+ //
+ // import "context"
+ //
+ // // User is the type of value stored in the Contexts.
+ // type User struct {...}
+ //
+ // // key is an unexported type for keys defined in this package.
+ // // This prevents collisions with keys defined in other packages.
+ // type key int
+ //
+ // // userKey is the key for user.User values in Contexts. It is
+ // // unexported; clients use user.NewContext and user.FromContext
+ // // instead of using this key directly.
+ // var userKey key = 0
+ //
+ // // NewContext returns a new Context that carries value u.
+ // func NewContext(ctx context.Context, u *User) context.Context {
+ // return context.WithValue(ctx, userKey, u)
+ // }
+ //
+ // // FromContext returns the User value stored in ctx, if any.
+ // func FromContext(ctx context.Context) (*User, bool) {
+ // u, ok := ctx.Value(userKey).(*User)
+ // return u, ok
+ // }
+ Value(key interface{}) interface{}
+}
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = errors.New("context canceled")
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded error = deadlineExceededError{}
+
+type deadlineExceededError struct{}
+
+func (deadlineExceededError) Error() string { return "context deadline exceeded" }
+func (deadlineExceededError) Timeout() bool { return true }
+func (deadlineExceededError) Temporary() 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.
+type emptyCtx int
+
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+ return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+ return nil
+}
+
+func (*emptyCtx) Err() error {
+ return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+ return nil
+}
+
+func (e *emptyCtx) String() string {
+ switch e {
+ case background:
+ return "context.Background"
+ case todo:
+ return "context.TODO"
+ }
+ return "unknown empty Context"
+}
+
+var (
+ background = new(emptyCtx)
+ todo = new(emptyCtx)
+)
+
+// Background returns a non-nil, empty Context. It is never canceled, has no
+// values, and has no deadline. It is typically used by the main function,
+// initialization, and tests, and as the top-level Context for incoming
+// requests.
+func Background() Context {
+ return background
+}
+
+// TODO returns a non-nil, empty Context. Code should use context.TODO when
+// it's unclear which Context to use or it is not yet available (because the
+// surrounding function has not yet been extended to accept a Context
+// parameter). TODO is recognized by static analysis tools that determine
+// whether Contexts are propagated correctly in a program.
+func TODO() Context {
+ return todo
+}
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc func()
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+ c := newCancelCtx(parent)
+ propagateCancel(parent, &c)
+ return &c, func() { c.cancel(true, Canceled) }
+}
+
+// newCancelCtx returns an initialized cancelCtx.
+func newCancelCtx(parent Context) cancelCtx {
+ return cancelCtx{
+ Context: parent,
+ done: make(chan struct{}),
+ }
+}
+
+// propagateCancel arranges for child to be canceled when parent is.
+func propagateCancel(parent Context, child canceler) {
+ if parent.Done() == nil {
+ return // parent is never canceled
+ }
+ if p, ok := parentCancelCtx(parent); ok {
+ p.mu.Lock()
+ if p.err != nil {
+ // parent has already been canceled
+ child.cancel(false, p.err)
+ } else {
+ if p.children == nil {
+ p.children = make(map[canceler]struct{})
+ }
+ p.children[child] = struct{}{}
+ }
+ p.mu.Unlock()
+ } else {
+ go func() {
+ select {
+ case <-parent.Done():
+ child.cancel(false, parent.Err())
+ case <-child.Done():
+ }
+ }()
+ }
+}
+
+// parentCancelCtx follows a chain of parent references until it finds a
+// *cancelCtx. This function understands how each of the concrete types in this
+// package represents its parent.
+func parentCancelCtx(parent Context) (*cancelCtx, bool) {
+ for {
+ switch c := parent.(type) {
+ case *cancelCtx:
+ return c, true
+ case *timerCtx:
+ return &c.cancelCtx, true
+ case *valueCtx:
+ parent = c.Context
+ default:
+ return nil, false
+ }
+ }
+}
+
+// removeChild removes a context from its parent.
+func removeChild(parent Context, child canceler) {
+ p, ok := parentCancelCtx(parent)
+ if !ok {
+ return
+ }
+ p.mu.Lock()
+ if p.children != nil {
+ delete(p.children, child)
+ }
+ p.mu.Unlock()
+}
+
+// A canceler is a context type that can be canceled directly. The
+// implementations are *cancelCtx and *timerCtx.
+type canceler interface {
+ cancel(removeFromParent bool, err error)
+ Done() <-chan struct{}
+}
+
+// A cancelCtx can be canceled. When canceled, it also cancels any children
+// that implement canceler.
+type cancelCtx struct {
+ Context
+
+ done chan struct{} // closed by the first cancel call.
+
+ mu sync.Mutex
+ children map[canceler]struct{} // set to nil by the first cancel call
+ err error // set to non-nil by the first cancel call
+}
+
+func (c *cancelCtx) Done() <-chan struct{} {
+ return c.done
+}
+
+func (c *cancelCtx) Err() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.err
+}
+
+func (c *cancelCtx) String() string {
+ return fmt.Sprintf("%v.WithCancel", c.Context)
+}
+
+// cancel closes c.done, cancels each of c's children, and, if
+// removeFromParent is true, removes c from its parent's children.
+func (c *cancelCtx) cancel(removeFromParent bool, err error) {
+ if err == nil {
+ panic("context: internal error: missing cancel error")
+ }
+ c.mu.Lock()
+ if c.err != nil {
+ c.mu.Unlock()
+ return // already canceled
+ }
+ c.err = err
+ close(c.done)
+ for child := range c.children {
+ // NOTE: acquiring the child's lock while holding parent's lock.
+ child.cancel(false, err)
+ }
+ c.children = nil
+ c.mu.Unlock()
+
+ if removeFromParent {
+ removeChild(c.Context, c)
+ }
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+ if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
+ // The current deadline is already sooner than the new one.
+ return WithCancel(parent)
+ }
+ c := &timerCtx{
+ cancelCtx: newCancelCtx(parent),
+ deadline: deadline,
+ }
+ propagateCancel(parent, c)
+ d := time.Until(deadline)
+ if d <= 0 {
+ c.cancel(true, DeadlineExceeded) // deadline has already passed
+ return c, func() { c.cancel(true, Canceled) }
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.err == nil {
+ c.timer = time.AfterFunc(d, func() {
+ c.cancel(true, DeadlineExceeded)
+ })
+ }
+ return c, func() { c.cancel(true, Canceled) }
+}
+
+// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
+// implement Done and Err. It implements cancel by stopping its timer then
+// delegating to cancelCtx.cancel.
+type timerCtx struct {
+ cancelCtx
+ timer *time.Timer // Under cancelCtx.mu.
+
+ deadline time.Time
+}
+
+func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
+ return c.deadline, true
+}
+
+func (c *timerCtx) String() string {
+ return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, time.Until(c.deadline))
+}
+
+func (c *timerCtx) cancel(removeFromParent bool, err error) {
+ c.cancelCtx.cancel(false, err)
+ if removeFromParent {
+ // Remove this timerCtx from its parent cancelCtx's children.
+ removeChild(c.cancelCtx.Context, c)
+ }
+ c.mu.Lock()
+ if c.timer != nil {
+ c.timer.Stop()
+ c.timer = nil
+ }
+ c.mu.Unlock()
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// defer cancel() // releases resources if slowOperation completes before timeout elapses
+// return slowOperation(ctx)
+// }
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+ return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The provided key must be comparable and should not be of type
+// string or any other built-in type to avoid collisions between
+// packages using context. Users of WithValue should define their own
+// types for keys. To avoid allocating when assigning to an
+// interface{}, context keys often have concrete type
+// struct{}. Alternatively, exported context key variables' static
+// type should be a pointer or interface.
+func WithValue(parent Context, key, val interface{}) Context {
+ if key == nil {
+ panic("nil key")
+ }
+ if !reflect.TypeOf(key).Comparable() {
+ panic("key is not comparable")
+ }
+ return &valueCtx{parent, key, val}
+}
+
+// A valueCtx carries a key-value pair. It implements Value for that key and
+// delegates all other calls to the embedded Context.
+type valueCtx struct {
+ Context
+ key, val interface{}
+}
+
+func (c *valueCtx) String() string {
+ return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
+}
+
+func (c *valueCtx) Value(key interface{}) interface{} {
+ if c.key == key {
+ return c.val
+ }
+ return c.Context.Value(key)
+}
diff --git a/libgo/go/context/context_test.go b/libgo/go/context/context_test.go
new file mode 100644
index 0000000000..b5e599fe82
--- /dev/null
+++ b/libgo/go/context/context_test.go
@@ -0,0 +1,650 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context
+
+import (
+ "fmt"
+ "math/rand"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+)
+
+type testingT interface {
+ Error(args ...interface{})
+ Errorf(format string, args ...interface{})
+ Fail()
+ FailNow()
+ Failed() bool
+ Fatal(args ...interface{})
+ Fatalf(format string, args ...interface{})
+ Log(args ...interface{})
+ Logf(format string, args ...interface{})
+ Name() string
+ Skip(args ...interface{})
+ SkipNow()
+ Skipf(format string, args ...interface{})
+ Skipped() bool
+}
+
+// otherContext is a Context that's not one of the types defined in context.go.
+// This lets us test code paths that differ based on the underlying type of the
+// Context.
+type otherContext struct {
+ Context
+}
+
+func XTestBackground(t testingT) {
+ c := Background()
+ if c == nil {
+ t.Fatalf("Background returned nil")
+ }
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if got, want := fmt.Sprint(c), "context.Background"; got != want {
+ t.Errorf("Background().String() = %q want %q", got, want)
+ }
+}
+
+func XTestTODO(t testingT) {
+ c := TODO()
+ if c == nil {
+ t.Fatalf("TODO returned nil")
+ }
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if got, want := fmt.Sprint(c), "context.TODO"; got != want {
+ t.Errorf("TODO().String() = %q want %q", got, want)
+ }
+}
+
+func XTestWithCancel(t testingT) {
+ c1, cancel := WithCancel(Background())
+
+ if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
+ t.Errorf("c1.String() = %q want %q", got, want)
+ }
+
+ o := otherContext{c1}
+ c2, _ := WithCancel(o)
+ contexts := []Context{c1, o, c2}
+
+ for i, c := range contexts {
+ if d := c.Done(); d == nil {
+ t.Errorf("c[%d].Done() == %v want non-nil", i, d)
+ }
+ if e := c.Err(); e != nil {
+ t.Errorf("c[%d].Err() == %v want nil", i, e)
+ }
+
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ }
+
+ cancel()
+ time.Sleep(100 * time.Millisecond) // let cancelation propagate
+
+ for i, c := range contexts {
+ select {
+ case <-c.Done():
+ default:
+ t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
+ }
+ if e := c.Err(); e != Canceled {
+ t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
+ }
+ }
+}
+
+func contains(m map[canceler]struct{}, key canceler) bool {
+ _, ret := m[key]
+ return ret
+}
+
+func XTestParentFinishesChild(t testingT) {
+ // Context tree:
+ // parent -> cancelChild
+ // parent -> valueChild -> timerChild
+ parent, cancel := WithCancel(Background())
+ cancelChild, stop := WithCancel(parent)
+ defer stop()
+ valueChild := WithValue(parent, "key", "value")
+ timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
+ defer stop()
+
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ case x := <-cancelChild.Done():
+ t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
+ case x := <-timerChild.Done():
+ t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
+ case x := <-valueChild.Done():
+ t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+
+ // The parent's children should contain the two cancelable children.
+ pc := parent.(*cancelCtx)
+ cc := cancelChild.(*cancelCtx)
+ tc := timerChild.(*timerCtx)
+ pc.mu.Lock()
+ if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
+ t.Errorf("bad linkage: pc.children = %v, want %v and %v",
+ pc.children, cc, tc)
+ }
+ pc.mu.Unlock()
+
+ if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
+ t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
+ }
+ if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
+ t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
+ }
+
+ cancel()
+
+ pc.mu.Lock()
+ if len(pc.children) != 0 {
+ t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
+ }
+ pc.mu.Unlock()
+
+ // parent and children should all be finished.
+ check := func(ctx Context, name string) {
+ select {
+ case <-ctx.Done():
+ default:
+ t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
+ }
+ if e := ctx.Err(); e != Canceled {
+ t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
+ }
+ }
+ check(parent, "parent")
+ check(cancelChild, "cancelChild")
+ check(valueChild, "valueChild")
+ check(timerChild, "timerChild")
+
+ // WithCancel should return a canceled context on a canceled parent.
+ precanceledChild := WithValue(parent, "key", "value")
+ select {
+ case <-precanceledChild.Done():
+ default:
+ t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
+ }
+ if e := precanceledChild.Err(); e != Canceled {
+ t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
+ }
+}
+
+func XTestChildFinishesFirst(t testingT) {
+ cancelable, stop := WithCancel(Background())
+ defer stop()
+ for _, parent := range []Context{Background(), cancelable} {
+ child, cancel := WithCancel(parent)
+
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ case x := <-child.Done():
+ t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+
+ cc := child.(*cancelCtx)
+ pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
+ if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
+ t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
+ }
+
+ if pcok {
+ pc.mu.Lock()
+ if len(pc.children) != 1 || !contains(pc.children, cc) {
+ t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
+ }
+ pc.mu.Unlock()
+ }
+
+ cancel()
+
+ if pcok {
+ pc.mu.Lock()
+ if len(pc.children) != 0 {
+ t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
+ }
+ pc.mu.Unlock()
+ }
+
+ // child should be finished.
+ select {
+ case <-child.Done():
+ default:
+ t.Errorf("<-child.Done() blocked, but shouldn't have")
+ }
+ if e := child.Err(); e != Canceled {
+ t.Errorf("child.Err() == %v want %v", e, Canceled)
+ }
+
+ // parent should not be finished.
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if e := parent.Err(); e != nil {
+ t.Errorf("parent.Err() == %v want nil", e)
+ }
+ }
+}
+
+func testDeadline(c Context, name string, failAfter time.Duration, t testingT) {
+ select {
+ case <-time.After(failAfter):
+ t.Fatalf("%s: context should have timed out", name)
+ case <-c.Done():
+ }
+ if e := c.Err(); e != DeadlineExceeded {
+ t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
+ }
+}
+
+func XTestDeadline(t testingT) {
+ c, _ := WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+ if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+ t.Errorf("c.String() = %q want prefix %q", got, prefix)
+ }
+ testDeadline(c, "WithDeadline", time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+ o := otherContext{c}
+ testDeadline(o, "WithDeadline+otherContext", time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+ o = otherContext{c}
+ c, _ = WithDeadline(o, time.Now().Add(4*time.Second))
+ testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(-time.Millisecond))
+ testDeadline(c, "WithDeadline+inthepast", time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now())
+ testDeadline(c, "WithDeadline+now", time.Second, t)
+}
+
+func XTestTimeout(t testingT) {
+ c, _ := WithTimeout(Background(), 50*time.Millisecond)
+ if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+ t.Errorf("c.String() = %q want prefix %q", got, prefix)
+ }
+ testDeadline(c, "WithTimeout", time.Second, t)
+
+ c, _ = WithTimeout(Background(), 50*time.Millisecond)
+ o := otherContext{c}
+ testDeadline(o, "WithTimeout+otherContext", time.Second, t)
+
+ c, _ = WithTimeout(Background(), 50*time.Millisecond)
+ o = otherContext{c}
+ c, _ = WithTimeout(o, 3*time.Second)
+ testDeadline(c, "WithTimeout+otherContext+WithTimeout", 2*time.Second, t)
+}
+
+func XTestCanceledTimeout(t testingT) {
+ c, _ := WithTimeout(Background(), time.Second)
+ o := otherContext{c}
+ c, cancel := WithTimeout(o, 2*time.Second)
+ cancel()
+ time.Sleep(100 * time.Millisecond) // let cancelation propagate
+ select {
+ case <-c.Done():
+ default:
+ t.Errorf("<-c.Done() blocked, but shouldn't have")
+ }
+ if e := c.Err(); e != Canceled {
+ t.Errorf("c.Err() == %v want %v", e, Canceled)
+ }
+}
+
+type key1 int
+type key2 int
+
+var k1 = key1(1)
+var k2 = key2(1) // same int as k1, different type
+var k3 = key2(3) // same type as k2, different int
+
+func XTestValues(t testingT) {
+ check := func(c Context, nm, v1, v2, v3 string) {
+ if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
+ t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
+ }
+ if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
+ t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
+ }
+ if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
+ t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
+ }
+ }
+
+ c0 := Background()
+ check(c0, "c0", "", "", "")
+
+ c1 := WithValue(Background(), k1, "c1k1")
+ check(c1, "c1", "c1k1", "", "")
+
+ if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
+ t.Errorf("c.String() = %q want %q", got, want)
+ }
+
+ c2 := WithValue(c1, k2, "c2k2")
+ check(c2, "c2", "c1k1", "c2k2", "")
+
+ c3 := WithValue(c2, k3, "c3k3")
+ check(c3, "c2", "c1k1", "c2k2", "c3k3")
+
+ c4 := WithValue(c3, k1, nil)
+ check(c4, "c4", "", "c2k2", "c3k3")
+
+ o0 := otherContext{Background()}
+ check(o0, "o0", "", "", "")
+
+ o1 := otherContext{WithValue(Background(), k1, "c1k1")}
+ check(o1, "o1", "c1k1", "", "")
+
+ o2 := WithValue(o1, k2, "o2k2")
+ check(o2, "o2", "c1k1", "o2k2", "")
+
+ o3 := otherContext{c4}
+ check(o3, "o3", "", "c2k2", "c3k3")
+
+ o4 := WithValue(o3, k3, nil)
+ check(o4, "o4", "", "c2k2", "")
+}
+
+func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {
+ bg := Background()
+ for _, test := range []struct {
+ desc string
+ f func()
+ limit float64
+ gccgoLimit float64
+ }{
+ {
+ desc: "Background()",
+ f: func() { Background() },
+ limit: 0,
+ gccgoLimit: 0,
+ },
+ {
+ desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
+ f: func() {
+ c := WithValue(bg, k1, nil)
+ c.Value(k1)
+ },
+ limit: 3,
+ gccgoLimit: 3,
+ },
+ {
+ desc: "WithTimeout(bg, 15*time.Millisecond)",
+ f: func() {
+ c, _ := WithTimeout(bg, 15*time.Millisecond)
+ <-c.Done()
+ },
+ limit: 8,
+ gccgoLimit: 18,
+ },
+ {
+ desc: "WithCancel(bg)",
+ f: func() {
+ c, cancel := WithCancel(bg)
+ cancel()
+ <-c.Done()
+ },
+ limit: 5,
+ gccgoLimit: 8,
+ },
+ {
+ desc: "WithTimeout(bg, 5*time.Millisecond)",
+ f: func() {
+ c, cancel := WithTimeout(bg, 5*time.Millisecond)
+ cancel()
+ <-c.Done()
+ },
+ limit: 8,
+ gccgoLimit: 25,
+ },
+ } {
+ limit := test.limit
+ if runtime.Compiler == "gccgo" {
+ // gccgo does not yet do escape analysis.
+ // TOOD(iant): Remove this when gccgo does do escape analysis.
+ limit = test.gccgoLimit
+ }
+ numRuns := 100
+ if testingShort() {
+ numRuns = 10
+ }
+ if n := testingAllocsPerRun(numRuns, test.f); n > limit {
+ t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
+ }
+ }
+}
+
+func XTestSimultaneousCancels(t testingT) {
+ root, cancel := WithCancel(Background())
+ m := map[Context]CancelFunc{root: cancel}
+ q := []Context{root}
+ // Create a tree of contexts.
+ for len(q) != 0 && len(m) < 100 {
+ parent := q[0]
+ q = q[1:]
+ for i := 0; i < 4; i++ {
+ ctx, cancel := WithCancel(parent)
+ m[ctx] = cancel
+ q = append(q, ctx)
+ }
+ }
+ // Start all the cancels in a random order.
+ var wg sync.WaitGroup
+ wg.Add(len(m))
+ for _, cancel := range m {
+ go func(cancel CancelFunc) {
+ cancel()
+ wg.Done()
+ }(cancel)
+ }
+ // Wait on all the contexts in a random order.
+ for ctx := range m {
+ select {
+ case <-ctx.Done():
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
+ }
+ }
+ // Wait for all the cancel functions to return.
+ done := make(chan struct{})
+ go func() {
+ wg.Wait()
+ close(done)
+ }()
+ select {
+ case <-done:
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
+ }
+}
+
+func XTestInterlockedCancels(t testingT) {
+ parent, cancelParent := WithCancel(Background())
+ child, cancelChild := WithCancel(parent)
+ go func() {
+ parent.Done()
+ cancelChild()
+ }()
+ cancelParent()
+ select {
+ case <-child.Done():
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
+ }
+}
+
+func XTestLayersCancel(t testingT) {
+ testLayers(t, time.Now().UnixNano(), false)
+}
+
+func XTestLayersTimeout(t testingT) {
+ testLayers(t, time.Now().UnixNano(), true)
+}
+
+func testLayers(t testingT, seed int64, testTimeout bool) {
+ rand.Seed(seed)
+ errorf := func(format string, a ...interface{}) {
+ t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
+ }
+ const (
+ timeout = 200 * time.Millisecond
+ minLayers = 30
+ )
+ type value int
+ var (
+ vals []*value
+ cancels []CancelFunc
+ numTimers int
+ ctx = Background()
+ )
+ for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
+ switch rand.Intn(3) {
+ case 0:
+ v := new(value)
+ ctx = WithValue(ctx, v, v)
+ vals = append(vals, v)
+ case 1:
+ var cancel CancelFunc
+ ctx, cancel = WithCancel(ctx)
+ cancels = append(cancels, cancel)
+ case 2:
+ var cancel CancelFunc
+ ctx, cancel = WithTimeout(ctx, timeout)
+ cancels = append(cancels, cancel)
+ numTimers++
+ }
+ }
+ checkValues := func(when string) {
+ for _, key := range vals {
+ if val := ctx.Value(key).(*value); key != val {
+ errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
+ }
+ }
+ }
+ select {
+ case <-ctx.Done():
+ errorf("ctx should not be canceled yet")
+ default:
+ }
+ if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
+ t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
+ }
+ t.Log(ctx)
+ checkValues("before cancel")
+ if testTimeout {
+ select {
+ case <-ctx.Done():
+ case <-time.After(timeout + time.Second):
+ errorf("ctx should have timed out")
+ }
+ checkValues("after timeout")
+ } else {
+ cancel := cancels[rand.Intn(len(cancels))]
+ cancel()
+ select {
+ case <-ctx.Done():
+ default:
+ errorf("ctx should be canceled")
+ }
+ checkValues("after cancel")
+ }
+}
+
+func XTestCancelRemoves(t testingT) {
+ checkChildren := func(when string, ctx Context, want int) {
+ if got := len(ctx.(*cancelCtx).children); got != want {
+ t.Errorf("%s: context has %d children, want %d", when, got, want)
+ }
+ }
+
+ ctx, _ := WithCancel(Background())
+ checkChildren("after creation", ctx, 0)
+ _, cancel := WithCancel(ctx)
+ checkChildren("with WithCancel child ", ctx, 1)
+ cancel()
+ checkChildren("after canceling WithCancel child", ctx, 0)
+
+ ctx, _ = WithCancel(Background())
+ checkChildren("after creation", ctx, 0)
+ _, cancel = WithTimeout(ctx, 60*time.Minute)
+ checkChildren("with WithTimeout child ", ctx, 1)
+ cancel()
+ checkChildren("after canceling WithTimeout child", ctx, 0)
+}
+
+func XTestWithCancelCanceledParent(t testingT) {
+ parent, pcancel := WithCancel(Background())
+ pcancel()
+
+ c, _ := WithCancel(parent)
+ select {
+ case <-c.Done():
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for Done")
+ }
+ if got, want := c.Err(), Canceled; got != want {
+ t.Errorf("child not cancelled; got = %v, want = %v", got, want)
+ }
+}
+
+func XTestWithValueChecksKey(t testingT) {
+ panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
+ if panicVal == nil {
+ t.Error("expected panic")
+ }
+ panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
+ if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
+ t.Errorf("panic = %q; want %q", got, want)
+ }
+}
+
+func recoveredValue(fn func()) (v interface{}) {
+ defer func() { v = recover() }()
+ fn()
+ return
+}
+
+func XTestDeadlineExceededSupportsTimeout(t testingT) {
+ 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")
+ }
+}
diff --git a/libgo/go/context/example_test.go b/libgo/go/context/example_test.go
new file mode 100644
index 0000000000..2d48d4e82b
--- /dev/null
+++ b/libgo/go/context/example_test.go
@@ -0,0 +1,116 @@
+// 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 context_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+)
+
+// This example demonstrates the use of a cancelable context to prevent a
+// goroutine leak. By the end of the example function, the goroutine started
+// by gen will return without leaking.
+func ExampleWithCancel() {
+ // gen generates integers in a separate goroutine and
+ // sends them to the returned channel.
+ // The callers of gen need to cancel the context once
+ // they are done consuming generated integers not to leak
+ // the internal goroutine started by gen.
+ gen := func(ctx context.Context) <-chan int {
+ dst := make(chan int)
+ n := 1
+ go func() {
+ for {
+ select {
+ case <-ctx.Done():
+ return // returning not to leak the goroutine
+ case dst <- n:
+ n++
+ }
+ }
+ }()
+ return dst
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel() // cancel when we are finished consuming integers
+
+ for n := range gen(ctx) {
+ fmt.Println(n)
+ if n == 5 {
+ break
+ }
+ }
+ // Output:
+ // 1
+ // 2
+ // 3
+ // 4
+ // 5
+}
+
+// This example passes a context with a arbitrary deadline to tell a blocking
+// function that it should abandon its work as soon as it gets to it.
+func ExampleWithDeadline() {
+ d := time.Now().Add(50 * time.Millisecond)
+ ctx, cancel := context.WithDeadline(context.Background(), d)
+
+ // Even though ctx will be expired, it is good practice to call its
+ // cancelation function in any case. Failure to do so may keep the
+ // context and its parent alive longer than necessary.
+ defer cancel()
+
+ select {
+ case <-time.After(1 * time.Second):
+ fmt.Println("overslept")
+ case <-ctx.Done():
+ fmt.Println(ctx.Err())
+ }
+
+ // Output:
+ // context deadline exceeded
+}
+
+// This example passes a context with a timeout to tell a blocking function that
+// it should abandon its work after the timeout elapses.
+func ExampleWithTimeout() {
+ // Pass a context with a timeout to tell a blocking function that it
+ // should abandon its work after the timeout elapses.
+ ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
+ defer cancel()
+
+ select {
+ case <-time.After(1 * time.Second):
+ fmt.Println("overslept")
+ case <-ctx.Done():
+ fmt.Println(ctx.Err()) // prints "context deadline exceeded"
+ }
+
+ // Output:
+ // context deadline exceeded
+}
+
+func ExampleWithValue() {
+ type favContextKey string
+
+ f := func(ctx context.Context, k favContextKey) {
+ if v := ctx.Value(k); v != nil {
+ fmt.Println("found value:", v)
+ return
+ }
+ fmt.Println("key not found:", k)
+ }
+
+ k := favContextKey("language")
+ ctx := context.WithValue(context.Background(), k, "Go")
+
+ f(ctx, k)
+ f(ctx, favContextKey("color"))
+
+ // Output:
+ // found value: Go
+ // key not found: color
+}
diff --git a/libgo/go/context/net_test.go b/libgo/go/context/net_test.go
new file mode 100644
index 0000000000..a007689d36
--- /dev/null
+++ b/libgo/go/context/net_test.go
@@ -0,0 +1,21 @@
+// 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 context_test
+
+import (
+ "context"
+ "net"
+ "testing"
+)
+
+func TestDeadlineExceededIsNetError(t *testing.T) {
+ err, ok := context.DeadlineExceeded.(net.Error)
+ if !ok {
+ t.Fatal("DeadlineExceeded does not implement net.Error")
+ }
+ if !err.Timeout() || !err.Temporary() {
+ t.Fatalf("Timeout() = %v, Temporary() = %v, want true, true", err.Timeout(), err.Temporary())
+ }
+}
diff --git a/libgo/go/context/x_test.go b/libgo/go/context/x_test.go
new file mode 100644
index 0000000000..d14b6f1a32
--- /dev/null
+++ b/libgo/go/context/x_test.go
@@ -0,0 +1,29 @@
+// 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 context_test
+
+import (
+ . "context"
+ "testing"
+)
+
+func TestBackground(t *testing.T) { XTestBackground(t) }
+func TestTODO(t *testing.T) { XTestTODO(t) }
+func TestWithCancel(t *testing.T) { XTestWithCancel(t) }
+func TestParentFinishesChild(t *testing.T) { XTestParentFinishesChild(t) }
+func TestChildFinishesFirst(t *testing.T) { XTestChildFinishesFirst(t) }
+func TestDeadline(t *testing.T) { XTestDeadline(t) }
+func TestTimeout(t *testing.T) { XTestTimeout(t) }
+func TestCanceledTimeout(t *testing.T) { XTestCanceledTimeout(t) }
+func TestValues(t *testing.T) { XTestValues(t) }
+func TestAllocs(t *testing.T) { XTestAllocs(t, testing.Short, testing.AllocsPerRun) }
+func TestSimultaneousCancels(t *testing.T) { XTestSimultaneousCancels(t) }
+func TestInterlockedCancels(t *testing.T) { XTestInterlockedCancels(t) }
+func TestLayersCancel(t *testing.T) { XTestLayersCancel(t) }
+func TestLayersTimeout(t *testing.T) { XTestLayersTimeout(t) }
+func TestCancelRemoves(t *testing.T) { XTestCancelRemoves(t) }
+func TestWithCancelCanceledParent(t *testing.T) { XTestWithCancelCanceledParent(t) }
+func TestWithValueChecksKey(t *testing.T) { XTestWithValueChecksKey(t) }
+func TestDeadlineExceededSupportsTimeout(t *testing.T) { XTestDeadlineExceededSupportsTimeout(t) }
diff --git a/libgo/go/crypto/aes/aes_gcm.go b/libgo/go/crypto/aes/aes_gcm.go
index 1377578950..3e5e2359d8 100644
--- a/libgo/go/crypto/aes/aes_gcm.go
+++ b/libgo/go/crypto/aes/aes_gcm.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64
+// +build ignore
+// -build amd64
package aes
@@ -45,9 +46,12 @@ var errOpen = errors.New("cipher: message authentication failed")
// will use the optimised implementation in this file when possible. Instances
// of this type only exist when hasGCMAsm returns true.
type aesCipherGCM struct {
- aesCipher
+ aesCipherAsm
}
+// Assert that aesCipherGCM implements the gcmAble interface.
+var _ gcmAble = (*aesCipherGCM)(nil)
+
// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
// called by crypto/cipher.NewGCM via the gcmAble interface.
func (c *aesCipherGCM) NewGCM(nonceSize int) (cipher.AEAD, error) {
@@ -96,6 +100,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
panic("cipher: incorrect nonce length given to GCM")
}
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("cipher: message too large for GCM")
+ }
var counter, tagMask [gcmBlockSize]byte
@@ -134,6 +141,10 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(ciphertext) < gcmTagSize {
return nil, errOpen
}
+ if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
tag := ciphertext[len(ciphertext)-gcmTagSize:]
ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go
index 363180931c..28144968fc 100644
--- a/libgo/go/crypto/aes/aes_test.go
+++ b/libgo/go/crypto/aes/aes_test.go
@@ -280,42 +280,6 @@ var encryptTests = []CryptTest{
},
}
-// Test encryptBlock against FIPS 197 examples.
-func TestEncryptBlock(t *testing.T) {
- for i, tt := range encryptTests {
- n := len(tt.key) + 28
- enc := make([]uint32, n)
- dec := make([]uint32, n)
- expandKey(tt.key, enc, dec)
- out := make([]byte, len(tt.in))
- encryptBlock(enc, out, tt.in)
- for j, v := range out {
- if v != tt.out[j] {
- t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
- break
- }
- }
- }
-}
-
-// Test decryptBlock against FIPS 197 examples.
-func TestDecryptBlock(t *testing.T) {
- for i, tt := range encryptTests {
- n := len(tt.key) + 28
- enc := make([]uint32, n)
- dec := make([]uint32, n)
- expandKey(tt.key, enc, dec)
- plain := make([]byte, len(tt.in))
- decryptBlock(dec, plain, tt.out)
- for j, v := range plain {
- if v != tt.in[j] {
- t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
- break
- }
- }
- }
-}
-
// Test Cipher Encrypt method against FIPS 197 examples.
func TestCipherEncrypt(t *testing.T) {
for i, tt := range encryptTests {
diff --git a/libgo/go/crypto/aes/block.go b/libgo/go/crypto/aes/block.go
index 57a7e9e25f..41ea9cf95e 100644
--- a/libgo/go/crypto/aes/block.go
+++ b/libgo/go/crypto/aes/block.go
@@ -137,7 +137,7 @@ func subw(w uint32) uint32 {
// Rotate
func rotw(w uint32) uint32 { return w<<8 | w>>24 }
-// Key expansion algorithm. See FIPS-197, Figure 11.
+// Key expansion algorithm. See FIPS-197, Figure 11.
// Their rcon[i] is our powx[i-1] << 24.
func expandKeyGo(key []byte, enc, dec []uint32) {
// Encryption key setup.
diff --git a/libgo/go/crypto/aes/cbc_s390x.go b/libgo/go/crypto/aes/cbc_s390x.go
new file mode 100644
index 0000000000..6b011b28b5
--- /dev/null
+++ b/libgo/go/crypto/aes/cbc_s390x.go
@@ -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.
+
+// +build ignore
+
+package aes
+
+import (
+ "crypto/cipher"
+)
+
+// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
+var _ cbcEncAble = (*aesCipherAsm)(nil)
+var _ cbcDecAble = (*aesCipherAsm)(nil)
+
+type cbc struct {
+ b *aesCipherAsm
+ c code
+ iv [BlockSize]byte
+}
+
+func (b *aesCipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.c = b.function
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (b *aesCipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.c = b.function + 128 // decrypt function code is encrypt + 128
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (x *cbc) BlockSize() int { return BlockSize }
+
+// cryptBlocksChain invokes the cipher message with chaining (KMC) instruction
+// with the given function code. The length must be a multiple of BlockSize (16).
+//go:noescape
+func cryptBlocksChain(c code, iv, key, dst, src *byte, length int)
+
+func (x *cbc) CryptBlocks(dst, src []byte) {
+ if len(src)%BlockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if len(src) > 0 {
+ cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
+ }
+}
+
+func (x *cbc) SetIV(iv []byte) {
+ if len(iv) != BlockSize {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv[:], iv)
+}
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
index 04d2be1283..c5a8e91d00 100644
--- a/libgo/go/crypto/aes/cipher.go
+++ b/libgo/go/crypto/aes/cipher.go
@@ -36,15 +36,15 @@ func NewCipher(key []byte) (cipher.Block, error) {
case 16, 24, 32:
break
}
+ return newCipher(key)
+}
- n := k + 28
+// newCipherGeneric creates and returns a new cipher.Block
+// implemented in pure Go.
+func newCipherGeneric(key []byte) (cipher.Block, error) {
+ n := len(key) + 28
c := aesCipher{make([]uint32, n), make([]uint32, n)}
- expandKey(key, c.enc, c.dec)
-
- if hasGCMAsm() {
- return &aesCipherGCM{c}, nil
- }
-
+ expandKeyGo(key, c.enc, c.dec)
return &c, nil
}
@@ -57,7 +57,7 @@ func (c *aesCipher) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
- encryptBlock(c.enc, dst, src)
+ encryptBlockGo(c.enc, dst, src)
}
func (c *aesCipher) Decrypt(dst, src []byte) {
@@ -67,5 +67,5 @@ func (c *aesCipher) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
- decryptBlock(c.dec, dst, src)
+ decryptBlockGo(c.dec, dst, src)
}
diff --git a/libgo/go/crypto/aes/cipher_amd64.go b/libgo/go/crypto/aes/cipher_amd64.go
new file mode 100644
index 0000000000..fbd157e49e
--- /dev/null
+++ b/libgo/go/crypto/aes/cipher_amd64.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/cipherhw"
+)
+
+// defined in asm_amd64.s
+func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
+
+type aesCipherAsm struct {
+ aesCipher
+}
+
+var useAsm = cipherhw.AESGCMSupport()
+
+func newCipher(key []byte) (cipher.Block, error) {
+ if !useAsm {
+ return newCipherGeneric(key)
+ }
+ n := len(key) + 28
+ c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
+ rounds := 10
+ switch len(key) {
+ case 128 / 8:
+ rounds = 10
+ case 192 / 8:
+ rounds = 12
+ case 256 / 8:
+ rounds = 14
+ }
+ expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0])
+ if hasGCMAsm() {
+ return &aesCipherGCM{c}, nil
+ }
+
+ return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
+}
+
+// expandKey is used by BenchmarkExpand to ensure that the asm implementation
+// of key expansion is used for the benchmark when it is available.
+func expandKey(key []byte, enc, dec []uint32) {
+ if useAsm {
+ rounds := 10 // rounds needed for AES128
+ switch len(key) {
+ case 192 / 8:
+ rounds = 12
+ case 256 / 8:
+ rounds = 14
+ }
+ expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
+ } else {
+ expandKeyGo(key, enc, dec)
+ }
+}
diff --git a/libgo/go/crypto/aes/cipher_asm.go b/libgo/go/crypto/aes/cipher_asm.go
deleted file mode 100644
index 964eaaa6f8..0000000000
--- a/libgo/go/crypto/aes/cipher_asm.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build amd64
-
-package aes
-
-// defined in asm_$GOARCH.s
-func hasAsm() bool
-func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
-
-var useAsm = hasAsm()
-
-func encryptBlock(xk []uint32, dst, src []byte) {
- if useAsm {
- encryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
- } else {
- encryptBlockGo(xk, dst, src)
- }
-}
-
-func decryptBlock(xk []uint32, dst, src []byte) {
- if useAsm {
- decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
- } else {
- decryptBlockGo(xk, dst, src)
- }
-}
-
-func expandKey(key []byte, enc, dec []uint32) {
- if useAsm {
- rounds := 10
- switch len(key) {
- case 128 / 8:
- rounds = 10
- case 192 / 8:
- rounds = 12
- case 256 / 8:
- rounds = 14
- }
- expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
- } else {
- expandKeyGo(key, enc, dec)
- }
-}
diff --git a/libgo/go/crypto/aes/cipher_generic.go b/libgo/go/crypto/aes/cipher_generic.go
index 32b2b3cc56..2c8d299c88 100644
--- a/libgo/go/crypto/aes/cipher_generic.go
+++ b/libgo/go/crypto/aes/cipher_generic.go
@@ -2,26 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64
+// -build !amd64,!s390x
package aes
-func encryptBlock(xk []uint32, dst, src []byte) {
- encryptBlockGo(xk, dst, src)
-}
+import (
+ "crypto/cipher"
+)
-func decryptBlock(xk []uint32, dst, src []byte) {
- decryptBlockGo(xk, dst, src)
+// newCipher calls the newCipherGeneric function
+// directly. Platforms with hardware accelerated
+// implementations of AES should implement their
+// own version of newCipher (which may then call
+// newCipherGeneric if needed).
+func newCipher(key []byte) (cipher.Block, error) {
+ return newCipherGeneric(key)
}
+// expandKey is used by BenchmarkExpand and should
+// call an assembly implementation if one is available.
func expandKey(key []byte, enc, dec []uint32) {
expandKeyGo(key, enc, dec)
}
-
-func hasGCMAsm() bool {
- return false
-}
-
-type aesCipherGCM struct {
- aesCipher
-}
diff --git a/libgo/go/crypto/aes/cipher_s390x.go b/libgo/go/crypto/aes/cipher_s390x.go
new file mode 100644
index 0000000000..253ce89389
--- /dev/null
+++ b/libgo/go/crypto/aes/cipher_s390x.go
@@ -0,0 +1,88 @@
+// 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 aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/cipherhw"
+)
+
+type code int
+
+// Function codes for the cipher message family of instructions.
+const (
+ aes128 code = 18
+ aes192 = 19
+ aes256 = 20
+)
+
+type aesCipherAsm struct {
+ function code // code for cipher message instruction
+ key []byte // key (128, 192 or 256 bytes)
+ storage [256]byte // array backing key slice
+}
+
+// cryptBlocks invokes the cipher message (KM) instruction with
+// the given function code. This is equivalent to AES in ECB
+// mode. The length must be a multiple of BlockSize (16).
+//go:noescape
+func cryptBlocks(c code, key, dst, src *byte, length int)
+
+var useAsm = cipherhw.AESGCMSupport()
+
+func newCipher(key []byte) (cipher.Block, error) {
+ if !useAsm {
+ return newCipherGeneric(key)
+ }
+
+ var function code
+ switch len(key) {
+ case 128 / 8:
+ function = aes128
+ case 192 / 8:
+ function = aes192
+ case 256 / 8:
+ function = aes256
+ default:
+ return nil, KeySizeError(len(key))
+ }
+
+ var c aesCipherAsm
+ c.function = function
+ c.key = c.storage[:len(key)]
+ copy(c.key, key)
+ return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ // The decrypt function code is equal to the function code + 128.
+ cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+// expandKey is used by BenchmarkExpand. cipher message (KM) does not need key
+// expansion so there is no assembly equivalent.
+func expandKey(key []byte, enc, dec []uint32) {
+ expandKeyGo(key, enc, dec)
+}
diff --git a/libgo/go/crypto/aes/const.go b/libgo/go/crypto/aes/const.go
index aee73a7c52..cbac5ff0ea 100644
--- a/libgo/go/crypto/aes/const.go
+++ b/libgo/go/crypto/aes/const.go
@@ -4,6 +4,13 @@
// Package aes implements AES encryption (formerly Rijndael), as defined in
// U.S. Federal Information Processing Standards Publication 197.
+//
+// The AES operations in this package are not implemented using constant-time algorithms.
+// An exception is when running on systems with enabled hardware support for AES
+// that makes these operations constant-time. Examples include amd64 systems using AES-NI
+// extensions and s390x systems using Message-Security-Assist extensions.
+// On such systems, when the result of NewCipher is passed to cipher.NewGCM,
+// the GHASH operation used by GCM is also constant-time.
package aes
// This file contains AES constants - 8720 bytes of initialized data.
diff --git a/libgo/go/crypto/aes/ctr_s390x.go b/libgo/go/crypto/aes/ctr_s390x.go
new file mode 100644
index 0000000000..ae09dbadaf
--- /dev/null
+++ b/libgo/go/crypto/aes/ctr_s390x.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package aes
+
+import (
+ "crypto/cipher"
+ "unsafe"
+)
+
+// Assert that aesCipherAsm implements the ctrAble interface.
+var _ ctrAble = (*aesCipherAsm)(nil)
+
+// xorBytes xors the contents of a and b and places the resulting values into
+// dst. If a and b are not the same length then the number of bytes processed
+// will be equal to the length of shorter of the two. Returns the number
+// of bytes processed.
+//go:noescape
+func xorBytes(dst, a, b []byte) int
+
+// streamBufferSize is the number of bytes of encrypted counter values to cache.
+const streamBufferSize = 32 * BlockSize
+
+type aesctr struct {
+ block *aesCipherAsm // block cipher
+ ctr [2]uint64 // next value of the counter (big endian)
+ buffer []byte // buffer for the encrypted counter values
+ storage [streamBufferSize]byte // array backing buffer slice
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the AES block
+// cipher in counter mode. The length of iv must be the same as BlockSize.
+func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream {
+ if len(iv) != BlockSize {
+ panic("cipher.NewCTR: IV length must equal block size")
+ }
+ var ac aesctr
+ ac.block = c
+ ac.ctr[0] = *(*uint64)(unsafe.Pointer((&iv[0]))) // high bits
+ ac.ctr[1] = *(*uint64)(unsafe.Pointer((&iv[8]))) // low bits
+ ac.buffer = ac.storage[:0]
+ return &ac
+}
+
+func (c *aesctr) refill() {
+ // Fill up the buffer with an incrementing count.
+ c.buffer = c.storage[:streamBufferSize]
+ c0, c1 := c.ctr[0], c.ctr[1]
+ for i := 0; i < streamBufferSize; i += BlockSize {
+ b0 := (*uint64)(unsafe.Pointer(&c.buffer[i]))
+ b1 := (*uint64)(unsafe.Pointer(&c.buffer[i+BlockSize/2]))
+ *b0, *b1 = c0, c1
+ // Increment in big endian: c0 is high, c1 is low.
+ c1++
+ if c1 == 0 {
+ // add carry
+ c0++
+ }
+ }
+ c.ctr[0], c.ctr[1] = c0, c1
+ // Encrypt the buffer using AES in ECB mode.
+ cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize)
+}
+
+func (c *aesctr) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if len(c.buffer) == 0 {
+ c.refill()
+ }
+ n := xorBytes(dst, src, c.buffer)
+ c.buffer = c.buffer[n:]
+ src = src[n:]
+ dst = dst[n:]
+ }
+}
diff --git a/libgo/go/crypto/aes/gcm_s390x.go b/libgo/go/crypto/aes/gcm_s390x.go
new file mode 100644
index 0000000000..ca7f6a778d
--- /dev/null
+++ b/libgo/go/crypto/aes/gcm_s390x.go
@@ -0,0 +1,272 @@
+// 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 aes
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+ "errors"
+)
+
+// gcmCount represents a 16-byte big-endian count value.
+type gcmCount [16]byte
+
+// inc increments the rightmost 32-bits of the count value by 1.
+func (x *gcmCount) inc() {
+ // The compiler should optimize this to a 32-bit addition.
+ n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24
+ n += 1
+ x[12] = byte(n >> 24)
+ x[13] = byte(n >> 16)
+ x[14] = byte(n >> 8)
+ x[15] = byte(n)
+}
+
+// gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
+func gcmLengths(len0, len1 uint64) [16]byte {
+ return [16]byte{
+ byte(len0 >> 56),
+ byte(len0 >> 48),
+ byte(len0 >> 40),
+ byte(len0 >> 32),
+ byte(len0 >> 24),
+ byte(len0 >> 16),
+ byte(len0 >> 8),
+ byte(len0),
+ byte(len1 >> 56),
+ byte(len1 >> 48),
+ byte(len1 >> 40),
+ byte(len1 >> 32),
+ byte(len1 >> 24),
+ byte(len1 >> 16),
+ byte(len1 >> 8),
+ byte(len1),
+ }
+}
+
+// gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
+type gcmHashKey [16]byte
+
+type gcmAsm struct {
+ block *aesCipherAsm
+ hashKey gcmHashKey
+ nonceSize int
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// Assert that aesCipherAsm implements the gcmAble interface.
+var _ gcmAble = (*aesCipherAsm)(nil)
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherAsm) NewGCM(nonceSize int) (cipher.AEAD, error) {
+ var hk gcmHashKey
+ c.Encrypt(hk[:], hk[:])
+ g := &gcmAsm{
+ block: c,
+ hashKey: hk,
+ nonceSize: nonceSize,
+ }
+ return g, nil
+}
+
+func (g *gcmAsm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (*gcmAsm) Overhead() int {
+ return gcmTagSize
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// ghash uses the GHASH algorithm to hash data with the given key. The initial
+// hash value is given by hash which will be updated with the new hash value.
+// The length of data must be a multiple of 16-bytes.
+//go:noescape
+func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
+
+// paddedGHASH pads data with zeroes until its length is a multiple of
+// 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
+func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
+ siz := len(data) &^ 0xf // align size to 16-bytes
+ if siz > 0 {
+ ghash(&g.hashKey, hash, data[:siz])
+ data = data[siz:]
+ }
+ if len(data) > 0 {
+ var s [16]byte
+ copy(s[:], data)
+ ghash(&g.hashKey, hash, s[:])
+ }
+}
+
+// cryptBlocksGCM encrypts src using AES in counter mode using the given
+// function code and key. The rightmost 32-bits of the counter are incremented
+// between each block as required by the GCM spec. The initial counter value
+// is given by cnt, which is updated with the value of the next counter value
+// to use.
+//
+// The lengths of both dst and buf must be greater than or equal to the length
+// of src. buf may be partially or completely overwritten during the execution
+// of the function.
+//go:noescape
+func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
+
+// counterCrypt encrypts src using AES in counter mode and places the result
+// into dst. cnt is the initial count value and will be updated with the next
+// count value. The length of dst must be greater than or equal to the length
+// of src.
+func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
+ // Copying src into a buffer improves performance on some models when
+ // src and dst point to the same underlying array. We also need a
+ // buffer for counter values.
+ var ctrbuf, srcbuf [2048]byte
+ for len(src) >= 16 {
+ siz := len(src)
+ if len(src) > len(ctrbuf) {
+ siz = len(ctrbuf)
+ }
+ siz &^= 0xf // align siz to 16-bytes
+ copy(srcbuf[:], src[:siz])
+ cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
+ src = src[siz:]
+ dst = dst[siz:]
+ }
+ if len(src) > 0 {
+ var x [16]byte
+ g.block.Encrypt(x[:], cnt[:])
+ for i := range src {
+ dst[i] = src[i] ^ x[i]
+ }
+ cnt.inc()
+ }
+}
+
+// deriveCounter computes the initial GCM counter state from the given nonce.
+// See NIST SP 800-38D, section 7.1.
+func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
+ // GCM has two modes of operation with respect to the initial counter
+ // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
+ // for nonces of other lengths. For a 96-bit nonce, the nonce, along
+ // with a four-byte big-endian counter starting at one, is used
+ // directly as the starting counter. For other nonce sizes, the counter
+ // is computed by passing it through the GHASH function.
+ var counter gcmCount
+ if len(nonce) == gcmStandardNonceSize {
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ var hash [16]byte
+ g.paddedGHASH(&hash, nonce)
+ lens := gcmLengths(0, uint64(len(nonce))*8)
+ g.paddedGHASH(&hash, lens[:])
+ copy(counter[:], hash[:])
+ }
+ return counter
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
+ var hash [16]byte
+ g.paddedGHASH(&hash, additionalData)
+ g.paddedGHASH(&hash, ciphertext)
+ lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
+ g.paddedGHASH(&hash, lens[:])
+
+ copy(out, hash[:])
+ for i := range out {
+ out[i] ^= tagMask[i]
+ }
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ g.counterCrypt(out, plaintext, &counter)
+ g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < gcmTagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-gcmTagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ var expectedTag [gcmTagSize]byte
+ g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+
+ if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
+ // The AESNI code decrypts and authenticates concurrently, and
+ // so overwrites dst in the event of a tag mismatch. That
+ // behavior is mimicked here in order to be consistent across
+ // platforms.
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ g.counterCrypt(out, ciphertext, &counter)
+ return ret, nil
+}
diff --git a/libgo/go/crypto/aes/modes.go b/libgo/go/crypto/aes/modes.go
new file mode 100644
index 0000000000..1623fc16e2
--- /dev/null
+++ b/libgo/go/crypto/aes/modes.go
@@ -0,0 +1,37 @@
+// 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 aes
+
+import (
+ "crypto/cipher"
+)
+
+// gcmAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of GCM through the AEAD interface.
+// See crypto/cipher/gcm.go.
+type gcmAble interface {
+ NewGCM(size int) (cipher.AEAD, error)
+}
+
+// cbcEncAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC encryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcEncAble interface {
+ NewCBCEncrypter(iv []byte) cipher.BlockMode
+}
+
+// cbcDecAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC decryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcDecAble interface {
+ NewCBCDecrypter(iv []byte) cipher.BlockMode
+}
+
+// ctrAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CTR through the cipher.Stream interface.
+// See crypto/cipher/ctr.go.
+type ctrAble interface {
+ NewCTR(iv []byte) cipher.Stream
+}
diff --git a/libgo/go/crypto/aes/modes_test.go b/libgo/go/crypto/aes/modes_test.go
new file mode 100644
index 0000000000..8c2e5f0560
--- /dev/null
+++ b/libgo/go/crypto/aes/modes_test.go
@@ -0,0 +1,112 @@
+// 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 aes
+
+import (
+ "crypto/cipher"
+ "testing"
+)
+
+// Check that the optimized implementations of cipher modes will
+// be picked up correctly.
+
+// testInterface can be asserted to check that a type originates
+// from this test group.
+type testInterface interface {
+ InAESPackage() bool
+}
+
+// testBlock implements the cipher.Block interface and any *Able
+// interfaces that need to be tested.
+type testBlock struct{}
+
+func (*testBlock) BlockSize() int { return 0 }
+func (*testBlock) Encrypt(a, b []byte) {}
+func (*testBlock) Decrypt(a, b []byte) {}
+func (*testBlock) NewGCM(int) (cipher.AEAD, error) {
+ return &testAEAD{}, nil
+}
+func (*testBlock) NewCBCEncrypter([]byte) cipher.BlockMode {
+ return &testBlockMode{}
+}
+func (*testBlock) NewCBCDecrypter([]byte) cipher.BlockMode {
+ return &testBlockMode{}
+}
+func (*testBlock) NewCTR([]byte) cipher.Stream {
+ return &testStream{}
+}
+
+// testAEAD implements the cipher.AEAD interface.
+type testAEAD struct{}
+
+func (*testAEAD) NonceSize() int { return 0 }
+func (*testAEAD) Overhead() int { return 0 }
+func (*testAEAD) Seal(a, b, c, d []byte) []byte { return []byte{} }
+func (*testAEAD) Open(a, b, c, d []byte) ([]byte, error) { return []byte{}, nil }
+func (*testAEAD) InAESPackage() bool { return true }
+
+// Test the gcmAble interface is detected correctly by the cipher package.
+func TestGCMAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(gcmAble); !ok {
+ t.Fatalf("testBlock does not implement the gcmAble interface")
+ }
+ aead, err := cipher.NewGCM(b)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if _, ok := aead.(testInterface); !ok {
+ t.Fatalf("cipher.NewGCM did not use gcmAble interface")
+ }
+}
+
+// testBlockMode implements the cipher.BlockMode interface.
+type testBlockMode struct{}
+
+func (*testBlockMode) BlockSize() int { return 0 }
+func (*testBlockMode) CryptBlocks(a, b []byte) {}
+func (*testBlockMode) InAESPackage() bool { return true }
+
+// Test the cbcEncAble interface is detected correctly by the cipher package.
+func TestCBCEncAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(cbcEncAble); !ok {
+ t.Fatalf("testBlock does not implement the cbcEncAble interface")
+ }
+ bm := cipher.NewCBCEncrypter(b, []byte{})
+ if _, ok := bm.(testInterface); !ok {
+ t.Fatalf("cipher.NewCBCEncrypter did not use cbcEncAble interface")
+ }
+}
+
+// Test the cbcDecAble interface is detected correctly by the cipher package.
+func TestCBCDecAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(cbcDecAble); !ok {
+ t.Fatalf("testBlock does not implement the cbcDecAble interface")
+ }
+ bm := cipher.NewCBCDecrypter(b, []byte{})
+ if _, ok := bm.(testInterface); !ok {
+ t.Fatalf("cipher.NewCBCDecrypter did not use cbcDecAble interface")
+ }
+}
+
+// testStream implements the cipher.Stream interface.
+type testStream struct{}
+
+func (*testStream) XORKeyStream(a, b []byte) {}
+func (*testStream) InAESPackage() bool { return true }
+
+// Test the ctrAble interface is detected correctly by the cipher package.
+func TestCTRAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(ctrAble); !ok {
+ t.Fatalf("testBlock does not implement the ctrAble interface")
+ }
+ s := cipher.NewCTR(b, []byte{})
+ if _, ok := s.(testInterface); !ok {
+ t.Fatalf("cipher.NewCTR did not use ctrAble interface")
+ }
+}
diff --git a/libgo/go/crypto/cipher/cbc.go b/libgo/go/crypto/cipher/cbc.go
index 241e122ee8..0367d5971a 100644
--- a/libgo/go/crypto/cipher/cbc.go
+++ b/libgo/go/crypto/cipher/cbc.go
@@ -29,6 +29,14 @@ func newCBC(b Block, iv []byte) *cbc {
type cbcEncrypter cbc
+// cbcEncAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC encryption, like crypto/aes.
+// NewCBCEncrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcEncAble interface {
+ NewCBCEncrypter(iv []byte) BlockMode
+}
+
// NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
// mode, using the given Block. The length of iv must be the same as the
// Block's block size.
@@ -36,6 +44,9 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
if len(iv) != b.BlockSize() {
panic("cipher.NewCBCEncrypter: IV length must equal block size")
}
+ if cbc, ok := b.(cbcEncAble); ok {
+ return cbc.NewCBCEncrypter(iv)
+ }
return (*cbcEncrypter)(newCBC(b, iv))
}
@@ -75,6 +86,14 @@ func (x *cbcEncrypter) SetIV(iv []byte) {
type cbcDecrypter cbc
+// cbcDecAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC decryption, like crypto/aes.
+// NewCBCDecrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcDecAble interface {
+ NewCBCDecrypter(iv []byte) BlockMode
+}
+
// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
// mode, using the given Block. The length of iv must be the same as the
// Block's block size and must match the iv used to encrypt the data.
@@ -82,6 +101,9 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
if len(iv) != b.BlockSize() {
panic("cipher.NewCBCDecrypter: IV length must equal block size")
}
+ if cbc, ok := b.(cbcDecAble); ok {
+ return cbc.NewCBCDecrypter(iv)
+ }
return (*cbcDecrypter)(newCBC(b, iv))
}
diff --git a/libgo/go/crypto/cipher/cipher.go b/libgo/go/crypto/cipher/cipher.go
index 7d27fde61d..531ecad9ac 100644
--- a/libgo/go/crypto/cipher/cipher.go
+++ b/libgo/go/crypto/cipher/cipher.go
@@ -9,8 +9,8 @@
package cipher
// A Block represents an implementation of block cipher
-// using a given key. It provides the capability to encrypt
-// or decrypt individual blocks. The mode implementations
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
// extend that capability to streams of blocks.
type Block interface {
// BlockSize returns the cipher's block size.
diff --git a/libgo/go/crypto/cipher/cipher_test.go b/libgo/go/crypto/cipher/cipher_test.go
index 8da5bce93f..4d7cd6b5dd 100644
--- a/libgo/go/crypto/cipher/cipher_test.go
+++ b/libgo/go/crypto/cipher/cipher_test.go
@@ -1,12 +1,14 @@
-// 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.
package cipher_test
import (
+ "bytes"
"crypto/aes"
"crypto/cipher"
+ "crypto/des"
"testing"
)
@@ -34,3 +36,55 @@ func mustPanic(t *testing.T, msg string, f func()) {
}()
f()
}
+
+func TestEmptyPlaintext(t *testing.T) {
+ var key [16]byte
+ a, err := aes.NewCipher(key[:16])
+ if err != nil {
+ t.Fatal(err)
+ }
+ d, err := des.NewCipher(key[:8])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ s := 16
+ pt := make([]byte, s)
+ ct := make([]byte, s)
+ for i := 0; i < 16; i++ {
+ pt[i], ct[i] = byte(i), byte(i)
+ }
+
+ assertEqual := func(name string, got, want []byte) {
+ if !bytes.Equal(got, want) {
+ t.Fatalf("%s: got %v, want %v", name, got, want)
+ }
+ }
+
+ for _, b := range []cipher.Block{a, d} {
+ iv := make([]byte, b.BlockSize())
+ cbce := cipher.NewCBCEncrypter(b, iv)
+ cbce.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC encrypt", ct, pt)
+
+ cbcd := cipher.NewCBCDecrypter(b, iv)
+ cbcd.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC decrypt", ct, pt)
+
+ cfbe := cipher.NewCFBEncrypter(b, iv)
+ cfbe.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB encrypt", ct, pt)
+
+ cfbd := cipher.NewCFBDecrypter(b, iv)
+ cfbd.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB decrypt", ct, pt)
+
+ ctr := cipher.NewCTR(b, iv)
+ ctr.XORKeyStream(ct, pt[:0])
+ assertEqual("CTR", ct, pt)
+
+ ofb := cipher.NewOFB(b, iv)
+ ofb.XORKeyStream(ct, pt[:0])
+ assertEqual("OFB", ct, pt)
+ }
+}
diff --git a/libgo/go/crypto/cipher/ctr.go b/libgo/go/crypto/cipher/ctr.go
index 16baa6d17d..75f46cfe51 100644
--- a/libgo/go/crypto/cipher/ctr.go
+++ b/libgo/go/crypto/cipher/ctr.go
@@ -21,9 +21,19 @@ type ctr struct {
const streamBufferSize = 512
+// ctrAble is an interface implemented by ciphers that have a specific optimized
+// implementation of CTR, like crypto/aes. NewCTR will check for this interface
+// and return the specific Stream if found.
+type ctrAble interface {
+ NewCTR(iv []byte) Stream
+}
+
// NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size.
func NewCTR(block Block, iv []byte) Stream {
+ if ctr, ok := block.(ctrAble); ok {
+ return ctr.NewCTR(iv)
+ }
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: IV length must equal block size")
}
diff --git a/libgo/go/crypto/cipher/example_test.go b/libgo/go/crypto/cipher/example_test.go
index f6cc386506..956cc2eaca 100644
--- a/libgo/go/crypto/cipher/example_test.go
+++ b/libgo/go/crypto/cipher/example_test.go
@@ -14,7 +14,7 @@ import (
"os"
)
-func ExampleNewGCMEncrypter() {
+func ExampleNewGCM_encrypt() {
// The key argument should be the AES key, either 16 or 32 bytes
// to select AES-128 or AES-256.
key := []byte("AES256Key-32Characters1234567890")
@@ -40,13 +40,13 @@ func ExampleNewGCMEncrypter() {
fmt.Printf("%x\n", ciphertext)
}
-func ExampleNewGCMDecrypter() {
+func ExampleNewGCM_decrypt() {
// 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() {
diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go
index 3868d7123a..62085aac0f 100644
--- a/libgo/go/crypto/cipher/gcm.go
+++ b/libgo/go/crypto/cipher/gcm.go
@@ -74,6 +74,10 @@ type gcm struct {
// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
// with the standard nonce length.
+//
+// In general, the GHASH operation performed by this implementation of GCM is not constant-time.
+// An exception is when the underlying Block was created by aes.NewCipher
+// on systems with hardware support for AES. See the crypto/aes package documentation for details.
func NewGCM(cipher Block) (AEAD, error) {
return NewGCMWithNonceSize(cipher, gcmStandardNonceSize)
}
@@ -135,6 +139,10 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
panic("cipher: incorrect nonce length given to GCM")
}
+ if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) {
+ panic("cipher: message too large for GCM")
+ }
+
ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
var counter, tagMask [gcmBlockSize]byte
@@ -159,6 +167,10 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(ciphertext) < gcmTagSize {
return nil, errOpen
}
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize())+gcmTagSize {
+ return nil, errOpen
+ }
+
tag := ciphertext[len(ciphertext)-gcmTagSize:]
ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
@@ -176,7 +188,7 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and
// so overwrites dst in the event of a tag mismatch. That
- // behaviour is mimicked here in order to be consistent across
+ // behavior is mimicked here in order to be consistent across
// platforms.
for i := range out {
out[i] = 0
diff --git a/libgo/go/crypto/cipher/gcm_test.go b/libgo/go/crypto/cipher/gcm_test.go
index bb1ab3c0b0..6878b4cb42 100644
--- a/libgo/go/crypto/cipher/gcm_test.go
+++ b/libgo/go/crypto/cipher/gcm_test.go
@@ -8,7 +8,11 @@ import (
"bytes"
"crypto/aes"
"crypto/cipher"
+ "crypto/rand"
"encoding/hex"
+ "errors"
+ "io"
+ "reflect"
"testing"
)
@@ -274,3 +278,157 @@ func TestTagFailureOverwrite(t *testing.T) {
}
}
}
+
+func TestGCMCounterWrap(t *testing.T) {
+ // Test that the last 32-bits of the counter wrap correctly.
+ tests := []struct {
+ nonce, tag string
+ }{
+ {"0fa72e25", "37e1948cdfff09fbde0c40ad99fee4a7"}, // counter: 7eb59e4d961dad0dfdd75aaffffffff0
+ {"afe05cc1", "438f3aa9fee5e54903b1927bca26bbdf"}, // counter: 75d492a7e6e6bfc979ad3a8ffffffff4
+ {"9ffecbef", "7b88ca424df9703e9e8611071ec7e16e"}, // counter: c8bb108b0ecdc71747b9d57ffffffff5
+ {"ffc3e5b3", "38d49c86e0abe853ac250e66da54c01a"}, // counter: 706414d2de9b36ab3b900a9ffffffff6
+ {"cfdd729d", "e08402eaac36a1a402e09b1bd56500e8"}, // counter: cd0b96fe36b04e750584e56ffffffff7
+ {"010ae3d486", "5405bb490b1f95d01e2ba735687154bc"}, // counter: e36c18e69406c49722808104fffffff8
+ {"01b1107a9d", "939a585f342e01e17844627492d44dbf"}, // counter: e6d56eaf9127912b6d62c6dcffffffff
+ }
+ key, err := aes.NewCipher(make([]byte, 16))
+ if err != nil {
+ t.Fatal(err)
+ }
+ plaintext := make([]byte, 16*17+1)
+ for i, test := range tests {
+ nonce, _ := hex.DecodeString(test.nonce)
+ want, _ := hex.DecodeString(test.tag)
+ aead, err := cipher.NewGCMWithNonceSize(key, len(nonce))
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := aead.Seal(nil, nonce, plaintext, nil)
+ if !bytes.Equal(got[len(plaintext):], want) {
+ t.Errorf("test[%v]: got: %x, want: %x", i, got[len(plaintext):], want)
+ }
+ _, err = aead.Open(nil, nonce, got, nil)
+ if err != nil {
+ t.Errorf("test[%v]: authentication failed", i)
+ }
+ }
+}
+
+var _ cipher.Block = (*wrapper)(nil)
+
+type wrapper struct {
+ block cipher.Block
+}
+
+func (w *wrapper) BlockSize() int { return w.block.BlockSize() }
+func (w *wrapper) Encrypt(dst, src []byte) { w.block.Encrypt(dst, src) }
+func (w *wrapper) Decrypt(dst, src []byte) { w.block.Decrypt(dst, src) }
+
+// wrap wraps the Block interface so that it does not fulfill
+// any optimizing interfaces such as gcmAble.
+func wrap(b cipher.Block) cipher.Block {
+ return &wrapper{b}
+}
+
+func TestGCMAsm(t *testing.T) {
+ // Create a new pair of AEADs, one using the assembly implementation
+ // and one using the generic Go implementation.
+ newAESGCM := func(key []byte) (asm, generic cipher.AEAD, err error) {
+ block, err := aes.NewCipher(key[:])
+ if err != nil {
+ return nil, nil, err
+ }
+ asm, err = cipher.NewGCM(block)
+ if err != nil {
+ return nil, nil, err
+ }
+ generic, err = cipher.NewGCM(wrap(block))
+ if err != nil {
+ return nil, nil, err
+ }
+ return asm, generic, nil
+ }
+
+ // check for assembly implementation
+ var key [16]byte
+ asm, generic, err := newAESGCM(key[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ if reflect.TypeOf(asm) == reflect.TypeOf(generic) {
+ t.Skipf("no assembly implementation of GCM")
+ }
+
+ // generate permutations
+ type pair struct{ align, length int }
+ lengths := []int{0, 8192, 8193, 8208}
+ keySizes := []int{16, 24, 32}
+ alignments := []int{0, 1, 2, 3}
+ if testing.Short() {
+ keySizes = []int{16}
+ alignments = []int{1}
+ }
+ perms := make([]pair, 0)
+ for _, l := range lengths {
+ for _, a := range alignments {
+ if a != 0 && l == 0 {
+ continue
+ }
+ perms = append(perms, pair{align: a, length: l})
+ }
+ }
+
+ // run test for all permutations
+ test := func(ks int, pt, ad []byte) error {
+ key := make([]byte, ks)
+ if _, err := io.ReadFull(rand.Reader, key); err != nil {
+ return err
+ }
+ asm, generic, err := newAESGCM(key)
+ if err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, pt); err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, ad); err != nil {
+ return err
+ }
+ nonce := make([]byte, 12)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ return err
+ }
+ want := generic.Seal(nil, nonce, pt, ad)
+ got := asm.Seal(nil, nonce, pt, ad)
+ if !bytes.Equal(want, got) {
+ return errors.New("incorrect Seal output")
+ }
+ got, err = asm.Open(nil, nonce, want, ad)
+ if err != nil {
+ return errors.New("authentication failed")
+ }
+ if !bytes.Equal(pt, got) {
+ return errors.New("incorrect Open output")
+ }
+ return nil
+ }
+ for _, a := range perms {
+ ad := make([]byte, a.align+a.length)
+ ad = ad[a.align:]
+ for _, p := range perms {
+ pt := make([]byte, p.align+p.length)
+ pt = pt[p.align:]
+ for _, ks := range keySizes {
+ if err := test(ks, pt, ad); err != nil {
+ t.Error(err)
+ t.Errorf(" key size: %v", ks)
+ t.Errorf(" plaintext alignment: %v", p.align)
+ t.Errorf(" plaintext length: %v", p.length)
+ t.Errorf(" additionalData alignment: %v", a.align)
+ t.Fatalf(" additionalData length: %v", a.length)
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/cipher/xor.go b/libgo/go/crypto/cipher/xor.go
index f88dc8914a..01ca0a9f08 100644
--- a/libgo/go/crypto/cipher/xor.go
+++ b/libgo/go/crypto/cipher/xor.go
@@ -10,7 +10,7 @@ import (
)
const wordSize = int(unsafe.Sizeof(uintptr(0)))
-const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
// fastXORBytes xors in bulk. It only works on architectures that
// support unaligned read/writes.
diff --git a/libgo/go/crypto/cipher/xor_test.go b/libgo/go/crypto/cipher/xor_test.go
index cc1c9d72d5..d9187eb726 100644
--- a/libgo/go/crypto/cipher/xor_test.go
+++ b/libgo/go/crypto/cipher/xor_test.go
@@ -19,7 +19,7 @@ func TestXOR(t *testing.T) {
d2 := make([]byte, 1024+alignD)[alignD:]
xorBytes(d1, p, q)
safeXORBytes(d2, p, q)
- if bytes.Compare(d1, d2) != 0 {
+ if !bytes.Equal(d1, d2) {
t.Error("not equal")
}
}
diff --git a/libgo/go/crypto/des/block.go b/libgo/go/crypto/des/block.go
index 26355a22e7..99338d62a6 100644
--- a/libgo/go/crypto/des/block.go
+++ b/libgo/go/crypto/des/block.go
@@ -72,7 +72,7 @@ func init() {
for i := 0; i < 4; i++ {
for j := 0; j < 16; j++ {
f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
- f = permuteBlock(uint64(f), permutationFunction[:])
+ f = permuteBlock(f, permutationFunction[:])
feistelBox[s][16*i+j] = uint32(f)
}
}
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index 9f414a470c..bc0c3e3462 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -3,6 +3,8 @@
// license that can be found in the LICENSE file.
// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
+//
+// The DSA operations in this package are not implemented using constant-time algorithms.
package dsa
import (
@@ -52,7 +54,7 @@ const numMRTests = 64
// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function can take many seconds, even on fast machines.
-func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
// This function doesn't follow FIPS 186-3 exactly in that it doesn't
// use a verification seed to generate the primes. The verification
// seed doesn't appear to be exported or used by other code and
@@ -87,9 +89,8 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
GeneratePrimes:
for {
- _, err = io.ReadFull(rand, qBytes)
- if err != nil {
- return
+ if _, err := io.ReadFull(rand, qBytes); err != nil {
+ return err
}
qBytes[len(qBytes)-1] |= 1
@@ -101,9 +102,8 @@ GeneratePrimes:
}
for i := 0; i < 4*L; i++ {
- _, err = io.ReadFull(rand, pBytes)
- if err != nil {
- return
+ if _, err := io.ReadFull(rand, pBytes); err != nil {
+ return err
}
pBytes[len(pBytes)-1] |= 1
@@ -142,7 +142,7 @@ GeneratePrimes:
}
params.G = g
- return
+ return nil
}
}
@@ -191,17 +191,21 @@ func fermatInverse(k, P *big.Int) *big.Int {
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
+//
+// Be aware that calling Sign with an attacker-controlled PrivateKey may
+// require an arbitrary amount of CPU.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
// FIPS 186-3, section 4.6
n := priv.Q.BitLen()
- if n&7 != 0 {
+ if priv.Q.Sign() <= 0 || priv.P.Sign() <= 0 || priv.G.Sign() <= 0 || priv.X.Sign() <= 0 || n&7 != 0 {
err = ErrInvalidPublicKey
return
}
n >>= 3
- for {
+ var attempts int
+ for attempts = 10; attempts > 0; attempts-- {
k := new(big.Int)
buf := make([]byte, n)
for {
@@ -210,6 +214,10 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
return
}
k.SetBytes(buf)
+ // priv.Q must be >= 128 because the test above
+ // requires it to be > 0 and that
+ // ceil(log_2(Q)) mod 8 = 0
+ // Thus this loop will quickly terminate.
if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
break
}
@@ -237,6 +245,12 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
}
}
+ // Only degenerate private keys will require more than a handful of
+ // attempts.
+ if attempts == 0 {
+ return nil, nil, ErrInvalidPublicKey
+ }
+
return
}
diff --git a/libgo/go/crypto/dsa/dsa_test.go b/libgo/go/crypto/dsa/dsa_test.go
index 568416d0df..8600059f03 100644
--- a/libgo/go/crypto/dsa/dsa_test.go
+++ b/libgo/go/crypto/dsa/dsa_test.go
@@ -73,6 +73,14 @@ func TestParameterGeneration(t *testing.T) {
testParameterGeneration(t, L3072N256, 3072, 256)
}
+func fromHex(s string) *big.Int {
+ result, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic(s)
+ }
+ return result
+}
+
func TestSignAndVerify(t *testing.T) {
var priv PrivateKey
priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
@@ -83,3 +91,33 @@ func TestSignAndVerify(t *testing.T) {
testSignAndVerify(t, 0, &priv)
}
+
+func TestSigningWithDegenerateKeys(t *testing.T) {
+ // Signing with degenerate private keys should not cause an infinite
+ // loop.
+ badKeys := []struct {
+ p, q, g, y, x string
+ }{
+ {"00", "01", "00", "00", "00"},
+ {"01", "ff", "00", "00", "00"},
+ }
+
+ for i, test := range badKeys {
+ priv := PrivateKey{
+ PublicKey: PublicKey{
+ Parameters: Parameters{
+ P: fromHex(test.p),
+ Q: fromHex(test.q),
+ G: fromHex(test.g),
+ },
+ Y: fromHex(test.y),
+ },
+ X: fromHex(test.x),
+ }
+
+ hashed := []byte("testing")
+ if _, _, err := Sign(rand.Reader, &priv, hashed); err == nil {
+ t.Errorf("#%d: unexpected success", i)
+ }
+ }
+}
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
index e54488c9cf..02848fd595 100644
--- a/libgo/go/crypto/ecdsa/ecdsa.go
+++ b/libgo/go/crypto/ecdsa/ecdsa.go
@@ -97,17 +97,17 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
}
// GenerateKey generates a public and private key pair.
-func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
+func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
k, err := randFieldElement(c, rand)
if err != nil {
- return
+ return nil, err
}
- priv = new(PrivateKey)
+ priv := new(PrivateKey)
priv.PublicKey.Curve = c
priv.D = k
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
- return
+ return priv, nil
}
// hashToInt converts a hash value to an integer. There is some disagreement
@@ -143,12 +143,13 @@ func fermatInverse(k, N *big.Int) *big.Int {
var errZeroParam = errors.New("zero parameter")
-// Sign signs an arbitrary length hash (which should be the result of hashing a
-// larger message) using the private key, priv. It returns the signature as a
-// pair of integers. The security of the private key depends on the entropy of
-// rand.
+// Sign signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length. It
+// returns the signature as a pair of integers. The security of the private key
+// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
- // Get max(log2(q) / 2, 256) bits of entropy from rand.
+ // Get min(log2(q) / 2, 256) bits of entropy from rand.
entropylen := (priv.Curve.Params().BitSize + 7) / 16
if entropylen > 32 {
entropylen = 32
@@ -228,7 +229,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
c := pub.Curve
N := c.Params().N
- if r.Sign() == 0 || s.Sign() == 0 {
+ if r.Sign() <= 0 || s.Sign() <= 0 {
return false
}
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go
index 62a3fcc496..9546f67c68 100644
--- a/libgo/go/crypto/ecdsa/ecdsa_test.go
+++ b/libgo/go/crypto/ecdsa/ecdsa_test.go
@@ -54,6 +54,18 @@ func BenchmarkSignP256(b *testing.B) {
}
}
+func BenchmarkSignP384(b *testing.B) {
+ b.ResetTimer()
+ p384 := elliptic.P384()
+ hashed := []byte("testing")
+ priv, _ := GenerateKey(p384, rand.Reader)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _, _ = Sign(rand.Reader, priv, hashed)
+ }
+}
+
func BenchmarkVerifyP256(b *testing.B) {
b.ResetTimer()
p256 := elliptic.P256()
@@ -130,7 +142,7 @@ func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
}
if r0.Cmp(r1) == 0 {
- t.Errorf("%s: the nonce used for two diferent messages was the same", tag)
+ t.Errorf("%s: the nonce used for two different messages was the same", tag)
}
}
@@ -296,3 +308,26 @@ func TestVectors(t *testing.T) {
}
}
}
+
+func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
+ key, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Errorf("failed to generate key for %q", tag)
+ }
+
+ var hash [32]byte
+ r := new(big.Int).SetInt64(1)
+ r.Lsh(r, 550 /* larger than any supported curve */)
+ r.Neg(r)
+
+ if Verify(&key.PublicKey, hash[:], r, r) {
+ t.Errorf("bogus signature accepted for %q", tag)
+ }
+}
+
+func TestNegativeInputs(t *testing.T) {
+ testNegativeInputs(t, elliptic.P224(), "p224")
+ testNegativeInputs(t, elliptic.P256(), "p256")
+ testNegativeInputs(t, elliptic.P384(), "p384")
+ testNegativeInputs(t, elliptic.P521(), "p521")
+}
diff --git a/libgo/go/crypto/ecdsa/testdata/SigVer.rsp.bz2 b/libgo/go/crypto/ecdsa/testdata/SigVer.rsp.bz2
new file mode 100644
index 0000000000..09fe2b4271
--- /dev/null
+++ b/libgo/go/crypto/ecdsa/testdata/SigVer.rsp.bz2
Binary files differ
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
index c02df45d10..d3527243e7 100644
--- a/libgo/go/crypto/elliptic/elliptic.go
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -367,18 +367,24 @@ func initP521() {
}
// P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3)
+//
+// The cryptographic operations are implemented using constant-time algorithms.
func P256() Curve {
initonce.Do(initAll)
return p256
}
// P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4)
+//
+// The cryptographic operations do not use constant-time algorithms.
func P384() Curve {
initonce.Do(initAll)
return p384
}
// P521 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)
+//
+// The cryptographic operations do not use constant-time algorithms.
func P521() Curve {
initonce.Do(initAll)
return p521
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
index 7f3f1a2118..902c414383 100644
--- a/libgo/go/crypto/elliptic/elliptic_test.go
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -28,7 +28,7 @@ func TestOffCurve(t *testing.T) {
b := Marshal(p224, x, y)
x1, y1 := Unmarshal(p224, b)
if x1 != nil || y1 != nil {
- t.Errorf("FAIL: unmarshalling a point not on the curve succeeded")
+ t.Errorf("FAIL: unmarshaling a point not on the curve succeeded")
}
}
diff --git a/libgo/go/crypto/elliptic/p224.go b/libgo/go/crypto/elliptic/p224.go
index 2d3fac74fb..22d0e2429c 100644
--- a/libgo/go/crypto/elliptic/p224.go
+++ b/libgo/go/crypto/elliptic/p224.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -35,7 +35,9 @@ func initP224() {
p224FromBig(&p224.b, p224.B)
}
-// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
+// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2).
+//
+// The cryptographic operations are implemented using constant-time algorithms.
func P224() Curve {
initonce.Do(initAll)
return p224
diff --git a/libgo/go/crypto/elliptic/p224_test.go b/libgo/go/crypto/elliptic/p224_test.go
index 4b26d1610e..8b4fa0483b 100644
--- a/libgo/go/crypto/elliptic/p224_test.go
+++ b/libgo/go/crypto/elliptic/p224_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/crypto/elliptic/p256.go b/libgo/go/crypto/elliptic/p256.go
index 5103e86de9..a0933dc6fb 100644
--- a/libgo/go/crypto/elliptic/p256.go
+++ b/libgo/go/crypto/elliptic/p256.go
@@ -1,8 +1,8 @@
-// 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.
-// +build !amd64
+// -build !amd64
package elliptic
@@ -17,7 +17,8 @@ type p256Curve struct {
}
var (
- p256 p256Curve
+ p256Params *CurveParams
+
// RInverse contains 1/R mod p - the inverse of the Montgomery constant
// (2**257).
p256RInverse *big.Int
@@ -25,15 +26,18 @@ var (
func initP256() {
// See FIPS 186-3, section D.2.3
- p256.CurveParams = &CurveParams{Name: "P-256"}
- p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
- p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
- p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
- p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
- p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
- p256.BitSize = 256
+ p256Params = &CurveParams{Name: "P-256"}
+ p256Params.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+ p256Params.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
+ p256Params.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
+ p256Params.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
+ p256Params.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
+ p256Params.BitSize = 256
p256RInverse, _ = new(big.Int).SetString("7fffffff00000001fffffffe8000000100000000ffffffff0000000180000000", 16)
+
+ // Arch-specific initialization, i.e. let a platform dynamically pick a P256 implementation
+ initP256Arch()
}
func (curve p256Curve) Params() *CurveParams {
@@ -47,8 +51,8 @@ func p256GetScalar(out *[32]byte, in []byte) {
n := new(big.Int).SetBytes(in)
var scalarBytes []byte
- if n.Cmp(p256.N) >= 0 {
- n.Mod(n, p256.N)
+ if n.Cmp(p256Params.N) >= 0 {
+ n.Mod(n, p256Params.N)
scalarBytes = n.Bytes()
} else {
scalarBytes = in
@@ -1056,7 +1060,7 @@ func p256ScalarBaseMult(xOut, yOut, zOut *[p256Limbs]uint32, scalar *[32]uint8)
p256CopyConditional(yOut, &ty, mask)
p256CopyConditional(zOut, &tz, mask)
// If p was not zero, then n is now non-zero.
- nIsInfinityMask &= ^pIsNoninfiniteMask
+ nIsInfinityMask &^= pIsNoninfiniteMask
}
}
}
@@ -1136,14 +1140,14 @@ func p256ScalarMult(xOut, yOut, zOut, x, y *[p256Limbs]uint32, scalar *[32]uint8
p256CopyConditional(xOut, &tx, mask)
p256CopyConditional(yOut, &ty, mask)
p256CopyConditional(zOut, &tz, mask)
- nIsInfinityMask &= ^pIsNoninfiniteMask
+ nIsInfinityMask &^= pIsNoninfiniteMask
}
}
// p256FromBig sets out = R*in.
func p256FromBig(out *[p256Limbs]uint32, in *big.Int) {
tmp := new(big.Int).Lsh(in, 257)
- tmp.Mod(tmp, p256.P)
+ tmp.Mod(tmp, p256Params.P)
for i := 0; i < p256Limbs; i++ {
if bits := tmp.Bits(); len(bits) > 0 {
@@ -1183,6 +1187,6 @@ func p256ToBig(in *[p256Limbs]uint32) *big.Int {
}
result.Mul(result, p256RInverse)
- result.Mod(result, p256.P)
+ result.Mod(result, p256Params.P)
return result
}
diff --git a/libgo/go/crypto/elliptic/p256_amd64.go b/libgo/go/crypto/elliptic/p256_amd64.go
index 586cd10c4f..8f3db0718b 100644
--- a/libgo/go/crypto/elliptic/p256_amd64.go
+++ b/libgo/go/crypto/elliptic/p256_amd64.go
@@ -10,6 +10,7 @@
// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x
// https://eprint.iacr.org/2013/816.pdf
+// +build ignore
// +build amd64
package elliptic
@@ -66,7 +67,7 @@ func p256NegCond(val []uint64, cond int)
// if cond == 0 res <- b; else res <- a
func p256MovCond(res, a, b []uint64, cond int)
-// Endianess swap
+// Endianness swap
func p256BigToLittle(res []uint64, in []byte)
func p256LittleToBig(res []byte, in []uint64)
@@ -93,10 +94,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/libgo/go/crypto/elliptic/p256_generic.go b/libgo/go/crypto/elliptic/p256_generic.go
new file mode 100644
index 0000000000..49445c3999
--- /dev/null
+++ b/libgo/go/crypto/elliptic/p256_generic.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// -build !amd64,!s390x
+
+package elliptic
+
+var (
+ p256 p256Curve
+)
+
+func initP256Arch() {
+ // Use pure Go implementation.
+ p256 = p256Curve{p256Params}
+}
diff --git a/libgo/go/crypto/elliptic/p256_s390x.go b/libgo/go/crypto/elliptic/p256_s390x.go
new file mode 100644
index 0000000000..5f99e71e5d
--- /dev/null
+++ b/libgo/go/crypto/elliptic/p256_s390x.go
@@ -0,0 +1,514 @@
+// 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
+// -build s390x
+
+package elliptic
+
+import (
+ "math/big"
+)
+
+type p256CurveFast struct {
+ *CurveParams
+}
+
+type p256Point struct {
+ x [32]byte
+ y [32]byte
+ z [32]byte
+}
+
+var (
+ p256 Curve
+ p256PreFast *[37][64]p256Point
+)
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
+
+func initP256Arch() {
+ if hasVX {
+ p256 = p256CurveFast{p256Params}
+ initTable()
+ return
+ }
+
+ // No vector support, use pure Go implementation.
+ p256 = p256Curve{p256Params}
+ return
+}
+
+func (curve p256CurveFast) Params() *CurveParams {
+ return curve.CurveParams
+}
+
+// Functions implemented in p256_asm_s390x.s
+// Montgomery multiplication modulo P256
+func p256MulAsm(res, in1, in2 []byte)
+
+// Montgomery square modulo P256
+func p256Sqr(res, in []byte) {
+ p256MulAsm(res, in, in)
+}
+
+// Montgomery multiplication by 1
+func p256FromMont(res, in []byte)
+
+// iff cond == 1 val <- -val
+func p256NegCond(val *p256Point, cond int)
+
+// if cond == 0 res <- b; else res <- a
+func p256MovCond(res, a, b *p256Point, cond int)
+
+// Constant time table access
+func p256Select(point *p256Point, table []p256Point, idx int)
+func p256SelectBase(point *p256Point, table []p256Point, idx int)
+
+// Montgomery multiplication modulo Ord(G)
+func p256OrdMul(res, in1, in2 []byte)
+
+// Montgomery square modulo Ord(G), repeated n times
+func p256OrdSqr(res, in []byte, n int) {
+ copy(res, in)
+ for i := 0; i < n; i += 1 {
+ p256OrdMul(res, res, res)
+ }
+}
+
+// Point add with P2 being affine point
+// If sign == 1 -> P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+func p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
+
+// Point add
+func p256PointAddAsm(P3, P1, P2 *p256Point)
+func p256PointDoubleAsm(P3, P1 *p256Point)
+
+func (curve p256CurveFast) Inverse(k *big.Int) *big.Int {
+ if k.Cmp(p256Params.N) >= 0 {
+ // This should never happen.
+ reducedK := new(big.Int).Mod(k, p256Params.N)
+ k = reducedK
+ }
+
+ // table will store precomputed powers of x. The 32 bytes at index
+ // i store x^(i+1).
+ var table [15][32]byte
+
+ x := fromBig(k)
+ // This code operates in the Montgomery domain where R = 2^256 mod n
+ // and n is the order of the scalar field. (See initP256 for the
+ // value.) Elements in the Montgomery domain take the form a×R and
+ // multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
+ // is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
+ // i.e. converts x into the Montgomery domain. Stored in BigEndian form
+ RR := []byte{0x66, 0xe1, 0x2d, 0x94, 0xf3, 0xd9, 0x56, 0x20, 0x28, 0x45, 0xb2, 0x39, 0x2b, 0x6b, 0xec, 0x59,
+ 0x46, 0x99, 0x79, 0x9c, 0x49, 0xbd, 0x6f, 0xa6, 0x83, 0x24, 0x4c, 0x95, 0xbe, 0x79, 0xee, 0xa2}
+
+ p256OrdMul(table[0][:], x, RR)
+
+ // Prepare the table, no need in constant time access, because the
+ // power is not a secret. (Entry 0 is never used.)
+ for i := 2; i < 16; i += 2 {
+ p256OrdSqr(table[i-1][:], table[(i/2)-1][:], 1)
+ p256OrdMul(table[i][:], table[i-1][:], table[0][:])
+ }
+
+ copy(x, table[14][:]) // f
+
+ p256OrdSqr(x[0:32], x[0:32], 4)
+ p256OrdMul(x[0:32], x[0:32], table[14][:]) // ff
+ t := make([]byte, 32)
+ copy(t, x)
+
+ p256OrdSqr(x, x, 8)
+ p256OrdMul(x, x, t) // ffff
+ copy(t, x)
+
+ p256OrdSqr(x, x, 16)
+ p256OrdMul(x, x, t) // ffffffff
+ copy(t, x)
+
+ p256OrdSqr(x, x, 64) // ffffffff0000000000000000
+ p256OrdMul(x, x, t) // ffffffff00000000ffffffff
+ p256OrdSqr(x, x, 32) // ffffffff00000000ffffffff00000000
+ p256OrdMul(x, x, t) // ffffffff00000000ffffffffffffffff
+
+ // Remaining 32 windows
+ expLo := [32]byte{0xb, 0xc, 0xe, 0x6, 0xf, 0xa, 0xa, 0xd, 0xa, 0x7, 0x1, 0x7, 0x9, 0xe, 0x8, 0x4,
+ 0xf, 0x3, 0xb, 0x9, 0xc, 0xa, 0xc, 0x2, 0xf, 0xc, 0x6, 0x3, 0x2, 0x5, 0x4, 0xf}
+ for i := 0; i < 32; i++ {
+ p256OrdSqr(x, x, 4)
+ p256OrdMul(x, x, table[expLo[i]-1][:])
+ }
+
+ // Multiplying by one in the Montgomery domain converts a Montgomery
+ // value out of the domain.
+ one := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ p256OrdMul(x, x, one)
+
+ return new(big.Int).SetBytes(x)
+}
+
+// fromBig converts a *big.Int into a format used by this code.
+func fromBig(big *big.Int) []byte {
+ // This could be done a lot more efficiently...
+ res := big.Bytes()
+ if 32 == len(res) {
+ return res
+ }
+ t := make([]byte, 32)
+ offset := 32 - len(res)
+ for i := len(res) - 1; i >= 0; i-- {
+ t[i+offset] = res[i]
+ }
+ return t
+}
+
+// p256GetMultiplier makes sure byte array will have 32 byte elements, If the scalar
+// is equal or greater than the order of the group, it's reduced modulo that order.
+func p256GetMultiplier(in []byte) []byte {
+ n := new(big.Int).SetBytes(in)
+
+ if n.Cmp(p256Params.N) >= 0 {
+ n.Mod(n, p256Params.N)
+ }
+ return fromBig(n)
+}
+
+// p256MulAsm operates in a Montgomery domain with R = 2^256 mod p, where p is the
+// underlying field of the curve. (See initP256 for the value.) Thus rr here is
+// R×R mod p. See comment in Inverse about how this is used.
+var rr = []byte{0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+
+// (This is one, in the Montgomery domain.)
+var one = []byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+
+func maybeReduceModP(in *big.Int) *big.Int {
+ if in.Cmp(p256Params.P) < 0 {
+ return in
+ }
+ return new(big.Int).Mod(in, p256Params.P)
+}
+
+func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+ var r1, r2 p256Point
+ r1.p256BaseMult(p256GetMultiplier(baseScalar))
+
+ copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r2.z[:], one)
+ p256MulAsm(r2.x[:], r2.x[:], rr[:])
+ p256MulAsm(r2.y[:], r2.y[:], rr[:])
+
+ r2.p256ScalarMult(p256GetMultiplier(scalar))
+ p256PointAddAsm(&r1, &r1, &r2)
+ return r1.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+ var r p256Point
+ r.p256BaseMult(p256GetMultiplier(scalar))
+ return r.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
+ var r p256Point
+ copy(r.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r.z[:], one)
+ p256MulAsm(r.x[:], r.x[:], rr[:])
+ p256MulAsm(r.y[:], r.y[:], rr[:])
+ r.p256ScalarMult(p256GetMultiplier(scalar))
+ return r.p256PointToAffine()
+}
+
+func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+
+ p256Inverse(zInv, p.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(zInvSq, p.x[:], zInvSq)
+ p256MulAsm(zInv, p.y[:], zInv)
+
+ p256FromMont(zInvSq, zInvSq)
+ p256FromMont(zInv, zInv)
+
+ return new(big.Int).SetBytes(zInvSq), new(big.Int).SetBytes(zInv)
+}
+
+// p256Inverse sets out to in^-1 mod p.
+func p256Inverse(out, in []byte) {
+ var stack [6 * 32]byte
+ p2 := stack[32*0 : 32*0+32]
+ p4 := stack[32*1 : 32*1+32]
+ p8 := stack[32*2 : 32*2+32]
+ p16 := stack[32*3 : 32*3+32]
+ p32 := stack[32*4 : 32*4+32]
+
+ p256Sqr(out, in)
+ p256MulAsm(p2, out, in) // 3*p
+
+ p256Sqr(out, p2)
+ p256Sqr(out, out)
+ p256MulAsm(p4, out, p2) // f*p
+
+ p256Sqr(out, p4)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(p8, out, p4) // ff*p
+
+ p256Sqr(out, p8)
+
+ for i := 0; i < 7; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p16, out, p8) // ffff*p
+
+ p256Sqr(out, p16)
+ for i := 0; i < 15; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p32, out, p16) // ffffffff*p
+
+ p256Sqr(out, p32)
+
+ for i := 0; i < 31; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, in)
+
+ for i := 0; i < 32*4; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 32; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 16; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p16)
+
+ for i := 0; i < 8; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p8)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p4)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p2)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, in)
+}
+
+func boothW5(in uint) (int, int) {
+ var s uint = ^((in >> 5) - 1)
+ var d uint = (1 << 6) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func boothW7(in uint) (int, int) {
+ var s uint = ^((in >> 7) - 1)
+ var d uint = (1 << 8) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func initTable() {
+ p256PreFast = new([37][64]p256Point) //z coordinate not used
+ basePoint := p256Point{
+ x: [32]byte{0x18, 0x90, 0x5f, 0x76, 0xa5, 0x37, 0x55, 0xc6, 0x79, 0xfb, 0x73, 0x2b, 0x77, 0x62, 0x25, 0x10,
+ 0x75, 0xba, 0x95, 0xfc, 0x5f, 0xed, 0xb6, 0x01, 0x79, 0xe7, 0x30, 0xd4, 0x18, 0xa9, 0x14, 0x3c}, //(p256.x*2^256)%p
+ y: [32]byte{0x85, 0x71, 0xff, 0x18, 0x25, 0x88, 0x5d, 0x85, 0xd2, 0xe8, 0x86, 0x88, 0xdd, 0x21, 0xf3, 0x25,
+ 0x8b, 0x4a, 0xb8, 0xe4, 0xba, 0x19, 0xe4, 0x5c, 0xdd, 0xf2, 0x53, 0x57, 0xce, 0x95, 0x56, 0x0a}, //(p256.y*2^256)%p
+ z: [32]byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //(p256.z*2^256)%p
+ }
+
+ t1 := new(p256Point)
+ t2 := new(p256Point)
+ *t2 = basePoint
+
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+ for j := 0; j < 64; j++ {
+ *t1 = *t2
+ for i := 0; i < 37; i++ {
+ // The window size is 7 so we need to double 7 times.
+ if i != 0 {
+ for k := 0; k < 7; k++ {
+ p256PointDoubleAsm(t1, t1)
+ }
+ }
+ // Convert the point to affine form. (Its values are
+ // still in Montgomery form however.)
+ p256Inverse(zInv, t1.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(t1.x[:], t1.x[:], zInvSq)
+ p256MulAsm(t1.y[:], t1.y[:], zInv)
+
+ copy(t1.z[:], basePoint.z[:])
+ // Update the table entry
+ copy(p256PreFast[i][j].x[:], t1.x[:])
+ copy(p256PreFast[i][j].y[:], t1.y[:])
+ }
+ if j == 0 {
+ p256PointDoubleAsm(t2, &basePoint)
+ } else {
+ p256PointAddAsm(t2, t2, &basePoint)
+ }
+ }
+}
+
+func (p *p256Point) p256BaseMult(scalar []byte) {
+ wvalue := (uint(scalar[31]) << 1) & 0xff
+ sel, sign := boothW7(uint(wvalue))
+ p256SelectBase(p, p256PreFast[0][:], sel)
+ p256NegCond(p, sign)
+
+ copy(p.z[:], one[:])
+ var t0 p256Point
+
+ copy(t0.z[:], one[:])
+
+ index := uint(6)
+ zero := sel
+
+ for i := 1; i < 37; i++ {
+ if index < 247 {
+ wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0xff
+ } else {
+ wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0xff
+ }
+ index += 7
+ sel, sign = boothW7(uint(wvalue))
+ p256SelectBase(&t0, p256PreFast[i][:], sel)
+ p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
+ zero |= sel
+ }
+}
+
+func (p *p256Point) p256ScalarMult(scalar []byte) {
+ // precomp is a table of precomputed points that stores powers of p
+ // from p^1 to p^16.
+ var precomp [16]p256Point
+ var t0, t1, t2, t3 p256Point
+
+ // Prepare the table
+ *&precomp[0] = *p
+
+ p256PointDoubleAsm(&t0, p)
+ p256PointDoubleAsm(&t1, &t0)
+ p256PointDoubleAsm(&t2, &t1)
+ p256PointDoubleAsm(&t3, &t2)
+ *&precomp[1] = t0 // 2
+ *&precomp[3] = t1 // 4
+ *&precomp[7] = t2 // 8
+ *&precomp[15] = t3 // 16
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ p256PointAddAsm(&t2, &t2, p)
+ *&precomp[2] = t0 // 3
+ *&precomp[4] = t1 // 5
+ *&precomp[8] = t2 // 9
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t1, &t1)
+ *&precomp[5] = t0 // 6
+ *&precomp[9] = t1 // 10
+
+ p256PointAddAsm(&t2, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ *&precomp[6] = t2 // 7
+ *&precomp[10] = t1 // 11
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t2, &t2)
+ *&precomp[11] = t0 // 12
+ *&precomp[13] = t2 // 14
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t2, &t2, p)
+ *&precomp[12] = t0 // 13
+ *&precomp[14] = t2 // 15
+
+ // Start scanning the window from top bit
+ index := uint(254)
+ var sel, sign int
+
+ wvalue := (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
+ sel, _ = boothW5(uint(wvalue))
+ p256Select(p, precomp[:], sel)
+ zero := sel
+
+ for index > 4 {
+ index -= 5
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ if index < 247 {
+ wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0x3f
+ } else {
+ wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
+ }
+
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+ zero |= sel
+ }
+
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ wvalue = (uint(scalar[31]) << 1) & 0x3f
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+}
diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go
index 3b41cde0bd..9ef9c448ee 100644
--- a/libgo/go/crypto/hmac/hmac.go
+++ b/libgo/go/crypto/hmac/hmac.go
@@ -37,26 +37,16 @@ import (
type hmac struct {
size int
blocksize int
- key, tmp []byte
+ opad, ipad []byte
outer, inner hash.Hash
}
-func (h *hmac) tmpPad(xor byte) {
- for i, k := range h.key {
- h.tmp[i] = xor ^ k
- }
- for i := len(h.key); i < h.blocksize; i++ {
- h.tmp[i] = xor
- }
-}
-
func (h *hmac) Sum(in []byte) []byte {
origLen := len(in)
in = h.inner.Sum(in)
- h.tmpPad(0x5c)
- copy(h.tmp[h.blocksize:], in[origLen:])
h.outer.Reset()
- h.outer.Write(h.tmp)
+ h.outer.Write(h.opad)
+ h.outer.Write(in[origLen:])
return h.outer.Sum(in[:origLen])
}
@@ -70,8 +60,7 @@ func (h *hmac) BlockSize() int { return h.blocksize }
func (h *hmac) Reset() {
h.inner.Reset()
- h.tmpPad(0x36)
- h.inner.Write(h.tmp[:h.blocksize])
+ h.inner.Write(h.ipad)
}
// New returns a new HMAC hash using the given hash.Hash type and key.
@@ -81,15 +70,22 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
hm.inner = h()
hm.size = hm.inner.Size()
hm.blocksize = hm.inner.BlockSize()
- hm.tmp = make([]byte, hm.blocksize+hm.size)
+ hm.ipad = make([]byte, hm.blocksize)
+ hm.opad = make([]byte, hm.blocksize)
if len(key) > hm.blocksize {
// If key is too big, hash it.
hm.outer.Write(key)
key = hm.outer.Sum(nil)
}
- hm.key = make([]byte, len(key))
- copy(hm.key, key)
- hm.Reset()
+ copy(hm.ipad, key)
+ copy(hm.opad, key)
+ for i := range hm.ipad {
+ hm.ipad[i] ^= 0x36
+ }
+ for i := range hm.opad {
+ hm.opad[i] ^= 0x5c
+ }
+ hm.inner.Write(hm.ipad)
return hm
}
@@ -98,5 +94,5 @@ func Equal(mac1, mac2 []byte) bool {
// We don't have to be constant time if the lengths of the MACs are
// different as that suggests that a completely different hash function
// was used.
- return len(mac1) == len(mac2) && subtle.ConstantTimeCompare(mac1, mac2) == 1
+ return subtle.ConstantTimeCompare(mac1, mac2) == 1
}
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
index e80b7e0baa..aac9aa96a8 100644
--- a/libgo/go/crypto/hmac/hmac_test.go
+++ b/libgo/go/crypto/hmac/hmac_test.go
@@ -568,3 +568,29 @@ func TestEqual(t *testing.T) {
t.Error("Equal accepted unequal slices")
}
}
+
+func BenchmarkHMACSHA256_1K(b *testing.B) {
+ key := make([]byte, 32)
+ buf := make([]byte, 1024)
+ h := New(sha256.New, key)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h.Write(buf)
+ h.Reset()
+ mac := h.Sum(nil)
+ buf[0] = mac[0]
+ }
+}
+
+func BenchmarkHMACSHA256_32(b *testing.B) {
+ key := make([]byte, 32)
+ buf := make([]byte, 32)
+ h := New(sha256.New, key)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h.Write(buf)
+ h.Reset()
+ mac := h.Sum(nil)
+ buf[0] = mac[0]
+ }
+}
diff --git a/libgo/go/crypto/internal/cipherhw/cipherhw_amd64.go b/libgo/go/crypto/internal/cipherhw/cipherhw_amd64.go
new file mode 100644
index 0000000000..be0d490a22
--- /dev/null
+++ b/libgo/go/crypto/internal/cipherhw/cipherhw_amd64.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package cipherhw
+
+// defined in asm_amd64.s
+func hasAESNI() bool
+
+// AESGCMSupport returns true if the Go standard library supports AES-GCM in
+// hardware.
+func AESGCMSupport() bool {
+ return hasAESNI()
+}
diff --git a/libgo/go/crypto/internal/cipherhw/cipherhw_s390x.go b/libgo/go/crypto/internal/cipherhw/cipherhw_s390x.go
new file mode 100644
index 0000000000..9cd7679598
--- /dev/null
+++ b/libgo/go/crypto/internal/cipherhw/cipherhw_s390x.go
@@ -0,0 +1,18 @@
+// 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 s390x,!gccgo,!appengine
+
+package cipherhw
+
+// hasHWSupport reports whether the AES-128, AES-192 and AES-256 cipher message
+// (KM) function codes are supported. Note that this function is expensive.
+// defined in asm_s390x.s
+func hasHWSupport() bool
+
+var hwSupport = hasHWSupport()
+
+func AESGCMSupport() bool {
+ return hwSupport
+}
diff --git a/libgo/go/crypto/internal/cipherhw/doc.go b/libgo/go/crypto/internal/cipherhw/doc.go
new file mode 100644
index 0000000000..a75fcf6496
--- /dev/null
+++ b/libgo/go/crypto/internal/cipherhw/doc.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cipherhw exposes common functions for detecting whether hardware
+// support for certain ciphers and authenticators is present.
+package cipherhw
diff --git a/libgo/go/crypto/internal/cipherhw/generic.go b/libgo/go/crypto/internal/cipherhw/generic.go
new file mode 100644
index 0000000000..64d90d3b41
--- /dev/null
+++ b/libgo/go/crypto/internal/cipherhw/generic.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!s390x gccgo appengine
+
+package cipherhw
+
+func AESGCMSupport() bool {
+ return false
+}
diff --git a/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go
index 8cd0a6358e..178fad1828 100644
--- a/libgo/go/crypto/md5/gen.go
+++ b/libgo/go/crypto/md5/gen.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go
index a3550cb7dd..ce58d5e713 100644
--- a/libgo/go/crypto/md5/md5.go
+++ b/libgo/go/crypto/md5/md5.go
@@ -89,7 +89,7 @@ func (d0 *digest) Sum(in []byte) []byte {
}
func (d *digest) checkSum() [Size]byte {
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
var tmp [64]byte
tmp[0] = 0x80
diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go
index d7956a6d20..4de38cf822 100644
--- a/libgo/go/crypto/md5/md5block_decl.go
+++ b/libgo/go/crypto/md5/md5block_decl.go
@@ -1,8 +1,9 @@
-// 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.
-// +build amd64 amd64p32 386 arm
+// +build ignore
+// -build amd64 amd64p32 386 arm ppc64le s390x
package md5
diff --git a/libgo/go/crypto/md5/md5block_generic.go b/libgo/go/crypto/md5/md5block_generic.go
index 263463e51c..c23d02b8d4 100644
--- a/libgo/go/crypto/md5/md5block_generic.go
+++ b/libgo/go/crypto/md5/md5block_generic.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!amd64p32,!386,!arm
+// -build !amd64,!amd64p32,!386,!arm,!ppc64le,!s390x
package md5
diff --git a/libgo/go/crypto/rand/eagain.go b/libgo/go/crypto/rand/eagain.go
index 2c853d0a13..7ed2f47ea6 100644
--- a/libgo/go/crypto/rand/eagain.go
+++ b/libgo/go/crypto/rand/eagain.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/crypto/rand/rand.go b/libgo/go/crypto/rand/rand.go
index ee32fa0bd6..6f7523d9d7 100644
--- a/libgo/go/crypto/rand/rand.go
+++ b/libgo/go/crypto/rand/rand.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -11,8 +11,9 @@ import "io"
// Reader is a global, shared instance of a cryptographically
// strong pseudo-random generator.
//
-// On Unix-like systems, Reader reads from /dev/urandom.
// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
+// On OpenBSD, Reader uses getentropy(2).
+// On other Unix-like systems, Reader reads from /dev/urandom.
// On Windows systems, Reader uses the CryptGenRandom API.
var Reader io.Reader
diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go
index 7d6d9e8a09..472daa7650 100644
--- a/libgo/go/crypto/rand/rand_linux.go
+++ b/libgo/go/crypto/rand/rand_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/crypto/rand/rand_openbsd.go b/libgo/go/crypto/rand/rand_openbsd.go
new file mode 100644
index 0000000000..9cc39f72d1
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_openbsd.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "internal/syscall/unix"
+)
+
+func init() {
+ altGetRandom = getRandomOpenBSD
+}
+
+func getRandomOpenBSD(p []byte) (ok bool) {
+ // getentropy(2) returns a maximum of 256 bytes per call
+ for i := 0; i < len(p); i += 256 {
+ end := i + 256
+ if len(p) < end {
+ end = len(p)
+ }
+ err := unix.GetEntropy(p[i:end])
+ if err != nil {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/crypto/rand/rand_test.go b/libgo/go/crypto/rand/rand_test.go
index e46e61d374..e45f58e4e7 100644
--- a/libgo/go/crypto/rand/rand_test.go
+++ b/libgo/go/crypto/rand/rand_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go
index 75c36e05b3..631972b92a 100644
--- a/libgo/go/crypto/rand/rand_unix.go
+++ b/libgo/go/crypto/rand/rand_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -84,7 +84,7 @@ func (hr hideAgainReader) Read(p []byte) (n int, err error) {
// systems without a reliable /dev/urandom.
// newReader returns a new pseudorandom generator that
-// seeds itself by reading from entropy. If entropy == nil,
+// seeds itself by reading from entropy. If entropy == nil,
// the generator seeds itself by reading from the system's
// random number generator, typically /dev/random.
// The Read method on the returned reader always returns
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
index 82b39b64a3..4d7511a840 100644
--- a/libgo/go/crypto/rand/rand_windows.go
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
index 5f74407850..592c57e763 100644
--- a/libgo/go/crypto/rand/util.go
+++ b/libgo/go/crypto/rand/util.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -70,7 +70,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
p.SetBytes(bytes)
- // Calculate the value mod the product of smallPrimes. If it's
+ // Calculate the value mod the product of smallPrimes. If it's
// a multiple of any of these primes we add two until it isn't.
// The probability of overflowing is minimal and can be ignored
// because we still perform Miller-Rabin tests on the result.
diff --git a/libgo/go/crypto/rand/util_test.go b/libgo/go/crypto/rand/util_test.go
index 2f7cba8364..48a2c3fc0c 100644
--- a/libgo/go/crypto/rand/util_test.go
+++ b/libgo/go/crypto/rand/util_test.go
@@ -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.
@@ -7,7 +7,9 @@ package rand_test
import (
"crypto/rand"
"math/big"
+ mathrand "math/rand"
"testing"
+ "time"
)
// https://golang.org/issue/6849.
@@ -63,3 +65,10 @@ func TestIntNegativeMaxPanics(t *testing.T) {
b := new(big.Int).SetInt64(int64(-1))
testIntPanics(t, b)
}
+
+func BenchmarkPrime(b *testing.B) {
+ r := mathrand.New(mathrand.NewSource(time.Now().UnixNano()))
+ for i := 0; i < b.N; i++ {
+ rand.Prime(r, 1024)
+ }
+}
diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go
index 9acb681bfb..bd04aee695 100644
--- a/libgo/go/crypto/rc4/rc4.go
+++ b/libgo/go/crypto/rc4/rc4.go
@@ -23,7 +23,7 @@ func (k KeySizeError) Error() string {
return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
}
-// NewCipher creates and returns a new Cipher. The key argument should be the
+// NewCipher creates and returns a new Cipher. The key argument should be the
// RC4 key, at least 1 byte and at most 256 bytes.
func NewCipher(key []byte) (*Cipher, error) {
k := len(key)
@@ -52,7 +52,7 @@ func (c *Cipher) Reset() {
}
// xorKeyStreamGeneric sets dst to the result of XORing src with the
-// key stream. Dst and src may be the same slice but otherwise should
+// key stream. Dst and src may be the same slice but otherwise should
// not overlap.
//
// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go
index 02e5b67d55..687ea237fc 100644
--- a/libgo/go/crypto/rc4/rc4_asm.go
+++ b/libgo/go/crypto/rc4/rc4_asm.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
// +build amd64 amd64p32 arm,!nacl 386
package rc4
diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go
index e34bd34cf1..bf56b51db9 100644
--- a/libgo/go/crypto/rc4/rc4_ref.go
+++ b/libgo/go/crypto/rc4/rc4_ref.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!amd64p32,!arm,!386 arm,nacl
+// -build !amd64,!amd64p32,!arm,!386 arm,nacl
package rc4
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
index 5c5f415c88..3517a8c776 100644
--- a/libgo/go/crypto/rsa/pkcs1v15.go
+++ b/libgo/go/crypto/rsa/pkcs1v15.go
@@ -24,31 +24,32 @@ type PKCS1v15DecryptOptions struct {
SessionKeyLen int
}
-// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
-// The message must be no longer than the length of the public modulus minus 11 bytes.
+// EncryptPKCS1v15 encrypts the given message with RSA and the padding
+// scheme from PKCS#1 v1.5. The message must be no longer than the
+// length of the public modulus minus 11 bytes.
//
-// The rand parameter is used as a source of entropy to ensure that encrypting
-// the same message twice doesn't result in the same ciphertext.
+// The rand parameter is used as a source of entropy to ensure that
+// encrypting the same message twice doesn't result in the same
+// ciphertext.
//
-// WARNING: use of this function to encrypt plaintexts other than session keys
-// is dangerous. Use RSA OAEP in new protocols.
-func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
+// WARNING: use of this function to encrypt plaintexts other than
+// session keys is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
if err := checkPub(pub); err != nil {
return nil, err
}
k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-11 {
- err = ErrMessageTooLong
- return
+ return nil, ErrMessageTooLong
}
// EM = 0x00 || 0x02 || PS || 0x00 || M
em := make([]byte, k)
em[1] = 2
ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):]
- err = nonZeroRandomBytes(ps, rand)
+ err := nonZeroRandomBytes(ps, rand)
if err != nil {
- return
+ return nil, err
}
em[len(em)-len(msg)-1] = 0
copy(mm, msg)
@@ -57,8 +58,7 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
c := encrypt(new(big.Int), pub, m)
copyWithLeftPad(em, c.Bytes())
- out = em
- return
+ return em, nil
}
// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
@@ -69,19 +69,18 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
// learn whether each instance returned an error then they can decrypt and
// forge signatures as if they had the private key. See
// DecryptPKCS1v15SessionKey for a way of solving this problem.
-func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error) {
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext)
if err != nil {
- return
+ return nil, err
}
if valid == 0 {
return nil, ErrDecryption
}
- out = out[index:]
- return
+ return out[index:], nil
}
// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5.
@@ -103,7 +102,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
// a random value was used (because it'll be different for the same ciphertext)
// and thus whether the padding was correct. This defeats the point of this
// function. Using at least a 16-byte key will protect against this attack.
-func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error {
if err := checkPub(&priv.PublicKey); err != nil {
return err
}
@@ -114,7 +113,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext)
if err != nil {
- return
+ return err
}
if len(em) != k {
@@ -125,7 +124,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key)))
subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):])
- return
+ return nil
}
// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if
@@ -213,21 +212,23 @@ var hashPrefixes = map[crypto.Hash][]byte{
crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
}
-// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
-// Note that hashed must be the result of hashing the input message using the
-// given hash function. If hash is zero, hashed is signed directly. This isn't
+// SignPKCS1v15 calculates the signature of hashed using
+// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. Note that hashed must
+// be the result of hashing the input message using the given hash
+// function. If hash is zero, hashed is signed directly. This isn't
// advisable except for interoperability.
//
-// If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks.
+// If rand is not nil then RSA blinding will be used to avoid timing
+// side-channel attacks.
//
-// This function is deterministic. Thus, if the set of possible messages is
-// small, an attacker may be able to build a map from messages to signatures
-// and identify the signed messages. As ever, signatures provide authenticity,
-// not confidentiality.
-func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
+// This function is deterministic. Thus, if the set of possible
+// messages is small, an attacker may be able to build a map from
+// messages to signatures and identify the signed messages. As ever,
+// signatures provide authenticity, not confidentiality.
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
- return
+ return nil, err
}
tLen := len(prefix) + hashLen
@@ -248,12 +249,11 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
m := new(big.Int).SetBytes(em)
c, err := decryptAndCheck(rand, priv, m)
if err != nil {
- return
+ return nil, err
}
copyWithLeftPad(em, c.Bytes())
- s = em
- return
+ return em, nil
}
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
@@ -261,17 +261,16 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
// function and sig is the signature. A valid signature is indicated by
// returning a nil error. If hash is zero then hashed is used directly. This
// isn't advisable except for interoperability.
-func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
- return
+ return err
}
tLen := len(prefix) + hashLen
k := (pub.N.BitLen() + 7) / 8
if k < tLen+11 {
- err = ErrVerification
- return
+ return ErrVerification
}
c := new(big.Int).SetBytes(sig)
diff --git a/libgo/go/crypto/rsa/pss.go b/libgo/go/crypto/rsa/pss.go
index 8a94589b1c..1ba194a4ad 100644
--- a/libgo/go/crypto/rsa/pss.go
+++ b/libgo/go/crypto/rsa/pss.go
@@ -64,7 +64,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt
hash.Reset()
// 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
- // zero octets. The length of PS may be 0.
+ // zero octets. The length of PS may be 0.
//
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
@@ -246,7 +246,7 @@ func (opts *PSSOptions) saltLength() int {
// Note that hashed must be the result of hashing the input message using the
// given hash function. The opts argument may be nil, in which case sensible
// defaults are used.
-func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) {
+func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error) {
saltLength := opts.saltLength()
switch saltLength {
case PSSSaltLengthAuto:
@@ -260,8 +260,8 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
}
salt := make([]byte, saltLength)
- if _, err = io.ReadFull(rand, salt); err != nil {
- return
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return nil, err
}
return signPSSWithSalt(rand, priv, hash, hashed, salt)
}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
index 0f487fe152..1de4fcb473 100644
--- a/libgo/go/crypto/rsa/rsa.go
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -14,10 +14,12 @@
// possible.
//
// Two sets of interfaces are included in this package. When a more abstract
-// interface isn't neccessary, there are functions for encrypting/decrypting
+// interface isn't necessary, there are functions for encrypting/decrypting
// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
// over the public-key primitive, the PrivateKey struct implements the
// Decrypter and Signer interfaces from the crypto package.
+//
+// The RSA operations in this package are not implemented using constant-time algorithms.
package rsa
import (
@@ -27,6 +29,7 @@ import (
"errors"
"hash"
"io"
+ "math"
"math/big"
)
@@ -191,7 +194,7 @@ func (priv *PrivateKey) Validate() error {
// GenerateKey generates an RSA keypair of the given bit size using the
// random source random (for example, crypto/rand.Reader).
-func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
+func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
return GenerateMultiPrimeKey(random, 2, bits)
}
@@ -206,14 +209,29 @@ func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
//
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
-func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) {
- priv = new(PrivateKey)
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) {
+ priv := new(PrivateKey)
priv.E = 65537
if nprimes < 2 {
return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")
}
+ if bits < 64 {
+ primeLimit := float64(uint64(1) << uint(bits/nprimes))
+ // pi approximates the number of primes less than primeLimit
+ pi := primeLimit / (math.Log(primeLimit) - 1)
+ // Generated primes start with 11 (in binary) so we can only
+ // use a quarter of them.
+ pi /= 4
+ // Use a factor of two to ensure that key generation terminates
+ // in a reasonable amount of time.
+ pi /= 2
+ if pi <= float64(nprimes) {
+ return nil, errors.New("crypto/rsa: too few primes of given length to generate an RSA key")
+ }
+ }
+
primes := make([]*big.Int, nprimes)
NextSetOfPrimes:
@@ -234,6 +252,7 @@ NextSetOfPrimes:
todo += (nprimes - 2) / 5
}
for i := 0; i < nprimes; i++ {
+ var err error
primes[i], err = rand.Prime(random, todo/(nprimes-i))
if err != nil {
return nil, err
@@ -267,9 +286,8 @@ NextSetOfPrimes:
g := new(big.Int)
priv.D = new(big.Int)
- y := new(big.Int)
e := big.NewInt(int64(priv.E))
- g.GCD(priv.D, y, e, totient)
+ g.GCD(priv.D, nil, e, totient)
if g.Cmp(bigOne) == 0 {
if priv.D.Sign() < 0 {
@@ -283,7 +301,7 @@ NextSetOfPrimes:
}
priv.Precompute()
- return
+ return priv, nil
}
// incCounter increments a four byte, big-endian counter.
@@ -346,17 +364,16 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
// values could be used to ensure that a ciphertext for one purpose cannot be
// used for another by an attacker. If not required it can be empty.
//
-// The message must be no longer than the length of the public modulus less
-// twice the hash length plus 2.
-func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) {
+// The message must be no longer than the length of the public modulus minus
+// twice the hash length, minus a further 2.
+func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
if err := checkPub(pub); err != nil {
return nil, err
}
hash.Reset()
k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-2*hash.Size()-2 {
- err = ErrMessageTooLong
- return
+ return nil, ErrMessageTooLong
}
hash.Write(label)
@@ -371,9 +388,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
db[len(db)-len(msg)-1] = 1
copy(db[len(db)-len(msg):], msg)
- _, err = io.ReadFull(random, seed)
+ _, err := io.ReadFull(random, seed)
if err != nil {
- return
+ return nil, err
}
mgf1XOR(db, hash, seed)
@@ -382,7 +399,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
m := new(big.Int)
m.SetBytes(em)
c := encrypt(new(big.Int), pub, m)
- out = c.Bytes()
+ out := c.Bytes()
if len(out) < k {
// If the output is too small, we need to left-pad with zeros.
@@ -391,7 +408,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
out = t
}
- return
+ return out, nil
}
// ErrDecryption represents a failure to decrypt a message.
@@ -565,22 +582,21 @@ func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int
//
// The label parameter must match the value given when encrypting. See
// EncryptOAEP for details.
-func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
k := (priv.N.BitLen() + 7) / 8
if len(ciphertext) > k ||
k < hash.Size()*2+2 {
- err = ErrDecryption
- return
+ return nil, ErrDecryption
}
c := new(big.Int).SetBytes(ciphertext)
m, err := decrypt(random, priv, c)
if err != nil {
- return
+ return nil, err
}
hash.Write(label)
@@ -628,12 +644,10 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
}
if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
- err = ErrDecryption
- return
+ return nil, ErrDecryption
}
- msg = rest[index+1:]
- return
+ return rest[index+1:], nil
}
// leftPad returns a new slice of length size. The contents of input are right
diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go
index 6902f9a867..84b167455f 100644
--- a/libgo/go/crypto/rsa/rsa_test.go
+++ b/libgo/go/crypto/rsa/rsa_test.go
@@ -73,6 +73,17 @@ func TestNPrimeKeyGeneration(t *testing.T) {
}
}
+func TestImpossibleKeyGeneration(t *testing.T) {
+ // This test ensures that trying to generate toy RSA keys doesn't enter
+ // an infinite loop.
+ for i := 0; i < 32; i++ {
+ GenerateKey(rand.Reader, i)
+ GenerateMultiPrimeKey(rand.Reader, 3, i)
+ GenerateMultiPrimeKey(rand.Reader, 4, i)
+ GenerateMultiPrimeKey(rand.Reader, 5, i)
+ }
+}
+
func TestGnuTLSKey(t *testing.T) {
// This is a key generated by `certtool --generate-privkey --bits 128`.
// It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
diff --git a/libgo/go/crypto/sha1/fallback_test.go b/libgo/go/crypto/sha1/fallback_test.go
new file mode 100644
index 0000000000..a47b3f4044
--- /dev/null
+++ b/libgo/go/crypto/sha1/fallback_test.go
@@ -0,0 +1,35 @@
+// 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
+// +build s390x
+
+package sha1
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜÎΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "0f58c2bb130f8182375f325c18342215255387e5"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/libgo/go/crypto/sha1/issue15617_test.go b/libgo/go/crypto/sha1/issue15617_test.go
new file mode 100644
index 0000000000..98038e5807
--- /dev/null
+++ b/libgo/go/crypto/sha1/issue15617_test.go
@@ -0,0 +1,28 @@
+// +build amd64
+// +build linux darwin
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1_test
+
+import (
+ "crypto/sha1"
+ "syscall"
+ "testing"
+)
+
+func TestOutOfBoundsRead(t *testing.T) {
+ const pageSize = 4 << 10
+ data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ panic(err)
+ }
+ if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil {
+ panic(err)
+ }
+ for i := 0; i < pageSize; i++ {
+ sha1.Sum(data[pageSize-i : pageSize])
+ }
+}
diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go
index 9f1a96e364..fbb2f94613 100644
--- a/libgo/go/crypto/sha1/sha1.go
+++ b/libgo/go/crypto/sha1/sha1.go
@@ -121,6 +121,74 @@ func (d *digest) checkSum() [Size]byte {
return digest
}
+// ConstantTimeSum computes the same result of Sum() but in constant time
+func (d0 *digest) ConstantTimeSum(in []byte) []byte {
+ d := *d0
+ hash := d.constSum()
+ return append(in, hash[:]...)
+}
+
+func (d *digest) constSum() [Size]byte {
+ var length [8]byte
+ l := d.len << 3
+ for i := uint(0); i < 8; i++ {
+ length[i] = byte(l >> (56 - 8*i))
+ }
+
+ nx := byte(d.nx)
+ t := nx - 56 // if nx < 56 then the MSB of t is one
+ mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
+
+ separator := byte(0x80) // gets reset to 0x00 once used
+ for i := byte(0); i < chunk; i++ {
+ mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
+
+ // if we reached the end of the data, replace with 0x80 or 0x00
+ d.x[i] = (^mask & separator) | (mask & d.x[i])
+
+ // zero the separator once used
+ separator &= mask
+
+ if i >= 56 {
+ // we might have to write the length here if all fit in one block
+ d.x[i] |= mask1b & length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if all fit in one block
+ block(d, d.x[:])
+
+ var digest [Size]byte
+ for i, s := range d.h {
+ digest[i*4] = mask1b & byte(s>>24)
+ digest[i*4+1] = mask1b & byte(s>>16)
+ digest[i*4+2] = mask1b & byte(s>>8)
+ digest[i*4+3] = mask1b & byte(s)
+ }
+
+ for i := byte(0); i < chunk; i++ {
+ // second block, it's always past the end of data, might start with 0x80
+ if i < 56 {
+ d.x[i] = separator
+ separator = 0
+ } else {
+ d.x[i] = length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if we actually needed the second block
+ block(d, d.x[:])
+
+ for i, s := range d.h {
+ digest[i*4] |= ^mask1b & byte(s>>24)
+ digest[i*4+1] |= ^mask1b & byte(s>>16)
+ digest[i*4+2] |= ^mask1b & byte(s>>8)
+ digest[i*4+3] |= ^mask1b & byte(s)
+ }
+
+ return digest
+}
+
// Sum returns the SHA1 checksum of the data.
func Sum(data []byte) [Size]byte {
var d digest
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
index 4a629518b7..3e59a5defe 100644
--- a/libgo/go/crypto/sha1/sha1_test.go
+++ b/libgo/go/crypto/sha1/sha1_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// SHA1 hash algorithm. See RFC 3174.
+// SHA1 hash algorithm. See RFC 3174.
package sha1
@@ -19,6 +19,7 @@ type sha1Test struct {
}
var golden = []sha1Test{
+ {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"},
{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
{"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
@@ -60,15 +61,24 @@ func TestGolden(t *testing.T) {
t.Fatalf("Sum function: sha1(%s) = %s want %s", g.in, s, g.out)
}
c := New()
- for j := 0; j < 3; j++ {
- if j < 2 {
+ for j := 0; j < 4; j++ {
+ var sum []byte
+ switch j {
+ case 0, 1:
io.WriteString(c, g.in)
- } else {
+ sum = c.Sum(nil)
+ case 2:
io.WriteString(c, g.in[0:len(g.in)/2])
c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.Sum(nil)
+ case 3:
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.(*digest).ConstantTimeSum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.(*digest).ConstantTimeSum(nil)
}
- s := fmt.Sprintf("%x", c.Sum(nil))
+ s := fmt.Sprintf("%x", sum)
if s != g.out {
t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
}
@@ -91,15 +101,17 @@ func TestBlockSize(t *testing.T) {
}
}
-// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+// 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 +132,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/libgo/go/crypto/sha1/sha1block_amd64.go b/libgo/go/crypto/sha1/sha1block_amd64.go
new file mode 100644
index 0000000000..8ef8b1faff
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1block_amd64.go
@@ -0,0 +1,36 @@
+// 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 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)
+ }
+}
diff --git a/libgo/go/crypto/sha1/sha1block_decl.go b/libgo/go/crypto/sha1/sha1block_decl.go
index 24e521af1f..bb18cbf734 100644
--- a/libgo/go/crypto/sha1/sha1block_decl.go
+++ b/libgo/go/crypto/sha1/sha1block_decl.go
@@ -1,8 +1,9 @@
-// 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.
-// +build amd64 amd64p32 arm 386
+// +build ignore
+// +build amd64p32 arm 386 s390x
package sha1
diff --git a/libgo/go/crypto/sha1/sha1block_generic.go b/libgo/go/crypto/sha1/sha1block_generic.go
index 696e26b625..e7515c915a 100644
--- a/libgo/go/crypto/sha1/sha1block_generic.go
+++ b/libgo/go/crypto/sha1/sha1block_generic.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!amd64p32,!386,!arm
+// -build !amd64,!amd64p32,!386,!arm,!s390x
package sha1
diff --git a/libgo/go/crypto/sha1/sha1block_s390x.go b/libgo/go/crypto/sha1/sha1block_s390x.go
new file mode 100644
index 0000000000..9edcbb0d4b
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1block_s390x.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package sha1
+
+// featureCheck reports whether the CPU supports the
+// SHA1 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/libgo/go/crypto/sha256/example_test.go b/libgo/go/crypto/sha256/example_test.go
new file mode 100644
index 0000000000..89d5c97778
--- /dev/null
+++ b/libgo/go/crypto/sha256/example_test.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package sha256_test
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleSum256() {
+ sum := sha256.Sum256([]byte("hello world\n"))
+ fmt.Printf("%x", sum)
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew() {
+ h := sha256.New()
+ h.Write([]byte("hello world\n"))
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := sha256.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%x", h.Sum(nil))
+}
diff --git a/libgo/go/crypto/sha256/fallback_test.go b/libgo/go/crypto/sha256/fallback_test.go
new file mode 100644
index 0000000000..1a6e6a572d
--- /dev/null
+++ b/libgo/go/crypto/sha256/fallback_test.go
@@ -0,0 +1,36 @@
+// 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
+// +build s390x
+
+package sha256
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜÎΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "e93d84ec2b22383123be9f713697fb25" +
+ "338c86e2f7d8d1ddc2d89d332dd9d76c"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go
index d84cebf2ff..74b05b92d7 100644
--- a/libgo/go/crypto/sha256/sha256.go
+++ b/libgo/go/crypto/sha256/sha256.go
@@ -137,7 +137,7 @@ func (d0 *digest) Sum(in []byte) []byte {
func (d *digest) checkSum() [Size]byte {
len := d.len
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go
index 1d883d3905..279cf5ad40 100644
--- a/libgo/go/crypto/sha256/sha256_test.go
+++ b/libgo/go/crypto/sha256/sha256_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// SHA256 hash algorithm. See FIPS 180-2.
+// SHA256 hash algorithm. See FIPS 180-2.
package sha256
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -150,6 +151,18 @@ 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")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/libgo/go/crypto/sha256/sha256block.go b/libgo/go/crypto/sha256/sha256block.go
index ca5efd156a..d43bbf0245 100644
--- a/libgo/go/crypto/sha256/sha256block.go
+++ b/libgo/go/crypto/sha256/sha256block.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !386,!amd64
-
// SHA256 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
@@ -77,7 +75,7 @@ var _K = []uint32{
0xc67178f2,
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
var w [64]uint32
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
for len(p) >= chunk {
diff --git a/libgo/go/crypto/sha256/sha256block_decl.go b/libgo/go/crypto/sha256/sha256block_decl.go
index a50c978710..e283c412c1 100644
--- a/libgo/go/crypto/sha256/sha256block_decl.go
+++ b/libgo/go/crypto/sha256/sha256block_decl.go
@@ -1,8 +1,9 @@
-// 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.
-// +build 386 amd64
+// +build ignore
+// +build 386 amd64 s390x ppc64le
package sha256
diff --git a/libgo/go/crypto/sha256/sha256block_generic.go b/libgo/go/crypto/sha256/sha256block_generic.go
new file mode 100644
index 0000000000..5cd022d269
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// -build !amd64,!386,!s390x,!ppc64le
+
+package sha256
+
+var block = blockGeneric
diff --git a/libgo/go/crypto/sha256/sha256block_s390x.go b/libgo/go/crypto/sha256/sha256block_s390x.go
new file mode 100644
index 0000000000..8e5f69d4e5
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256block_s390x.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package sha256
+
+// featureCheck reports whether the CPU supports the
+// SHA256 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/libgo/go/crypto/sha512/fallback_test.go b/libgo/go/crypto/sha512/fallback_test.go
new file mode 100644
index 0000000000..14081318ad
--- /dev/null
+++ b/libgo/go/crypto/sha512/fallback_test.go
@@ -0,0 +1,38 @@
+// 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
+// +build s390x
+
+package sha512
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜÎΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "6922e319366d677f34c504af31bfcb29" +
+ "e531c125ecd08679362bffbd6b6ebfb9" +
+ "0dcc27dfc1f3d3b16a16c0763cf43b91" +
+ "40bbf9bbb7233724e9a0c6655b185d76"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go
index e7781fd2f4..5603c90fb7 100644
--- a/libgo/go/crypto/sha512/sha512.go
+++ b/libgo/go/crypto/sha512/sha512.go
@@ -208,7 +208,7 @@ func (d0 *digest) Sum(in []byte) []byte {
}
func (d *digest) checkSum() [Size]byte {
- // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
+ // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
len := d.len
var tmp [128]byte
tmp[0] = 0x80
diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go
index 04b3d4a3cc..a3a136a19f 100644
--- a/libgo/go/crypto/sha512/sha512_test.go
+++ b/libgo/go/crypto/sha512/sha512_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// SHA512 hash algorithm. See FIPS 180-4.
+// SHA512 hash algorithm. See FIPS 180-4.
package sha512
import (
+ "crypto/rand"
"encoding/hex"
"hash"
"io"
@@ -304,6 +305,18 @@ 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")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/libgo/go/crypto/sha512/sha512block.go b/libgo/go/crypto/sha512/sha512block.go
index 648ae8f7e1..42e8d19fe8 100644
--- a/libgo/go/crypto/sha512/sha512block.go
+++ b/libgo/go/crypto/sha512/sha512block.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64
-
// SHA512 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
@@ -93,7 +91,7 @@ var _K = []uint64{
0x6c44198c4a475817,
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
var w [80]uint64
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
for len(p) >= chunk {
diff --git a/libgo/go/crypto/sha512/sha512block_decl.go b/libgo/go/crypto/sha512/sha512block_decl.go
index bef99de2e4..3859a40e32 100644
--- a/libgo/go/crypto/sha512/sha512block_decl.go
+++ b/libgo/go/crypto/sha512/sha512block_decl.go
@@ -1,8 +1,9 @@
-// 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.
-// +build amd64
+// +build ignore
+// +build amd64 s390x ppc64le
package sha512
diff --git a/libgo/go/crypto/sha512/sha512block_generic.go b/libgo/go/crypto/sha512/sha512block_generic.go
new file mode 100644
index 0000000000..fb2e6c6bf5
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// -build !amd64,!s390x,!ppc64le
+
+package sha512
+
+var block = blockGeneric
diff --git a/libgo/go/crypto/sha512/sha512block_s390x.go b/libgo/go/crypto/sha512/sha512block_s390x.go
new file mode 100644
index 0000000000..26896fcec4
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512block_s390x.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package sha512
+
+// featureCheck reports whether the CPU supports the
+// SHA512 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/libgo/go/crypto/subtle/constant_time.go b/libgo/go/crypto/subtle/constant_time.go
index 6f80e7c58d..11312b8dd4 100644
--- a/libgo/go/crypto/subtle/constant_time.go
+++ b/libgo/go/crypto/subtle/constant_time.go
@@ -6,7 +6,7 @@
// code but require careful thought to use correctly.
package subtle
-// ConstantTimeCompare returns 1 iff the two slices, x
+// ConstantTimeCompare returns 1 if and only if the two slices, x
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
diff --git a/libgo/go/crypto/tls/alert.go b/libgo/go/crypto/tls/alert.go
index 3de4834d3f..4929868257 100644
--- a/libgo/go/crypto/tls/alert.go
+++ b/libgo/go/crypto/tls/alert.go
@@ -38,6 +38,7 @@ const (
alertInappropriateFallback alert = 86
alertUserCanceled alert = 90
alertNoRenegotiation alert = 100
+ alertNoApplicationProtocol alert = 120
)
var alertText = map[alert]string{
@@ -64,14 +65,15 @@ var alertText = map[alert]string{
alertInappropriateFallback: "inappropriate fallback",
alertUserCanceled: "user canceled",
alertNoRenegotiation: "no renegotiation",
+ alertNoApplicationProtocol: "no application protocol",
}
func (e alert) String() string {
s, ok := alertText[e]
if ok {
- return s
+ return "tls: " + s
}
- return "alert(" + strconv.Itoa(int(e)) + ")"
+ return "tls: alert(" + strconv.Itoa(int(e)) + ")"
}
func (e alert) Error() string {
diff --git a/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go
index 869ffa50bd..beb0f1926d 100644
--- a/libgo/go/crypto/tls/cipher_suites.go
+++ b/libgo/go/crypto/tls/cipher_suites.go
@@ -11,8 +11,11 @@ import (
"crypto/hmac"
"crypto/rc4"
"crypto/sha1"
+ "crypto/sha256"
"crypto/x509"
"hash"
+
+ "golang_org/x/crypto/chacha20poly1305"
)
// a keyAgreement implements the client and server side of a TLS key agreement
@@ -73,25 +76,32 @@ type cipherSuite struct {
}
var cipherSuites = []*cipherSuite{
- // Ciphersuite order is chosen so that ECDHE comes before plain RSA
- // and RC4 comes before AES (because of the Lucky13 attack).
+ // Ciphersuite order is chosen so that ECDHE comes before plain RSA and
+ // AEADs are the top preference.
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
- {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+
+ // RC4-based cipher suites are disabled by default.
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -125,35 +135,84 @@ func macSHA1(version uint16, key []byte) macFunction {
copy(mac.key, key)
return mac
}
- return tls10MAC{hmac.New(sha1.New, key)}
+ return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)}
+}
+
+// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
+// so the given version is ignored.
+func macSHA256(version uint16, key []byte) macFunction {
+ return tls10MAC{hmac.New(sha256.New, key)}
}
type macFunction interface {
Size() int
- MAC(digestBuf, seq, header, data []byte) []byte
+ MAC(digestBuf, seq, header, data, extra []byte) []byte
+}
+
+type aead interface {
+ cipher.AEAD
+
+ // explicitIVLen returns the number of bytes used by the explicit nonce
+ // that is included in the record. This is eight for older AEADs and
+ // zero for modern ones.
+ explicitNonceLen() int
}
// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
// each call.
type fixedNonceAEAD struct {
- // sealNonce and openNonce are buffers where the larger nonce will be
- // constructed. Since a seal and open operation may be running
- // concurrently, there is a separate buffer for each.
- sealNonce, openNonce []byte
- aead cipher.AEAD
+ // nonce contains the fixed part of the nonce in the first four bytes.
+ nonce [12]byte
+ aead cipher.AEAD
}
-func (f *fixedNonceAEAD) NonceSize() int { return 8 }
-func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *fixedNonceAEAD) NonceSize() int { return 8 }
+func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }
func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
- copy(f.sealNonce[len(f.sealNonce)-8:], nonce)
- return f.aead.Seal(out, f.sealNonce, plaintext, additionalData)
+ copy(f.nonce[4:], nonce)
+ return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
}
func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
- copy(f.openNonce[len(f.openNonce)-8:], nonce)
- return f.aead.Open(out, f.openNonce, plaintext, additionalData)
+ copy(f.nonce[4:], nonce)
+ return f.aead.Open(out, f.nonce[:], plaintext, additionalData)
+}
+
+// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+ nonceMask [12]byte
+ aead cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int { return 8 }
+func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result, err := f.aead.Open(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result, err
}
func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
@@ -166,11 +225,20 @@ func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
panic(err)
}
- nonce1, nonce2 := make([]byte, 12), make([]byte, 12)
- copy(nonce1, fixedNonce)
- copy(nonce2, fixedNonce)
+ ret := &fixedNonceAEAD{aead: aead}
+ copy(ret.nonce[:], fixedNonce)
+ return ret
+}
+
+func aeadChaCha20Poly1305(key, fixedNonce []byte) cipher.AEAD {
+ aead, err := chacha20poly1305.New(key)
+ if err != nil {
+ panic(err)
+ }
- return &fixedNonceAEAD{nonce1, nonce2, aead}
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], fixedNonce)
+ return ret
}
// ssl30MAC implements the SSLv3 MAC function, as defined in
@@ -188,7 +256,9 @@ var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0
var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
-func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+// MAC does not offer constant timing guarantees for SSL v3.0, since it's deemed
+// useless considering the similar, protocol-level POODLE vulnerability.
+func (s ssl30MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
padLength := 48
if s.h.Size() == 20 {
padLength = 40
@@ -210,6 +280,29 @@ func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
return s.h.Sum(digestBuf[:0])
}
+type constantTimeHash interface {
+ hash.Hash
+ ConstantTimeSum(b []byte) []byte
+}
+
+// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
+// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
+type cthWrapper struct {
+ h constantTimeHash
+}
+
+func (c *cthWrapper) Size() int { return c.h.Size() }
+func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
+func (c *cthWrapper) Reset() { c.h.Reset() }
+func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
+func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
+
+func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+ return func() hash.Hash {
+ return &cthWrapper{h().(constantTimeHash)}
+ }
+}
+
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
type tls10MAC struct {
h hash.Hash
@@ -219,12 +312,19 @@ func (s tls10MAC) Size() int {
return s.h.Size()
}
-func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+// MAC is guaranteed to take constant time, as long as
+// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
+// the MAC, but is only provided to make the timing profile constant.
+func (s tls10MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
s.h.Reset()
s.h.Write(seq)
s.h.Write(header)
s.h.Write(data)
- return s.h.Sum(digestBuf[:0])
+ res := s.h.Sum(digestBuf[:0])
+ if extra != nil {
+ s.h.Write(extra)
+ }
+ return res
}
func rsaKA(version uint16) keyAgreement {
@@ -261,13 +361,16 @@ func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
return nil
}
-// A list of the possible cipher suite ids. Taken from
-// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+// A list of cipher suite IDs that are, or have been, implemented by this
+// package.
+//
+// Taken from http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
@@ -277,13 +380,17 @@ const (
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca8
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
// that the client is doing version fallback. See
- // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+ // https://tools.ietf.org/html/rfc7507.
TLS_FALLBACK_SCSV uint16 = 0x5600
)
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index c68ebfe188..de833a9056 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -7,6 +7,7 @@ package tls
import (
"container/list"
"crypto"
+ "crypto/internal/cipherhw"
"crypto/rand"
"crypto/sha512"
"crypto/x509"
@@ -14,6 +15,7 @@ import (
"fmt"
"io"
"math/big"
+ "net"
"strings"
"sync"
"time"
@@ -48,6 +50,7 @@ const (
// TLS handshake message types.
const (
+ typeHelloRequest uint8 = 0
typeClientHello uint8 = 1
typeServerHello uint8 = 2
typeNewSessionTicket uint8 = 4
@@ -94,6 +97,7 @@ const (
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
+ X25519 CurveID = 29
)
// TLS Elliptic Curve Point Formats
@@ -114,7 +118,7 @@ const (
certTypeRSAFixedDH = 3 // A certificate containing a static DH key
certTypeDSSFixedDH = 4 // A certificate containing a static DH key
- // See RFC4492 sections 3 and 5.5.
+ // See RFC 4492 sections 3 and 5.5.
certTypeECDSASign = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA.
certTypeRSAFixedECDH = 65 // A certificate containing an ECDH-capable public key, signed with RSA.
certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA.
@@ -212,6 +216,25 @@ type ClientSessionCache interface {
Put(sessionKey string, cs *ClientSessionState)
}
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3.
+type SignatureScheme uint16
+
+const (
+ PKCS1WithSHA1 SignatureScheme = 0x0201
+ PKCS1WithSHA256 SignatureScheme = 0x0401
+ PKCS1WithSHA384 SignatureScheme = 0x0501
+ PKCS1WithSHA512 SignatureScheme = 0x0601
+
+ PSSWithSHA256 SignatureScheme = 0x0804
+ PSSWithSHA384 SignatureScheme = 0x0805
+ PSSWithSHA512 SignatureScheme = 0x0806
+
+ ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+ ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+ ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+)
+
// ClientHelloInfo contains information from a ClientHello message in order to
// guide certificate selection in the GetCertificate callback.
type ClientHelloInfo struct {
@@ -236,7 +259,75 @@ type ClientHelloInfo struct {
// is being used (see
// http://tools.ietf.org/html/rfc4492#section-5.1.2).
SupportedPoints []uint8
-}
+
+ // SignatureSchemes lists the signature and hash schemes that the client
+ // is willing to verify. SignatureSchemes is set only if the Signature
+ // Algorithms Extension is being used (see
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1).
+ SignatureSchemes []SignatureScheme
+
+ // SupportedProtos lists the application protocols supported by the client.
+ // SupportedProtos is set only if the Application-Layer Protocol
+ // Negotiation Extension is being used (see
+ // https://tools.ietf.org/html/rfc7301#section-3.1).
+ //
+ // Servers can select a protocol by setting Config.NextProtos in a
+ // GetConfigForClient return value.
+ SupportedProtos []string
+
+ // SupportedVersions lists the TLS versions supported by the client.
+ // For TLS versions less than 1.3, this is extrapolated from the max
+ // version advertised by the client, so values other than the greatest
+ // might be rejected if used.
+ SupportedVersions []uint16
+
+ // Conn is the underlying net.Conn for the connection. Do not read
+ // from, or write to, this connection; that will cause the TLS
+ // connection to fail.
+ Conn net.Conn
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+ // AcceptableCAs contains zero or more, DER-encoded, X.501
+ // Distinguished Names. These are the names of root or intermediate CAs
+ // that the server wishes the returned certificate to be signed by. An
+ // empty slice indicates that the server has no preference.
+ AcceptableCAs [][]byte
+
+ // SignatureSchemes lists the signature schemes that the server is
+ // willing to verify.
+ SignatureSchemes []SignatureScheme
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+type RenegotiationSupport int
+
+const (
+ // RenegotiateNever disables renegotiation.
+ RenegotiateNever RenegotiationSupport = iota
+
+ // RenegotiateOnceAsClient allows a remote server to request
+ // renegotiation once per connection.
+ RenegotiateOnceAsClient
+
+ // RenegotiateFreelyAsClient allows a remote server to repeatedly
+ // request renegotiation.
+ RenegotiateFreelyAsClient
+)
// A Config structure is used to configure a TLS client or server.
// After one has been passed to a TLS function it must not be
@@ -253,10 +344,11 @@ type Config struct {
// If Time is nil, TLS uses time.Now.
Time func() time.Time
- // Certificates contains one or more certificate chains
- // to present to the other side of the connection.
- // Server configurations must include at least one certificate
- // or else set GetCertificate.
+ // Certificates contains one or more certificate chains to present to
+ // the other side of the connection. Server configurations must include
+ // at least one certificate or else set GetCertificate. Clients doing
+ // client-authentication may set either Certificates or
+ // GetClientCertificate.
Certificates []Certificate
// NameToCertificate maps from a certificate name to an element of
@@ -274,7 +366,54 @@ type Config struct {
// If GetCertificate is nil or returns nil, then the certificate is
// retrieved from NameToCertificate. If NameToCertificate is nil, the
// first element of Certificates will be used.
- GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
+ GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+ // GetClientCertificate, if not nil, is called when a server requests a
+ // certificate from a client. If set, the contents of Certificates will
+ // be ignored.
+ //
+ // If GetClientCertificate returns an error, the handshake will be
+ // aborted and that error will be returned. Otherwise
+ // GetClientCertificate must return a non-nil Certificate. If
+ // Certificate.Certificate is empty then no certificate will be sent to
+ // the server. If this is unacceptable to the server then it may abort
+ // the handshake.
+ //
+ // GetClientCertificate may be called multiple times for the same
+ // connection if renegotiation occurs or if TLS 1.3 is in use.
+ GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+ // GetConfigForClient, if not nil, is called after a ClientHello is
+ // received from a client. It may return a non-nil Config in order to
+ // change the Config that will be used to handle this connection. If
+ // the returned Config is nil, the original Config will be used. The
+ // Config returned by this callback may not be subsequently modified.
+ //
+ // If GetConfigForClient is nil, the Config passed to Server() will be
+ // used for all connections.
+ //
+ // Uniquely for the fields in the returned Config, session ticket keys
+ // will be duplicated from the original Config if not set.
+ // Specifically, if SetSessionTicketKeys was called on the original
+ // config but not on the returned config then the ticket keys from the
+ // original config will be copied into the new config before use.
+ // Otherwise, if SessionTicketKey was set in the original config but
+ // not in the returned config then it will be copied into the returned
+ // config before use. If neither of those cases applies then the key
+ // material from the returned config will be used for session tickets.
+ GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification by either a TLS client or server. It
+ // receives the raw ASN.1 certificates provided by the peer and also
+ // any verified chains that normal processing found. If it returns a
+ // non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled by
+ // setting InsecureSkipVerify then this callback will be considered but
+ // the verifiedChains argument will always be nil.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
// RootCAs defines the set of root certificate authorities
// that clients use when verifying server certificates.
@@ -349,15 +488,37 @@ type Config struct {
// be used.
CurvePreferences []CurveID
+ // DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+ // When true, the largest possible TLS record size is always used. When
+ // false, the size of TLS records may be adjusted in an attempt to
+ // improve latency.
+ DynamicRecordSizingDisabled bool
+
+ // Renegotiation controls what types of renegotiation are supported.
+ // The default, none, is correct for the vast majority of applications.
+ Renegotiation RenegotiationSupport
+
+ // KeyLogWriter optionally specifies a destination for TLS master secrets
+ // in NSS key log format that can be used to allow external programs
+ // such as Wireshark to decrypt TLS connections.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ // Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+ KeyLogWriter io.Writer
+
serverInitOnce sync.Once // guards calling (*Config).serverInit
- // mutex protects sessionTicketKeys
+ // mutex protects sessionTicketKeys and originalConfig.
mutex sync.RWMutex
// sessionTicketKeys contains zero or more ticket keys. If the length
// is zero, SessionTicketsDisabled must be true. The first key is used
// for new tickets and any subsequent keys can be used to decrypt old
// tickets.
sessionTicketKeys []ticketKey
+ // originalConfig is set to the Config that was passed to Server if
+ // this Config is returned by a GetConfigForClient callback. It's used
+ // by serverInit in order to copy session ticket keys if needed.
+ originalConfig *Config
}
// ticketKeyNameLen is the number of bytes of identifier that is prepended to
@@ -384,11 +545,59 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
return key
}
+// Clone returns a shallow clone of c. It is safe to clone a Config that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+ // Running serverInit ensures that it's safe to read
+ // SessionTicketsDisabled.
+ c.serverInitOnce.Do(c.serverInit)
+
+ var sessionTicketKeys []ticketKey
+ c.mutex.RLock()
+ sessionTicketKeys = c.sessionTicketKeys
+ c.mutex.RUnlock()
+
+ return &Config{
+ Rand: c.Rand,
+ Time: c.Time,
+ Certificates: c.Certificates,
+ NameToCertificate: c.NameToCertificate,
+ GetCertificate: c.GetCertificate,
+ GetClientCertificate: c.GetClientCertificate,
+ GetConfigForClient: c.GetConfigForClient,
+ VerifyPeerCertificate: c.VerifyPeerCertificate,
+ RootCAs: c.RootCAs,
+ NextProtos: c.NextProtos,
+ ServerName: c.ServerName,
+ ClientAuth: c.ClientAuth,
+ ClientCAs: c.ClientCAs,
+ InsecureSkipVerify: c.InsecureSkipVerify,
+ CipherSuites: c.CipherSuites,
+ PreferServerCipherSuites: c.PreferServerCipherSuites,
+ SessionTicketsDisabled: c.SessionTicketsDisabled,
+ SessionTicketKey: c.SessionTicketKey,
+ ClientSessionCache: c.ClientSessionCache,
+ MinVersion: c.MinVersion,
+ MaxVersion: c.MaxVersion,
+ CurvePreferences: c.CurvePreferences,
+ DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+ Renegotiation: c.Renegotiation,
+ KeyLogWriter: c.KeyLogWriter,
+ sessionTicketKeys: sessionTicketKeys,
+ // originalConfig is deliberately not duplicated.
+ }
+}
+
func (c *Config) serverInit() {
- if c.SessionTicketsDisabled {
+ if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
return
}
+ var originalConfig *Config
+ c.mutex.Lock()
+ originalConfig, c.originalConfig = c.originalConfig, nil
+ c.mutex.Unlock()
+
alreadySet := false
for _, b := range c.SessionTicketKey {
if b != 0 {
@@ -398,13 +607,21 @@ func (c *Config) serverInit() {
}
if !alreadySet {
- if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ if originalConfig != nil {
+ copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
+ } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
c.SessionTicketsDisabled = true
return
}
}
- c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+ if originalConfig != nil {
+ originalConfig.mutex.RLock()
+ c.sessionTicketKeys = originalConfig.sessionTicketKeys
+ originalConfig.mutex.RUnlock()
+ } else {
+ c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+ }
}
func (c *Config) ticketKeys() []ticketKey {
@@ -474,7 +691,7 @@ func (c *Config) maxVersion() uint16 {
return c.MaxVersion
}
-var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
if c == nil || len(c.CurvePreferences) == 0 {
@@ -510,7 +727,7 @@ func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, err
}
if len(c.Certificates) == 0 {
- return nil, errors.New("crypto/tls: no certificates configured")
+ return nil, errors.New("tls: no certificates configured")
}
if len(c.Certificates) == 1 || c.NameToCertificate == nil {
@@ -562,6 +779,26 @@ func (c *Config) BuildNameToCertificate() {
}
}
+// writeKeyLog logs client random and master secret if logging was enabled by
+// setting c.KeyLogWriter.
+func (c *Config) writeKeyLog(clientRandom, masterSecret []byte) error {
+ if c.KeyLogWriter == nil {
+ return nil
+ }
+
+ logLine := []byte(fmt.Sprintf("CLIENT_RANDOM %x %x\n", clientRandom, masterSecret))
+
+ writerMutex.Lock()
+ _, err := c.KeyLogWriter.Write(logLine)
+ writerMutex.Unlock()
+
+ return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
@@ -584,13 +821,6 @@ type Certificate struct {
Leaf *x509.Certificate
}
-// A TLS record.
-type record struct {
- contentType recordType
- major, minor uint8
- payload []byte
-}
-
type handshakeMessage interface {
marshal() []byte
unmarshal([]byte) bool
@@ -691,11 +921,46 @@ func defaultCipherSuites() []uint16 {
}
func initDefaultCipherSuites() {
+ var topCipherSuites []uint16
+ if cipherhw.AESGCMSupport() {
+ // If AES-GCM hardware is provided then prioritise AES-GCM
+ // cipher suites.
+ topCipherSuites = []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ }
+ } else {
+ // Without AES-GCM hardware, we put the ChaCha20-Poly1305
+ // cipher suites first.
+ topCipherSuites = []uint16{
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ }
+ }
+
varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+ for _, topCipher := range topCipherSuites {
+ varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher)
+ }
+
+NextCipherSuite:
for _, suite := range cipherSuites {
if suite.flags&suiteDefaultOff != 0 {
continue
}
+ for _, existing := range varDefaultCipherSuites {
+ if existing == suite.id {
+ continue NextCipherSuite
+ }
+ }
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
}
}
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index 03775685fb..03895a723f 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -28,34 +28,71 @@ type Conn struct {
isClient bool
// constant after handshake; protected by handshakeMutex
- handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
- handshakeErr error // error resulting from handshake
- vers uint16 // TLS version
- haveVers bool // version has been negotiated
- config *Config // configuration passed to constructor
+ handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ // handshakeCond, if not nil, indicates that a goroutine is committed
+ // to running the handshake for this Conn. Other goroutines that need
+ // to wait for the handshake can wait on this, under handshakeMutex.
+ handshakeCond *sync.Cond
+ handshakeErr error // error resulting from handshake
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ // handshakeComplete is true if the connection is currently transferring
+ // application data (i.e. is not currently processing a handshake).
handshakeComplete bool
- didResume bool // whether this connection was a session resumption
- cipherSuite uint16
- ocspResponse []byte // stapled OCSP response
- scts [][]byte // signed certificate timestamps from server
- peerCertificates []*x509.Certificate
+ // handshakes counts the number of handshakes performed on the
+ // connection so far. If renegotiation is disabled then this is either
+ // zero or one.
+ handshakes int
+ didResume bool // whether this connection was a session resumption
+ cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ scts [][]byte // signed certificate timestamps from server
+ peerCertificates []*x509.Certificate
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
// serverName contains the server name indicated by the client, if any.
serverName string
- // firstFinished contains the first Finished hash sent during the
- // handshake. This is the "tls-unique" channel binding value.
- firstFinished [12]byte
+ // secureRenegotiation is true if the server echoed the secure
+ // renegotiation extension. (This is meaningless as a server because
+ // renegotiation is not supported in that case.)
+ secureRenegotiation bool
+
+ // clientFinishedIsFirst is true if the client sent the first Finished
+ // message during the most recent handshake. This is recorded because
+ // the first transmitted Finished message is the tls-unique
+ // channel-binding value.
+ clientFinishedIsFirst bool
+
+ // closeNotifyErr is any error from sending the alertCloseNotify record.
+ closeNotifyErr error
+ // closeNotifySent is true if the Conn attempted to send an
+ // alertCloseNotify record.
+ closeNotifySent bool
+
+ // clientFinished and serverFinished contain the Finished message sent
+ // by the client or server in the most recent handshake. This is
+ // retained to support the renegotiation extension and tls-unique
+ // channel-binding.
+ clientFinished [12]byte
+ serverFinished [12]byte
clientProtocol string
clientProtocolFallback bool
// input/output
- in, out halfConn // in.Mutex < out.Mutex
- rawInput *block // raw input, right off the wire
- input *block // application data waiting to be read
- hand bytes.Buffer // handshake data waiting to be read
+ in, out halfConn // in.Mutex < out.Mutex
+ rawInput *block // raw input, right off the wire
+ input *block // application data waiting to be read
+ hand bytes.Buffer // handshake data waiting to be read
+ buffering bool // whether records are buffered in sendBuf
+ sendBuf []byte // a buffer of records waiting to be sent
+
+ // bytesSent counts the bytes of application data sent.
+ // packetsSent counts packets.
+ bytesSent int64
+ packetsSent int64
// activeCall is an atomic int32; the low bit is whether Close has
// been called. the rest of the bits are the number of goroutines
@@ -124,13 +161,6 @@ func (hc *halfConn) setErrorLocked(err error) error {
return err
}
-func (hc *halfConn) error() error {
- hc.Lock()
- err := hc.err
- hc.Unlock()
- return err
-}
-
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -170,25 +200,18 @@ func (hc *halfConn) incSeq() {
panic("TLS: sequence number wraparound")
}
-// resetSeq resets the sequence number to zero.
-func (hc *halfConn) resetSeq() {
- for i := range hc.seq {
- hc.seq[i] = 0
- }
-}
-
-// removePadding returns an unpadded slice, in constant time, which is a prefix
-// of the input. It also returns a byte which is equal to 255 if the padding
-// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
-func removePadding(payload []byte) ([]byte, byte) {
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func extractPadding(payload []byte) (toRemove int, good byte) {
if len(payload) < 1 {
- return payload, 0
+ return 0, 0
}
paddingLen := payload[len(payload)-1]
t := uint(len(payload)-1) - uint(paddingLen)
// if len(payload) >= (paddingLen - 1) then the MSB of t is zero
- good := byte(int32(^t) >> 31)
+ good = byte(int32(^t) >> 31)
toCheck := 255 // the maximum possible padding length
// The length of the padded data is public, so we can use an if here
@@ -211,24 +234,24 @@ func removePadding(payload []byte) ([]byte, byte) {
good &= good << 1
good = uint8(int8(good) >> 7)
- toRemove := good&paddingLen + 1
- return payload[:len(payload)-int(toRemove)], good
+ toRemove = int(paddingLen) + 1
+ return
}
-// removePaddingSSL30 is a replacement for removePadding in the case that the
+// extractPaddingSSL30 is a replacement for extractPadding in the case that the
// protocol version is SSLv3. In this version, the contents of the padding
// are random and cannot be checked.
-func removePaddingSSL30(payload []byte) ([]byte, byte) {
+func extractPaddingSSL30(payload []byte) (toRemove int, good byte) {
if len(payload) < 1 {
- return payload, 0
+ return 0, 0
}
paddingLen := int(payload[len(payload)-1]) + 1
if paddingLen > len(payload) {
- return payload, 0
+ return 0, 0
}
- return payload[:len(payload)-paddingLen], 255
+ return paddingLen, 255
}
func roundUp(a, b int) int {
@@ -254,6 +277,7 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
paddingGood := byte(255)
+ paddingLen := 0
explicitIVLen := 0
// decrypt
@@ -261,13 +285,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
switch c := hc.cipher.(type) {
case cipher.Stream:
c.XORKeyStream(payload, payload)
- case cipher.AEAD:
- explicitIVLen = 8
+ case aead:
+ explicitIVLen = c.explicitNonceLen()
if len(payload) < explicitIVLen {
return false, 0, alertBadRecordMAC
}
- nonce := payload[:8]
- payload = payload[8:]
+ nonce := payload[:explicitIVLen]
+ payload = payload[explicitIVLen:]
+
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
@@ -296,22 +324,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
c.CryptBlocks(payload, payload)
if hc.version == VersionSSL30 {
- payload, paddingGood = removePaddingSSL30(payload)
+ paddingLen, paddingGood = extractPaddingSSL30(payload)
} else {
- payload, paddingGood = removePadding(payload)
+ paddingLen, paddingGood = extractPadding(payload)
+
+ // To protect against CBC padding oracles like Lucky13, the data
+ // past paddingLen (which is secret) is passed to the MAC
+ // function as extra data, to be fed into the HMAC after
+ // computing the digest. This makes the MAC constant time as
+ // long as the digest computation is constant time and does not
+ // affect the subsequent write.
}
- b.resize(recordHeaderLen + explicitIVLen + len(payload))
-
- // note that we still have a timing side-channel in the
- // MAC check, below. An attacker can align the record
- // so that a correct padding will cause one less hash
- // block to be calculated. Then they can iteratively
- // decrypt a record by breaking each byte. See
- // "Password Interception in a SSL/TLS Channel", Brice
- // Canvel et al.
- //
- // However, our behavior matches OpenSSL, so we leak
- // only as much as they do.
default:
panic("unknown cipher type")
}
@@ -324,17 +347,19 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
// strip mac off payload, b.data
- n := len(payload) - macSize
+ n := len(payload) - macSize - paddingLen
+ n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
b.data[3] = byte(n >> 8)
b.data[4] = byte(n)
- b.resize(recordHeaderLen + explicitIVLen + n)
- remoteMAC := payload[n:]
- localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n])
+ remoteMAC := payload[n : n+macSize]
+ localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n], payload[n+macSize:])
if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
return false, 0, alertBadRecordMAC
}
hc.inDigestBuf = localMAC
+
+ b.resize(recordHeaderLen + explicitIVLen + n)
}
hc.incSeq()
@@ -362,7 +387,7 @@ func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
// mac
if hc.mac != nil {
- mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+ mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:], nil)
n := len(b.data)
b.resize(n + len(mac))
@@ -377,10 +402,13 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
switch c := hc.cipher.(type) {
case cipher.Stream:
c.XORKeyStream(payload, payload)
- case cipher.AEAD:
+ case aead:
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
b.resize(len(b.data) + c.Overhead())
nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
payload := b.data[recordHeaderLen+explicitIVLen:]
payload = payload[:payloadLen]
@@ -535,7 +563,7 @@ func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) {
func (c *Conn) readRecord(want recordType) error {
// Caller must be in sync with connection:
// handshake data if handshake not yet completed,
- // else application data. (We don't support renegotiation.)
+ // else application data.
switch want {
default:
c.sendAlert(alertInternalError)
@@ -543,12 +571,12 @@ func (c *Conn) readRecord(want recordType) error {
case recordTypeHandshake, recordTypeChangeCipherSpec:
if c.handshakeComplete {
c.sendAlert(alertInternalError)
- return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
+ return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake"))
}
case recordTypeApplicationData:
if !c.handshakeComplete {
c.sendAlert(alertInternalError)
- return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
+ return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake"))
}
}
@@ -616,9 +644,10 @@ Again:
// Process message.
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
- ok, off, err := c.in.decrypt(b)
+ ok, off, alertValue := c.in.decrypt(b)
if !ok {
- c.in.setErrorLocked(c.sendAlert(err))
+ c.in.freeBlock(b)
+ return c.in.setErrorLocked(c.sendAlert(alertValue))
}
b.off = off
data := b.data[b.off:]
@@ -672,7 +701,7 @@ Again:
case recordTypeHandshake:
// TODO(rsc): Should at least pick off connection close.
- if typ != want {
+ if typ != want && !(c.isClient && c.config.Renegotiation != RenegotiateNever) {
return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
}
c.hand.Write(data)
@@ -694,12 +723,14 @@ func (c *Conn) sendAlertLocked(err alert) error {
c.tmp[0] = alertLevelError
}
c.tmp[1] = byte(err)
- c.writeRecord(recordTypeAlert, c.tmp[0:2])
- // closeNotify is a special case in that it isn't an error:
- if err != alertCloseNotify {
- return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+
+ _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+ if err == alertCloseNotify {
+ // closeNotify is a special case in that it isn't an error.
+ return writeErr
}
- return nil
+
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
// sendAlert sends a TLS alert message.
@@ -710,16 +741,120 @@ func (c *Conn) sendAlert(err alert) error {
return c.sendAlertLocked(err)
}
-// writeRecord writes a TLS record with the given type and payload
-// to the connection and updates the record layer state.
+const (
+ // tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+ // size (MSS). A constant is used, rather than querying the kernel for
+ // the actual MSS, to avoid complexity. The value here is the IPv6
+ // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+ // bytes) and a TCP header with timestamps (32 bytes).
+ tcpMSSEstimate = 1208
+
+ // recordSizeBoostThreshold is the number of bytes of application data
+ // sent after which the TLS record size will be increased to the
+ // maximum.
+ recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+// - For latency-sensitive applications, such as web browsing, each TLS
+// record should fit in one TCP segment.
+// - For throughput-sensitive applications, such as large file transfers,
+// larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+//
// c.out.Mutex <= L.
-func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
+func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
+ if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+ return maxPlaintext
+ }
+
+ if c.bytesSent >= recordSizeBoostThreshold {
+ return maxPlaintext
+ }
+
+ // Subtract TLS overheads to get the maximum payload size.
+ macSize := 0
+ if c.out.mac != nil {
+ macSize = c.out.mac.Size()
+ }
+
+ payloadBytes := tcpMSSEstimate - recordHeaderLen - explicitIVLen
+ if c.out.cipher != nil {
+ switch ciph := c.out.cipher.(type) {
+ case cipher.Stream:
+ payloadBytes -= macSize
+ case cipher.AEAD:
+ payloadBytes -= ciph.Overhead()
+ case cbcMode:
+ blockSize := ciph.BlockSize()
+ // The payload must fit in a multiple of blockSize, with
+ // room for at least one padding byte.
+ payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+ // The MAC is appended before padding so affects the
+ // payload size directly.
+ payloadBytes -= macSize
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // Allow packet growth in arithmetic progression up to max.
+ pkt := c.packetsSent
+ c.packetsSent++
+ if pkt > 1000 {
+ return maxPlaintext // avoid overflow in multiply below
+ }
+
+ n := payloadBytes * int(pkt+1)
+ if n > maxPlaintext {
+ n = maxPlaintext
+ }
+ return n
+}
+
+// c.out.Mutex <= L.
+func (c *Conn) write(data []byte) (int, error) {
+ if c.buffering {
+ c.sendBuf = append(c.sendBuf, data...)
+ return len(data), nil
+ }
+
+ n, err := c.conn.Write(data)
+ c.bytesSent += int64(n)
+ return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+ if len(c.sendBuf) == 0 {
+ return 0, nil
+ }
+
+ n, err := c.conn.Write(c.sendBuf)
+ c.bytesSent += int64(n)
+ c.sendBuf = nil
+ c.buffering = false
+ return n, err
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
b := c.out.newBlock()
+ defer c.out.freeBlock(b)
+
+ var n int
for len(data) > 0 {
- m := len(data)
- if m > maxPlaintext {
- m = maxPlaintext
- }
explicitIVLen := 0
explicitIVIsSeq := false
@@ -731,17 +866,22 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
}
}
if explicitIVLen == 0 {
- if _, ok := c.out.cipher.(cipher.AEAD); ok {
- explicitIVLen = 8
+ if c, ok := c.out.cipher.(aead); ok {
+ explicitIVLen = c.explicitNonceLen()
+
// The AES-GCM construction in TLS has an
// explicit nonce so that the nonce can be
// random. However, the nonce is only 8 bytes
// which is too small for a secure, random
// nonce. Therefore we use the sequence number
// as the nonce.
- explicitIVIsSeq = true
+ explicitIVIsSeq = explicitIVLen > 0
}
}
+ m := len(data)
+ if maxPayload := c.maxPayloadSizeForWrite(typ, explicitIVLen); m > maxPayload {
+ m = maxPayload
+ }
b.resize(recordHeaderLen + explicitIVLen + m)
b.data[0] = byte(typ)
vers := c.vers
@@ -759,34 +899,37 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
if explicitIVIsSeq {
copy(explicitIV, c.out.seq[:])
} else {
- if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
- break
+ if _, err := io.ReadFull(c.config.rand(), explicitIV); err != nil {
+ return n, err
}
}
}
copy(b.data[recordHeaderLen+explicitIVLen:], data)
c.out.encrypt(b, explicitIVLen)
- _, err = c.conn.Write(b.data)
- if err != nil {
- break
+ if _, err := c.write(b.data); err != nil {
+ return n, err
}
n += m
data = data[m:]
}
- c.out.freeBlock(b)
if typ == recordTypeChangeCipherSpec {
- err = c.out.changeCipherSpec()
- if err != nil {
- // Cannot call sendAlert directly,
- // because we already hold c.out.Mutex.
- c.tmp[0] = alertLevelError
- c.tmp[1] = byte(err.(alert))
- c.writeRecord(recordTypeAlert, c.tmp[0:2])
- return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+ if err := c.out.changeCipherSpec(); err != nil {
+ return n, c.sendAlertLocked(err.(alert))
}
}
- return
+
+ return n, nil
+}
+
+// writeRecord writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// L < c.out.Mutex.
+func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ return c.writeRecordLocked(typ, data)
}
// readHandshake reads the next handshake message from
@@ -805,7 +948,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
data := c.hand.Bytes()
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
if n > maxHandshake {
- return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
+ c.sendAlertLocked(alertInternalError)
+ return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
}
for c.hand.Len() < 4+n {
if err := c.in.err; err != nil {
@@ -818,6 +962,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
data = c.hand.Next(4 + n)
var m handshakeMessage
switch data[0] {
+ case typeHelloRequest:
+ m = new(helloRequestMsg)
case typeClientHello:
m = new(clientHelloMsg)
case typeServerHello:
@@ -850,7 +996,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
- // The handshake message unmarshallers
+ // The handshake message unmarshalers
// expect to be able to keep references to data,
// so pass in a fresh copy that won't be overwritten.
data = append([]byte(nil), data...)
@@ -861,7 +1007,10 @@ func (c *Conn) readHandshake() (interface{}, error) {
return m, nil
}
-var errClosed = errors.New("crypto/tls: use of closed connection")
+var (
+ errClosed = errors.New("tls: use of closed connection")
+ errShutdown = errors.New("tls: protocol is shutdown")
+)
// Write writes data to the connection.
func (c *Conn) Write(b []byte) (int, error) {
@@ -892,6 +1041,10 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, alertInternalError
}
+ if c.closeNotifySent {
+ return 0, errShutdown
+ }
+
// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
// attack when using block mode ciphers due to predictable IVs.
// This can be prevented by splitting each Application Data
@@ -904,7 +1057,7 @@ func (c *Conn) Write(b []byte) (int, error) {
var m int
if len(b) > 1 && c.vers <= VersionTLS10 {
if _, ok := c.out.cipher.(cipher.BlockMode); ok {
- n, err := c.writeRecord(recordTypeApplicationData, b[:1])
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
if err != nil {
return n, c.out.setErrorLocked(err)
}
@@ -912,10 +1065,52 @@ func (c *Conn) Write(b []byte) (int, error) {
}
}
- n, err := c.writeRecord(recordTypeApplicationData, b)
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b)
return n + m, c.out.setErrorLocked(err)
}
+// handleRenegotiation processes a HelloRequest handshake message.
+// c.in.Mutex <= L
+func (c *Conn) handleRenegotiation() error {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ _, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return alertUnexpectedMessage
+ }
+
+ if !c.isClient {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+
+ switch c.config.Renegotiation {
+ case RenegotiateNever:
+ return c.sendAlert(alertNoRenegotiation)
+ case RenegotiateOnceAsClient:
+ if c.handshakes > 1 {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ case RenegotiateFreelyAsClient:
+ // Ok.
+ default:
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: unknown Renegotiation value")
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ c.handshakeComplete = false
+ if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
+ c.handshakes++
+ }
+ return c.handshakeErr
+}
+
// Read can be made to time out and return a net.Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Conn) Read(b []byte) (n int, err error) {
@@ -940,6 +1135,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// Soft error, like EAGAIN
return 0, err
}
+ if c.hand.Len() > 0 {
+ // We received handshake bytes, indicating the
+ // start of a renegotiation.
+ if err := c.handleRenegotiation(); err != nil {
+ return 0, err
+ }
+ }
}
if err := c.in.err; err != nil {
return 0, err
@@ -1006,7 +1208,7 @@ func (c *Conn) Close() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if c.handshakeComplete {
- alertErr = c.sendAlert(alertCloseNotify)
+ alertErr = c.closeNotify()
}
if err := c.conn.Close(); err != nil {
@@ -1015,18 +1217,90 @@ func (c *Conn) Close() error {
return alertErr
}
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use Close.
+func (c *Conn) CloseWrite() error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.handshakeComplete {
+ return errEarlyCloseWrite
+ }
+
+ return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.closeNotifySent {
+ c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+ c.closeNotifySent = true
+ }
+ return c.closeNotifyErr
+}
+
// Handshake runs the client or server handshake
// protocol if it has not yet been run.
// Most uses of this package need not call Handshake
// explicitly: the first Read or Write will call it automatically.
func (c *Conn) Handshake() error {
+ // c.handshakeErr and c.handshakeComplete are protected by
+ // c.handshakeMutex. In order to perform a handshake, we need to lock
+ // c.in also and c.handshakeMutex must be locked after c.in.
+ //
+ // However, if a Read() operation is hanging then it'll be holding the
+ // lock on c.in and so taking it here would cause all operations that
+ // need to check whether a handshake is pending (such as Write) to
+ // block.
+ //
+ // Thus we first take c.handshakeMutex to check whether a handshake is
+ // needed.
+ //
+ // If so then, previously, this code would unlock handshakeMutex and
+ // then lock c.in and handshakeMutex in the correct order to run the
+ // handshake. The problem was that it was possible for a Read to
+ // complete the handshake once handshakeMutex was unlocked and then
+ // keep c.in while waiting for network data. Thus a concurrent
+ // operation could be blocked on c.in.
+ //
+ // Thus handshakeCond is used to signal that a goroutine is committed
+ // to running the handshake and other goroutines can wait on it if they
+ // need. handshakeCond is protected by handshakeMutex.
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- if err := c.handshakeErr; err != nil {
- return err
+
+ for {
+ if err := c.handshakeErr; err != nil {
+ return err
+ }
+ if c.handshakeComplete {
+ return nil
+ }
+ if c.handshakeCond == nil {
+ break
+ }
+
+ c.handshakeCond.Wait()
}
- if c.handshakeComplete {
- return nil
+
+ // Set handshakeCond to indicate that this goroutine is committing to
+ // running the handshake.
+ c.handshakeCond = sync.NewCond(&c.handshakeMutex)
+ c.handshakeMutex.Unlock()
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ c.handshakeMutex.Lock()
+
+ // The handshake cannot have completed when handshakeMutex was unlocked
+ // because this goroutine set handshakeCond.
+ if c.handshakeErr != nil || c.handshakeComplete {
+ panic("handshake should not have been able to complete after handshakeCond was set")
}
if c.isClient {
@@ -1034,6 +1308,23 @@ func (c *Conn) Handshake() error {
} else {
c.handshakeErr = c.serverHandshake()
}
+ if c.handshakeErr == nil {
+ c.handshakes++
+ } else {
+ // If an error occurred during the hadshake try to flush the
+ // alert that might be left in the buffer.
+ c.flush()
+ }
+
+ if c.handshakeErr == nil && !c.handshakeComplete {
+ panic("handshake should have had a result.")
+ }
+
+ // Wake any other goroutines that are waiting for this handshake to
+ // complete.
+ c.handshakeCond.Broadcast()
+ c.handshakeCond = nil
+
return c.handshakeErr
}
@@ -1044,6 +1335,8 @@ func (c *Conn) ConnectionState() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
+ state.ServerName = c.serverName
+
if c.handshakeComplete {
state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
@@ -1052,11 +1345,14 @@ func (c *Conn) ConnectionState() ConnectionState {
state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates
state.VerifiedChains = c.verifiedChains
- state.ServerName = c.serverName
state.SignedCertificateTimestamps = c.scts
state.OCSPResponse = c.ocspResponse
if !c.didResume {
- state.TLSUnique = c.firstFinished[:]
+ if c.clientFinishedIsFirst {
+ state.TLSUnique = c.clientFinished[:]
+ } else {
+ state.TLSUnique = c.serverFinished[:]
+ }
}
}
@@ -1073,7 +1369,7 @@ func (c *Conn) OCSPResponse() []byte {
}
// VerifyHostname checks that the peer certificate chain is valid for
-// connecting to host. If so, it returns nil; if not, it returns an error
+// connecting to host. If so, it returns nil; if not, it returns an error
// describing the problem.
func (c *Conn) VerifyHostname(host string) error {
c.handshakeMutex.Lock()
diff --git a/libgo/go/crypto/tls/conn_test.go b/libgo/go/crypto/tls/conn_test.go
index ec802cad70..5e5c7a2e96 100644
--- a/libgo/go/crypto/tls/conn_test.go
+++ b/libgo/go/crypto/tls/conn_test.go
@@ -5,6 +5,9 @@
package tls
import (
+ "bytes"
+ "io"
+ "net"
"testing"
)
@@ -37,7 +40,7 @@ var paddingTests = []struct {
func TestRemovePadding(t *testing.T) {
for i, test := range paddingTests {
- payload, good := removePadding(test.in)
+ paddingLen, good := extractPadding(test.in)
expectedGood := byte(255)
if !test.good {
expectedGood = 0
@@ -45,19 +48,19 @@ func TestRemovePadding(t *testing.T) {
if good != expectedGood {
t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good)
}
- if good == 255 && len(payload) != test.expectedLen {
- t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen)
+ if good == 255 && len(test.in)-paddingLen != test.expectedLen {
+ t.Errorf("#%d: got %d, want %d", i, len(test.in)-paddingLen, test.expectedLen)
}
}
}
-var certExampleCom = `308201403081eda003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313138353835325a170d3132303933303138353835325a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31a301830160603551d11040f300d820b6578616d706c652e636f6d300b06092a864886f70d0101050341001a0b419d2c74474c6450654e5f10b32bf426ffdf55cad1c52602e7a9151513a3424c70f5960dcd682db0c33769cc1daa3fcdd3db10809d2392ed4a1bf50ced18`
+var certExampleCom = `308201713082011ba003020102021005a75ddf21014d5f417083b7a010ba2e300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343135335a170d3137303831373231343135335a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b37f0fdd67e715bf532046ac34acbd8fdc4dabe2b598588f3f58b1f12e6219a16cbfe54d2b4b665396013589262360b6721efa27d546854f17cc9aeec6751db10203010001a34d304b300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff0402300030160603551d11040f300d820b6578616d706c652e636f6d300d06092a864886f70d01010b050003410059fc487866d3d855503c8e064ca32aac5e9babcece89ec597f8b2b24c17867f4a5d3b4ece06e795bfc5448ccbd2ffca1b3433171ebf3557a4737b020565350a0`
-var certWildcardExampleCom = `308201423081efa003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303034365a170d3132303933303139303034365a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31c301a30180603551d110411300f820d2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001676f0c9e7c33c1b656ed5a6476c4e2ee9ec8e62df7407accb1875272b2edd0a22096cb2c22598d11604104d604f810eb4b5987ca6bb319c7e6ce48725c54059`
+var certWildcardExampleCom = `308201743082011ea003020102021100a7aa6297c9416a4633af8bec2958c607300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343231395a170d3137303831373231343231395a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b105afc859a711ee864114e7d2d46c2dcbe392d3506249f6c2285b0eb342cc4bf2d803677c61c0abde443f084745c1a6d62080e5664ef2cc8f50ad8a0ab8870b0203010001a34f304d300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff0402300030180603551d110411300f820d2a2e6578616d706c652e636f6d300d06092a864886f70d01010b0500034100af26088584d266e3f6566360cf862c7fecc441484b098b107439543144a2b93f20781988281e108c6d7656934e56950e1e5f2bcf38796b814ccb729445856c34`
-var certFooExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303131345a170d3132303933303139303131345a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f666f6f2e6578616d706c652e636f6d300b06092a864886f70d010105034100646a2a51f2aa2477add854b462cf5207ba16d3213ffb5d3d0eed473fbf09935019192d1d5b8ca6a2407b424cf04d97c4cd9197c83ecf81f0eab9464a1109d09f`
+var certFooExampleCom = `308201753082011fa00302010202101bbdb6070b0aeffc49008cde74deef29300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343234345a170d3137303831373231343234345a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100f00ac69d8ca2829f26216c7b50f1d4bbabad58d447706476cd89a2f3e1859943748aa42c15eedc93ac7c49e40d3b05ed645cb6b81c4efba60d961f44211a54eb0203010001a351304f300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000301a0603551d1104133011820f666f6f2e6578616d706c652e636f6d300d06092a864886f70d01010b0500034100a0957fca6d1e0f1ef4b247348c7a8ca092c29c9c0ecc1898ea6b8065d23af6d922a410dd2335a0ea15edd1394cef9f62c9e876a21e35250a0b4fe1ddceba0f36`
-var certDoubleWildcardExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303134315a170d3132303933303139303134315a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f2a2e2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001c3de267975f56ef57771c6218ef95ecc65102e57bd1defe6f7efea90d9b26cf40de5bd7ad75e46201c7f2a92aaa3e907451e9409f65e28ddb6db80d726290f6`
+var certDoubleWildcardExampleCom = `308201753082011fa003020102021039d262d8538db8ffba30d204e02ddeb5300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343331335a170d3137303831373231343331335a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100abb6bd84b8b9be3fb9415d00f22b4ddcaec7c99855b9d818c09003e084578430e5cfd2e35faa3561f036d496aa43a9ca6e6cf23c72a763c04ae324004f6cbdbb0203010001a351304f300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000301a0603551d1104133011820f2a2e2a2e6578616d706c652e636f6d300d06092a864886f70d01010b05000341004837521004a5b6bc7ad5d6c0dae60bb7ee0fa5e4825be35e2bb6ef07ee29396ca30ceb289431bcfd363888ba2207139933ac7c6369fa8810c819b2e2966abb4b`
func TestCertificateSelection(t *testing.T) {
config := Config{
@@ -116,3 +119,125 @@ func TestCertificateSelection(t *testing.T) {
t.Errorf("foo.bar.baz.example.com returned certificate %d, not 0", n)
}
}
+
+// Run with multiple crypto configs to test the logic for computing TLS record overheads.
+func runDynamicRecordSizingTest(t *testing.T, config *Config) {
+ clientConn, serverConn := net.Pipe()
+
+ serverConfig := config.Clone()
+ serverConfig.DynamicRecordSizingDisabled = false
+ tlsConn := Server(serverConn, serverConfig)
+
+ recordSizesChan := make(chan []int, 1)
+ go func() {
+ // This goroutine performs a TLS handshake over clientConn and
+ // then reads TLS records until EOF. It writes a slice that
+ // contains all the record sizes to recordSizesChan.
+ defer close(recordSizesChan)
+ defer clientConn.Close()
+
+ tlsConn := Client(clientConn, config)
+ if err := tlsConn.Handshake(); err != nil {
+ t.Errorf("Error from client handshake: %s", err)
+ return
+ }
+
+ var recordHeader [recordHeaderLen]byte
+ var record []byte
+ var recordSizes []int
+
+ for {
+ n, err := clientConn.Read(recordHeader[:])
+ if err == io.EOF {
+ break
+ }
+ if err != nil || n != len(recordHeader) {
+ t.Errorf("Error from client read: %s", err)
+ return
+ }
+
+ length := int(recordHeader[3])<<8 | int(recordHeader[4])
+ if len(record) < length {
+ record = make([]byte, length)
+ }
+
+ n, err = clientConn.Read(record[:length])
+ if err != nil || n != length {
+ t.Errorf("Error from client read: %s", err)
+ return
+ }
+
+ // The last record will be a close_notify alert, which
+ // we don't wish to record.
+ if recordType(recordHeader[0]) == recordTypeApplicationData {
+ recordSizes = append(recordSizes, recordHeaderLen+length)
+ }
+ }
+
+ recordSizesChan <- recordSizes
+ }()
+
+ if err := tlsConn.Handshake(); err != nil {
+ t.Fatalf("Error from server handshake: %s", err)
+ }
+
+ // The server writes these plaintexts in order.
+ plaintext := bytes.Join([][]byte{
+ bytes.Repeat([]byte("x"), recordSizeBoostThreshold),
+ bytes.Repeat([]byte("y"), maxPlaintext*2),
+ bytes.Repeat([]byte("z"), maxPlaintext),
+ }, nil)
+
+ if _, err := tlsConn.Write(plaintext); err != nil {
+ t.Fatalf("Error from server write: %s", err)
+ }
+ if err := tlsConn.Close(); err != nil {
+ t.Fatalf("Error from server close: %s", err)
+ }
+
+ recordSizes := <-recordSizesChan
+ if recordSizes == nil {
+ t.Fatalf("Client encountered an error")
+ }
+
+ // Drop the size of last record, which is likely to be truncated.
+ recordSizes = recordSizes[:len(recordSizes)-1]
+
+ // recordSizes should contain a series of records smaller than
+ // tcpMSSEstimate followed by some larger than maxPlaintext.
+ seenLargeRecord := false
+ for i, size := range recordSizes {
+ if !seenLargeRecord {
+ 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 {
+ t.Fatalf("Record #%d has size %d but should be full sized", i, size)
+ }
+ }
+
+ if !seenLargeRecord {
+ t.Fatalf("No large records observed")
+ }
+}
+
+func TestDynamicRecordSizingWithStreamCipher(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+ runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithCBC(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+ runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithAEAD(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+ runDynamicRecordSizingTest(t, config)
+}
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index 3c996acf87..6eda18dbfc 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -16,6 +16,7 @@ import (
"io"
"net"
"strconv"
+ "strings"
)
type clientHandshakeState struct {
@@ -28,11 +29,16 @@ type clientHandshakeState struct {
session *ClientSessionState
}
+// c.out.Mutex <= L; c.handshakeMutex <= L.
func (c *Conn) clientHandshake() error {
if c.config == nil {
c.config = defaultConfig()
}
+ // This may be a renegotiation handshake, in which case some fields
+ // need to be reset.
+ c.didResume = false
+
if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
}
@@ -49,25 +55,22 @@ func (c *Conn) clientHandshake() error {
return errors.New("tls: NextProtos values too large")
}
- sni := c.config.ServerName
- // IP address literals are not permitted as SNI values. See
- // https://tools.ietf.org/html/rfc6066#section-3.
- if net.ParseIP(sni) != nil {
- sni = ""
+ hello := &clientHelloMsg{
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ scts: true,
+ serverName: hostnameInSNI(c.config.ServerName),
+ supportedCurves: c.config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiationSupported: true,
+ alpnProtocols: c.config.NextProtos,
}
- hello := &clientHelloMsg{
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- scts: true,
- serverName: sni,
- supportedCurves: c.config.curvePreferences(),
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
- secureRenegotiation: true,
- alpnProtocols: c.config.NextProtos,
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
}
possibleCipherSuites := c.config.cipherSuites()
@@ -108,7 +111,12 @@ NextCipherSuite:
if sessionCache != nil {
hello.ticketSupported = true
+ }
+ // Session resumption is not allowed if renegotiating because
+ // renegotiation is primarily used to allow a client to send a client
+ // certificate, which would be skipped if session resumption occurred.
+ if sessionCache != nil && c.handshakes == 0 {
// Try to resume a previously negotiated TLS session, if
// available.
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
@@ -144,7 +152,9 @@ NextCipherSuite:
}
}
- c.writeRecord(recordTypeHandshake, hello.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
+ return err
+ }
msg, err := c.readHandshake()
if err != nil {
@@ -189,13 +199,14 @@ NextCipherSuite:
// Otherwise, in a full handshake, if we don't have any certificates
// configured then we will never send a CertificateVerify message and
// thus no signatures are needed in that case either.
- if isResume || len(c.config.Certificates) == 0 {
+ if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
hs.finishedHash.discardHandshakeBuffer()
}
hs.finishedHash.Write(hs.hello.marshal())
hs.finishedHash.Write(hs.serverHello.marshal())
+ c.buffering = true
if isResume {
if err := hs.establishKeys(); err != nil {
return err
@@ -203,10 +214,14 @@ NextCipherSuite:
if err := hs.readSessionTicket(); err != nil {
return err
}
- if err := hs.readFinished(c.firstFinished[:]); err != nil {
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = false
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
return err
}
- if err := hs.sendFinished(nil); err != nil {
+ if _, err := c.flush(); err != nil {
return err
}
} else {
@@ -216,13 +231,17 @@ NextCipherSuite:
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
return err
}
+ c.clientFinishedIsFirst = true
if err := hs.readSessionTicket(); err != nil {
return err
}
- if err := hs.readFinished(nil); err != nil {
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
return err
}
}
@@ -251,47 +270,69 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(certMsg.marshal())
- certs := make([]*x509.Certificate, len(certMsg.certificates))
- for i, asn1Data := range certMsg.certificates {
- cert, err := x509.ParseCertificate(asn1Data)
- if err != nil {
- c.sendAlert(alertBadCertificate)
- return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ if c.handshakes == 0 {
+ // If this is the first handshake on a connection, process and
+ // (optionally) verify the server's certificates.
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ }
+ certs[i] = cert
}
- certs[i] = cert
- }
- if !c.config.InsecureSkipVerify {
- opts := x509.VerifyOptions{
- Roots: c.config.RootCAs,
- CurrentTime: c.config.time(),
- DNSName: c.config.ServerName,
- Intermediates: x509.NewCertPool(),
+ if !c.config.InsecureSkipVerify {
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ DNSName: c.config.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+ c.verifiedChains, err = certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
}
- for i, cert := range certs {
- if i == 0 {
- continue
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certMsg.certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
}
- opts.Intermediates.AddCert(cert)
}
- c.verifiedChains, err = certs[0].Verify(opts)
- if err != nil {
- c.sendAlert(alertBadCertificate)
- return err
+
+ switch certs[0].PublicKey.(type) {
+ case *rsa.PublicKey, *ecdsa.PublicKey:
+ break
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
}
- }
- switch certs[0].PublicKey.(type) {
- case *rsa.PublicKey, *ecdsa.PublicKey:
- break
- default:
- c.sendAlert(alertUnsupportedCertificate)
- return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+ c.peerCertificates = certs
+ } else {
+ // This is a renegotiation handshake. We require that the
+ // server's identity (i.e. leaf certificate) is unchanged and
+ // thus any previous trust decision is still valid.
+ //
+ // See https://mitls.org/pages/attacks/3SHAKE for the
+ // motivation behind this requirement.
+ if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: server's identity changed during renegotiation")
+ }
}
- c.peerCertificates = certs
-
if hs.serverHello.ocspStapling {
msg, err = c.readHandshake()
if err != nil {
@@ -319,7 +360,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
hs.finishedHash.Write(skx.marshal())
- err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
@@ -336,71 +377,11 @@ func (hs *clientHandshakeState) doFullHandshake() error {
certReq, ok := msg.(*certificateRequestMsg)
if ok {
certRequested = true
-
- // RFC 4346 on the certificateAuthorities field:
- // A list of the distinguished names of acceptable certificate
- // authorities. These distinguished names may specify a desired
- // distinguished name for a root CA or for a subordinate CA;
- // thus, this message can be used to describe both known roots
- // and a desired authorization space. If the
- // certificate_authorities list is empty then the client MAY
- // send any certificate of the appropriate
- // ClientCertificateType, unless there is some external
- // arrangement to the contrary.
-
hs.finishedHash.Write(certReq.marshal())
- var rsaAvail, ecdsaAvail bool
- for _, certType := range certReq.certificateTypes {
- switch certType {
- case certTypeRSASign:
- rsaAvail = true
- case certTypeECDSASign:
- ecdsaAvail = true
- }
- }
-
- // We need to search our list of client certs for one
- // where SignatureAlgorithm is acceptable to the server and the
- // Issuer is in certReq.certificateAuthorities
- findCert:
- for i, chain := range c.config.Certificates {
- if !rsaAvail && !ecdsaAvail {
- continue
- }
-
- for j, cert := range chain.Certificate {
- x509Cert := chain.Leaf
- // parse the certificate if this isn't the leaf
- // node, or if chain.Leaf was nil
- if j != 0 || x509Cert == nil {
- if x509Cert, err = x509.ParseCertificate(cert); err != nil {
- c.sendAlert(alertInternalError)
- return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
- }
- }
-
- switch {
- case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
- case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
- default:
- continue findCert
- }
-
- if len(certReq.certificateAuthorities) == 0 {
- // they gave us an empty list, so just take the
- // first cert from c.config.Certificates
- chainToSend = &chain
- break findCert
- }
-
- for _, ca := range certReq.certificateAuthorities {
- if bytes.Equal(x509Cert.RawIssuer, ca) {
- chainToSend = &chain
- break findCert
- }
- }
- }
+ if chainToSend, err = hs.getCertificate(certReq); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
}
msg, err = c.readHandshake()
@@ -421,24 +402,26 @@ func (hs *clientHandshakeState) doFullHandshake() error {
// certificate to send.
if certRequested {
certMsg = new(certificateMsg)
- if chainToSend != nil {
- certMsg.certificates = chainToSend.Certificate
- }
+ certMsg.certificates = chainToSend.Certificate
hs.finishedHash.Write(certMsg.marshal())
- c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+ return err
+ }
}
- preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
if err != nil {
c.sendAlert(alertInternalError)
return err
}
if ckx != nil {
hs.finishedHash.Write(ckx.marshal())
- c.writeRecord(recordTypeHandshake, ckx.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
+ return err
+ }
}
- if chainToSend != nil {
+ if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{
hasSignatureAndHash: c.vers >= VersionTLS12,
}
@@ -477,10 +460,16 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(certVerify.marshal())
- c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
+ return err
+ }
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ if err := c.config.writeKeyLog(hs.hello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to write to key log: " + err.Error())
+ }
hs.finishedHash.discardHandshakeBuffer()
@@ -524,6 +513,24 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("tls: server selected unsupported compression format")
}
+ if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+ c.secureRenegotiation = true
+ if len(hs.serverHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+ }
+
+ if c.handshakes > 0 && c.secureRenegotiation {
+ var expectedSecureRenegotiation [24]byte
+ copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+ copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+ if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: incorrect renegotiation extension contents")
+ }
+ }
+
clientDidNPN := hs.hello.nextProtoNeg
clientDidALPN := len(hs.hello.alpnProtocols) > 0
serverHasNPN := hs.serverHello.nextProtoNeg
@@ -531,17 +538,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
if !clientDidNPN && serverHasNPN {
c.sendAlert(alertHandshakeFailure)
- return false, errors.New("server advertised unrequested NPN extension")
+ return false, errors.New("tls: server advertised unrequested NPN extension")
}
if !clientDidALPN && serverHasALPN {
c.sendAlert(alertHandshakeFailure)
- return false, errors.New("server advertised unrequested ALPN extension")
+ return false, errors.New("tls: server advertised unrequested ALPN extension")
}
if serverHasNPN && serverHasALPN {
c.sendAlert(alertHandshakeFailure)
- return false, errors.New("server advertised both NPN and ALPN extensions")
+ return false, errors.New("tls: server advertised both NPN and ALPN extensions")
}
if serverHasALPN {
@@ -550,22 +557,33 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
}
c.scts = hs.serverHello.scts
- if hs.serverResumedSession() {
- // Restore masterSecret and peerCerts from previous state
- hs.masterSecret = hs.session.masterSecret
- c.peerCertificates = hs.session.serverCertificates
- c.verifiedChains = hs.session.verifiedChains
- return true, nil
+ if !hs.serverResumedSession() {
+ return false, nil
}
- return false, nil
+
+ if hs.session.vers != c.vers {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different version")
+ }
+
+ if hs.session.cipherSuite != hs.suite.id {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different cipher suite")
+ }
+
+ // Restore masterSecret and peerCerts from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ c.verifiedChains = hs.session.verifiedChains
+ return true, nil
}
func (hs *clientHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.in.error(); err != nil {
- return err
+ if c.in.err != nil {
+ return c.in.err
}
msg, err := c.readHandshake()
@@ -621,7 +639,9 @@ func (hs *clientHandshakeState) readSessionTicket() error {
func (hs *clientHandshakeState) sendFinished(out []byte) error {
c := hs.c
- c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+ return err
+ }
if hs.serverHello.nextProtoNeg {
nextProto := new(nextProtoMsg)
proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
@@ -630,17 +650,132 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
c.clientProtocolFallback = fallback
hs.finishedHash.Write(nextProto.marshal())
- c.writeRecord(recordTypeHandshake, nextProto.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, nextProto.marshal()); err != nil {
+ return err
+ }
}
finished := new(finishedMsg)
finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
hs.finishedHash.Write(finished.marshal())
- c.writeRecord(recordTypeHandshake, finished.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+ return err
+ }
copy(out, finished.verifyData)
return nil
}
+// tls11SignatureSchemes contains the signature schemes that we synthesise for
+// a TLS <= 1.1 connection, based on the supported certificate types.
+var tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
+
+const (
+ // tls11SignatureSchemesNumECDSA is the number of initial elements of
+ // tls11SignatureSchemes that use ECDSA.
+ tls11SignatureSchemesNumECDSA = 3
+ // tls11SignatureSchemesNumRSA is the number of trailing elements of
+ // tls11SignatureSchemes that use RSA.
+ tls11SignatureSchemesNumRSA = 4
+)
+
+func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) {
+ c := hs.c
+
+ var rsaAvail, ecdsaAvail bool
+ for _, certType := range certReq.certificateTypes {
+ switch certType {
+ case certTypeRSASign:
+ rsaAvail = true
+ case certTypeECDSASign:
+ ecdsaAvail = true
+ }
+ }
+
+ if c.config.GetClientCertificate != nil {
+ var signatureSchemes []SignatureScheme
+
+ if !certReq.hasSignatureAndHash {
+ // Prior to TLS 1.2, the signature schemes were not
+ // included in the certificate request message. In this
+ // case we use a plausible list based on the acceptable
+ // certificate types.
+ signatureSchemes = tls11SignatureSchemes
+ if !ecdsaAvail {
+ signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:]
+ }
+ if !rsaAvail {
+ signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA]
+ }
+ } else {
+ signatureSchemes = make([]SignatureScheme, 0, len(certReq.signatureAndHashes))
+ for _, sah := range certReq.signatureAndHashes {
+ signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature))
+ }
+ }
+
+ return c.config.GetClientCertificate(&CertificateRequestInfo{
+ AcceptableCAs: certReq.certificateAuthorities,
+ SignatureSchemes: signatureSchemes,
+ })
+ }
+
+ // RFC 4346 on the certificateAuthorities field: A list of the
+ // distinguished names of acceptable certificate authorities.
+ // These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA;
+ // thus, this message can be used to describe both known roots
+ // and a desired authorization space. If the
+ // certificate_authorities list is empty then the client MAY
+ // send any certificate of the appropriate
+ // ClientCertificateType, unless there is some external
+ // arrangement to the contrary.
+
+ // We need to search our list of client certs for one
+ // where SignatureAlgorithm is acceptable to the server and the
+ // Issuer is in certReq.certificateAuthorities
+findCert:
+ for i, chain := range c.config.Certificates {
+ if !rsaAvail && !ecdsaAvail {
+ continue
+ }
+
+ for j, cert := range chain.Certificate {
+ x509Cert := chain.Leaf
+ // parse the certificate if this isn't the leaf
+ // node, or if chain.Leaf was nil
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+ }
+ }
+
+ switch {
+ case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
+ case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
+ default:
+ continue findCert
+ }
+
+ if len(certReq.certificateAuthorities) == 0 {
+ // they gave us an empty list, so just take the
+ // first cert from c.config.Certificates
+ return &chain, nil
+ }
+
+ for _, ca := range certReq.certificateAuthorities {
+ if bytes.Equal(x509Cert.RawIssuer, ca) {
+ return &chain, nil
+ }
+ }
+ }
+ }
+
+ // No acceptable certificate found. Don't send a certificate.
+ return new(Certificate), nil
+}
+
// clientSessionCacheKey returns a key used to cache sessionTickets that could
// be used to resume previously negotiated TLS sessions with a server.
func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
@@ -665,3 +800,23 @@ func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
return protos[0], true
}
+
+// hostnameInSNI converts name into an approriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See https://tools.ietf.org/html/rfc6066#section-3.
+func hostnameInSNI(name string) string {
+ host := name
+ if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+ host = host[1 : len(host)-1]
+ }
+ if i := strings.LastIndex(host, "%"); i > 0 {
+ host = host[:i]
+ }
+ if net.ParseIP(host) != nil {
+ return ""
+ }
+ if len(name) > 0 && name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+ return name
+}
diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go
index f78cc46935..5851f897f9 100644
--- a/libgo/go/crypto/tls/handshake_client_test.go
+++ b/libgo/go/crypto/tls/handshake_client_test.go
@@ -12,14 +12,17 @@ import (
"encoding/base64"
"encoding/binary"
"encoding/pem"
+ "errors"
"fmt"
"io"
+ "math/big"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
+ "sync"
"testing"
"time"
)
@@ -27,14 +30,80 @@ import (
// Note: see comment in handshake_test.go for details of how the reference
// tests work.
-// blockingSource is an io.Reader that blocks a Read call until it's closed.
-type blockingSource chan bool
+// opensslInputEvent enumerates possible inputs that can be sent to an `openssl
+// s_client` process.
+type opensslInputEvent int
+
+const (
+ // opensslRenegotiate causes OpenSSL to request a renegotiation of the
+ // connection.
+ opensslRenegotiate opensslInputEvent = iota
+
+ // opensslSendBanner causes OpenSSL to send the contents of
+ // opensslSentinel on the connection.
+ opensslSendSentinel
+)
+
+const opensslSentinel = "SENTINEL\n"
+
+type opensslInput chan opensslInputEvent
+
+func (i opensslInput) Read(buf []byte) (n int, err error) {
+ for event := range i {
+ switch event {
+ case opensslRenegotiate:
+ return copy(buf, []byte("R\n")), nil
+ case opensslSendSentinel:
+ return copy(buf, []byte(opensslSentinel)), nil
+ default:
+ panic("unknown event")
+ }
+ }
-func (b blockingSource) Read([]byte) (n int, err error) {
- <-b
return 0, io.EOF
}
+// opensslOutputSink is an io.Writer that receives the stdout and stderr from
+// an `openssl` process and sends a value to handshakeComplete when it sees a
+// log message from a completed server handshake.
+type opensslOutputSink struct {
+ handshakeComplete chan struct{}
+ all []byte
+ line []byte
+}
+
+func newOpensslOutputSink() *opensslOutputSink {
+ return &opensslOutputSink{make(chan struct{}), nil, nil}
+}
+
+// opensslEndOfHandshake is a message that the “openssl s_server†tool will
+// print when a handshake completes if run with “-stateâ€.
+const opensslEndOfHandshake = "SSL_accept:SSLv3/TLS write finished"
+
+func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
+ o.line = append(o.line, data...)
+ o.all = append(o.all, data...)
+
+ for {
+ i := bytes.Index(o.line, []byte{'\n'})
+ if i < 0 {
+ break
+ }
+
+ if bytes.Equal([]byte(opensslEndOfHandshake), o.line[:i]) {
+ o.handshakeComplete <- struct{}{}
+ }
+ o.line = o.line[i+1:]
+ }
+
+ return len(data), nil
+}
+
+func (o *opensslOutputSink) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(o.all)
+ return int64(n), err
+}
+
// clientTest represents a test of the TLS client handshake against a reference
// implementation.
type clientTest struct {
@@ -60,15 +129,25 @@ type clientTest struct {
// ConnectionState of the resulting connection. It returns a non-nil
// error if the ConnectionState is unacceptable.
validate func(ConnectionState) error
+ // numRenegotiations is the number of times that the connection will be
+ // renegotiated.
+ numRenegotiations int
+ // renegotiationExpectedToFail, if not zero, is the number of the
+ // renegotiation attempt that is expected to fail.
+ renegotiationExpectedToFail int
+ // checkRenegotiationError, if not nil, is called with any error
+ // arising from renegotiation. It can map expected errors to nil to
+ // ignore them.
+ checkRenegotiationError func(renegotiationNum int, err error) error
}
var defaultServerCommand = []string{"openssl", "s_server"}
// connFromCommand starts the reference server process, connects to it and
-// returns a recordingConn for the connection. The stdin return value is a
-// blockingSource for the stdin of the child process. It must be closed before
+// returns a recordingConn for the connection. The stdin return value is an
+// opensslInput for the stdin of the child process. It must be closed before
// Waiting for child.
-func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) {
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin opensslInput, stdout *opensslOutputSink, err error) {
cert := testRSACertificate
if len(test.cert) > 0 {
cert = test.cert
@@ -131,14 +210,28 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
command = append(command, "-serverinfo", serverInfoPath)
}
+ if test.numRenegotiations > 0 {
+ found := false
+ for _, flag := range command[1:] {
+ if flag == "-state" {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ panic("-state flag missing to OpenSSL. You need this if testing renegotiation")
+ }
+ }
+
cmd := exec.Command(command[0], command[1:]...)
- stdin = blockingSource(make(chan bool))
+ stdin = opensslInput(make(chan opensslInputEvent))
cmd.Stdin = stdin
- var out bytes.Buffer
- cmd.Stdout = &out
- cmd.Stderr = &out
+ out := newOpensslOutputSink()
+ cmd.Stdout = out
+ cmd.Stderr = out
if err := cmd.Start(); err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// OpenSSL does print an "ACCEPT" banner, but it does so *before*
@@ -160,14 +253,14 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
close(stdin)
out.WriteTo(os.Stdout)
cmd.Process.Kill()
- return nil, nil, nil, cmd.Wait()
+ return nil, nil, nil, nil, cmd.Wait()
}
record := &recordingConn{
Conn: tcpConn,
}
- return record, cmd, stdin, nil
+ return record, cmd, stdin, out, nil
}
func (test *clientTest) dataPath() string {
@@ -184,14 +277,17 @@ func (test *clientTest) loadData() (flows [][]byte, err error) {
}
func (test *clientTest) run(t *testing.T, write bool) {
+ checkOpenSSLVersion(t)
+
var clientConn, serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
- var stdin blockingSource
+ var stdin opensslInput
+ var stdout *opensslOutputSink
if write {
var err error
- recordingConn, childProcess, stdin, err = test.connFromCommand()
+ recordingConn, childProcess, stdin, stdout, err = test.connFromCommand()
if err != nil {
t.Fatalf("Failed to start subcommand: %s", err)
}
@@ -208,17 +304,77 @@ func (test *clientTest) run(t *testing.T, write bool) {
doneChan := make(chan bool)
go func() {
+ defer func() { doneChan <- true }()
+ defer clientConn.Close()
+ defer client.Close()
+
if _, err := client.Write([]byte("hello\n")); err != nil {
t.Errorf("Client.Write failed: %s", err)
+ return
+ }
+
+ for i := 1; i <= test.numRenegotiations; i++ {
+ // The initial handshake will generate a
+ // handshakeComplete signal which needs to be quashed.
+ if i == 1 && write {
+ <-stdout.handshakeComplete
+ }
+
+ // OpenSSL will try to interleave application data and
+ // a renegotiation if we send both concurrently.
+ // Therefore: ask OpensSSL to start a renegotiation, run
+ // a goroutine to call client.Read and thus process the
+ // renegotiation request, watch for OpenSSL's stdout to
+ // indicate that the handshake is complete and,
+ // finally, have OpenSSL write something to cause
+ // client.Read to complete.
+ if write {
+ stdin <- opensslRenegotiate
+ }
+
+ signalChan := make(chan struct{})
+
+ go func() {
+ defer func() { signalChan <- struct{}{} }()
+
+ buf := make([]byte, 256)
+ n, err := client.Read(buf)
+
+ if test.checkRenegotiationError != nil {
+ newErr := test.checkRenegotiationError(i, err)
+ if err != nil && newErr == nil {
+ return
+ }
+ err = newErr
+ }
+
+ if err != nil {
+ t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
+ return
+ }
+
+ buf = buf[:n]
+ if !bytes.Equal([]byte(opensslSentinel), buf) {
+ t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
+ }
+
+ if expected := i + 1; client.handshakes != expected {
+ t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
+ }
+ }()
+
+ if write && test.renegotiationExpectedToFail != i {
+ <-stdout.handshakeComplete
+ stdin <- opensslSendSentinel
+ }
+ <-signalChan
}
+
if test.validate != nil {
if err := test.validate(client.ConnectionState()); err != nil {
t.Errorf("validate callback returned error: %s", err)
}
}
- client.Close()
- clientConn.Close()
- doneChan <- true
}()
if !write {
@@ -257,7 +413,7 @@ func (test *clientTest) run(t *testing.T, write bool) {
childProcess.Process.Kill()
childProcess.Wait()
if len(recordingConn.flows) < 3 {
- childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ os.Stdout.Write(childProcess.Stdout.(*opensslOutputSink).all)
t.Fatalf("Client connection didn't work")
}
recordingConn.WriteTo(out)
@@ -265,7 +421,26 @@ func (test *clientTest) run(t *testing.T, write bool) {
}
}
+var (
+ didParMu sync.Mutex
+ didPar = map[*testing.T]bool{}
+)
+
+// setParallel calls t.Parallel once. If you call it twice, it would
+// panic.
+func setParallel(t *testing.T) {
+ didParMu.Lock()
+ v := didPar[t]
+ didPar[t] = true
+ didParMu.Unlock()
+ if !v {
+ t.Parallel()
+ }
+}
+
func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) {
+ setParallel(t)
+
test := *template
test.name = prefix + test.name
if len(test.command) == 0 {
@@ -356,15 +531,82 @@ func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
runClientTestTLS12(t, test)
}
+func TestHandshakeClientAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &clientTest{
+ name: "X25519-ECDHE-RSA-AES-GCM",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-RSA-CHACHA20-POLY1305",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-ECDSA-CHACHA20-POLY1305",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-CHACHA20-POLY1305"},
+ config: config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
func TestHandshakeClientCertRSA(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
config.Certificates = []Certificate{cert}
test := &clientTest{
name: "ClientCert-RSA-RSA",
- command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
- config: &config,
+ command: []string{"openssl", "s_server", "-cipher", "AES128", "-verify", "1"},
+ config: config,
}
runClientTestTLS10(t, test)
@@ -373,7 +615,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
test = &clientTest{
name: "ClientCert-RSA-ECDSA",
command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
- config: &config,
+ config: config,
cert: testECDSACertificate,
key: testECDSAPrivateKey,
}
@@ -384,7 +626,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
test = &clientTest{
name: "ClientCert-RSA-AES256-GCM-SHA384",
command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"},
- config: &config,
+ config: config,
cert: testRSACertificate,
key: testRSAPrivateKey,
}
@@ -393,14 +635,14 @@ func TestHandshakeClientCertRSA(t *testing.T) {
}
func TestHandshakeClientCertECDSA(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
config.Certificates = []Certificate{cert}
test := &clientTest{
name: "ClientCert-ECDSA-RSA",
- command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
- config: &config,
+ command: []string{"openssl", "s_server", "-cipher", "AES128", "-verify", "1"},
+ config: config,
}
runClientTestTLS10(t, test)
@@ -409,7 +651,7 @@ func TestHandshakeClientCertECDSA(t *testing.T) {
test = &clientTest{
name: "ClientCert-ECDSA-ECDSA",
command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
- config: &config,
+ config: config,
cert: testECDSACertificate,
key: testECDSAPrivateKey,
}
@@ -448,7 +690,7 @@ func TestClientResumption(t *testing.T) {
t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
}
if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
- t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
+ t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifiedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
}
}
@@ -470,13 +712,14 @@ func TestClientResumption(t *testing.T) {
t.Fatal("first ticket doesn't match ticket after resumption")
}
- key2 := randomKey()
- serverConfig.SetSessionTicketKeys([][32]byte{key2})
+ key1 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key1})
testResumeState("InvalidSessionTicketKey", false)
testResumeState("ResumeAfterInvalidSessionTicketKey", true)
- serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2})
+ key2 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key2, key1})
ticket = getTicket()
testResumeState("KeyChange", true)
if bytes.Equal(ticket, getTicket()) {
@@ -484,6 +727,16 @@ func TestClientResumption(t *testing.T) {
}
testResumeState("KeyChangeFinish", true)
+ // Reset serverConfig to ensure that calling SetSessionTicketKeys
+ // before the serverConfig is used works.
+ serverConfig = &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ serverConfig.SetSessionTicketKeys([][32]byte{key2})
+
+ testResumeState("FreshConfig", true)
+
clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
testResumeState("DifferentCipherSuite", false)
testResumeState("DifferentCipherSuiteRecovers", true)
@@ -538,8 +791,59 @@ func TestLRUClientSessionCache(t *testing.T) {
}
}
+func TestKeyLog(t *testing.T) {
+ var serverBuf, clientBuf bytes.Buffer
+
+ clientConfig := testConfig.Clone()
+ clientConfig.KeyLogWriter = &clientBuf
+
+ serverConfig := testConfig.Clone()
+ serverConfig.KeyLogWriter = &serverBuf
+
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ go func() {
+ defer close(done)
+
+ if err := Server(s, serverConfig).Handshake(); err != nil {
+ t.Errorf("server: %s", err)
+ return
+ }
+ s.Close()
+ }()
+
+ if err := Client(c, clientConfig).Handshake(); err != nil {
+ t.Fatalf("client: %s", err)
+ }
+
+ c.Close()
+ <-done
+
+ checkKeylogLine := func(side, loggedLine string) {
+ if len(loggedLine) == 0 {
+ t.Fatalf("%s: no keylog line was produced", side)
+ }
+ const expectedLen = 13 /* "CLIENT_RANDOM" */ +
+ 1 /* space */ +
+ 32*2 /* hex client nonce */ +
+ 1 /* space */ +
+ 48*2 /* hex master secret */ +
+ 1 /* new line */
+ if len(loggedLine) != expectedLen {
+ t.Fatalf("%s: keylog line has incorrect length (want %d, got %d): %q", side, expectedLen, len(loggedLine), loggedLine)
+ }
+ if !strings.HasPrefix(loggedLine, "CLIENT_RANDOM "+strings.Repeat("0", 64)+" ") {
+ t.Fatalf("%s: keylog line has incorrect structure or nonce: %q", side, loggedLine)
+ }
+ }
+
+ checkKeylogLine("client", string(clientBuf.Bytes()))
+ checkKeylogLine("server", string(serverBuf.Bytes()))
+}
+
func TestHandshakeClientALPNMatch(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.NextProtos = []string{"proto2", "proto1"}
test := &clientTest{
@@ -547,7 +851,7 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
// Note that this needs OpenSSL 1.0.2 because that is the first
// version that supports the -alpn flag.
command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
- config: &config,
+ config: config,
validate: func(state ConnectionState) error {
// The server's preferences should override the client.
if state.NegotiatedProtocol != "proto1" {
@@ -559,32 +863,11 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
runClientTestTLS12(t, test)
}
-func TestHandshakeClientALPNNoMatch(t *testing.T) {
- config := *testConfig
- config.NextProtos = []string{"proto3"}
-
- test := &clientTest{
- name: "ALPN-NoMatch",
- // Note that this needs OpenSSL 1.0.2 because that is the first
- // version that supports the -alpn flag.
- command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
- config: &config,
- validate: func(state ConnectionState) error {
- // There's no overlap so OpenSSL will not select a protocol.
- if state.NegotiatedProtocol != "" {
- return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol)
- }
- return nil
- },
- }
- runClientTestTLS12(t, test)
-}
-
// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0="
func TestHandshakClientSCTs(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
scts, err := base64.StdEncoding.DecodeString(sctsBase64)
if err != nil {
@@ -596,7 +879,7 @@ func TestHandshakClientSCTs(t *testing.T) {
// Note that this needs OpenSSL 1.0.2 because that is the first
// version that supports the -serverinfo flag.
command: []string{"openssl", "s_server"},
- config: &config,
+ config: config,
extensions: [][]byte{scts},
validate: func(state ConnectionState) error {
expectedSCTs := [][]byte{
@@ -618,14 +901,113 @@ func TestHandshakClientSCTs(t *testing.T) {
runClientTestTLS12(t, test)
}
-func TestNoIPAddressesInSNI(t *testing.T) {
- for _, ipLiteral := range []string{"1.2.3.4", "::1"} {
+func TestRenegotiationRejected(t *testing.T) {
+ config := testConfig.Clone()
+ test := &clientTest{
+ name: "RenegotiationRejected",
+ command: []string{"openssl", "s_server", "-state"},
+ config: config,
+ numRenegotiations: 1,
+ renegotiationExpectedToFail: 1,
+ checkRenegotiationError: func(renegotiationNum int, err error) error {
+ if err == nil {
+ return errors.New("expected error from renegotiation but got nil")
+ }
+ if !strings.Contains(err.Error(), "no renegotiation") {
+ return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+ }
+ return nil
+ },
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateOnce(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateOnceAsClient
+
+ test := &clientTest{
+ name: "RenegotiateOnce",
+ command: []string{"openssl", "s_server", "-state"},
+ config: config,
+ numRenegotiations: 1,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwice(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateFreelyAsClient
+
+ test := &clientTest{
+ name: "RenegotiateTwice",
+ command: []string{"openssl", "s_server", "-state"},
+ config: config,
+ numRenegotiations: 2,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwiceRejected(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateOnceAsClient
+
+ test := &clientTest{
+ name: "RenegotiateTwiceRejected",
+ command: []string{"openssl", "s_server", "-state"},
+ config: config,
+ numRenegotiations: 2,
+ renegotiationExpectedToFail: 2,
+ checkRenegotiationError: func(renegotiationNum int, err error) error {
+ if renegotiationNum == 1 {
+ return err
+ }
+
+ if err == nil {
+ return errors.New("expected error from renegotiation but got nil")
+ }
+ if !strings.Contains(err.Error(), "no renegotiation") {
+ return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+ }
+ return nil
+ },
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+var hostnameInSNITests = []struct {
+ in, out string
+}{
+ // Opaque string
+ {"", ""},
+ {"localhost", "localhost"},
+ {"foo, bar, baz and qux", "foo, bar, baz and qux"},
+
+ // DNS hostname
+ {"golang.org", "golang.org"},
+ {"golang.org.", "golang.org"},
+
+ // Literal IPv4 address
+ {"1.2.3.4", ""},
+
+ // Literal IPv6 address
+ {"::1", ""},
+ {"::1%lo0", ""}, // with zone identifier
+ {"[::1]", ""}, // as per RFC 5952 we allow the [] style as IPv6 literal
+ {"[::1%lo0]", ""},
+}
+
+func TestHostnameInSNI(t *testing.T) {
+ for _, tt := range hostnameInSNITests {
c, s := net.Pipe()
- go func() {
- client := Client(c, &Config{ServerName: ipLiteral})
- client.Handshake()
- }()
+ go func(host string) {
+ Client(c, &Config{ServerName: host, InsecureSkipVerify: true}).Handshake()
+ }(tt.in)
var header [5]byte
if _, err := io.ReadFull(s, header[:]); err != nil {
@@ -637,10 +1019,20 @@ func TestNoIPAddressesInSNI(t *testing.T) {
if _, err := io.ReadFull(s, record[:]); err != nil {
t.Fatal(err)
}
+
+ c.Close()
s.Close()
- if bytes.Index(record, []byte(ipLiteral)) != -1 {
- t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record)
+ var m clientHelloMsg
+ if !m.unmarshal(record) {
+ t.Errorf("unmarshaling ClientHello for %q failed", tt.in)
+ continue
+ }
+ if tt.in != tt.out && m.serverName == tt.in {
+ t.Errorf("prohibited %q found in ClientHello: %x", tt.in, record)
+ }
+ if m.serverName != tt.out {
+ t.Errorf("expected %q not found in ClientHello: %x", tt.out, record)
}
}
}
@@ -694,3 +1086,480 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
t.Fatalf("Expected error about unconfigured cipher suite but got %q", err)
}
}
+
+func TestVerifyPeerCertificate(t *testing.T) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ now := func() time.Time { return time.Unix(1476984729, 0) }
+
+ sentinelErr := errors.New("TestVerifyPeerCertificate")
+
+ verifyCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ if len(validatedChains) == 0 {
+ return errors.New("got len(validatedChains) = 0, wanted non-zero")
+ }
+ *called = true
+ return nil
+ }
+
+ tests := []struct {
+ configureServer func(*Config, *bool)
+ configureClient func(*Config, *bool)
+ validate func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error)
+ }{
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyCallback(called, rawCerts, validatedChains)
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyCallback(called, rawCerts, validatedChains)
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = true
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ // With InsecureSkipVerify set, this
+ // callback should still be called but
+ // validatedChains must be empty.
+ if l := len(validatedChains); l != 0 {
+ return errors.New("got len(validatedChains) = 0, wanted zero")
+ }
+ *called = true
+ return nil
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ },
+ },
+ }
+
+ for i, test := range tests {
+ c, s := net.Pipe()
+ done := make(chan error)
+
+ var clientCalled, serverCalled bool
+
+ go func() {
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.ClientAuth = RequireAndVerifyClientCert
+ config.ClientCAs = rootCAs
+ config.Time = now
+ test.configureServer(config, &serverCalled)
+
+ err = Server(s, config).Handshake()
+ s.Close()
+ done <- err
+ }()
+
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.RootCAs = rootCAs
+ config.Time = now
+ test.configureClient(config, &clientCalled)
+ clientErr := Client(c, config).Handshake()
+ c.Close()
+ serverErr := <-done
+
+ test.validate(t, i, clientCalled, serverCalled, clientErr, serverErr)
+ }
+}
+
+// brokenConn wraps a net.Conn and causes all Writes after a certain number to
+// fail with brokenConnErr.
+type brokenConn struct {
+ net.Conn
+
+ // breakAfter is the number of successful writes that will be allowed
+ // before all subsequent writes fail.
+ breakAfter int
+
+ // numWrites is the number of writes that have been done.
+ numWrites int
+}
+
+// brokenConnErr is the error that brokenConn returns once exhausted.
+var brokenConnErr = errors.New("too many writes to brokenConn")
+
+func (b *brokenConn) Write(data []byte) (int, error) {
+ if b.numWrites >= b.breakAfter {
+ return 0, brokenConnErr
+ }
+
+ b.numWrites++
+ return b.Conn.Write(data)
+}
+
+func TestFailedWrite(t *testing.T) {
+ // Test that a write error during the handshake is returned.
+ for _, breakAfter := range []int{0, 1} {
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ go func() {
+ Server(s, testConfig).Handshake()
+ s.Close()
+ done <- true
+ }()
+
+ brokenC := &brokenConn{Conn: c, breakAfter: breakAfter}
+ err := Client(brokenC, testConfig).Handshake()
+ if err != brokenConnErr {
+ t.Errorf("#%d: expected error from brokenConn but got %q", breakAfter, err)
+ }
+ brokenC.Close()
+
+ <-done
+ }
+}
+
+// writeCountingConn wraps a net.Conn and counts the number of Write calls.
+type writeCountingConn struct {
+ net.Conn
+
+ // numWrites is the number of writes that have been done.
+ numWrites int
+}
+
+func (wcc *writeCountingConn) Write(data []byte) (int, error) {
+ wcc.numWrites++
+ return wcc.Conn.Write(data)
+}
+
+func TestBuffering(t *testing.T) {
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ clientWCC := &writeCountingConn{Conn: c}
+ serverWCC := &writeCountingConn{Conn: s}
+
+ go func() {
+ Server(serverWCC, testConfig).Handshake()
+ serverWCC.Close()
+ done <- true
+ }()
+
+ err := Client(clientWCC, testConfig).Handshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+ clientWCC.Close()
+ <-done
+
+ if n := clientWCC.numWrites; n != 2 {
+ t.Errorf("expected client handshake to complete with only two writes, but saw %d", n)
+ }
+
+ if n := serverWCC.numWrites; n != 2 {
+ t.Errorf("expected server handshake to complete with only two writes, but saw %d", n)
+ }
+}
+
+func TestAlertFlushing(t *testing.T) {
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ clientWCC := &writeCountingConn{Conn: c}
+ serverWCC := &writeCountingConn{Conn: s}
+
+ serverConfig := testConfig.Clone()
+
+ // Cause a signature-time error
+ brokenKey := rsa.PrivateKey{PublicKey: testRSAPrivateKey.PublicKey}
+ brokenKey.D = big.NewInt(42)
+ serverConfig.Certificates = []Certificate{{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: &brokenKey,
+ }}
+
+ go func() {
+ Server(serverWCC, serverConfig).Handshake()
+ serverWCC.Close()
+ done <- true
+ }()
+
+ err := Client(clientWCC, testConfig).Handshake()
+ if err == nil {
+ t.Fatal("client unexpectedly returned no error")
+ }
+
+ const expectedError = "remote error: tls: handshake failure"
+ if e := err.Error(); !strings.Contains(e, expectedError) {
+ t.Fatalf("expected to find %q in error but error was %q", expectedError, e)
+ }
+ clientWCC.Close()
+ <-done
+
+ if n := clientWCC.numWrites; n != 1 {
+ t.Errorf("expected client handshake to complete with one write, but saw %d", n)
+ }
+
+ if n := serverWCC.numWrites; n != 1 {
+ t.Errorf("expected server handshake to complete with one write, but saw %d", n)
+ }
+}
+
+func TestHandshakeRace(t *testing.T) {
+ t.Parallel()
+ // This test races a Read and Write to try and complete a handshake in
+ // order to provide some evidence that there are no races or deadlocks
+ // in the handshake locking.
+ for i := 0; i < 32; i++ {
+ c, s := net.Pipe()
+
+ go func() {
+ server := Server(s, testConfig)
+ if err := server.Handshake(); err != nil {
+ panic(err)
+ }
+
+ var request [1]byte
+ if n, err := server.Read(request[:]); err != nil || n != 1 {
+ panic(err)
+ }
+
+ server.Write(request[:])
+ server.Close()
+ }()
+
+ startWrite := make(chan struct{})
+ startRead := make(chan struct{})
+ readDone := make(chan struct{})
+
+ client := Client(c, testConfig)
+ go func() {
+ <-startWrite
+ var request [1]byte
+ client.Write(request[:])
+ }()
+
+ go func() {
+ <-startRead
+ var reply [1]byte
+ if n, err := client.Read(reply[:]); err != nil || n != 1 {
+ panic(err)
+ }
+ c.Close()
+ readDone <- struct{}{}
+ }()
+
+ if i&1 == 1 {
+ startWrite <- struct{}{}
+ startRead <- struct{}{}
+ } else {
+ startRead <- struct{}{}
+ startWrite <- struct{}{}
+ }
+ <-readDone
+ }
+}
+
+func TestTLS11SignatureSchemes(t *testing.T) {
+ expected := tls11SignatureSchemesNumECDSA + tls11SignatureSchemesNumRSA
+ if expected != len(tls11SignatureSchemes) {
+ t.Errorf("expected to find %d TLS 1.1 signature schemes, but found %d", expected, len(tls11SignatureSchemes))
+ }
+}
+
+var getClientCertificateTests = []struct {
+ setup func(*Config)
+ expectedClientError string
+ verify func(*testing.T, int, *ConnectionState)
+}{
+ {
+ func(clientConfig *Config) {
+ // Returning a Certificate with no certificate data
+ // should result in an empty message being sent to the
+ // server.
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ // With TLS 1.1, the SignatureSchemes should be
+ // synthesised from the supported certificate types.
+ clientConfig.MaxVersion = VersionTLS11
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ // Returning an error should abort the handshake with
+ // that error.
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ return nil, errors.New("GetClientCertificate")
+ }
+ },
+ "GetClientCertificate",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ return &testConfig.Certificates[0], nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.VerifiedChains); l != 0 {
+ t.Errorf("#%d: expected some verified chains, but found none", testNum)
+ }
+ },
+ },
+}
+
+func TestGetClientCertificate(t *testing.T) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ for i, test := range getClientCertificateTests {
+ serverConfig := testConfig.Clone()
+ serverConfig.ClientAuth = RequestClientCert
+ serverConfig.RootCAs = x509.NewCertPool()
+ serverConfig.RootCAs.AddCert(issuer)
+
+ clientConfig := testConfig.Clone()
+
+ test.setup(clientConfig)
+
+ type serverResult struct {
+ cs ConnectionState
+ err error
+ }
+
+ c, s := net.Pipe()
+ done := make(chan serverResult)
+
+ go func() {
+ defer s.Close()
+ server := Server(s, serverConfig)
+ err := server.Handshake()
+
+ var cs ConnectionState
+ if err == nil {
+ cs = server.ConnectionState()
+ }
+ done <- serverResult{cs, err}
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ result := <-done
+
+ if clientErr != nil {
+ if len(test.expectedClientError) == 0 {
+ t.Errorf("#%d: client error: %v", i, clientErr)
+ } else if got := clientErr.Error(); got != test.expectedClientError {
+ t.Errorf("#%d: expected client error %q, but got %q", i, test.expectedClientError, got)
+ }
+ } else if len(test.expectedClientError) > 0 {
+ t.Errorf("#%d: expected client error %q, but got no error", i, test.expectedClientError)
+ } else if err := result.err; err != nil {
+ t.Errorf("#%d: server error: %v", i, err)
+ } else {
+ test.verify(t, i, &result.cs)
+ }
+ }
+}
diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go
index 111ce53487..694bd918d8 100644
--- a/libgo/go/crypto/tls/handshake_messages.go
+++ b/libgo/go/crypto/tls/handshake_messages.go
@@ -7,23 +7,24 @@ package tls
import "bytes"
type clientHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuites []uint16
- compressionMethods []uint8
- nextProtoNeg bool
- serverName string
- ocspStapling bool
- scts bool
- supportedCurves []CurveID
- supportedPoints []uint8
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
- secureRenegotiation bool
- alpnProtocols []string
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ scts bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation []byte
+ secureRenegotiationSupported bool
+ alpnProtocols []string
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -47,7 +48,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
- m.secureRenegotiation == m1.secureRenegotiation &&
+ m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+ bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols)
}
@@ -86,8 +88,8 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
- if m.secureRenegotiation {
- extensionsLength += 1
+ if m.secureRenegotiationSupported {
+ extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if len(m.alpnProtocols) > 0 {
@@ -214,7 +216,7 @@ func (m *clientHelloMsg) marshal() []byte {
z[4] = byte(l)
z = z[5:]
for _, pointFormat := range m.supportedPoints {
- z[0] = byte(pointFormat)
+ z[0] = pointFormat
z = z[1:]
}
}
@@ -248,12 +250,15 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
- if m.secureRenegotiation {
+ if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
- z[3] = 1
+ z[3] = byte(len(m.secureRenegotiation) + 1)
+ z[4] = byte(len(m.secureRenegotiation))
z = z[5:]
+ copy(z, m.secureRenegotiation)
+ z = z[len(m.secureRenegotiation):]
}
if len(m.alpnProtocols) > 0 {
z[0] = byte(extensionALPN >> 8)
@@ -316,7 +321,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
if m.cipherSuites[i] == scsvRenegotiation {
- m.secureRenegotiation = true
+ m.secureRenegotiationSupported = true
}
}
data = data[2+cipherSuiteLen:]
@@ -448,10 +453,18 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
d = d[2:]
}
case extensionRenegotiationInfo:
- if length != 1 || data[0] != 0 {
+ if length == 0 {
+ return false
+ }
+ d := data[:length]
+ l := int(d[0])
+ d = d[1:]
+ if l != len(d) {
return false
}
- m.secureRenegotiation = true
+
+ m.secureRenegotiation = d
+ m.secureRenegotiationSupported = true
case extensionALPN:
if length < 2 {
return false
@@ -483,19 +496,20 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- scts [][]byte
- ticketSupported bool
- secureRenegotiation bool
- alpnProtocol string
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ scts [][]byte
+ ticketSupported bool
+ secureRenegotiation []byte
+ secureRenegotiationSupported bool
+ alpnProtocol string
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -523,7 +537,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
m.ticketSupported == m1.ticketSupported &&
- m.secureRenegotiation == m1.secureRenegotiation &&
+ m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+ bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
m.alpnProtocol == m1.alpnProtocol
}
@@ -551,8 +566,8 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
- if m.secureRenegotiation {
- extensionsLength += 1
+ if m.secureRenegotiationSupported {
+ extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
@@ -589,7 +604,7 @@ func (m *serverHelloMsg) marshal() []byte {
z := x[39+len(m.sessionId):]
z[0] = uint8(m.cipherSuite >> 8)
z[1] = uint8(m.cipherSuite)
- z[2] = uint8(m.compressionMethod)
+ z[2] = m.compressionMethod
z = z[3:]
if numExtensions > 0 {
@@ -624,12 +639,15 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
- if m.secureRenegotiation {
+ if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
- z[3] = 1
+ z[3] = byte(len(m.secureRenegotiation) + 1)
+ z[4] = byte(len(m.secureRenegotiation))
z = z[5:]
+ copy(z, m.secureRenegotiation)
+ z = z[len(m.secureRenegotiation):]
}
if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
z[0] = byte(extensionALPN >> 8)
@@ -744,10 +762,18 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.ticketSupported = true
case extensionRenegotiationInfo:
- if length != 1 || data[0] != 0 {
+ if length == 0 {
+ return false
+ }
+ d := data[:length]
+ l := int(d[0])
+ d = d[1:]
+ if l != len(d) {
return false
}
- m.secureRenegotiation = true
+
+ m.secureRenegotiation = d
+ m.secureRenegotiationSupported = true
case extensionALPN:
d := data[:length]
if len(d) < 3 {
@@ -776,12 +802,9 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
l := int(d[0])<<8 | int(d[1])
d = d[2:]
- if len(d) != l {
+ if len(d) != l || l == 0 {
return false
}
- if l == 0 {
- continue
- }
m.scts = make([][]byte, 0, 3)
for len(d) != 0 {
@@ -790,7 +813,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
sctLen := int(d[0])<<8 | int(d[1])
d = d[2:]
- if len(d) < sctLen {
+ if sctLen == 0 || len(d) < sctLen {
return false
}
m.scts = append(m.scts, d[:sctLen])
@@ -1316,11 +1339,8 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
- if len(data) > 0 {
- return false
- }
- return true
+ return len(data) == 0
}
type certificateVerifyMsg struct {
@@ -1466,6 +1486,17 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return true
}
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() []byte {
+ return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
func eqUint16s(x, y []uint16) bool {
if len(x) != len(y) {
return false
diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go
index 95d825bd17..f1154d4d01 100644
--- a/libgo/go/crypto/tls/handshake_messages_test.go
+++ b/libgo/go/crypto/tls/handshake_messages_test.go
@@ -5,6 +5,7 @@
package tls
import (
+ "bytes"
"math/rand"
"reflect"
"testing"
@@ -260,3 +261,65 @@ func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value {
}
return reflect.ValueOf(s)
}
+
+func TestRejectEmptySCTList(t *testing.T) {
+ // https://tools.ietf.org/html/rfc6962#section-3.3.1 specifies that
+ // empty SCT lists are invalid.
+
+ var random [32]byte
+ sct := []byte{0x42, 0x42, 0x42, 0x42}
+ serverHello := serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{sct},
+ }
+ serverHelloBytes := serverHello.marshal()
+
+ var serverHelloCopy serverHelloMsg
+ if !serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Failed to unmarshal initial message")
+ }
+
+ // Change serverHelloBytes so that the SCT list is empty
+ i := bytes.Index(serverHelloBytes, sct)
+ if i < 0 {
+ t.Fatal("Cannot find SCT in ServerHello")
+ }
+
+ var serverHelloEmptySCT []byte
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[:i-6]...)
+ // Append the extension length and SCT list length for an empty list.
+ serverHelloEmptySCT = append(serverHelloEmptySCT, []byte{0, 2, 0, 0}...)
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[i+4:]...)
+
+ // Update the handshake message length.
+ serverHelloEmptySCT[1] = byte((len(serverHelloEmptySCT) - 4) >> 16)
+ serverHelloEmptySCT[2] = byte((len(serverHelloEmptySCT) - 4) >> 8)
+ serverHelloEmptySCT[3] = byte(len(serverHelloEmptySCT) - 4)
+
+ // Update the extensions length
+ serverHelloEmptySCT[42] = byte((len(serverHelloEmptySCT) - 44) >> 8)
+ serverHelloEmptySCT[43] = byte((len(serverHelloEmptySCT) - 44))
+
+ if serverHelloCopy.unmarshal(serverHelloEmptySCT) {
+ t.Fatal("Unmarshaled ServerHello with empty SCT list")
+ }
+}
+
+func TestRejectEmptySCT(t *testing.T) {
+ // Not only must the SCT list be non-empty, but the SCT elements must
+ // not be zero length.
+
+ var random [32]byte
+ serverHello := serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{nil},
+ }
+ serverHelloBytes := serverHello.marshal()
+
+ var serverHelloCopy serverHelloMsg
+ if serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Unmarshaled ServerHello with zero-length SCT")
+ }
+}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index e16cddcbd8..b786c3083a 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -19,28 +19,28 @@ import (
// serverHandshakeState contains details of a server handshake in progress.
// It's discarded once the handshake has completed.
type serverHandshakeState struct {
- c *Conn
- clientHello *clientHelloMsg
- hello *serverHelloMsg
- suite *cipherSuite
- ellipticOk bool
- ecdsaOk bool
- rsaDecryptOk bool
- rsaSignOk bool
- sessionState *sessionState
- finishedHash finishedHash
- masterSecret []byte
- certsFromClient [][]byte
- cert *Certificate
+ c *Conn
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ellipticOk bool
+ ecdsaOk bool
+ rsaDecryptOk bool
+ rsaSignOk bool
+ sessionState *sessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ certsFromClient [][]byte
+ cert *Certificate
+ cachedClientHelloInfo *ClientHelloInfo
}
// serverHandshake performs a TLS handshake as a server.
+// c.out.Mutex <= L; c.handshakeMutex <= L.
func (c *Conn) serverHandshake() error {
- config := c.config
-
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
- config.serverInitOnce.Do(config.serverInit)
+ c.config.serverInitOnce.Do(c.config.serverInit)
hs := serverHandshakeState{
c: c,
@@ -51,6 +51,7 @@ func (c *Conn) serverHandshake() error {
}
// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+ c.buffering = true
if isResume {
// The client has included a session ticket and so we do an abbreviated handshake.
if err := hs.doResumeHandshake(); err != nil {
@@ -67,9 +68,13 @@ func (c *Conn) serverHandshake() error {
return err
}
}
- if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+ if err := hs.sendFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
return err
}
+ c.clientFinishedIsFirst = false
if err := hs.readFinished(nil); err != nil {
return err
}
@@ -83,15 +88,20 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.readFinished(c.firstFinished[:]); err != nil {
+ if err := hs.readFinished(c.clientFinished[:]); err != nil {
return err
}
+ c.clientFinishedIsFirst = true
+ c.buffering = true
if err := hs.sendSessionTicket(); err != nil {
return err
}
if err := hs.sendFinished(nil); err != nil {
return err
}
+ if _, err := c.flush(); err != nil {
+ return err
+ }
}
c.handshakeComplete = true
@@ -101,7 +111,6 @@ func (c *Conn) serverHandshake() error {
// readClientHello reads a ClientHello message from the client and decides
// whether we will perform session resumption.
func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
- config := hs.c.config
c := hs.c
msg, err := c.readHandshake()
@@ -114,7 +123,22 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
c.sendAlert(alertUnexpectedMessage)
return false, unexpectedMessageError(hs.clientHello, msg)
}
- c.vers, ok = config.mutualVersion(hs.clientHello.vers)
+
+ if c.config.GetConfigForClient != nil {
+ if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
+ c.sendAlert(alertInternalError)
+ return false, err
+ } else if newConfig != nil {
+ newConfig.mutex.Lock()
+ newConfig.originalConfig = c.config
+ newConfig.mutex.Unlock()
+
+ newConfig.serverInitOnce.Do(newConfig.serverInit)
+ c.config = newConfig
+ }
+ }
+
+ c.vers, ok = c.config.mutualVersion(hs.clientHello.vers)
if !ok {
c.sendAlert(alertProtocolVersion)
return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
@@ -124,7 +148,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
hs.hello = new(serverHelloMsg)
supportedCurve := false
- preferredCurves := config.curvePreferences()
+ preferredCurves := c.config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
for _, supported := range preferredCurves {
@@ -160,12 +184,18 @@ Curves:
hs.hello.vers = c.vers
hs.hello.random = make([]byte, 32)
- _, err = io.ReadFull(config.rand(), hs.hello.random)
+ _, err = io.ReadFull(c.config.rand(), hs.hello.random)
if err != nil {
c.sendAlert(alertInternalError)
return false, err
}
- hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
@@ -179,20 +209,16 @@ Curves:
} else {
// Although sending an empty NPN extension is reasonable, Firefox has
// had a bug around this. Best to send nothing at all if
- // config.NextProtos is empty. See
+ // c.config.NextProtos is empty. See
// https://golang.org/issue/5445.
- if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+ if hs.clientHello.nextProtoNeg && len(c.config.NextProtos) > 0 {
hs.hello.nextProtoNeg = true
- hs.hello.nextProtos = config.NextProtos
+ hs.hello.nextProtos = c.config.NextProtos
}
}
- if hs.cert, err = config.getCertificate(&ClientHelloInfo{
- CipherSuites: hs.clientHello.cipherSuites,
- ServerName: hs.clientHello.serverName,
- SupportedCurves: hs.clientHello.supportedCurves,
- SupportedPoints: hs.clientHello.supportedPoints,
- }); err != nil {
+ hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
+ if err != nil {
c.sendAlert(alertInternalError)
return false, err
}
@@ -208,7 +234,7 @@ Curves:
hs.rsaSignOk = true
default:
c.sendAlert(alertInternalError)
- return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+ return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
}
}
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
@@ -217,7 +243,7 @@ Curves:
hs.rsaDecryptOk = true
default:
c.sendAlert(alertInternalError)
- return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+ return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
}
}
@@ -245,7 +271,7 @@ Curves:
return false, errors.New("tls: no cipher suite supported by both client and server")
}
- // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+ // See https://tools.ietf.org/html/rfc7507.
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
// The client is doing a fallback connection.
@@ -274,10 +300,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
}
@@ -322,7 +346,9 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
hs.finishedHash.discardHandshakeBuffer()
hs.finishedHash.Write(hs.clientHello.marshal())
hs.finishedHash.Write(hs.hello.marshal())
- c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+ return err
+ }
if len(hs.sessionState.certificates) > 0 {
if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
@@ -336,51 +362,58 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
}
func (hs *serverHandshakeState) doFullHandshake() error {
- config := hs.c.config
c := hs.c
if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
hs.hello.ocspStapling = true
}
- hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
+ hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
- if config.ClientAuth == NoClientCert {
+ if c.config.ClientAuth == NoClientCert {
// No need to keep a full record of the handshake if client
// certificates won't be used.
hs.finishedHash.discardHandshakeBuffer()
}
hs.finishedHash.Write(hs.clientHello.marshal())
hs.finishedHash.Write(hs.hello.marshal())
- c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+ return err
+ }
certMsg := new(certificateMsg)
certMsg.certificates = hs.cert.Certificate
hs.finishedHash.Write(certMsg.marshal())
- c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+ return err
+ }
if hs.hello.ocspStapling {
certStatus := new(certificateStatusMsg)
certStatus.statusType = statusTypeOCSP
certStatus.response = hs.cert.OCSPStaple
hs.finishedHash.Write(certStatus.marshal())
- c.writeRecord(recordTypeHandshake, certStatus.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
+ return err
+ }
}
keyAgreement := hs.suite.ka(c.vers)
- skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
+ skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
if skx != nil {
hs.finishedHash.Write(skx.marshal())
- c.writeRecord(recordTypeHandshake, skx.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
+ return err
+ }
}
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := new(certificateRequestMsg)
certReq.certificateTypes = []byte{
@@ -397,16 +430,24 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// to our request. When we know the CAs we trust, then
// we can send them down, so that the client can choose
// an appropriate certificate to give to us.
- if config.ClientCAs != nil {
- certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
}
hs.finishedHash.Write(certReq.marshal())
- c.writeRecord(recordTypeHandshake, certReq.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+ return err
+ }
}
helloDone := new(serverHelloDoneMsg)
hs.finishedHash.Write(helloDone.marshal())
- c.writeRecord(recordTypeHandshake, helloDone.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
+ return err
+ }
+
+ if _, err := c.flush(); err != nil {
+ return err
+ }
var pub crypto.PublicKey // public key for client auth, if any
@@ -418,7 +459,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
var ok bool
// If we requested a client certificate, then the client must send a
// certificate message, even if it's empty.
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
@@ -427,7 +468,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if len(certMsg.certificates) == 0 {
// The client didn't actually send a certificate
- switch config.ClientAuth {
+ switch c.config.ClientAuth {
case RequireAnyClientCert, RequireAndVerifyClientCert:
c.sendAlert(alertBadCertificate)
return errors.New("tls: client didn't provide a certificate")
@@ -453,16 +494,20 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(ckx.marshal())
- preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ if err := c.config.writeKeyLog(hs.clientHello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
- // clientKeyExchangeMsg. This message is a digest of all preceding
+ // clientKeyExchangeMsg. This message is a digest of all preceding
// handshake-layer messages that is signed using the private key corresponding
// to the client's certificate. This allows us to verify that the client is in
// possession of the private key of the certificate.
@@ -499,7 +544,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
switch key := pub.(type) {
case *ecdsa.PublicKey:
if signatureAndHash.signature != signatureECDSA {
- err = errors.New("bad signature type for client's ECDSA certificate")
+ err = errors.New("tls: bad signature type for client's ECDSA certificate")
break
}
ecdsaSig := new(ecdsaSignature)
@@ -507,7 +552,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
break
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- err = errors.New("ECDSA signature contained zero or negative values")
+ err = errors.New("tls: ECDSA signature contained zero or negative values")
break
}
var digest []byte
@@ -515,11 +560,11 @@ func (hs *serverHandshakeState) doFullHandshake() error {
break
}
if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
- err = errors.New("ECDSA verification failure")
+ err = errors.New("tls: ECDSA verification failure")
}
case *rsa.PublicKey:
if signatureAndHash.signature != signatureRSA {
- err = errors.New("bad signature type for client's RSA certificate")
+ err = errors.New("tls: bad signature type for client's RSA certificate")
break
}
var digest []byte
@@ -571,8 +616,8 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.in.error(); err != nil {
- return err
+ if c.in.err != nil {
+ return c.in.err
}
if hs.hello.nextProtoNeg {
@@ -632,7 +677,9 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
}
hs.finishedHash.Write(m.marshal())
- c.writeRecord(recordTypeHandshake, m.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+ return err
+ }
return nil
}
@@ -640,12 +687,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
func (hs *serverHandshakeState) sendFinished(out []byte) error {
c := hs.c
- c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+ return err
+ }
finished := new(finishedMsg)
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
hs.finishedHash.Write(finished.marshal())
- c.writeRecord(recordTypeHandshake, finished.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+ return err
+ }
c.cipherSuite = hs.suite.id
copy(out, finished.verifyData)
@@ -690,20 +741,27 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
c.verifiedChains = chains
}
- if len(certs) > 0 {
- var pub crypto.PublicKey
- switch key := certs[0].PublicKey.(type) {
- case *ecdsa.PublicKey, *rsa.PublicKey:
- pub = key
- default:
- c.sendAlert(alertUnsupportedCertificate)
- return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, err
}
- c.peerCertificates = certs
- return pub, nil
}
- return nil, nil
+ if len(certs) == 0 {
+ return nil, nil
+ }
+
+ var pub crypto.PublicKey
+ switch key := certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey:
+ pub = key
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ c.peerCertificates = certs
+ return pub, nil
}
// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
@@ -748,3 +806,37 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
}
return false
}
+
+// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
+var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
+
+func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
+ if hs.cachedClientHelloInfo != nil {
+ return hs.cachedClientHelloInfo
+ }
+
+ var supportedVersions []uint16
+ if hs.clientHello.vers > VersionTLS12 {
+ supportedVersions = suppVersArray[:]
+ } else if hs.clientHello.vers >= VersionSSL30 {
+ supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:]
+ }
+
+ signatureSchemes := make([]SignatureScheme, 0, len(hs.clientHello.signatureAndHashes))
+ for _, sah := range hs.clientHello.signatureAndHashes {
+ signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature))
+ }
+
+ hs.cachedClientHelloInfo = &ClientHelloInfo{
+ CipherSuites: hs.clientHello.cipherSuites,
+ ServerName: hs.clientHello.serverName,
+ SupportedCurves: hs.clientHello.supportedCurves,
+ SupportedPoints: hs.clientHello.supportedPoints,
+ SignatureSchemes: signatureSchemes,
+ SupportedProtos: hs.clientHello.alpnProtocols,
+ SupportedVersions: supportedVersions,
+ Conn: hs.c.conn,
+ }
+
+ return hs.cachedClientHelloInfo
+}
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
index 438fb3140a..bcd3d43ea3 100644
--- a/libgo/go/crypto/tls/handshake_server_test.go
+++ b/libgo/go/crypto/tls/handshake_server_test.go
@@ -69,7 +69,7 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
// Create in-memory network connection,
- // send message to server. Should return
+ // send message to server. Should return
// expected error.
c, s := net.Pipe()
go func() {
@@ -80,7 +80,10 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
cli.writeRecord(recordTypeHandshake, m.marshal())
c.Close()
}()
- err := Server(s, serverConfig).Handshake()
+ hs := serverHandshakeState{
+ c: Server(s, serverConfig),
+ }
+ _, err := hs.readClientHello()
s.Close()
if len(expectedSubStr) == 0 {
if err != nil && err != io.EOF {
@@ -105,16 +108,16 @@ func TestRejectBadProtocolVersion(t *testing.T) {
func TestNoSuiteOverlap(t *testing.T) {
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{0xff00},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
}
testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server")
}
func TestNoCompressionOverlap(t *testing.T) {
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{0xff},
}
@@ -123,56 +126,56 @@ func TestNoCompressionOverlap(t *testing.T) {
func TestNoRC4ByDefault(t *testing.T) {
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
}
- serverConfig := *testConfig
+ serverConfig := testConfig.Clone()
// Reset the enabled cipher suites to nil in order to test the
// defaults.
serverConfig.CipherSuites = nil
- testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
}
func TestDontSelectECDSAWithRSAKey(t *testing.T) {
// Test that, even when both sides support an ECDSA cipher suite, it
// won't be selected if the server's private key doesn't support it.
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
supportedCurves: []CurveID{CurveP256},
supportedPoints: []uint8{pointFormatUncompressed},
}
- serverConfig := *testConfig
+ serverConfig := testConfig.Clone()
serverConfig.CipherSuites = clientHello.cipherSuites
serverConfig.Certificates = make([]Certificate, 1)
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
serverConfig.BuildNameToCertificate()
// First test that it *does* work when the server's key is ECDSA.
- testClientHello(t, &serverConfig, clientHello)
+ testClientHello(t, serverConfig, clientHello)
// Now test that switching to an RSA key causes the expected error (and
// not an internal error about a signing failure).
serverConfig.Certificates = testConfig.Certificates
- testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
}
func TestDontSelectRSAWithECDSAKey(t *testing.T) {
// Test that, even when both sides support an RSA cipher suite, it
// won't be selected if the server's private key doesn't support it.
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
supportedCurves: []CurveID{CurveP256},
supportedPoints: []uint8{pointFormatUncompressed},
}
- serverConfig := *testConfig
+ serverConfig := testConfig.Clone()
serverConfig.CipherSuites = clientHello.cipherSuites
// First test that it *does* work when the server's key is RSA.
- testClientHello(t, &serverConfig, clientHello)
+ testClientHello(t, serverConfig, clientHello)
// Now test that switching to an ECDSA key causes the expected error
// (and not an internal error about a signing failure).
@@ -180,16 +183,16 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
serverConfig.BuildNameToCertificate()
- testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
}
func TestRenegotiationExtension(t *testing.T) {
clientHello := &clientHelloMsg{
- vers: VersionTLS12,
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- secureRenegotiation: true,
- cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ vers: VersionTLS12,
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ secureRenegotiationSupported: true,
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
}
var buf []byte
@@ -203,7 +206,8 @@ func TestRenegotiationExtension(t *testing.T) {
buf = make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
- t.Fatalf("Server read returned error: %s", err)
+ t.Errorf("Server read returned error: %s", err)
+ return
}
buf = buf[:n]
c.Close()
@@ -226,7 +230,7 @@ func TestRenegotiationExtension(t *testing.T) {
t.Fatalf("Failed to parse ServerHello")
}
- if !serverHello.secureRenegotiation {
+ if !serverHello.secureRenegotiationSupported {
t.Errorf("Secure renegotiation extension was not echoed.")
}
}
@@ -262,9 +266,9 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
reply, clientErr = cli.readHandshake()
c.Close()
}()
- config := *testConfig
+ config := testConfig.Clone()
config.CipherSuites = clientHello.cipherSuites
- Server(s, &config).Handshake()
+ Server(s, config).Handshake()
s.Close()
if clientErr != nil {
t.Fatal(clientErr)
@@ -396,6 +400,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.
@@ -497,6 +559,8 @@ func (test *serverTest) loadData() (flows [][]byte, err error) {
}
func (test *serverTest) run(t *testing.T, write bool) {
+ checkOpenSSLVersion(t)
+
var clientConn, serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
@@ -518,16 +582,17 @@ func (test *serverTest) run(t *testing.T, write bool) {
server := Server(serverConn, config)
connStateChan := make(chan ConnectionState, 1)
go func() {
- var err error
- if _, err = server.Write([]byte("hello, world\n")); err != nil {
- t.Logf("Error from Server.Write: %s", err)
- }
+ _, err := server.Write([]byte("hello, world\n"))
if len(test.expectHandshakeErrorIncluding) > 0 {
if err == nil {
t.Errorf("Error expected, but no error returned")
} else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
}
+ } else {
+ if err != nil {
+ t.Logf("Error from Server.Write: '%s'", err)
+ }
}
server.Close()
serverConn.Close()
@@ -596,6 +661,7 @@ func (test *serverTest) run(t *testing.T, write bool) {
}
func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) {
+ setParallel(t)
test := *template
test.name = prefix + test.name
if len(test.command) == 0 {
@@ -670,7 +736,7 @@ func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
}
func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.Certificates = make([]Certificate, 1)
config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
config.Certificates[0].PrivateKey = testECDSAPrivateKey
@@ -679,14 +745,26 @@ func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
test := &serverTest{
name: "ECDHE-ECDSA-AES",
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
- config: &config,
+ config: config,
}
runServerTestTLS10(t, test)
runServerTestTLS12(t, test)
}
+func TestHandshakeServerX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &serverTest{
+ name: "X25519-ECDHE-RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+}
+
func TestHandshakeServerALPN(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.NextProtos = []string{"proto1", "proto2"}
test := &serverTest{
@@ -694,7 +772,7 @@ func TestHandshakeServerALPN(t *testing.T) {
// Note that this needs OpenSSL 1.0.2 because that is the first
// version that supports the -alpn flag.
command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
- config: &config,
+ config: config,
validate: func(state ConnectionState) error {
// The server's preferences should override the client.
if state.NegotiatedProtocol != "proto1" {
@@ -707,7 +785,7 @@ func TestHandshakeServerALPN(t *testing.T) {
}
func TestHandshakeServerALPNNoMatch(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.NextProtos = []string{"proto3"}
test := &serverTest{
@@ -715,7 +793,7 @@ func TestHandshakeServerALPNNoMatch(t *testing.T) {
// Note that this needs OpenSSL 1.0.2 because that is the first
// version that supports the -alpn flag.
command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
- config: &config,
+ config: config,
validate: func(state ConnectionState) error {
// Rather than reject the connection, Go doesn't select
// a protocol when there is no overlap.
@@ -742,7 +820,7 @@ func TestHandshakeServerSNI(t *testing.T) {
// TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
// tests the dynamic GetCertificate method
func TestHandshakeServerSNIGetCertificate(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
// Replace the NameToCertificate map with a GetCertificate function
nameToCert := config.NameToCertificate
@@ -754,7 +832,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
test := &serverTest{
name: "SNI-GetCertificate",
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
- config: &config,
+ config: config,
}
runServerTestTLS12(t, test)
}
@@ -764,7 +842,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
// GetCertificate method doesn't return a cert, we fall back to what's in
// the NameToCertificate map.
func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, nil
@@ -772,7 +850,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
test := &serverTest{
name: "SNI-GetCertificateNotFound",
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
- config: &config,
+ config: config,
}
runServerTestTLS12(t, test)
}
@@ -782,18 +860,18 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
const errMsg = "TestHandshakeServerSNIGetCertificateError error"
- serverConfig := *testConfig
+ serverConfig := testConfig.Clone()
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, errors.New(errMsg)
}
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
serverName: "test",
}
- testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+ testClientHelloFailure(t, serverConfig, clientHello, errMsg)
}
// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
@@ -801,45 +879,45 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
func TestHandshakeServerEmptyCertificates(t *testing.T) {
const errMsg = "TestHandshakeServerEmptyCertificates error"
- serverConfig := *testConfig
+ serverConfig := testConfig.Clone()
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, errors.New(errMsg)
}
serverConfig.Certificates = nil
clientHello := &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
}
- testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+ testClientHelloFailure(t, serverConfig, clientHello, errMsg)
// With an empty Certificates and a nil GetCertificate, the server
// should always return a “no certificates†error.
serverConfig.GetCertificate = nil
clientHello = &clientHelloMsg{
- vers: 0x0301,
+ vers: VersionTLS10,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- compressionMethods: []uint8{0},
+ compressionMethods: []uint8{compressionNone},
}
- testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
+ testClientHelloFailure(t, serverConfig, clientHello, "no certificates")
}
// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
- config := *testConfig
+ config := testConfig.Clone()
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
config.PreferServerCipherSuites = true
test := &serverTest{
name: "CipherSuiteCertPreferenceRSA",
- config: &config,
+ config: config,
}
runServerTestTLS12(t, test)
- config = *testConfig
+ config = testConfig.Clone()
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
config.Certificates = []Certificate{
{
@@ -852,7 +930,7 @@ func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
test = &serverTest{
name: "CipherSuiteCertPreferenceECDSA",
- config: &config,
+ config: config,
}
runServerTestTLS12(t, test)
}
@@ -863,13 +941,13 @@ func TestResumption(t *testing.T) {
test := &serverTest{
name: "IssueTicket",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath},
}
runServerTestTLS12(t, test)
test = &serverTest{
name: "Resume",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath},
}
runServerTestTLS12(t, test)
}
@@ -878,12 +956,12 @@ func TestResumptionDisabled(t *testing.T) {
sessionFilePath := tempFile("")
defer os.Remove(sessionFilePath)
- config := *testConfig
+ config := testConfig.Clone()
test := &serverTest{
name: "IssueTicketPreDisable",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
- config: &config,
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath},
+ config: config,
}
runServerTestTLS12(t, test)
@@ -891,8 +969,8 @@ func TestResumptionDisabled(t *testing.T) {
test = &serverTest{
name: "ResumeDisabled",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
- config: &config,
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath},
+ config: config,
}
runServerTestTLS12(t, test)
@@ -901,12 +979,12 @@ func TestResumptionDisabled(t *testing.T) {
}
func TestFallbackSCSV(t *testing.T) {
- serverConfig := &Config{
+ serverConfig := Config{
Certificates: testConfig.Certificates,
}
test := &serverTest{
name: "FallbackSCSV",
- config: serverConfig,
+ config: &serverConfig,
// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
command: []string{"openssl", "s_client", "-fallback_scsv"},
expectHandshakeErrorIncluding: "inappropriate protocol fallback",
@@ -914,40 +992,40 @@ func TestFallbackSCSV(t *testing.T) {
runServerTestTLS11(t, test)
}
-// cert.pem and key.pem were generated with generate_cert.go
-// Thus, they have no ExtKeyUsage fields and trigger an error
-// when verification is turned on.
+// clientCertificatePEM and clientKeyPEM were generated with generate_cert.go
+// Thus, they have no ExtKeyUsage fields and trigger an error when verification
+// is turned on.
const clientCertificatePEM = `
-----BEGIN CERTIFICATE-----
-MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
-bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
-MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
-MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
-hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
-ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
-E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
-DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
-p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
-hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
-GFGNEH5PlGffo05wc46QkYU=
+MIIB7zCCAVigAwIBAgIQXBnBiWWDVW/cC8m5k5/pvDANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMB4XDTE2MDgxNzIxNTIzMVoXDTE3MDgxNzIxNTIz
+MVowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEAum+qhr3Pv5/y71yUYHhv6BPy0ZZvzdkybiI3zkH5yl0prOEn2mGi7oHLEMff
+NFiVhuk9GeZcJ3NgyI14AvQdpJgJoxlwaTwlYmYqqyIjxXuFOE8uCXMyp70+m63K
+hAfmDzr/d8WdQYUAirab7rCkPy1MTOZCPrtRyN1IVPQMjkcCAwEAAaNGMEQwDgYD
+VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAw
+DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOBgQBGq0Si+yhU+Fpn+GKU
+8ZqyGJ7ysd4dfm92lam6512oFmyc9wnTN+RLKzZ8Aa1B0jLYw9KT+RBrjpW5LBeK
+o0RIvFkTgxYEiKSBXCUNmAysEbEoVr4dzWFihAm/1oDGRY2CLLTYg5vbySK3KhIR
+e/oCO8HJ/+rJnahJ05XX1Q7lNQ==
-----END CERTIFICATE-----`
const clientKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
-MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
-NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
-DNBNbocuXMXSu01LT862LPd+iOx81wKRdKYeDBra40paLt4TnExAiFmTAgMBAAEC
-gYBxvXd8yNteFTns8A/2yomEMC4yeosJJSpp1CsN3BJ7g8/qTnrVPxBy+RU+qr63
-t2WquaOu/cr5P8iEsa6lk20tf8pjKLNXeX0b1RTzK8rJLbS7nGzP3tvOhL096VtQ
-dAo4ROEaro0TzYpHmpciSvxVIeEIAAdFDObDJPKqcJAxyQJBAJizfYgK8Gzx9fsx
-hxp+VteCbVPg2euASH5Yv3K5LukRdKoSzHE2grUVQgN/LafC0eZibRanxHegYSr7
-7qaswKUCQQCEIWor/X4XTMdVj3Oj+vpiw75y/S9gh682+myZL+d/02IEkwnB098P
-RkKVpenBHyrGg0oeN5La7URILWKj7CPXAkBKo6F+d+phNjwIFoN1Xb/RA32w/D1I
-saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
-Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
-qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
-1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA
+MIICXQIBAAKBgQC6b6qGvc+/n/LvXJRgeG/oE/LRlm/N2TJuIjfOQfnKXSms4Sfa
+YaLugcsQx980WJWG6T0Z5lwnc2DIjXgC9B2kmAmjGXBpPCViZiqrIiPFe4U4Ty4J
+czKnvT6brcqEB+YPOv93xZ1BhQCKtpvusKQ/LUxM5kI+u1HI3UhU9AyORwIDAQAB
+AoGAEJZ03q4uuMb7b26WSQsOMeDsftdatT747LGgs3pNRkMJvTb/O7/qJjxoG+Mc
+qeSj0TAZXp+PXXc3ikCECAc+R8rVMfWdmp903XgO/qYtmZGCorxAHEmR80SrfMXv
+PJnznLQWc8U9nphQErR+tTESg7xWEzmFcPKwnZd1xg8ERYkCQQDTGtrFczlB2b/Z
+9TjNMqUlMnTLIk/a/rPE2fLLmAYhK5sHnJdvDURaH2mF4nso0EGtENnTsh6LATnY
+dkrxXGm9AkEA4hXHG2q3MnhgK1Z5hjv+Fnqd+8bcbII9WW4flFs15EKoMgS1w/PJ
+zbsySaSy5IVS8XeShmT9+3lrleed4sy+UwJBAJOOAbxhfXP5r4+5R6ql66jES75w
+jUCVJzJA5ORJrn8g64u2eGK28z/LFQbv9wXgCwfc72R468BdawFSLa/m2EECQGbZ
+rWiFla26IVXV0xcD98VWJsTBZMlgPnSOqoMdM1kSEd4fUmlAYI/dFzV1XYSkOmVr
+FhdZnklmpVDeu27P4c0CQQCuCOup0FlJSBpWY1TTfun/KMBkBatMz0VMA3d7FKIU
+csPezl677Yjo8u1r/KzeI6zLg87Z8E6r6ZWNc9wBSZK6
-----END RSA PRIVATE KEY-----`
const clientECDSACertificatePEM = `
@@ -978,6 +1056,7 @@ FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
-----END EC PRIVATE KEY-----`
func TestClientAuth(t *testing.T) {
+ setParallel(t)
var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string
if *update {
@@ -991,33 +1070,209 @@ func TestClientAuth(t *testing.T) {
defer os.Remove(ecdsaKeyPath)
}
- config := *testConfig
+ config := testConfig.Clone()
config.ClientAuth = RequestClientCert
test := &serverTest{
name: "ClientAuthRequestedNotGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
- config: &config,
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
+ config: config,
}
runServerTestTLS12(t, test)
test = &serverTest{
name: "ClientAuthRequestedAndGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
- config: &config,
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-cert", certPath, "-key", keyPath},
+ config: config,
expectedPeerCerts: []string{clientCertificatePEM},
}
runServerTestTLS12(t, test)
test = &serverTest{
name: "ClientAuthRequestedAndECDSAGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
- config: &config,
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+ config: config,
expectedPeerCerts: []string{clientECDSACertificatePEM},
}
runServerTestTLS12(t, test)
}
+func TestSNIGivenOnFailure(t *testing.T) {
+ const expectedServerName = "test.testing"
+
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ serverName: expectedServerName,
+ }
+
+ serverConfig := testConfig.Clone()
+ // Erase the server's cipher suites to ensure the handshake fails.
+ serverConfig.CipherSuites = nil
+
+ c, s := net.Pipe()
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ cli.writeRecord(recordTypeHandshake, clientHello.marshal())
+ c.Close()
+ }()
+ hs := serverHandshakeState{
+ c: Server(s, serverConfig),
+ }
+ _, err := hs.readClientHello()
+ defer s.Close()
+
+ if err == nil {
+ t.Error("No error reported from server")
+ }
+
+ cs := hs.c.ConnectionState()
+ if cs.HandshakeComplete {
+ t.Error("Handshake registered as complete")
+ }
+
+ if cs.ServerName != expectedServerName {
+ t.Errorf("Expected ServerName of %q, but got %q", expectedServerName, cs.ServerName)
+ }
+}
+
+var getConfigForClientTests = []struct {
+ setup func(config *Config)
+ callback func(clientHello *ClientHelloInfo) (*Config, error)
+ errorSubstring string
+ verify func(config *Config) error
+}{
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, nil
+ },
+ "",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, errors.New("should bubble up")
+ },
+ "should bubble up",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ // Setting a maximum version of TLS 1.1 should cause
+ // the handshake to fail.
+ config.MaxVersion = VersionTLS11
+ return config, nil
+ },
+ "version 301 when expecting version 302",
+ nil,
+ },
+ {
+ func(config *Config) {
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = byte(i)
+ }
+ config.sessionTicketKeys = nil
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = 0
+ }
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ // The value of SessionTicketKey should have been
+ // duplicated into the per-connection Config.
+ for i := range config.SessionTicketKey {
+ if b := config.SessionTicketKey[i]; b != byte(i) {
+ return fmt.Errorf("SessionTicketKey was not duplicated from original Config: byte %d has value %d", i, b)
+ }
+ }
+ return nil
+ },
+ },
+ {
+ func(config *Config) {
+ var dummyKey [32]byte
+ for i := range dummyKey {
+ dummyKey[i] = byte(i)
+ }
+
+ config.SetSessionTicketKeys([][32]byte{dummyKey})
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ // The session ticket keys should have been duplicated
+ // into the per-connection Config.
+ if l := len(config.sessionTicketKeys); l != 1 {
+ return fmt.Errorf("got len(sessionTicketKeys) == %d, wanted 1", l)
+ }
+ return nil
+ },
+ },
+}
+
+func TestGetConfigForClient(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ clientConfig := testConfig.Clone()
+ clientConfig.MinVersion = VersionTLS12
+
+ for i, test := range getConfigForClientTests {
+ if test.setup != nil {
+ test.setup(serverConfig)
+ }
+
+ var configReturned *Config
+ serverConfig.GetConfigForClient = func(clientHello *ClientHelloInfo) (*Config, error) {
+ config, err := test.callback(clientHello)
+ configReturned = config
+ return config, err
+ }
+ c, s := net.Pipe()
+ done := make(chan error)
+
+ go func() {
+ defer s.Close()
+ done <- Server(s, serverConfig).Handshake()
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ serverErr := <-done
+
+ if len(test.errorSubstring) == 0 {
+ if serverErr != nil || clientErr != nil {
+ t.Errorf("test[%d]: expected no error but got serverErr: %q, clientErr: %q", i, serverErr, clientErr)
+ }
+ if test.verify != nil {
+ if err := test.verify(configReturned); err != nil {
+ t.Errorf("test[%d]: verify returned error: %v", i, err)
+ }
+ }
+ } else {
+ if serverErr == nil {
+ t.Errorf("test[%d]: expected error containing %q but got no error", i, test.errorSubstring)
+ } else if !strings.Contains(serverErr.Error(), test.errorSubstring) {
+ t.Errorf("test[%d]: expected error to contain %q but it was %q", i, test.errorSubstring, serverErr)
+ }
+ }
+ }
+}
+
func bigFromString(s string) *big.Int {
ret := new(big.Int)
ret.SetString(s, 10)
@@ -1029,23 +1284,23 @@ func fromHex(s string) []byte {
return b
}
-var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a64316600baf48e92afc76bd876d4f35f41cb6e5615971b97c13c123921663d2b16d1bcdb1cc0a7dab7caadbadacbd52150ecde8dabd16b814b8902f3c4bec16c89b14484bd21d1047d9d164df98215f6effad60947f2fb0203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e0412041012508d896f1bd1dc544d6ecb695e06f4301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a4130190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b050003818100927caf91551218965931a64840d52dd5eebb02a0f5c21e7c9bb3307d3cdc76da4f3dc0faae2d33246b037b1b67591121b511bc77b9d9e06ea82d2e35fa645f223e63106bbeff14866d0df01531a814381e3b84872ccb98ed5176b9b14fdddb9b84048640fa51ddbab48debe346de46b94f86c7f9a4c24134acccf6eab0ab3918")
+var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
-var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1de24338d6d5e5a91cc8301628445d6eb4e675927b9c1ea5c0f676acfb0f708ce4f19827e321c1898bf86df9823d5f0b05df2b6779888eff8abbc7f41c6e7d2667386a579b8cbaad3f6fd597cd7c4b187911a425aed1b555c1965190203010001a37a3078300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e04120410bf3db6a966f2b840cfeab40378481a41301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a41300d06092a864886f70d01010b050003818100586e68c1219ed4f5782b7cfd53cf1a55750a98781b2023f8694bb831fff6d7d4aad1f0ac782b1ec787f00a8956bdd06b4a1063444fcafe955c07d679163a730802c568886a2cf8a3c2ab41176957131c4b9e077ebd7ffbb91fdad8b08b932e9aeefac04923ffdc0aa145563f7f061995317400203578f350e3e566deb29dec5e")
+var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76")
var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+var testSNICertificate = fromHex("0441883421114c81480804c430820237308201a0a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a3023310b3009060355040a1302476f311430120603550403130b736e69746573742e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a3773075300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b0500038181007beeecff0230dbb2e7a334af65430b7116e09f327c3bbf918107fc9c66cb497493207ae9b4dbb045cb63d605ec1b5dd485bb69124d68fa298dc776699b47632fd6d73cab57042acb26f083c4087459bc5a3bb3ca4d878d7fe31016b7bc9a627438666566e3389bfaeebe6becc9a0093ceed18d0f9ac79d56f3a73f18188988ed")
var testRSAPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
- N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"),
+ N: bigFromString("153980389784927331788354528594524332344709972855165340650588877572729725338415474372475094155672066328274535240275856844648695200875763869073572078279316458648124537905600131008790701752441155668003033945258023841165089852359980273279085783159654751552359397986180318708491098942831252291841441726305535546071"),
E: 65537,
},
- D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"),
+ D: bigFromString("7746362285745539358014631136245887418412633787074173796862711588221766398229333338511838891484974940633857861775630560092874987828057333663969469797013996401149696897591265769095952887917296740109742927689053276850469671231961384712725169432413343763989564437170644270643461665184965150423819594083121075825"),
Primes: []*big.Int{
- bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"),
- bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"),
+ bigFromString("13299275414352936908236095374926261633419699590839189494995965049151460173257838079863316944311313904000258169883815802963543635820059341150014695560313417"),
+ bigFromString("11578103692682951732111718237224894755352163854919244905974423810539077224889290605729035287537520656160688625383765857517518932447378594964220731750802463"),
},
}
diff --git a/libgo/go/crypto/tls/handshake_test.go b/libgo/go/crypto/tls/handshake_test.go
index f95f274ab4..8e5410a17d 100644
--- a/libgo/go/crypto/tls/handshake_test.go
+++ b/libgo/go/crypto/tls/handshake_test.go
@@ -13,9 +13,11 @@ import (
"io"
"io/ioutil"
"net"
+ "os/exec"
"strconv"
"strings"
"sync"
+ "testing"
)
// TLS reference tests run a connection against a reference implementation
@@ -35,7 +37,52 @@ import (
// generate fresh random numbers, large parts of the reference connection will
// always change.
-var update = flag.Bool("update", false, "update golden files on disk")
+var (
+ update = flag.Bool("update", false, "update golden files on disk")
+
+ opensslVersionTestOnce sync.Once
+ opensslVersionTestErr error
+)
+
+func checkOpenSSLVersion(t *testing.T) {
+ opensslVersionTestOnce.Do(testOpenSSLVersion)
+ if opensslVersionTestErr != nil {
+ t.Fatal(opensslVersionTestErr)
+ }
+}
+
+func testOpenSSLVersion() {
+ // This test ensures that the version of OpenSSL looks reasonable
+ // before updating the test data.
+
+ if !*update {
+ return
+ }
+
+ openssl := exec.Command("openssl", "version")
+ output, err := openssl.CombinedOutput()
+ if err != nil {
+ opensslVersionTestErr = err
+ return
+ }
+
+ version := string(output)
+ if strings.HasPrefix(version, "OpenSSL 1.1.0") {
+ return
+ }
+
+ println("***********************************************")
+ println("")
+ println("You need to build OpenSSL 1.1.0 from source in order")
+ println("to update the test data.")
+ println("")
+ println("Configure it with:")
+ println("./Configure enable-weak-ssl-ciphers enable-ssl3 enable-ssl3-method -static linux-x86_64")
+ println("and then add the apps/ directory at the front of your PATH.")
+ println("***********************************************")
+
+ opensslVersionTestErr = errors.New("version of OpenSSL does not appear to be suitable for updating test data")
+}
// recordingConn is a net.Conn that records the traffic that passes through it.
// WriteTo can be used to produce output that can be later be loaded with
@@ -88,21 +135,33 @@ func (r *recordingConn) Write(b []byte) (n int, err error) {
}
// WriteTo writes Go source code to w that contains the recorded traffic.
-func (r *recordingConn) WriteTo(w io.Writer) {
+func (r *recordingConn) WriteTo(w io.Writer) (int64, error) {
// TLS always starts with a client to server flow.
clientToServer := true
-
+ var written int64
for i, flow := range r.flows {
source, dest := "client", "server"
if !clientToServer {
source, dest = dest, source
}
- fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ n, err := fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
dumper := hex.Dumper(w)
- dumper.Write(flow)
- dumper.Close()
+ n, err = dumper.Write(flow)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
+ err = dumper.Close()
+ if err != nil {
+ return written, err
+ }
clientToServer = !clientToServer
}
+ return written, nil
}
func parseTestData(r io.Reader) (flows [][]byte, err error) {
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
index 0e6a7c2262..1b27c049ed 100644
--- a/libgo/go/crypto/tls/key_agreement.go
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -16,6 +16,8 @@ import (
"errors"
"io"
"math/big"
+
+ "golang_org/x/crypto/curve25519"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
@@ -51,7 +53,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
if err != nil {
return nil, err
}
- // We don't check the version number in the premaster secret. For one,
+ // We don't check the version number in the premaster secret. For one,
// by checking it, we would leak information about the validity of the
// encrypted pre-master secret. Secondly, it provides only a small
// benefit against a downgrade attack and some implementations send the
@@ -177,52 +179,71 @@ type ecdheKeyAgreement struct {
version uint16
sigType uint8
privateKey []byte
- curve elliptic.Curve
- x, y *big.Int
+ curveid CurveID
+
+ // publicKey is used to store the peer's public value when X25519 is
+ // being used.
+ publicKey []byte
+ // x and y are used to store the peer's public value when one of the
+ // NIST curves is being used.
+ x, y *big.Int
}
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
- var curveid CurveID
preferredCurves := config.curvePreferences()
NextCandidate:
for _, candidate := range preferredCurves {
for _, c := range clientHello.supportedCurves {
if candidate == c {
- curveid = c
+ ka.curveid = c
break NextCandidate
}
}
}
- if curveid == 0 {
+ if ka.curveid == 0 {
return nil, errors.New("tls: no supported elliptic curves offered")
}
- var ok bool
- if ka.curve, ok = curveForCurveID(curveid); !ok {
- return nil, errors.New("tls: preferredCurves includes unsupported curve")
- }
+ var ecdhePublic []byte
- var x, y *big.Int
- var err error
- ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
- if err != nil {
- return nil, err
+ if ka.curveid == X25519 {
+ var scalar, public [32]byte
+ if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+ return nil, err
+ }
+
+ curve25519.ScalarBaseMult(&public, &scalar)
+ ka.privateKey = scalar[:]
+ ecdhePublic = public[:]
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ return nil, errors.New("tls: preferredCurves includes unsupported curve")
+ }
+
+ var x, y *big.Int
+ var err error
+ ka.privateKey, x, y, err = elliptic.GenerateKey(curve, config.rand())
+ if err != nil {
+ return nil, err
+ }
+ ecdhePublic = elliptic.Marshal(curve, x, y)
}
- ecdhePublic := elliptic.Marshal(ka.curve, x, y)
// http://tools.ietf.org/html/rfc4492#section-5.4
serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHParams[0] = 3 // named curve
- serverECDHParams[1] = byte(curveid >> 8)
- serverECDHParams[2] = byte(curveid)
+ serverECDHParams[1] = byte(ka.curveid >> 8)
+ serverECDHParams[2] = byte(ka.curveid)
serverECDHParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic)
sigAndHash := signatureAndHash{signature: ka.sigType}
if ka.version >= VersionTLS12 {
+ var err error
if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
return nil, err
}
@@ -242,19 +263,19 @@ NextCandidate:
case signatureECDSA:
_, ok := priv.Public().(*ecdsa.PublicKey)
if !ok {
- return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
+ return nil, errors.New("tls: ECDHE ECDSA requires an ECDSA server key")
}
case signatureRSA:
_, ok := priv.Public().(*rsa.PublicKey)
if !ok {
- return nil, errors.New("ECDHE RSA requires a RSA server key")
+ return nil, errors.New("tls: ECDHE RSA requires a RSA server key")
}
default:
- return nil, errors.New("unknown ECDHE signature algorithm")
+ return nil, errors.New("tls: unknown ECDHE signature algorithm")
}
sig, err = priv.Sign(config.rand(), digest, hashFunc)
if err != nil {
- return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+ return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
}
skx := new(serverKeyExchangeMsg)
@@ -281,15 +302,32 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errClientKeyExchange
}
- x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
+
+ if ka.curveid == X25519 {
+ if len(ckx.ciphertext) != 1+32 {
+ return nil, errClientKeyExchange
+ }
+
+ var theirPublic, sharedKey, scalar [32]byte
+ copy(theirPublic[:], ckx.ciphertext[1:])
+ copy(scalar[:], ka.privateKey)
+ curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+ return sharedKey[:], nil
+ }
+
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ panic("internal error")
+ }
+ x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:])
if x == nil {
return nil, errClientKeyExchange
}
- if !ka.curve.IsOnCurve(x, y) {
+ if !curve.IsOnCurve(x, y) {
return nil, errClientKeyExchange
}
- x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
- preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
+ x, _ = curve.ScalarMult(x, y, ka.privateKey)
+ preMasterSecret := make([]byte, (curve.Params().BitSize+7)>>3)
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
@@ -303,31 +341,40 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if skx.key[0] != 3 { // named curve
return errors.New("tls: server selected unsupported curve")
}
- curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
-
- var ok bool
- if ka.curve, ok = curveForCurveID(curveid); !ok {
- return errors.New("tls: server selected unsupported curve")
- }
+ ka.curveid = CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
return errServerKeyExchange
}
- ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen])
- if ka.x == nil {
- return errServerKeyExchange
- }
- if !ka.curve.IsOnCurve(ka.x, ka.y) {
- return errServerKeyExchange
- }
serverECDHParams := skx.key[:4+publicLen]
+ publicKey := serverECDHParams[4:]
sig := skx.key[4+publicLen:]
if len(sig) < 2 {
return errServerKeyExchange
}
+ if ka.curveid == X25519 {
+ if len(publicKey) != 32 {
+ return errors.New("tls: bad X25519 public value")
+ }
+ ka.publicKey = publicKey
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ return errors.New("tls: server selected unsupported curve")
+ }
+
+ ka.x, ka.y = elliptic.Unmarshal(curve, publicKey)
+ if ka.x == nil {
+ return errServerKeyExchange
+ }
+ if !curve.IsOnCurve(ka.x, ka.y) {
+ return errServerKeyExchange
+ }
+ }
+
sigAndHash := signatureAndHash{signature: ka.sigType}
if ka.version >= VersionTLS12 {
// handle SignatureAndHashAlgorithm
@@ -354,47 +401,68 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
case signatureECDSA:
pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
- return errors.New("ECDHE ECDSA requires a ECDSA server public key")
+ return errors.New("tls: ECDHE ECDSA requires a ECDSA server public key")
}
ecdsaSig := new(ecdsaSignature)
if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
return err
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return errors.New("ECDSA signature contained zero or negative values")
+ return errors.New("tls: ECDSA signature contained zero or negative values")
}
if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
- return errors.New("ECDSA verification failure")
+ return errors.New("tls: ECDSA verification failure")
}
case signatureRSA:
pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
- return errors.New("ECDHE RSA requires a RSA server public key")
+ return errors.New("tls: ECDHE RSA requires a RSA server public key")
}
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
return err
}
default:
- return errors.New("unknown ECDHE signature algorithm")
+ return errors.New("tls: unknown ECDHE signature algorithm")
}
return nil
}
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
- if ka.curve == nil {
- return nil, nil, errors.New("missing ServerKeyExchange message")
- }
- priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
- if err != nil {
- return nil, nil, err
+ if ka.curveid == 0 {
+ return nil, nil, errors.New("tls: missing ServerKeyExchange message")
}
- x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
- preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
- xBytes := x.Bytes()
- copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
- serialized := elliptic.Marshal(ka.curve, mx, my)
+ var serialized, preMasterSecret []byte
+
+ if ka.curveid == X25519 {
+ var ourPublic, theirPublic, sharedKey, scalar [32]byte
+
+ if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+ return nil, nil, err
+ }
+
+ copy(theirPublic[:], ka.publicKey)
+ curve25519.ScalarBaseMult(&ourPublic, &scalar)
+ curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+ serialized = ourPublic[:]
+ preMasterSecret = sharedKey[:]
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ panic("internal error")
+ }
+ priv, mx, my, err := elliptic.GenerateKey(curve, config.rand())
+ if err != nil {
+ return nil, nil, err
+ }
+ x, _ := curve.ScalarMult(ka.x, ka.y, priv)
+ preMasterSecret = make([]byte, (curve.Params().BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ serialized = elliptic.Marshal(curve, mx, my)
+ }
ckx := new(clientKeyExchangeMsg)
ckx.ciphertext = make([]byte, 1+len(serialized))
diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go
index 747b817ba3..5833fc1963 100644
--- a/libgo/go/crypto/tls/prf.go
+++ b/libgo/go/crypto/tls/prf.go
@@ -85,7 +85,7 @@ func prf30(result, secret, label, seed []byte) {
done := 0
i := 0
- // RFC5246 section 6.3 says that the largest PRF output needed is 128
+ // RFC 5246 section 6.3 says that the largest PRF output needed is 128
// bytes. Since no more ciphersuites will be added to SSLv3, this will
// remain true. Each iteration gives us 16 bytes so 10 iterations will
// be sufficient.
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
index a62d27d5e3..099cef4ba9 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 38 1a 94 8d 84 |....Y...U..8....|
-00000010 d7 a4 29 89 50 ad 07 97 5b c0 2c 7b 8c a6 75 0e |..).P...[.,{..u.|
-00000020 97 51 62 10 07 87 c5 6f 0a 5f 86 20 1d ac 1d 05 |.Qb....o._. ....|
-00000030 ea 85 48 84 73 d9 07 8d d0 81 56 99 81 10 7b 18 |..H.s.....V...{.|
-00000040 e8 5e da a9 fe cd f9 91 88 31 9b 6e c0 09 00 00 |.^.......1.n....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 4f 5d 09 43 37 |....Y...U..O].C7|
+00000010 70 c6 d9 8b 07 ca 1a f0 fb a7 05 51 53 67 7a 7e |p..........QSgz~|
+00000020 c9 c6 68 10 10 2a 69 bd 47 db 8e 20 f2 13 5b 26 |..h..*i.G.. ..[&|
+00000030 e6 8e 19 b0 bc b5 ee 1f ca 44 5d 32 11 37 b0 78 |.........D]2.7.x|
+00000040 49 16 6e c2 44 86 52 3f 9f 05 15 aa c0 09 00 00 |I.n.D.R?........|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,21 +49,20 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 68 |*............A.h|
-00000280 37 18 3d 57 d2 5a 39 75 1e 7f 0a 3a 47 65 36 2e |7.=W.Z9u...:Ge6.|
-00000290 6d cb 8f aa 0f 0d 45 5e 3f 14 82 f5 8c b1 11 0a |m.....E^?.......|
-000002a0 8f e0 bc e4 07 d3 d5 bf 2d f4 82 ba cf c9 1c 88 |........-.......|
-000002b0 33 72 a8 49 39 48 40 74 c6 96 c3 30 72 31 34 00 |3r.I9H@t...0r14.|
-000002c0 8a 30 81 87 02 41 0e 43 2d 29 81 e9 c3 07 fc 5c |.0...A.C-).....\|
-000002d0 ad c0 51 9e 0f cf c5 77 e4 bf 00 b6 66 f9 0e c6 |..Q....w....f...|
-000002e0 40 c6 b5 49 a4 04 05 31 2c 7c 1f 24 38 80 1b 3f |@..I...1,|.$8..?|
-000002f0 16 5f c7 4d a8 7d 98 50 7f 7d 6d ed e9 19 1d 19 |._.M.}.P.}m.....|
-00000300 7b fd ec c5 4d 18 ab 02 42 01 00 db 37 b7 fa 39 |{...M...B...7..9|
-00000310 4b 3f 16 06 eb b8 4a 22 c6 de 00 d8 a7 eb a2 9e |K?....J"........|
-00000320 e1 6f f4 a4 32 e2 ca d0 72 3a e5 f3 14 27 a0 dd |.o..2...r:...'..|
-00000330 c4 26 34 b3 6c a3 d0 03 90 7a 2e 0e bf 0b 63 63 |.&4.l....z....cc|
-00000340 77 66 37 dd 1a 0f 7a 90 3f c8 a9 16 03 01 00 0e |wf7...z.?.......|
-00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 56 b4 |*............ V.|
+00000280 39 d4 8f 18 79 87 89 d0 04 ee 12 54 20 2b be c1 |9...y......T +..|
+00000290 94 99 40 a2 73 df 1e 92 66 0b d1 f1 d6 38 00 8b |..@.s...f....8..|
+000002a0 30 81 88 02 42 01 38 12 59 bd ea 44 59 f4 6f a9 |0...B.8.Y..DY.o.|
+000002b0 8e 9e a0 85 b5 b3 55 3e 76 49 b7 75 98 6e 81 30 |......U>vI.u.n.0|
+000002c0 c4 73 bd 54 78 39 f7 e2 22 49 4c 93 0d c1 26 89 |.s.Tx9.."IL...&.|
+000002d0 08 b9 9c 8b 86 3e 81 2c a5 50 7c e9 88 ec c0 ad |.....>.,.P|.....|
+000002e0 9e e0 40 ac 4e 0a fd 02 42 01 2e 0d 37 73 6a 0d |..@.N...B...7sj.|
+000002f0 a4 60 08 a0 2b 32 0f 87 8d f8 9b c7 68 cf 50 79 |.`..+2......h.Py|
+00000300 73 f7 cf 93 aa 75 57 20 58 3d 13 c0 f3 66 7d 59 |s....uW X=...f}Y|
+00000310 15 73 d4 29 03 34 df 33 00 c0 b5 71 bc 2a 90 ef |.s.).4.3...q.*..|
+00000320 3c 02 5e ea 9d 29 93 1c 18 db 04 16 03 01 00 0a |<.^..)..........|
+00000330 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000340 00 00 00 |...|
>>> Flow 3 (client to server)
00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -97,34 +97,32 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
-00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 90 0f |.h.A.Vk.Z.......|
-00000260 00 00 8c 00 8a 30 81 87 02 41 51 c5 53 a8 0f cb |.....0...AQ.S...|
-00000270 18 79 4a 59 53 62 17 bb 29 39 fa cd 56 6c 5c 29 |.yJYSb..)9..Vl\)|
-00000280 1f e3 bc df fb 9a 29 fa 38 1a 73 aa 4c 79 6b 1c |......).8.s.Lyk.|
-00000290 9f 1c 8e 95 c7 11 cc df 5d e9 c7 93 ce a3 9b e6 |........].......|
-000002a0 94 17 24 3a 8e f8 9a a9 46 01 f9 02 42 01 a1 df |..$:....F...B...|
-000002b0 c5 cc fe 8d 5b 34 fb 89 2f f5 b3 3f 75 d7 19 1b |....[4../..?u...|
-000002c0 5e 0f 1a 2e 8f 2d 62 61 73 85 2c 03 3b 22 07 2f |^....-bas.,.;"./|
-000002d0 6b f3 5c fb ba b2 87 54 1c ef d2 f8 82 f3 9e f8 |k.\....T........|
-000002e0 ce 1b fa ce b0 6d d0 85 f8 62 6e d6 ba 93 cc 14 |.....m...bn.....|
-000002f0 03 01 00 01 01 16 03 01 00 30 76 90 a8 a2 8d 25 |.........0v....%|
-00000300 c5 c2 ff ef 2b 76 83 2c 7a 0d 44 37 99 67 02 d3 |....+v.,z.D7.g..|
-00000310 6e 3b 28 83 21 cf f5 6a 71 61 2d 5b 24 57 b2 19 |n;(.!..jqa-[$W..|
-00000320 63 d4 e5 96 0c 0c e1 f3 3a 99 |c.......:.|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 53 2c a8 59 57 d2 |....0...B.S,.YW.|
+00000250 fc 0b 12 27 6f 9a f7 4e a0 dd 2c af 1b 4c 81 0b |...'o..N..,..L..|
+00000260 97 79 7e 6f dd a1 cf cb e2 14 4d af 76 99 d8 06 |.y~o......M.v...|
+00000270 4f 8d 4f 86 d3 25 04 ea 80 02 ae 25 10 9d 2d 59 |O.O..%.....%..-Y|
+00000280 11 39 65 6b 83 d0 16 7d bf a8 a4 02 42 01 f2 16 |.9ek...}....B...|
+00000290 6c f1 e6 3b b1 af fb 3f 99 f0 8a e3 c8 62 ba 71 |l..;...?.....b.q|
+000002a0 12 a1 2c 1e 15 74 d5 98 b5 ae 9f 50 a2 15 9b 73 |..,..t.....P...s|
+000002b0 9a 5f 2c 90 d4 9d 20 6f 35 b6 32 3e f4 b7 dd 50 |._,... o5.2>...P|
+000002c0 64 42 e3 4e 51 f3 11 4b b4 9e a3 92 a2 10 59 14 |dB.NQ..K......Y.|
+000002d0 03 01 00 01 01 16 03 01 00 30 78 8c 7c 31 ce 16 |.........0x.|1..|
+000002e0 8f 1f 2a b9 ee cb 72 7f 1e 59 5b ad c2 58 32 77 |..*...r..Y[..X2w|
+000002f0 fa 46 83 b9 67 0c 5f 41 25 6a 38 ec 20 d2 80 e6 |.F..g._A%j8. ...|
+00000300 be 85 ce 94 b1 89 5f 8d 17 9b |......_...|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 37 f0 ad 4c 11 |..........07..L.|
-00000010 6d fb 54 90 13 d2 10 93 43 d8 be 3b d0 2b 14 a5 |m.T.....C..;.+..|
-00000020 9d fb a6 5d 38 e0 f5 e9 a6 0a 8e 3d 99 a2 ec 96 |...]8......=....|
-00000030 d8 ff 90 13 03 99 33 d7 15 29 5f |......3..)_|
+00000000 14 03 01 00 01 01 16 03 01 00 30 95 d6 f2 a2 75 |..........0....u|
+00000010 0e f8 c7 7c f9 1d 65 b4 82 08 c9 62 aa 93 24 8f |...|..e....b..$.|
+00000020 4d 11 c7 b0 17 04 f1 0a 8b be 64 06 f9 07 20 0b |M.........d... .|
+00000030 f0 3b 92 db 62 ba 63 91 a1 58 fe |.;..b.c..X.|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 f9 59 b0 e2 8b f9 2c dd 30 1b 8f |.... .Y....,.0..|
-00000010 df 85 0f 17 88 23 5e ca c9 d3 ca 5f 52 d4 33 e0 |.....#^...._R.3.|
-00000020 d2 62 54 17 f2 17 03 01 00 20 62 2d 28 d2 55 68 |.bT...... b-(.Uh|
-00000030 77 ab 6e c0 ac d9 cd 31 1c 38 aa 07 b3 e8 0d 89 |w.n....1.8......|
-00000040 7e e4 f3 a0 65 84 f6 b8 c8 91 15 03 01 00 20 b5 |~...e......... .|
-00000050 95 69 90 d7 32 d1 5a a5 e0 e2 6c 0a dc 00 1c 5e |.i..2.Z...l....^|
-00000060 d2 10 2b a2 3e ae a5 b2 63 9f c4 4e 62 56 db |..+.>...c..NbV.|
+00000000 17 03 01 00 20 3e a4 b5 b5 2f 4f c8 e0 08 cf 8a |.... >.../O.....|
+00000010 9c f6 69 94 a9 91 0f 5d c5 06 ee 71 e2 42 11 b4 |..i....]...q.B..|
+00000020 a8 17 54 19 3d 17 03 01 00 20 ce d2 8d 8a 78 e4 |..T.=.... ....x.|
+00000030 15 a4 ab 83 0d 9c fa 47 1c 8f 2d 87 a8 55 65 9d |.......G..-..Ue.|
+00000040 7f 03 75 11 62 83 0b 44 0b f1 15 03 01 00 20 eb |..u.b..D...... .|
+00000050 1a 46 95 1e 1b 10 b7 25 a8 c4 5b db 8b 3c 61 c9 |.F.....%..[..<a.|
+00000060 25 38 27 1e 69 11 18 16 0a 25 44 ad 9f 52 64 |%8'.i....%D..Rd|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
index 298cbe1df5..7e9c2724ab 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -1,60 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 4e 15 d3 06 f6 |....Q...M..N....|
-00000010 ec 13 16 c5 fa 59 cf 5e 2f ad 85 b9 38 e7 7f fb |.....Y.^/...8...|
-00000020 85 cb da eb f2 2e 17 51 a2 b0 be 20 61 e4 32 c9 |.......Q... a.2.|
-00000030 66 92 36 89 0c 0c f4 00 15 47 86 d9 e9 90 ab 2d |f.6......G.....-|
-00000040 8f a3 e2 5e f6 44 2c 6a 1d 98 88 5c 00 05 00 00 |...^.D,j...\....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 32 7c 5c ac bd |....Y...U..2|\..|
+00000010 77 70 c2 f8 f0 20 37 e4 e8 45 db be 97 22 e4 f3 |wp... 7..E..."..|
+00000020 24 1c c1 29 8f 02 e1 bc ba 4a 1e 20 81 6f b5 12 |$..).....J. .o..|
+00000030 c0 9d 9e de 2f b6 04 b2 74 34 da 2b 04 55 2c 4f |..../...t4.+.U,O|
+00000040 dd 01 8a 30 d9 67 45 9f f1 31 f1 78 c0 13 00 00 |...0.gE..1.x....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 2f f7 3b 44 1a 47 85 |........ /.;D.G.|
+000002d0 d7 db 40 28 4e 6a f1 2f 1e b5 cc b0 58 0d 92 93 |..@(Nj./....X...|
+000002e0 30 41 65 08 05 f7 51 23 57 00 80 87 0d c3 22 ff |0Ae...Q#W.....".|
+000002f0 aa d1 3f 55 09 cf 98 dc 91 f8 d0 63 58 da dc 52 |..?U.......cX..R|
+00000300 03 f0 06 a6 4e 7e 5b 96 a1 3b d7 8e 1e 68 50 ef |....N~[..;...hP.|
+00000310 59 3f 78 06 eb 9a 33 c5 01 3c e0 fb c6 f1 b6 bc |Y?x...3..<......|
+00000320 5a bc 95 e8 43 d9 ab 36 05 26 13 c5 a6 68 9b e2 |Z...C..6.&...h..|
+00000330 b1 42 6e 89 60 5c b3 91 02 c5 8b ab 53 d1 d9 79 |.Bn.`\......S..y|
+00000340 d0 37 b5 5e 2c 16 72 29 f8 9c d0 4a 46 87 46 f4 |.7.^,.r)...JF.F.|
+00000350 01 2b e8 6a 4f 59 d1 2d 3d de 4b 3b 0e c7 cd 42 |.+.jOY.-=.K;...B|
+00000360 ae d2 94 e9 a6 6b 65 ad 3f 77 57 16 03 01 00 0a |.....ke.?wW.....|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -89,33 +101,32 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..|
-00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....|
-00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S|
-00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...|
-00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e|
-00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...|
-00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR|
-00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M|
-00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 91 0f |.x.N.8FB........|
-000002a0 00 00 8d 00 8b 30 81 88 02 42 01 45 b9 8f b1 1f |.....0...B.E....|
-000002b0 72 80 2c 4f 2c 65 58 db 40 7e f1 d5 14 0b cc 4c |r.,O,eX.@~.....L|
-000002c0 8b 50 5c ee 93 45 95 3d fe 00 5e 5e ca 13 56 8d |.P\..E.=..^^..V.|
-000002d0 2b b3 1a 22 70 3f d2 41 cf 74 8f c3 0f 37 ba 97 |+.."p?.A.t...7..|
-000002e0 cb 29 16 77 92 df 19 35 f9 8a a0 8e 02 42 01 00 |.).w...5.....B..|
-000002f0 3f 8b ce b1 2a 01 43 e8 2c b5 27 d1 19 bc 04 b3 |?...*.C.,.'.....|
-00000300 c3 ad bf e8 12 37 57 6f c9 01 7c 8e f4 4d 88 39 |.....7Wo..|..M.9|
-00000310 4b 00 f6 ff fd 38 39 f8 3e 7f 49 d4 6a 82 94 6a |K....89.>.I.j..j|
-00000320 d3 f4 17 f2 a9 e0 ef 85 1e 01 85 b6 ca 89 91 ee |................|
-00000330 14 03 01 00 01 01 16 03 01 00 24 8d 82 24 82 55 |..........$..$.U|
-00000340 c4 0e 45 8c f0 f3 e3 29 4e ff 6c ee 43 4b ca 68 |..E....)N.l.CK.h|
-00000350 2e 12 98 cf ce b6 7e fa 73 07 e1 0f aa 7f 80 |......~.s......|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 b3 df 59 06 71 e6 |....0...B...Y.q.|
+00000250 74 c9 9d d5 2c b0 a7 f8 1e ac bc f3 5a e2 ed 0b |t...,.......Z...|
+00000260 f2 e9 37 82 c6 fe 7c 23 b9 63 6e 88 1d 63 31 ad |..7...|#.cn..c1.|
+00000270 d3 29 48 eb f3 5d 52 f5 76 ab fc 16 9e 09 4f 49 |.)H..]R.v.....OI|
+00000280 cf b4 03 6a ed db e5 13 ea 67 74 02 42 01 8e 2f |...j.....gt.B../|
+00000290 b8 12 38 c9 a6 8c 77 40 85 89 ef d8 ac 08 00 c0 |..8...w@........|
+000002a0 ee 70 68 a6 88 1f d1 67 0d 1b 7b 1f be e0 a7 b9 |.ph....g..{.....|
+000002b0 c3 7d ff 6a 39 3c b9 aa f6 78 ac 9a ca 67 55 0c |.}.j9<...x...gU.|
+000002c0 38 23 cc ab 18 c0 b9 ea 9c 84 61 32 0a 0d f3 14 |8#........a2....|
+000002d0 03 01 00 01 01 16 03 01 00 30 73 12 76 94 30 37 |.........0s.v.07|
+000002e0 e5 e3 30 59 88 2f 5f e9 f2 7b 3d 02 88 65 09 14 |..0Y./_..{=..e..|
+000002f0 68 23 02 d0 ae e5 7f 7f 8d 95 3b 1c 75 f5 1f 24 |h#........;.u..$|
+00000300 43 60 29 bb 0e 69 88 36 a9 68 |C`)..i.6.h|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 21 a3 eb a6 f5 |..........$!....|
-00000010 d0 17 38 9b 89 ec f3 39 23 33 f6 49 51 41 97 92 |..8....9#3.IQA..|
-00000020 a6 64 bd 60 68 9d 0e 45 06 2f dd ff 79 b6 50 |.d.`h..E./..y.P|
+00000000 14 03 01 00 01 01 16 03 01 00 30 a0 5f 7f 59 e0 |..........0._.Y.|
+00000010 b1 7e ed ad de 6a 47 94 21 e5 1b 77 a7 d0 88 fd |.~...jG.!..w....|
+00000020 9e 4e 48 87 1d cf 40 e4 b9 38 a3 2e e4 00 c3 94 |.NH...@..8......|
+00000030 95 20 1c 97 d2 a9 3a 11 86 30 5f |. ....:..0_|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a d2 72 d5 91 9d fc 6c 22 02 cc 32 |......r....l"..2|
-00000010 58 5c 8a f6 75 11 48 e1 3f e4 e5 81 29 63 62 15 |X\..u.H.?...)cb.|
-00000020 03 01 00 16 b6 9a 1f 43 d4 ae b7 16 25 ce ae b7 |.......C....%...|
-00000030 6c 37 f7 35 0a 26 7d ea 1f 80 |l7.5.&}...|
+00000000 17 03 01 00 20 ca 4c f5 cb 81 66 2f 97 e3 5d 8b |.... .L...f/..].|
+00000010 dd 7d dd fa fe 8c 98 45 3f 3d 16 17 98 4d b5 15 |.}.....E?=...M..|
+00000020 6c 91 8a 79 7a 17 03 01 00 20 96 ec 30 cb d3 78 |l..yz.... ..0..x|
+00000030 b9 0a a1 ab fd 12 25 d5 82 7b 7a 3c 17 56 7b b7 |......%..{z<.V{.|
+00000040 c4 6e ea a2 5b d7 6b b6 22 a9 15 03 01 00 20 ba |.n..[.k."..... .|
+00000050 ff fe 2b 60 83 34 ad 45 75 15 d5 95 b3 27 92 46 |..+`.4.Eu....'.F|
+00000060 47 ae f1 d4 a4 9d 63 ef db d9 b5 37 0f f1 74 |G.....c....7..t|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
index ba4976df3b..67772e174a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 eb ed 76 6a 07 |....Y...U....vj.|
-00000010 65 02 ec 6f 93 a0 38 21 09 0d d7 bf 11 20 51 eb |e..o..8!..... Q.|
-00000020 cc 00 08 9b 7a 98 c4 c5 02 ff c1 20 f9 1b c7 66 |....z...... ...f|
-00000030 35 40 8c 67 8d 7f d5 c8 28 f0 cb d2 f9 da af 7a |5@.g....(......z|
-00000040 ea 4e 42 f2 5d 44 1c cc 92 36 b1 10 c0 09 00 00 |.NB.]D...6......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 ed 13 de 15 cc |....Y...U.......|
+00000010 90 4f f3 72 5a d4 7a 01 26 fa 7a ae 38 92 a0 d6 |.O.rZ.z.&.z.8...|
+00000020 70 4a 20 f6 7e 11 f7 ac e6 94 87 20 9f 37 0f 8f |pJ .~...... .7..|
+00000030 55 a6 6a 97 b8 0f 56 aa 2d 69 c5 79 01 d5 c0 01 |U.j...V.-i.y....|
+00000040 2c 2b 0e 16 d8 79 a3 f3 44 99 7c 01 c0 09 00 00 |,+...y..D.|.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,82 +49,79 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 34 |*............A.4|
-00000280 47 57 64 b3 20 6d eb 17 9c 36 d4 aa 78 8b 20 26 |GWd. m...6..x. &|
-00000290 6f 22 10 79 5f 96 69 62 1d ae 9f c7 40 17 1e 30 |o".y_.ib....@..0|
-000002a0 10 db d1 13 51 d8 63 61 ef 8e fb 34 d6 02 95 ac |....Q.ca...4....|
-000002b0 fb 33 72 a9 46 ff 27 b1 15 ca dd 81 8f 5a 58 00 |.3r.F.'......ZX.|
-000002c0 8a 30 81 87 02 41 5c 09 1a 87 40 f3 1a 87 84 31 |.0...A\...@....1|
-000002d0 62 6c e5 a5 c0 3c cc ba 5d 4a 5e 65 ea e0 60 83 |bl...<..]J^e..`.|
-000002e0 fe fe 99 1d 66 4a bb 6c 0d 5e 25 64 e3 92 ce eb |....fJ.l.^%d....|
-000002f0 15 39 42 a6 b0 98 a1 d3 79 65 c7 fc e7 c7 64 c7 |.9B.....ye....d.|
-00000300 69 9c 2f 7e 00 c1 a3 02 42 01 f2 61 91 ae 8e f6 |i./~....B..a....|
-00000310 88 99 70 55 32 4a fe 08 31 f0 8d d6 e6 1d fa a1 |..pU2J..1.......|
-00000320 76 b6 16 98 58 8e 46 30 b1 00 b6 dd 5d 70 bb e1 |v...X.F0....]p..|
-00000330 81 89 bd aa ac b5 7f 9b d3 c0 8b 4b c3 36 00 87 |...........K.6..|
-00000340 47 0c 34 92 27 c3 aa bd 0d 7c 36 16 03 01 00 0e |G.4.'....|6.....|
-00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......|
+00000270 2a 16 03 01 00 b4 0c 00 00 b0 03 00 1d 20 ca e8 |*............ ..|
+00000280 ef 79 56 cd aa eb 12 8f e1 89 d1 3c 63 1f c8 54 |.yV........<c..T|
+00000290 5f 4e cf 6b 72 7d 1c bb f6 80 ae 17 33 69 00 8a |_N.kr}......3i..|
+000002a0 30 81 87 02 42 01 d1 45 df fc 46 21 5b 9b 49 f0 |0...B..E..F![.I.|
+000002b0 3c f2 16 65 1e 33 90 d8 be 1d 65 12 2f 46 93 5b |<..e.3....e./F.[|
+000002c0 e2 14 67 b8 67 9b c1 10 31 a1 96 b8 86 c3 8b 26 |..g.g...1......&|
+000002d0 3f da 5e 86 e7 b1 f9 3f f1 04 57 ed e6 6f a5 86 |?.^....?..W..o..|
+000002e0 f7 58 38 6e 0d ae 42 02 41 05 1b 07 9b 4c 4d 39 |.X8n..B.A....LM9|
+000002f0 2d 0c 4e d7 94 d6 86 c9 6c b9 4d 54 a2 56 87 12 |-.N.....l.MT.V..|
+00000300 08 ec 4e f1 a4 19 5e 52 69 ed 9f 6c 59 5f 31 0f |..N...^Ri..lY_1.|
+00000310 8d 33 1f a7 42 e5 56 9d 54 f4 18 9b 33 31 97 b9 |.3..B.V.T...31..|
+00000320 57 55 c9 9f ea 7d f2 9e 24 e0 16 03 01 00 0a 0d |WU...}..$.......|
+00000330 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e 00 |......@.........|
+00000340 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......|
-00000250 0f 00 00 82 00 80 1e 4d 89 4e e2 82 ca 5d 31 8a |.......M.N...]1.|
-00000260 66 c7 c2 d6 00 4d 2e 1e 94 34 61 6b 86 3d 78 60 |f....M...4ak.=x`|
-00000270 70 e1 71 93 22 df 5d 81 d3 d7 33 10 f5 01 f9 1d |p.q.".]...3.....|
-00000280 e2 4a 91 22 67 ae 5b 2f 4c d9 43 31 35 c6 01 ad |.J."g.[/L.C15...|
-00000290 59 86 03 a1 9b c5 ea a5 2d aa ef 46 5a a8 70 57 |Y.......-..FZ.pW|
-000002a0 50 59 ea 7a 07 32 bb a6 a1 11 33 05 d8 88 2e 42 |PY.z.2....3....B|
-000002b0 d8 7b f7 34 be 5e 5f 42 9f 6a 90 ed d7 4b c4 7e |.{.4.^_B.j...K.~|
-000002c0 f9 5c a5 ff 28 f8 a1 f1 8f 1c e0 7a 37 a0 49 e5 |.\..(......z7.I.|
-000002d0 ce 11 46 ef 5f 06 14 03 01 00 01 01 16 03 01 00 |..F._...........|
-000002e0 30 cb 08 f0 3c d4 21 f2 3a 7d db 59 75 80 48 24 |0...<.!.:}.Yu.H$|
-000002f0 27 6f 2c 26 50 a4 7d 6c 91 d5 5d f7 c9 b4 bd 15 |'o,&P.}l..].....|
-00000300 a8 8a 12 d5 40 8c 9a 0f 56 67 66 89 dd 12 36 d8 |....@...Vgf...6.|
-00000310 d3 |.|
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 8f 6f 77 5d d5 99 28 0c 7a |........ow]..(.z|
+00000240 36 f2 50 ec 9a e6 eb 88 ac 45 f7 9b 6f 98 84 ba |6.P......E..o...|
+00000250 fb 3c b8 d6 54 61 b8 87 25 50 3c 31 5a d2 c1 54 |.<..Ta..%P<1Z..T|
+00000260 e8 ed c3 93 cc 98 b1 c3 d4 84 11 d8 a0 c7 ae 67 |...............g|
+00000270 67 35 6a 0f 93 18 bb 18 52 f8 25 88 1f d2 19 4d |g5j.....R.%....M|
+00000280 3b 4c f2 0f f7 06 68 57 cf 45 20 e0 57 75 37 e9 |;L....hW.E .Wu7.|
+00000290 cd 86 1f e5 d2 90 1e cf 3a 18 fd 45 bc a1 84 63 |........:..E...c|
+000002a0 36 d8 ac 6b 09 41 da 0a 87 7f ab ce 8e 49 e6 c8 |6..k.A.......I..|
+000002b0 bf fb 2c 3b 7b e9 ae 14 03 01 00 01 01 16 03 01 |..,;{...........|
+000002c0 00 30 7d 65 9c c1 25 e4 85 d7 39 d4 67 cf eb f1 |.0}e..%...9.g...|
+000002d0 b7 c2 4d e6 5d bd 13 74 55 22 f0 8a 7e a6 a2 eb |..M.]..tU"..~...|
+000002e0 93 cc b7 fa 86 b1 b5 e0 a3 ef ee 56 f0 cd f7 a5 |...........V....|
+000002f0 d8 9e |..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 02 e3 be 9d 2d |..........0....-|
-00000010 6f 2c 9a b7 b4 f1 a5 30 ec 3e ae 05 e6 02 19 2f |o,.....0.>...../|
-00000020 a4 ac d1 6e ac de 75 4e cc 14 e6 78 5a ea 27 7f |...n..uN...xZ.'.|
-00000030 4e 45 c4 9d b2 da a6 ea b7 d2 7e |NE........~|
+00000000 14 03 01 00 01 01 16 03 01 00 30 ff 13 14 c5 ad |..........0.....|
+00000010 88 ec a1 cf cc 0d 3f 7b ec 50 4a 25 69 1f 18 dc |......?{.PJ%i...|
+00000020 b1 99 1f 3b 78 60 e0 83 c0 cd 9a b3 0d 59 0b f8 |...;x`.......Y..|
+00000030 8a b7 7c 2c b4 2c e4 d0 49 82 82 |..|,.,..I..|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 e0 71 e9 54 11 6e 48 4b be a2 2a |.... .q.T.nHK..*|
-00000010 b1 70 d2 2c 74 c0 f4 74 05 f1 d3 d6 84 29 58 f7 |.p.,t..t.....)X.|
-00000020 87 90 84 2b c8 17 03 01 00 20 b6 a2 e9 e0 f0 0d |...+..... ......|
-00000030 d5 ef d7 32 6d cb 99 5d a6 37 c2 6e f9 c3 8e 6f |...2m..].7.n...o|
-00000040 76 71 d8 a6 c5 ae 4e 04 77 06 15 03 01 00 20 f2 |vq....N.w..... .|
-00000050 09 ab dc 37 90 78 3a 2a 41 ab 9b a9 c1 78 2a 64 |...7.x:*A....x*d|
-00000060 a8 3f 21 c4 bb af 76 b3 c6 2f e1 20 a3 b1 1e |.?!...v../. ...|
+00000000 17 03 01 00 20 51 91 74 f6 31 07 15 6b 9e 0b 28 |.... Q.t.1..k..(|
+00000010 02 b8 ec 9d c6 e3 15 24 d3 ea 4b 27 d0 fa 9f c2 |.......$..K'....|
+00000020 c4 8d 37 b3 d9 17 03 01 00 20 7d 97 75 fe de 3f |..7...... }.u..?|
+00000030 ae ab e6 a8 1d 76 1c 06 9c 02 61 cc f5 1d fe c8 |.....v....a.....|
+00000040 a2 dc ae 97 7f 1c 05 19 e5 14 15 03 01 00 20 4a |.............. J|
+00000050 bc 45 97 6b 09 8e 47 5f d5 a0 97 78 79 67 09 8d |.E.k..G_...xyg..|
+00000060 d3 80 38 58 5c cc ae 8e d4 67 1d 93 2b 20 79 |..8X\....g..+ y|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
index e00787037a..e585894db7 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -1,120 +1,131 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 e5 d7 4b 56 7b |....Q...M....KV{|
-00000010 a8 2c 07 33 fc 66 d7 79 e9 26 91 56 7d 9d 99 1d |.,.3.f.y.&.V}...|
-00000020 b2 24 36 2c f6 78 3a e7 63 15 f6 20 9f e1 d4 07 |.$6,.x:.c.. ....|
-00000030 a9 75 3d b9 3b 8c 46 cb a7 37 36 56 af 4e 99 cf |.u=.;.F..76V.N..|
-00000040 90 49 e1 e9 69 25 81 0f fd 22 48 e6 00 05 00 00 |.I..i%..."H.....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 61 6b 2e 41 7f |....Y...U..ak.A.|
+00000010 af 26 6f a2 8b 63 ee e4 b1 76 19 3a 6d a3 c2 30 |.&o..c...v.:m..0|
+00000020 37 e8 47 c2 90 10 7e e8 c5 b2 eb 20 00 1c 8f 70 |7.G...~.... ...p|
+00000030 0d 15 4a c7 7d ab ca 79 a7 d8 c2 01 62 6e 6f aa |..J.}..y....bno.|
+00000040 df a2 1c 8f 7c 27 d9 e6 fe e9 c8 ab c0 13 00 00 |....|'..........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 29 0b ca 37 f3 a1 52 |........ )..7..R|
+000002d0 49 1c 84 9a e4 74 6b 4b 2d 1f e6 e9 83 1d 5d 59 |I....tkK-.....]Y|
+000002e0 5a 2f 09 9f bc a4 30 af 71 00 80 d9 bb 6d 09 a7 |Z/....0.q....m..|
+000002f0 ab 47 6f e8 a6 1a da fb 66 7d a5 f0 c9 c3 24 4c |.Go.....f}....$L|
+00000300 99 56 c6 29 71 27 08 0b c1 60 44 cc 6d 42 1b 5e |.V.)q'...`D.mB.^|
+00000310 cd 9f 82 24 38 23 ec d9 fa 32 49 2f 16 5d d2 9d |...$8#...2I/.]..|
+00000320 e9 13 4e 66 3d f8 bf 30 2e 8c eb 35 4c e8 81 86 |..Nf=..0...5L...|
+00000330 c0 de c7 0d a9 60 7e 7c 4a c4 1d a0 89 70 de 82 |.....`~|J....p..|
+00000340 1b 37 a0 ea 7f 20 a5 fe d4 20 1d 6f 1a 84 dd a4 |.7... ... .o....|
+00000350 13 46 18 c6 31 14 81 4b a4 bb 43 5c c4 49 1c 5a |.F..1..K..C\.I.Z|
+00000360 8d 12 57 e0 1d 9a b6 cd f1 39 ff 16 03 01 00 0a |..W......9......|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 86 |M.x.N.8FB.......|
-00000290 0f 00 00 82 00 80 3d f7 ff c1 72 82 b8 90 42 a3 |......=...r...B.|
-000002a0 10 24 b5 01 44 60 98 39 e4 36 86 56 09 55 e5 73 |.$..D`.9.6.V.U.s|
-000002b0 3a d9 9d 00 ae 05 23 6f 78 4e 49 28 c1 cc 7a ff |:.....#oxNI(..z.|
-000002c0 8f 67 92 cd 94 c0 d2 68 7f 48 ec 10 83 48 9e 02 |.g.....h.H...H..|
-000002d0 b8 10 b2 1b f0 ba 8f 5a c8 85 d9 19 53 c2 8d 37 |.......Z....S..7|
-000002e0 8e 86 4c ca ee 0f c4 97 20 f9 a5 4e 94 b8 c5 c5 |..L..... ..N....|
-000002f0 53 0c c1 b6 e5 a1 4e d6 15 b3 6b 08 c2 25 c3 de |S.....N...k..%..|
-00000300 e7 69 85 85 56 31 16 ad 68 7e 00 8f 1b fc f8 9f |.i..V1..h~......|
-00000310 d7 50 87 08 0d c5 14 03 01 00 01 01 16 03 01 00 |.P..............|
-00000320 24 eb 0c f3 4f 56 04 e3 54 b0 a8 e4 bb af 3a 44 |$...OV..T.....:D|
-00000330 c7 d6 f0 24 2f fc e6 79 93 f4 4e ec c5 1f 5b 99 |...$/..y..N...[.|
-00000340 32 37 c2 f1 ad |27...|
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 12 76 af 25 e4 e7 ff d6 e4 |........v.%.....|
+00000240 27 58 31 0f 6b 1e 84 13 2f d0 60 80 18 c3 f8 c1 |'X1.k.../.`.....|
+00000250 f8 04 39 d4 07 05 d3 96 e2 b2 10 de 1f 68 88 67 |..9..........h.g|
+00000260 1d dd 0a 11 52 9d 16 0e af 07 de cb f1 7c f4 b4 |....R........|..|
+00000270 5d 0f 4f 43 5b 3c 25 07 32 13 f2 ab 9b 2d d0 a8 |].OC[<%.2....-..|
+00000280 28 90 cb 04 48 c3 43 bd 2b b4 ef b9 7b cd bd d5 |(...H.C.+...{...|
+00000290 bc d1 cc 00 17 46 fa 9b 1f 44 58 b7 6c de 1b 7a |.....F...DX.l..z|
+000002a0 e0 d7 12 38 a3 09 f8 7a 9b 26 0b ee 37 bc 79 1b |...8...z.&..7.y.|
+000002b0 51 9f 9a 1f f9 a9 51 14 03 01 00 01 01 16 03 01 |Q.....Q.........|
+000002c0 00 30 97 df fb 79 78 a8 27 fd 2b 68 6b ec 4d 29 |.0...yx.'.+hk.M)|
+000002d0 a1 02 59 ae 18 0b 46 62 af 61 53 2f 95 50 f2 ac |..Y...Fb.aS/.P..|
+000002e0 c8 c3 5e 78 ca b0 e2 5d ff d7 1b 9b 00 30 f6 da |..^x...].....0..|
+000002f0 d7 91 |..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 75 ac 09 a6 28 |..........$u...(|
-00000010 60 ce 7f 81 a2 75 86 af 84 95 dc 3f e1 07 1c 02 |`....u.....?....|
-00000020 bc 3c 90 db 1e 1a 35 06 93 60 22 69 b9 05 bb |.<....5..`"i...|
+00000000 14 03 01 00 01 01 16 03 01 00 30 f9 e9 d7 8c 4a |..........0....J|
+00000010 6b f4 c9 88 d6 98 70 53 13 fc 51 9c 81 14 cf 71 |k.....pS..Q....q|
+00000020 d9 30 7a d9 2c 34 96 00 a4 a0 2b 1e 7d ff d0 f2 |.0z.,4....+.}...|
+00000030 b7 81 ed 86 c5 e1 09 16 82 47 20 |.........G |
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a f4 67 a7 d8 0a 67 8d 3a 11 53 7e |......g...g.:.S~|
-00000010 49 91 bf 92 85 e0 35 24 25 72 92 26 63 9b 09 15 |I.....5$%r.&c...|
-00000020 03 01 00 16 98 bb a0 ca 40 70 26 6f 2d 73 35 3d |........@p&o-s5=|
-00000030 90 8c ff 01 e0 b1 50 52 e3 57 |......PR.W|
+00000000 17 03 01 00 20 db b5 66 4e fb b1 47 8a 8e 6b a8 |.... ..fN..G..k.|
+00000010 03 53 1a 51 22 8e 47 a3 3a 74 ed a4 6a aa 79 fd |.S.Q".G.:t..j.y.|
+00000020 55 0f ac 35 a9 17 03 01 00 20 3e 0b 39 f5 5a 03 |U..5..... >.9.Z.|
+00000030 43 d9 e2 7d 1c dc 3b 42 82 2a 2d d4 04 0a 76 97 |C..}..;B.*-...v.|
+00000040 70 ed ee 99 58 15 40 c1 3a d5 15 03 01 00 20 bf |p...X.@.:..... .|
+00000050 ea e8 93 67 a4 91 1a b5 f5 03 a5 94 50 95 41 16 |...g........P.A.|
+00000060 b0 2a 74 d9 32 65 94 35 45 b9 0f 2e 80 87 fd |.*t.2e.5E......|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
index 929e1c6b12..529b7cef48 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 78 09 57 86 09 |....Y...U..x.W..|
-00000010 64 7e 35 c7 c7 b9 44 9c 09 ae f0 49 cb 1c 1f 58 |d~5...D....I...X|
-00000020 89 ef 65 16 9e 32 73 cd 4d 1b 8f 20 10 4d 5b cf |..e..2s.M.. .M[.|
-00000030 d0 24 59 dd e8 47 c9 a2 ad 9c 98 b5 eb 16 46 6b |.$Y..G........Fk|
-00000040 7d 33 6e 53 0a 3d 81 71 a1 bc 43 7a c0 09 00 00 |}3nS.=.q..Cz....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 b0 ec 4b 2e 9e |....Y...U....K..|
+00000010 19 7d 7b 7e 7c 52 8a d2 2e 8a 97 05 8a c6 ae aa |.}{~|R..........|
+00000020 c5 62 bd 6f bd 7e fe 6b c6 9f d4 20 74 db 02 b1 |.b.o.~.k... t...|
+00000030 65 88 41 bb 9a 55 22 f3 01 c4 5c ca 39 86 b1 77 |e.A..U"...\.9..w|
+00000040 c4 b3 45 16 eb 55 d8 15 b8 4d ac 12 c0 09 00 00 |..E..U...M......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,41 +49,37 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 51 |*............A.Q|
-00000280 39 70 43 9c 01 de 29 df 3c d0 f8 31 54 70 34 53 |9pC...).<..1Tp4S|
-00000290 0e ab e8 e0 b0 8b 21 66 63 ac a9 68 7c 92 6f f8 |......!fc..h|.o.|
-000002a0 cf a3 ba cb 6d 39 f4 5c f5 2e ff 1d d7 1b b9 e7 |....m9.\........|
-000002b0 08 13 59 f8 64 7e 23 e0 1d 04 cf 37 47 d6 b7 00 |..Y.d~#....7G...|
-000002c0 8b 30 81 88 02 42 01 cd 1d 01 46 68 da 4c b6 0d |.0...B....Fh.L..|
-000002d0 67 05 39 0d aa 6c c5 40 e4 5d bf 4f 2a 92 78 8d |g.9..l.@.].O*.x.|
-000002e0 08 0e c0 07 8c 68 cc 55 4e 54 a9 9d 22 f9 a6 4a |.....h.UNT.."..J|
-000002f0 e4 38 9f 53 4a 60 e8 eb 81 02 50 75 7e 13 31 2a |.8.SJ`....Pu~.1*|
-00000300 ff 3e 17 cd b4 d1 d4 75 02 42 01 95 ba b6 a0 12 |.>.....u.B......|
-00000310 23 59 9f ae 1c c0 60 d2 8f 59 6b 35 ee b3 3f ac |#Y....`..Yk5..?.|
-00000320 e4 42 9a 23 d0 f4 fd a1 3c 36 1b 31 33 76 8d f0 |.B.#....<6.13v..|
-00000330 b6 66 fd 92 9a 2a 27 8b 06 11 72 41 09 bd 27 55 |.f...*'...rA..'U|
-00000340 c7 1b a9 d1 49 5e 8f 85 dc aa 9d be 16 03 01 00 |....I^..........|
-00000350 04 0e 00 00 00 |.....|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 7d 74 |*............ }t|
+00000280 bf aa a8 b6 c0 1f 78 0c 1a ee c5 b7 56 ff 5c aa |......x.....V.\.|
+00000290 f4 e3 a5 0c f7 64 31 eb 85 8a c9 bd 05 1b 00 8b |.....d1.........|
+000002a0 30 81 88 02 42 00 f8 5d e5 bf 2e 70 79 f4 36 90 |0...B..]...py.6.|
+000002b0 fc 6e 9a cc f1 c4 01 50 8c b9 92 4e bd e0 82 2d |.n.....P...N...-|
+000002c0 1b ab 30 71 d1 db 76 af 50 75 08 fb cb 50 5b 00 |..0q..v.Pu...P[.|
+000002d0 49 72 f5 d7 d9 44 48 94 ac 1d 8d 2e 50 90 ad a3 |Ir...DH.....P...|
+000002e0 42 2b 5f 57 48 5e 9e 02 42 00 bb 0b 9a d7 25 53 |B+_WH^..B.....%S|
+000002f0 04 5c 58 01 07 8e 3d ee f5 4f 0b 80 bd 02 07 3e |.\X...=..O.....>|
+00000300 ff b9 01 ac 7a 49 be 94 fa cf 58 5c 59 91 b5 5d |....zI....X\Y..]|
+00000310 cc 61 b9 e3 2f 53 7d 3c 3f 41 c5 31 1a 90 fc fa |.a../S}<?A.1....|
+00000320 f7 0b eb e9 01 17 ab 23 ab 28 63 16 03 01 00 04 |.......#.(c.....|
+00000330 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 01 00 30 64 61 7f ea 98 8e e7 c9 0f ea |.....0da........|
-00000060 0a b3 52 ba 3d 01 36 a4 47 24 7b 2d 19 b5 7e 92 |..R.=.6.G${-..~.|
-00000070 04 b7 8c 4f fc 02 5d 79 15 3e 50 72 05 3c df d2 |...O..]y.>Pr.<..|
-00000080 c6 a3 b3 c8 7c 48 |....|H|
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 f5 d0 86 ef 96 7e b9 94 cc 19 62 |....0.....~....b|
+00000040 cc 3a 14 f1 74 a2 0d c8 b9 4c 5d 8a c5 80 60 23 |.:..t....L]...`#|
+00000050 d5 f5 04 06 16 e2 69 ca 4d 99 1b a0 b5 3b 7d 62 |......i.M....;}b|
+00000060 51 62 ee d9 60 |Qb..`|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 7d 49 8d e9 da |..........0}I...|
-00000010 87 77 18 4d 10 63 17 ed 1f 34 7a d4 be e3 dd b6 |.w.M.c...4z.....|
-00000020 8b f3 a7 06 bc de 76 8e 04 be 8a 95 5b 24 19 ec |......v.....[$..|
-00000030 66 55 8a 1b e0 df 0b a1 57 cb 67 |fU......W.g|
+00000000 14 03 01 00 01 01 16 03 01 00 30 4d f9 c2 63 4f |..........0M..cO|
+00000010 98 1b 02 ce df ca d1 15 a2 4f 6f 4c 2c b8 1a 88 |.........OoL,...|
+00000020 11 c9 b3 45 e6 1d cf e8 6b dd 8c 89 c6 1d 0b 66 |...E....k......f|
+00000030 82 d5 1d c6 55 14 1c 56 59 3e 69 |....U..VY>i|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 2d a3 e5 55 13 3f 73 8e ba 41 79 |.... -..U.?s..Ay|
-00000010 65 e0 83 d5 3a ea cd e9 a8 b4 4b 3c d0 0c bf 06 |e...:.....K<....|
-00000020 75 2a 67 f2 f7 17 03 01 00 20 a0 8d 3c a2 ca b3 |u*g...... ..<...|
-00000030 f3 e5 36 dc 44 a4 3b ad cd 03 be a9 70 a8 75 51 |..6.D.;.....p.uQ|
-00000040 0f 8e 9f 7c a7 3c 03 84 38 88 15 03 01 00 20 75 |...|.<..8..... u|
-00000050 0f db fe 48 b4 7e 04 3b f5 5b 47 5b 0a ab 69 18 |...H.~.;.[G[..i.|
-00000060 37 bb 89 d3 a8 40 ba 53 3b 5f 6d 8b 06 ff ae |7....@.S;_m....|
+00000000 17 03 01 00 20 12 be 42 b4 31 07 55 8e f9 a1 64 |.... ..B.1.U...d|
+00000010 96 70 46 68 3e fd 4e 4f 9c af b3 11 de fc 80 f1 |.pFh>.NO........|
+00000020 c8 11 84 ba ae 17 03 01 00 20 2f f9 ec dd 50 97 |......... /...P.|
+00000030 1e a4 f1 66 fe 28 e3 c1 51 8d c0 f6 c3 d8 b3 ad |...f.(..Q.......|
+00000040 7d dc a5 98 87 90 34 71 b4 73 15 03 01 00 20 d1 |}.....4q.s.... .|
+00000050 6f 91 91 01 68 c4 11 6a e5 a2 ed 20 3f 3a 3d b7 |o...h..j... ?:=.|
+00000060 d9 7f c3 b3 29 c3 df 3e 17 69 76 9f 04 f8 58 |....)..>.iv...X|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
index 0b481ea5ec..78947ace0e 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -1,93 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 90 3d f6 98 16 |....Y...U...=...|
-00000010 55 0f 73 94 05 96 4c ab ad f4 98 7a db c5 ca 26 |U.s...L....z...&|
-00000020 1b c8 d9 15 a8 79 8e 2b 10 67 54 20 b2 8e 45 24 |.....y.+.gT ..E$|
-00000030 6d 82 ec f5 30 41 2e 32 10 fa c0 76 3f 84 81 39 |m...0A.2...v?..9|
-00000040 1e 5d 98 c1 33 d9 0d 4f 21 e1 0d 47 c0 13 00 00 |.]..3..O!..G....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 45 04 14 a2 70 |....Y...U..E...p|
+00000010 3e 1e d9 2c d4 bd f3 e8 9c f3 e0 08 d8 0f 7f 82 |>..,............|
+00000020 2b 07 a0 bd 47 56 a0 e1 06 0d 36 20 fc 0f 5b 85 |+...GV....6 ..[.|
+00000030 8e 17 20 f1 f6 1e 80 c3 79 1a e1 86 c3 ed e9 24 |.. .....y......$|
+00000040 6d bb 24 3c 0c 8d 2c 79 f2 03 27 b0 c0 13 00 00 |m.$<..,y..'.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 01 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 01 00 cb 0c 00 00 c7 03 00 17 |..9.............|
-000002e0 41 04 d9 ae 3f 05 64 d3 77 d9 1d b8 37 8a d4 ac |A...?.d.w...7...|
-000002f0 51 f4 af 65 70 da c0 64 76 00 53 50 a2 d4 6c bc |Q..ep..dv.SP..l.|
-00000300 9c 62 ab 2f 7b 02 48 fe b2 0d 0b bb be 8f 34 55 |.b./{.H.......4U|
-00000310 fb ce ee 93 43 76 d5 ce 3b b5 79 ab 3d 74 6e 19 |....Cv..;.y.=tn.|
-00000320 a9 7d 00 80 05 cf 57 f2 f7 e0 ad 71 f1 75 d0 8b |.}....W....q.u..|
-00000330 f5 9d 83 1a 7e 0a 71 10 d7 9e fe bd 9d 47 62 45 |....~.q......GbE|
-00000340 8d 1b 9c 33 fa 2c 5c aa ce 9e 62 dc ad 56 ac 87 |...3.,\...b..V..|
-00000350 84 54 f5 32 87 d1 bb 8b d9 d7 6d 3c 6c 6d b7 79 |.T.2......m<lm.y|
-00000360 05 4d 55 f1 7c ef b1 fc e7 35 5d 41 66 60 44 4f |.MU.|....5]Af`DO|
-00000370 f3 dd de 25 f4 73 12 c2 b6 cc 61 d5 14 5a ff 88 |...%.s....a..Z..|
-00000380 ae f5 04 62 ac 2d 10 a0 95 c1 8e fa e6 db fe 41 |...b.-.........A|
-00000390 46 98 f1 3d 2e e3 2a 5a ea 87 26 6e 7a 4f 38 6c |F..=..*Z..&nzO8l|
-000003a0 4b 1f 1b 56 16 03 01 00 04 0e 00 00 00 |K..V.........|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 85 05 5f e3 a2 b2 12 |........ .._....|
+000002d0 c8 82 53 2b c2 38 e1 a8 08 87 a7 d5 b3 98 6f 81 |..S+.8........o.|
+000002e0 ce 81 6b 78 3e 3a b7 1d 71 00 80 43 81 fb 47 5e |..kx>:..q..C..G^|
+000002f0 08 16 39 35 d3 c2 f3 ea bb 2c 7d bc 01 9b 35 5d |..95.....,}...5]|
+00000300 63 7e c3 38 f3 04 96 eb d7 3f d1 df 71 97 ec 22 |c~.8.....?..q.."|
+00000310 1b 4a 89 14 4d e5 44 08 87 52 69 ea 28 f8 6a ea |.J..M.D..Ri.(.j.|
+00000320 3e ff 17 de 4d 20 95 e3 6e 3f af 05 20 9b a3 ac |>...M ..n?.. ...|
+00000330 70 1b 1c bf f9 52 d6 11 6d d9 85 90 08 4d 64 1f |p....R..m....Md.|
+00000340 c5 35 34 37 11 b8 44 a3 ef 93 a6 b6 87 58 0b c4 |.547..D......X..|
+00000350 8e 94 d8 67 4d 09 7a 2a aa 95 db e6 af 29 21 a2 |...gM.z*.....)!.|
+00000360 ee c3 90 ef c6 53 46 12 fb 87 06 16 03 01 00 04 |.....SF.........|
+00000370 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 01 00 30 73 96 2d 54 e3 9a bc 54 f5 9e |.....0s.-T...T..|
-00000060 e5 c7 46 35 b8 e1 d6 f6 14 95 92 f1 95 81 5a 9d |..F5..........Z.|
-00000070 4b df cc 96 77 f2 39 60 5d 5d da 94 b0 bf a0 80 |K...w.9`]]......|
-00000080 bd 28 55 b1 6a c3 |.(U.j.|
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 50 f5 a9 34 25 ed a2 fb c8 7f 35 |....0P..4%.....5|
+00000040 08 57 59 da 54 c1 8d 92 ec 23 73 af f3 92 8d 19 |.WY.T....#s.....|
+00000050 03 ce ab 5b eb dc 5b 81 3f 51 a1 20 31 3f 33 da |...[..[.?Q. 1?3.|
+00000060 27 c5 c3 9c fd |'....|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 c9 46 7a 8b be |..........0.Fz..|
-00000010 cd eb 5c 83 13 9c 9b 9f 70 84 38 3b 48 8c f4 11 |..\.....p.8;H...|
-00000020 b3 ca 10 09 38 d0 8e c8 9f 66 db b9 8a 95 15 6b |....8....f.....k|
-00000030 5e f8 1d 39 25 75 3d f1 b9 32 a3 |^..9%u=..2.|
+00000000 14 03 01 00 01 01 16 03 01 00 30 b1 61 9b 63 4e |..........0.a.cN|
+00000010 43 96 80 49 ac 2d 93 7d b9 f2 bb 81 79 5e 94 bf |C..I.-.}....y^..|
+00000020 06 d0 a6 14 46 91 cd 90 b0 8a 85 ee fe 41 a7 4d |....F........A.M|
+00000030 97 d7 4d 40 5e f4 5b bd d3 0c db |..M@^.[....|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 04 69 a9 01 42 f4 1a fd 5a 4e 12 |.... .i..B...ZN.|
-00000010 2b 6d cd 68 6b 94 70 b2 80 07 cf 79 a4 43 69 bf |+m.hk.p....y.Ci.|
-00000020 27 25 b5 ae e7 17 03 01 00 20 bf 1e cd 83 64 af |'%....... ....d.|
-00000030 6f cc 89 21 bf 16 e7 e8 86 29 f3 0a 36 ab a4 e3 |o..!.....)..6...|
-00000040 fa c0 7e 7a 78 ca 29 17 11 9c 15 03 01 00 20 94 |..~zx.)....... .|
-00000050 7a dd 17 eb fd 67 b1 cc 58 c9 c3 ae db b6 b0 a4 |z....g..X.......|
-00000060 68 15 36 ca 33 22 ec 03 fb cf 2f f5 70 d6 9d |h.6.3"..../.p..|
+00000000 17 03 01 00 20 49 21 bc a5 4c 96 41 3f 22 87 0a |.... I!..L.A?"..|
+00000010 c0 4e 0e 54 cb c2 27 8a 4f b0 37 fb b4 1f c1 4e |.N.T..'.O.7....N|
+00000020 77 e1 09 57 23 17 03 01 00 20 f0 f0 3b 78 a8 ae |w..W#.... ..;x..|
+00000030 ef b1 e0 f4 29 0f 90 4a 0f e5 48 34 84 5e 4f d8 |....)..J..H4.^O.|
+00000040 53 46 f8 29 64 2b 8e 87 79 0a 15 03 01 00 20 71 |SF.)d+..y..... q|
+00000050 32 6c 08 2a f7 18 c8 d5 48 a8 c7 d1 68 7a 65 ec |2l.*....H...hze.|
+00000060 3e fa 4b fe ff 76 1a 57 64 22 61 27 a0 5d b6 |>.K..v.Wd"a'.].|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
index 57eb930d09..7ecfbde86a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 1c 0e e9 7a c6 |....Q...M.....z.|
-00000010 91 fe 7e 8c 6f 0b 8e cf 23 f5 07 29 10 de 05 a6 |..~.o...#..)....|
-00000020 20 72 11 65 4f 2b 45 95 96 02 62 20 43 a8 93 34 | r.eO+E...b C..4|
-00000030 e7 c0 29 d5 fb 26 f9 c2 59 37 94 dc e6 b5 c4 ed |..)..&..Y7......|
-00000040 ae 7a d7 94 d1 f4 d8 0b 02 ad 20 1b 00 05 00 00 |.z........ .....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 01 00 51 02 00 00 4d 03 01 4c 98 ce a5 80 |....Q...M..L....|
+00000010 84 dc d3 70 de 75 bf 26 5c 15 8b b7 2c 78 30 a7 |...p.u.&\...,x0.|
+00000020 65 1a 0c f7 1a e5 51 91 7c cb ca 20 83 2c 90 3b |e.....Q.|.. .,.;|
+00000030 cf dd 4e 51 8b 27 98 95 aa d9 1d da 4d 3d e1 18 |..NQ.'......M=..|
+00000040 f5 58 fd 85 c5 ed c9 5f 12 2f 4b b3 00 05 00 00 |.X....._./K.....|
+00000050 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 01 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 01 00 24 ae a9 da 45 6b 5e 76 57 02 62 |.....$...Ek^vW.b|
-000000a0 63 d4 1f 40 bf c9 47 27 a9 7a 24 c0 f0 e9 c2 c4 |c..@..G'.z$.....|
-000000b0 9c 07 84 df ae c7 66 40 d2 b0 |......f@..|
+00000000 16 03 01 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 01 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 01 00 24 0e 4d ff 2c 39 80 ba a5 96 18 |.....$.M.,9.....|
+000000a0 56 15 94 9f e2 1e 7d 13 62 51 d5 e1 05 f8 d8 b3 |V.....}.bQ......|
+000000b0 bd 77 58 38 95 b4 7d 37 66 8a |.wX8..}7f.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 e9 84 92 41 c5 |..........$...A.|
-00000010 31 e1 3c a9 78 18 d1 7b e1 b1 0b 0a ef 18 54 19 |1.<.x..{......T.|
-00000020 7c ba c7 59 ca c8 7b 4d c9 f4 ad d6 7b 77 fb ||..Y..{M....{w.|
+00000000 14 03 01 00 01 01 16 03 01 00 24 dc 6f da 57 0d |..........$.o.W.|
+00000010 f8 b8 aa d5 e5 0a 2e 81 ed 2a b7 f8 0e 2a f1 05 |.........*...*..|
+00000020 76 8d 4f b0 0e db 16 c5 d7 c8 5e f9 fb 9e e0 |v.O.......^....|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a 1a dc 95 e2 4f ec f1 f6 68 9d 15 |.........O...h..|
-00000010 56 d5 7b 06 1a f5 be bb b1 ca b2 a6 d3 9e 28 15 |V.{...........(.|
-00000020 03 01 00 16 64 fe 4a 37 d3 32 a8 55 38 9e 0f 76 |....d.J7.2.U8..v|
-00000030 50 de e2 2e aa 77 15 2b e5 21 |P....w.+.!|
+00000000 17 03 01 00 1a 47 97 4d e6 59 d4 2f bb 60 56 69 |.....G.M.Y./.`Vi|
+00000010 d8 bc 8d 91 44 7c cd 85 7e c5 18 5f 57 8e 08 15 |....D|..~.._W...|
+00000020 03 01 00 16 f7 79 56 72 e6 77 8d af 94 55 d7 0e |.....yVr.w...U..|
+00000030 96 c8 3b 35 52 ea f7 e7 b8 d6 |..;5R.....|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
index 87fbe3f405..5232ad57df 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 59 02 00 00 55 03 02 07 ae a6 e4 1a |....Y...U.......|
-00000010 f7 7a 0c bc ea 21 0e 86 e3 d0 b4 2c fc d9 97 a3 |.z...!.....,....|
-00000020 8b 29 5f 59 3e a9 06 fb ca d9 57 20 cd 45 e7 cd |.)_Y>.....W .E..|
-00000030 6c 4c 56 cd 7c 4c 51 2c 8f 8c 67 a2 05 51 26 f5 |lLV.|LQ,..g..Q&.|
-00000040 17 cc 18 c2 a1 29 94 4b e2 02 cc 1c c0 09 00 00 |.....).K........|
+00000000 16 03 02 00 59 02 00 00 55 03 02 30 f8 f6 b2 af |....Y...U..0....|
+00000010 99 b0 e0 f6 9a eb 47 6f 2f ad 2f 45 18 56 b3 dd |......Go/./E.V..|
+00000020 b6 b9 20 fb af 97 43 1f 0e 51 c0 20 fe 6c 12 64 |.. ...C..Q. .l.d|
+00000030 8e cc a4 24 d6 e6 80 cf f2 9e 74 3f a7 1e 8b da |...$......t?....|
+00000040 0e 3c 58 74 f4 8f be 1f 60 86 57 c6 c0 09 00 00 |.<Xt....`.W.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,43 +49,39 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 02 00 d6 0c 00 00 d2 03 00 17 41 04 cd |*............A..|
-00000280 9d 30 75 8d 98 17 b5 1b 2f 4e af ea 69 52 a1 c1 |.0u...../N..iR..|
-00000290 86 73 6a 56 54 f8 ed b6 35 e5 4e 34 a0 6f b1 85 |.sjVT...5.N4.o..|
-000002a0 95 8e be 77 c5 1a 56 9a 59 d1 69 79 ea d6 2b c7 |...w..V.Y.iy..+.|
-000002b0 c1 4a fb bc f8 98 c3 49 1c f3 ce 33 ef 98 20 00 |.J.....I...3.. .|
-000002c0 8b 30 81 88 02 42 00 8b 15 7e 3b 4f 73 b0 8e ca |.0...B...~;Os...|
-000002d0 67 e0 7c d8 89 70 f1 b2 6b 9c 19 84 fa aa 6e 15 |g.|..p..k.....n.|
-000002e0 8b 46 95 57 d5 ac 79 f3 e8 2a e5 7a a8 1e c3 d7 |.F.W..y..*.z....|
-000002f0 0a b2 02 cd d6 32 34 2f 37 65 41 c8 61 c6 ed e5 |.....24/7eA.a...|
-00000300 d2 6f 0f e8 1a 49 b6 c7 02 42 00 d1 00 f4 05 65 |.o...I...B.....e|
-00000310 dd 43 42 db 8b 0b 95 9d f5 62 51 e6 58 60 20 9b |.CB......bQ.X` .|
-00000320 46 84 e6 1f 76 4a 92 42 e4 4d 77 5b 76 a5 78 a0 |F...vJ.B.Mw[v.x.|
-00000330 b0 f0 50 7d f9 4f ca 43 9d c2 50 cb 20 1c 40 52 |..P}.O.C..P. .@R|
-00000340 0f a8 c4 43 7a 9d d5 61 de 26 30 b5 16 03 02 00 |...Cz..a.&0.....|
-00000350 04 0e 00 00 00 |.....|
+00000270 2a 16 03 02 00 b3 0c 00 00 af 03 00 1d 20 4b 2d |*............ K-|
+00000280 60 48 54 b4 48 42 10 de e1 98 f0 fb 73 d9 49 16 |`HT.HB......s.I.|
+00000290 3e a2 11 b3 84 50 de 26 00 09 d8 36 34 04 00 89 |>....P.&...64...|
+000002a0 30 81 86 02 41 24 90 6f 3e 1a 2c a5 7f 08 dc b2 |0...A$.o>.,.....|
+000002b0 d3 46 27 5e cb 1f 2a 6d 92 ba 1b fe e3 c5 64 79 |.F'^..*m......dy|
+000002c0 31 50 8c 43 4b b1 ee 0d 6f 53 ad 6f e9 db 86 e7 |1P.CK...oS.o....|
+000002d0 1f e3 77 f1 8d a8 ab 81 2a d6 fa e7 98 d5 bc 0d |..w.....*.......|
+000002e0 ec af ea 84 c4 f8 02 41 6a d2 66 32 e1 d7 46 1a |.......Aj.f2..F.|
+000002f0 95 5a 91 c3 76 82 20 c2 a3 a2 32 f5 fd eb a2 0e |.Z..v. ...2.....|
+00000300 0f d8 a9 31 7a ef a8 05 6c 5d bf 27 d0 2d 94 ca |...1z...l].'.-..|
+00000310 fb d6 62 7a 1c 6a 46 20 fe ed a6 60 a3 db b1 bd |..bz.jF ...`....|
+00000320 11 82 05 c3 db 0c 4a 2d 6c 16 03 02 00 04 0e 00 |......J-l.......|
+00000330 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
-00000060 00 00 00 00 00 00 c0 81 e7 e8 40 f3 24 45 ed 74 |..........@.$E.t|
-00000070 86 31 7b 39 d1 3c a2 67 99 28 06 b1 34 b6 3c a6 |.1{9.<.g.(..4.<.|
-00000080 1d ce 39 aa 56 c9 72 0d f1 e0 c1 5a 51 a0 5d f2 |..9.V.r....ZQ.].|
-00000090 44 4d e6 d7 0e 84 |DM....|
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 22 71 28 3d 07 73 61 5e 84 72 36 |....."q(=.sa^.r6|
+00000050 c0 87 37 4a 5b c2 d9 40 96 a2 01 20 b2 04 23 2f |..7J[..@... ..#/|
+00000060 c1 6f 1e 7c a1 77 20 0f 87 46 98 a2 5c aa 35 37 |.o.|.w ..F..\.57|
+00000070 37 87 5a 75 33 |7.Zu3|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 40 82 8d c7 e3 7b |..........@....{|
-00000010 f8 9d 33 a1 c2 08 8c 24 d9 af 66 64 6e e8 61 8e |..3....$..fdn.a.|
-00000020 3c 03 65 2d c3 64 a2 26 23 a5 25 3f a2 a4 f9 40 |<.e-.d.&#.%?...@|
-00000030 ec 9f 0e b8 57 b1 5f 84 ea 94 72 1a 3e 60 f1 dd |....W._...r.>`..|
-00000040 af 2e 81 f7 16 de 43 85 21 51 49 |......C.!QI|
+00000000 14 03 02 00 01 01 16 03 02 00 40 21 b5 1f 8d 4b |..........@!...K|
+00000010 1c a7 28 4e 73 3e d7 c5 75 6e eb e4 b3 95 02 4e |..(Ns>..un.....N|
+00000020 a3 47 03 44 97 69 c9 89 f5 ac e2 29 5e 22 e7 2c |.G.D.i.....)^".,|
+00000030 a2 2d e3 ac 64 45 ae 9d 07 9e fe f8 c6 85 47 4d |.-..dE........GM|
+00000040 59 be 72 8d e6 50 da c7 83 91 14 |Y.r..P.....|
>>> Flow 5 (client to server)
00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 43 8f 88 82 c8 e1 55 37 76 d7 a5 |.....C.....U7v..|
-00000020 83 c6 d2 94 26 fe 30 1f e2 24 ca d7 27 22 33 47 |....&.0..$..'"3G|
-00000030 5f a9 74 9d ad 15 03 02 00 30 00 00 00 00 00 00 |_.t......0......|
-00000040 00 00 00 00 00 00 00 00 00 00 49 8e ee 5c ec 86 |..........I..\..|
-00000050 e7 64 a7 ac 0d 5c c4 43 a6 45 a4 22 b7 3d 21 06 |.d...\.C.E.".=!.|
-00000060 11 67 08 99 9a 08 a1 7c e0 1e |.g.....|..|
+00000010 00 00 00 00 00 57 45 25 4c 1b 90 d3 28 e1 69 43 |.....WE%L...(.iC|
+00000020 c5 28 d9 d5 15 35 cf 41 bb 38 f2 12 c6 18 a5 a2 |.(...5.A.8......|
+00000030 f5 e4 64 1d 59 15 03 02 00 30 00 00 00 00 00 00 |..d.Y....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 35 06 5f e3 ff e7 |..........5._...|
+00000050 f0 f1 0c d5 b1 59 42 80 19 8d 67 1b 18 18 5c 18 |.....YB...g...\.|
+00000060 42 38 67 85 c3 ab e2 dc 60 d4 |B8g.....`.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
index 75816429d1..48ff7bce32 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -1,95 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 59 02 00 00 55 03 02 0c 74 28 d1 02 |....Y...U...t(..|
-00000010 15 8f 15 9c ec 8c 4e 34 97 d8 14 ab 0c ed 1b 38 |......N4.......8|
-00000020 af 7f e6 d3 41 db fd ad a0 8d 4f 20 03 71 4a d6 |....A.....O .qJ.|
-00000030 32 23 57 6c e1 55 34 1d 48 6f 9d e0 9a db 15 9d |2#Wl.U4.Ho......|
-00000040 5b 45 a7 3e 4e 98 31 7d f5 d4 b6 36 c0 13 00 00 |[E.>N.1}...6....|
+00000000 16 03 02 00 59 02 00 00 55 03 02 10 ca d9 1b 83 |....Y...U.......|
+00000010 59 c8 a5 a5 6a 89 65 6e 1c 0a 49 98 69 05 49 27 |Y...j.en..I.i.I'|
+00000020 96 72 74 5f 6e 5b 66 26 3b fd f8 20 23 b5 d6 c5 |.rt_n[f&;.. #...|
+00000030 09 f1 66 02 27 5c 5a 15 17 83 c5 11 a4 32 cf d8 |..f.'\Z......2..|
+00000040 1e a0 e7 93 83 35 6e aa 61 ae 97 77 c0 13 00 00 |.....5n.a..w....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 02 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 02 00 cb 0c 00 00 c7 03 00 17 |..9.............|
-000002e0 41 04 2c e8 55 b8 19 d6 cd e5 c7 96 a4 aa 61 af |A.,.U.........a.|
-000002f0 aa b2 f1 fc b3 ac 9a 90 02 d0 0a 86 61 9a c1 2e |............a...|
-00000300 3e fd 42 0b ba 07 95 77 2b 92 a2 5b 1f 44 ad 6b |>.B....w+..[.D.k|
-00000310 78 7a f4 b3 4b 04 d3 d5 2d eb 20 2d 73 02 4c db |xz..K...-. -s.L.|
-00000320 7e ac 00 80 79 b0 c6 b9 a8 50 e4 bf de 97 c6 1f |~...y....P......|
-00000330 ae 5f 89 77 6e e4 23 8c 8d 1a 49 f8 d4 92 cf 0d |._.wn.#...I.....|
-00000340 f0 08 bd 3a 88 9c 55 46 fc be 9e 7c 70 ff 6f 70 |...:..UF...|p.op|
-00000350 7b 94 b3 7b 82 c3 58 53 f7 20 13 3c 83 6e 10 55 |{..{..XS. .<.n.U|
-00000360 9d 51 cb 53 8c 93 dc 0e 02 06 40 d4 df ce 57 e4 |.Q.S......@...W.|
-00000370 e0 9a ba e2 b3 9b 01 98 0e 12 ca e9 96 5b 7a f2 |.............[z.|
-00000380 b1 ac 9c 44 e7 6e 2e c6 51 63 99 68 26 93 ca e2 |...D.n..Qc.h&...|
-00000390 40 31 e5 9a 80 ce 83 8f ca 80 90 c4 e8 ab 89 b2 |@1..............|
-000003a0 ca d6 30 a5 16 03 02 00 04 0e 00 00 00 |..0..........|
+00000060 02 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 02 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 97 a4 91 6b cd ca 44 |........ ...k..D|
+000002d0 7e ac fd a5 b1 c0 ce 88 07 f3 a2 d9 93 2b a8 d9 |~............+..|
+000002e0 0b 65 0b 47 c0 2e 4f 3b 26 00 80 00 18 01 a1 29 |.e.G..O;&......)|
+000002f0 0b 84 c9 09 5e 8c 58 5f 62 b6 22 8b 94 6e 72 26 |....^.X_b."..nr&|
+00000300 44 27 32 b9 22 12 67 58 34 a1 ce 6f 87 19 a0 5c |D'2.".gX4..o...\|
+00000310 5d 58 dc 91 fb c7 e6 31 33 76 6d 1f 8e 4f 46 55 |]X.....13vm..OFU|
+00000320 f1 08 57 9b bb fe 8d c7 6c 0b cd 8b ad b7 51 28 |..W.....l.....Q(|
+00000330 f8 5b 75 97 fe a0 d4 a1 2e 9a d3 d5 45 62 f8 19 |.[u.........Eb..|
+00000340 f6 73 d0 f6 6d e8 43 49 a2 f5 71 66 c5 29 1a 99 |.s..m.CI..qf.)..|
+00000350 e6 c0 cc f9 a5 cd a5 b7 58 08 4d cc 17 46 91 4c |........X.M..F.L|
+00000360 29 99 b4 05 78 af e7 b0 d1 2d 38 16 03 02 00 04 |)...x....-8.....|
+00000370 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
-00000060 00 00 00 00 00 00 7d 87 6f 44 8f b9 92 51 5a b7 |......}.oD...QZ.|
-00000070 d2 6c 22 7f 62 a1 4e 30 61 f8 42 cd b0 05 c0 24 |.l".b.N0a.B....$|
-00000080 1f e0 49 a8 36 ce 8a 68 94 b7 37 c7 e8 d9 d8 05 |..I.6..h..7.....|
-00000090 be fb 5e 48 ba d1 |..^H..|
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 f2 fb 8f ab ae 46 f2 6a 18 1b 77 |..........F.j..w|
+00000050 f3 ce 0c b6 83 9c d6 34 54 82 76 db 5c 79 5d cf |.......4T.v.\y].|
+00000060 24 f3 26 6d 9d f0 af d3 fc e0 96 69 0a 04 f7 ba |$.&m.......i....|
+00000070 78 54 af 37 a5 |xT.7.|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 40 7d ed 01 b9 5a |..........@}...Z|
-00000010 34 f4 e1 63 70 84 13 86 e6 4d 90 92 da 3c 9b 35 |4..cp....M...<.5|
-00000020 77 92 7f 0a fd 69 09 75 30 5b c3 2c 6e 8e d0 59 |w....i.u0[.,n..Y|
-00000030 08 08 5c c9 eb 53 45 f3 a6 12 16 f2 95 06 27 82 |..\..SE.......'.|
-00000040 6d 9b 9e 6a bb 52 79 65 ca 94 9b |m..j.Rye...|
+00000000 14 03 02 00 01 01 16 03 02 00 40 e7 d9 0e af 0c |..........@.....|
+00000010 06 55 85 ab b0 0a 5e d9 11 81 7a 53 c0 f6 3f 84 |.U....^...zS..?.|
+00000020 06 7d 9c 20 05 e9 0d 1d df 9b 48 11 d9 df 0c e6 |.}. ......H.....|
+00000030 6b c2 a8 8f f4 d9 e8 8e f6 1a 3e db 7c e5 97 ac |k.........>.|...|
+00000040 5d 63 08 b2 3a 54 91 62 fc 2e a5 |]c..:T.b...|
>>> Flow 5 (client to server)
00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 bb 2d 28 50 1f a4 8f be 94 b9 99 |......-(P.......|
-00000020 e6 0b dd cf 50 fc 72 92 ec 1d 72 9b 27 9a 36 18 |....P.r...r.'.6.|
-00000030 3e e3 d7 cc 69 15 03 02 00 30 00 00 00 00 00 00 |>...i....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 61 ca 39 3c 7e 9f |..........a.9<~.|
-00000050 1c c8 c2 2a 42 4a d0 c4 f3 80 41 04 b4 35 d0 41 |...*BJ....A..5.A|
-00000060 3d 47 1b 16 2c 71 27 04 7c 81 |=G..,q'.|.|
+00000010 00 00 00 00 00 3f ef e9 bc 10 07 75 99 67 8f 99 |.....?.....u.g..|
+00000020 bb c0 15 94 86 a2 80 cc 15 97 54 f8 4e 1a d1 9a |..........T.N...|
+00000030 33 80 aa da ec 15 03 02 00 30 00 00 00 00 00 00 |3........0......|
+00000040 00 00 00 00 00 00 00 00 00 00 6f 78 7b d2 80 62 |..........ox{..b|
+00000050 5c cf 34 d6 5a 72 d8 63 95 24 c6 ff 69 d0 6d 90 |\.4.Zr.c.$..i.m.|
+00000060 8d a2 9f 37 e8 7b b1 d4 68 04 |...7.{..h.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
index e5e315e255..2e9c49e27a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 51 02 00 00 4d 03 02 59 22 be 64 85 |....Q...M..Y".d.|
-00000010 71 af 54 70 5f a8 50 ff 68 52 a0 9e a7 79 4d 90 |q.Tp_.P.hR...yM.|
-00000020 cd bc c7 9c 4f 62 bc 4d a6 b9 0c 20 e1 94 8f 01 |....Ob.M... ....|
-00000030 fa 7f 9e 6f 01 72 82 ef cc 41 ed 4d 7e 76 ee e1 |...o.r...A.M~v..|
-00000040 21 34 f3 5c e0 b4 4b e2 73 37 a8 40 00 05 00 00 |!4.\..K.s7.@....|
-00000050 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 02 00 51 02 00 00 4d 03 02 36 8f 18 79 0f |....Q...M..6..y.|
+00000010 99 6b 3d 1d f4 19 aa ff 79 7c 50 15 52 db 9d c5 |.k=.....y|P.R...|
+00000020 62 40 2d 5b de 45 0c 66 b1 cb be 20 9e 00 c3 00 |b@-[.E.f... ....|
+00000030 22 2f b5 c6 79 c1 f7 72 8f 4b 94 f4 ac fe a9 53 |"/..y..r.K.....S|
+00000040 97 4e fb 00 df 34 b6 24 8f ff 89 db 00 05 00 00 |.N...4.$........|
+00000050 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 02 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 02 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 02 00 24 0b 7b 3e 32 fb 94 95 66 26 a9 |.....$.{>2...f&.|
-000000a0 4c 21 5e 18 59 cb 80 57 1b 9a 89 c8 91 c5 30 1f |L!^.Y..W......0.|
-000000b0 1a e2 80 9a 0f 03 8e 7b 4c 7d |.......{L}|
+00000000 16 03 02 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 02 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 02 00 24 92 fa 9a bb 9b a3 39 3f 6b 0c |.....$......9?k.|
+000000a0 70 b5 48 4a fc cf 79 86 c7 90 e8 db ca 6a ff 95 |p.HJ..y......j..|
+000000b0 11 9b 65 b2 07 61 00 a8 dc 14 |..e..a....|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 24 06 7f be 82 45 |..........$....E|
-00000010 79 c6 67 fb d3 1e 3f ca d9 0f 8f 81 36 cc 80 77 |y.g...?.....6..w|
-00000020 b8 48 f3 88 29 fa f1 3a b2 d4 fd 10 e5 8c 43 |.H..)..:......C|
+00000000 14 03 02 00 01 01 16 03 02 00 24 47 d5 78 31 32 |..........$G.x12|
+00000010 db db 2b f4 2f e6 a4 fa fa 04 31 ba c0 bc 86 38 |..+./.....1....8|
+00000020 29 70 53 c6 8c 28 e5 75 90 ed 0f 4f 3e cb 06 |)pS..(.u...O>..|
>>> Flow 5 (client to server)
-00000000 17 03 02 00 1a 29 4d a2 80 38 2c 9e 96 bb 29 8b |.....)M..8,...).|
-00000010 22 69 ea 85 3e d8 a9 66 39 b8 58 12 ae 67 db 15 |"i..>..f9.X..g..|
-00000020 03 02 00 16 8c b2 f4 c1 35 5d 28 dc 5c bc 30 95 |........5](.\.0.|
-00000030 99 3e f6 c6 ff 4f 5c f4 85 1a |.>...O\...|
+00000000 17 03 02 00 1a f3 e7 6c 01 c5 70 c6 69 dd 4f 40 |.......l..p.i.O@|
+00000010 38 c1 b2 d2 28 69 2f 99 b1 bd 71 d0 c2 00 08 15 |8...(i/...q.....|
+00000020 03 02 00 16 4c 44 14 02 8e 46 f8 84 40 f1 3d 6d |....LD...F..@.=m|
+00000030 f2 01 f6 9d 7a 0b 18 ee 9d 41 |....z....A|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
index 9e41089e82..c20dcc658f 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 e7 18 39 61 14 |....Q...M....9a.|
-00000010 47 69 40 34 ae 4e 58 4b 32 2d ed 2a 52 09 c5 2f |Gi@4.NXK2-.*R../|
-00000020 07 f6 44 0b 2b 9c 43 4b bb 79 b6 20 48 f4 ff f1 |..D.+.CK.y. H...|
-00000030 c6 72 77 e5 3a e0 8d 08 b9 cd 8b bf e3 9b ec 41 |.rw.:..........A|
-00000040 1d d9 86 1b 35 7b 8c 04 e0 83 0d d3 00 9c 00 00 |....5{..........|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 65 9c b1 7a 5c |....Q...M..e..z\|
+00000010 84 e5 a5 12 ba 54 1f 4c ec 95 0b 8f ea 5c cc 3b |.....T.L.....\.;|
+00000020 de b8 18 23 8e c4 95 59 d7 7f 8f 20 36 fe ec 27 |...#...Y... 6..'|
+00000030 10 85 43 fb 9c 68 3f 69 d0 08 a6 57 10 a6 29 a4 |..C..h?i...W..).|
+00000040 f6 0c 2e 05 6e 0d e5 44 61 e1 2e 07 00 9c 00 00 |....n..Da.......|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 8a 9b |.....(..........|
-000000a0 29 1d 64 2e ee 0d 39 d9 c5 86 b9 02 9d c3 bd 74 |).d...9........t|
-000000b0 39 9d 53 9f 1a ee 84 64 82 82 41 81 f8 2f |9.S....d..A../|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 f1 |.....(..........|
+000000a0 fe 34 f7 de 76 9b 56 27 e6 9f 36 48 30 a6 de 78 |.4..v.V'..6H0..x|
+000000b0 10 6a ef bf 92 8a 6e 99 21 2f 1b 7b 48 80 |.j....n.!/.{H.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 60 71 25 f9 f9 |..........(`q%..|
-00000010 89 cd f8 6f 00 a6 0e 92 f8 3e 84 08 79 6f 91 cd |...o.....>..yo..|
-00000020 e2 62 d5 da 96 79 c3 0d f4 34 26 bd 47 9c 30 aa |.b...y...4&.G.0.|
-00000030 1b 5f 24 |._$|
+00000000 14 03 03 00 01 01 16 03 03 00 28 23 9d a2 ae a1 |..........(#....|
+00000010 7d dd 92 1f 42 18 68 f6 fb 31 56 7b e4 58 a4 e9 |}...B.h..1V{.X..|
+00000020 c2 1c e7 67 1b 40 b1 b9 63 9d 05 fb c7 44 9e f6 |...g.@..c....D..|
+00000030 7a 14 bb |z..|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 44 05 c9 |.............D..|
-00000010 2b 82 55 26 ab 4b 65 b1 94 e5 8a 81 bf 44 a5 cb |+.U&.Ke......D..|
-00000020 22 f0 0a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |"...............|
-00000030 59 8d 6f 5d 30 47 4d 3e ed aa 87 5f ca 39 44 a4 |Y.o]0GM>..._.9D.|
-00000040 9b fc |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d7 31 70 |..............1p|
+00000010 c8 11 3f bd 83 fc 6e f8 3b e0 ee 45 c5 1a c8 41 |..?...n.;..E...A|
+00000020 80 22 d4 15 03 03 00 1a 00 00 00 00 00 00 00 02 |."..............|
+00000030 7a fe 3a 11 7c c0 26 30 55 24 85 0b 43 cb 7c ac |z.:.|.&0U$..C.|.|
+00000040 ef 2c |.,|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
new file mode 100644
index 0000000000..774481e84a
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 26 31 ba 4a 56 |....Q...M..&1.JV|
+00000010 16 83 15 47 b9 c4 7e 10 ca 92 31 4d 77 af cc cd |...G..~...1Mw...|
+00000020 70 f4 cc 82 6e b9 ac 1b 0d 17 25 20 e9 08 ec 95 |p...n.....% ....|
+00000030 ea 84 a4 bd 8f 9d 8e d3 58 a7 5e 72 42 e4 19 8f |........X.^rB...|
+00000040 46 c3 d9 be 16 3c d4 53 5a 02 8f a1 00 3c 00 00 |F....<.SZ....<..|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 |.....P..........|
+000000a0 00 00 00 00 00 00 46 91 40 e2 65 40 fe 42 c3 34 |......F.@.e@.B.4|
+000000b0 98 65 89 d0 96 7e 7b 67 8e c4 d5 e6 37 f5 96 04 |.e...~{g....7...|
+000000c0 b7 c8 63 83 76 5c ca 9d 89 18 d4 97 8b 3f f6 75 |..c.v\.......?.u|
+000000d0 1d 51 0b b9 90 1c 85 8f 83 20 9e 9a 21 d9 db 14 |.Q....... ..!...|
+000000e0 1e 02 d4 ab aa c4 |......|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 6d 34 72 de 79 |..........Pm4r.y|
+00000010 ad 96 d0 92 5f d7 01 de 90 f4 5d 0f de 02 ae 19 |...._.....].....|
+00000020 61 a3 ee 29 ab 18 f1 09 2e 5b bc e0 73 9a 68 19 |a..).....[..s.h.|
+00000030 17 dd c8 d9 63 b4 28 c8 da 1a 81 40 ca d3 5a 99 |....c.(....@..Z.|
+00000040 17 67 fe e9 dd 1a 52 c4 6e 70 0a 0e cf e8 c0 f8 |.g....R.np......|
+00000050 6c 1f ee d2 70 97 dc ee b8 95 35 |l...p.....5|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 ee 03 cc 04 97 17 f0 04 85 02 b7 |................|
+00000020 5c 24 ca 9f c2 25 e0 76 f4 72 e5 71 2b ac f4 a5 |\$...%.v.r.q+...|
+00000030 c4 62 08 9a da b7 ab 30 2f 34 b0 70 20 a3 b9 b3 |.b.....0/4.p ...|
+00000040 df 90 9b 01 0b 15 03 03 00 40 00 00 00 00 00 00 |.........@......|
+00000050 00 00 00 00 00 00 00 00 00 00 3b ca fc 0e 08 f2 |..........;.....|
+00000060 c8 b7 22 61 43 24 b3 54 1b ca 58 c6 bd 27 f3 3d |.."aC$.T..X..'.=|
+00000070 ac a0 d8 fe 0e b5 15 7c 1f 98 32 f0 6b 28 bc 61 |.......|..2.k(.a|
+00000080 6c c7 ba 66 54 19 92 a9 6f 43 |l..fT...oC|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
index 33fb70871e..6d2674639a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 08 e2 40 1b 1a |....Q...M....@..|
-00000010 54 dc 66 60 e1 e0 8d 94 c6 dd 2c eb 95 e0 e9 2f |T.f`......,..../|
-00000020 fb 49 17 d8 34 d7 a2 7a 1b e1 60 20 26 a3 4b 7c |.I..4..z..` &.K||
-00000030 40 cc df 4b 9c 72 a9 e6 61 89 1e 20 b2 e5 e3 1e |@..K.r..a.. ....|
-00000040 4e a3 b6 32 ce fc 94 0d ab 13 74 f8 00 9d 00 00 |N..2......t.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 98 b0 4a 9a c8 |....Q...M....J..|
+00000010 8f f9 1f f9 70 03 d9 1a ee 7c 29 30 6a 71 7c 6c |....p....|)0jq|l|
+00000020 ea 2c de 84 f9 ee 4d 2c d7 58 12 20 a4 e2 1b f3 |.,....M,.X. ....|
+00000030 42 b8 9a 0b 71 8c 27 57 61 98 c5 c5 1b 04 01 5b |B...q.'Wa......[|
+00000040 a0 bc 88 64 d9 ce 5a a1 b2 7b 6c 4e 00 9d 00 00 |...d..Z..{lN....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 28 9a |.....(........(.|
-000000a0 46 23 21 fa a9 ec 6d 57 d1 27 2f 53 58 a9 00 48 |F#!...mW.'/SX..H|
-000000b0 7e 82 82 b8 23 f3 c4 a8 d3 2c a3 99 76 2e |~...#....,..v.|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 57 97 |.....(........W.|
+000000a0 64 ef 80 07 b0 31 02 c8 2a a2 b7 1f d6 a3 7c 7a |d....1..*.....|z|
+000000b0 e9 c4 e1 55 9f 0a ef 0d 8f 0a 57 13 f5 a4 |...U......W...|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 0c c8 0a e1 b8 |..........(.....|
-00000010 95 b9 84 bc 0f 48 eb d4 4a a5 63 c2 92 58 8a 91 |.....H..J.c..X..|
-00000020 27 30 36 28 23 f5 50 bd d6 a9 e9 61 54 10 f9 72 |'06(#.P....aT..r|
-00000030 98 d1 0e |...|
+00000000 14 03 03 00 01 01 16 03 03 00 28 42 49 9c 67 4f |..........(BI.gO|
+00000010 36 75 b8 34 0e ee 00 98 1a ba 52 d5 96 7b 91 d7 |6u.4......R..{..|
+00000020 ba ec e4 5e 2e 42 e3 72 a0 ea 60 24 31 30 3d a2 |...^.B.r..`$10=.|
+00000030 c5 6c 8f |.l.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 b9 55 ce |..............U.|
-00000010 5a ab 7e 7e 58 4f c9 5a bc 0e 93 98 4f 87 86 98 |Z.~~XO.Z....O...|
-00000020 a6 40 7e 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.@~.............|
-00000030 57 0c 6f d9 28 87 d4 a6 de 14 91 a7 79 cc 19 e5 |W.o.(.......y...|
-00000040 28 66 |(f|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 42 9f da |.............B..|
+00000010 a1 e6 98 48 a8 6c 78 a0 f7 fd e7 0f bc df 97 ef |...H.lx.........|
+00000020 b8 62 4c 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.bL.............|
+00000030 99 ac 35 a4 d9 1f 58 26 51 c6 6a b9 1f 53 ec 19 |..5...X&Q.j..S..|
+00000040 90 78 |.x|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
index d7745dc295..9f90ff269a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -1,93 +1,86 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 9d 01 00 00 99 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 a9 01 00 00 a5 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 4e 33 74 00 00 00 05 00 05 01 00 00 00 |...N3t..........|
-00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................|
-00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................|
-00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 10 00 0e |................|
-00000090 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 12 |.proto2.proto1..|
-000000a0 00 00 |..|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 50 33 74 |.............P3t|
+00000060 00 00 00 05 00 05 01 00 00 00 00 00 0a 00 0a 00 |................|
+00000070 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
+00000080 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
+00000090 03 ff 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f |.............pro|
+000000a0 74 6f 32 06 70 72 6f 74 6f 31 00 12 00 00 |to2.proto1....|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 66 02 00 00 62 03 03 a2 7d b9 7c f9 |....f...b...}.|.|
-00000010 bf fb cb b2 d5 11 c0 99 19 73 3d b4 eb 6b 39 f8 |.........s=..k9.|
-00000020 1b 7c 1d 6b 17 4d 66 a3 ed 20 5b 20 ee 87 d7 1f |.|.k.Mf.. [ ....|
-00000030 cf 60 6c 75 12 8b de 56 f6 ca da 4a 92 76 49 43 |.`lu...V...J.vIC|
-00000040 70 18 0a e7 7b 2a 0c f3 44 a6 d8 dd c0 2f 00 00 |p...{*..D..../..|
+00000000 16 03 03 00 66 02 00 00 62 03 03 8d 70 c6 03 ad |....f...b...p...|
+00000010 2f 20 b3 c2 ab e0 fc 80 74 c4 23 9e 82 65 61 a1 |/ ......t.#..ea.|
+00000020 26 97 14 a0 9b 9c d5 e0 92 43 ee 20 ec 84 cf 78 |&........C. ...x|
+00000030 44 16 7d f3 ad 94 a9 f8 c3 e0 c6 e1 b6 c5 e3 3d |D.}............=|
+00000040 77 ea 76 1d 58 cc 94 3a ad 1a 1a 6c cc a8 00 00 |w.v.X..:...l....|
00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................|
-00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 71 |.....proto1....q|
-00000070 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.|
-00000080 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....|
-00000090 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
-000000a0 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go|
-000000b0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.|
-000000c0 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
-000000d0 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.|
-000000e0 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&|
-000000f0 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl|
-00000100 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U|
-00000110 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H|
-00000120 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...|
-00000130 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.|
-00000140 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb|
-00000150 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.|
-00000160 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV|
-00000170 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....|
-00000180 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...|
-00000190 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.|
-000001a0 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........|
-000001b0 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.|
-000001c0 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.|
-000001d0 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....|
-000001e0 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..|
-000001f0 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U|
-00000200 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM|
-00000210 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0|
-00000220 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f..@....x|
-00000230 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...|
-00000240 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.|
-00000250 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........|
-00000260 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H@.-|
-00000270 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v|
-00000280 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.|
-00000290 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_|
-000002a0 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..|
-000002b0 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..|
-000002c0 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |....@.Q......F.F|
-000002d0 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9|
-000002e0 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 41 |.............A.A|
-000002f0 a4 1f 6f ea 6d 59 68 72 1a 6d 47 c7 b4 a0 08 01 |..o.mYhr.mG.....|
-00000300 b9 b3 d8 7a 95 75 c0 58 2a d9 29 91 e7 d9 78 b2 |...z.u.X*.)...x.|
-00000310 97 1d 52 72 2d 18 cb ce 83 8a 07 f4 bd dd 7e a1 |..Rr-.........~.|
-00000320 d2 45 51 9d bf f1 bf 01 33 3a 10 94 6c 2b 99 04 |.EQ.....3:..l+..|
-00000330 01 00 80 63 8f 03 6d b4 4d f7 27 d0 1f f2 0f ff |...c..m.M.'.....|
-00000340 af 27 c2 97 21 68 8c 32 8b 14 67 0e b5 75 3a 5b |.'..!h.2..g..u:[|
-00000350 73 08 9a c7 fd ad 8d 50 2a de e7 d6 c5 87 7a b2 |s......P*.....z.|
-00000360 06 29 0a 09 dd d4 81 d5 a7 2b 4d 20 50 72 6f be |.).......+M Pro.|
-00000370 35 9b c6 2d b0 1e 8f a2 cf 10 33 d4 53 0b 33 95 |5..-......3.S.3.|
-00000380 b8 a5 34 38 1b db 1e 45 07 36 3a 86 c7 f1 b1 3a |..48...E.6:....:|
-00000390 2e 5d 82 b2 1d 3e e1 27 8f f2 f4 2c 8c c3 27 e9 |.]...>.'...,..'.|
-000003a0 f0 9a 8f 6d 20 b1 19 8e 23 d5 04 69 e4 eb 0d eb |...m ...#..i....|
-000003b0 97 fb 71 16 03 03 00 04 0e 00 00 00 |..q.........|
+00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 59 |.....proto1....Y|
+00000070 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+00000080 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+00000090 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+000000a0 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+000000b0 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+000000c0 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+000000d0 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+000000e0 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+000000f0 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000100 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000110 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000120 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000130 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+00000140 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y.@.Om..+.....g|
+00000150 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+00000160 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+00000170 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+00000180 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+00000190 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+000001a0 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+000001b0 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+000001c0 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+000001d0 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+000001e0 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+000001f0 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000200 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000210 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000220 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000230 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+00000240 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0.@+[P|
+00000250 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+00000260 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+00000270 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+00000280 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+00000290 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+000002a0 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F|
+000002b0 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+000002c0 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+000002d0 00 a8 03 00 1d 20 84 de 31 92 b6 a5 d8 a4 88 a2 |..... ..1.......|
+000002e0 54 67 e6 61 40 f2 5a 87 0f ce 15 b1 d6 af f3 5d |Tg.a@.Z........]|
+000002f0 99 71 d6 04 f5 52 04 01 00 80 a8 1d 8b 8c e9 a3 |.q...R..........|
+00000300 af 2d 31 e4 0f f0 26 74 c2 e5 1b ae ac 47 9c 6e |.-1...&t.....G.n|
+00000310 6c 5f 45 7d b1 b3 2a af 36 68 42 13 95 0d 33 1c |l_E}..*.6hB...3.|
+00000320 8d 6c 72 48 4a 94 f0 fb 82 20 cc 76 21 7f 62 e7 |.lrHJ.... .v!.b.|
+00000330 23 a3 c8 4e 3a ce f1 5c c3 60 73 26 59 4c 94 f3 |#..N:..\.`s&YL..|
+00000340 07 36 f6 a0 b3 60 03 d5 72 1e bf c8 d9 1d 61 01 |.6...`..r.....a.|
+00000350 9a 18 57 a3 b4 de 36 1f e1 7d dc 69 c0 fb c0 71 |..W...6..}.i...q|
+00000360 45 1f 73 0d 50 69 d3 18 97 23 60 1c 5a 9a 93 b4 |E.s.Pi...#`.Z...|
+00000370 67 cc e5 80 3b 25 d0 6c 50 c8 16 03 03 00 04 0e |g...;%.lP.......|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 15 94 |.....(..........|
-00000060 6f 5b 35 9d eb 14 c8 be 23 a7 05 8c 14 86 35 a7 |o[5.....#.....5.|
-00000070 5c 91 76 4f 85 b1 09 f8 0f 58 9f ec d2 a9 |\.vO.....X....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 5c c5 3e 7a 14 97 1b 55 88 25 08 |.... \.>z...U.%.|
+00000040 ad 86 48 ac f0 43 8c 17 5b 58 93 6c 7a 95 69 a8 |..H..C..[X.lz.i.|
+00000050 ad 0c b3 61 4d |...aM|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 e7 7f 99 c9 fa |..........(.....|
-00000010 e0 a3 e3 77 68 74 37 62 26 90 d6 be ec a1 ae 5a |...wht7b&......Z|
-00000020 de af 10 f1 2e a0 42 f0 88 ed 89 54 04 b2 b9 eb |......B....T....|
-00000030 b0 91 b8 |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 dd 1b 80 da d9 |.......... .....|
+00000010 73 da 7d 15 9b 92 82 01 a7 8f fe 4a 75 97 8f f4 |s.}........Ju...|
+00000020 64 1b bf cf c3 40 78 f2 52 f5 7a |d....@x.R.z|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 be e7 77 |...............w|
-00000010 f9 92 ac 51 d0 34 25 34 e6 35 9e ea f0 d3 89 45 |...Q.4%4.5.....E|
-00000020 84 1b 93 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 1a 27 54 01 c9 7c 86 4b 61 c8 98 1b d3 15 1f 93 |.'T..|.Ka.......|
-00000040 f9 42 |.B|
+00000000 17 03 03 00 16 4e fa 7c 37 80 48 19 a6 03 25 7c |.....N.|7.H...%||
+00000010 65 56 43 af 9a e8 e2 aa e5 79 98 15 03 03 00 12 |eVC......y......|
+00000020 f9 b7 01 e8 2e 85 33 89 60 44 84 93 26 4c ec ac |......3.`D..&L..|
+00000030 2e 6f |.o|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
index 9a34e4a78b..62e7d11bb8 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -1,91 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 96 01 00 00 92 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 9c 01 00 00 98 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 47 33 74 00 00 00 05 00 05 01 00 00 00 |...G3t..........|
-00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................|
-00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................|
-00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 09 00 07 |................|
-00000090 06 70 72 6f 74 6f 33 00 12 00 00 |.proto3....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 28 c0 2f |.............(./|
+00000030 c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 c0 09 c0 14 |.+.0.,.'...#....|
+00000040 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 c0 12 00 0a |.......<./.5....|
+00000050 00 05 c0 11 c0 07 01 00 00 47 33 74 00 00 00 05 |.........G3t....|
+00000060 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 |................|
+00000070 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 0c 04 |................|
+00000080 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 01 00 |................|
+00000090 00 10 00 09 00 07 06 70 72 6f 74 6f 33 00 12 00 |.......proto3...|
+000000a0 00 |.|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 18 3d 15 59 fb |....Y...U...=.Y.|
-00000010 0a a4 93 d7 43 50 59 7f 6c f9 64 db b5 47 cc 17 |....CPY.l.d..G..|
-00000020 8c cd 91 b5 04 02 3f c0 5d 60 b7 20 75 ed d2 e9 |......?.]`. u...|
-00000030 b6 72 2d f7 66 34 2e 2f d2 b9 80 66 eb c3 36 f6 |.r-.f4./...f..6.|
-00000040 b2 61 77 79 a9 c2 db cd 57 5a b2 6b c0 2f 00 00 |.awy....WZ.k./..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 36 0e 9f 51 42 |....Y...U..6..QB|
+00000010 82 65 fa b5 17 7a 86 d6 40 33 a9 67 d3 3d aa 2f |.e...z..@3.g.=./|
+00000020 89 a0 39 82 af 16 30 8e 64 80 d4 20 23 a6 d0 12 |..9...0.d.. #...|
+00000030 ff 8c fc b4 b5 47 ec 10 fe ba 73 fb 0f ab e8 1c |.....G....s.....|
+00000040 15 c1 fb 11 c1 b2 e1 8a f7 5d 5b ad c0 2f 00 00 |.........][../..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 62 52 78 76 89 36 e7 b9 a6 cc df 8e f8 c3 |A.bRxv.6........|
-000002f0 52 54 b6 42 9b 68 65 65 27 91 bf 1b 0f 21 ab a9 |RT.B.hee'....!..|
-00000300 f4 00 62 dd 70 25 b8 ec d0 3d 9b 0c 53 16 6e eb |..b.p%...=..S.n.|
-00000310 a8 c3 1a ad a9 de ec 27 64 07 e8 9b b8 bf 5a 6c |.......'d.....Zl|
-00000320 87 f4 04 01 00 80 05 ec 2b f7 2e a4 5e 79 85 6f |........+...^y.o|
-00000330 64 7a b5 fb 9a e9 f1 12 ae 28 93 4b 6d 8e a0 2f |dz.......(.Km../|
-00000340 94 bc 38 26 01 64 ab fb 03 c8 3d 17 bc b4 43 09 |..8&.d....=...C.|
-00000350 19 c8 e9 ac 60 40 67 57 71 e3 72 22 cf b1 a7 38 |....`@gWq.r"...8|
-00000360 ac 86 88 9d 47 6f 70 c9 43 82 75 b6 bf 42 4e 72 |....Gop.C.u..BNr|
-00000370 12 48 d1 2b ce 74 02 5d 30 56 66 6f 71 8f 9b 82 |.H.+.t.]0Vfoq...|
-00000380 70 3b 92 5d fb 37 d3 cf d3 23 27 d2 d5 8d 72 22 |p;.].7...#'...r"|
-00000390 d4 b4 92 6d 64 06 d9 0b e0 bb 34 eb bf 42 ec 6a |...md.....4..B.j|
-000003a0 ea e3 56 68 85 a0 16 03 03 00 04 0e 00 00 00 |..Vh...........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 cd 0c 00 00 c9 03 00 17 41 04 11 b4 a9 10 7e 5c |........A.....~\|
+000002d0 41 5e 39 12 15 a3 ed 5b 3e 5d 68 c8 ad 48 39 ef |A^9....[>]h..H9.|
+000002e0 09 8b b1 a7 bf db 5f 54 49 cd d5 de 4d b3 47 4c |......_TI...M.GL|
+000002f0 18 02 84 7c ec 75 4e d0 3e 8a d1 6c 80 83 98 64 |...|.uN.>..l...d|
+00000300 4a 81 bc 8f 84 c7 e5 b4 2d fa 04 01 00 80 72 ee |J.......-.....r.|
+00000310 41 38 f2 b8 a1 56 81 d8 04 78 75 05 f4 78 5f f2 |A8...V...xu..x_.|
+00000320 2b 5d a2 46 23 9d 48 c8 63 a9 1d de a8 78 6e 99 |+].F#.H.c....xn.|
+00000330 cd 59 6b 19 20 f5 b1 11 e1 f8 1c 5b 40 c3 b8 cd |.Yk. ......[@...|
+00000340 66 a3 98 37 c5 c2 5c b7 d6 cc 61 b4 5e 97 fa dd |f..7..\...a.^...|
+00000350 b7 85 5d b6 34 8c 39 4a 60 5a 03 20 47 7f e3 65 |..].4.9J`Z. G..e|
+00000360 01 18 00 2c c3 eb be d4 aa 58 57 a9 5e 69 fb 3c |...,.....XW.^i.<|
+00000370 fa c6 28 1a 5c f7 00 d5 21 e5 c1 30 db 84 38 c3 |..(.\...!..0..8.|
+00000380 08 aa 08 5f c9 fd a0 b7 8e d0 66 77 bf 13 16 03 |..._......fw....|
+00000390 03 00 04 0e 00 00 00 |.......|
>>> Flow 3 (client to server)
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 34 |.....(.........4|
-00000060 d5 c2 64 97 f6 a9 f5 60 bc 17 f3 d3 02 3f 42 a8 |..d....`.....?B.|
-00000070 2f ba eb c6 50 3c ec 9b 8d 3b 22 ed ec 35 |/...P<...;"..5|
+00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 4f 7e |.....(........O~|
+00000060 9a 3a cc 74 a4 91 77 01 0b 0e 28 0a c5 bd 55 b7 |.:.t..w...(...U.|
+00000070 9a 4c 40 4e e9 c9 46 d5 5f c5 e1 77 c3 f2 |.L@N..F._..w..|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 9a e5 f5 51 5c |..........(...Q\|
-00000010 cb be 5d a1 67 cc 55 aa ba db e7 0a ab 96 3b 33 |..].g.U.......;3|
-00000020 5f 2c 8c 61 20 f1 0d 6e ce 90 d8 39 27 d7 fb 68 |_,.a ..n...9'..h|
-00000030 d9 dd da |...|
+00000000 14 03 03 00 01 01 16 03 03 00 28 62 4b 13 ef 22 |..........(bK.."|
+00000010 f9 a8 8d ec 42 3a 36 80 5d a8 5b e9 60 d1 ba 65 |....B:6.].[.`..e|
+00000020 2b d8 37 64 e5 12 b2 ef 84 75 87 0c 0f 3d 35 6e |+.7d.....u...=5n|
+00000030 59 7c 51 |Y|Q|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 a8 be 7c |...............||
-00000010 05 48 ea df 62 4a 7a 45 68 e4 dc e6 42 ff 06 f2 |.H..bJzEh...B...|
-00000020 02 33 1a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.3..............|
-00000030 66 68 f4 de da 69 b4 f9 80 9c 80 c6 46 e5 2b ae |fh...i......F.+.|
-00000040 0e d1 |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5f cd 4d |............._.M|
+00000010 7b a7 c0 f9 6c 1f 80 93 cf 55 3b 12 c7 21 12 86 |{...l....U;..!..|
+00000020 f6 b1 52 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..R.............|
+00000030 fd 31 a4 4b d1 e9 f0 e0 18 b5 96 28 f7 b4 0c 29 |.1.K.......(...)|
+00000040 8c 0c |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
index 4b88acff71..336e10da83 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 f0 5c 85 c8 ff |....Y...U...\...|
-00000010 c5 57 76 99 3d 75 e6 2e db 31 26 c0 0c 81 c5 6b |.Wv.=u...1&....k|
-00000020 30 79 e6 72 86 77 48 01 ec 43 1a 20 f8 fd ad b5 |0y.r.wH..C. ....|
-00000030 a0 7b f3 35 27 df ad 95 f9 56 f9 79 6c a2 6c 23 |.{.5'....V.yl.l#|
-00000040 51 4c ef fc 92 fb fa 59 97 e9 63 27 c0 09 00 00 |QL.....Y..c'....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 cf 28 2c 3e 4f |....Y...U...(,>O|
+00000010 da 6b ae 24 74 a9 91 c3 c5 55 4b ab ec 07 f8 cd |.k.$t....UK.....|
+00000020 65 f8 fe 08 f6 9a 23 da 99 6c 5d 20 af 4a 1e 32 |e.....#..l] .J.2|
+00000030 7b bd 3c 0b b1 14 66 a3 b7 2f a4 2a c3 43 c4 e0 |{.<...f../.*.C..|
+00000040 c2 ad 78 b1 28 ab 51 06 1b 87 d2 75 c0 09 00 00 |..x.(.Q....u....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,24 +49,22 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 51 |*............A.Q|
-00000280 1e 2e 40 c5 a1 13 15 f0 bc 8a 04 e1 9a 57 74 10 |..@..........Wt.|
-00000290 7e b3 17 bf 0c c9 85 9b 5f bd 6b 39 c7 a6 c0 50 |~......._.k9...P|
-000002a0 0e 5e 9b b1 8c cc 57 39 e8 0f 94 02 be 28 19 16 |.^....W9.....(..|
-000002b0 94 73 2b c1 3c a7 0f c9 e7 b0 89 ac 13 53 f9 04 |.s+.<........S..|
-000002c0 03 00 8b 30 81 88 02 42 01 1b e0 ab 94 02 aa 27 |...0...B.......'|
-000002d0 fa 7b 99 9c 68 36 d8 2d 2e e0 92 84 c7 7b 37 74 |.{..h6.-.....{7t|
-000002e0 6a ad a8 f5 50 3f 74 d5 e8 8e 5a db 31 43 c8 98 |j...P?t...Z.1C..|
-000002f0 d3 ee 61 43 80 9a 72 eb 2d 2b 21 b8 33 aa 61 0a |..aC..r.-+!.3.a.|
-00000300 cd dc 85 88 29 26 83 ee 3c b2 02 42 00 b6 ea 34 |....)&..<..B...4|
-00000310 30 71 5c 0a 9a 6d a2 25 62 1c 3e 13 90 9c a3 b8 |0q\..m.%b.>.....|
-00000320 0d 97 a8 06 26 9e 31 50 88 9a b9 ff 12 63 a8 14 |....&.1P.....c..|
-00000330 18 f3 c2 b0 af d1 27 25 a9 ec ef 69 85 7a 72 c6 |......'%...i.zr.|
-00000340 b0 88 d2 c1 41 43 f4 69 62 25 13 eb f9 f8 16 03 |....AC.ib%......|
-00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&...@.....|
-00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................|
-00000380 00 |.|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 18 6f |*............ .o|
+00000280 77 a5 2b 27 2c 52 fc 6c 8a 34 41 1c a8 c6 4f 90 |w.+',R.l.4A...O.|
+00000290 a9 4b b7 e0 39 8b b1 f5 a6 15 4b 94 e8 2c 04 03 |.K..9.....K..,..|
+000002a0 00 8b 30 81 88 02 42 00 dc 3a 14 a2 38 32 c1 40 |..0...B..:..82.@|
+000002b0 98 83 17 94 e9 2a 0d 95 c3 59 d6 76 94 c2 3e a0 |.....*...Y.v..>.|
+000002c0 f7 e0 5d 64 47 5a d1 d9 ed d2 1c 6b 13 3e e7 83 |..]dGZ.....k.>..|
+000002d0 6e bb 53 33 03 7d 69 c6 8f 9d 98 d7 96 9c 73 e3 |n.S3.}i.......s.|
+000002e0 12 bd 69 1f b1 d3 f4 25 d7 02 42 01 11 6d c8 53 |..i....%..B..m.S|
+000002f0 9b bf f4 db ff 8a 00 82 93 f7 b5 bf c9 bb cd ec |................|
+00000300 64 f8 d9 6d 36 0d f8 db ce 9d 65 a0 5e 5a e0 13 |d..m6.....e.^Z..|
+00000310 ec 08 73 2c 3f 8c c6 5b 08 cc 0f 4a 7d 6b 5e 89 |..s,?..[...J}k^.|
+00000320 bf 4a 4e db 51 5a 9f 51 3e 9d 9a c5 84 16 03 03 |.JN.QZ.Q>.......|
+00000330 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......|
+00000340 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000350 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+00000360 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -100,36 +99,34 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
-00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 93 0f |.h.A.Vk.Z.......|
-00000260 00 00 8f 05 03 00 8b 30 81 88 02 42 00 8a 82 c2 |.......0...B....|
-00000270 c0 30 8c a1 12 c4 4a ed d1 00 3f 2d ee bd 8e 9c |.0....J...?-....|
-00000280 a5 a0 d9 6f 44 27 49 60 e9 75 01 ee b4 0d 87 25 |...oD'I`.u.....%|
-00000290 2a 8d 67 f1 e3 d9 49 6f a0 34 90 76 93 52 f9 17 |*.g...Io.4.v.R..|
-000002a0 fb 1b cc d0 5a f4 50 37 9c 4c 44 b6 61 5f 02 42 |....Z.P7.LD.a_.B|
-000002b0 01 ad 85 38 e9 3a 69 35 ea 74 76 2c 09 6b ab d4 |...8.:i5.tv,.k..|
-000002c0 e0 dc d1 d5 03 41 22 8e 8b 53 98 b7 f1 b6 e9 29 |.....A"..S.....)|
-000002d0 d2 57 34 dc e0 b6 71 77 79 bd 57 61 7c 30 77 00 |.W4...qwy.Wa|0w.|
-000002e0 7a 42 2d 1f ed e8 14 da 16 33 c6 31 e4 3d 53 3a |zB-......3.1.=S:|
-000002f0 9a 37 14 03 03 00 01 01 16 03 03 00 40 00 00 00 |.7..........@...|
-00000300 00 00 00 00 00 00 00 00 00 00 00 00 00 d4 fe c1 |................|
-00000310 a6 fb 21 78 21 80 af 0d da a1 80 68 e2 9c ec 0b |..!x!......h....|
-00000320 57 8c 2a 7e f1 11 3b 52 ea 17 00 d1 d4 14 78 c5 |W.*~..;R......x.|
-00000330 81 39 12 ad 30 98 93 1b 29 77 45 7d 00 |.9..0...)wE}.|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......|
+00000240 00 8f 05 03 00 8b 30 81 88 02 42 01 32 6d 32 38 |......0...B.2m28|
+00000250 d6 bd 1b b6 c5 80 f2 ea 60 b8 bf 3f b6 76 68 1b |........`..?.vh.|
+00000260 66 fb 5d 69 0b 25 09 7f 2d 73 ad 7e cd 98 cb b5 |f.]i.%..-s.~....|
+00000270 93 4e 4f 1c 4e 3f a1 39 cf a0 70 a6 3d 29 36 27 |.NO.N?.9..p.=)6'|
+00000280 51 e0 55 95 11 df 00 88 6c 38 d6 de 36 02 42 01 |Q.U.....l8..6.B.|
+00000290 67 50 81 90 a7 ae b5 e2 34 75 81 41 c2 71 8d 0c |gP......4u.A.q..|
+000002a0 9a 20 e7 33 af 0e 61 48 85 51 a1 f7 90 17 d1 ad |. .3..aH.Q......|
+000002b0 b3 e1 cf 3e 12 fc ce 39 16 a8 78 3b 69 0d 79 76 |...>...9..x;i.yv|
+000002c0 03 17 75 c2 a0 63 5e dc 0a a7 c9 aa 15 2a 83 65 |..u..c^......*.e|
+000002d0 df 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |...........@....|
+000002e0 00 00 00 00 00 00 00 00 00 00 00 00 27 da 48 f6 |............'.H.|
+000002f0 d3 00 98 b9 a6 b7 41 0b eb e6 d1 d7 82 9a 0c 59 |......A........Y|
+00000300 8a 42 1c 99 59 af da a7 5b 88 ab b6 7d 01 bc 0f |.B..Y...[...}...|
+00000310 45 08 c4 05 0d 2a 4a 83 bf eb b1 b6 |E....*J.....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 f7 0a 50 d0 87 |..........@..P..|
-00000010 fb f9 be b0 6b 8d 9b a5 8b d2 56 27 67 7d 3c 51 |....k.....V'g}<Q|
-00000020 af 53 8c 7d 61 9f 12 a5 54 5d ec 56 36 31 01 73 |.S.}a...T].V61.s|
-00000030 37 cb 5f ff 36 3c 1c 4a e3 db ec 99 bc 86 15 e4 |7._.6<.J........|
-00000040 cd 5d 87 bd d7 80 c7 b1 fe 42 9f |.].......B.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 73 7c e6 43 b9 |..........@s|.C.|
+00000010 47 85 1c 50 f1 cb a1 29 79 02 dd 13 85 2a d9 a2 |G..P...)y....*..|
+00000020 07 50 e4 80 c4 7e 66 ee f2 1a 21 1d cd e4 ff 4a |.P...~f...!....J|
+00000030 a4 61 9d b4 a1 26 88 72 20 2b 06 77 c3 8b 3b 21 |.a...&.r +.w..;!|
+00000040 53 33 02 3d a2 06 77 3b a5 a6 0b |S3.=..w;...|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 ef 81 cf 63 f1 b5 6b b2 30 6f 00 |........c..k.0o.|
-00000020 0e c0 0c 5d d4 85 76 d2 30 db 6b 14 06 e4 75 0b |...]..v.0.k...u.|
-00000030 cf fc 72 aa 64 15 03 03 00 30 00 00 00 00 00 00 |..r.d....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 ef 28 8a e7 15 51 |...........(...Q|
-00000050 0d 0d 27 4f 36 35 f6 43 28 d2 16 dc a3 35 33 3e |..'O65.C(....53>|
-00000060 be 80 db 31 a9 89 3d 17 c2 58 |...1..=..X|
+00000010 00 00 00 00 00 1a 45 68 03 9b f0 42 e4 21 5e d8 |......Eh...B.!^.|
+00000020 98 d6 46 67 2b 93 80 92 1f 91 60 a3 05 04 1c a0 |..Fg+.....`.....|
+00000030 1b a9 ce 45 03 15 03 03 00 30 00 00 00 00 00 00 |...E.....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 6b 23 42 c8 5c 29 |..........k#B.\)|
+00000050 f5 1f 7c d5 80 c4 9f 6f 12 77 95 71 8f 82 f9 63 |..|....o.w.q...c|
+00000060 07 2c 6d ed 6d c6 4f 90 50 a3 |.,m.m.O.P.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
index 53f2f8645e..fb6c940a5f 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -1,62 +1,74 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 e8 b5 19 bd df |....Q...M.......|
-00000010 e5 18 78 4b 01 f1 3f 7f ab 91 05 78 98 77 50 bf |..xK..?....x.wP.|
-00000020 60 f5 a4 76 7b 3c 40 9f 54 56 68 20 a1 99 57 a7 |`..v{<@.TVh ..W.|
-00000030 a8 46 ca 26 22 d8 bb 8d 93 12 48 ff be 8e d3 d4 |.F.&".....H.....|
-00000040 e0 fd cd ce f5 d9 a9 2e fe d4 cd 85 00 05 00 00 |................|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&...@.......|
-000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 2e d2 1c 3f f8 |....Y...U.....?.|
+00000010 3a dc be 78 0b fa 03 00 e0 9a b9 62 34 45 f8 34 |:..x.......b4E.4|
+00000020 54 21 4c c0 76 a6 e1 5a a1 67 c2 20 1b 98 25 34 |T!L.v..Z.g. ..%4|
+00000030 79 ac 59 b5 39 c8 93 10 a9 ea 9d 25 3d 2c d8 69 |y.Y.9......%=,.i|
+00000040 da d8 33 75 ef 44 4c 76 92 2b 3b b4 c0 2f 00 00 |..3u.DLv.+;../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 06 be 1b 0b d8 95 59 |........ ......Y|
+000002d0 b2 13 1c 4a 06 b8 36 3e 4f 98 3f 81 11 3e 7d 21 |...J..6>O.?..>}!|
+000002e0 fa d9 f0 db 1b 41 4a d0 14 04 01 00 80 ca 57 f5 |.....AJ.......W.|
+000002f0 e7 b6 72 7e 3f b0 67 f2 a2 d0 84 d5 7f 7d 83 ff |..r~?.g......}..|
+00000300 92 73 4f 19 f7 94 b6 d7 95 f4 1b 56 2a fc fa 24 |.sO........V*..$|
+00000310 3e fe 00 65 52 76 c8 30 8a bf ae fe b5 c9 f2 47 |>..eRv.0.......G|
+00000320 0a 71 ad c1 6a 61 8c b5 ab 59 09 12 92 b2 b4 ad |.q..ja...Y......|
+00000330 cb cc ac c4 30 e9 a4 8a 82 4e 2e d6 1d 16 46 dd |....0....N....F.|
+00000340 60 37 50 b8 ae 83 c1 e6 1d ba 8c c7 18 f7 5e d7 |`7P...........^.|
+00000350 23 e5 8a 14 ba e4 8e a1 77 8a b6 41 03 61 8a 25 |#.......w..A.a.%|
+00000360 8a 27 f8 cb 2e 4a e0 07 aa bf 03 32 98 16 03 03 |.'...J.....2....|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -91,33 +103,30 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..|
-00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....|
-00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S|
-00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...|
-00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e|
-00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...|
-00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR|
-00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M|
-00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 92 0f |.x.N.8FB........|
-000002a0 00 00 8e 05 03 00 8a 30 81 87 02 42 01 4c f6 31 |.......0...B.L.1|
-000002b0 4f ec 64 bb ce d0 96 4d 66 f3 8d 64 78 c9 2d 47 |O.d....Mf..dx.-G|
-000002c0 39 02 88 31 49 84 7f cc a8 af c1 17 35 fb 46 b1 |9..1I.......5.F.|
-000002d0 dc 07 58 71 13 6b 8e 71 2b 94 fd 41 7c 26 45 39 |..Xq.k.q+..A|&E9|
-000002e0 28 b1 aa f7 5b 89 04 de 84 d1 b5 d9 9f f3 02 41 |(...[..........A|
-000002f0 4e f6 2a ed 39 ee 63 68 da f5 ae 1b 4d f5 01 0f |N.*.9.ch....M...|
-00000300 bc f7 05 d2 96 42 67 e3 8f ff 27 d5 bf c4 53 bf |.....Bg...'...S.|
-00000310 8a d7 46 58 05 54 94 d8 73 a9 d9 38 40 5f cb 8c |..FX.T..s..8@_..|
-00000320 c7 d1 94 56 2a e1 61 32 29 f7 c9 c1 e8 95 30 e3 |...V*.a2).....0.|
-00000330 33 14 03 03 00 01 01 16 03 03 00 24 b1 86 d2 50 |3..........$...P|
-00000340 fc ea 68 b1 d9 3d b7 2c fd 2c 87 f0 d4 44 2b 22 |..h..=.,.,...D+"|
-00000350 b8 47 74 77 46 14 6d 18 b3 08 9c 3a d4 a1 ba cb |.GtwF.m....:....|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 92 0f 00 |...._X.;t.......|
+00000240 00 8e 05 03 00 8a 30 81 87 02 41 19 c6 1e f0 f4 |......0...A.....|
+00000250 ca 79 d7 8c 36 0f 56 9a 9d 07 55 31 fe 63 f1 ec |.y..6.V...U1.c..|
+00000260 20 80 6f 12 ed 7f bb c0 87 0a 0d 68 81 89 bd 8b | .o........h....|
+00000270 19 04 5e c0 19 8a d2 0f 6d 71 83 59 ee a7 be be |..^.....mq.Y....|
+00000280 1d bb 2f 12 53 9b ca 58 0e a6 8d ae 02 42 00 d0 |../.S..X.....B..|
+00000290 4c 69 75 30 86 d1 da 73 1b 8e 3e e1 82 9b f3 58 |Liu0...s..>....X|
+000002a0 8f 6d 0a 10 86 72 5f 90 17 d1 ac 34 8a b5 60 d0 |.m...r_....4..`.|
+000002b0 b8 54 0f 05 7f cd 6a c0 62 b5 04 d9 3a 98 95 b6 |.T....j.b...:...|
+000002c0 b3 00 1d 94 6e 79 35 57 d2 78 a4 7a 4a 45 89 d1 |....ny5W.x.zJE..|
+000002d0 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+000002e0 00 00 00 cf b5 3c cf 0a b7 6b 51 cb fe 06 4c df |.....<...kQ...L.|
+000002f0 2c 79 a6 5e a8 75 8b 4c 44 7b ae ff 64 d7 67 dc |,y.^.u.LD{..d.g.|
+00000300 af ef 54 |..T|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 70 c7 ee d4 d3 |..........$p....|
-00000010 d3 ad dc 5a d1 a3 01 89 4d ae 0f b9 7b 97 91 4a |...Z....M...{..J|
-00000020 c0 5b e2 94 ef 5f 2f e0 90 1a 18 8a e8 50 9d |.[..._/......P.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 1c 12 5e 29 ba |..........(..^).|
+00000010 34 b3 d8 ae f7 2a 83 0d 3e 21 ec 91 c9 fa 7f d1 |4....*..>!......|
+00000020 42 7e 8d d9 e5 ed 4e f9 ae 95 66 27 85 cc 44 2d |B~....N...f'..D-|
+00000030 cd a3 26 |..&|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a e8 e8 00 30 71 09 61 65 55 90 c8 |........0q.aeU..|
-00000010 d6 fd 8d 5d a9 fb e6 2b d4 45 a9 8c ea 2f 0b 15 |...]...+.E.../..|
-00000020 03 03 00 16 f2 d3 36 ce 26 42 59 1b d7 15 c5 c4 |......6.&BY.....|
-00000030 8b 0b 06 0a d0 fd 78 62 3d 39 |......xb=9|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 8b 4c 36 |..............L6|
+00000010 6f b8 69 16 0a 40 67 05 5e a8 e6 48 cc ad 7b 29 |o.i..@g.^..H..{)|
+00000020 95 3d 02 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.=..............|
+00000030 58 e3 b5 8e 30 e7 5d 02 cd e5 c0 11 95 3a ef a9 |X...0.]......:..|
+00000040 d7 86 |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
index 9ba51f5ac6..17fc8f8e11 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -1,134 +1,130 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 f5 6d a6 9a 3d |....Y...U...m..=|
-00000010 b4 32 c7 59 b9 f7 09 bb 56 7e 06 26 02 ac eb dd |.2.Y....V~.&....|
-00000020 78 91 e4 cd f9 f4 e7 98 7f 13 f0 20 6d d5 42 4a |x.......... m.BJ|
-00000030 85 ac 86 9a a6 78 6d 5c d7 ef 9d 16 dc ff 5a 41 |.....xm\......ZA|
-00000040 91 5a 54 ff ba f6 90 f4 2a 4f fd 37 c0 30 00 00 |.ZT.....*O.7.0..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 31 df 35 e4 36 |....Y...U..1.5.6|
+00000010 c5 f1 b4 9f e7 5d fa e1 e0 23 04 54 bd 2b fb ab |.....]...#.T.+..|
+00000020 a2 37 8f 35 eb 79 47 e6 f8 2b cb 20 ba d8 db 26 |.7.5.yG..+. ...&|
+00000030 ce 6b 4a e9 1e 0c 46 9f 4d 85 cb d7 b0 e2 3d 20 |.kJ...F.M.....= |
+00000040 58 43 83 37 e1 53 ac 3b d9 b3 fd 0a c0 30 00 00 |XC.7.S.;.....0..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 2a 2a b7 63 a8 8e 34 67 32 18 57 6e fe 2a |A.**.c..4g2.Wn.*|
-000002f0 51 41 41 5f 65 a3 a7 e9 d6 0b 42 7f 77 fb 40 09 |QAA_e.....B.w.@.|
-00000300 c8 7a a2 9b fd 5f 6e 2b ce 85 f6 24 c2 8d e8 bb |.z..._n+...$....|
-00000310 69 3e dc 51 15 6f a8 db a4 fb 11 10 70 04 82 6a |i>.Q.o......p..j|
-00000320 7b 81 04 01 00 80 7a a3 c9 1b e6 02 33 39 55 36 |{.....z.....39U6|
-00000330 dc f9 2d f7 00 5b 8d f4 de 7a f7 3b 1b 4c 9a 27 |..-..[...z.;.L.'|
-00000340 f6 db 3c d1 6b f8 d6 7a 20 53 33 5f 88 9f f6 73 |..<.k..z S3_...s|
-00000350 90 2f 35 9e f6 05 b5 80 96 4f c8 85 e6 72 95 ba |./5......O...r..|
-00000360 3b 42 43 94 c3 0b db 91 ff 6b 24 c6 b1 78 de 18 |;BC......k$..x..|
-00000370 9f d5 3b 33 53 22 45 bf cb b2 d2 77 ce 03 56 7b |..;3S"E....w..V{|
-00000380 b7 56 b6 ec 04 64 62 04 f7 f8 52 1a 47 49 01 71 |.V...db...R.GI.q|
-00000390 29 9e ee 68 1f e9 c6 36 fb 77 4c 9a 14 90 e1 70 |)..h...6.wL....p|
-000003a0 7d 7e 77 92 a6 18 16 03 03 00 2e 0d 00 00 26 03 |}~w...........&.|
-000003b0 01 02 40 00 1e 06 01 06 02 06 03 05 01 05 02 05 |..@.............|
-000003c0 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-000003d0 02 02 03 00 00 0e 00 00 00 |.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 9a 18 f9 2e 33 f7 bb |........ ....3..|
+000002d0 ca 60 0b 51 ad 5c 01 e2 61 82 0b 3f 09 8f 78 9d |.`.Q.\..a..?..x.|
+000002e0 3b 11 8b e0 4a 35 2e d5 54 04 01 00 80 90 94 0e |;...J5..T.......|
+000002f0 bf 3a b7 95 d3 58 cc 65 c3 79 5e 1e bb d9 21 56 |.:...X.e.y^...!V|
+00000300 06 93 6c 2b 6e 26 55 ee 26 c3 02 44 7e db 35 9b |..l+n&U.&..D~.5.|
+00000310 d4 d4 1a a0 65 35 41 a4 6c ce de 1f 94 ff b4 1b |....e5A.l.......|
+00000320 1e 9c 28 0b 4c 8d 55 d0 d8 be f1 df e0 d1 1a b5 |..(.L.U.........|
+00000330 c8 be 2c 5a 2c c3 3f ea 4f e6 d5 b4 6b e1 ff eb |..,Z,.?.O...k...|
+00000340 f3 f3 40 54 d5 62 1f a0 fc b2 34 66 ee c5 27 a6 |..@T.b....4f..'.|
+00000350 2b 2a b9 5d 3f 36 28 eb 39 99 25 e5 04 d2 18 13 |+*.]?6(.9.%.....|
+00000360 3c 23 93 d0 04 37 85 b0 4d 6e 9b 32 9a 16 03 03 |<#...7..Mn.2....|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......|
-00000250 0f 00 00 84 05 01 00 80 45 11 dc 3c 2a fc 5f aa |........E..<*._.|
-00000260 60 09 59 47 45 cc a7 74 e3 9d 0c c3 a4 08 b0 2a |`.YGE..t.......*|
-00000270 44 47 cd 66 ed 94 54 8f d7 74 fd 47 a3 90 56 69 |DG.f..T..t.G..Vi|
-00000280 5a b6 c5 b0 bd c2 16 a2 1e af 58 37 88 cb d1 4b |Z.........X7...K|
-00000290 5c ee e6 0f 16 9b e0 d7 43 b3 e6 0a b2 90 fa 21 |\.......C......!|
-000002a0 78 95 3e 7f fc c1 b3 df a1 bf fc eb bc e8 37 63 |x.>...........7c|
-000002b0 87 33 3e c3 9a e4 6c 0f 3d 0d 9f e8 db 2d 82 ad |.3>...l.=....-..|
-000002c0 3c 6d f7 4a 5e 81 21 4f 19 0e 60 2d ef c1 40 8d |<m.J^.!O..`-..@.|
-000002d0 cb 97 4f 08 1c c0 66 e7 14 03 03 00 01 01 16 03 |..O...f.........|
-000002e0 03 00 28 00 00 00 00 00 00 00 00 8c ce 5e 94 90 |..(..........^..|
-000002f0 22 2c 8d 64 be 29 99 62 1f 95 6e 3b 51 22 9c eb |",.d.).b..n;Q"..|
-00000300 f3 0f 24 b8 a5 84 58 70 82 71 a1 |..$...Xp.q.|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 ad f7 ff a0 cb d0 6e |...............n|
+00000240 8f 19 0c 40 2a 1f bb dd 11 52 81 84 f1 7b 3f cf |...@*....R...{?.|
+00000250 75 72 83 a4 4c 0a 9c 70 95 98 d5 51 a2 28 0c 8c |ur..L..p...Q.(..|
+00000260 20 08 d7 2a a5 3e 0c cf 6c a2 1d 32 bd cc a1 b4 | ..*.>..l..2....|
+00000270 61 e0 6d 9a 61 16 03 5c 7a b8 fa 15 ea cd e4 de |a.m.a..\z.......|
+00000280 d6 16 93 b2 e0 d2 55 b9 03 e0 67 04 27 64 8c e2 |......U...g.'d..|
+00000290 01 ee 8f f7 59 3e 12 16 51 f2 07 20 fe 03 e2 3e |....Y>..Q.. ...>|
+000002a0 09 1f 96 24 c5 73 0e 69 ac 57 ff 43 2b 6a c6 20 |...$.s.i.W.C+j. |
+000002b0 2f e4 ef 7e bc b3 38 57 06 14 03 03 00 01 01 16 |/..~..8W........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 fd 71 f5 ca |...(.........q..|
+000002d0 91 26 67 54 a5 e6 f3 06 c8 40 24 9d a9 bd b1 9a |.&gT.....@$.....|
+000002e0 63 c4 c2 53 56 ba af c0 16 bc 06 5c |c..SV......\|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 b1 23 11 48 69 |..........(.#.Hi|
-00000010 52 44 34 f1 9a 69 2b 79 fb 68 b4 53 d5 d7 08 08 |RD4..i+y.h.S....|
-00000020 34 95 5f 56 b2 57 eb 91 31 6c 32 25 b5 68 8a 8e |4._V.W..1l2%.h..|
-00000030 f1 68 6e |.hn|
+00000000 14 03 03 00 01 01 16 03 03 00 28 92 8f bd c5 97 |..........(.....|
+00000010 94 76 70 f4 0a f9 9a 79 69 31 27 0e c0 c5 0b 3c |.vp....yi1'....<|
+00000020 9f 4f c2 2f cb 6c 56 62 80 3b e5 72 6a 05 9e 4b |.O./.lVb.;.rj..K|
+00000030 34 b9 66 |4.f|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 03 ab 9e |................|
-00000010 f0 a6 6c f1 ea 23 20 63 42 a3 9d c6 5d 41 96 c1 |..l..# cB...]A..|
-00000020 44 b2 8b 15 03 03 00 1a 00 00 00 00 00 00 00 02 |D...............|
-00000030 e9 73 41 50 28 b0 d3 00 46 81 d6 c9 1a ca ab cd |.sAP(...F.......|
-00000040 44 9b |D.|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 43 fb 43 |.............C.C|
+00000010 3d 96 63 dd 25 94 9d 7a fb 9e 15 6f 62 5e ed 34 |=.c.%..z...ob^.4|
+00000020 19 89 b8 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 53 c2 2d 6c b7 91 6c 62 84 09 a2 1c 9b 3d 9e 89 |S.-l..lb.....=..|
+00000040 6a 3d |j=|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
index 4fa5e20e93..1ff91986d2 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 2a 01 f8 3e d1 |....Y...U..*..>.|
-00000010 52 41 2e 9a 8d 56 ff 52 3d 6a fe 65 ab 91 bb b7 |RA...V.R=j.e....|
-00000020 82 be f1 60 40 3b 80 a1 f8 dc 95 20 48 87 41 46 |...`@;..... H.AF|
-00000030 6a d2 f3 b8 d8 68 20 40 45 b7 fe 19 21 bc 84 00 |j....h @E...!...|
-00000040 5d 40 40 21 58 3e 7d fb a7 e3 30 37 c0 09 00 00 |]@@!X>}...07....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 84 4b ff a4 2a |....Y...U...K..*|
+00000010 a4 76 c0 26 f6 05 72 94 01 15 44 f2 c6 7d b0 4b |.v.&..r...D..}.K|
+00000020 1b fa da 51 54 45 78 66 e6 0a dd 20 17 df d2 0c |...QTExf... ....|
+00000030 2f d6 55 b9 ae 82 ce 2f 2f 07 67 54 5e 02 bd 2f |/.U....//.gT^../|
+00000040 48 f6 fb 3d 9c fa 4f a8 66 15 08 da c0 09 00 00 |H..=..O.f.......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,87 +49,83 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 00 |*............A..|
-00000280 9e 90 3a 3d 00 37 0a c0 43 92 6e bf b4 23 d9 64 |..:=.7..C.n..#.d|
-00000290 99 d2 90 9e eb 88 b6 d6 6f 15 4a 22 72 f0 bf 5e |........o.J"r..^|
-000002a0 72 80 93 90 aa f1 d1 9c 45 c6 6e 3a f8 a9 6f fe |r.......E.n:..o.|
-000002b0 fb 24 dc b1 4d 52 39 91 f5 48 36 06 f6 15 0e 04 |.$..MR9..H6.....|
-000002c0 03 00 8b 30 81 88 02 42 00 a9 54 74 a7 a8 d0 04 |...0...B..Tt....|
-000002d0 ae ef e4 64 38 74 21 e6 18 f0 79 b2 d7 7e 7b 0e |...d8t!...y..~{.|
-000002e0 f6 74 75 52 f0 b8 15 3c 3d 15 52 75 9f 60 03 63 |.tuR...<=.Ru.`.c|
-000002f0 15 b8 1e b8 0e 5c 58 c7 e7 2f 6d 76 c7 c8 42 7a |.....\X../mv..Bz|
-00000300 df 15 26 4b dc 9c 3b 4d b3 b6 02 42 00 a5 fd bf |..&K..;M...B....|
-00000310 a9 5d fc 87 42 24 f9 0b 7a 17 97 7c ee 45 1c 29 |.]..B$..z..|.E.)|
-00000320 3a 07 5f df 4d f2 d3 cb fc a6 fd 84 34 2c 40 84 |:._.M.......4,@.|
-00000330 06 76 bf 43 35 d2 f6 9a 7c d6 1b 5e d8 fd 08 35 |.v.C5...|..^...5|
-00000340 1b 90 0e 24 a7 48 9d 71 ab 4a 11 92 d3 6e 16 03 |...$.H.q.J...n..|
-00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&...@.....|
-00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................|
-00000380 00 |.|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 5d 4e |*............ ]N|
+00000280 0c 9e ad 7b f1 48 0c db 03 96 26 2e 16 87 2c e2 |...{.H....&...,.|
+00000290 ce a2 47 5a 57 30 e8 e1 7e b2 53 5b c6 7b 04 03 |..GZW0..~.S[.{..|
+000002a0 00 8b 30 81 88 02 42 00 e8 8e 68 a8 e3 b5 b4 fe |..0...B...h.....|
+000002b0 b9 91 aa 4f 96 3d 97 8d b2 ef 23 a4 3d 16 db 2b |...O.=....#.=..+|
+000002c0 50 6d 52 cd a5 e7 79 ae 65 10 d6 36 e0 ba c3 6b |PmR...y.e..6...k|
+000002d0 53 61 14 bb 05 47 5a df 26 2f cb 3a 95 c6 6b dc |Sa...GZ.&/.:..k.|
+000002e0 88 fd 2e 22 b5 ef ff 31 0e 02 42 01 be ce 6e 53 |..."...1..B...nS|
+000002f0 42 43 1c 1c d8 83 7f 45 c4 16 ee d2 7b 66 a0 f4 |BC.....E....{f..|
+00000300 f3 14 da 5c 14 e8 fc bc 86 7d 18 43 b9 7b 90 8c |...\.....}.C.{..|
+00000310 af f1 05 95 c6 53 0b 0b 0d 10 a1 e9 bb 89 35 c2 |.....S........5.|
+00000320 b2 e1 d7 dd 99 7c bf 85 19 3c 4e 8e 8f 16 03 03 |.....|...<N.....|
+00000330 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......|
+00000340 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000350 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+00000360 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......|
-00000250 0f 00 00 84 05 01 00 80 20 ef 4b 1c d7 67 37 6e |........ .K..g7n|
-00000260 24 12 9e e9 59 b1 6d da e5 3e 6b 11 03 f4 96 e4 |$...Y.m..>k.....|
-00000270 2e fb 03 e1 13 af 73 4d 15 11 c1 80 e2 ed 11 c6 |......sM........|
-00000280 73 6a 96 ce d1 26 e4 bc fe 71 c9 48 32 fd d8 70 |sj...&...q.H2..p|
-00000290 01 9d 18 7b ed a3 bd 6a 68 df 45 a0 d5 77 79 d2 |...{...jh.E..wy.|
-000002a0 5b e2 8c 96 68 95 46 8d 7d e6 b6 26 fa e1 c4 05 |[...h.F.}..&....|
-000002b0 4c d1 39 4e 35 e3 0c 1b 26 37 2e 0b 9b 0b cf f7 |L.9N5...&7......|
-000002c0 25 c3 da 27 18 70 83 18 49 ff ee ba e3 f8 70 75 |%..'.p..I.....pu|
-000002d0 e8 9b 2d 89 d7 b2 00 a5 14 03 03 00 01 01 16 03 |..-.............|
-000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............|
-000002f0 00 00 00 d3 33 79 85 64 14 07 a6 93 74 f8 f8 55 |....3y.d....t..U|
-00000300 0f fb fc 8e 1b 4c 38 21 b6 61 c5 4b b2 d4 17 b2 |.....L8!.a.K....|
-00000310 c4 be a6 4b d6 3f a3 5f 3c ff 5f 1d 93 a2 c4 82 |...K.?._<._.....|
-00000320 96 90 eb |...|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 98 58 a8 77 3d db 0b |..........X.w=..|
+00000240 04 36 78 51 8b 23 48 fc 70 2b c9 94 1f ee 32 ae |.6xQ.#H.p+....2.|
+00000250 41 c0 42 20 19 51 67 e7 fa c0 fd 15 a1 5f 55 4f |A.B .Qg......_UO|
+00000260 aa be 29 77 f5 47 71 b9 6c 51 89 18 df 25 98 fd |..)w.Gq.lQ...%..|
+00000270 c8 6e ae e3 fd 99 63 ca 2c d2 fb ca bc 57 b7 7f |.n....c.,....W..|
+00000280 a2 90 a6 6f b7 2e b7 2a 52 29 e6 75 57 86 cc b1 |...o...*R).uW...|
+00000290 d8 6c f3 4e 49 ab 4b 66 0a 72 aa ec c2 f7 6e 57 |.l.NI.Kf.r....nW|
+000002a0 15 26 79 1a a4 24 c2 ba 76 9e dd b9 f9 d4 da 1b |.&y..$..v.......|
+000002b0 c9 29 66 eb 64 1b 68 66 66 14 03 03 00 01 01 16 |.)f.d.hff.......|
+000002c0 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 |...@............|
+000002d0 00 00 00 00 70 2b 69 27 05 9a 96 e6 e8 52 ea 0f |....p+i'.....R..|
+000002e0 3a d6 40 b5 e2 89 5b bf aa 95 6c c1 7d 53 09 89 |:.@...[...l.}S..|
+000002f0 23 38 6b 83 85 84 fa f4 2e fb cd b3 57 4e 79 8a |#8k.........WNy.|
+00000300 92 74 03 22 |.t."|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 80 b0 df ff b3 |..........@.....|
-00000010 34 11 03 f5 2d fb c7 c2 38 15 df 41 97 55 0e 1d |4...-...8..A.U..|
-00000020 36 f7 a5 35 5b 63 d7 c5 a6 fd fc a1 91 32 9d cd |6..5[c.......2..|
-00000030 34 66 75 4c 5d 27 ee 89 ed d4 4a ec 67 b0 da e7 |4fuL]'....J.g...|
-00000040 f0 e7 36 eb db b9 22 97 74 30 cd |..6...".t0.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 8f 91 f1 f5 6b |..........@....k|
+00000010 cc 52 9d db 35 1f db b4 64 fe 33 a5 83 08 24 2f |.R..5...d.3...$/|
+00000020 57 18 0e 60 4e 18 54 bb 80 31 37 fe 26 14 b8 c8 |W..`N.T..17.&...|
+00000030 dd c4 8c 07 42 0b 80 0b 41 82 40 f6 9b b8 60 4f |....B...A.@...`O|
+00000040 cb 7b 43 ea 1a 6e 31 8d 9f 82 f7 |.{C..n1....|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 62 24 32 e9 40 38 c8 c3 dd 07 42 |.....b$2.@8....B|
-00000020 05 c8 7c 3d d1 27 68 00 e4 91 6c 2d 08 c1 a1 b6 |..|=.'h...l-....|
-00000030 8a 89 3d 1d c1 15 03 03 00 30 00 00 00 00 00 00 |..=......0......|
-00000040 00 00 00 00 00 00 00 00 00 00 d1 c8 bc cb cb a5 |................|
-00000050 24 1e ad c5 bf 23 92 4b 81 a6 c0 77 19 e0 46 30 |$....#.K...w..F0|
-00000060 48 51 0c cc 39 cd 4b 8d e5 a7 |HQ..9.K...|
+00000010 00 00 00 00 00 70 e7 c8 03 9c e2 58 73 68 ab 9b |.....p.....Xsh..|
+00000020 5c bf 32 57 f8 f1 13 97 02 59 de 99 d3 3e 16 3d |\.2W.....Y...>.=|
+00000030 87 11 d4 b4 63 15 03 03 00 30 00 00 00 00 00 00 |....c....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 9b 99 45 f3 0d f1 |............E...|
+00000050 c5 36 07 8c 81 94 b7 0a dc 7c ee 0c 22 1b 36 fd |.6.......|..".6.|
+00000060 d4 fc 7d f1 98 8b 87 be 5f c6 |..}....._.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
index a0a9640031..76f0c2511b 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -1,122 +1,130 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 60 8e 1c c9 6d |....Q...M..`...m|
-00000010 de 9d 2a dc 6a a6 82 71 9a 3f 8f 5b 18 52 44 4e |..*.j..q.?.[.RDN|
-00000020 4d 72 0d e7 c8 a1 b0 81 64 8c 1f 20 06 a8 17 35 |Mr......d.. ...5|
-00000030 b8 0b 96 52 30 f7 b3 d4 2a 25 94 c0 ba a8 a2 f7 |...R0...*%......|
-00000040 86 5c 18 18 3c 68 3a 71 0f bc 3f 12 00 05 00 00 |.\..<h:q..?.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&...@.......|
-000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 92 93 45 4c f9 |....Y...U....EL.|
+00000010 93 bf ee 78 58 e0 42 b6 df 32 c2 63 6d ec 89 66 |...xX.B..2.cm..f|
+00000020 5a 11 7c 0d 31 2f b5 90 22 ab 3d 20 65 f3 40 c4 |Z.|.1/..".= e.@.|
+00000030 f8 31 fa 80 f3 fb a7 f6 9e dc 0c 94 67 48 d9 2b |.1..........gH.+|
+00000040 cb 94 82 5f 4e 8b 41 5e c6 63 27 da c0 2f 00 00 |..._N.A^.c'../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 66 49 44 2b 04 fe f5 |........ fID+...|
+000002d0 41 68 60 09 81 0e 24 c4 46 68 33 87 41 dd 48 69 |Ah`...$.Fh3.A.Hi|
+000002e0 4c be c8 22 2d 4e ff 80 20 04 01 00 80 30 85 40 |L.."-N.. ....0.@|
+000002f0 30 56 d5 1d 41 14 9d e8 27 39 a2 18 d5 eb 92 27 |0V..A...'9.....'|
+00000300 63 4b 05 85 1a 9e 5f 60 2c 80 a3 20 9f 9c 57 29 |cK...._`,.. ..W)|
+00000310 ba 5f ac 0a aa 89 98 fc ca 8e 37 6b 44 bc 0f 33 |._........7kD..3|
+00000320 5d 47 91 46 55 d4 f9 4f 76 73 51 c4 f6 a9 90 e4 |]G.FU..OvsQ.....|
+00000330 95 10 92 94 f1 33 11 3d 83 0a eb 5d ff e6 9d 9c |.....3.=...]....|
+00000340 19 ec e1 65 11 ad d7 7b 6a a4 f9 d8 b6 0c 53 8a |...e...{j.....S.|
+00000350 16 d5 1f a7 0b 80 6f c5 d8 6a 57 11 2f b1 84 65 |......o..jW./..e|
+00000360 24 8a 02 de aa 10 40 bd 9b 68 a2 b7 b6 16 03 03 |$.....@..h......|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 88 |M.x.N.8FB.......|
-00000290 0f 00 00 84 05 01 00 80 21 58 47 70 c2 2e 1c 4a |........!XGp...J|
-000002a0 fa 97 b2 cf 8d f8 93 f4 b0 8c b3 e0 e7 33 a6 ea |.............3..|
-000002b0 d7 fe 8e 25 e7 f3 f5 a1 8d 09 b7 0b 01 ec a1 15 |...%............|
-000002c0 5b 67 06 53 2a 7d 31 e5 a8 16 bc e3 1d ed 5a 77 |[g.S*}1.......Zw|
-000002d0 0b 78 78 c5 fc c5 62 8e 41 49 d3 ea cd 69 10 3f |.xx...b.AI...i.?|
-000002e0 34 9e 86 df f9 9f f6 02 0c 29 c4 66 a0 45 cf 7b |4........).f.E.{|
-000002f0 ce 51 ec 0a 26 b4 9d 3d 9e 63 5d 40 1a e8 84 4e |.Q..&..=.c]@...N|
-00000300 24 f5 42 48 b5 3e f8 92 c4 f2 e6 5d f4 ad 67 01 |$.BH.>.....]..g.|
-00000310 f8 a7 a7 2b b5 fc be e8 14 03 03 00 01 01 16 03 |...+............|
-00000320 03 00 24 f0 ec 1d f5 39 1c d2 d2 c7 f4 1f 3b 0c |..$....9......;.|
-00000330 cd 25 e4 8e ed c4 bb 02 9d 38 e5 a7 91 e0 ea 00 |.%.......8......|
-00000340 73 a8 9a 63 c9 e7 7d |s..c..}|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 05 9b 97 90 30 0b 21 |.............0.!|
+00000240 ed 52 16 19 e0 54 7d 59 42 17 94 81 9b 2c b6 5b |.R...T}YB....,.[|
+00000250 7f 7c 8e a5 bf 27 a9 25 14 74 f0 37 fa 6e 2b 84 |.|...'.%.t.7.n+.|
+00000260 80 a4 cd ae a6 8a 1b 62 2d 5e 03 ff 70 55 d7 99 |.......b-^..pU..|
+00000270 68 3c b3 0e 03 41 ae af c6 3e 09 d4 16 8e 06 71 |h<...A...>.....q|
+00000280 14 f8 90 97 cd f6 eb 7d 90 3c d1 f3 95 db 35 3c |.......}.<....5<|
+00000290 c9 7d dc 30 55 e1 a0 66 8e 26 20 4f 43 89 08 6f |.}.0U..f.& OC..o|
+000002a0 95 58 42 ae e8 6c b6 77 45 c6 8c c7 ad e5 ed ff |.XB..l.wE.......|
+000002b0 09 6f 2e 7e b0 e4 5c f2 db 14 03 03 00 01 01 16 |.o.~..\.........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 c0 2c cc 32 |...(.........,.2|
+000002d0 78 5e 6c 3e e9 a3 83 65 b4 bb 4e 79 b2 04 08 30 |x^l>...e..Ny...0|
+000002e0 09 e9 04 99 70 48 44 95 26 b0 37 c9 |....pHD.&.7.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 0b c5 7d ca a6 |..........$..}..|
-00000010 87 7f 50 7b 88 9c d9 8e ea 78 a0 40 6b 8e 92 0b |..P{.....x.@k...|
-00000020 78 88 97 46 ec 7c 20 5b 1f fc da 49 d8 6a be |x..F.| [...I.j.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 5f 80 e2 f1 78 |..........(_...x|
+00000010 0f cb 58 5c 3c 50 4c 1e 33 8a 1f b7 89 92 37 11 |..X\<PL.3.....7.|
+00000020 a3 8a 76 39 4a 3d b0 1f a3 e9 ba 52 f8 2b e5 a3 |..v9J=.....R.+..|
+00000030 59 7c ac |Y|.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a 16 25 97 df 98 e4 d6 8e d1 2c 0c |......%.......,.|
-00000010 27 74 67 e5 b7 f1 c7 58 41 5f 04 f5 e4 74 dc 15 |'tg....XA_...t..|
-00000020 03 03 00 16 df 55 01 0d 53 5b b4 36 c7 88 8d b0 |.....U..S[.6....|
-00000030 22 53 ec 87 1b 07 c7 9d af 89 |"S........|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 75 dc 54 |.............u.T|
+00000010 d9 c5 b1 c2 c9 64 9a ea 20 e5 76 61 6c 05 af 33 |.....d.. .val..3|
+00000020 6b bc d7 15 03 03 00 1a 00 00 00 00 00 00 00 02 |k...............|
+00000030 24 6b 03 76 d3 da d0 ee a6 32 c3 58 a1 5e a5 21 |$k.v.....2.X.^.!|
+00000040 b8 3a |.:|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
index c9b5351f45..5d795e791f 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 8a ae 27 5b 39 |....Y...U....'[9|
-00000010 8b c4 a6 d5 fa 9e 67 9e 6c fe 53 ed ab ec e0 04 |......g.l.S.....|
-00000020 8d 7c f8 1f d0 db 2e cb 22 4d a1 20 ee 80 5f fc |.|......"M. .._.|
-00000030 f8 77 8a 23 23 c5 95 81 7f a6 12 f5 e0 19 91 50 |.w.##..........P|
-00000040 da 75 42 c2 eb 45 bf e2 a5 54 ed 6e c0 09 00 00 |.uB..E...T.n....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 c3 2f 08 30 ba |....Y...U.../.0.|
+00000010 5d 9e 55 ef 23 f9 8a 0d 2f b4 25 02 5f c0 d2 c2 |].U.#.../.%._...|
+00000020 50 7c da db a4 ee 7c 18 df af aa 20 f3 a5 02 de |P|....|.... ....|
+00000030 54 9f ce b9 6d 69 66 5d 57 76 ff 18 91 d3 93 ab |T...mif]Wv......|
+00000040 39 13 29 4c b9 a7 3c db 7f 4d 97 fc c0 09 00 00 |9.)L..<..M......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,43 +49,39 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3e |*............A.>|
-00000280 e3 d6 d6 7b d7 ec 6f 4b 88 50 53 26 5a 2b a6 69 |...{..oK.PS&Z+.i|
-00000290 25 6f 30 a7 c3 a5 39 5c e2 ca b6 35 a5 30 35 9a |%o0...9\...5.05.|
-000002a0 35 8f e3 65 bd 4c 47 30 72 9a 4b 32 c4 6d 01 c9 |5..e.LG0r.K2.m..|
-000002b0 a5 91 d1 cd 0b 79 e2 04 0f a9 9c c2 72 cd 58 04 |.....y......r.X.|
-000002c0 03 00 8a 30 81 87 02 41 70 01 8c dd 0a 32 db e3 |...0...Ap....2..|
-000002d0 0b 04 9c d0 64 a1 08 06 b1 cf e3 66 79 1f c0 c1 |....d......fy...|
-000002e0 14 34 87 a6 e5 52 11 20 12 24 a5 b6 c2 50 63 86 |.4...R. .$...Pc.|
-000002f0 31 6a e3 85 7d 19 2d 3b 68 bf b7 64 20 37 c7 f9 |1j..}.-;h..d 7..|
-00000300 76 38 b5 32 84 0b f9 b6 71 02 42 01 89 e3 93 85 |v8.2....q.B.....|
-00000310 d6 16 8e 44 66 72 d6 9f b3 b1 e9 22 ad 2e f8 49 |...Dfr....."...I|
-00000320 41 8f 80 f9 0e d4 fd de 35 67 cf 09 ba 65 f7 a1 |A.......5g...e..|
-00000330 17 a8 c0 b5 a3 cc c0 17 83 af 68 92 5b 5c a9 ce |..........h.[\..|
-00000340 ce 11 92 93 fe 39 b9 80 19 20 f2 b6 3b 16 03 03 |.....9... ..;...|
-00000350 00 04 0e 00 00 00 |......|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 46 07 |*............ F.|
+00000280 78 fd 3b 0c e0 2c 96 f8 44 b9 e9 06 e9 66 17 35 |x.;..,..D....f.5|
+00000290 c0 92 87 51 f6 e3 d7 f5 09 50 56 c6 e9 3b 04 03 |...Q.....PV..;..|
+000002a0 00 8a 30 81 87 02 41 5d 88 4b fe eb 45 ee 5e 9f |..0...A].K..E.^.|
+000002b0 ec 20 90 1f 41 aa 47 87 f7 ae 46 71 dc 55 8b 2c |. ..A.G...Fq.U.,|
+000002c0 ce 70 5f ad 3e fa 3c c3 cb 77 d2 69 67 25 27 08 |.p_.>.<..w.ig%'.|
+000002d0 23 de 52 3c 0e 6c ca 8f 86 8f 61 cd 5b cf d8 42 |#.R<.l....a.[..B|
+000002e0 aa 5a 95 aa 4b d4 d9 f3 02 42 01 81 78 53 9c bd |.Z..K....B..xS..|
+000002f0 af 7e d9 be 26 07 24 11 ca 4b 1d dd 2b 49 ec 35 |.~..&.$..K..+I.5|
+00000300 25 8d 58 87 ad 80 4f 90 c7 f8 a4 b9 c2 75 b5 12 |%.X...O......u..|
+00000310 a7 2c 49 82 76 e8 ce c4 a7 23 68 75 fc 88 82 13 |.,I.v....#hu....|
+00000320 27 55 a7 50 3c d6 d0 ae e3 88 94 b4 16 03 03 00 |'U.P<...........|
+00000330 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
-00000060 00 00 00 00 00 00 39 19 e6 fb c7 28 b4 c9 f5 ba |......9....(....|
-00000070 a2 44 0a 74 70 18 86 1f 5f c2 3d 99 f5 d7 17 04 |.D.tp..._.=.....|
-00000080 88 07 a5 06 01 6a 2c 13 55 0b fc 82 75 b5 24 54 |.....j,.U...u.$T|
-00000090 a0 63 9e f0 ce 92 |.c....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 04 f4 cc a8 9f 48 44 ca 19 e6 4c |..........HD...L|
+00000050 3d 51 f2 29 40 0b 70 06 09 f0 69 5c 51 78 51 1e |=Q.)@.p...i\QxQ.|
+00000060 2b d1 47 22 8d d6 fb f5 41 bd e4 fd 3d f4 1b 48 |+.G"....A...=..H|
+00000070 44 96 2d 97 b9 |D.-..|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 15 37 89 e6 1f |..........@.7...|
-00000010 20 f6 91 b9 1f fb 29 e9 3e 07 ab c2 09 96 06 89 | .....).>.......|
-00000020 69 c2 dd 63 e1 24 5d cd af 08 e2 ed df 46 45 6b |i..c.$]......FEk|
-00000030 1e 9f 62 b6 89 27 04 3f fc f2 77 71 23 04 24 37 |..b..'.?..wq#.$7|
-00000040 74 8a 0a 64 a8 10 e3 1c dc 53 64 |t..d.....Sd|
+00000000 14 03 03 00 01 01 16 03 03 00 40 f1 a2 70 ba 50 |..........@..p.P|
+00000010 9d 7a 9f 8f c6 fb 7e 83 75 bd 94 cf e6 c1 4a f0 |.z....~.u.....J.|
+00000020 e6 54 e9 2c 30 23 a2 5c c2 09 32 d4 06 f7 54 e7 |.T.,0#.\..2...T.|
+00000030 ab 27 a6 66 ab 86 e6 2c 20 12 cf 61 4d ef 12 20 |.'.f..., ..aM.. |
+00000040 ba b6 42 39 b7 76 b9 1b fc f4 44 |..B9.v....D|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 ae 4e e7 3a 25 9d 8f fa 06 99 49 |......N.:%.....I|
-00000020 2e b8 0f 49 d0 54 2d 06 b4 d7 4c 60 51 f1 13 11 |...I.T-...L`Q...|
-00000030 c1 b3 f5 d0 bc 15 03 03 00 30 00 00 00 00 00 00 |.........0......|
-00000040 00 00 00 00 00 00 00 00 00 00 80 de bf db 10 74 |...............t|
-00000050 da 3f d8 77 ca 37 cc f3 96 bd d3 e1 34 9c f2 0a |.?.w.7......4...|
-00000060 70 60 5e 7c a4 7e c9 bd 89 5f |p`^|.~..._|
+00000010 00 00 00 00 00 0b 5b d0 ab 14 3f ae 1f 4b 12 25 |......[...?..K.%|
+00000020 05 2a 67 11 0c 17 42 1b b6 d2 af 16 40 26 fd 7b |.*g...B.....@&.{|
+00000030 d7 57 10 2a f8 15 03 03 00 30 00 00 00 00 00 00 |.W.*.....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 83 54 64 d6 31 32 |...........Td.12|
+00000050 55 62 32 49 b9 54 7b e3 34 02 1c 75 e3 1b 5a 41 |Ub2I.T{.4..u..ZA|
+00000060 a2 cd 47 26 f0 ed c2 d5 41 34 |..G&....A4|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
index 48d822a39c..28a9ef7c65 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 42 ab c5 81 f5 |....Y...U..B....|
-00000010 c0 5b 73 64 f6 1b e0 59 30 b0 fd c5 e6 b3 57 f2 |.[sd...Y0.....W.|
-00000020 28 3f 5c d2 e8 05 7d a8 29 84 2e 20 8e 18 6b 52 |(?\...}.).. ..kR|
-00000030 1b ee 03 02 64 52 fb 24 44 4f 39 f2 d3 0f e6 9d |....dR.$DO9.....|
-00000040 50 31 31 b3 39 9e c1 3a b3 67 41 a0 c0 2b 00 00 |P11.9..:.gA..+..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 72 81 c3 91 37 |....Y...U..r...7|
+00000010 54 37 fb 0f 2b 16 3b 7b bc a6 d9 2e e2 83 23 83 |T7..+.;{......#.|
+00000020 b3 67 cf 36 dc 65 8d a6 3d cb 72 20 ac b9 b9 48 |.g.6.e..=.r ...H|
+00000030 30 9d fe 67 09 39 f5 47 d2 9a c8 3e 22 02 50 5e |0..g.9.G...>".P^|
+00000040 fd 02 c9 ff c1 84 2e 2e ab 78 ef c6 c0 2b 00 00 |.........x...+..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,38 +49,34 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 7a |*............A.z|
-00000280 01 b4 2c 50 85 34 6e 2c 2c 52 bc fa cf 71 82 e5 |..,P.4n,,R...q..|
-00000290 98 8d b0 f1 65 5f 7d bc c8 1b 7c 84 3e 46 45 c5 |....e_}...|.>FE.|
-000002a0 43 0e 72 e1 90 63 40 26 1c 22 dc 9a 3b b8 12 26 |C.r..c@&."..;..&|
-000002b0 a9 d6 1c e1 44 cf c7 38 db 9e 1b d0 b9 bb 06 04 |....D..8........|
-000002c0 03 00 8b 30 81 88 02 42 01 6b af f8 34 ae 89 50 |...0...B.k..4..P|
-000002d0 df 44 20 16 0b f9 ef a9 99 63 39 48 39 08 69 2d |.D ......c9H9.i-|
-000002e0 2d 9d 8b 3a e8 8a 9c 2f e9 d2 85 f2 d3 54 53 ec |-..:.../.....TS.|
-000002f0 b7 18 5b b0 76 3c 38 02 85 cc 00 20 45 9d e7 ba |..[.v<8.... E...|
-00000300 c0 3f c0 b5 1f df 64 42 fd 34 02 42 00 fa e5 dd |.?....dB.4.B....|
-00000310 04 c4 60 60 ff 9b 95 a2 a4 b4 80 87 9f 59 b4 8e |..``.........Y..|
-00000320 72 bf 53 8e 61 b6 df 99 9d 81 05 c5 71 a2 00 cb |r.S.a.......q...|
-00000330 80 bd e5 2a c3 51 d0 45 2f a3 8b 6d 21 6e 6c 80 |...*.Q.E/..m!nl.|
-00000340 4e f1 28 23 6d 76 df 55 77 69 a1 be 39 05 16 03 |N.(#mv.Uwi..9...|
-00000350 03 00 04 0e 00 00 00 |.......|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 b7 1c |*............ ..|
+00000280 2f 05 5e c8 ae 68 6b 54 c5 88 19 cf 7c 04 b2 ed |/.^..hkT....|...|
+00000290 8d 5a e9 7e 6b 50 8a ee 12 66 2d 6f e4 7a 04 03 |.Z.~kP...f-o.z..|
+000002a0 00 8a 30 81 87 02 42 01 8d 7e 23 bc d7 a7 ad 73 |..0...B..~#....s|
+000002b0 5f 45 9e 04 da 6e c0 34 a8 09 59 e3 bc ab 80 e1 |_E...n.4..Y.....|
+000002c0 d4 84 79 7d de 90 c1 f2 ea 95 ed fc 7e d3 f0 31 |..y}........~..1|
+000002d0 4c 9b da 82 a0 97 ed e6 c9 f2 b9 2a 0a 1e 0a 2c |L..........*...,|
+000002e0 7f 1d 62 ea 11 a9 77 5e 2f 02 41 09 88 2b eb 84 |..b...w^/.A..+..|
+000002f0 4f 62 9a c9 8a 0b a2 c6 88 0e 3e d9 29 f0 2b ba |Ob........>.).+.|
+00000300 08 40 b0 9c 17 70 d9 84 1e d3 39 ad 70 fc df 63 |.@...p....9.p..c|
+00000310 a0 f6 69 3c 19 ce 0b a5 95 d2 6a b1 46 b1 e5 ba |..i<......j.F...|
+00000320 fd d2 67 4b 76 e3 eb b9 21 d0 7c 85 16 03 03 00 |..gKv...!.|.....|
+00000330 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 94 ba |.....(..........|
-00000060 0a c6 38 6b 65 60 95 5e df fc 42 7e ac 9f 5a 25 |..8ke`.^..B~..Z%|
-00000070 39 0e a9 7a 61 b3 17 80 77 82 e5 80 0a af |9..za...w.....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 32 49 7e |....(........2I~|
+00000040 8f d6 2e 81 d7 03 a6 61 a3 04 98 81 95 84 58 d1 |.......a......X.|
+00000050 a2 33 fe 4a 5d cd 96 76 64 1e 1a 62 03 |.3.J]..vd..b.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 ef 8d ac 17 6f |..........(....o|
-00000010 88 03 88 8f f3 d5 a0 60 28 a9 4d e8 20 ae 0c 21 |.......`(.M. ..!|
-00000020 fd d1 50 9b c3 d1 e9 cd 27 ed d7 8b 92 60 49 47 |..P.....'....`IG|
-00000030 ed 9a 74 |..t|
+00000000 14 03 03 00 01 01 16 03 03 00 28 28 14 2d ae 7c |..........((.-.||
+00000010 b8 7d dc 27 b2 18 39 57 c8 be 5c 3d a3 ab fa 5a |.}.'..9W..\=...Z|
+00000020 3d 55 1b 3d 31 77 95 af 42 86 af 2b e7 5a 98 40 |=U.=1w..B..+.Z.@|
+00000030 18 77 d1 |.w.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 1d 4f 3c |..............O<|
-00000010 c5 d1 39 01 46 ab 7d d1 75 59 e7 f5 cd fa 02 0b |..9.F.}.uY......|
-00000020 dd 02 17 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 e9 a5 d5 0c 05 2a 82 fe a5 6c 03 6e d0 c4 7d cb |.....*...l.n..}.|
-00000040 32 f3 |2.|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 30 50 2f |.............0P/|
+00000010 36 4a 7c ee e6 f0 b9 b8 bf 4d e3 63 4d 5e 58 08 |6J|......M.cM^X.|
+00000020 ac ac 82 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 80 e2 42 ca 91 65 04 4e ca a8 6f 81 7c 30 c0 1f |..B..e.N..o.|0..|
+00000040 aa 7b |.{|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
new file mode 100644
index 0000000000..831fa2101f
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 be c0 b6 d7 fe |....Y...U.......|
+00000010 43 9d 21 1f 89 27 bd db 0a 9a 5a 44 dd 79 d1 f2 |C.!..'....ZD.y..|
+00000020 18 9a 2a 04 8c eb e6 a9 93 ef ee 20 35 48 44 08 |..*........ 5HD.|
+00000030 8c 7a 3e f6 0f d7 5f 33 54 60 0b c9 65 4e 17 8d |.z>..._3T`..eN..|
+00000040 d2 69 b7 20 0b c5 ba 9a d4 b7 40 39 c0 23 00 00 |.i. ......@9.#..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 0e 53 |*............ .S|
+00000280 82 54 1a ba f8 a4 52 1d 6d b8 70 18 41 e8 67 f9 |.T....R.m.p.A.g.|
+00000290 38 1e fb fa b8 89 2d d6 4d 1b ae 67 fe 75 04 03 |8.....-.M..g.u..|
+000002a0 00 8b 30 81 88 02 42 01 68 0e d4 92 a6 1a d9 66 |..0...B.h......f|
+000002b0 ff 0e ca 4c 32 b8 78 d3 52 d1 ad a2 32 83 f0 3c |...L2.x.R...2..<|
+000002c0 43 e0 7e 92 94 e9 c6 99 00 d9 f7 06 c0 2c 72 c0 |C.~..........,r.|
+000002d0 9b f7 c0 ec 1f 23 8f b5 e5 74 9d ff 89 17 12 b4 |.....#...t......|
+000002e0 f1 f5 25 f7 2e 0d 78 f6 1c 02 42 01 fc da dd c8 |..%...x...B.....|
+000002f0 65 30 67 a3 ff 42 e3 37 19 ba 7c 04 6b a1 b3 97 |e0g..B.7..|.k...|
+00000300 b0 ca 8c 2d fc b0 40 1c a1 d8 c9 64 fe df 48 3b |...-..@....d..H;|
+00000310 07 57 1f 81 a2 3e a4 84 96 00 fb 55 29 1c 94 9d |.W...>.....U)...|
+00000320 f9 0d a4 71 4f 5f fd c3 22 e2 88 07 21 16 03 03 |...qO_.."...!...|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 7c e9 97 4b 98 8a 4c 59 95 3e 31 |.....|..K..LY.>1|
+00000050 c4 b6 e2 79 10 de bc 8e aa 1e 52 07 b2 e1 52 bc |...y......R...R.|
+00000060 3b da 8d 5f 12 6a 18 d1 0a 5d 93 1c ad bb f9 b7 |;.._.j...]......|
+00000070 6b 58 49 39 ea 3a 9e 20 47 69 43 b4 b4 d8 16 d0 |kXI9.:. GiC.....|
+00000080 f0 9d 36 74 04 |..6t.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 60 d5 ac 39 b6 |..........P`..9.|
+00000010 58 50 03 90 9f c9 78 f1 45 43 b1 34 bd c8 29 65 |XP....x.EC.4..)e|
+00000020 54 38 7a 88 46 15 e8 a4 fb 9d 80 4e d6 45 e1 8d |T8z.F......N.E..|
+00000030 27 d6 09 66 1d ee 46 6d dd 8e 89 34 0f 4a fb fd |'..f..Fm...4.J..|
+00000040 bc 85 08 07 f0 5b 1c 24 e2 11 1b e2 a4 94 f5 80 |.....[.$........|
+00000050 fa 47 f4 62 0e b9 1c 31 cb 7b bf |.G.b...1.{.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 37 b7 23 a2 06 97 f3 60 9a f0 7e |.....7.#....`..~|
+00000020 b7 11 6d 0d 66 0e db 38 1a eb cd 72 80 c8 54 ef |..m.f..8...r..T.|
+00000030 cf 90 6d 22 68 41 63 03 46 b9 28 4f 2f d6 fe fa |..m"hAc.F.(O/...|
+00000040 b2 91 07 36 71 15 03 03 00 40 00 00 00 00 00 00 |...6q....@......|
+00000050 00 00 00 00 00 00 00 00 00 00 ca 17 d9 fd 1a 0e |................|
+00000060 21 db a4 92 dc 92 e8 89 9d 14 6b 8a d3 ee a7 95 |!.........k.....|
+00000070 c0 91 8d 3c af 5a 48 d5 c6 2f 66 b8 b8 d4 ce f9 |...<.ZH../f.....|
+00000080 59 e5 e0 e2 df e5 7e ea 94 03 |Y.....~...|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
index 2a16651136..c22edd05e0 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 ed 6d 5a 1c 89 |....Y...U...mZ..|
-00000010 a4 f3 35 0b e4 74 7e e2 05 a5 36 4d 4a 55 b3 7c |..5..t~...6MJU.||
-00000020 a1 a6 42 a3 fc 35 8c e0 97 5b 4b 20 a1 4a 06 28 |..B..5...[K .J.(|
-00000030 4d 40 0b fc 47 d5 4d 9b d5 43 b0 0d 0d c6 ae 30 |M@..G.M..C.....0|
-00000040 79 59 00 d4 90 96 98 92 d2 3a 57 07 c0 2c 00 00 |yY.......:W..,..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 e6 0e 27 a7 58 |....Y...U....'.X|
+00000010 1d a3 1d 1d 21 64 31 f6 1e bc 28 b4 46 7e 26 be |....!d1...(.F~&.|
+00000020 de 0a 65 eb f0 18 dc 7f 3e 1b 55 20 fe 66 50 20 |..e.....>.U .fP |
+00000030 f0 f0 48 a8 db 0a ff ee 60 ea 3d 7f 07 5e b9 65 |..H.....`.=..^.e|
+00000040 c3 e4 2a 19 9c bd 57 36 ca e3 a7 2d c0 2c 00 00 |..*...W6...-.,..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,38 +49,34 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 89 |*............A..|
-00000280 e6 6d 6a 56 3e e5 4e 72 df 2b 41 11 de a0 c0 3e |.mjV>.Nr.+A....>|
-00000290 22 04 9a b5 a8 d6 22 30 2a e5 bd 83 1c 7a 8e 6c |"....."0*....z.l|
-000002a0 93 ab 8f d7 64 9e fe 89 c0 da 9a 45 7d 76 91 69 |....d......E}v.i|
-000002b0 0a 11 c5 59 26 49 ec 69 99 b3 91 a5 4b 2b 89 04 |...Y&I.i....K+..|
-000002c0 03 00 8a 30 81 87 02 42 01 17 1d ff 9a 99 76 20 |...0...B......v |
-000002d0 13 8a e1 5a a8 04 8a 1e 84 57 fd b0 95 c1 6c af |...Z.....W....l.|
-000002e0 b2 66 13 b5 75 36 ce 86 69 67 3d dc 82 2f 06 57 |.f..u6..ig=../.W|
-000002f0 19 14 56 54 0e 8e 04 74 0b 73 49 61 92 8e d1 9a |..VT...t.sIa....|
-00000300 b5 60 7f 65 a8 f8 99 eb ac 56 02 41 57 a3 78 57 |.`.e.....V.AW.xW|
-00000310 8a dd fa 9c 3d 24 a0 f2 0a 74 1a 8a 8f 6c 82 55 |....=$...t...l.U|
-00000320 4c cd d8 5d 79 99 87 93 41 e7 78 f4 28 0d ef 63 |L..]y...A.x.(..c|
-00000330 fb da 8e 93 86 31 6e 3e ca 6f 6b 1b fd 7a a3 86 |.....1n>.ok..z..|
-00000340 6e bb 17 35 90 d9 a4 df 12 d0 54 5e 25 16 03 03 |n..5......T^%...|
-00000350 00 04 0e 00 00 00 |......|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 17 21 |*............ .!|
+00000280 a9 b8 65 8b aa 41 d2 d1 45 45 e5 ce 39 60 54 b6 |..e..A..EE..9`T.|
+00000290 43 9f c4 19 a4 aa ec 71 08 b0 d1 22 f7 46 04 03 |C......q...".F..|
+000002a0 00 8b 30 81 88 02 42 00 8b a5 d9 d3 8f a1 72 48 |..0...B.......rH|
+000002b0 06 42 25 c3 f6 c8 46 8d 88 30 36 7d d8 18 a9 cc |.B%...F..06}....|
+000002c0 de e4 c8 3f e9 d2 f0 88 18 cc c6 fb 14 e0 05 b1 |...?............|
+000002d0 ec 50 3d 57 b4 e9 83 57 55 4b 0d 2c 89 69 ff b1 |.P=W...WUK.,.i..|
+000002e0 58 0b 01 89 48 97 ee 88 7e 02 42 01 e1 6f 9c 36 |X...H...~.B..o.6|
+000002f0 6a 6c 86 24 d6 b3 45 f1 6c 03 d8 fd da d8 cc 52 |jl.$..E.l......R|
+00000300 04 41 7a c5 f9 b5 91 a5 6c d8 5a 03 ad de e3 da |.Az.....l.Z.....|
+00000310 de f8 db b0 bc 75 38 03 ab 84 ac 3f b2 c2 7e 6d |.....u8....?..~m|
+00000320 a7 2e c0 d9 bd 85 e2 7b 36 11 2b 12 14 16 03 03 |.......{6.+.....|
+00000330 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 9d e7 |.....(..........|
-00000060 31 2a 0a 46 84 fd d9 18 c2 b0 b1 31 eb 63 4d 2d |1*.F.......1.cM-|
-00000070 ee 17 59 e6 b4 0f c6 d8 3d 8c e9 57 83 a8 |..Y.....=..W..|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 4b a3 cc |....(........K..|
+00000040 a1 5b 04 d4 1e 6c 2c 26 56 23 62 50 bc d6 90 0b |.[...l,&V#bP....|
+00000050 67 41 d9 7c 79 a5 53 54 73 0a 93 e2 73 |gA.|y.STs...s|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 e0 85 25 02 b4 |..........(..%..|
-00000010 86 32 57 70 3c 7e 6b e5 75 e0 3a 43 c8 c2 fe f8 |.2Wp<~k.u.:C....|
-00000020 2e 04 fe 73 e4 7b 2c 9a e0 65 2e d6 53 ae f1 19 |...s.{,..e..S...|
-00000030 dd 6f 1a |.o.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 e3 19 7b 8c 8a |..........(..{..|
+00000010 52 35 82 cc 70 50 83 22 88 8b 0a 54 bc eb ff 57 |R5..pP."...T...W|
+00000020 2c df 0d 50 d6 21 2f d2 d9 e8 15 27 b9 d7 01 a3 |,..P.!/....'....|
+00000030 f2 62 0b |.b.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 29 b2 e6 |.............)..|
-00000010 c3 2e 72 ba cc ac d9 3b c7 0c 1d 53 b2 30 39 71 |..r....;...S.09q|
-00000020 6e dd 79 15 03 03 00 1a 00 00 00 00 00 00 00 02 |n.y.............|
-00000030 88 c9 92 fe 6c 1f 6c fd bd 7b fb 0a 8a b5 cc c9 |....l.l..{......|
-00000040 94 90 |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 cc cf 92 |................|
+00000010 4d 25 58 96 1d dc df fb d9 1f a5 49 87 45 dd 73 |M%X........I.E.s|
+00000020 1a 17 ae 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 fb b5 c5 e4 aa ea e7 7e ff dd f7 11 63 c0 e4 a3 |.......~....c...|
+00000040 86 fc |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
new file mode 100644
index 0000000000..61e665721a
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
@@ -0,0 +1,77 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 02 cc a9 |................|
+00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............|
+00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................|
+00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 d6 47 27 38 fc |....Y...U...G'8.|
+00000010 16 92 2c 1f a6 53 a9 31 85 65 a7 83 0a 8f cb 4d |..,..S.1.e.....M|
+00000020 7d 5b df c1 2e b9 b1 08 e3 b9 96 20 16 0c e5 07 |}[......... ....|
+00000030 27 cc 4f 7d 11 ef 1a 14 c6 42 bf e9 c1 b7 a5 89 |'.O}.....B......|
+00000040 ca 2b 4c 30 4f c7 c8 10 13 b0 b1 6b cc a9 00 00 |.+L0O......k....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 69 78 |*............ ix|
+00000280 7b e5 14 95 c8 d1 3c 7e c2 d7 38 33 c3 9f 8f dc |{.....<~..83....|
+00000290 25 8d 89 8a 99 a4 e4 8b 40 17 fc 80 43 67 04 03 |%.......@...Cg..|
+000002a0 00 8b 30 81 88 02 42 01 32 a8 dd d9 ec 11 d2 f2 |..0...B.2.......|
+000002b0 6d 86 da 31 00 8c bf ed 81 1d 8c c8 23 87 98 f7 |m..1........#...|
+000002c0 25 0c 1b 3d 9f 07 80 11 bc 07 b1 15 5f 3a 81 0e |%..=........_:..|
+000002d0 59 04 e8 09 be ea 21 97 34 a9 8a 2f ef 3a 47 ad |Y.....!.4../.:G.|
+000002e0 3b f9 9d f3 b8 b8 9a 93 03 02 42 01 bc 88 6b 99 |;.........B...k.|
+000002f0 d7 7a df de 5a 75 53 b0 3c 4c 1d 8b 15 c5 a7 9d |.z..ZuS.<L......|
+00000300 3d 00 c0 f7 19 47 88 30 00 29 24 80 23 45 88 2e |=....G.0.)$.#E..|
+00000310 11 60 3e 4b 6a 41 ad dc 3d 7d 3f 59 a0 0e fd d6 |.`>KjA..=}?Y....|
+00000320 f7 c7 7f 63 49 2f e4 4e d9 8f 2d e5 98 16 03 03 |...cI/.N..-.....|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 7c 89 36 36 77 8c 09 31 e4 48 01 |.... |.66w..1.H.|
+00000040 6f 08 27 a8 bb 1b 1c a6 0c 09 ec 0b f6 a3 be bd |o.'.............|
+00000050 76 70 fb f8 e5 |vp...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 a0 db 6c df b1 |.......... ..l..|
+00000010 87 77 78 ad 22 b2 98 77 e8 57 aa 13 a8 98 35 63 |.wx."..w.W....5c|
+00000020 00 c5 13 b9 88 5d ca bf bc c5 c3 |.....].....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 16 00 c8 c6 25 ae 11 9d a5 10 75 |.........%.....u|
+00000010 e4 4c e3 69 12 2b d9 9e 8e 40 88 15 03 03 00 12 |.L.i.+...@......|
+00000020 cf ab ac d4 c4 8e 9c 92 c4 2f 1f c6 96 0b 36 c9 |........./....6.|
+00000030 f5 22 |."|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
index 29767b7b93..45728cfbe7 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -1,95 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 2a 6a a8 b3 97 |....Y...U..*j...|
-00000010 d5 c8 5e b4 22 7e d0 a5 c7 46 af 89 60 44 77 5e |..^."~...F..`Dw^|
-00000020 1a f8 3a 30 08 6d 5f 4c 61 36 c5 20 57 79 91 3e |..:0.m_La6. Wy.>|
-00000030 1f 40 d1 f1 33 d7 a9 fb 93 eb 16 0d e1 39 e3 a3 |.@..3........9..|
-00000040 80 e3 4f 58 a6 f8 a4 be 19 dd ef ee c0 13 00 00 |..OX............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 2f 51 e0 81 eb |....Y...U../Q...|
+00000010 d2 db 4f 22 fa 11 d2 56 f3 06 d6 a0 97 d2 f3 74 |..O"...V.......t|
+00000020 fc a9 a7 73 ba a8 ee f2 05 89 15 20 0f 96 70 60 |...s....... ..p`|
+00000030 6f 78 aa 56 fa 92 5e e3 bc e7 f0 40 00 48 8b 84 |ox.V..^....@.H..|
+00000040 57 b8 49 e9 f9 00 99 ff 73 29 f6 e7 c0 13 00 00 |W.I.....s)......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 8e c8 e8 42 7c 8a 01 c2 ff 01 cb 0b e1 20 |A....B|........ |
-000002f0 50 42 d4 3a 1b 34 ff 74 59 81 2f a2 0e 29 b2 f9 |PB.:.4.tY./..)..|
-00000300 47 cf 0d 08 97 cf aa 9f fe f0 7f e8 f4 fd 3a fa |G.............:.|
-00000310 a6 b6 47 32 d3 25 78 87 bf 77 cc 12 37 02 6a ad |..G2.%x..w..7.j.|
-00000320 cf 2c 04 01 00 80 13 a1 95 17 7b 21 86 7f f2 02 |.,........{!....|
-00000330 9f ed 88 2d 1f 2c 38 96 bc fa 5a 39 85 4b 9f ff |...-.,8...Z9.K..|
-00000340 5c 7a 02 1e 5f c9 4a 69 51 d3 83 34 9f dc 8c 39 |\z.._.JiQ..4...9|
-00000350 fe 81 76 fc c3 59 ff e2 a8 81 ca 6f f6 52 c9 44 |..v..Y.....o.R.D|
-00000360 a0 3f 5e 5e 92 20 db d9 2e 0b e3 ab 75 e7 79 f6 |.?^^. ......u.y.|
-00000370 b2 73 17 e1 94 1e 12 62 e9 b0 0f 04 e7 5d 83 ac |.s.....b.....]..|
-00000380 71 ca a5 62 40 dd 69 b1 3f cf bb 3d c7 3e 51 6c |q..b@.i.?..=.>Ql|
-00000390 11 f2 cf 39 f1 b5 72 bd 52 d4 3d 3c c0 90 34 c8 |...9..r.R.=<..4.|
-000003a0 4b 22 55 39 1c 2b 16 03 03 00 04 0e 00 00 00 |K"U9.+.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 48 77 87 3e 04 c9 14 |........ Hw.>...|
+000002d0 56 9d 1b 41 4b d0 eb 65 8d 56 56 97 fd 73 97 cd |V..AK..e.VV..s..|
+000002e0 c6 88 8f 8e 79 99 09 65 53 04 01 00 80 98 c2 ff |....y..eS.......|
+000002f0 49 aa 41 ce 0e 7b 03 99 39 c0 b5 ac 72 16 1c 5e |I.A..{..9...r..^|
+00000300 a0 92 f1 07 0c 93 dc f6 25 2b 5c be e3 65 41 a9 |........%+\..eA.|
+00000310 1e 57 6d 9f 28 50 ca 87 2f c7 b0 15 2e 15 d2 cc |.Wm.(P../.......|
+00000320 4d 0e 42 4c 0a 01 4d 1b 9c d1 17 e7 22 9a 6a a9 |M.BL..M.....".j.|
+00000330 27 0b 7a a7 32 e3 c7 5a d1 7f f2 1c 45 61 91 a8 |'.z.2..Z....Ea..|
+00000340 e0 e0 49 de b7 2f a6 89 63 94 ed 0e 63 15 6b 4f |..I../..c...c.kO|
+00000350 fb 62 c4 35 cb 98 89 c2 d1 bc f6 e2 2d 8f 9f 72 |.b.5........-..r|
+00000360 56 79 50 5f cd 73 00 f1 65 bf a4 3f 87 16 03 03 |VyP_.s..e..?....|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
-00000060 00 00 00 00 00 00 a2 6e de ea 78 0c 4d 20 ad 1f |.......n..x.M ..|
-00000070 1a f5 6b 15 09 f1 50 bb cd 40 0e c7 d9 ed 7f e1 |..k...P..@......|
-00000080 4b bc d3 26 5d 89 b7 26 c5 6c 0e 59 6f 84 51 5d |K..&]..&.l.Yo.Q]|
-00000090 2f 75 d8 0f 2e e8 |/u....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 93 4b 37 8d 57 43 52 77 56 d2 af |......K7.WCRwV..|
+00000050 7c 56 d0 bf 1e 7b 29 55 3e b7 d0 1c 02 2e 0d de ||V...{)U>.......|
+00000060 09 66 f2 98 21 57 ab d2 d2 4a 73 c1 c5 fe f1 b8 |.f..!W...Js.....|
+00000070 95 d3 fc 70 ce |...p.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 dd d8 e7 63 89 |..........@...c.|
-00000010 8e cc 3e e0 df 6d 5a 42 b3 49 1b 66 e8 79 e9 f0 |..>..mZB.I.f.y..|
-00000020 8a c3 0e 5e d7 01 ac 04 81 6a e1 60 14 60 b9 a6 |...^.....j.`.`..|
-00000030 4c a5 46 43 74 df 30 1e f8 74 77 4c b5 42 e5 25 |L.FCt.0..twL.B.%|
-00000040 81 9d b1 04 bc 02 46 bd b1 55 d0 |......F..U.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 b3 e1 81 3e 0a |..........@...>.|
+00000010 f8 f3 c6 05 c1 09 f5 73 01 eb 18 1a 05 fa 2f 9b |.......s....../.|
+00000020 b2 bc c7 44 23 38 ed b9 99 a0 56 7d 8b e4 a5 4b |...D#8....V}...K|
+00000030 f1 89 45 bc 95 ea 06 a8 48 de 07 bf d5 cb 53 bc |..E.....H.....S.|
+00000040 50 fa 25 fb d5 79 17 ec 4d be 3d |P.%..y..M.=|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 35 49 6d a7 3f a1 39 5d 37 8d 2e |.....5Im.?.9]7..|
-00000020 c5 1e 90 3b f9 60 58 d3 47 e3 db 73 8b aa 6c 9e |...;.`X.G..s..l.|
-00000030 b5 82 55 09 62 15 03 03 00 30 00 00 00 00 00 00 |..U.b....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 71 b3 7b c7 d4 27 |..........q.{..'|
-00000050 f9 77 7f d0 80 25 1b 43 d0 0e 92 38 8c f3 2f 50 |.w...%.C...8../P|
-00000060 eb 96 22 fb e6 09 45 ec 7f 16 |.."...E...|
+00000010 00 00 00 00 00 3e 90 61 a4 f1 53 ac 7b b2 9f 4e |.....>.a..S.{..N|
+00000020 2c 16 5a 77 8b da 5d 68 5c 8b a8 6d 44 52 f3 ad |,.Zw..]h\..mDR..|
+00000030 8e ba c8 89 2f 15 03 03 00 30 00 00 00 00 00 00 |..../....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 e5 01 5d ef 4c 0c |............].L.|
+00000050 07 8f 21 99 60 83 ee 36 13 8e 25 15 32 85 a5 96 |..!.`..6..%.2...|
+00000060 36 90 60 49 4f c7 54 99 dd 76 |6.`IO.T..v|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
new file mode 100644
index 0000000000..6b02249f3f
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 ab d3 05 5e d0 |....Y...U.....^.|
+00000010 80 0b 87 e9 43 26 e2 c9 28 04 3f eb 68 05 54 3d |....C&..(.?.h.T=|
+00000020 9b 28 d0 4e d4 d9 25 e5 b0 27 2b 20 89 27 da d5 |.(.N..%..'+ .'..|
+00000030 3d 19 38 63 01 34 f6 43 1b a9 f7 09 12 7d 27 e1 |=.8c.4.C.....}'.|
+00000040 f6 23 b8 39 24 8b 1e c7 a3 2f 07 16 c0 27 00 00 |.#.9$..../...'..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 ec 71 cc fb 07 bd 0f |........ .q.....|
+000002d0 6b e0 e1 27 7f 62 59 06 09 3c 09 bc b1 c9 09 93 |k..'.bY..<......|
+000002e0 e9 b0 a4 5b f3 be 14 d1 3c 04 01 00 80 a9 c7 98 |...[....<.......|
+000002f0 ea ac 6a 9b 49 7c 72 45 4d 5c c8 4c d6 56 64 1b |..j.I|rEM\.L.Vd.|
+00000300 44 7f 13 4f 2a ed e9 6b c7 c0 a2 25 3b 7a 99 f4 |D..O*..k...%;z..|
+00000310 93 84 35 78 72 21 ca f6 29 1b 60 d7 f6 bd 31 5b |..5xr!..).`...1[|
+00000320 7a fb 57 20 30 cc e6 90 07 b2 0e 08 82 86 56 a7 |z.W 0.........V.|
+00000330 55 00 fd f4 ce f4 b1 74 27 e9 0a 28 1c bc 56 47 |U......t'..(..VG|
+00000340 f7 18 3e 9e 9c 45 2d 1d 82 a8 66 51 27 25 be ec |..>..E-...fQ'%..|
+00000350 cd 9e 83 89 7e e0 e3 0f 3b 7b 32 f2 26 7b 30 c8 |....~...;{2.&{0.|
+00000360 c1 e3 7b 4c f4 14 d5 51 ea b7 45 7a 59 16 03 03 |..{L...Q..EzY...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 76 d8 c4 58 a1 94 11 ab 19 4c 7b |.....v..X.....L{|
+00000050 7c 34 d1 b6 8b 7f a2 96 41 e6 e9 98 d8 55 62 2b ||4......A....Ub+|
+00000060 56 54 2a 65 25 f0 fa 15 ac cb b7 cc 3b 59 8b 99 |VT*e%.......;Y..|
+00000070 e9 be 9e fe 56 97 07 ae 39 38 a7 f4 f0 d0 e9 f5 |....V...98......|
+00000080 33 de 20 a6 04 |3. ..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 8c 0f 2a be cd |..........P..*..|
+00000010 30 f7 46 cf 58 5b 38 88 86 5e d1 33 b1 61 d6 95 |0.F.X[8..^.3.a..|
+00000020 13 c7 e7 f2 fb bc 37 e5 a3 db ac a7 74 49 00 89 |......7.....tI..|
+00000030 db 94 25 aa 00 b6 b2 34 0a dd 97 bf fa cf 33 6e |..%....4......3n|
+00000040 6e f7 ab bf 70 a6 85 91 9b 4f f2 86 15 83 60 0d |n...p....O....`.|
+00000050 79 9e 11 51 17 a6 6f 06 2f 98 bc |y..Q..o./..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 c3 c9 23 7b bd 57 1a 29 5f ac f6 |.......#{.W.)_..|
+00000020 8d bb 90 bb 48 8a 9a 75 65 3b 5b 52 c0 ee 0e 24 |....H..ue;[R...$|
+00000030 43 f6 62 1f 1e 51 36 4e 3e a3 e4 96 d8 2b d8 a7 |C.b..Q6N>....+..|
+00000040 d0 18 97 d7 1e 15 03 03 00 40 00 00 00 00 00 00 |.........@......|
+00000050 00 00 00 00 00 00 00 00 00 00 c0 c8 9f 7d df b1 |.............}..|
+00000060 78 72 b5 3d 0d 3e d9 88 38 c2 42 eb 2b 4d e0 b3 |xr.=.>..8.B.+M..|
+00000070 d7 69 19 31 57 16 7c 0a bb 24 5b 9c 9b c2 4b b9 |.i.1W.|..$[...K.|
+00000080 55 ef ad 2c c1 eb 9b 59 06 5a |U..,...Y.Z|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
new file mode 100644
index 0000000000..64f999a05a
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 02 cc a8 |................|
+00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............|
+00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................|
+00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 45 f5 61 06 a8 |....Y...U..E.a..|
+00000010 4e ce c0 32 d6 af fb 12 5e c8 6c 06 ac c9 d7 e4 |N..2....^.l.....|
+00000020 02 49 09 b9 42 ee ae fa e4 52 18 20 12 3a 53 7d |.I..B....R. .:S}|
+00000030 11 cf 13 13 a3 f8 42 c3 98 bb bc a6 10 3e f4 13 |......B......>..|
+00000040 a5 a2 fd ef aa b3 01 3c cb 8a 3a 2c cc a8 00 00 |.......<..:,....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 57 53 06 53 e5 14 06 |........ WS.S...|
+000002d0 df 26 9d 3a 06 dc a9 d5 49 d3 3f 5f 7b c2 ab 77 |.&.:....I.?_{..w|
+000002e0 fd a1 fe 28 dc 54 36 06 22 04 01 00 80 da 23 f5 |...(.T6.".....#.|
+000002f0 19 de e8 d2 a9 79 b8 37 3d c0 8c ae f6 7c d5 d9 |.....y.7=....|..|
+00000300 87 ab 6b 3f 76 7c 5f 94 be 11 55 a3 78 66 1e e3 |..k?v|_...U.xf..|
+00000310 f3 11 3d 1a f7 02 26 a4 a6 cd 7c fe 87 0d 68 a1 |..=...&...|...h.|
+00000320 50 e8 7e 94 41 bd 5b 74 d0 6d 3b 6c ef ee 88 2d |P.~.A.[t.m;l...-|
+00000330 60 0a a9 53 cf 1f f4 03 a3 54 e5 91 36 50 62 54 |`..S.....T..6PbT|
+00000340 5f e6 e5 36 63 58 ba 7b bb 3a 79 59 58 08 a8 f2 |_..6cX.{.:yYX...|
+00000350 f5 1e 35 f8 f5 0f 7f 19 e7 7f 5f 56 e2 50 6d 8c |..5......._V.Pm.|
+00000360 da 45 70 60 0d 58 32 94 e7 a0 f7 da 93 16 03 03 |.Ep`.X2.........|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 9d 2f a6 b7 21 56 ad 38 a8 31 20 |.... ./..!V.8.1 |
+00000040 0b 2e dc 3f 8a 34 64 de 81 0e d3 a5 b1 c1 fc 05 |...?.4d.........|
+00000050 18 d9 3e 77 35 |..>w5|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 a8 82 60 8a ef |.......... ..`..|
+00000010 31 55 42 e9 1d 33 0e d8 a9 b1 43 85 1c 04 7b 20 |1UB..3....C...{ |
+00000020 81 df 03 e9 fd c0 f7 32 b9 b3 31 |.......2..1|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 ef 72 f7 1b 26 1a 47 99 f9 4c e7 |......r..&.G..L.|
+00000010 be 8e ab c5 8e ea 8c c6 60 6c 10 15 03 03 00 12 |........`l......|
+00000020 2c f4 39 e3 3a 74 a4 3c 72 63 77 e8 82 cf a9 e2 |,.9.:t.<rcw.....|
+00000030 2b 04 |+.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
index ffdc3284b8..74282d4b1a 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 79 8f 56 ac 75 |....Q...M..y.V.u|
-00000010 4f a9 fc 2c b9 53 82 a6 b4 c8 0d 4e 50 9a 9e aa |O..,.S.....NP...|
-00000020 8d ed 21 21 91 5d a2 cc 99 1b 68 20 0c e7 35 50 |..!!.]....h ..5P|
-00000030 67 02 70 2a 45 0d 6c 4c 46 df 75 dc 5f 6e 2f 79 |g.p*E.lLF.u._n/y|
-00000040 03 26 da 45 53 25 50 23 c0 85 3b 8c 00 05 00 00 |.&.ES%P#..;.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 ac bf 85 b8 5f |....Q...M......_|
+00000010 56 44 a0 c5 3b 20 77 71 af de 34 bc 79 a0 a4 a7 |VD..; wq..4.y...|
+00000020 fa 2e cf b5 ee c5 a7 a2 5e 11 48 20 05 89 5e a6 |........^.H ..^.|
+00000030 cd ad 91 e4 be c3 c3 6c 6a 0e 1d ab 27 03 5e 0f |.......lj...'.^.|
+00000040 05 9d ef b0 63 8d 2d b6 29 08 66 e3 00 05 00 00 |....c.-.).f.....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 24 72 bd b1 13 05 73 26 c0 0b ec |.....$r....s&...|
-000000a0 e6 39 08 6a 2d 87 00 51 58 9d e3 8d da be 60 98 |.9.j-..QX.....`.|
-000000b0 0a ee 0c 96 13 f4 e5 30 90 85 |.......0..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 24 e1 ef 77 60 cf 7a 44 79 74 59 |.....$..w`.zDytY|
+000000a0 ff 81 72 b9 b5 f5 97 af 60 59 78 f5 01 49 2d bb |..r.....`Yx..I-.|
+000000b0 4a ec 98 1f f5 31 f4 00 a2 f3 |J....1....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 d4 ad ab a0 01 |..........$.....|
-00000010 1b 87 9c aa c4 27 08 b5 8c 4a 7f fc 03 df a6 d6 |.....'...J......|
-00000020 f8 6c d1 61 7c d3 1f 6d 18 c3 8d 88 5c 7b cf |.l.a|..m....\{.|
+00000000 14 03 03 00 01 01 16 03 03 00 24 52 fd a3 51 aa |..........$R..Q.|
+00000010 ee 9d 4d be 8c 08 32 f6 f7 4a a5 26 26 6c b2 5a |..M...2..J.&&l.Z|
+00000020 49 7f 31 7d 44 b1 83 67 19 4a e3 07 7d 59 34 |I.1}D..g.J..}Y4|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a 33 a8 7a 61 46 09 7b 64 e6 aa f8 |.....3.zaF.{d...|
-00000010 8a 43 d3 a9 0c e9 2e c0 89 7c 72 fb 75 50 50 15 |.C.......|r.uPP.|
-00000020 03 03 00 16 2b b9 b5 eb f8 bd 53 20 ea 67 bc 47 |....+.....S .g.G|
-00000030 83 cf c5 6e f9 4f 9e 12 f5 1a |...n.O....|
+00000000 17 03 03 00 1a 61 73 4d 86 b2 a1 36 b2 3e b0 1d |.....asM...6.>..|
+00000010 6a b9 8a 8b 00 e0 3a d9 7e 23 c7 83 72 97 28 15 |j.....:.~#..r.(.|
+00000020 03 03 00 16 4a 8a 04 00 0a b2 75 80 20 ad 76 2a |....J.....u. .v*|
+00000030 88 16 56 e6 4a a5 c0 ea c7 0c |..V.J.....|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
new file mode 100644
index 0000000000..8a9ac36058
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
@@ -0,0 +1,231 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 16 d2 11 2e d6 |....Y...U.......|
+00000010 62 0c 5e 5c 9b 1f d2 31 87 b3 43 3e cd 47 4f f1 |b.^\...1..C>.GO.|
+00000020 0b a9 d1 4f f1 2a 42 5d 35 e0 ce 20 f2 f3 45 4b |...O.*B]5.. ..EK|
+00000030 98 2f 80 06 49 9a c3 4f 3f 70 0d e5 9a 2a 2e ff |./..I..O?p...*..|
+00000040 34 1b 0e 30 2c 85 52 e1 84 8c 3c dc cc a8 00 00 |4..0,.R...<.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 63 85 d4 43 2a d6 9f |........ c..C*..|
+000002d0 2f 1f 0c 73 fe dc 96 1e 51 50 a5 0d 5e fd b0 5b |/..s....QP..^..[|
+000002e0 a5 88 2a cd 1e bf c1 ec 4d 04 01 00 80 90 fc 48 |..*.....M......H|
+000002f0 53 eb 1b bc ec 39 be ae 60 4d c9 d1 49 eb 97 cf |S....9..`M..I...|
+00000300 94 53 75 30 84 35 ff 0c f6 ad 9f 24 98 70 2b d3 |.Su0.5.....$.p+.|
+00000310 45 0a 7f 25 ca a3 eb 37 5a a5 97 f1 78 8b b6 02 |E..%...7Z...x...|
+00000320 92 f9 12 9e 90 52 36 0e 40 15 76 de 37 02 c5 22 |.....R6.@.v.7.."|
+00000330 44 8f a4 fc f9 ac 88 88 ad 0c 9b f6 0e d6 9f f3 |D...............|
+00000340 68 cb f1 41 dd 2d c2 71 b6 43 36 12 d2 35 1c 9a |h..A.-.q.C6..5..|
+00000350 a9 72 ea af a9 9e 77 19 16 86 be 3e ec 5f 5a 53 |.r....w....>._ZS|
+00000360 f8 38 27 7f 08 2a ae 68 e0 17 31 df 9b 16 03 03 |.8'..*.h..1.....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b1 f2 9a ca 02 d3 ac 26 f5 32 03 |.... .......&.2.|
+00000040 4c b6 de cb f2 a3 11 19 eb c3 e0 e9 3b 8e 99 7d |L...........;..}|
+00000050 c2 f3 d0 6d 4d |...mM|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 c5 d4 b1 e2 0f |.......... .....|
+00000010 37 ad d5 c1 1a 6c 7f da 5f 25 e3 bd 20 1d 6e 58 |7....l.._%.. .nX|
+00000020 27 7a 07 55 76 11 76 72 1b 28 9e |'z.Uv.vr.(.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 3d 89 e4 a6 38 75 31 c2 08 3d 86 |.....=...8u1..=.|
+00000010 45 ed 8d c4 49 c4 da 54 3b 8f e3 |E...I..T;..|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 aa 85 e4 64 46 2f 8e dc 89 3e ef |........dF/...>.|
+00000010 6d 9e 1a af 53 3b a0 81 c2 |m...S;...|
+>>> Flow 7 (client to server)
+00000000 16 03 03 00 ad c3 12 d1 1a b2 88 da c1 0b 5a 32 |..............Z2|
+00000010 cf 05 35 53 ce 5d d8 42 cd 99 7e e7 9f 62 b8 35 |..5S.].B..~..b.5|
+00000020 9e f5 b5 a6 15 fd 82 26 9b 6a fe 3b 8e c0 43 27 |.......&.j.;..C'|
+00000030 1c 56 37 d1 6f d9 2c a6 a8 e8 b4 50 64 80 ae 5c |.V7.o.,....Pd..\|
+00000040 ed eb a6 58 58 52 cf 32 de 1d be 80 69 63 38 a6 |...XXR.2....ic8.|
+00000050 12 4e 11 9b 50 aa 4b 10 f7 ad 6f 5b 08 c6 cc bd |.N..P.K...o[....|
+00000060 94 42 64 90 c7 33 58 65 18 c5 a7 66 ce dd 83 8b |.Bd..3Xe...f....|
+00000070 b0 15 8a 61 26 c7 eb 15 4b 6c 0b 15 45 33 2a 01 |...a&...Kl..E3*.|
+00000080 ea 13 5a 20 52 16 15 a0 70 8f 86 dc 28 50 bb e4 |..Z R...p...(P..|
+00000090 9d 01 f4 c9 7f 27 5a 54 3f 42 34 c9 5c 04 3f a3 |.....'ZT?B4.\.?.|
+000000a0 6a 5c a1 3f 03 7c fc 57 94 9b 3e 76 65 bf 78 40 |j\.?.|.W..>ve.x@|
+000000b0 b1 4f |.O|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 33 ef 78 c8 2d 94 4b e3 b8 ea eb |.....3.x.-.K....|
+00000010 67 1e 6c 10 98 25 5f df ce 46 4c 13 77 ec d1 b1 |g.l..%_..FL.w...|
+00000020 e9 e2 c9 b0 de 9c ce 40 d0 d9 6f a5 fb a6 69 1f |.......@..o...i.|
+00000030 9f 53 68 6c ab f8 f0 10 4a c9 43 f0 ad 61 59 01 |.Shl....J.C..aY.|
+00000040 b2 90 97 9e cf 62 64 a5 46 b2 27 2f 1e b8 33 24 |.....bd.F.'/..3$|
+00000050 ed 7e 6b 5a dd 45 4d 00 61 a3 7e 22 5e bc 02 af |.~kZ.EM.a.~"^...|
+00000060 5a a0 73 fb c5 1c 0f 11 f6 70 5f cc 9e 1c fa 3c |Z.s......p_....<|
+00000070 13 0d 8b 03 4c 3b d5 5a 02 7b 95 64 ae cb 2f 50 |....L;.Z.{.d../P|
+00000080 e7 e1 32 13 72 96 16 03 03 02 69 f0 60 6a b8 fb |..2.r.....i.`j..|
+00000090 50 6e f9 f2 65 d0 73 90 f7 55 0d bc 3a 66 72 32 |Pn..e.s..U..:fr2|
+000000a0 b7 32 ad 1d de 18 04 90 55 70 2d b8 c9 3f 4b 2f |.2......Up-..?K/|
+000000b0 37 98 1c 4e c1 78 c1 ed 1f e2 bf 50 78 40 04 10 |7..N.x.....Px@..|
+000000c0 b8 55 48 29 26 b0 a4 4d ea aa 45 65 b4 21 93 ed |.UH)&..M..Ee.!..|
+000000d0 49 4c 1d d9 77 33 38 2e 14 92 b4 e3 06 ce fe 51 |IL..w38........Q|
+000000e0 6a 19 1c aa e9 a6 7d fa 45 86 66 1a 6e bb 01 01 |j.....}.E.f.n...|
+000000f0 82 86 89 86 81 ce 0a 93 1a b2 f1 90 71 7a 43 fa |............qzC.|
+00000100 b1 03 24 75 a1 48 f8 ee a0 b4 c0 18 ff 81 95 2a |..$u.H.........*|
+00000110 aa 74 87 39 da 23 ba ab 33 6b 63 ee df 2b f1 d1 |.t.9.#..3kc..+..|
+00000120 1a 9a 4a 0d ef de 68 13 28 81 49 d5 c6 08 57 a9 |..J...h.(.I...W.|
+00000130 d7 5e 56 a4 ec 81 42 de 28 39 51 7d 3a 66 cf a7 |.^V...B.(9Q}:f..|
+00000140 f7 81 7a b2 a7 09 b3 24 a6 b0 a5 cc 96 24 30 b2 |..z....$.....$0.|
+00000150 5b 94 1b ef 70 dd 7f bc 63 2f 7b bc 80 70 9e 9f |[...p...c/{..p..|
+00000160 01 c9 20 ab 35 53 7c 3b d6 70 d9 1d 9a f6 e8 76 |.. .5S|;.p.....v|
+00000170 f5 46 f8 b1 10 46 a9 eb da 7b 80 cc 74 18 f9 30 |.F...F...{..t..0|
+00000180 56 1a cb 4e 60 2a b3 9f 35 fe a9 b8 b8 76 02 a7 |V..N`*..5....v..|
+00000190 4e f9 43 c9 52 70 6a fd 9c 3e dd c4 3f 28 08 19 |N.C.Rpj..>..?(..|
+000001a0 28 ed f9 44 e3 d1 b9 53 7e b7 cd 1b e9 11 c8 9f |(..D...S~.......|
+000001b0 35 ed ab e3 5e 26 e8 49 7a 13 5c 20 9a b7 a0 95 |5...^&.Iz.\ ....|
+000001c0 60 0f 54 68 5c a8 c9 1d 37 0b 9f f6 61 3b fe 4c |`.Th\...7...a;.L|
+000001d0 dc 4f 11 98 0c 7a b7 32 0b 50 e2 cd a7 59 bf 05 |.O...z.2.P...Y..|
+000001e0 a2 8a 51 33 23 ab 99 49 23 97 42 3b 0f 1c 39 b1 |..Q3#..I#.B;..9.|
+000001f0 43 c4 01 aa f9 f8 54 d7 2c b4 ef 33 f3 05 13 d0 |C.....T.,..3....|
+00000200 8d 81 06 23 d3 38 cb 3a 6b 37 f0 4d 1f be ed 0c |...#.8.:k7.M....|
+00000210 b7 58 00 3a bd 74 02 a4 f4 b4 fc fd b8 fa 89 15 |.X.:.t..........|
+00000220 01 46 49 52 47 f1 4c 94 ee de 00 a1 25 aa b4 9b |.FIRG.L.....%...|
+00000230 f6 b4 23 a1 0d fd 00 5a de 45 38 ee 69 17 6f c3 |..#....Z.E8.i.o.|
+00000240 0b ed c5 3b b1 7d b1 2c a4 8f ed 30 44 9a 0b 51 |...;.}.,...0D..Q|
+00000250 34 12 cc 6a 09 e4 74 ec 11 94 4b ba ce 72 93 64 |4..j..t...K..r.d|
+00000260 07 c8 ff 78 6e 1a bd 5e 26 15 a7 e8 72 90 71 a9 |...xn..^&...r.q.|
+00000270 0a bb cf 25 40 1d 20 a7 d7 b3 46 4b 53 6c c2 50 |...%@. ...FKSl.P|
+00000280 c7 7b 58 e1 3c df 6d db 28 71 15 f9 84 b7 ad b0 |.{X.<.m.(q......|
+00000290 9f e9 7a 08 5d 85 7a dd bc c0 62 2e 6a d0 63 6a |..z.].z...b.j.cj|
+000002a0 e2 46 6b 80 68 cf e5 a7 9e 60 42 8a 17 54 9c ec |.Fk.h....`B..T..|
+000002b0 80 9b 81 80 7e 6f 33 8c d1 be 95 30 f2 a9 19 f8 |....~o3....0....|
+000002c0 36 2c 8e 89 c2 5a b4 04 2e 12 05 21 3b 4f 42 26 |6,...Z.....!;OB&|
+000002d0 d1 98 11 f4 17 c2 a3 06 54 37 31 8e ca 9b 07 62 |........T71....b|
+000002e0 79 95 b8 fd 49 aa 60 5b 03 7d 60 50 b6 2f 3b 0a |y...I.`[.}`P./;.|
+000002f0 5d c2 9f 92 16 03 03 00 bc ba f6 73 85 34 20 c4 |]..........s.4 .|
+00000300 b3 a4 15 01 fe 37 b3 b4 57 a5 b5 26 0c 64 2b 3e |.....7..W..&.d+>|
+00000310 07 d3 e4 59 a8 64 3f fd 15 24 24 70 61 77 9b 96 |...Y.d?..$$paw..|
+00000320 c6 4b 79 2e a8 a7 c4 ac 5e cd 6e 8f 30 e5 3f f8 |.Ky.....^.n.0.?.|
+00000330 08 22 cb de 5f 8c b8 dc 07 4b 79 ec 41 41 20 20 |.".._....Ky.AA |
+00000340 02 f6 4e 98 a3 5e 38 e2 5a d9 4a 2d 2e 3b 29 13 |..N..^8.Z.J-.;).|
+00000350 26 dc 4e eb a5 5e a3 b6 6f 16 75 b3 9e 63 4e 8e |&.N..^..o.u..cN.|
+00000360 00 c1 46 30 fc 25 f9 05 86 ed 00 87 f2 6b 5c 18 |..F0.%.......k\.|
+00000370 69 e5 5c 32 9e 15 d2 47 9e 0e d8 c1 7a 9d 45 7a |i.\2...G....z.Ez|
+00000380 76 4a ef 8d b5 60 7d 4d fa 99 8f c5 58 18 ad a2 |vJ...`}M....X...|
+00000390 93 c1 36 85 39 73 e1 7b 46 be 69 de 88 fa 68 8e |..6.9s.{F.i...h.|
+000003a0 be d1 48 bc 7b 29 2a 21 ba 60 60 58 51 c2 03 66 |..H.{)*!.``XQ..f|
+000003b0 51 9a 4e 70 06 16 03 03 00 3a c5 ed 8d 5d b9 c0 |Q.Np.....:...]..|
+000003c0 a2 07 15 c3 ef 76 ff fb ca f6 b6 4b ab a5 7a 80 |.....v.....K..z.|
+000003d0 a9 2e 43 d0 d2 f1 d9 96 61 ff 43 59 3d d1 82 57 |..C.....a.CY=..W|
+000003e0 68 d7 c8 3a 5f 86 4a 2e 00 8f 3d 0e 73 49 c6 4a |h..:_.J...=.sI.J|
+000003f0 81 4e ec e2 16 03 03 00 14 d5 5f c3 d2 9c 13 36 |.N........_....6|
+00000400 cb 22 23 3d e4 03 5b b9 26 66 cf 79 7c |."#=..[.&f.y||
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 15 0b 29 0e 27 a9 4b 52 4d 0a 77 |....i..).'.KRM.w|
+00000010 b8 3a 40 95 84 a7 7a 8d b1 6b 90 61 94 3a e4 06 |.:@...z..k.a.:..|
+00000020 20 6f 88 40 8a 8c c2 4e dc 3a 01 39 c2 11 5a 9b | o.@...N.:.9..Z.|
+00000030 28 92 bc 72 04 a3 60 c3 42 c0 b8 dd f3 41 40 be |(..r..`.B....A@.|
+00000040 6d 51 5b b8 db 75 63 3d 4f 2a cf f5 04 3d 53 be |mQ[..uc=O*...=S.|
+00000050 47 f1 ae be 0a 97 5d 2c df 55 5d dd 9a f6 0e 40 |G.....],.U]....@|
+00000060 59 02 91 d8 55 c9 3b e6 84 9c 8d 40 af 29 77 59 |Y...U.;....@.)wY|
+00000070 15 0c 83 dd ec c7 e2 16 85 d8 6e e7 4e c5 a5 b1 |..........n.N...|
+00000080 8b 4b 46 3e 62 7c ff 27 1b 37 b7 5c 05 32 30 fb |.KF>b|.'.7.\.20.|
+00000090 c1 cc 1d 13 1f 09 db 57 6a 70 2b 9f a7 25 9b 75 |.......Wjp+..%.u|
+000000a0 d3 62 20 45 d1 2f 28 c0 d7 84 d6 2e b3 6d 4a c3 |.b E./(......mJ.|
+000000b0 46 0d 92 32 87 65 dd b8 98 68 1a 52 0a df be b3 |F..2.e...h.R....|
+000000c0 09 bc 63 bb a3 da f7 52 5a 81 53 9a e0 ff bb 06 |..c....RZ.S.....|
+000000d0 7f 81 f8 ea 02 bb 3b 96 7b 0f 84 a5 4d 17 3a 2a |......;.{...M.:*|
+000000e0 20 e9 21 70 b2 ab 8a 55 31 4b 1b 60 52 7f a8 39 | .!p...U1K.`R..9|
+000000f0 5a 0f 0b 00 4e eb 01 0c a6 d8 f0 30 2b a3 6f 7b |Z...N......0+.o{|
+00000100 99 82 90 9e 4c c8 03 1c 0e 85 55 bc 2d 42 28 66 |....L.....U.-B(f|
+00000110 35 c3 1e 08 70 d0 45 05 5b 2e 00 fc 9a f1 44 0e |5...p.E.[.....D.|
+00000120 cb 91 ce b8 0f 2a 9f 5a 18 a8 ca 38 ff 2a ab 11 |.....*.Z...8.*..|
+00000130 57 a5 03 2f 3e 92 21 77 df dc 85 e7 fd d4 7e d0 |W../>.!w......~.|
+00000140 d9 6e ef 99 66 5d a8 f5 9a d3 c3 0f 0c 98 cd fe |.n..f]..........|
+00000150 5a 46 79 77 c9 28 fb 5e 3e c0 d5 b3 db 98 79 9d |ZFyw.(.^>.....y.|
+00000160 d4 20 a5 ad 25 d8 3b 39 35 60 fd 21 e0 eb 86 be |. ..%.;95`.!....|
+00000170 8f 65 72 a2 d3 91 4c 25 70 31 b1 02 29 17 da e0 |.er...L%p1..)...|
+00000180 9f 7d 4e 5f 1a 7b 93 09 4c 84 5b 40 f8 3c 98 36 |.}N_.{..L.[@.<.6|
+00000190 9b 14 43 db 43 11 0a e2 9a 8b 73 96 a3 7b 4d 67 |..C.C.....s..{Mg|
+000001a0 d7 35 a6 85 40 6d 45 0e 9d 47 43 96 b8 64 d4 d7 |.5..@mE..GC..d..|
+000001b0 d1 28 c8 32 7e ab d5 11 ad b4 a7 9c c9 ab c5 96 |.(.2~...........|
+000001c0 72 69 1a db 42 06 8e 03 d0 70 f9 7a 75 56 53 49 |ri..B....p.zuVSI|
+000001d0 29 e1 60 16 86 99 da 9e d6 c3 95 94 e3 e4 6c 9c |).`...........l.|
+000001e0 4f d0 5d e7 a6 23 e1 49 a5 b8 3d 41 a4 e0 8c a2 |O.]..#.I..=A....|
+000001f0 f8 35 40 4d 12 f1 0b 70 06 f5 b5 29 f8 5d 74 73 |.5@M...p...).]ts|
+00000200 32 35 11 7f 50 a3 22 5b d6 db a5 a8 9f ca db 47 |25..P."[.......G|
+00000210 b9 a8 c7 fc 16 40 ae 94 6e 6c 40 30 7a d6 9c 89 |.....@..nl@0z...|
+00000220 d7 e9 1b 6b 26 72 1f d7 c9 bc ce 6f 84 03 3d 65 |...k&r.....o..=e|
+00000230 34 f9 7b 32 54 e4 b4 72 8c e1 31 9e e5 13 50 2f |4.{2T..r..1...P/|
+00000240 ea 16 27 15 cb ec 0f 1b 21 aa dd cb 25 74 b9 4d |..'.....!...%t.M|
+00000250 36 c0 0d fe a4 99 2f 86 50 52 d0 83 e2 3f fa e7 |6...../.PR...?..|
+00000260 2d 24 b6 7a ca 7f 69 3e 7d 0b 61 df 29 3b 16 03 |-$.z..i>}.a.);..|
+00000270 03 00 35 8e 89 3d 7b 39 aa d2 21 01 6a 3d fe 4f |..5..={9..!.j=.O|
+00000280 e2 d9 e6 6d 5d 1e d3 a5 1d 3f f8 8e fb 97 3d 06 |...m]....?....=.|
+00000290 9b 68 67 45 15 3b a1 e8 e8 39 77 1a 41 77 2b c5 |.hgE.;...9w.Aw+.|
+000002a0 8c fe bd 28 7a 85 eb 7a 16 03 03 00 98 f0 ed 3c |...(z..z.......<|
+000002b0 37 3f 34 3b 35 e4 15 a8 f3 b4 b6 76 49 65 e8 26 |7?4;5......vIe.&|
+000002c0 93 4b cc b1 31 7a 4c e7 7d 80 63 60 65 9a ff 11 |.K..1zL.}.c`e...|
+000002d0 a8 c5 c4 4e c2 7a ca 95 cb 08 21 77 42 ce 70 1e |...N.z....!wB.p.|
+000002e0 bf d9 b5 6d de dc 03 67 2e 11 b5 47 c1 c0 74 6b |...m...g...G..tk|
+000002f0 b4 9d c4 de 8c d4 80 e4 99 92 31 68 09 85 00 34 |..........1h...4|
+00000300 43 cc 06 09 bc a8 6e 83 a0 fa df 6e a0 04 e9 37 |C.....n....n...7|
+00000310 b3 05 69 b9 f1 85 7f 48 27 73 d0 64 2c 33 48 1f |..i....H's.d,3H.|
+00000320 f9 7c 0a 21 1f cb 0f 4c c2 28 b0 3b 8c 9b 23 21 |.|.!...L.(.;..#!|
+00000330 f4 8c 69 b2 1d 55 35 20 b9 92 09 36 01 aa e1 e3 |..i..U5 ...6....|
+00000340 ee b7 3d 83 7b 14 03 03 00 11 40 bb bb 2e 3d 48 |..=.{.....@...=H|
+00000350 9f fa c6 0c d8 4f 45 cb 11 b3 a5 16 03 03 00 20 |.....OE........ |
+00000360 39 b7 46 30 00 68 12 c5 f5 d7 a0 85 7f ce 49 70 |9.F0.h........Ip|
+00000370 05 83 64 26 7a 0c 43 fb a9 4d bb 61 3a c3 8a 91 |..d&z.C..M.a:...|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 d1 d7 7e 3c 5f 01 cb f8 eb af d5 |.......~<_......|
+00000010 ba 09 32 68 4b cf 16 03 03 00 20 02 f1 23 45 32 |..2hK..... ..#E2|
+00000020 60 9b 49 db 2f 3a cb 5c e4 f3 64 b1 cb ca 09 b0 |`.I./:.\..d.....|
+00000030 b3 34 a3 75 7d a5 a0 80 44 fd b7 17 03 03 00 19 |.4.u}...D.......|
+00000040 d7 c3 c4 33 e6 f2 73 d2 2c 0b 7e 0e 40 d3 8b f6 |...3..s.,.~.@...|
+00000050 47 57 13 88 be 4b 12 43 57 |GW...K.CW|
+>>> Flow 11 (client to server)
+00000000 15 03 03 00 12 3a 90 85 e8 ce 53 d1 2a 3b d6 9a |.....:....S.*;..|
+00000010 f3 61 c1 72 81 c0 03 |.a.r...|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
new file mode 100644
index 0000000000..c2f4e4aca9
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
@@ -0,0 +1,376 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 30 5b 03 80 cf |....Y...U..0[...|
+00000010 ad 5e 69 9b da 4a de 2f 07 f3 6c 42 d7 50 99 10 |.^i..J./..lB.P..|
+00000020 80 15 dc dd d2 ef 3d 20 b9 eb bd 20 51 63 fd 9d |......= ... Qc..|
+00000030 3d b7 3e ea 4e 18 45 90 40 50 f2 f3 2b b8 00 42 |=.>.N.E.@P..+..B|
+00000040 bf 77 ae d1 ff 29 2d ca d8 c2 4e c7 cc a8 00 00 |.w...)-...N.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 6b cd 37 6d a7 76 7a |........ k.7m.vz|
+000002d0 04 0e 8c 93 db b0 62 67 14 65 26 5e 91 b3 8d 66 |......bg.e&^...f|
+000002e0 20 40 31 c1 84 3c ef d8 67 04 01 00 80 ce 3a f2 | @1..<..g.....:.|
+000002f0 16 01 b2 8a cd d6 1c b3 c4 46 a5 e8 1f 17 85 d9 |.........F......|
+00000300 5b 97 fb dd 43 65 52 82 e3 49 99 e8 49 d9 09 13 |[...CeR..I..I...|
+00000310 05 73 19 d0 d9 66 54 03 de 4b fa 43 2d f1 f8 98 |.s...fT..K.C-...|
+00000320 79 21 3b fa a9 ea 29 78 fa 87 59 8e 9b 2f f2 99 |y!;...)x..Y../..|
+00000330 14 85 21 9c 7e 59 5b 4b 2f e3 33 c4 7c 2c ac 35 |..!.~Y[K/.3.|,.5|
+00000340 4f 68 c8 a3 0b f5 43 7e 72 9a e6 4f 9c 10 4d 4a |Oh....C~r..O..MJ|
+00000350 d4 b5 84 62 61 4e f4 0f 3f a5 b5 23 89 d9 33 e2 |...baN..?..#..3.|
+00000360 06 22 02 c5 fe db 27 fb 40 87 8c e7 6e 16 03 03 |."....'.@...n...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 5a b9 f7 81 81 7f 65 84 c9 87 40 |.... Z.....e...@|
+00000040 a4 66 07 85 38 3b 85 8d ff c4 7e b7 f6 16 1d c1 |.f..8;....~.....|
+00000050 36 4f 53 1a bb |6OS..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 ff b2 f4 3b af |.......... ...;.|
+00000010 ba 44 66 0b f9 31 09 18 df 9d d0 04 82 38 11 dd |.Df..1.......8..|
+00000020 a7 ee 83 ef 03 51 21 08 f9 c4 8a |.....Q!....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 b6 45 4e 35 df 21 f4 c7 24 ba e6 |......EN5.!..$..|
+00000010 18 65 1c 75 ba 72 5d 5b 4a fd 78 |.e.u.r][J.x|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 1a ec 37 ab 36 23 80 76 1c 0b d0 |.......7.6#.v...|
+00000010 54 9a 8f 7e 7a c0 bd 09 9a |T..~z....|
+>>> Flow 7 (client to server)
+00000000 16 03 03 00 ad 7a d4 bf 4d bf 48 0a 0f 2c d1 38 |.....z..M.H..,.8|
+00000010 9f 20 f7 c7 36 27 82 d9 5e f4 21 44 0e 75 46 ca |. ..6'..^.!D.uF.|
+00000020 67 f8 87 6c 4f 1e c7 1e 5f 8d f2 88 58 1b 92 12 |g..lO..._...X...|
+00000030 e0 f6 d5 5c d7 4b 21 b9 8c 93 a8 bc a4 e6 e5 cb |...\.K!.........|
+00000040 d0 33 eb d5 10 ad 53 50 58 e0 94 f0 b8 52 20 8c |.3....SPX....R .|
+00000050 c2 69 7a c3 43 73 3f 2e 4a 42 2c c1 8d c1 ff 1e |.iz.Cs?.JB,.....|
+00000060 57 ba 7d 99 9c a2 10 99 19 d6 72 38 96 ba 2b ff |W.}.......r8..+.|
+00000070 7b a8 42 c0 c0 c4 d4 50 20 39 39 b8 18 23 a1 d3 |{.B....P 99..#..|
+00000080 38 d3 9d 41 81 c2 4b ba 4c 28 c0 14 22 71 df d9 |8..A..K.L(.."q..|
+00000090 e1 57 fc 9c 4f 0e 28 9a 13 c6 a1 e2 de f0 81 3b |.W..O.(........;|
+000000a0 5f c1 7b 61 f5 fc 74 93 f1 06 7d 9b 67 56 45 a4 |_.{a..t...}.gVE.|
+000000b0 f8 83 |..|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 ec 0e 7c 60 5b ed 0f 29 e6 cd 3a |.......|`[..)..:|
+00000010 ca ff f7 68 3e 22 30 cf 43 b2 29 71 ca 3a 06 db |...h>"0.C.)q.:..|
+00000020 e0 df bc 87 51 62 df 37 37 7a 9d b4 2d 35 ab bb |....Qb.77z..-5..|
+00000030 d2 ed d1 50 e7 61 a4 27 18 43 23 74 4b 1d 14 46 |...P.a.'.C#tK..F|
+00000040 80 5c 10 99 10 47 b2 51 92 11 1f aa f1 5a c3 cf |.\...G.Q.....Z..|
+00000050 f5 30 69 96 26 f6 0e 7c e9 e1 7c 4b d5 2f 46 1c |.0i.&..|..|K./F.|
+00000060 7d 18 a5 20 f1 ff 40 9e c7 d5 d4 54 33 c4 99 9c |}.. ..@....T3...|
+00000070 26 95 d9 ca 82 fc e7 27 37 fc 33 9f f8 c7 cb 0a |&......'7.3.....|
+00000080 9d 4e bc 66 ca fc 16 03 03 02 69 ab be 55 39 99 |.N.f......i..U9.|
+00000090 ac 66 a6 86 03 51 70 d8 fa 7d e7 89 09 fc eb b5 |.f...Qp..}......|
+000000a0 25 f6 95 0c 40 3d b8 ea b6 78 41 db a4 f3 92 83 |%...@=...xA.....|
+000000b0 00 c8 8d 1f 19 0c ec ec e5 60 07 d9 31 2d 3b 91 |.........`..1-;.|
+000000c0 ba ad b3 c1 fb b5 57 52 73 37 43 89 22 e0 45 7c |......WRs7C.".E||
+000000d0 b0 da 1f 69 76 d3 af fc ba f0 98 ec d2 7f be f0 |...iv...........|
+000000e0 a4 76 f0 d9 30 1b 78 22 bb 43 fd 45 64 07 e4 64 |.v..0.x".C.Ed..d|
+000000f0 c5 74 2f ed ba 23 8d 3a 5a ff 7f 35 de 25 53 0d |.t/..#.:Z..5.%S.|
+00000100 ac ae 5b da b1 7d 86 fe da c8 9e 79 58 6c 4c 9c |..[..}.....yXlL.|
+00000110 6d f9 e9 1d 31 ff aa fb 8e 2e 98 f4 3a 67 33 9b |m...1.......:g3.|
+00000120 a3 63 5e fc 74 f5 c5 28 76 30 e6 22 8a 85 79 56 |.c^.t..(v0."..yV|
+00000130 4e cf 94 38 92 61 09 22 00 95 d4 16 b4 e0 80 05 |N..8.a."........|
+00000140 28 35 30 6f 56 7d f8 b9 ed 49 72 b0 9f 47 9f 07 |(50oV}...Ir..G..|
+00000150 7f 1d b9 3b 6d ce c9 09 72 2f 65 b0 88 b4 ec 24 |...;m...r/e....$|
+00000160 29 8d 57 93 a7 51 85 32 26 4c 31 21 24 b1 ab 97 |).W..Q.2&L1!$...|
+00000170 c6 3c 38 44 d4 8f d0 3b ea 62 39 48 90 ca c4 5c |.<8D...;.b9H...\|
+00000180 9c 72 08 a4 3f d0 1e 3e 9f 23 02 0e 94 b4 14 cc |.r..?..>.#......|
+00000190 96 bc 23 22 2f af c5 ed 81 da 49 ca 26 f4 55 6a |..#"/.....I.&.Uj|
+000001a0 b3 24 3f 13 a5 f7 d6 82 70 04 37 63 dc 92 63 0f |.$?.....p.7c..c.|
+000001b0 3d f7 4e 42 7c 5a 42 df 53 17 48 25 cb da 31 e1 |=.NB|ZB.S.H%..1.|
+000001c0 67 a7 22 8c ca db 2d 33 49 86 62 b5 ba 38 53 4c |g."...-3I.b..8SL|
+000001d0 12 f3 c3 f6 b6 01 53 b1 11 43 e1 e8 ba 3f 68 7a |......S..C...?hz|
+000001e0 9c 10 09 82 d1 90 cd 9e 52 2e 29 15 0b 13 c3 e3 |........R.).....|
+000001f0 34 ef 76 8a 0d f9 f6 17 76 57 c2 55 cb 7d 45 e0 |4.v.....vW.U.}E.|
+00000200 d5 e6 53 93 75 57 c2 ab 26 5a 13 02 05 7a 60 2b |..S.uW..&Z...z`+|
+00000210 b6 92 1a 88 0c 34 59 81 40 42 70 d5 4e 7b d3 14 |.....4Y.@Bp.N{..|
+00000220 3c e6 70 81 90 ff 53 79 c5 f3 7c d9 02 6f 35 6b |<.p...Sy..|..o5k|
+00000230 d4 81 ff 32 a2 71 28 a0 4b 22 75 9f 3b 50 c8 03 |...2.q(.K"u.;P..|
+00000240 22 e7 4f 1f c5 c5 99 67 f3 2c 97 5e 43 89 84 39 |".O....g.,.^C..9|
+00000250 04 c9 4c 1e e0 da 39 8f 78 8f 95 3a 64 74 d3 63 |..L...9.x..:dt.c|
+00000260 13 d4 14 9d 98 6c bb 27 81 1e 12 88 8c d4 11 1c |.....l.'........|
+00000270 4a 71 2f 10 dc 5b 9a 8e 70 e6 bf 0b a2 50 4c d1 |Jq/..[..p....PL.|
+00000280 c4 29 b7 85 9e 0f 86 33 7c 38 e4 ae d4 53 5e 81 |.).....3|8...S^.|
+00000290 95 cf 6c 1a 15 7d af 20 53 21 f4 84 5c 46 5f 10 |..l..}. S!..\F_.|
+000002a0 1f 68 7d 9a 20 0d a8 1f 90 2f ae b8 c0 57 e0 4b |.h}. ..../...W.K|
+000002b0 ad ec 9d ae 51 52 78 5d 3f bb de 54 54 d4 18 ff |....QRx]?..TT...|
+000002c0 e6 b4 c9 52 f8 66 63 e3 bf 7a f3 5e c6 3f d9 27 |...R.fc..z.^.?.'|
+000002d0 71 07 e7 69 6d cb 60 24 55 4e f9 34 e7 5f a3 37 |q..im.`$UN.4._.7|
+000002e0 76 90 ec b5 eb ff 49 38 15 71 23 fd 77 30 80 c8 |v.....I8.q#.w0..|
+000002f0 ca 0e 38 3c 16 03 03 00 bc 89 27 c8 13 dd 05 8b |..8<......'.....|
+00000300 46 97 5f 19 76 db 29 8d b1 24 52 fe 7a 2e 2c 4d |F._.v.)..$R.z.,M|
+00000310 e2 f9 59 89 48 82 f5 d7 87 af 99 4b 98 c5 7c 1d |..Y.H......K..|.|
+00000320 1a e1 4d fd 0c 37 d0 d3 d8 e2 f8 0f 04 d5 15 21 |..M..7.........!|
+00000330 60 09 47 0c d6 bf 09 bf 55 c1 ae 33 11 35 94 29 |`.G.....U..3.5.)|
+00000340 80 96 3a 53 ae a8 29 c4 84 37 e2 80 f9 da 79 18 |..:S..)..7....y.|
+00000350 77 50 26 32 bf f6 b2 6d 3a 73 25 e7 cd 34 6d ea |wP&2...m:s%..4m.|
+00000360 a0 92 40 7e f8 eb d0 82 06 b3 a1 f5 1c 8e b2 ef |..@~............|
+00000370 b2 4f 0c bb 04 1b c7 cf bc dd 42 19 00 3e 45 93 |.O........B..>E.|
+00000380 e6 72 57 ed eb d9 1d b3 71 b7 fe 84 03 57 e4 9c |.rW.....q....W..|
+00000390 71 78 35 39 63 b1 cf 36 b9 5a d6 95 13 ee 4d 2f |qx59c..6.Z....M/|
+000003a0 22 ef ed 2e fc 69 7c 12 c2 0e 32 ed 05 17 42 5c |"....i|...2...B\|
+000003b0 a7 62 ab 6b 46 16 03 03 00 3a b9 af 3d 25 e4 6a |.b.kF....:..=%.j|
+000003c0 a9 b5 b4 00 79 21 aa 3c f3 56 50 bd 32 a4 a8 ab |....y!.<.VP.2...|
+000003d0 8a 60 77 5d b7 3e 89 d3 60 a2 b8 5c a8 99 27 bb |.`w].>..`..\..'.|
+000003e0 0e dd 93 af 3e 2b 66 8e 56 19 03 29 44 6a 63 a1 |....>+f.V..)Djc.|
+000003f0 c7 17 f3 1e 16 03 03 00 14 1c bd e4 7b c3 88 d9 |............{...|
+00000400 be ba c3 c3 fb b7 07 9d f1 58 3e b0 61 |.........X>.a|
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 d3 b2 83 ca 08 61 36 6f fa 66 de |....i.....a6o.f.|
+00000010 5c 42 5f 35 17 f4 4c b3 5e 17 94 07 c5 2a 89 90 |\B_5..L.^....*..|
+00000020 b8 31 50 af 55 91 b1 28 bc 00 00 da 57 85 cc d5 |.1P.U..(....W...|
+00000030 a5 a7 ec ba 52 d5 1f ab b5 4f a3 53 9c af 59 20 |....R....O.S..Y |
+00000040 be 13 f6 c5 70 b0 cc f7 59 69 d1 db 80 7f 60 29 |....p...Yi....`)|
+00000050 e1 e8 7a 1e 97 a6 e1 a2 11 70 4f b4 7b 53 7c 9a |..z......pO.{S|.|
+00000060 dd fa 58 5d 12 a4 fb 3e 46 dd d3 4d ac e3 b6 73 |..X]...>F..M...s|
+00000070 05 42 03 f3 37 79 a0 10 34 ef 01 6f c6 27 52 4b |.B..7y..4..o.'RK|
+00000080 75 4c b2 86 1b d6 ca 13 b4 31 41 db 93 2f a3 35 |uL.......1A../.5|
+00000090 e1 e9 bc 65 85 c8 1a e2 7b 6e 36 49 e8 ed 04 a9 |...e....{n6I....|
+000000a0 cb a9 70 32 c0 4d e5 f5 94 d8 af 7d 41 b6 dc e5 |..p2.M.....}A...|
+000000b0 fc ff db 9f 91 50 df c6 b2 4a 0c bb 86 4e 50 a5 |.....P...J...NP.|
+000000c0 2a 3b 69 e2 3d fa 10 eb cc 48 21 9d 98 78 02 0b |*;i.=....H!..x..|
+000000d0 e7 4d 83 63 9e e5 ad 2c 7b 46 d1 09 28 35 07 6c |.M.c...,{F..(5.l|
+000000e0 12 c9 ae f0 4c 7c 00 aa 54 ba 7b e8 42 be e0 18 |....L|..T.{.B...|
+000000f0 f4 df a0 9d eb 8f a2 3a d0 00 b6 e0 eb 90 65 38 |.......:......e8|
+00000100 b2 cc 21 87 57 b7 50 07 41 e2 5a 9b c8 2b ae 64 |..!.W.P.A.Z..+.d|
+00000110 55 6a d7 b5 0d 5d f0 ac da 0b f0 80 75 8d 6a 0a |Uj...]......u.j.|
+00000120 5b c5 2a 20 f2 ab 75 76 a3 33 f1 43 24 06 45 75 |[.* ..uv.3.C$.Eu|
+00000130 63 58 60 57 ca 7f d2 8f e8 a5 b8 e3 72 37 39 bd |cX`W........r79.|
+00000140 9c dd 10 b0 f8 b5 e8 46 4a 39 ac 94 69 08 51 29 |.......FJ9..i.Q)|
+00000150 27 2d 28 0f 15 8a 91 00 3b cc 99 77 ea 82 0d e1 |'-(.....;..w....|
+00000160 66 ed 34 da 6e 88 47 e5 f4 1b 28 28 cd 38 9f e5 |f.4.n.G...((.8..|
+00000170 1c 26 67 3d 83 d0 b1 88 a3 08 9c 2e 08 a5 b7 af |.&g=............|
+00000180 15 28 d5 1e aa c9 58 17 48 85 f7 13 17 6f 55 c3 |.(....X.H....oU.|
+00000190 dc 9d 2e 7e 67 45 7a cb 80 a7 e5 77 86 96 36 4d |...~gEz....w..6M|
+000001a0 f7 df 27 7d f4 5d 53 9b be e6 b2 b9 44 b9 86 e9 |..'}.]S.....D...|
+000001b0 8f 33 26 4e 20 97 e4 34 66 58 6d d5 28 be e8 84 |.3&N ..4fXm.(...|
+000001c0 de 2f 19 f2 46 52 80 84 e9 ef 0e 6c 55 5c 43 8c |./..FR.....lU\C.|
+000001d0 51 19 8b 22 30 b7 b3 eb 9f ed 35 a1 fe 09 aa 6a |Q.."0.....5....j|
+000001e0 f8 b6 37 7e 20 4c e5 76 ae 10 4c dd 67 7c 07 e2 |..7~ L.v..L.g|..|
+000001f0 0c dc 78 77 a1 8e c1 d1 aa fa d3 36 8b 9c 74 ed |..xw.......6..t.|
+00000200 e2 fe 84 98 40 95 f2 1a a6 fd 77 cf 47 d3 c3 d6 |....@.....w.G...|
+00000210 bc 38 45 a9 94 63 13 52 2d 7b 3f 3d 06 1e 0a 31 |.8E..c.R-{?=...1|
+00000220 cb 98 1d 18 fa a7 86 21 65 c7 58 dd 78 13 2d 4d |.......!e.X.x.-M|
+00000230 76 57 9d 65 15 a3 2d be 7f c9 58 78 b7 89 3c d6 |vW.e..-...Xx..<.|
+00000240 dc 7e 5b c5 1b 93 78 04 7b ca ef 61 77 6c 27 6b |.~[...x.{..awl'k|
+00000250 a5 30 67 43 64 a7 30 f0 dd 5c 63 92 76 9a e3 a2 |.0gCd.0..\c.v...|
+00000260 31 12 49 8e c4 7e 80 ce 1e ce 94 66 2f 6f 16 03 |1.I..~.....f/o..|
+00000270 03 00 35 39 86 a0 5a 88 07 66 5f 43 59 ed fb b5 |..59..Z..f_CY...|
+00000280 0c 0b ee ff 76 62 28 ea 62 7e 53 72 3d d9 26 9f |....vb(.b~Sr=.&.|
+00000290 06 64 99 83 a5 3c 59 45 84 4d 79 86 1d b4 21 14 |.d...<YE.My...!.|
+000002a0 29 df f1 99 aa 6a 64 91 16 03 03 00 98 22 32 c2 |)....jd......"2.|
+000002b0 63 2c 82 b9 47 02 65 97 6b 14 fc 35 b8 20 ce 3c |c,..G.e.k..5. .<|
+000002c0 1b 16 fd 51 55 e8 31 b5 58 e6 64 a8 2b b0 f2 ab |...QU.1.X.d.+...|
+000002d0 31 7a cd 3e 32 43 64 eb 08 b0 52 d4 81 56 e3 04 |1z.>2Cd...R..V..|
+000002e0 4e d2 1a b8 f6 ae 64 d2 c0 05 9b 18 84 71 a7 ad |N.....d......q..|
+000002f0 ea 49 f6 b5 ae 91 ad 66 6f cb fa 56 de 1e 40 22 |.I.....fo..V..@"|
+00000300 7f d3 44 c4 a7 bf b1 7b 61 e3 09 1f fe 3b 4b 7b |..D....{a....;K{|
+00000310 5a 3f ae 4e c4 5c a8 ac a4 c2 fc 0e 1f 12 4f 9b |Z?.N.\........O.|
+00000320 f9 e0 a2 89 ab a0 bb e8 f9 97 5a 7c 8d e8 58 87 |..........Z|..X.|
+00000330 3f 4c 1c f3 ff 6e b9 a0 e6 f7 e4 c2 43 cc af 9e |?L...n......C...|
+00000340 06 3a 1c ee ef 14 03 03 00 11 8b 6d c3 12 83 c4 |.:.........m....|
+00000350 2f e7 67 81 db 18 9a 33 e6 fa 82 16 03 03 00 20 |/.g....3....... |
+00000360 ef c9 6f 3f b7 9d 9d 2d a0 05 b6 fd 74 8e ff de |..o?...-....t...|
+00000370 cc 4b ca 4c 5b 4d 61 30 76 b5 f3 7a d1 46 d6 6a |.K.L[Ma0v..z.F.j|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 2e d9 0e 1b 6b 4b 9a 60 96 e9 38 |.........kK.`..8|
+00000010 35 a3 72 3d c4 5b 16 03 03 00 20 62 1f 2b 02 e8 |5.r=.[.... b.+..|
+00000020 22 0a 89 a2 f6 60 8a da f2 09 52 5a 92 12 a8 f6 |"....`....RZ....|
+00000030 c3 ee 25 17 6b 91 25 3e 2b 75 ba 17 03 03 00 19 |..%.k.%>+u......|
+00000040 b9 4e 6b c3 74 30 39 f9 3f a2 aa af 80 49 6b 8a |.Nk.t09.?....Ik.|
+00000050 f2 a1 9b f5 c7 34 f7 1b 2f 16 03 03 00 14 2d 25 |.....4../.....-%|
+00000060 74 c2 c7 80 a8 5f 65 ff 65 b0 c2 50 c8 bc fe 8c |t...._e.e..P....|
+00000070 d4 9e |..|
+>>> Flow 11 (client to server)
+00000000 16 03 03 00 ad d0 25 9a 38 60 d3 94 8e b8 23 45 |......%.8`....#E|
+00000010 44 67 95 20 79 1a 27 5f cf bb dc 72 8c 95 2a 02 |Dg. y.'_...r..*.|
+00000020 1d d9 80 c6 61 12 c2 5c ae d5 62 a9 aa b0 4a d0 |....a..\..b...J.|
+00000030 13 ad 6d ae df c9 63 e2 6b 27 bb ca 88 c3 dc 8b |..m...c.k'......|
+00000040 e9 bc 0b fb 32 d6 0f 99 b6 d1 03 7e c9 8d 72 ee |....2......~..r.|
+00000050 09 7b 82 f1 79 11 a7 23 43 8b 77 b8 a9 bd 9e 67 |.{..y..#C.w....g|
+00000060 43 03 79 88 34 ab c2 6b d1 2a cf c7 c9 b6 14 ee |C.y.4..k.*......|
+00000070 ee 32 01 10 fb 85 dc 5a 04 cf 9a ea 8d 8c fc f8 |.2.....Z........|
+00000080 b3 b2 49 c0 93 37 93 09 24 1c 26 97 43 5f dd 09 |..I..7..$.&.C_..|
+00000090 7a 0d c0 6c bd 17 df 78 37 3d 23 6b 9d 27 d2 f7 |z..l...x7=#k.'..|
+000000a0 1c 2e 82 5c ba 95 1c 0f b3 40 af 9f 2f 5e 42 40 |...\.....@../^B@|
+000000b0 cc b9 |..|
+>>> Flow 12 (server to client)
+00000000 16 03 03 00 81 39 20 22 4a e1 4e 21 2e 78 35 50 |.....9 "J.N!.x5P|
+00000010 8a d4 c4 c6 a9 20 74 8e 10 4b fd 31 4c ba c4 7f |..... t..K.1L...|
+00000020 14 91 ab 4b 7a b2 7a 86 56 cc 61 ed 12 63 4a d5 |...Kz.z.V.a..cJ.|
+00000030 b5 c9 48 6e ae 10 71 fc 30 f5 e5 36 8b e2 7d 9d |..Hn..q.0..6..}.|
+00000040 93 e2 34 cd 8e a0 72 c4 19 9b 62 eb 9b c4 5e c3 |..4...r...b...^.|
+00000050 df 22 d4 16 4d 88 b1 d5 e5 74 ac 9d 38 40 7d 1f |."..M....t..8@}.|
+00000060 40 bd 86 e5 fc 19 88 bb 67 cf 3f 22 0f 39 1f 8f |@.......g.?".9..|
+00000070 40 5c ee 29 48 00 c1 bf 6a f1 85 51 03 c0 e8 7a |@\.)H...j..Q...z|
+00000080 2e f4 2a f9 b6 fb 16 03 03 02 69 59 b1 5a b9 98 |..*.......iY.Z..|
+00000090 86 77 af 76 a7 4c 69 0d 83 79 3c 9a b9 3c dd 49 |.w.v.Li..y<..<.I|
+000000a0 f2 0f ef d2 38 ac 31 b0 9b 5d 57 ed a7 ca f9 79 |....8.1..]W....y|
+000000b0 7c ef 58 f7 ca 7e 0c 60 1c 53 09 c5 06 dd b8 31 ||.X..~.`.S.....1|
+000000c0 09 88 af 50 9f c2 2a 2c 24 89 9e 57 ae c8 e6 49 |...P..*,$..W...I|
+000000d0 f4 6f 46 e9 dd 38 f1 52 e9 06 50 38 69 b3 e1 69 |.oF..8.R..P8i..i|
+000000e0 f5 33 28 54 39 43 05 b9 04 04 c2 d9 3d 34 da 48 |.3(T9C......=4.H|
+000000f0 99 7e 8a b2 59 d1 d3 20 da 34 c8 ab 91 f7 66 69 |.~..Y.. .4....fi|
+00000100 3a 4f fc 6d ee e6 ef f5 c0 b0 08 bf 59 c0 f8 e5 |:O.m........Y...|
+00000110 dc c6 dc c6 49 a7 d5 3c 22 0f e3 9f 39 0b 2a 09 |....I..<"...9.*.|
+00000120 7a 56 f8 90 33 05 06 09 21 6f 6a 53 0d 89 63 2a |zV..3...!ojS..c*|
+00000130 76 28 19 33 73 e5 a0 2a fa d2 82 bf 4c 43 84 f9 |v(.3s..*....LC..|
+00000140 e1 bb 7f 31 62 04 c5 26 ed 16 40 f5 6a 04 e0 c5 |...1b..&..@.j...|
+00000150 4e fe bd e3 4c 57 e2 61 41 2f 9a 95 7f 8a e1 34 |N...LW.aA/.....4|
+00000160 64 f4 fc ce 13 e5 0c 68 c1 e5 29 df e7 b1 56 0b |d......h..)...V.|
+00000170 42 6b fc d6 5d 63 0b 3c 0c ca ce 38 11 50 f2 64 |Bk..]c.<...8.P.d|
+00000180 1a 6e 16 da 3e 69 cf 82 ba a0 03 0f 9d 72 ed 10 |.n..>i.......r..|
+00000190 78 b2 54 c0 be 9c 16 fa 15 4b 88 db dd 85 dd 08 |x.T......K......|
+000001a0 bd f4 50 a0 50 01 77 7a cf 20 c1 3e 50 55 5f bd |..P.P.wz. .>PU_.|
+000001b0 4a ba b4 d5 6d 51 38 b2 6d 4f fc b5 af b9 92 ff |J...mQ8.mO......|
+000001c0 c4 44 f1 0e db 4d 71 09 15 b3 c3 37 47 57 03 35 |.D...Mq....7GW.5|
+000001d0 95 de da 33 31 8c 60 bc 8a 97 2d f8 27 9b 4e dc |...31.`...-.'.N.|
+000001e0 2a 6d aa 3e 4d eb 8f 97 b8 fa d4 ef f6 27 d9 da |*m.>M........'..|
+000001f0 a6 fe 38 91 4b 96 ff 75 4b 71 52 9f 37 e4 d9 85 |..8.K..uKqR.7...|
+00000200 a8 d8 ac 21 e9 b2 c0 4f c0 c0 e3 3a 9f ab e0 93 |...!...O...:....|
+00000210 dc 03 18 30 92 55 33 67 58 f3 47 f3 0a 95 bc 33 |...0.U3gX.G....3|
+00000220 70 73 e1 5b 9d 63 cf f7 c7 9b da 9e 5d 2e 7a 66 |ps.[.c......].zf|
+00000230 03 b1 b8 5c fa b9 f4 fb 4e 0b 38 9a 97 f0 c9 e5 |...\....N.8.....|
+00000240 ce 18 33 ea 66 1c 59 cd 41 3e af 71 7c bf 00 a0 |..3.f.Y.A>.q|...|
+00000250 d9 ee 20 d7 80 a9 5d 55 b8 f8 92 7b 7e 4f bc 66 |.. ...]U...{~O.f|
+00000260 92 98 6a c6 15 5b e3 1d 59 14 d9 d0 5a 30 c0 4d |..j..[..Y...Z0.M|
+00000270 37 f5 d9 40 a4 f9 f4 ad b6 cf 55 98 03 1e e7 13 |7..@......U.....|
+00000280 5a 23 49 69 36 fa ae 9d c2 cb 90 16 cc 36 f4 41 |Z#Ii6........6.A|
+00000290 3a c7 56 9f 05 23 be 1d 3f 8f 90 41 09 6b 88 9a |:.V..#..?..A.k..|
+000002a0 70 91 76 e1 6d f0 5c 86 de 77 a4 83 c7 d5 3c c4 |p.v.m.\..w....<.|
+000002b0 67 ff b1 a2 e2 f5 61 4f 3b 4d 38 5d c9 c2 8c 97 |g.....aO;M8]....|
+000002c0 e2 a7 c0 72 3b 5e 4c d9 0f 18 a8 b9 77 8d 31 8f |...r;^L.....w.1.|
+000002d0 d9 73 ac 33 a6 7a b5 bd 5e 58 b4 51 22 be d8 d4 |.s.3.z..^X.Q"...|
+000002e0 f5 e1 bc 37 80 d3 cf 3b 58 be 3e ce 33 83 1c 46 |...7...;X.>.3..F|
+000002f0 8b f3 f3 56 16 03 03 00 bc 30 f0 e1 0b eb 80 fe |...V.....0......|
+00000300 5f fb 94 c9 5a 04 08 82 0f 0b b5 9b f7 f6 f6 d3 |_...Z...........|
+00000310 7e 68 e7 e5 2e cf a0 56 e6 b7 70 0a 63 5e 53 42 |~h.....V..p.c^SB|
+00000320 7f 27 ec 82 a0 5d e3 e8 77 27 40 3c 6d 47 ce dd |.'...]..w'@<mG..|
+00000330 89 6e ac 0c 48 ab 25 d1 8e 4e 4e b8 99 69 a5 94 |.n..H.%..NN..i..|
+00000340 8d 19 ab f9 82 6b 28 e3 b8 5f f7 75 a8 dd 1f b5 |.....k(.._.u....|
+00000350 0a ff d1 72 4f 82 9b 9e 8e b3 3f f9 73 d6 cd ea |...rO.....?.s...|
+00000360 c8 5b 51 4e 7f 16 a5 4b 81 5e 9a d7 a3 f2 64 35 |.[QN...K.^....d5|
+00000370 fd 2e dc 11 07 10 04 63 80 77 eb 0d d2 ba 9f 7c |.......c.w.....||
+00000380 ad 66 eb 0a 2e f7 f2 3d d3 a4 04 7b 83 8f 84 94 |.f.....=...{....|
+00000390 93 8e 8c 74 2a b0 3a 3e e1 33 92 f9 59 e5 0a 56 |...t*.:>.3..Y..V|
+000003a0 95 3a 8b dc 1f 24 6c 08 07 c0 f1 20 6d 96 43 71 |.:...$l.... m.Cq|
+000003b0 bf c6 92 81 e3 16 03 03 00 3a 91 c1 13 a0 26 c9 |.........:....&.|
+000003c0 12 6a 09 23 5b 8b e8 da 10 cc 4d 00 ed 9e a6 09 |.j.#[.....M.....|
+000003d0 d8 d4 c0 b7 f0 cd 5f 7a 6e 4d 31 21 f6 6a 22 e7 |......_znM1!.j".|
+000003e0 6e 25 11 94 4a f2 b1 f1 b2 c9 30 4b e4 cd f3 f5 |n%..J.....0K....|
+000003f0 ce 86 e7 5d 16 03 03 00 14 20 c5 91 f0 6e 21 b8 |...]..... ...n!.|
+00000400 e8 a1 bb cf 62 ed 4b 5a fa 19 40 ea 54 |....b.KZ..@.T|
+>>> Flow 13 (client to server)
+00000000 16 03 03 02 69 1a b5 80 9c c6 42 be a6 d9 d1 c8 |....i.....B.....|
+00000010 0b 2c f7 f8 2a 1a 02 f6 db 48 8b 5c 45 fc 28 41 |.,..*....H.\E.(A|
+00000020 a4 db 35 fb a7 a9 72 07 19 86 9e e9 dc 53 48 fb |..5...r......SH.|
+00000030 97 94 f3 a0 0d 8d 46 69 cf eb d9 ea de 21 a3 f4 |......Fi.....!..|
+00000040 b9 94 4f 8f 09 c3 de 66 fa 20 83 34 fc 50 ae c6 |..O....f. .4.P..|
+00000050 13 f6 7c c5 80 45 17 51 af a9 da bd 24 dd f6 15 |..|..E.Q....$...|
+00000060 8e c4 b4 e6 10 54 85 23 9d fe 72 b1 4c 2f ab ec |.....T.#..r.L/..|
+00000070 78 9a 06 60 03 96 f7 d0 af dd 94 26 c9 67 1d e5 |x..`.......&.g..|
+00000080 9f 87 22 c4 11 82 f1 4c f5 68 a7 fd d8 f3 dc ac |.."....L.h......|
+00000090 35 90 6b c2 97 1c 78 54 d9 b2 3c d8 9d 13 66 42 |5.k...xT..<...fB|
+000000a0 6e 3b 1b 8f 32 4e 8f b5 a0 60 6e e4 35 fd d5 b4 |n;..2N...`n.5...|
+000000b0 f8 fb a6 a9 c7 b7 31 39 8e 90 0c 42 bc 1a 4f 67 |......19...B..Og|
+000000c0 fa b3 10 a8 45 01 88 8a dd 41 43 c6 6c 41 9d 28 |....E....AC.lA.(|
+000000d0 bd 4c 43 85 4c 3b 7c 03 c4 55 70 f1 49 a0 d6 52 |.LC.L;|..Up.I..R|
+000000e0 5c 49 3e 2b d7 e8 a9 75 5e 92 bf f3 4c 1c c3 7e |\I>+...u^...L..~|
+000000f0 69 ca 52 25 07 bb 54 e0 58 2d 28 ba 50 30 81 e8 |i.R%..T.X-(.P0..|
+00000100 93 0d 9d 78 3d c0 f1 c3 34 72 29 f1 da 60 de 84 |...x=...4r)..`..|
+00000110 aa fc d3 0f 2b 1e 1a 9c 7c af 6f 6a 4c cc 88 36 |....+...|.ojL..6|
+00000120 03 03 34 79 f9 89 6d 41 bb 19 61 6a 60 75 d7 0f |..4y..mA..aj`u..|
+00000130 dc 22 7a e4 36 91 32 2b 99 24 36 19 4b 4c c4 ae |."z.6.2+.$6.KL..|
+00000140 4f 98 6d f0 97 ce bc b4 ee 97 30 97 0b 54 8c 14 |O.m.......0..T..|
+00000150 8f d5 9d 44 ae 0a a6 07 9f 39 f6 66 80 cb fa 27 |...D.....9.f...'|
+00000160 bb 2f 26 bb c3 1a a4 9b a0 d3 e8 75 13 49 da 0a |./&........u.I..|
+00000170 8f cc e8 15 77 f8 05 c2 17 a0 ff e7 2a 59 bc c8 |....w.......*Y..|
+00000180 67 b5 7e b8 78 1e 32 81 22 3e 57 28 ee 51 96 b7 |g.~.x.2.">W(.Q..|
+00000190 0e dc 3f d1 00 16 a5 eb 01 cb c3 e3 5b 01 ad a9 |..?.........[...|
+000001a0 d5 1b ac 9b e2 0d 9a 6f 7a 2f f1 7d 05 57 6d 2d |.......oz/.}.Wm-|
+000001b0 9d 35 68 88 e7 c5 e0 fb 9d 87 a7 ef 71 d8 47 b8 |.5h.........q.G.|
+000001c0 19 8e 87 d8 b1 36 0f 52 ab 98 8b 97 43 53 86 be |.....6.R....CS..|
+000001d0 9d 86 2a cd 7c b0 46 c4 48 89 5b 6c 1e 93 9e a2 |..*.|.F.H.[l....|
+000001e0 15 af 60 8f 84 75 99 97 53 11 23 f9 0d ba 78 12 |..`..u..S.#...x.|
+000001f0 9b a9 04 91 d0 3a b3 4d 7b 67 a0 fa 78 5c 19 d6 |.....:.M{g..x\..|
+00000200 88 d2 21 f6 8d e4 91 d1 76 95 67 9d 4e 3b a1 d2 |..!.....v.g.N;..|
+00000210 61 c3 d2 a6 53 fd 82 93 20 7e f6 07 a0 49 3a ea |a...S... ~...I:.|
+00000220 bc 73 03 0b f2 df 51 ac 35 d8 e4 35 9d 13 56 b5 |.s....Q.5..5..V.|
+00000230 be fc 7c 36 8b 37 a0 71 57 62 bd 89 38 18 90 1e |..|6.7.qWb..8...|
+00000240 7a 1f b3 8f 73 55 32 94 5a 3a 31 91 b3 95 bd 61 |z...sU2.Z:1....a|
+00000250 ea 93 9d f0 38 33 fb 5b 28 3d a7 29 a4 91 de 85 |....83.[(=.)....|
+00000260 9c 16 63 10 81 c6 e0 11 92 3d 53 db 69 95 16 03 |..c......=S.i...|
+00000270 03 00 35 f7 3a b7 d1 20 aa f7 ed b1 c7 46 52 cb |..5.:.. .....FR.|
+00000280 6e dd e2 f4 ae 83 20 cd 6c 59 b5 26 f9 81 7e 6c |n..... .lY.&..~l|
+00000290 ed e9 0b 2a f1 3a dc f8 d6 ed e5 6d 89 14 3d 79 |...*.:.....m..=y|
+000002a0 e7 c8 af 89 30 eb 98 3d 16 03 03 00 98 a0 59 2f |....0..=......Y/|
+000002b0 cd d9 f6 63 e3 53 47 77 e5 c4 fc 2e 12 d7 24 8a |...c.SGw......$.|
+000002c0 4c c7 d8 c9 77 4f bc 3c af 93 6f 57 3d 6f 5d 1c |L...wO.<..oW=o].|
+000002d0 6a 5a 2c 42 1c e0 92 d5 5e 34 c8 a5 9e 11 21 16 |jZ,B....^4....!.|
+000002e0 01 1a 08 af 4e f6 a1 e3 19 a6 81 41 3d 7a f3 d1 |....N......A=z..|
+000002f0 e0 9e 55 90 42 4b d9 5c 46 b7 eb c8 fb 83 1c 97 |..U.BK.\F.......|
+00000300 9e d9 74 bb 7f 2f 4d 61 89 46 db 32 da 1a 76 95 |..t../Ma.F.2..v.|
+00000310 88 f8 ca 62 14 88 dc 97 b8 58 82 74 16 78 be c5 |...b.....X.t.x..|
+00000320 f9 78 a4 88 c1 d4 6b 36 6e 54 60 a5 21 30 47 07 |.x....k6nT`.!0G.|
+00000330 e8 2d 22 ce a5 17 fb 43 10 9d 74 c9 64 a3 db ac |.-"....C..t.d...|
+00000340 d9 24 7a a7 5d 14 03 03 00 11 68 20 87 e9 9b 91 |.$z.].....h ....|
+00000350 81 67 2b 31 c4 47 e8 9b 2e 7c c4 16 03 03 00 20 |.g+1.G...|..... |
+00000360 ef 6f 3d 0f 23 fa 77 8c a9 46 d9 0d b0 d9 f8 16 |.o=.#.w..F......|
+00000370 62 e2 07 21 ec b6 a7 78 ce a6 ea b3 68 c1 c7 af |b..!...x....h...|
+>>> Flow 14 (server to client)
+00000000 14 03 03 00 11 bb 45 96 9e 08 cb e4 24 c2 e3 71 |......E.....$..q|
+00000010 40 d1 ef a1 5e 2f 16 03 03 00 20 1b 3f 69 fb ae |@...^/.... .?i..|
+00000020 cd 98 15 59 16 14 cf a5 16 af 36 6d 6d 3a 49 06 |...Y......6mm:I.|
+00000030 a6 f9 cf 53 ea 9a b7 3b 48 d2 e3 17 03 03 00 19 |...S...;H.......|
+00000040 72 2c 82 a0 8c 6c 8b c3 78 e4 41 1b ff ba 92 6d |r,...l..x.A....m|
+00000050 3c 4d 9c c3 95 e3 27 b9 82 |<M....'..|
+>>> Flow 15 (client to server)
+00000000 15 03 03 00 12 3d f9 72 53 84 b5 a4 ec 27 39 cc |.....=.rS....'9.|
+00000010 72 29 c0 e6 37 7b 0f |r)..7{.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
new file mode 100644
index 0000000000..737ccc61ba
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
@@ -0,0 +1,234 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 75 f6 1b 17 2f |....Y...U..u.../|
+00000010 e0 d4 19 06 0d 93 90 51 46 d9 c3 a0 cd 45 6c 85 |.......QF....El.|
+00000020 94 87 01 21 3e 92 62 1d e7 d1 39 20 07 26 a1 5b |...!>.b...9 .&.[|
+00000030 d2 4a 61 40 ba 58 c0 23 0c 3f c3 08 5d 28 04 94 |.Ja@.X.#.?..](..|
+00000040 a9 34 37 28 64 75 6f 9c ae fa 1f 24 cc a8 00 00 |.47(duo....$....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 84 74 e5 bc 24 39 39 |........ .t..$99|
+000002d0 e0 6e 35 fb 34 87 76 0d 78 89 35 5c 85 e7 92 da |.n5.4.v.x.5\....|
+000002e0 e1 39 f4 b2 e7 ec d5 cd 58 04 01 00 80 cf 3a 57 |.9......X.....:W|
+000002f0 6a 8b b7 72 d8 a2 6b 47 87 77 8b 7a bf 63 6c e8 |j..r..kG.w.z.cl.|
+00000300 d4 20 6a 6a 9c 62 b6 ef 4b 9f a7 89 8c a6 fd 02 |. jj.b..K.......|
+00000310 92 2f 8d 07 44 09 f6 d9 03 99 39 49 1d 8d 1b 7f |./..D.....9I....|
+00000320 eb eb 4b a6 fb 9f 83 3b 3d d3 61 3e e4 d3 22 24 |..K....;=.a>.."$|
+00000330 c1 44 76 e8 75 c7 aa 31 96 e3 50 bb 76 3e 87 02 |.Dv.u..1..P.v>..|
+00000340 b9 1d 82 dd 55 ee 05 b9 b5 1e 65 90 2c 50 c9 87 |....U.....e.,P..|
+00000350 49 dd 35 c8 84 67 6e 52 3a 3b ec 3c 63 f4 0f 95 |I.5..gnR:;.<c...|
+00000360 87 05 8e ec bd d7 97 9f 9a 14 78 d7 97 16 03 03 |..........x.....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 3e a2 12 3b a4 83 4a c2 0e 93 d5 |.... >..;..J....|
+00000040 98 d5 2e 11 9e 60 60 23 78 5a 63 49 f1 7a ee c4 |.....``#xZcI.z..|
+00000050 47 00 6c 4e fb |G.lN.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 6d 78 5b 5f 1b |.......... mx[_.|
+00000010 2c 05 ba 92 46 e2 f0 04 48 fa a1 da be 93 ed fd |,...F...H.......|
+00000020 f5 f8 b8 dd 00 60 09 a6 36 3c c4 |.....`..6<.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 a4 db 13 bc c1 6e 06 9e 6d 1a c9 |..........n..m..|
+00000010 85 a7 e9 28 b8 27 74 19 8f 1a bc |...(.'t....|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 fa a3 77 3c 76 11 5d be 12 4f 6a |.......w<v.]..Oj|
+00000010 f7 0d 26 73 ab 7c bd 4b 19 |..&s.|.K.|
+>>> Flow 7 (client to server)
+00000000 16 03 03 00 ad 59 80 a4 91 95 56 2a 01 ee 04 84 |.....Y....V*....|
+00000010 f9 d2 dd a5 2c a6 46 a8 69 a3 c7 47 7e eb 54 da |....,.F.i..G~.T.|
+00000020 ec cc 9d aa e1 0a b1 7c e9 cf 9f c9 c8 12 62 35 |.......|......b5|
+00000030 d2 4a eb 28 0d 9b aa a4 d5 79 66 f7 72 4c 26 10 |.J.(.....yf.rL&.|
+00000040 b6 71 db 4a 68 8b 47 f9 47 e3 6d a6 4e 99 d5 0b |.q.Jh.G.G.m.N...|
+00000050 27 b2 2c 23 9b 58 60 8a 37 a1 8e 26 09 26 2a 46 |'.,#.X`.7..&.&*F|
+00000060 e6 24 7f 9b cb 6b d1 9d b1 c0 48 c9 50 8b ab 06 |.$...k....H.P...|
+00000070 05 57 ef 1a e0 bd ce db ca 3d e1 59 df 24 4c 02 |.W.......=.Y.$L.|
+00000080 bf 1b 9e 48 52 42 6c dd 8f fa 82 68 56 52 a6 be |...HRBl....hVR..|
+00000090 d0 93 cb 43 74 e1 2f 86 cc e1 4c fa ba fc 1d f0 |...Ct./...L.....|
+000000a0 d5 20 3a 79 b3 b8 b7 24 b5 cf 4c dd a5 d0 4d 18 |. :y...$..L...M.|
+000000b0 15 55 |.U|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 10 b8 d9 9a 82 21 14 86 6d ef e4 |..........!..m..|
+00000010 b6 bc 10 84 80 a6 72 7b dc 24 ba e1 e5 d2 bb d2 |......r{.$......|
+00000020 9f 09 d3 d7 37 20 ec 7d bd 13 e0 bd 40 44 8a 6e |....7 .}....@D.n|
+00000030 7f f6 d5 42 03 4b 00 b5 87 99 ac 6d 11 03 38 46 |...B.K.....m..8F|
+00000040 33 71 c4 10 ce da 36 d6 c1 41 9f 96 8e eb 4b 99 |3q....6..A....K.|
+00000050 24 07 8c 6b 88 2c f1 dd 31 35 ba 43 0f 60 bf b0 |$..k.,..15.C.`..|
+00000060 74 77 a9 d4 a7 65 f6 68 e2 70 4a 7e fe db ab 13 |tw...e.h.pJ~....|
+00000070 7f 51 c3 0f b4 93 42 12 d6 29 5d 44 5c df 17 6e |.Q....B..)]D\..n|
+00000080 73 1d b8 95 fc 8b 16 03 03 02 69 64 5d 4f b4 3a |s.........id]O.:|
+00000090 23 98 07 51 63 18 09 07 9a 8c dd 8e 51 a8 ca 23 |#..Qc.......Q..#|
+000000a0 37 21 f4 d5 e0 8f 03 1c 6f 6d c4 60 dd 99 8f 4b |7!......om.`...K|
+000000b0 4c 11 f7 78 f8 aa f6 29 87 cf 4d ba 89 87 2a c9 |L..x...)..M...*.|
+000000c0 48 66 48 d3 a6 19 8a 84 f6 db 17 b4 59 5b e4 8e |HfH.........Y[..|
+000000d0 8e ef fc 32 10 aa 0d 57 47 68 82 07 72 95 03 f6 |...2...WGh..r...|
+000000e0 e5 c1 c3 01 00 f9 85 4f 0f 85 37 73 f7 c5 af a2 |.......O..7s....|
+000000f0 37 96 ba 06 49 6a 2d a2 23 39 2e 9b f1 fc 01 de |7...Ij-.#9......|
+00000100 53 75 ee 34 ae 27 ea 49 6a d8 d0 cd 9b e8 60 b7 |Su.4.'.Ij.....`.|
+00000110 f6 b1 8e 26 ec 6c 36 87 d6 70 49 07 e0 96 2a bd |...&.l6..pI...*.|
+00000120 45 a3 b1 f5 dc b0 a3 4f dc d8 c3 fd 4f fb 98 13 |E......O....O...|
+00000130 67 55 99 39 b5 16 19 72 9d f1 5a cf 6e 53 d9 03 |gU.9...r..Z.nS..|
+00000140 05 f5 81 07 a1 38 a1 e5 4c 76 51 1a ae f6 4b f6 |.....8..LvQ...K.|
+00000150 b2 a7 84 1e 2a 31 b0 b8 9f 41 e8 e5 32 18 44 4c |....*1...A..2.DL|
+00000160 0b fb e3 d9 4c dd 45 c5 c4 c4 57 bf f7 5a dc f6 |....L.E...W..Z..|
+00000170 73 98 d4 ea 2f c0 cb 35 97 c1 45 94 37 87 d3 8c |s.../..5..E.7...|
+00000180 65 3f ee a8 67 a6 00 80 92 02 76 e8 0a 04 ce 7a |e?..g.....v....z|
+00000190 79 4f cd 70 1a 31 5a 03 83 01 de 1f 4a 46 39 4e |yO.p.1Z.....JF9N|
+000001a0 d0 80 6e 67 d7 e6 fc ba 74 4b 57 d2 3c 19 7b 03 |..ng....tKW.<.{.|
+000001b0 ab 9a e2 f7 db 58 c2 b7 58 96 55 88 e6 e2 e2 f8 |.....X..X.U.....|
+000001c0 ab e9 b0 12 ef ff e6 53 7b 4e 01 2f 65 0d 05 f0 |.......S{N./e...|
+000001d0 95 9f 46 d2 ae e7 33 5c 37 56 ab 67 95 87 81 59 |..F...3\7V.g...Y|
+000001e0 f2 35 76 78 ed 13 63 a3 58 52 af 46 e6 aa c3 99 |.5vx..c.XR.F....|
+000001f0 37 9d 10 25 cc 7f 7e 63 e1 96 6d 7a 8e ac 9e 00 |7..%..~c..mz....|
+00000200 d1 0e 7a 48 b6 82 77 6a a0 17 d1 77 70 f8 40 4a |..zH..wj...wp.@J|
+00000210 c4 90 da b0 3f 25 68 f5 9f dd 5e ec 95 02 19 53 |....?%h...^....S|
+00000220 08 6a 13 11 88 9e 2b 25 b8 28 cd 58 36 d7 d3 95 |.j....+%.(.X6...|
+00000230 f5 91 63 92 ff 3b d2 4f 75 ae 47 6c 64 8a a4 76 |..c..;.Ou.Gld..v|
+00000240 48 96 a7 35 d6 35 22 96 4d 4f ee 45 fb 88 52 68 |H..5.5".MO.E..Rh|
+00000250 4e 38 93 e8 08 6a e6 f3 00 a7 f7 b0 0b 68 41 ab |N8...j.......hA.|
+00000260 9b 3a 92 2b fd b2 71 14 77 91 48 e7 70 62 b5 b0 |.:.+..q.w.H.pb..|
+00000270 45 90 35 d2 b3 22 f5 70 6c 62 7f 55 6b 56 42 f8 |E.5..".plb.UkVB.|
+00000280 6c 87 a7 60 45 37 f0 41 41 ec 73 f5 f1 d9 d2 84 |l..`E7.AA.s.....|
+00000290 bd 88 bc 9b 43 ec 8b b3 c4 3a 59 2c 30 61 30 98 |....C....:Y,0a0.|
+000002a0 78 d3 e7 85 dd 7e 80 b8 fb b3 bf 7e 11 79 e8 20 |x....~.....~.y. |
+000002b0 aa b8 81 94 10 5c f8 ba 70 4c 1e 7c 35 8f 48 30 |.....\..pL.|5.H0|
+000002c0 17 38 d6 1c 91 ed 00 2c f7 af 29 d3 cb 9b ab 6b |.8.....,..)....k|
+000002d0 b3 fa 6e 1a 9b a8 cf 08 8e 03 a5 f7 76 17 74 3a |..n.........v.t:|
+000002e0 9e 36 ae 19 fd 2c 44 14 f3 2b 1d 01 db e1 96 22 |.6...,D..+....."|
+000002f0 25 14 5b d8 16 03 03 00 bc bb 8c bb cf f9 d7 76 |%.[............v|
+00000300 7a a7 d6 e0 29 cb 45 21 8d 57 0b 81 0c e0 96 05 |z...).E!.W......|
+00000310 c7 96 67 43 0f 41 11 e9 c2 07 2d 62 17 b4 64 01 |..gC.A....-b..d.|
+00000320 c5 75 79 dc 9c 36 3f ea 42 ea 09 a7 bc 0f 6b b1 |.uy..6?.B.....k.|
+00000330 b4 4d ae 38 0a ca 51 d0 97 46 b6 55 12 7c 24 28 |.M.8..Q..F.U.|$(|
+00000340 77 16 64 42 53 70 c4 52 ed e5 aa 20 3a 00 7e d0 |w.dBSp.R... :.~.|
+00000350 9e 99 e4 56 5f ef 30 56 00 8b e7 31 6d 66 6d dc |...V_.0V...1mfm.|
+00000360 58 8a b0 60 6f 16 a7 b0 14 a5 9d 3d 38 94 6e 16 |X..`o......=8.n.|
+00000370 a3 22 76 e9 59 d8 90 cd 32 83 bb 8c c5 23 cb c2 |."v.Y...2....#..|
+00000380 c5 03 02 de 13 97 ac 4e 99 9f 4d 6d aa ed 72 b7 |.......N..Mm..r.|
+00000390 76 db 8b c9 31 17 b9 1c 4a fa 87 2c 6b dc 07 82 |v...1...J..,k...|
+000003a0 a2 39 e0 09 32 a2 8e 1c 6e 68 e1 14 ba ab 3a d4 |.9..2...nh....:.|
+000003b0 1e 4f f4 39 c7 16 03 03 00 3a cf b2 61 5f 7e ef |.O.9.....:..a_~.|
+000003c0 04 51 64 f6 3d b3 54 44 bd 8a d0 87 48 64 76 a6 |.Qd.=.TD....Hdv.|
+000003d0 0d bc 7f b7 99 d4 67 8b cd e3 c4 5d df c5 c8 fc |......g....]....|
+000003e0 be d1 c4 03 6d 61 2d 10 58 b1 7a 7c 9e 1c 6b 16 |....ma-.X.z|..k.|
+000003f0 ff 31 a8 87 16 03 03 00 14 85 99 57 4b a1 19 33 |.1.........WK..3|
+00000400 bd 9a 86 ed be 5d 24 f0 02 9d ca 1e 26 |.....]$.....&|
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 8c c7 01 da 38 a5 36 3d 2c 21 1c |....i....8.6=,!.|
+00000010 64 1b b8 e7 c2 cd 17 06 b6 51 0e e6 d9 d9 18 c5 |d........Q......|
+00000020 a9 c9 ac 5d 2d 23 f8 15 92 b2 e1 62 6e d7 8d 58 |...]-#.....bn..X|
+00000030 5b d9 b8 26 e5 ec 0f 61 15 3e 12 70 89 0d 3f 4e |[..&...a.>.p..?N|
+00000040 e3 2e 18 42 7c c7 59 7b e1 48 d9 a8 cf b1 cd 38 |...B|.Y{.H.....8|
+00000050 17 90 97 89 2e 4f 4b df 58 b0 9f 4e 95 d2 e9 70 |.....OK.X..N...p|
+00000060 6d 0b 82 af b7 05 be 11 26 d8 f9 89 e6 d6 44 f5 |m.......&.....D.|
+00000070 db 7c 8c 91 61 78 dc 68 98 9b 10 17 5b 85 42 93 |.|..ax.h....[.B.|
+00000080 31 a2 16 97 72 c5 f2 d0 81 76 a6 9b b7 9c 14 ab |1...r....v......|
+00000090 a7 bf 19 f7 34 e3 8f 3f a5 aa 23 c8 49 07 1b 6f |....4..?..#.I..o|
+000000a0 e5 5d 65 66 a1 dc d2 e7 bb c2 4b 9e a7 9a dc d6 |.]ef......K.....|
+000000b0 72 42 d3 71 d3 51 a4 3a 82 f7 cd 2a 15 34 da 6d |rB.q.Q.:...*.4.m|
+000000c0 44 3a a9 7d 6e 4c ce a5 ba 6b 5b 3b 88 8c e1 29 |D:.}nL...k[;...)|
+000000d0 ee a8 17 1b 02 36 8f 68 c9 9e e6 f1 bf e3 e3 e0 |.....6.h........|
+000000e0 cd 6d 7f ff c2 4d 3f 88 c7 9b 75 20 e5 cd fa fa |.m...M?...u ....|
+000000f0 a0 d7 10 6a c1 00 73 f9 df bd 22 60 8c 82 71 e6 |...j..s..."`..q.|
+00000100 56 aa 90 bf c7 a8 82 51 e7 23 42 ec 99 f5 b9 aa |V......Q.#B.....|
+00000110 3c cc c6 32 11 29 1f a6 ae 89 03 04 e8 de 9f f4 |<..2.)..........|
+00000120 bd 87 ae af 91 ee a2 f3 e2 6d 7b 87 ad 67 16 2d |.........m{..g.-|
+00000130 ad 92 34 38 52 ed 7c 38 92 45 16 26 9f 65 d2 67 |..48R.|8.E.&.e.g|
+00000140 3e 33 a1 bd b2 f6 d3 c8 76 96 52 11 0d 8d ac a6 |>3......v.R.....|
+00000150 27 10 6a 43 63 5f 82 41 e7 fe 91 24 68 70 bd 2c |'.jCc_.A...$hp.,|
+00000160 35 fd 0e 49 ec 3a dd f3 c0 af 5c f4 61 9a 2a 00 |5..I.:....\.a.*.|
+00000170 59 b5 28 24 f0 cf d3 25 bc 77 65 74 04 ee 4b 5e |Y.($...%.wet..K^|
+00000180 2b 9f 1d 27 e2 dd 1a ed ab e5 ff d6 1a 55 d7 4d |+..'.........U.M|
+00000190 5c da 14 96 21 43 f6 c3 2d 78 e5 75 60 69 26 ce |\...!C..-x.u`i&.|
+000001a0 7a 66 5e 42 91 0e ef 41 c2 c4 e6 15 8a 9a 17 a1 |zf^B...A........|
+000001b0 d9 23 2c cc c7 81 00 71 b0 52 ec 4e ea eb f9 75 |.#,....q.R.N...u|
+000001c0 2e 87 16 b4 ba 25 8c 09 f1 23 f9 ee ea db 0e b5 |.....%...#......|
+000001d0 d0 dd 47 9b b6 06 a3 f3 5e 0d 34 5a ba 76 cd 0a |..G.....^.4Z.v..|
+000001e0 b1 9f 8a 99 aa d3 02 2e b6 04 7b c5 d3 2f dc d7 |..........{../..|
+000001f0 68 af 6b 88 90 0a 94 a4 29 65 0b ba b3 da f2 cd |h.k.....)e......|
+00000200 51 93 4f ea b4 f8 54 c7 28 e3 2d 63 d0 62 54 d9 |Q.O...T.(.-c.bT.|
+00000210 27 a0 85 57 7b a2 f2 f5 a5 25 83 1b e2 36 15 06 |'..W{....%...6..|
+00000220 41 ae e1 f9 ca a5 c6 59 2d da 4a ed 10 7b 80 01 |A......Y-.J..{..|
+00000230 06 39 f2 a8 4b 22 37 4d aa 84 79 85 71 29 1b 4e |.9..K"7M..y.q).N|
+00000240 c3 79 af 13 f5 4e 3c 6d fa 8c d7 55 13 2b 48 3d |.y...N<m...U.+H=|
+00000250 9a 79 e2 b4 3f 59 f8 f9 6c d2 39 51 e0 6e c2 c3 |.y..?Y..l.9Q.n..|
+00000260 09 06 d4 e0 4f 76 a6 54 b8 9d ef 30 ba 80 16 03 |....Ov.T...0....|
+00000270 03 00 35 df a1 cc 0f 77 42 24 fe 38 ac ec 25 cf |..5....wB$.8..%.|
+00000280 13 85 03 87 73 b4 c0 d9 97 d0 a8 8e 12 f4 13 61 |....s..........a|
+00000290 42 40 03 a6 b6 6c d3 dd d9 92 f0 e9 bc bc a7 22 |B@...l........."|
+000002a0 64 cf 4b 00 97 71 ac 3b 16 03 03 00 98 f7 61 85 |d.K..q.;......a.|
+000002b0 47 fc 23 b5 34 4b 1f 10 c7 12 51 07 a2 40 40 48 |G.#.4K....Q..@@H|
+000002c0 1c 79 52 3a a7 9d ca 45 62 a2 53 71 bd 23 0a 77 |.yR:...Eb.Sq.#.w|
+000002d0 0b 7f 8c ff f2 51 da 91 07 d7 67 71 bb ec 02 8d |.....Q....gq....|
+000002e0 3f 79 dc d9 af f4 4c 78 3e ac 8d 30 ed eb c9 19 |?y....Lx>..0....|
+000002f0 96 89 a7 0f 7c fb 96 18 84 86 e7 bd e2 35 31 0c |....|........51.|
+00000300 7a 51 d7 94 6b 61 62 7a 6a d8 56 62 e6 cf bf 60 |zQ..kabzj.Vb...`|
+00000310 df 7a c5 ce d3 87 ea 2f 5a ad 90 d4 39 f7 47 8e |.z...../Z...9.G.|
+00000320 8b d3 6b 8e e0 3f 2f 59 71 e4 e6 bf 3f 4a 29 a8 |..k..?/Yq...?J).|
+00000330 60 df 1b 5c 2d 21 ab 0a a5 9f 5a a2 a3 d6 08 3c |`..\-!....Z....<|
+00000340 4a 4b f9 d6 a0 14 03 03 00 11 44 a4 62 7e c1 4a |JK........D.b~.J|
+00000350 4e 56 dd 08 65 b2 ab 12 cd fa 8d 16 03 03 00 20 |NV..e.......... |
+00000360 b4 52 5a e8 33 b6 23 b1 b4 e6 59 da b0 84 52 94 |.RZ.3.#...Y...R.|
+00000370 70 de dc 02 f6 41 e3 27 7c 27 56 6a 7c 92 e3 48 |p....A.'|'Vj|..H|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 c7 92 b3 aa a0 91 21 4f 42 96 0c |...........!OB..|
+00000010 3a 92 c3 53 55 d1 16 03 03 00 20 4b da e5 1c 08 |:..SU..... K....|
+00000020 ce a7 33 f1 a6 c7 47 52 19 68 b4 f5 1d 66 a7 38 |..3...GR.h...f.8|
+00000030 97 45 43 9f ca b5 db 2c 14 fc f4 17 03 03 00 19 |.EC....,........|
+00000040 28 f4 bb bf c1 5a 2d 1e b8 fc c7 fc 55 16 e9 cc |(....Z-.....U...|
+00000050 43 a3 63 58 7e 2c 60 77 23 16 03 03 00 14 2c e6 |C.cX~,`w#.....,.|
+00000060 25 0a b7 26 7b 13 55 62 f1 fe 6e fe 0e 57 53 57 |%..&{.Ub..n..WSW|
+00000070 19 1b |..|
+>>> Flow 11 (client to server)
+00000000 15 03 03 00 12 dd 2b 00 09 fd 8c 7d 21 3d 7c 06 |......+....}!=|.|
+00000010 93 ca c9 21 b2 3e 20 15 03 03 00 12 90 32 4b 3b |...!.> ......2K;|
+00000020 33 4d fd 69 55 81 aa 42 16 ae 47 b9 4c 06 |3M.iU..B..G.L.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
new file mode 100644
index 0000000000..cb964324fd
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 91 a6 bc 02 ab |....Y...U.......|
+00000010 19 62 2c de 45 57 ba 71 c0 b0 4d 78 5e f4 c2 b9 |.b,.EW.q..Mx^...|
+00000020 81 ba 8b d6 b1 9b c8 fb 0c 7c 40 20 dc 66 80 5b |.........|@ .f.[|
+00000030 20 3c 60 65 7f 9e 0c 67 a8 f3 22 c9 c5 48 80 fa | <`e...g.."..H..|
+00000040 02 a1 1a 48 6d 1c 46 07 db 6c 8e 85 cc a8 00 00 |...Hm.F..l......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 f5 fd 54 ea 3e bb 70 |........ ..T.>.p|
+000002d0 fb 8e fb e4 8a 25 1f 9d 3d 9a fb fb 9d ff d1 52 |.....%..=......R|
+000002e0 81 9d b0 ea a1 e6 b0 87 2f 04 01 00 80 77 54 16 |......../....wT.|
+000002f0 98 5d 22 c4 7f 9b 2a 44 dd e4 0d 78 c2 60 6a ad |.]"...*D...x.`j.|
+00000300 91 9d d9 ed 93 0b 4e b4 c6 26 f1 94 6d e0 cc f4 |......N..&..m...|
+00000310 8d fa 9c ec 70 f5 5b ac 80 d7 5e 4f 49 04 bc 24 |....p.[...^OI..$|
+00000320 8e 0a 7d 44 e1 7e 47 1e a8 68 d1 fe 6f 41 0d 4a |..}D.~G..h..oA.J|
+00000330 e5 5b f6 f6 a3 af 76 21 56 1a 25 d2 03 3c f4 dd |.[....v!V.%..<..|
+00000340 0c 13 ce 56 8a 61 6f 5b 8c a1 04 43 82 87 64 20 |...V.ao[...C..d |
+00000350 4a 3b ec 90 d7 59 aa ca 08 3a 39 57 f1 56 57 6a |J;...Y...:9W.VWj|
+00000360 18 c9 14 7f e3 8d 83 0f e2 0b 4d 24 01 16 03 03 |..........M$....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 6b ce 5c 2f df 85 e7 5e fa 51 48 |.... k.\/...^.QH|
+00000040 f9 31 a5 02 64 c7 1e b1 2e f2 6b 86 30 43 23 91 |.1..d.....k.0C#.|
+00000050 76 6b 40 74 2b |vk@t+|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 e7 1e 88 10 2d |.......... ....-|
+00000010 dc 35 6d 2b 4a 91 39 5d 5c 46 ed 2e 45 6f 41 38 |.5m+J.9]\F..EoA8|
+00000020 66 0f 15 58 f8 af d8 a6 6c 99 61 |f..X....l.a|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 ab 2a df 2f 3c 07 6a 24 98 55 0b |......*./<.j$.U.|
+00000010 67 20 2d 92 cd 9a 44 74 da fd 6a |g -...Dt..j|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 d6 fb e7 9a 76 2a 6f e1 e9 33 1a |.........v*o..3.|
+00000010 77 07 fd 7f 98 af 1e 04 43 |w.......C|
+>>> Flow 7 (client to server)
+00000000 15 03 03 00 12 7e e3 20 96 03 31 8c 6a 31 f8 62 |.....~. ..1.j1.b|
+00000010 02 a7 a4 ce 77 83 c1 15 03 03 00 12 b9 91 75 45 |....w.........uE|
+00000020 a5 4a f9 c6 6d b2 5c c3 0a 1a 26 63 00 04 |.J..m.\...&c..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT
index e6187baa3f..a0f6a090af 100644
--- a/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 01 c6 02 00 01 c2 03 03 5d d8 84 38 51 |...........]..8Q|
-00000010 c6 51 9e 6c d3 e0 b2 d7 81 2a 9b 1c 06 0b 11 c8 |.Q.l.....*......|
-00000020 54 90 f3 d1 66 83 7a 68 2f 65 8b 20 ac 8b 35 9a |T...f.zh/e. ..5.|
-00000030 31 25 04 c9 89 31 27 80 8f 10 74 8e 3c 4f 20 bc |1%...1'...t.<O .|
-00000040 3b 46 9d d0 91 f3 ca 7e 0e 59 b7 72 c0 2f 00 01 |;F.....~.Y.r./..|
+00000000 16 03 03 01 c6 02 00 01 c2 03 03 08 db 5c c4 da |.............\..|
+00000010 fe 2c a2 21 0d c4 9e c4 14 b9 e3 15 d7 c5 2c 84 |.,.!..........,.|
+00000020 f2 b8 0e 32 67 9e 72 08 9c 17 6b 20 86 09 60 52 |...2g.r...k ..`R|
+00000030 9d 53 ba c8 8a c3 1a 11 c0 e5 c6 a0 59 49 ed cb |.S..........YI..|
+00000040 e0 6f 0a 56 e9 4f bf 02 2f 23 10 b8 cc a8 00 01 |.o.V.O../#......|
00000050 7a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 12 |z...............|
00000060 01 69 01 67 00 75 00 a4 b9 09 90 b4 18 58 14 87 |.i.g.u.......X..|
00000070 bb 13 a2 cc 67 70 0a 3c 35 98 04 f9 1b df b8 e3 |....gp.<5.......|
@@ -37,77 +38,70 @@
00000190 91 bc f1 b5 40 be 1e 2e e7 5c b4 74 27 ed 8f 9b |....@....\.t'...|
000001a0 02 e9 fa c2 4c ba a2 be 02 21 00 af 43 64 52 71 |....L....!..CdRq|
000001b0 15 29 58 40 91 c7 08 16 96 03 a8 73 a5 65 a0 6c |.)X@.......s.e.l|
-000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 71 |.HVZ.).dm*.....q|
-000001d0 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.|
-000001e0 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....|
-000001f0 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
-00000200 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go|
-00000210 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.|
-00000220 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
-00000230 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.|
-00000240 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&|
-00000250 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl|
-00000260 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U|
-00000270 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H|
-00000280 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...|
-00000290 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.|
-000002a0 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb|
-000002b0 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.|
-000002c0 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV|
-000002d0 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....|
-000002e0 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...|
-000002f0 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.|
-00000300 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........|
-00000310 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.|
-00000320 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.|
-00000330 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....|
-00000340 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..|
-00000350 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U|
-00000360 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM|
-00000370 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0|
-00000380 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f..@....x|
-00000390 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...|
-000003a0 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.|
-000003b0 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........|
-000003c0 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H@.-|
-000003d0 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v|
-000003e0 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.|
-000003f0 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_|
-00000400 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..|
-00000410 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..|
-00000420 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |....@.Q......F.F|
-00000430 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9|
-00000440 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e |.............A..|
-00000450 d1 1c 5c d3 00 41 84 cd f7 e2 78 ad b5 7d 5b f2 |..\..A....x..}[.|
-00000460 23 5b 1a 18 44 3f 86 8e 3e 52 f2 4b b6 7d 84 b4 |#[..D?..>R.K.}..|
-00000470 1d 98 83 8f 2f 58 07 92 1f 58 2a 8d 8c e3 fa b7 |..../X...X*.....|
-00000480 aa 78 7e 33 9a 64 b9 b6 cb 78 94 be 2b c3 ac 04 |.x~3.d...x..+...|
-00000490 01 00 80 65 9f 42 e3 24 5c cd 18 aa 08 8e 6b bf |...e.B.$\.....k.|
-000004a0 39 15 2a a3 e6 42 1c 9d 6b 34 39 a2 2c 58 f5 5f |9.*..B..k49.,X._|
-000004b0 3e fb 2a 4c 01 2b e5 20 4e f5 69 77 c1 62 8f 68 |>.*L.+. N.iw.b.h|
-000004c0 be b4 c4 77 27 c9 4a 97 6d 18 7f 45 fd c9 9e 24 |...w'.J.m..E...$|
-000004d0 19 6b d9 00 c5 52 1a 34 a3 c9 cb eb 92 fc f6 48 |.k...R.4.......H|
-000004e0 3d 89 8a ff 82 be 55 c9 92 e2 24 86 b0 99 c6 e8 |=.....U...$.....|
-000004f0 a5 4c b7 bc 5a e5 f3 81 94 ee 15 47 e7 5e 8c 66 |.L..Z......G.^.f|
-00000500 32 72 7d 81 78 61 fe 25 98 dd 07 a2 92 4c eb ed |2r}.xa.%.....L..|
-00000510 f1 a7 17 16 03 03 00 04 0e 00 00 00 |............|
+000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 59 |.HVZ.).dm*.....Y|
+000001d0 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+000001e0 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+000001f0 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+00000200 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+00000210 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+00000220 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+00000230 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+00000240 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+00000250 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000260 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000270 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000280 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000290 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+000002a0 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y.@.Om..+.....g|
+000002b0 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+000002c0 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+000002d0 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+000002e0 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+000002f0 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+00000300 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+00000310 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+00000320 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+00000330 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+00000340 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+00000350 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000360 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000370 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000380 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000390 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+000003a0 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0.@+[P|
+000003b0 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+000003c0 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+000003d0 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+000003e0 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+000003f0 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+00000400 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F|
+00000410 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+00000420 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+00000430 00 a8 03 00 1d 20 27 94 d8 62 00 f3 3f 21 e6 e1 |..... '..b..?!..|
+00000440 0f 1f 2d 9b 37 4d cf 72 34 48 72 2e 85 46 dd b6 |..-.7M.r4Hr..F..|
+00000450 32 23 64 b3 4b 63 04 01 00 80 82 34 e5 7f 70 51 |2#d.Kc.....4..pQ|
+00000460 42 3b ab 51 61 73 1f 2c 64 04 1d 66 96 ff f9 95 |B;.Qas.,d..f....|
+00000470 86 09 a8 75 11 16 34 05 17 fb 96 9c fb 78 40 4c |...u..4......x@L|
+00000480 10 5b ee 0d 31 a0 77 32 a8 0f 19 ef a4 30 cd 08 |.[..1.w2.....0..|
+00000490 cb f5 ec 36 fa 24 0a ca 0b d8 16 02 d1 34 86 a7 |...6.$.......4..|
+000004a0 f8 e3 cb e6 62 1c cd 40 d6 4f 0c 2f 5b 66 12 6f |....b..@.O./[f.o|
+000004b0 8a 2f c4 ef ac 46 86 44 90 e0 65 38 94 4d 5e df |./...F.D..e8.M^.|
+000004c0 51 a3 40 6e 64 b6 00 6b 88 97 7b 43 78 d9 df 70 |Q.@nd..k..{Cx..p|
+000004d0 fe 66 66 56 82 14 ed ab 08 cd 16 03 03 00 04 0e |.ffV............|
+000004e0 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 f0 4f |.....(.........O|
-00000060 fe 22 53 9e e1 61 f4 45 4e 41 ff 5e e4 63 25 f7 |."S..a.ENA.^.c%.|
-00000070 b2 f6 0a ea 89 75 7f d4 e7 3a cc e8 c2 2c |.....u...:...,|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 7a 58 e1 33 d4 ce ca 57 ef ea b9 |.... zX.3...W...|
+00000040 9d f2 4d ec ce 86 4b e9 c2 b5 64 dd 0f 32 f0 66 |..M...K...d..2.f|
+00000050 65 42 74 d8 59 |eBt.Y|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 ad 49 0a 66 16 |..........(.I.f.|
-00000010 6d 64 42 c2 ab 38 bf 81 3d d9 14 13 d6 69 27 81 |mdB..8..=....i'.|
-00000020 ea 5c 53 fd 6c bf 81 6c 06 81 a5 67 f2 cd ed a3 |.\S.l..l...g....|
-00000030 d4 c2 08 |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 27 df 9b 14 a1 |.......... '....|
+00000010 cd a5 83 5b 6b 30 60 a3 ae 8d 64 56 fe 8e 87 a2 |...[k0`...dV....|
+00000020 ff 1b 54 72 c8 7c b2 85 9d 8a de |..Tr.|.....|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5c ab e3 |.............\..|
-00000010 f9 61 72 9e 44 46 1a 05 e9 00 eb 5b e0 73 22 03 |.ar.DF.....[.s".|
-00000020 9f 90 f9 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 04 28 a4 9d 07 79 95 40 0f f0 eb b9 5d 97 bf 87 |.(...y.@....]...|
-00000040 4a b6 |J.|
+00000000 17 03 03 00 16 c7 bf a9 7a 72 07 27 88 9a ec 1b |........zr.'....|
+00000010 d3 44 f2 20 88 e4 c2 8b 61 86 5c 15 03 03 00 12 |.D. ....a.\.....|
+00000020 35 ab f5 f6 92 f9 db 23 bf f1 8e e8 65 62 cf 48 |5......#....eb.H|
+00000030 91 9d |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM
new file mode 100644
index 0000000000..90541fd16e
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM
@@ -0,0 +1,85 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 8b 01 00 00 87 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 32 00 05 |.............2..|
+00000060 00 05 01 00 00 00 00 00 0a 00 04 00 02 00 1d 00 |................|
+00000070 0b 00 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 |................|
+00000080 01 05 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 |................|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 07 42 b0 44 05 |....Y...U...B.D.|
+00000010 b1 6d 3c f0 60 fe 6a f2 1f 8f 1d 88 de 4b 6a 1b |.m<.`.j......Kj.|
+00000020 4f 72 60 4d 42 a5 f7 77 eb 86 c2 20 99 35 47 07 |Or`MB..w... .5G.|
+00000030 64 60 32 52 2e 1d 54 d5 b7 e2 26 85 72 c1 ec 8d |d`2R..T...&.r...|
+00000040 fb 59 86 91 46 7d ad 16 bd b7 38 94 c0 2f 00 00 |.Y..F}....8../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 cc f6 2e 98 6c e0 8b |........ ....l..|
+000002d0 15 17 63 6f 97 5e 37 6a a7 3c 4b f2 d4 91 e0 87 |..co.^7j.<K.....|
+000002e0 53 1d d3 9e f3 43 a9 21 40 04 01 00 80 3c 35 db |S....C.!@....<5.|
+000002f0 b1 ef 58 96 b4 3f eb 6b d5 0d b7 ab cd 51 8d 57 |..X..?.k.....Q.W|
+00000300 2b fe 3a 7f 72 42 a0 a7 7d 1d db c1 6c cd df de |+.:.rB..}...l...|
+00000310 7f 98 69 b0 0b c1 56 07 34 51 79 dc 1a 52 d1 11 |..i...V.4Qy..R..|
+00000320 ea b4 dd 0f 9d 9a 8c a3 4f 23 da 0e aa dc 2a e1 |........O#....*.|
+00000330 16 51 a4 33 e2 4f f8 34 2d b0 ba f5 f5 ed 3e 24 |.Q.3.O.4-.....>$|
+00000340 04 f0 b9 ab 81 b8 4e 39 88 8f b7 46 2c 60 b8 5c |......N9...F,`.\|
+00000350 6f 4d d4 5d 7a 04 f7 1d 82 98 a2 b1 f9 7e f0 1f |oM.]z........~..|
+00000360 cf a5 e5 28 25 d4 3d b0 32 ea eb 21 c6 16 03 03 |...(%.=.2..!....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 75 70 c8 |....(........up.|
+00000040 c5 ef ae 60 b5 8d ba 98 1a 7d 8d c3 e4 32 fc 33 |...`.....}...2.3|
+00000050 5e 15 cc e2 d7 5d d5 76 52 1a fe ac 1e |^....].vR....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 7f 2b fe 0d 9f |..........(.+...|
+00000010 93 07 fd ee 48 76 09 fb 8d 4c dd 7b b5 b5 26 36 |....Hv...L.{..&6|
+00000020 3e 05 e1 1b a7 dc 0b 4a c0 69 a8 22 33 0b 17 fc |>......J.i."3...|
+00000030 6f ab b8 |o..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 49 61 5c |.............Ia\|
+00000010 db f2 e5 63 23 3a f1 dd 12 3e 61 ed d9 4b 5f b5 |...c#:...>a..K_.|
+00000020 d3 f7 38 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..8.............|
+00000030 af 09 a7 f1 e1 d9 1f 54 d1 35 19 16 b7 23 ce 4e |.......T.5...#.N|
+00000040 3a b1 |:.|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
index 10b7f52bce..11a8a1c8cb 100644
--- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -1,78 +1,76 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 50 32 2f f9 d5 |....0...,..P2/..|
-00000010 8f 83 ac 79 0e 0b e5 65 2c 87 79 01 7d 15 73 00 |...y...e,.y.}.s.|
-00000020 46 7c dc c6 6d 70 0b f3 d2 dc de 00 00 04 00 0a |F|..mp..........|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 47 b4 bd 36 64 |..../...+..G..6d|
+00000010 0a 7d 37 1d 99 ac fd 1c 7a 3f d5 0f 9d 90 e3 59 |.}7.....z?.....Y|
+00000020 64 e4 fb 59 3a 4a 5f 53 d2 af 88 00 00 04 00 0a |d..Y:J_S........|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 48 96 89 e9 d2 e6 c6 |.........H......|
-00000010 eb 9d f8 46 dd c7 d8 01 95 57 76 1a 59 1c 79 21 |...F.....Wv.Y.y!|
-00000020 94 0b 83 b2 c9 5e c1 5f 4f 12 00 10 63 12 d3 f9 |.....^._O...c...|
-00000030 ae ae 31 18 fa b4 33 37 eb b9 23 15 55 7e cf 62 |..1...37..#.U~.b|
-00000040 20 a7 cb eb 69 35 e0 35 32 e4 0a 4c c0 33 e9 7d | ...i5.52..L.3.}|
-00000050 f2 a8 4b e2 fe 90 62 7a 09 df c5 46 03 0c 52 7a |..K...bz...F..Rz|
-00000060 fb 96 dd fd 55 aa e5 be 3c 35 65 03 be e1 51 0f |....U...<5e...Q.|
-00000070 7b b3 05 6b e9 af 9b 0e e4 ea d9 34 69 a5 c2 9a |{..k.......4i...|
-00000080 71 a8 cc 0a 94 ef 91 14 88 14 03 00 00 01 01 16 |q...............|
-00000090 03 00 00 40 0c 34 26 4c cf f0 d4 a0 08 b9 b7 6b |...@.4&L.......k|
-000000a0 0a 69 55 48 91 2c 92 4c 9b e7 66 d0 b8 da 2d e7 |.iUH.,.L..f...-.|
-000000b0 89 ca f5 a4 3d 11 ff 87 22 07 c0 ed 72 9c ad 19 |....=..."...r...|
-000000c0 7d 63 2b 67 43 e3 33 76 a1 ac 69 77 55 bb 60 ba |}c+gC.3v..iwU.`.|
-000000d0 57 00 4e 2a |W.N*|
+00000000 16 03 00 00 84 10 00 00 80 43 4d 76 6b 7f b3 e6 |.........CMvk...|
+00000010 82 18 f9 8a a5 cd 45 ab 8f 1a 1d d4 9a 0a 1d 50 |......E........P|
+00000020 96 f2 08 14 a7 6b e3 ef d1 31 6b 18 d2 f5 ee e3 |.....k...1k.....|
+00000030 cd df 67 23 3d ec 70 09 07 df 32 c2 cd 60 6c 2b |..g#=.p...2..`l+|
+00000040 7f 04 cd b3 77 87 78 e5 90 60 41 0c fc 22 1a 3a |....w.x..`A..".:|
+00000050 82 29 28 92 9c f8 33 3a 72 ee 08 58 55 d5 ea 9c |.)(...3:r..XU...|
+00000060 37 96 a4 92 75 e0 29 8a 18 ad 5a c1 1f 4c aa c7 |7...u.)...Z..L..|
+00000070 49 89 6e ff 29 32 a3 c8 51 e8 50 3f 41 10 36 27 |I.n.)2..Q.P?A.6'|
+00000080 0b 60 a2 96 4b 82 a9 c6 52 14 03 00 00 01 01 16 |.`..K...R.......|
+00000090 03 00 00 40 b3 59 d0 de d1 47 8e 9e 1a 27 16 41 |...@.Y...G...'.A|
+000000a0 f7 38 4e 91 12 a0 71 89 1c 68 29 dc 60 7e 2c 39 |.8N...q..h).`~,9|
+000000b0 45 cb e6 98 8d 43 5e 76 34 ca 5b 86 24 9d 77 0a |E....C^v4.[.$.w.|
+000000c0 90 60 19 75 67 74 3d 95 1d e7 82 ee a8 9f 3a 60 |.`.ugt=.......:`|
+000000d0 8e ac 28 74 |..(t|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 40 dd e1 34 c5 4a |..........@..4.J|
-00000010 96 76 81 49 df 1b 3d 48 cc 6c b0 3b ee 77 a9 62 |.v.I..=H.l.;.w.b|
-00000020 91 b3 16 b0 e1 79 4b 2a 95 d8 54 98 7b 5e ac 0f |.....yK*..T.{^..|
-00000030 07 3b 06 36 e1 38 dc 75 6a af f7 ce a4 b2 3f 9e |.;.6.8.uj.....?.|
-00000040 36 b1 44 ce e9 6c 34 ba ce 97 02 17 03 00 00 18 |6.D..l4.........|
-00000050 5b be 71 2f a1 15 2f e9 9b 83 8e f1 9b e7 5b 4a |[.q/../.......[J|
-00000060 a1 85 13 03 c0 f2 30 0c 17 03 00 00 28 2c d9 9e |......0.....(,..|
-00000070 f4 d2 70 2a 37 76 66 e7 f4 5c c7 55 be d8 82 49 |..p*7vf..\.U...I|
-00000080 77 e0 4f 0f 87 4b c0 b1 f3 d2 a3 63 df 62 bc ee |w.O..K.....c.b..|
-00000090 5c c2 50 2a 96 15 03 00 00 18 8b 0a 68 8a d8 64 |\.P*........h..d|
-000000a0 4e 3f f9 ee c6 b2 21 51 03 10 6b 73 3b 8c a4 bb |N?....!Q..ks;...|
-000000b0 6d f2 |m.|
+00000000 14 03 00 00 01 01 16 03 00 00 40 e8 3e 89 b5 10 |..........@.>...|
+00000010 e4 c9 eb f7 3f 83 e5 6a 7c 04 fd e6 96 69 25 fb |....?..j|....i%.|
+00000020 0b 0b 0e f7 13 4e 99 45 d2 0e 13 22 6b d1 0e 32 |.....N.E..."k..2|
+00000030 30 b5 c4 a2 03 cf 22 59 68 5c cc 63 96 f5 01 f3 |0....."Yh\.c....|
+00000040 2c b3 b5 13 e1 9d 19 45 c0 4f 28 17 03 00 00 18 |,......E.O(.....|
+00000050 2e cb 8c b3 d4 d5 c2 18 fd 6e dc 72 7b b3 4b b8 |.........n.r{.K.|
+00000060 10 56 0a 01 af 55 e8 5a 17 03 00 00 28 3f df 74 |.V...U.Z....(?.t|
+00000070 2f b9 5b a4 43 ec 24 68 ad ff 6c 52 b5 6a 91 0c |/.[.C.$h..lR.j..|
+00000080 be 3b 25 c9 e4 40 59 66 17 cb f0 e7 6b 6e cd 43 |.;%..@Yf....kn.C|
+00000090 ac be b7 62 d0 15 03 00 00 18 43 4d 3c fd 83 6e |...b......CM<..n|
+000000a0 e0 3f ae 40 0c 8a a1 08 d2 74 e2 60 7b d0 97 d5 |.?.@.....t.`{...|
+000000b0 e8 a5 |..|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
index e73381950e..771373c27f 100644
--- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -1,79 +1,77 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 36 b0 f3 52 13 |....0...,..6..R.|
-00000010 00 17 16 8f 6e 44 24 06 84 05 5b 03 e6 8a 55 ee |....nD$...[...U.|
-00000020 75 9c a8 77 9e e0 7b 15 f9 60 6e 00 00 04 00 2f |u..w..{..`n..../|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 26 1e 06 cd 27 |..../...+..&...'|
+00000010 f5 2a b4 8d 00 07 47 16 02 23 aa 5e 92 02 95 4a |.*....G..#.^...J|
+00000020 1a 0b a8 51 8a 6f 4a 31 3c e9 a2 00 00 04 00 2f |...Q.oJ1<....../|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 2d 0b b1 1c 96 72 65 |.........-....re|
-00000010 e5 3b 5b 48 35 91 b8 2e 18 b5 6c 36 a4 91 10 0e |.;[H5.....l6....|
-00000020 15 63 de fb 7e ea 44 cd 2e 2f 37 2c 88 96 30 d4 |.c..~.D../7,..0.|
-00000030 07 ff 02 9b af 84 2c 43 6c 3a 1f 75 17 4c 5e 8b |......,Cl:.u.L^.|
-00000040 4a d9 df 68 fe ad 72 c9 0c f7 a5 0c a1 70 8b 9f |J..h..r......p..|
-00000050 e7 8e 1d 32 61 8e 80 e5 3a 3a 61 ea 22 1a 67 e5 |...2a...::a.".g.|
-00000060 06 6a 5e 0c 65 bd c7 32 9c 13 c1 53 ad 8e f1 be |.j^.e..2...S....|
-00000070 4d 6c 53 89 8f 9c 49 d2 85 58 04 b5 e8 53 b4 82 |MlS...I..X...S..|
-00000080 84 46 9d 70 fa 0a 34 15 1d 14 03 00 00 01 01 16 |.F.p..4.........|
-00000090 03 00 00 40 71 c7 4b ef 6b 7a f4 a2 29 dd c0 4b |...@q.K.kz..)..K|
-000000a0 ef 04 7d ea 1c 31 16 38 ae 85 f9 89 db 2f a8 04 |..}..1.8...../..|
-000000b0 ad 61 b7 33 73 8c 31 9b 72 5a f6 8b 10 71 0c af |.a.3s.1.rZ...q..|
-000000c0 99 89 14 63 b8 19 f8 0e 2c 0f 14 c6 d6 0a bd 4f |...c....,......O|
-000000d0 96 59 0d 60 |.Y.`|
+00000000 16 03 00 00 84 10 00 00 80 66 67 59 2f 21 b9 e3 |.........fgY/!..|
+00000010 0d a9 78 0c 6b fc dc 6f 69 4e f9 00 8b 40 a2 0f |..x.k..oiN...@..|
+00000020 5a d8 8c d2 59 ab 33 78 f6 42 2f fa cf d6 48 7a |Z...Y.3x.B/...Hz|
+00000030 59 30 94 1c 10 49 30 69 4a 6c a2 e5 ce 59 6d e3 |Y0...I0iJl...Ym.|
+00000040 49 0c a7 0a ab 17 8b c6 48 82 71 44 d5 7d 80 e5 |I.......H.qD.}..|
+00000050 6d 45 6c 10 12 01 85 71 ee dc c5 e3 19 41 ed 22 |mEl....q.....A."|
+00000060 11 5c c4 25 c6 90 ad c8 4c 48 45 8d ad 6c f4 ef |.\.%....LHE..l..|
+00000070 fb b4 2b 53 90 cc 78 b0 9e 22 e7 2c 1a 64 0e 8b |..+S..x..".,.d..|
+00000080 d8 57 54 74 c5 33 20 3f 42 14 03 00 00 01 01 16 |.WTt.3 ?B.......|
+00000090 03 00 00 40 18 b6 0a d4 9e 4d fa 8a 67 ce 8e d5 |...@.....M..g...|
+000000a0 51 31 75 65 f1 ff 54 a2 1b 80 c5 c3 a0 fc d2 78 |Q1ue..T........x|
+000000b0 0b 99 3b 65 6c 1d 52 6d a9 9f 64 13 97 d5 2e b1 |..;el.Rm..d.....|
+000000c0 76 0b a0 fb f6 16 f7 72 28 a5 8a 11 a7 46 d5 59 |v......r(....F.Y|
+000000d0 e1 f4 f3 6f |...o|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 40 28 76 de 29 3b |..........@(v.);|
-00000010 48 77 56 f1 e5 97 21 20 88 9c 7d 5e 02 3d bb c9 |HwV...! ..}^.=..|
-00000020 2f b1 ce 2e 65 ac 53 ea a2 06 0e fb cf 53 28 1d |/...e.S......S(.|
-00000030 df b3 24 48 52 7a 28 d6 9e 50 83 64 da 34 c1 f4 |..$HRz(..P.d.4..|
-00000040 c9 bf ec 42 33 c4 8a 6f 89 aa 1c 17 03 00 00 20 |...B3..o....... |
-00000050 f2 af bb 38 4f 37 58 0e c4 2b 28 45 01 45 89 e9 |...8O7X..+(E.E..|
-00000060 31 5a 6d 8d 4d 1b 49 bd 7d 87 8a 62 e6 c8 03 43 |1Zm.M.I.}..b...C|
-00000070 17 03 00 00 30 60 ec e4 6f ec 88 33 d8 89 49 73 |....0`..o..3..Is|
-00000080 3a aa 67 ab 45 9f de c7 3f 0e 39 3d 9a 30 99 9c |:.g.E...?.9=.0..|
-00000090 2d 10 5f f0 7d 70 10 d5 8e ca 18 91 25 e8 9d d1 |-._.}p......%...|
-000000a0 36 b0 a7 90 9b 15 03 00 00 20 63 e9 92 98 7d b1 |6........ c...}.|
-000000b0 9a 88 07 37 b2 27 99 95 b9 16 17 74 c2 42 9c dc |...7.'.....t.B..|
-000000c0 80 32 de f4 f6 87 cb f1 87 d8 |.2........|
+00000000 14 03 00 00 01 01 16 03 00 00 40 6c 5b 64 b5 f9 |..........@l[d..|
+00000010 76 cc 7e 51 72 46 ab 21 17 b3 fb 2b 48 c5 5a 9f |v.~QrF.!...+H.Z.|
+00000020 e6 35 14 ff df c7 a7 4b 5e 5a 9b 82 57 b5 bf 4d |.5.....K^Z..W..M|
+00000030 5f 7c a5 be 67 96 71 3a 63 ad 76 86 66 06 e9 a2 |_|..g.q:c.v.f...|
+00000040 35 39 6f 79 13 21 4b 19 c1 83 0e 17 03 00 00 20 |59oy.!K........ |
+00000050 1a 80 c5 d1 8b 33 79 89 39 fc 11 44 80 33 1a f7 |.....3y.9..D.3..|
+00000060 9f 63 96 5d c9 1a d4 56 2a ee 68 24 68 83 5d ca |.c.]...V*.h$h.].|
+00000070 17 03 00 00 30 7c d4 88 17 d0 10 66 6a b3 61 ed |....0|.....fj.a.|
+00000080 0a b5 72 55 ca fb c4 ec e2 f2 e2 bf 67 dd 3d c9 |..rU........g.=.|
+00000090 01 3b 50 5c 35 ce 28 2d e6 9c 1f 5c 70 14 46 2a |.;P\5.(-...\p.F*|
+000000a0 d8 9e ef 6a 66 15 03 00 00 20 c7 af e1 86 10 30 |...jf.... .....0|
+000000b0 41 73 88 b2 86 02 a8 60 38 61 92 32 11 22 2d 47 |As.....`8a.2."-G|
+000000c0 76 fe 22 9c 76 c2 00 ee e9 03 |v.".v.....|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
index dce3ebe9cd..f5674ccd67 100644
--- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -1,74 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 3c 64 40 96 81 |....0...,..<d@..|
-00000010 b4 90 3d a5 bb 90 8a ba 39 73 4c cd 2d f9 4c 12 |..=.....9sL.-.L.|
-00000020 4c 6e d6 09 43 e3 eb 07 2e 52 1a 00 00 04 00 05 |Ln..C....R......|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 3f cc 8d 3f f0 |..../...+..?..?.|
+00000010 c9 36 6f 43 43 c1 46 45 cd bf e5 ba 02 e6 55 2c |.6oCC.FE......U,|
+00000020 3a 24 4a db cb a8 f2 1d 26 3e ef 00 00 04 00 05 |:$J.....&>......|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 00 e0 40 dd e4 0f 54 |...........@...T|
-00000010 40 66 62 06 72 2a 7a 06 2d a9 0f 16 3b 5c 63 9b |@fb.r*z.-...;\c.|
-00000020 95 82 9c d4 95 57 c0 37 d1 30 6a 33 e1 5a ec 93 |.....W.7.0j3.Z..|
-00000030 12 ec 2a 94 c6 9c b3 6c a3 4f ef cd f1 80 25 a7 |..*....l.O....%.|
-00000040 54 ca 6a 6e b9 80 0b fc f1 e9 60 a0 f5 33 24 3b |T.jn......`..3$;|
-00000050 13 04 9a f1 8a 37 cd 11 cf 95 ae 71 ba 73 8e 00 |.....7.....q.s..|
-00000060 86 17 6a 3b d5 9e a9 04 87 fd 62 ed 4c b5 01 55 |..j;......b.L..U|
-00000070 65 a2 fb e8 1d 86 a5 58 2a ad e7 fd d3 44 2f 7d |e......X*....D/}|
-00000080 25 b7 3b c7 75 39 5c 45 f6 14 03 00 00 01 01 16 |%.;.u9\E........|
-00000090 03 00 00 3c e6 58 15 b2 fb 0d 44 ed 43 d5 ff a8 |...<.X....D.C...|
-000000a0 41 25 83 41 46 da f6 8e 70 34 39 c6 6c 2c ea 1b |A%.AF...p49.l,..|
-000000b0 2a 02 5c 4b e4 87 58 33 6c d0 22 2e ce 85 df 31 |*.\K..X3l."....1|
-000000c0 0d 71 4c 1a f9 9c 64 d7 87 53 eb c9 1a 0a 16 dc |.qL...d..S......|
+00000000 16 03 00 00 84 10 00 00 80 13 5d 75 f0 6d 24 54 |..........]u.m$T|
+00000010 f5 a1 f0 13 86 61 ce ea 66 86 06 eb c8 27 78 9f |.....a..f....'x.|
+00000020 10 0d ef 94 3f 1b fb 8c 11 14 67 2a 0e 2a 1b cf |....?.....g*.*..|
+00000030 ae 5a cb ac b8 b2 ea a8 70 85 ee fd 88 a9 61 a4 |.Z......p.....a.|
+00000040 75 66 86 a5 88 96 a0 0d 6f 77 fe 63 5e 88 60 4d |uf......ow.c^.`M|
+00000050 f6 b7 93 28 99 72 e8 60 ed 64 9a 3f e6 12 ea ee |...(.r.`.d.?....|
+00000060 83 58 d4 0c 19 e0 2b ce b0 b4 fa 73 9f 78 d9 09 |.X....+....s.x..|
+00000070 8c 17 b8 f5 04 e1 de c4 fe a9 1a aa ba 0d be f3 |................|
+00000080 c8 e1 e4 e8 cc 39 4c f0 b9 14 03 00 00 01 01 16 |.....9L.........|
+00000090 03 00 00 3c 1b 70 07 7f ad 8f a7 78 fd e8 eb b2 |...<.p.....x....|
+000000a0 9a 54 86 a2 dd bc fa b6 0a 52 48 24 79 6a 04 f6 |.T.......RH$yj..|
+000000b0 28 80 1f b7 b1 c6 4e 07 a3 52 60 5a 5a 81 14 11 |(.....N..R`ZZ...|
+000000c0 d2 ee 33 71 e7 d3 ba 3e 4b 31 81 f2 f0 49 ee e4 |..3q...>K1...I..|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 3c 17 a2 5b 4a 06 |..........<..[J.|
-00000010 63 6a 4b f9 ef 66 ed 31 f6 87 75 20 8b 08 8d 5d |cjK..f.1..u ...]|
-00000020 0f 72 87 dd 8d db 99 d5 06 42 2b a3 84 77 35 f2 |.r.......B+..w5.|
-00000030 1d 11 ae 0b 0c df ed 10 6e 23 27 93 29 65 25 f6 |........n#'.)e%.|
-00000040 60 b9 76 c8 95 2b 0c 17 03 00 00 21 df 08 e8 1f |`.v..+.....!....|
-00000050 2f ea 5a 61 d6 d4 4a c0 c1 b5 59 bc e1 89 6e 88 |/.Za..J...Y...n.|
-00000060 bb 8d 16 db 64 87 31 6c 2d d6 c7 d2 ed 15 03 00 |....d.1l-.......|
-00000070 00 16 a9 53 32 af 7a a4 88 02 93 6b aa 95 84 4f |...S2.z....k...O|
-00000080 17 5a 97 93 67 87 3b 07 |.Z..g.;.|
+00000000 14 03 00 00 01 01 16 03 00 00 3c 47 20 7c b9 0d |..........<G |..|
+00000010 f8 59 c0 79 25 ae 8a f3 f5 7d 0c f5 62 d4 a5 5b |.Y.y%....}..b..[|
+00000020 f6 08 36 cc 99 21 ac 80 04 48 49 2c 04 7c 87 08 |..6..!...HI,.|..|
+00000030 d3 10 43 a9 6a ec 99 96 99 0a fa cb db 95 6f fe |..C.j.........o.|
+00000040 b1 75 77 1e b7 a9 9d 17 03 00 00 21 1a 2f bc 70 |.uw........!./.p|
+00000050 2c 00 6b 55 e1 e5 81 17 1c b7 a1 11 d7 21 c1 2f |,.kU.........!./|
+00000060 3e 95 f8 48 74 a4 97 0a 9d a2 0b bc d4 15 03 00 |>..Ht...........|
+00000070 00 16 67 0d 6d 69 53 87 92 23 21 51 72 f6 31 73 |..g.miS..#!Qr.1s|
+00000080 db bd 3c e6 f4 12 4c 69 |..<...Li|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
index 9314b90924..3e170818a0 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -1,11 +1,10 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 01 ad 87 94 6b 8a |...._...[.....k.|
-00000010 38 9e 70 d6 94 8a 73 a9 39 d8 d7 25 ab 47 92 4c |8.p...s.9..%.G.L|
-00000020 b1 20 8e 4d f3 7b cd 84 5e 13 c1 00 00 04 c0 0a |. .M.{..^.......|
-00000030 00 ff 02 01 00 00 2d 00 0b 00 04 03 00 01 02 00 |......-.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 4f 01 00 00 4b 03 01 f1 86 d0 c8 69 |....O...K......i|
+00000010 46 0b 0b 89 08 c0 82 c0 f7 f1 9a b6 d2 2b e1 46 |F............+.F|
+00000020 e6 e1 44 65 de 39 0a 68 a8 d5 1c 00 00 04 c0 0a |..De.9.h........|
+00000030 00 ff 01 00 00 1e 00 0b 00 04 03 00 01 02 00 0a |................|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 16 00 00 |................|
+00000050 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -43,41 +42,37 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 d6 0c 00 |{j.9....*.......|
-00000250 00 d2 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 8b |A.Vk.Z...0...B..|
-000002a0 48 d5 a3 a0 35 5c 31 f5 0b e8 72 7c 87 31 79 af |H...5\1...r|.1y.|
-000002b0 7f 12 93 9a f9 df d5 44 bf 08 5a 6b 1c 68 dd 73 |.......D..Zk.h.s|
-000002c0 67 0f 32 41 45 53 bf 74 cf 91 54 e7 7a 88 41 7a |g.2AES.t..T.z.Az|
-000002d0 15 ea 3d e3 b8 93 c0 3f 24 4c fb ee 25 f1 20 80 |..=....?$L..%. .|
-000002e0 02 42 01 ab 97 5f 8b 8d 22 71 f9 f5 a3 59 69 42 |.B..._.."q...YiB|
-000002f0 06 bd 12 f5 61 53 cb c8 a1 b4 90 87 12 94 9b f8 |....aS..........|
-00000300 b3 1d 34 d9 cd 64 20 9c 92 ec b5 72 35 01 44 3a |..4..d ....r5.D:|
-00000310 86 e4 54 46 0d 74 1d 4e d8 41 16 eb ac c3 8a 2f |..TF.t.N.A...../|
-00000320 20 11 ad bc 16 03 01 00 04 0e 00 00 00 | ............|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 b5 0c 00 |{j.9....*.......|
+00000250 00 b1 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 00 8b 30 81 88 02 42 00 ad 93 |._X.;t..0...B...|
+00000280 e2 c2 3d 7e 95 63 17 5d 45 cf cd 27 af d2 db b3 |..=~.c.]E..'....|
+00000290 d0 bc 13 1e 6f 0a 61 3a fb 3c b3 03 61 2c 36 ae |....o.a:.<..a,6.|
+000002a0 4f be 27 e9 43 3c cf 57 9b 82 5e 7d 54 36 ed 7e |O.'.C<.W..^}T6.~|
+000002b0 0b 34 68 26 90 00 20 02 0f c1 18 bc 79 1b 90 02 |.4h&.. .....y...|
+000002c0 42 01 6b 66 9d 56 48 8e 5e 38 93 48 03 6b b9 d7 |B.kf.VH.^8.H.k..|
+000002d0 bd 14 a0 3e 8a 27 81 7f fe 4d e5 8a 12 4d 95 16 |...>.'...M...M..|
+000002e0 ef c7 8d 60 07 1d 22 f8 5d 72 0d cc be c3 51 69 |...`..".]r....Qi|
+000002f0 7a 04 e3 84 e5 ba dd 04 1d d4 4c 6f 9f 6b 12 e0 |z.........Lo.k..|
+00000300 2f 83 3c 16 03 01 00 04 0e 00 00 00 |/.<.........|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 38 ca 59 61 cd |....F...BA.8.Ya.|
-00000010 17 4a cf a8 0b 81 c6 b7 7f 52 dd 95 d7 57 9d 24 |.J.......R...W.$|
-00000020 bb b1 02 af 57 ee b9 f9 c5 a0 c3 20 44 e1 9a e4 |....W...... D...|
-00000030 83 64 7d a1 fa 9d 2e 3b 5e be 0f af ed 96 f3 09 |.d}....;^.......|
-00000040 62 a2 22 21 72 f8 84 89 8a fd 10 14 03 01 00 01 |b."!r...........|
-00000050 01 16 03 01 00 30 bd e6 23 e0 32 b8 4c ef ce 9e |.....0..#.2.L...|
-00000060 22 a5 77 2c f1 7e 2f 8d 8b 9e a5 92 42 f9 0f 02 |".w,.~/.....B...|
-00000070 eb 2e 94 f1 6d a3 24 3f c0 ae bb c0 c4 99 08 51 |....m.$?.......Q|
-00000080 47 28 8b 4e f9 02 |G(.N..|
+00000000 16 03 01 00 25 10 00 00 21 20 18 40 ea d1 e1 17 |....%...! .@....|
+00000010 b6 a2 a5 db 20 13 70 81 90 fc ac e8 96 7c b1 e1 |.... .p......|..|
+00000020 ff 6f 57 1f c1 64 72 94 f7 05 14 03 01 00 01 01 |.oW..dr.........|
+00000030 16 03 01 00 30 05 33 48 f0 2a 3a df df 1d c4 3d |....0.3H.*:....=|
+00000040 87 ea 9d 04 04 eb 84 bf a0 ed bc 56 2f ab 36 52 |...........V/.6R|
+00000050 d5 b2 2c 6f 8c 58 49 51 33 d5 fc df 5d 09 df e9 |..,o.XIQ3...]...|
+00000060 be 20 30 9a 37 |. 0.7|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 11 a9 f0 95 27 |..........0....'|
-00000010 ac 0a b7 8e 0d 42 0a 2a f8 f8 e2 4f 4f 4a 79 d1 |.....B.*...OOJy.|
-00000020 73 e6 4d 42 90 3c 06 f8 7b da 26 cc 58 be 97 f6 |s.MB.<..{.&.X...|
-00000030 41 32 fb 39 2f fa e1 bc 59 2b 45 17 03 01 00 20 |A2.9/...Y+E.... |
-00000040 93 6a a1 a6 a2 e6 be bb be 2f 8f 0c 52 39 1c 6a |.j......./..R9.j|
-00000050 6d 4c af 38 f7 60 8b ad 0e c7 62 0c 8b a4 42 14 |mL.8.`....b...B.|
-00000060 17 03 01 00 30 da b0 1b ef cf 45 86 09 e9 be aa |....0.....E.....|
-00000070 0f 71 af a3 86 d0 0f 2d e8 76 39 9a c4 1f f5 c2 |.q.....-.v9.....|
-00000080 82 0a ee 34 0e a6 3b 19 b8 2c 10 ad fc 03 33 31 |...4..;..,....31|
-00000090 10 42 9b 6e 7b 15 03 01 00 20 ac 73 4d 4b 92 30 |.B.n{.... .sMK.0|
-000000a0 bf 4c bc 77 c1 87 d7 20 ad 82 bd 75 31 82 0d 34 |.L.w... ...u1..4|
-000000b0 cb b2 86 fd 4f 9c 84 a3 80 af |....O.....|
+00000000 14 03 01 00 01 01 16 03 01 00 30 8c b6 5b 83 03 |..........0..[..|
+00000010 c0 d8 83 f7 1d 24 2e ec 39 68 00 91 73 d2 5a 15 |.....$..9h..s.Z.|
+00000020 3f 83 aa e3 6d fd cc 31 58 90 e9 a9 e3 e4 78 5d |?...m..1X.....x]|
+00000030 ce 8e b3 ba cd 71 aa a2 fd f4 7c 17 03 01 00 20 |.....q....|.... |
+00000040 62 98 34 9d 01 13 13 2d 1b 27 3a 4f 10 28 48 d6 |b.4....-.':O.(H.|
+00000050 32 8c 99 2a c8 64 14 6e dc f5 7c 6d 16 59 45 8e |2..*.d.n..|m.YE.|
+00000060 17 03 01 00 30 1e ed f9 40 ad 5c 5d f6 94 c9 fd |....0...@.\]....|
+00000070 a1 ac fc 00 7b 48 9a 59 6d f5 b7 06 a4 66 25 04 |....{H.Ym....f%.|
+00000080 61 33 08 f3 66 86 21 00 fb f3 03 78 83 4c b6 c8 |a3..f.!....x.L..|
+00000090 9d 5e ea f5 7e 15 03 01 00 20 98 d8 f6 2a 79 60 |.^..~.... ...*y`|
+000000a0 8d fb c9 45 2f 27 59 17 a9 79 eb e7 b9 46 f1 57 |...E/'Y..y...F.W|
+000000b0 a6 fa ea e1 d0 23 8c 03 4f 72 |.....#..Or|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
index 33e8063ba6..9590b0daa1 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -1,74 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 8d f4 8c 3d bd |....7...3.....=.|
-00000010 d8 81 53 bb f5 bc 18 69 07 09 0d 05 93 4f 6f eb |..S....i.....Oo.|
-00000020 fa fb 03 65 d4 49 a3 df 9f c3 a5 00 00 04 00 0a |...e.I..........|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 58 71 a3 0c c4 |....9...5..Xq...|
+00000010 b6 b0 33 0a 66 3c eb c6 f4 d9 0e 99 75 d4 9e b6 |..3.f<......u...|
+00000020 03 b4 ae ae ad bc a8 ab 64 a0 27 00 00 04 00 0a |........d.'.....|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 6b 00 e3 47 e3 |...........k..G.|
-00000010 0d 22 44 53 7a b9 d1 14 4e e4 47 17 a1 e2 f5 d2 |."DSz...N.G.....|
-00000020 f7 82 2f 1b e2 3a 60 aa 79 36 fa 74 05 72 66 88 |../..:`.y6.t.rf.|
-00000030 3f 6a 57 8d 10 8a a1 80 3c 74 5b 29 c3 a1 b8 57 |?jW.....<t[)...W|
-00000040 20 cc 75 fc 0e 3c 09 06 46 52 b2 ca b2 cd bf 4c | .u..<..FR.....L|
-00000050 b3 12 2b 59 f1 41 a2 c7 4c 62 c7 61 26 2b 89 fe |..+Y.A..Lb.a&+..|
-00000060 01 9a b6 2b b4 15 75 05 4b f8 5b 04 9a 64 cc 06 |...+..u.K.[..d..|
-00000070 6b 8c 98 6d 51 37 50 b4 69 03 5c 9a ed e3 9a 23 |k..mQ7P.i.\....#|
-00000080 a9 68 e0 56 58 f7 f4 a0 d6 b4 55 14 03 01 00 01 |.h.VX.....U.....|
-00000090 01 16 03 01 00 28 9f ac be d9 6f ab cb 0e 45 8a |.....(....o...E.|
-000000a0 96 71 fd 23 39 b0 02 cc a6 5a 7a 64 e2 29 9f 18 |.q.#9....Zzd.)..|
-000000b0 dc 25 84 ee 76 56 3c cc d9 15 34 16 67 7e |.%..vV<...4.g~|
+00000000 16 03 01 00 86 10 00 00 82 00 80 ab 50 cd 04 9e |............P...|
+00000010 db 19 e4 18 26 ff 59 41 20 02 a5 a2 20 a3 1c 44 |....&.YA ... ..D|
+00000020 02 bc 9a 1c d9 d7 5d 5b 55 fc 2a 4d 2b 03 22 b1 |......][U.*M+.".|
+00000030 de 96 10 84 6f e3 f2 22 2d 6f cb 29 07 43 a6 6e |....o.."-o.).C.n|
+00000040 ce 23 64 f7 72 2b dc 9b c0 6f 7f bd 8e cf e2 7f |.#d.r+...o......|
+00000050 75 12 24 72 23 6b 26 08 69 76 17 c0 21 91 c0 7d |u.$r#k&.iv..!..}|
+00000060 8c 8f 20 83 08 02 0d 73 27 23 91 35 5f 3f e6 56 |.. ....s'#.5_?.V|
+00000070 1d 69 d3 1d 3b 0e fa 60 86 8b 40 ad c0 48 59 60 |.i..;..`..@..HY`|
+00000080 45 eb b0 77 2c 91 94 75 fd 6a d3 14 03 01 00 01 |E..w,..u.j......|
+00000090 01 16 03 01 00 28 8b 25 c1 8f 25 32 b5 cb 74 6d |.....(.%..%2..tm|
+000000a0 08 67 59 a3 ae ae 16 f9 fa 03 f6 54 42 f4 56 3f |.gY........TB.V?|
+000000b0 c4 12 66 f3 1a b0 48 95 24 79 fe 41 a5 d1 |..f...H.$y.A..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 28 f4 cf 23 f8 86 |..........(..#..|
-00000010 83 df 44 af 1c 25 b1 51 84 5b 6a f3 0e 6b 47 5c |..D..%.Q.[j..kG\|
-00000020 2a 59 67 db 42 11 f9 53 58 4e db 6f 00 b2 20 5b |*Yg.B..SXN.o.. [|
-00000030 ae a3 43 17 03 01 00 18 df e0 22 d6 05 ab 79 c7 |..C......."...y.|
-00000040 87 8a 82 83 01 bc 06 45 36 74 4d 1c 40 96 97 5f |.......E6tM.@.._|
-00000050 17 03 01 00 28 49 bd b7 e9 41 6b eb b1 aa 89 60 |....(I...Ak....`|
-00000060 21 91 df bf f4 7a 49 9d 54 04 4a 16 1a d1 44 9a |!....zI.T.J...D.|
-00000070 09 6c 4f 01 3d c0 2f d5 a3 72 a3 b2 fe 15 03 01 |.lO.=./..r......|
-00000080 00 18 5c 7a de a0 ef ed 56 99 99 01 5f b4 32 b3 |..\z....V..._.2.|
-00000090 00 be c6 cc 7e bb 6f 82 7d f7 |....~.o.}.|
+00000000 14 03 01 00 01 01 16 03 01 00 28 ff 69 ed 0f 20 |..........(.i.. |
+00000010 ff e1 42 78 b9 bc a8 61 48 82 08 a0 01 a5 98 91 |..Bx...aH.......|
+00000020 3e 39 d4 6d 17 38 a2 04 18 ed 90 3c f0 cf 6a 9a |>9.m.8.....<..j.|
+00000030 ea c5 45 17 03 01 00 18 b5 76 2c 0e f1 34 51 e5 |..E......v,..4Q.|
+00000040 f5 38 d3 9f c9 c5 d5 19 35 c3 2e ec 18 df 8e c8 |.8......5.......|
+00000050 17 03 01 00 28 47 6f e9 c0 fa b3 21 ec 6c 16 e7 |....(Go....!.l..|
+00000060 71 a8 09 15 17 86 68 1c cf fa ea 37 68 d3 33 ef |q.....h....7h.3.|
+00000070 4a b1 95 46 5b 16 d7 95 f8 13 65 2f 93 15 03 01 |J..F[.....e/....|
+00000080 00 18 1b 0c 09 81 ff fc 6d 82 84 ab 83 98 fc 72 |........m......r|
+00000090 f5 4a a0 eb 08 96 79 01 76 26 |.J....y.v&|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
index e51bc17ee7..c1750292d7 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -1,77 +1,75 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 39 72 8e 06 ed |....7...3..9r...|
-00000010 d2 74 5c 02 74 0e 2b 7a bd 54 ce be 17 a0 4f 1a |.t\.t.+z.T....O.|
-00000020 c5 72 b1 e8 3e 2e 90 68 ff fc 6e 00 00 04 00 2f |.r..>..h..n..../|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 82 f3 04 d5 71 |....9...5......q|
+00000010 d8 65 69 36 46 cb 45 77 b2 ef 00 75 98 e4 16 d2 |.ei6F.Ew...u....|
+00000020 70 f7 3c 97 84 49 ef da 5d cd 64 00 00 04 00 2f |p.<..I..].d..../|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 0e a2 23 fe 89 |.............#..|
-00000010 46 08 20 98 da 4d 91 a4 48 40 ab 03 df 1f 00 67 |F. ..M..H@.....g|
-00000020 f3 fb fb 22 f7 8e d6 65 2c 43 a7 f4 9c 0e 25 cc |..."...e,C....%.|
-00000030 d9 3b b5 58 df bd 93 27 1c df 69 37 27 01 cb 0d |.;.X...'..i7'...|
-00000040 b4 f4 a6 8d 91 fe ef dc 9a e2 09 7c 53 1a 73 6d |...........|S.sm|
-00000050 b9 f6 89 0a 1f 94 f0 26 25 ef 73 54 20 d5 8d 77 |.......&%.sT ..w|
-00000060 36 2e e7 4c 9a f1 4a be ae 6e b6 be 16 10 31 42 |6..L..J..n....1B|
-00000070 9e d2 49 41 2c 32 52 11 bc 85 2d fa 39 80 9b f9 |..IA,2R...-.9...|
-00000080 95 fe e8 88 2a a2 57 65 7e 38 b2 14 03 01 00 01 |....*.We~8......|
-00000090 01 16 03 01 00 30 1c 6f 91 45 16 ed 25 82 ee 5f |.....0.o.E..%.._|
-000000a0 f9 f0 09 0c a4 ad 56 61 e5 b7 a2 05 50 02 b8 80 |......Va....P...|
-000000b0 ef 73 d1 11 3c 25 50 44 0d ba b5 7c fd 5d 7a df |.s..<%PD...|.]z.|
-000000c0 14 62 1b 29 be 29 |.b.).)|
+00000000 16 03 01 00 86 10 00 00 82 00 80 9c a1 18 77 22 |..............w"|
+00000010 f5 a1 cf 4d cc df 27 7c c5 7e 98 24 24 be 2f b2 |...M..'|.~.$$./.|
+00000020 1d d7 b8 2f fe 90 73 d0 fc f6 88 3c 91 a4 bc dc |.../..s....<....|
+00000030 b9 0b 48 0d 55 e5 9f c1 8a 6c 1c 7d 4d a9 12 d5 |..H.U....l.}M...|
+00000040 87 4b 9a 77 74 3d 33 8c c7 17 fb 32 09 df 86 f1 |.K.wt=3....2....|
+00000050 93 cc 17 f9 08 bd bc 0e 38 df 9d 82 ad cc 70 0c |........8.....p.|
+00000060 f5 8b 8d 99 e8 5f 3e e5 a6 c7 c2 6a 67 02 90 82 |....._>....jg...|
+00000070 28 9a 72 e1 3e 77 51 10 84 29 21 09 56 36 f2 6a |(.r.>wQ..)!.V6.j|
+00000080 1d 15 08 7b 44 41 43 59 55 8d 52 14 03 01 00 01 |...{DACYU.R.....|
+00000090 01 16 03 01 00 30 06 5b 20 42 7e 7b 1f 4b 7c 36 |.....0.[ B~{.K|6|
+000000a0 99 bb c6 b4 ea a1 19 3e 02 0c 3b 3a 38 be 80 11 |.......>..;:8...|
+000000b0 29 72 a8 12 92 ad 24 9d bf 01 3e ef 9a f1 db 33 |)r....$...>....3|
+000000c0 3e c1 dc d2 51 b1 |>...Q.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 5e 8c b1 dc 1f |..........0^....|
-00000010 b3 18 85 4a 46 02 fb 34 e4 05 56 78 4c e3 34 63 |...JF..4..VxL.4c|
-00000020 06 08 b4 ee 36 e2 28 ab c9 98 ee 26 4e 5b 5d 42 |....6.(....&N[]B|
-00000030 5f f8 e1 d1 2f 8b c8 ef 5a 65 40 17 03 01 00 20 |_.../...Ze@.... |
-00000040 e7 92 6e b1 60 b9 f8 cd 53 d3 37 5b 44 74 1c af |..n.`...S.7[Dt..|
-00000050 90 93 13 8e 55 25 cc 9f 57 8c f3 06 f7 ba e0 f9 |....U%..W.......|
-00000060 17 03 01 00 30 fc 83 e6 4e 8c 65 8f d1 7c c7 f4 |....0...N.e..|..|
-00000070 8b 68 0d 5d da 8e 49 45 68 ea 4c e3 7f 7d 84 87 |.h.]..IEh.L..}..|
-00000080 2f 63 e0 fb 43 24 04 cd e2 38 32 50 0a 4c 43 ce |/c..C$...82P.LC.|
-00000090 3b 12 a5 6b 99 15 03 01 00 20 2a 42 d8 57 26 79 |;..k..... *B.W&y|
-000000a0 51 ee 79 9d b2 83 b8 49 a4 e9 a2 08 34 73 c4 f5 |Q.y....I....4s..|
-000000b0 53 21 4b 78 ec 5b ce b4 4e a0 |S!Kx.[..N.|
+00000000 14 03 01 00 01 01 16 03 01 00 30 2e d5 04 91 6d |..........0....m|
+00000010 32 12 8b 41 4a 46 2c f3 7f d4 16 0a 21 c2 ac 88 |2..AJF,.....!...|
+00000020 09 a0 b5 0d 65 4e 44 e1 92 5a ae b8 3f 61 1f 35 |....eND..Z..?a.5|
+00000030 ab 3a fe bd f8 3c 2c 42 dd 68 0f 17 03 01 00 20 |.:...<,B.h..... |
+00000040 6e d4 08 98 bf b7 18 84 ee 68 f8 17 88 c5 13 7a |n........h.....z|
+00000050 73 e0 c6 ca 0d 21 4d 6b 44 dc 94 36 6c e4 a0 2f |s....!MkD..6l../|
+00000060 17 03 01 00 30 a0 45 d0 88 5d 96 48 26 46 37 33 |....0.E..].H&F73|
+00000070 f6 48 f3 38 2e 38 d7 b6 ef d5 25 bf f3 1b b6 78 |.H.8.8....%....x|
+00000080 32 a7 9c fe be 55 35 f2 07 5b b7 14 87 89 80 f2 |2....U5..[......|
+00000090 cc d5 cb c8 57 15 03 01 00 20 80 2a 8e 6c b8 5a |....W.... .*.l.Z|
+000000a0 41 b4 ae 56 ca 3f 8b a2 e1 ea a0 55 64 b5 60 44 |A..V.?.....Ud.`D|
+000000b0 8f de 33 c6 37 f7 df b5 d9 c3 |..3.7.....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
index 8d5446341b..3d788c35d2 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -1,71 +1,69 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 b3 82 99 50 b0 |....7...3.....P.|
-00000010 1e 7a 46 48 9d 8e 93 32 3b 01 bc 50 e9 5c eb 91 |.zFH...2;..P.\..|
-00000020 25 4b c1 ea 0a 91 c9 b3 2b 54 90 00 00 04 00 05 |%K......+T......|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 71 34 00 f7 c4 |....9...5..q4...|
+00000010 e6 94 b4 ca f2 af d5 0a 82 ce d4 f6 b7 4a a7 d1 |.............J..|
+00000020 1a 88 65 b2 3c b2 6c ec f7 eb 4a 00 00 04 00 05 |..e.<.l...J.....|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 05 1c 93 2a 69 |..............*i|
-00000010 f7 0b 1d 59 ea ca c2 4a b1 7c ef 22 4c 7b 31 5f |...Y...J.|."L{1_|
-00000020 18 8d 32 b6 db 75 8c f8 45 07 27 e1 9f 3f 9d 0b |..2..u..E.'..?..|
-00000030 02 ac 2c 3f aa bf 79 fb d4 af 98 0c b2 c0 03 4b |..,?..y........K|
-00000040 86 26 c3 30 f3 ea 2b 1a ab 70 90 8d 01 2b 0e ff |.&.0..+..p...+..|
-00000050 4c 10 9a 29 75 cb 14 bb 85 80 98 35 fb 82 e8 b5 |L..)u......5....|
-00000060 80 6f 9d e6 3b b6 14 36 bb 61 8e 18 f2 6b da 09 |.o..;..6.a...k..|
-00000070 71 9c 6d 1e c3 60 a9 c5 8b 4e 77 41 db ec 12 49 |q.m..`...NwA...I|
-00000080 a4 c2 e2 10 ce 7f 18 05 b9 74 aa 14 03 01 00 01 |.........t......|
-00000090 01 16 03 01 00 24 3d 90 d0 f6 6f 15 94 05 a0 fb |.....$=...o.....|
-000000a0 43 83 55 b5 b1 ef e5 fd fc 00 d3 d5 25 b4 7c 9f |C.U.........%.|.|
-000000b0 e0 82 99 2a 6d 5a 26 7c 05 21 |...*mZ&|.!|
+00000000 16 03 01 00 86 10 00 00 82 00 80 a5 75 5a 20 2c |............uZ ,|
+00000010 31 f7 61 dc 73 c7 f6 4c 06 d2 b9 c0 e8 5f cc 0c |1.a.s..L....._..|
+00000020 51 70 0a 30 b2 8a bb 3b 4c 37 f6 d3 38 da 13 48 |Qp.0...;L7..8..H|
+00000030 90 4f fe 41 ec 53 3c fb 07 26 77 68 07 a0 fb 71 |.O.A.S<..&wh...q|
+00000040 b6 cc 3c cd b4 64 03 08 3a 76 97 6e 6c f1 b4 a9 |..<..d..:v.nl...|
+00000050 af f4 e0 ce bf 36 b9 8e 37 12 de 5b ac 24 06 63 |.....6..7..[.$.c|
+00000060 e2 fb 13 33 be 3b 8d 93 e3 10 95 29 21 b2 22 77 |...3.;.....)!."w|
+00000070 cb 95 b2 13 b3 76 47 98 13 1b a8 cc 50 47 ed 50 |.....vG.....PG.P|
+00000080 f0 cc ca 5a c6 a0 1e c9 9c 97 58 14 03 01 00 01 |...Z......X.....|
+00000090 01 16 03 01 00 24 e7 fd a2 7e fd 6f 53 da 29 68 |.....$...~.oS.)h|
+000000a0 c3 49 2e e9 69 a1 94 b9 e4 a0 cb a2 94 14 a6 42 |.I..i..........B|
+000000b0 df 75 1e da 95 e5 60 e3 35 f1 |.u....`.5.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 28 d0 1f ec 1d |..........$(....|
-00000010 9e 1d e3 80 6b 6d 3e 8b c5 f7 9c 14 a9 0b c3 53 |....km>........S|
-00000020 fd 48 d0 b3 eb d1 49 97 97 71 e9 36 b9 e6 3a 17 |.H....I..q.6..:.|
-00000030 03 01 00 21 c3 b6 2e 02 05 86 0f 57 04 dd 88 33 |...!.......W...3|
-00000040 0a ed 1d d5 a8 0f 55 54 c5 8c 87 5b 11 b7 80 7f |......UT...[....|
-00000050 30 79 e0 64 ee 15 03 01 00 16 b1 50 de 3d 18 05 |0y.d.......P.=..|
-00000060 2f db 37 4c db 62 f1 c8 d5 19 ca c2 fb a5 8a 37 |/.7L.b.........7|
+00000000 14 03 01 00 01 01 16 03 01 00 24 44 a6 c8 7b 5f |..........$D..{_|
+00000010 b9 4e c2 62 2d e0 c3 9f 76 0f b3 e5 f5 07 b7 c0 |.N.b-...v.......|
+00000020 93 cd 1f 32 3c 0a 7a 83 57 4a 24 59 ac 95 f9 17 |...2<.z.WJ$Y....|
+00000030 03 01 00 21 6f 02 76 2e 70 82 a0 6c 11 ce 3c b8 |...!o.v.p..l..<.|
+00000040 dd d3 9e 2a ee ce d7 7f 63 1a 5b 35 d0 46 68 7d |...*....c.[5.Fh}|
+00000050 21 6e 5b 64 fc 15 03 01 00 16 81 56 32 7d 51 e4 |!n[d.......V2}Q.|
+00000060 08 53 85 45 65 c3 87 ac b0 58 70 4f 6f f7 64 4e |.S.Ee....XpOo.dN|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
index a6e2137e50..209e6216cf 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
@@ -1,17 +1,10 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 cf 01 00 00 cb 03 02 ee 33 c1 3f a6 |............3.?.|
-00000010 62 ba a6 4f c7 32 25 0f 15 66 f7 35 a2 cf c0 cd |b..O.2%..f.5....|
-00000020 48 93 77 1c 04 1f fb 65 41 37 ca 00 00 70 c0 14 |H.w....eA7...p..|
-00000030 c0 0a 00 39 00 38 00 37 00 36 00 88 00 87 00 86 |...9.8.7.6......|
-00000040 00 85 c0 0f c0 05 00 35 00 84 c0 13 c0 09 00 33 |.......5.......3|
-00000050 00 32 00 31 00 30 00 9a 00 99 00 98 00 97 00 45 |.2.1.0.........E|
-00000060 00 44 00 43 00 42 c0 0e c0 04 00 2f 00 96 00 41 |.D.C.B...../...A|
-00000070 00 07 c0 11 c0 07 c0 0c c0 02 00 05 00 04 c0 12 |................|
-00000080 c0 08 00 16 00 13 00 10 00 0d c0 0d c0 03 00 0a |................|
-00000090 00 15 00 12 00 0f 00 0c 00 09 00 ff 56 00 02 01 |............V...|
-000000a0 00 00 31 00 0b 00 04 03 00 01 02 00 0a 00 1c 00 |..1.............|
-000000b0 1a 00 17 00 19 00 1c 00 1b 00 18 00 1a 00 16 00 |................|
-000000c0 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 23 00 00 00 |............#...|
-000000d0 0f 00 01 01 |....|
+00000000 16 03 01 00 63 01 00 00 5f 03 02 6e 78 cc 6a ea |....c..._..nx.j.|
+00000010 13 aa a8 20 76 7d 32 ca c7 3f be 88 36 ae fb c3 |... v}2..?..6...|
+00000020 ca 95 35 70 54 20 3b 18 3b ba 82 00 00 14 c0 0a |..5pT ;.;.......|
+00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..|
+00000040 56 00 01 00 00 22 00 0b 00 04 03 00 01 02 00 0a |V...."..........|
+00000050 00 0a 00 08 00 1d 00 17 00 19 00 18 00 23 00 00 |.............#..|
+00000060 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 15 03 02 00 02 02 56 |......V|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
index b3916f9fd1..18debc470c 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -1,71 +1,69 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 02 95 4a cf f5 14 |....7...3...J...|
-00000010 56 9b d6 be 0c ba 0d b2 ad 65 47 d2 c6 ce 84 c9 |V........eG.....|
-00000020 f4 80 2a 4e 75 df ff 48 cf 48 9b 00 00 04 00 05 |..*Nu..H.H......|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 02 15 67 73 bf 3f |....9...5...gs.?|
+00000010 6f 15 30 c2 34 2e c6 1b 23 3a 42 45 4d d9 87 a2 |o.0.4...#:BEM...|
+00000020 e7 b8 de 1c b8 2b cc 21 7a 0b a1 00 00 04 00 05 |.....+.!z.......|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 02 00 31 02 00 00 2d 03 02 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 02 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 86 10 00 00 82 00 80 19 c3 d4 f2 e4 |................|
-00000010 bf 4a 52 90 a4 65 f6 e7 29 1a 7f ef 0e a4 1e b4 |.JR..e..).......|
-00000020 c2 df b2 83 43 4a 1a f4 b6 cd 51 a5 24 62 3f e1 |....CJ....Q.$b?.|
-00000030 fb 5f 7e b1 10 08 3b 8a ab eb 3a a3 72 ba 31 1c |._~...;...:.r.1.|
-00000040 23 bd ef 2e 3d 13 dc 61 88 a6 af ca 80 82 5d e4 |#...=..a......].|
-00000050 d6 a2 d3 13 80 87 c6 ad a5 13 4e f1 b6 a0 5d fa |..........N...].|
-00000060 ed a7 0d 37 58 f1 54 38 18 f5 be db 90 9f 07 4a |...7X.T8.......J|
-00000070 67 25 c9 8d 9d 5e 07 62 ca db 72 74 b5 bd a0 ed |g%...^.b..rt....|
-00000080 d0 95 9f 3e cd 37 b8 96 df df 3b 14 03 02 00 01 |...>.7....;.....|
-00000090 01 16 03 02 00 24 80 53 7a 8f 23 06 a7 6b e6 be |.....$.Sz.#..k..|
-000000a0 61 c2 1a c8 35 30 6b e2 2f 82 f3 46 ff e3 1d bd |a...50k./..F....|
-000000b0 68 e9 a2 78 49 33 05 ca d9 41 |h..xI3...A|
+00000000 16 03 02 00 86 10 00 00 82 00 80 75 8e 85 93 be |...........u....|
+00000010 53 df e0 4f 65 92 ed 3d 58 34 f8 06 fd 36 e4 5a |S..Oe..=X4...6.Z|
+00000020 f7 7a 59 88 f6 ac bd de 21 ed c4 04 0d 35 19 cd |.zY.....!....5..|
+00000030 ff 3b 9f c4 bc 93 4f 21 2a 36 a3 99 a4 6f eb 1e |.;....O!*6...o..|
+00000040 7b b4 a8 a7 6d 69 a5 93 b6 e3 d2 2d be 7a c8 f3 |{...mi.....-.z..|
+00000050 9f 25 9e f9 51 75 d9 4f 05 41 0e 17 56 31 4e 3f |.%..Qu.O.A..V1N?|
+00000060 c0 15 d8 c4 29 4d e5 92 f9 ed 50 b6 88 f1 41 ea |....)M....P...A.|
+00000070 cb 5a 8c 50 12 78 16 e7 21 b6 11 ca 2c 49 cf b6 |.Z.P.x..!...,I..|
+00000080 d2 1a 16 28 f7 08 b5 c9 61 e0 18 14 03 02 00 01 |...(....a.......|
+00000090 01 16 03 02 00 24 a1 cf 1b 5d dc 4c 9c 2c d7 39 |.....$...].L.,.9|
+000000a0 af 13 e9 04 48 c0 2a aa 6f 3a 9c fb 9e 0a 25 55 |....H.*.o:....%U|
+000000b0 7e 82 3d 1b 78 d1 e3 e0 f5 30 |~.=.x....0|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 24 8f 06 3e 7b 8c |..........$..>{.|
-00000010 fb f2 3d 9e 5c a9 46 56 79 2a 3a ba ad 25 30 57 |..=.\.FVy*:..%0W|
-00000020 f9 f1 16 70 51 5d 73 7e 47 74 8d c0 84 b0 31 17 |...pQ]s~Gt....1.|
-00000030 03 02 00 21 76 09 88 df 7e f7 2f c9 3d 86 b9 30 |...!v...~./.=..0|
-00000040 b0 5c ac ea db c6 d0 d5 69 55 91 7b a1 72 0b 4d |.\......iU.{.r.M|
-00000050 7d ae 6f aa 50 15 03 02 00 16 8c 31 73 86 1a c7 |}.o.P......1s...|
-00000060 ef 08 52 8a 7d 30 b8 00 3b 62 4d 21 7b 81 2c 76 |..R.}0..;bM!{.,v|
+00000000 14 03 02 00 01 01 16 03 02 00 24 7b 68 71 56 0f |..........${hqV.|
+00000010 a5 46 1c 13 34 81 b5 b6 ba 29 fb 41 46 dc fe 78 |.F..4....).AF..x|
+00000020 cc 0b 2d 75 bd fe c1 55 45 b1 fc 04 28 5e b1 17 |..-u...UE...(^..|
+00000030 03 02 00 21 0b fa a9 2f 9e 82 5b 77 30 c2 27 88 |...!.../..[w0.'.|
+00000040 f5 f3 50 47 7b 62 4c 7a d4 07 71 74 46 da 24 de |..PG{bLz..qtF.$.|
+00000050 bf 3f 56 a7 9b 15 03 02 00 16 85 26 8a 89 33 21 |.?V........&..3!|
+00000060 36 ce 69 83 84 50 fc 8f 99 b3 43 ad 6b 14 1e b2 |6.i..P....C.k...|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
index df832d7dea..3e90ebd90f 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,109 +1,94 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 4d 01 00 01 49 03 03 ac 76 61 d8 20 |....M...I...va. |
-00000010 b3 c3 1d c2 3d c2 a4 b9 e2 46 a2 a1 0a 5e 08 56 |....=....F...^.V|
-00000020 4a aa 59 43 42 d6 21 9c 46 0c 21 00 00 b6 c0 30 |J.YCB.!.F.!....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......|
-00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................|
-00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot|
-00000150 6f 31 |o1|
+00000000 16 03 01 00 bf 01 00 00 bb 03 03 18 c9 32 10 f3 |.............2..|
+00000010 be ff a8 60 c5 2a 03 cb 25 8a b3 54 8d 70 27 90 |...`.*..%..T.p'.|
+00000020 74 1e 15 3e 61 48 9b be f0 77 1f 00 00 38 c0 2c |t..>aH...w...8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 5a 00 0b 00 04 03 00 |.5./.....Z......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........|
+00000090 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000a0 03 03 02 01 02 02 02 03 00 10 00 10 00 0e 06 70 |...............p|
+000000b0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
+000000c0 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 42 02 00 00 3e 03 03 00 00 00 00 00 |....B...>.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
00000030 16 00 23 00 00 ff 01 00 01 00 00 10 00 09 00 07 |..#.............|
-00000040 06 70 72 6f 74 6f 31 16 03 03 02 71 0b 00 02 6d |.proto1....q...m|
-00000050 00 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 |..j..g0..c0.....|
-00000060 02 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d |.......s......0.|
-00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 |..*.H........0+1|
-00000080 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-00000090 20 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 | TESTING1.0...U.|
-000000a0 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 |...Go Root0...15|
-000000b0 30 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 |0101000000Z..250|
-000000c0 31 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 |101000000Z0&1.0.|
-000000d0 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 |..U....Google TE|
-000000e0 53 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 |STING1.0...U....|
-000000f0 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |Go0..0...*.H....|
-00000100 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af |........0.......|
-00000110 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 |... ..el..D..;E.|
-00000120 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a |..m..cM...jb5..J|
-00000130 f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 |..|..%^zd1f.....|
-00000140 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 |..k.v.._A.nV....|
-00000150 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da |.<.9!f=+........|
-00000160 b7 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 |.......!P.....k.|
-00000170 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 |K......l..D..!..|
-00000180 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 |}..M........G...|
-00000190 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d |.......0..0...U.|
-000001a0 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d |..........0...U.|
-000001b0 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 |%..0...+........|
-000001c0 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 |.+.......0...U..|
-000001d0 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 |.....0.0...U....|
-000001e0 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e |...P..o...TMn.i^|
-000001f0 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf |..0...U.#..0....|
-00000200 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 |=..f..@....xH.A0|
-00000210 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d |...U....0...exam|
-00000220 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 |ple.golang0...*.|
-00000230 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af |H.............|.|
-00000240 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 |.U...Y1.H@.-....|
-00000250 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 |....|..0}<.v.O=.|
-00000260 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc |..-3$k.{.gY.!...|
-00000270 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 |w...n.-.5.d_">c.|
-00000280 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 |k....m...1..8.;.|
-00000290 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 |.,...Qv..O......|
-000002a0 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 |@.Q......F.F.O..|
-000002b0 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 |...A4......9....|
-000002c0 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d |.........A...7..|
-000002d0 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-000002e0 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-000002f0 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000300 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 aa |..h.A.Vk.Z......|
-00000310 8c a6 e1 51 65 fc 99 37 cf 63 d8 fd 04 52 d5 50 |...Qe..7.c...R.P|
-00000320 1f 0a f5 90 58 48 19 8d d8 0b 64 23 e4 24 56 b4 |....XH....d#.$V.|
-00000330 e5 87 0f 88 a1 7a 29 fa 88 79 99 75 6d 53 a9 50 |.....z)..y.umS.P|
-00000340 a4 9c b9 47 c2 51 87 10 b9 a5 e3 6f a9 38 b8 83 |...G.Q.....o.8..|
-00000350 0d 39 b5 28 27 5f ec 9d a3 2d 1c 53 6b da 93 0d |.9.('_...-.Sk...|
-00000360 cc cf 0c 27 7e d2 f0 05 d5 c0 04 dc 6d d4 2e 03 |...'~.......m...|
-00000370 a7 16 98 58 e4 8d fd 14 6b bb 0c 09 b0 16 35 9e |...X....k.....5.|
-00000380 78 3a 29 21 b5 2f 13 37 94 ae f7 fe 54 89 c0 16 |x:)!./.7....T...|
-00000390 03 03 00 04 0e 00 00 00 |........|
+00000040 06 70 72 6f 74 6f 31 16 03 03 02 59 0b 00 02 55 |.proto1....Y...U|
+00000050 00 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 |..R..O0..K0.....|
+00000060 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d |.........?.[..0.|
+00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 |..*.H........0.1|
+00000080 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e |.0...U....Go1.0.|
+00000090 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
+000000a0 17 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 |..160101000000Z.|
+000000b0 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a |.250101000000Z0.|
+000000c0 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 |1.0...U....Go1.0|
+000000d0 09 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 |...U....Go0..0..|
+000000e0 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+000000f0 30 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 |0.......F}...'.H|
+00000100 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a |..(!.~...]..RE.z|
+00000110 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 |6G....B[.....y.@|
+00000120 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e |.Om..+.....g....|
+00000130 d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 |."8.J.ts+.4.....|
+00000140 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b |.t{.X.la<..A..++|
+00000150 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 |$#w[.;.u]. T..c.|
+00000160 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 |..$....P....C...|
+00000170 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 |ub...R.........0|
+00000180 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 |..0...U.........|
+00000190 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b |..0...U.%..0...+|
+000001a0 06 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 |.........+......|
+000001b0 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 |.0...U.......0.0|
+000001c0 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 |...U..........CC|
+000001d0 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d |>I..m....`0...U.|
+000001e0 23 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb |#..0...H.IM.~.1.|
+000001f0 a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 |.....n{0...U....|
+00000200 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 |0...example.gola|
+00000210 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |ng0...*.H.......|
+00000220 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba |......0.@+[P.a..|
+00000230 e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac |.SX...(.X..8....|
+00000240 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 |1Z..f=C.-...... |
+00000250 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa |d8.$:....}.@ ._.|
+00000260 d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 |..a..v......\...|
+00000270 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 |..l..s..Cw......|
+00000280 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 |.@.a.Lr+...F..M.|
+00000290 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 |..>...B...=.`.\!|
+000002a0 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 |.;..............|
+000002b0 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb |. /.}.G.bC.(.._.|
+000002c0 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb |).0.........._X.|
+000002d0 3b 74 05 01 00 80 2e c1 51 a1 e8 92 a6 bb ad 1e |;t......Q.......|
+000002e0 4d f1 22 c5 e7 10 e6 31 1d 78 61 8a 22 a3 93 84 |M."....1.xa."...|
+000002f0 58 d6 5a c6 94 d0 da 6c 6a 35 d1 31 ea 1b 7e 55 |X.Z....lj5.1..~U|
+00000300 d6 35 a3 b7 42 e4 04 f8 31 15 15 88 5f 91 a8 7e |.5..B...1..._..~|
+00000310 3e 73 52 8f 32 50 2e ad 95 44 83 b6 88 d6 18 99 |>sR.2P...D......|
+00000320 cf 86 57 97 c0 b2 a0 91 ee a7 ac f8 38 4b 1c 8e |..W.........8K..|
+00000330 a4 58 59 4a f6 fc 88 a4 02 ed c8 04 1a 8b 7b 9e |.XYJ..........{.|
+00000340 83 91 72 ca 1e 1c e0 76 58 73 89 3a 7d 12 c5 ef |..r....vXs.:}...|
+00000350 f8 f7 45 dc ca c4 16 03 03 00 04 0e 00 00 00 |..E............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 35 ca 56 91 15 |....F...BA.5.V..|
-00000010 4f dd af 97 f2 2d fb df 54 2b 80 98 18 bb 33 54 |O....-..T+....3T|
-00000020 3f 7e 66 21 d3 81 38 f9 a4 b5 b9 a6 46 9a 52 8b |?~f!..8.....F.R.|
-00000030 98 f7 81 1f 77 81 78 38 01 c5 3b fb 7a b7 53 e7 |....w.x8..;.z.S.|
-00000040 ae c3 4c 2e 73 f4 8e 3a 36 0d 43 14 03 03 00 01 |..L.s..:6.C.....|
-00000050 01 16 03 03 00 28 38 26 8e 03 ad 81 9b a0 41 d9 |.....(8&......A.|
-00000060 c0 11 3f 36 dc 6b ab 6c 29 dc df 02 a3 fe b0 0f |..?6.k.l).......|
-00000070 2e b1 c6 44 39 42 d5 ef 29 30 d8 e0 f1 f9 |...D9B..)0....|
+00000000 16 03 03 00 25 10 00 00 21 20 be 4e 0d d5 31 aa |....%...! .N..1.|
+00000010 27 13 df 73 d3 8d 17 8c b3 5f 44 61 7b 01 b6 99 |'..s....._Da{...|
+00000020 7b ba b3 5d bf d4 be 3c 87 26 14 03 03 00 01 01 |{..]...<.&......|
+00000030 16 03 03 00 28 9c 86 e0 30 d4 a5 ec 0c 9e a6 08 |....(...0.......|
+00000040 ce 8a 7a ff ef be 52 0c 56 86 62 de 49 09 a1 18 |..z...R.V.b.I...|
+00000050 aa 62 e5 e3 d3 2e 4a 24 c9 ef 44 c9 67 |.b....J$..D.g|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 fb fb 41 b1 31 e9 71 75 43 c3 74 |o...a..A.1.quC.t|
-00000040 a1 a0 ac fb 97 b7 69 ee a6 2f e3 a3 dd 9f de e4 |......i../......|
-00000050 80 9d d7 69 1a 2c 0b b4 02 bd ef e2 6a c1 ca 30 |...i.,......j..0|
-00000060 8b 9d 60 f9 fe 33 94 53 3a 14 a3 1a aa 5a ba ff |..`..3.S:....Z..|
-00000070 1e 94 fd 4f e7 90 0b 09 ee 80 f3 d6 d5 c0 48 83 |...O..........H.|
-00000080 98 20 d7 a4 07 99 e0 14 03 03 00 01 01 16 03 03 |. ..............|
-00000090 00 28 00 00 00 00 00 00 00 00 0d 66 de 91 4a 97 |.(.........f..J.|
-000000a0 21 c6 d2 d7 df 68 9b 7e f6 43 73 02 66 b3 5a d6 |!....h.~.Cs.f.Z.|
-000000b0 92 48 c2 c1 11 fc cd 1e 2e 4b 17 03 03 00 25 00 |.H.......K....%.|
-000000c0 00 00 00 00 00 00 01 72 0c 48 75 fa b2 8b 23 09 |.......r.Hu...#.|
-000000d0 be 76 36 a4 bc e0 62 ef bd 79 8e de 6b 39 4b 55 |.v6...b..y..k9KU|
-000000e0 8d 3c ca 14 15 03 03 00 1a 00 00 00 00 00 00 00 |.<..............|
-000000f0 02 74 5f 79 31 41 4f f5 4d 02 96 bc c3 9a 85 92 |.t_y1AO.M.......|
-00000100 44 e1 76 |D.v|
+00000030 6f ec 80 83 61 da 3d a1 df 0d 11 25 4b 66 55 09 |o...a.=....%KfU.|
+00000040 af 7a c1 82 b9 ea 2f 9f 5c f4 0a 62 15 62 c2 32 |.z..../.\..b.b.2|
+00000050 c6 37 51 5b bb 19 14 f8 73 f8 fb 82 00 ef 19 21 |.7Q[....s......!|
+00000060 e2 52 7d ab 0a 33 94 df 78 54 ba 6c 5e 94 eb 16 |.R}..3..xT.l^...|
+00000070 ad 85 01 ca d5 98 8f 8e b7 04 7e 9a 3c 35 c0 e5 |..........~.<5..|
+00000080 8f cf 27 6d b4 12 c2 14 03 03 00 01 01 16 03 03 |..'m............|
+00000090 00 28 00 00 00 00 00 00 00 00 75 da b5 10 2e 7c |.(........u....||
+000000a0 39 ec 3d 98 12 fb 5d 15 81 79 f3 c7 b1 e4 e0 54 |9.=...]..y.....T|
+000000b0 ed 27 6e bc c3 81 a0 74 7e 38 17 03 03 00 25 00 |.'n....t~8....%.|
+000000c0 00 00 00 00 00 00 01 bf 81 cc 93 49 4f b2 59 8b |...........IO.Y.|
+000000d0 53 4a 61 96 04 00 4b ac 34 d5 bd 5a 94 44 18 5b |SJa...K.4..Z.D.[|
+000000e0 7d 81 dc 05 15 03 03 00 1a 00 00 00 00 00 00 00 |}...............|
+000000f0 02 bd 32 d5 cf 4d 13 61 6a 77 8b 3e 51 b3 13 84 |..2..M.ajw.>Q...|
+00000100 e6 1a 23 |..#|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index 35bfdc1062..d40300e839 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,108 +1,94 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 4d 01 00 01 49 03 03 73 f2 f2 44 4f |....M...I..s..DO|
-00000010 87 05 77 e2 e7 07 ca c7 d4 36 37 4e d9 17 ba ff |..w......67N....|
-00000020 b0 e1 47 65 f8 7f fd 7a b4 85 39 00 00 b6 c0 30 |..Ge...z..9....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......|
-00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................|
-00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot|
-00000150 6f 31 |o1|
+00000000 16 03 01 00 bf 01 00 00 bb 03 03 82 57 14 fc ab |............W...|
+00000010 56 21 ff 72 39 72 3f fe f1 9b 0f 22 00 ff ef 44 |V!.r9r?...."...D|
+00000020 da db e0 83 d2 c0 a7 1c fb f0 6c 00 00 38 c0 2c |..........l..8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 5a 00 0b 00 04 03 00 |.5./.....Z......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........|
+00000090 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000a0 03 03 02 01 02 02 02 03 00 10 00 10 00 0e 06 70 |...............p|
+000000b0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
+000000c0 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 |............A...|
-000002c0 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f |7...Q.5uq..T[...|
-000002d0 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b |.g..$ >.V...(^.+|
-000002e0 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 |-O....lK[.V.2B.X|
-000002f0 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 |..I..h.A.Vk.Z...|
-00000300 00 80 97 89 a3 7f 30 d1 7b 70 26 3d a4 d5 66 2e |......0.{p&=..f.|
-00000310 cd fc 02 f5 37 a5 cd 09 69 7a c6 2f b2 62 e8 a6 |....7...iz./.b..|
-00000320 88 e2 3a c4 0a 8c 77 ad d3 c9 29 49 84 81 9c cd |..:...w...)I....|
-00000330 33 44 59 2d b5 2e e7 ce 12 c5 3b 46 13 6d 4a c8 |3DY-......;F.mJ.|
-00000340 6d f6 1f e7 f1 99 13 01 ca 43 79 fa b5 78 c7 1a |m........Cy..x..|
-00000350 7d 8f 85 dd 3b ca 56 22 c3 d0 41 11 1b 13 8c 07 |}...;.V"..A.....|
-00000360 02 75 87 7a ea 68 43 30 0b 2a 38 52 b2 8f cc ea |.u.z.hC0.*8R....|
-00000370 a3 a3 cb 71 fb 97 cd 3e 74 d0 5b 9b bd 17 13 f0 |...q...>t.[.....|
-00000380 d9 fe 16 03 03 00 04 0e 00 00 00 |...........|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 |.\!.;...........|
+000002a0 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.|
+000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
+000002c0 5f 58 cb 3b 74 05 01 00 80 bf 6d 57 f5 0c 78 c4 |_X.;t.....mW..x.|
+000002d0 77 48 0e 60 67 7a 3a 1b 3e 9e d2 88 a4 89 07 ef |wH.`gz:.>.......|
+000002e0 d1 45 1a 66 7e 8c ec cb da 71 ea ec ba ed 81 9e |.E.f~....q......|
+000002f0 21 4d 2e ba d4 8f c2 0a 67 ea 3a a1 d1 67 09 66 |!M......g.:..g.f|
+00000300 dc a8 ad 16 a2 23 2a db 4f 31 65 b1 54 13 73 d1 |.....#*.O1e.T.s.|
+00000310 f6 7b 75 d9 f1 07 19 b8 67 21 87 d2 3b cf a5 6c |.{u.....g!..;..l|
+00000320 61 8e af ed 60 7f f2 56 9f 0d 0f 19 88 98 30 3a |a...`..V......0:|
+00000330 61 8c 21 e7 8b 5d ab 6f cf 93 73 33 63 cd 50 bb |a.!..].o..s3c.P.|
+00000340 dd 0e ab 4f 6a fb a3 f9 68 16 03 03 00 04 0e 00 |...Oj...h.......|
+00000350 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 ba 5b 0f e7 ec |....F...BA..[...|
-00000010 8e c8 ad 51 8c c0 50 f1 8a 2a 68 32 74 d0 95 03 |...Q..P..*h2t...|
-00000020 0c 61 f1 1c 89 ed 95 5d 9a 4a 14 ee cc 14 9a 73 |.a.....].J.....s|
-00000030 f6 db 46 dd b7 47 8a 82 3d 7a b8 9f 45 d1 a2 3f |..F..G..=z..E..?|
-00000040 f4 34 9b b6 6d 7d 41 87 c9 d5 cd 14 03 03 00 01 |.4..m}A.........|
-00000050 01 16 03 03 00 28 1e ae f6 90 a9 91 eb 4b ca 23 |.....(.......K.#|
-00000060 6e bf 9e 67 5b 38 ab f6 d6 ee 12 aa b9 b6 d0 6e |n..g[8.........n|
-00000070 a7 dd 45 91 34 45 78 a0 04 9e d8 85 48 48 |..E.4Ex.....HH|
+00000000 16 03 03 00 25 10 00 00 21 20 05 0c 3b 8b 22 36 |....%...! ..;."6|
+00000010 61 79 58 28 b0 82 65 44 39 67 93 c5 2c 3b d1 40 |ayX(..eD9g..,;.@|
+00000020 88 af 9f 38 c1 fa e0 81 a0 19 14 03 03 00 01 01 |...8............|
+00000030 16 03 03 00 28 87 2e d2 c2 ce 65 6d e8 d9 da a0 |....(.....em....|
+00000040 9d dc f5 51 b0 84 88 8d c6 a3 0a 5d 08 10 ca c6 |...Q.......]....|
+00000050 e3 83 0c 0a cb 6d ec 09 b8 9f a5 45 99 |.....m.....E.|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 4f 7f 09 64 32 96 26 b5 71 46 6a |o...aO..d2.&.qFj|
-00000040 29 7d fd 0b bb 49 13 0e c8 c5 de 06 ed 47 e8 cb |)}...I.......G..|
-00000050 d8 9f 18 82 69 af ab 24 d2 78 90 ba 9a c8 24 95 |....i..$.x....$.|
-00000060 46 53 19 2e e8 33 94 3c 22 73 26 d6 86 4e 01 a4 |FS...3.<"s&..N..|
-00000070 34 ea a8 bf f2 ca b5 0d fc f6 08 b9 31 b3 42 e7 |4...........1.B.|
-00000080 c1 92 96 f9 bf 9a 00 14 03 03 00 01 01 16 03 03 |................|
-00000090 00 28 00 00 00 00 00 00 00 00 bd 51 1d 0e bd 51 |.(.........Q...Q|
-000000a0 a3 b1 03 f2 df f4 ba 9b 1e a5 a8 22 e7 ce 7c 19 |..........."..|.|
-000000b0 1a bf 37 3d 42 f4 4d 6f 63 75 17 03 03 00 25 00 |..7=B.Mocu....%.|
-000000c0 00 00 00 00 00 00 01 52 8a d2 34 52 70 f1 cf 87 |.......R..4Rp...|
-000000d0 54 4e fd e6 11 a7 76 1a f4 7b 70 e8 34 ef 01 c8 |TN....v..{p.4...|
-000000e0 6c 4a f8 6d 15 03 03 00 1a 00 00 00 00 00 00 00 |lJ.m............|
-000000f0 02 8a 4c f9 7c d1 61 a6 cd 2a e6 3a 5b b0 cb aa |..L.|.a..*.:[...|
-00000100 91 2e 8b |...|
+00000030 6f ec 80 83 61 34 53 e2 a4 e2 ff 73 4f 1b 15 8f |o...a4S....sO...|
+00000040 3b 43 47 ac 20 c6 2d 5e 52 7a 61 6f af 40 c3 5a |;CG. .-^Rzao.@.Z|
+00000050 cb 3f 7d 10 a9 90 ca cf 8d c4 c4 d4 a3 b8 1d 62 |.?}............b|
+00000060 7d a9 68 32 01 33 94 65 8b 67 73 aa 51 d4 08 1d |}.h2.3.e.gs.Q...|
+00000070 ce 76 6b ef 3d e6 ce d3 42 fe 24 cf f3 82 5b 17 |.vk.=...B.$...[.|
+00000080 5c 03 e9 50 94 8e 8b 14 03 03 00 01 01 16 03 03 |\..P............|
+00000090 00 28 00 00 00 00 00 00 00 00 c2 7c e6 69 c9 ec |.(.........|.i..|
+000000a0 b5 55 57 34 8e 86 38 e6 28 85 b0 c8 2e c8 0f a6 |.UW4..8.(.......|
+000000b0 a9 07 f4 91 47 46 dd fe c8 57 17 03 03 00 25 00 |....GF...W....%.|
+000000c0 00 00 00 00 00 00 01 39 9a a2 da d8 3d 7f 25 0e |.......9....=.%.|
+000000d0 83 a8 cd 57 d8 a4 7e 9f e1 e2 fe 3f 5a ed b9 99 |...W..~....?Z...|
+000000e0 b6 4d 97 3a 15 03 03 00 1a 00 00 00 00 00 00 00 |.M.:............|
+000000f0 02 d5 2a aa 1e 7a 60 b8 79 56 c6 56 75 11 b7 4c |..*..z`.yV.Vu..L|
+00000100 83 19 9c |...|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
index ae3748f49b..e2864070a4 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -1,24 +1,15 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 35 01 00 01 31 03 03 00 02 67 8e 1d |....5...1....g..|
-00000010 3b d2 26 20 63 c5 6a b6 68 25 02 72 ce 86 6b c7 |;.& c.j.h%.r..k.|
-00000020 97 1a 9f 4d be 02 98 ac 24 5e 82 00 00 b6 c0 30 |...M....$^.....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........|
-00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................|
-00000130 01 02 02 02 03 00 0f 00 01 01 |..........|
+00000000 16 03 01 00 a7 01 00 00 a3 03 03 27 01 f3 21 98 |...........'..!.|
+00000010 ff 55 7f 78 32 44 b7 9d 88 6b 82 43 26 52 00 74 |.U.x2D...k.C&R.t|
+00000020 fb 05 ca be 23 1f d0 18 1f 74 c2 00 00 38 c0 2c |....#....t...8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 42 00 0b 00 04 03 00 |.5./.....B......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............|
+00000090 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................|
+000000a0 02 02 02 03 00 16 00 00 00 17 00 00 |............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -56,43 +47,39 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......|
-00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B|
-000002a0 01 bc 56 16 22 ad fd e7 ac ba c8 f5 3f c0 d7 f8 |..V.".......?...|
-000002b0 8c 64 e0 ba 09 30 c3 66 49 90 7e d2 68 86 07 72 |.d...0.fI.~.h..r|
-000002c0 20 87 a1 e1 36 92 a7 68 e2 c3 6e 34 93 a9 ca e8 | ...6..h..n4....|
-000002d0 68 3d 9e 42 c4 1e 8e 2d 95 05 ee a6 a4 2c 8d be |h=.B...-.....,..|
-000002e0 e3 88 02 42 01 16 18 77 b9 99 0e f8 46 90 46 07 |...B...w....F.F.|
-000002f0 f9 67 a9 26 68 d7 da c8 a1 d9 67 55 ec 37 11 2d |.g.&h.....gU.7.-|
-00000300 4b f3 52 f4 96 6a 0e 8a 6a 14 21 94 63 ea f9 70 |K.R..j..j.!.c..p|
-00000310 2d 57 05 8a 72 29 6e d2 60 a1 97 af 08 5b c3 cf |-W..r)n.`....[..|
-00000320 3a 82 a3 81 11 cf 16 03 03 00 04 0e 00 00 00 |:..............|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b7 0c 00 |{j.9....*.......|
+00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.|
+00000280 4f 30 aa d0 4d e5 61 db ba fc 95 15 52 ef 2a 41 |O0..M.a.....R.*A|
+00000290 b4 d6 59 ac 39 61 b6 38 08 1e 87 b3 ca 9b 49 d3 |..Y.9a.8......I.|
+000002a0 95 5a c5 29 84 cd 10 73 4a cc 09 df 1a b0 54 6d |.Z.)...sJ.....Tm|
+000002b0 b8 61 28 80 2e ec cf 95 9d 6f c3 d9 ed 80 53 63 |.a(......o....Sc|
+000002c0 d9 02 42 00 af 71 2f 91 80 ff a1 79 82 c7 d9 79 |..B..q/....y...y|
+000002d0 fa 12 a9 88 7b 93 47 be 6a dc 80 42 17 9d 85 7a |....{.G.j..B...z|
+000002e0 b8 1b fe 85 7f 5c 10 9c 9e 0e e1 71 a7 b0 12 02 |.....\.....q....|
+000002f0 e2 a4 79 c4 8d d8 02 09 01 9c 6f 7a 27 7c 1f f4 |..y.......oz'|..|
+00000300 38 46 59 46 94 16 03 03 00 04 0e 00 00 00 |8FYF..........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 8c 80 0c da 24 |....F...BA.....$|
-00000010 d6 66 ff cc 1b 26 d5 3f 37 37 16 8f 16 ee 0d 5f |.f...&.?77....._|
-00000020 c3 0e 62 7c e4 52 2d 43 29 e9 6b da 49 bc 99 16 |..b|.R-C).k.I...|
-00000030 28 46 8e 43 20 7f 12 66 1c 94 1c 03 55 6f 05 53 |(F.C ..f....Uo.S|
-00000040 6f b7 dc 8b 70 9d 9d c5 1f da 5b 14 03 03 00 01 |o...p.....[.....|
-00000050 01 16 03 03 00 40 17 60 dd e5 b2 58 fd 74 10 38 |.....@.`...X.t.8|
-00000060 95 b1 73 7e 8f 7a 2b d0 f5 65 80 0c dc b1 ca 29 |..s~.z+..e.....)|
-00000070 06 25 e1 f9 c3 c0 7c 88 e4 ad d3 16 0a 8a dd 1f |.%....|.........|
-00000080 a7 86 86 0f ac c7 ea f5 0f 1f 2b 97 85 b3 81 f7 |..........+.....|
-00000090 5d 42 2f 3b 72 80 |]B/;r.|
+00000000 16 03 03 00 25 10 00 00 21 20 8c 80 e4 c7 bd d7 |....%...! ......|
+00000010 ea ea 42 f7 53 24 50 28 6a e9 f3 ff 4f 4a 28 22 |..B.S$P(j...OJ("|
+00000020 a2 95 09 fc f0 d9 3e fc cc 6e 14 03 03 00 01 01 |......>..n......|
+00000030 16 03 03 00 40 79 56 60 f5 45 e7 48 9e 97 1d 49 |....@yV`.E.H...I|
+00000040 de 59 dd b0 f0 0a d2 cc 10 f0 98 3c c2 d5 67 d6 |.Y.........<..g.|
+00000050 2c 18 2b 21 ae a3 2f ea 2d 0b ff fd e6 c2 73 25 |,.+!../.-.....s%|
+00000060 1c 01 3e 94 3a cc 1d 58 6b fb 7f 85 e4 50 ec 10 |..>.:..Xk....P..|
+00000070 b9 d7 71 cb be |..q..|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 82 01 fd 38 ae |..............8.|
-00000020 a4 07 8f bd 72 0a a2 b5 c5 78 09 89 65 1b 6d 1e |....r....x..e.m.|
-00000030 56 52 9d 4f de 02 15 2d 93 d8 8f d7 1f bb 07 3b |VR.O...-.......;|
-00000040 e9 62 3c 19 3e 19 65 ac 10 aa e5 17 03 03 00 40 |.b<.>.e........@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 83 5c 5c e3 c0 |............\\..|
+00000020 20 56 8c 92 4b 75 f0 30 bd 67 74 52 f1 af 9c 14 | V..Ku.0.gtR....|
+00000030 29 1e e4 b2 5b c0 2c e6 48 6f 94 42 7b 21 92 96 |)...[.,.Ho.B{!..|
+00000040 0a 83 ce 1c 91 36 95 8c 14 38 57 17 03 03 00 40 |.....6...8W....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 18 61 1d 26 f3 b9 34 20 00 6c 27 75 fc 35 f5 c2 |.a.&..4 .l'u.5..|
-00000070 6f 71 ca 9b 0d 70 30 46 57 7c 07 86 7d 52 a9 d6 |oq...p0FW|..}R..|
-00000080 ab fc 89 a5 48 79 ae 60 03 05 4b 17 b2 d9 6b 39 |....Hy.`..K...k9|
+00000060 73 a4 40 cf ad 86 cc 05 9e 47 5f 83 50 ae 68 d5 |s.@......G_.P.h.|
+00000070 d1 6a a9 8c ba 74 fe c0 cc 4a 1a e3 b0 14 0d 31 |.j...t...J.....1|
+00000080 9f 06 54 e3 95 3a 89 6d 34 54 0c e4 b4 34 38 21 |..T..:.m4T...48!|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 8f 8d 88 88 c5 1e f5 bf 06 f2 45 |...............E|
-000000b0 e7 fe f0 24 c7 4c 92 5a 80 a7 89 c8 2b ac 49 d9 |...$.L.Z....+.I.|
-000000c0 39 00 ca 57 ec |9..W.|
+000000a0 00 00 00 00 00 e6 dd b2 11 ab a7 34 61 00 d4 09 |...........4a...|
+000000b0 bc ea c1 5f c4 e2 52 60 63 96 f0 fd 44 4e f9 0e |..._..R`c...DN..|
+000000c0 af 32 99 e4 12 |.2...|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
index 144ef4288a..1f9fbc1abb 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -1,104 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 35 01 00 01 31 03 03 ed 84 e2 1a c1 |....5...1.......|
-00000010 d9 3f a5 ba 70 0b 5f 3f 3b 87 79 18 27 03 92 ee |.?..p._?;.y.'...|
-00000020 b1 9f c7 36 26 e3 0b 6d fc d5 ed 00 00 b6 c0 30 |...6&..m.......0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........|
-00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................|
-00000130 01 02 02 02 03 00 0f 00 01 01 |..........|
+00000000 16 03 01 00 a7 01 00 00 a3 03 03 1d 39 c9 33 73 |............9.3s|
+00000010 c2 b9 71 d8 66 23 63 a7 5c 9e 50 b6 3e a5 f9 bb |..q.f#c.\.P.>...|
+00000020 34 1b 71 e1 09 4f ae d5 53 8a e8 00 00 38 c0 2c |4.q..O..S....8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 42 00 0b 00 04 03 00 |.5./.....B......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............|
+00000090 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................|
+000000a0 02 02 02 03 00 16 00 00 00 17 00 00 |............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7c 5c |.h.A.Vk.Z.....|\|
-00000300 f6 68 cc 07 f0 bd ec 30 07 d0 70 1b c6 95 a4 14 |.h.....0..p.....|
-00000310 67 3a 83 a1 43 ff 0a c3 f0 b7 ee 59 f8 c7 09 65 |g:..C......Y...e|
-00000320 08 ac 18 34 d4 8f 46 c4 2c 91 7b 57 95 e0 54 03 |...4..F.,.{W..T.|
-00000330 d8 8e b6 53 61 74 77 8b a3 5f 23 f0 06 dc 3a 56 |...Satw.._#...:V|
-00000340 61 80 5e 31 d5 75 c3 05 9f d0 06 1f c5 32 ba 79 |a.^1.u.......2.y|
-00000350 fd 14 a9 54 5a 18 b4 2b 09 0e 19 ab 76 0b 12 5d |...TZ..+....v..]|
-00000360 52 27 ce b8 dd 4c f8 f2 d2 70 56 43 19 53 b3 13 |R'...L...pVC.S..|
-00000370 b9 b7 65 ce cd 50 ed 4a 9f 42 96 c7 3c b9 16 03 |..e..P.J.B..<...|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 06 d4 bd e4 7b 10 77 89 d7 d4 d6 |t........{.w....|
+000002d0 4e f6 3e 46 49 db ee 5c 4e bc ee fe cb 8b a6 9b |N.>FI..\N.......|
+000002e0 5c f6 99 fb 31 96 60 a8 23 09 f6 31 65 53 f0 6e |\...1.`.#..1eS.n|
+000002f0 07 5c 32 f9 59 5d 8b c0 b4 74 c8 01 85 8a b7 19 |.\2.Y]...t......|
+00000300 ab 19 08 68 6a e8 2f 81 bd 04 9b 38 ab d9 27 66 |...hj./....8..'f|
+00000310 d7 a5 3f 75 9c 4f 81 5b 9e 69 10 20 2b f2 1d a2 |..?u.O.[.i. +...|
+00000320 8f fc 7f ba ee 5b 76 8b 19 3f 46 60 01 25 99 72 |.....[v..?F`.%.r|
+00000330 78 24 02 8e 28 d5 24 f1 2e 6b 70 53 75 ec e2 8d |x$..(.$..kpSu...|
+00000340 76 ab e0 8e e8 16 03 03 00 04 0e 00 00 00 |v.............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 36 1c 6c f5 0a |....F...BA.6.l..|
-00000010 7f 52 84 ac 5a 27 45 76 79 a6 89 f1 1d d9 30 30 |.R..Z'Evy.....00|
-00000020 b6 64 af c7 34 11 12 b3 b9 72 83 e6 78 bc 06 74 |.d..4....r..x..t|
-00000030 a7 a4 10 01 34 77 5c 05 88 82 0f a9 cf 8d e8 68 |....4w\........h|
-00000040 09 80 c7 79 b6 e9 5a 2a 5f 80 5e 14 03 03 00 01 |...y..Z*_.^.....|
-00000050 01 16 03 03 00 40 ef f9 3c 34 cd 26 70 c9 7b 60 |.....@..<4.&p.{`|
-00000060 a7 27 0a 2b 86 18 2f 10 ad 48 3f 2e 9e 88 13 d6 |.'.+../..H?.....|
-00000070 d8 c6 fd 35 99 be 09 e6 dd ae 02 06 ea df 60 62 |...5..........`b|
-00000080 e0 f8 67 ea 9d c8 8c 11 d8 5a e7 6a a6 b2 eb 62 |..g......Z.j...b|
-00000090 23 b2 d2 be 75 58 |#...uX|
+00000000 16 03 03 00 25 10 00 00 21 20 21 75 22 84 bc b7 |....%...! !u"...|
+00000010 82 b3 03 d2 42 ff b6 ce 76 26 88 bf 8f 72 fc dd |....B...v&...r..|
+00000020 63 9b f1 4c 22 6d 12 cc d3 57 14 03 03 00 01 01 |c..L"m...W......|
+00000030 16 03 03 00 40 20 2b 26 bd 60 1b 27 a1 32 cb ab |....@ +&.`.'.2..|
+00000040 30 83 9c 47 59 7d f5 bb d9 45 8a d9 3e 29 86 4d |0..GY}...E..>).M|
+00000050 54 86 48 38 25 d9 b9 af 36 7c 7a f0 ae f6 b6 4e |T.H8%...6|z....N|
+00000060 a1 76 93 91 26 f3 c9 49 b5 6d 49 cf 22 97 bf c7 |.v..&..I.mI."...|
+00000070 db 44 c8 7a e3 |.D.z.|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 a6 52 02 4f 20 |............R.O |
-00000020 f6 d7 2d 2d 7c 65 4e 7b 43 33 32 50 9b c6 68 2c |..--|eN{C32P..h,|
-00000030 c0 6a 02 6f c6 bc 38 d8 06 c0 42 ba c1 41 ce 5c |.j.o..8...B..A.\|
-00000040 d0 a0 5f fc 8a 31 33 26 a2 79 9a 17 03 03 00 40 |.._..13&.y.....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 43 7c 61 f2 30 |...........C|a.0|
+00000020 c6 4a c2 76 da 7d 84 c6 ed 5d ee 2e 9c 33 e4 3b |.J.v.}...]...3.;|
+00000030 e3 a1 ea ee 44 02 4b f7 90 f6 0c 8b 45 d7 26 2e |....D.K.....E.&.|
+00000040 4a 37 43 1d 93 44 79 e6 5d c5 8c 17 03 03 00 40 |J7C..Dy.]......@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 f2 42 8f e8 79 0d f3 c0 a0 b7 8a 5e de b8 52 c4 |.B..y......^..R.|
-00000070 b6 9d b2 10 00 e8 a3 19 27 12 ac 38 e7 d8 ec 89 |........'..8....|
-00000080 af 7d 68 15 03 e8 c4 c8 08 34 ad ad 15 7b 69 bb |.}h......4...{i.|
+00000060 b2 e4 62 17 e2 d4 d8 73 2b ea 77 39 78 51 1a 86 |..b....s+.w9xQ..|
+00000070 64 54 1f 36 9a cc a1 c0 d2 6d df b7 8a 2e 68 b0 |dT.6.....m....h.|
+00000080 79 9a 9f a1 15 b1 78 fa db 2e 5a 43 0d fe 45 71 |y.....x...ZC..Eq|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 a0 a5 02 ff b1 77 9a 8f e0 fc ca |..........w.....|
-000000b0 86 ee ca 9c 7c 3b ca 61 33 7f f9 12 54 79 41 97 |....|;.a3...TyA.|
-000000c0 b0 7d bd 9b 93 |.}...|
+000000a0 00 00 00 00 00 04 8c d0 bf 15 9f b4 55 22 b8 8e |............U"..|
+000000b0 a5 a7 df ed bd b2 ab 88 71 38 bd b2 5d b4 5e 8e |........q8..].^.|
+000000c0 54 fc e4 63 5a |T..cZ|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
index 626024cb2b..7a950db0ac 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -1,57 +1,56 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 55 46 9e 3b 51 |....[...W..UF.;Q|
-00000010 e7 cd bf df bc fe 0d 5a 5a de a6 09 6c 72 cb ea |.......ZZ...lr..|
-00000020 ab f8 a6 fd 9a 5b be 77 7d 25 20 00 00 04 00 05 |.....[.w}% .....|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 8e 50 ff 02 c4 |....]...Y...P...|
+00000010 3b 5e dd ee 59 d1 3a e1 db f1 30 f4 bb a7 8a 8c |;^..Y.:...0.....|
+00000020 b2 d2 1a fd f8 a4 c9 e4 5f 41 e1 00 00 04 00 2f |........_A...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -86,32 +85,40 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 86 10 00 00 82 00 80 03 64 6f 74 1b 0e |...........dot..|
-00000220 df 6b a4 8e f8 ec b5 02 c2 d6 7a 9a f3 bf 3e 32 |.k........z...>2|
-00000230 ba 41 dd 61 33 8a 63 fb 71 e6 87 68 32 9c 41 d5 |.A.a3.c.q..h2.A.|
-00000240 59 ee 93 55 16 e9 0a 01 72 14 93 23 82 73 91 3a |Y..U....r..#.s.:|
-00000250 6d 3c e6 e0 a8 33 34 84 80 59 65 6b c1 6d 01 19 |m<...34..Yek.m..|
-00000260 cc d5 4f 1d f6 88 4f cc b5 c6 3c 9c 68 4a be 47 |..O...O...<.hJ.G|
-00000270 c2 67 61 a4 e3 c3 00 c0 9c d4 83 ed b5 65 25 a4 |.ga..........e%.|
-00000280 2e 1c 8d 47 3f 80 b8 1d 5b 74 a2 bf fa b9 b7 e2 |...G?...[t......|
-00000290 58 94 ba ec a9 cf 1c 56 ef 0a 16 03 03 00 92 0f |X......V........|
-000002a0 00 00 8e 04 03 00 8a 30 81 87 02 41 75 cf 19 3a |.......0...Au..:|
-000002b0 a1 9e e9 69 c7 f3 63 0b 46 c2 60 35 e1 cc 95 0d |...i..c.F.`5....|
-000002c0 ee 0f ad 28 17 b4 b2 09 ea 38 18 c7 08 84 b6 ac |...(.....8......|
-000002d0 65 03 b9 49 c3 ea ff e4 45 d3 15 14 3a 94 14 0c |e..I....E...:...|
-000002e0 cb 48 ce 75 c2 a4 4a 0e 7d d8 f0 c5 5f 02 42 01 |.H.u..J.}..._.B.|
-000002f0 99 dd c7 54 ce ee 38 bb 18 16 eb 92 0a 53 0b 92 |...T..8......S..|
-00000300 d8 73 73 48 b3 0a 3b ea 12 ea 62 d3 88 99 00 54 |.ssH..;...b....T|
-00000310 bc 92 28 7d 66 b3 17 7f e7 5f 69 50 d1 a1 4c 6a |..(}f...._iP..Lj|
-00000320 99 60 00 59 0a 4d 6c 97 05 54 ee 82 5a e1 c5 88 |.`.Y.Ml..T..Z...|
-00000330 1b 14 03 03 00 01 01 16 03 03 00 24 80 64 11 aa |...........$.d..|
-00000340 cc 9d 1c 83 b6 2f 56 dc 48 cb 33 e5 0f 25 a2 42 |...../V.H.3..%.B|
-00000350 df b8 a6 cc 64 93 10 63 ad 76 91 27 3f c7 8f d4 |....d..c.v.'?...|
+00000210 03 03 00 86 10 00 00 82 00 80 2b 80 6e 49 b8 ec |..........+.nI..|
+00000220 12 7a 7c f3 2a d3 7e 16 a0 39 e5 77 61 7a 56 15 |.z|.*.~..9.wazV.|
+00000230 97 c6 64 63 13 cf 09 d0 1b f5 b6 78 1d cb 86 4f |..dc.......x...O|
+00000240 14 84 c9 e6 5d 3c 6b 61 5e 46 83 7e ef 1d 74 d4 |....]<ka^F.~..t.|
+00000250 3b 8c 78 be 26 92 24 04 b4 6f 21 88 03 8d 92 a8 |;.x.&.$..o!.....|
+00000260 60 c6 08 b5 75 5d 2f 2c 71 60 5f 54 27 a0 fa 83 |`...u]/,q`_T'...|
+00000270 4d 39 1e 22 1e 1e 60 92 51 ac 2d 35 c7 cf fc 5e |M9."..`.Q.-5...^|
+00000280 db e3 60 37 6b 4e 7c d8 04 f3 09 54 de 38 af 57 |..`7kN|....T.8.W|
+00000290 20 d0 f5 08 5a a8 6f 65 03 55 16 03 03 00 93 0f | ...Z.oe.U......|
+000002a0 00 00 8f 04 03 00 8b 30 81 88 02 42 00 97 84 ac |.......0...B....|
+000002b0 cf 9b df b0 3a c8 9d a6 da 8c 11 87 35 2a d7 d0 |....:.......5*..|
+000002c0 15 df e1 02 ca 85 3f 1c a5 21 17 8c 8a 73 1b 76 |......?..!...s.v|
+000002d0 8d 0f af 26 ea b5 7f 87 a6 b6 c8 61 32 27 fc f4 |...&.......a2'..|
+000002e0 b7 c5 c3 2c 53 61 59 5a 5d 12 c6 dd 9e 54 02 42 |...,SaYZ]....T.B|
+000002f0 01 04 3f 82 bb a4 5c ea ea c9 9c 2a 75 96 c2 88 |..?...\....*u...|
+00000300 5a ae f8 2e 29 01 cf 7b a4 20 83 df ec c8 9d 37 |Z...)..{. .....7|
+00000310 0c 33 fb 20 73 51 47 6d 81 d0 75 b1 19 ed 02 00 |.3. sQGm..u.....|
+00000320 b8 40 67 75 b9 72 63 9c 1e e1 c9 44 93 d6 ec e7 |.@gu.rc....D....|
+00000330 16 5c 14 03 03 00 01 01 16 03 03 00 40 43 51 cf |.\..........@CQ.|
+00000340 07 b2 de 6e 40 10 eb dd 3f 84 6a 54 a3 7f b2 48 |...n@...?.jT...H|
+00000350 b3 aa 3c d4 e7 69 32 7c 77 ba e9 0b 99 b3 c9 e8 |..<..i2|w.......|
+00000360 c5 53 29 9a 6b 82 ee 7d 5e a9 ae 63 fa a9 af 21 |.S).k..}^..c...!|
+00000370 f2 04 b1 a1 bf f1 10 4c 65 6c 49 34 a0 |.......LelI4.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 24 8d e5 5f d9 |..........$$.._.|
-00000010 99 7d d4 f2 5f f4 4b e3 b4 8e 33 84 7a c3 cb bf |.}.._.K...3.z...|
-00000020 21 00 94 db 7b 7f 6c fa a0 f2 9f 0e e9 3b 27 17 |!...{.l......;'.|
-00000030 03 03 00 21 67 f8 3a ff c1 3b cb de 04 bf 49 a6 |...!g.:..;....I.|
-00000040 9a 45 56 ab 64 99 06 7e 40 cc a7 f6 4e 1e ca cb |.EV.d..~@...N...|
-00000050 11 87 da 58 b7 15 03 03 00 16 10 1b 62 97 25 bf |...X........b.%.|
-00000060 84 c1 23 d6 76 4a a1 da 07 c7 25 68 f6 6e 63 55 |..#.vJ....%h.ncU|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 93 a2 18 a9 e2 |................|
+00000020 51 be f7 bd c0 05 64 51 0a 17 9d 58 11 d1 a6 b9 |Q.....dQ...X....|
+00000030 6d 1e 42 16 e4 bc bf 09 f2 b9 29 20 74 8a cd 8a |m.B.......) t...|
+00000040 b6 31 04 64 fb 5b 1f 83 c3 19 78 17 03 03 00 40 |.1.d.[....x....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 ee c4 d0 5d 69 37 2b fc dc 9c f1 77 df 44 6f da |...]i7+....w.Do.|
+00000070 4e 22 05 05 3a 6c 32 a8 6c c2 fb ce ca a7 1b 54 |N"..:l2.l......T|
+00000080 2a 25 ae cf 77 e4 47 21 33 b6 29 54 62 00 dd 30 |*%..w.G!3.)Tb..0|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 cf e1 fd e3 5f d3 19 cd 05 70 79 |........._....py|
+000000b0 be 16 a5 26 18 f1 92 bc 73 bd 6f 4d 33 3d 6f 8a |...&....s.oM3=o.|
+000000c0 13 51 7c 57 c7 |.Q|W.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
index 819825ca89..c81acc8992 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -1,116 +1,123 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 87 41 6f c5 67 |....[...W...Ao.g|
-00000010 07 3b 12 46 ad aa d2 be 0d 08 98 e3 c7 4b ac 48 |.;.F.........K.H|
-00000020 67 02 6b 3b dc 84 79 c5 57 e9 89 00 00 04 00 05 |g.k;..y.W.......|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 f3 3a db 98 ff |....]...Y...:...|
+00000010 29 a2 30 75 53 87 b3 5f 00 b5 9f 77 4d 88 38 ea |).0uS.._...wM.8.|
+00000020 e9 87 f4 a4 e4 da dd 73 00 47 d1 00 00 04 00 2f |.......s.G...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 86 10 00 00 82 00 80 79 a7 23 10 fc |...........y.#..|
-00000210 64 a7 ab 17 ce d6 8b ab ff c2 44 40 3b ba b4 c6 |d.........D@;...|
-00000220 86 b7 66 7d be 9b fa 66 f9 f6 bb e4 f7 02 16 ea |..f}...f........|
-00000230 0f 13 9c 8a 98 3a 34 e6 58 82 dc dc 27 3a 3d 5c |.....:4.X...':=\|
-00000240 99 09 db 48 54 a5 5a a2 16 7f ba 99 d9 0d ca fb |...HT.Z.........|
-00000250 4a 9e b7 f6 3a ab 26 ef f9 df a2 0c 4c 45 19 3b |J...:.&.....LE.;|
-00000260 b2 9f 21 cd ff fc cc c7 fb 91 fa 54 93 a9 42 a9 |..!........T..B.|
-00000270 4c 48 4a 8c 7b 9a d7 90 97 f6 21 89 03 f6 a5 86 |LHJ.{.....!.....|
-00000280 83 6f 21 19 2f 5b f8 ec a6 36 e9 16 03 03 00 88 |.o!./[...6......|
-00000290 0f 00 00 84 04 01 00 80 0f 9d 15 cc c0 0b 71 8a |..............q.|
-000002a0 b9 95 ca 9a 86 ff bf 93 8d da 64 ce 99 28 e2 6e |..........d..(.n|
-000002b0 6d 6f 34 c9 03 fa 87 96 b0 1d 4f b2 3c 9e 4d 2c |mo4.......O.<.M,|
-000002c0 df be 7d fb 53 fe 90 6f 45 f3 f0 d9 ab 70 d4 df |..}.S..oE....p..|
-000002d0 5a 95 a4 53 12 02 c1 45 15 c2 2b 69 7e 5f 6f cd |Z..S...E..+i~_o.|
-000002e0 b3 eb 5d ff 48 36 94 ad 28 29 fe 47 40 ab 9c eb |..].H6..().G@...|
-000002f0 02 f9 ca 7d e0 48 9f 6e a4 9f 1e c2 d7 fd 16 18 |...}.H.n........|
-00000300 db ad d9 35 27 89 96 c8 c4 70 10 be a4 5d 6b b4 |...5'....p...]k.|
-00000310 d8 61 70 93 08 00 0f c9 14 03 03 00 01 01 16 03 |.ap.............|
-00000320 03 00 24 7b ee b7 23 12 63 f0 80 ca b3 6f d3 b8 |..${..#.c....o..|
-00000330 ca cc 4a 54 06 ea e5 3e 73 f2 de 1d d6 16 7e 61 |..JT...>s.....~a|
-00000340 32 76 eb f8 8a 66 74 |2v...ft|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 47 31 82 |.5...........G1.|
+00000210 ae c1 d2 74 3f a4 74 5a 57 16 ae e2 d0 46 72 53 |...t?.tZW....FrS|
+00000220 e1 5e 6a e8 e4 d5 8c 84 2b d9 82 c1 4a da 9e 1d |.^j.....+...J...|
+00000230 a0 da 60 08 0d 35 0c 55 6d 6a 68 04 09 ee 94 39 |..`..5.Umjh....9|
+00000240 c7 a3 49 7f 2c ee 6a cf 09 01 bd 08 d3 59 0a bd |..I.,.j......Y..|
+00000250 7f 6c d3 26 eb be 7b fd 9b 17 fd e2 6e 82 d1 c7 |.l.&..{.....n...|
+00000260 dd c3 64 8c 87 f0 41 f2 71 75 f1 0a 01 26 5b 97 |..d...A.qu...&[.|
+00000270 94 ba ac 50 df 19 32 39 80 ae 14 ea 4a d2 e5 9f |...P..29....J...|
+00000280 5d 07 9f 2d 89 ac 83 33 40 aa 8e cc 2c 16 03 03 |]..-...3@...,...|
+00000290 00 88 0f 00 00 84 04 01 00 80 7d 37 8b 6f be e9 |..........}7.o..|
+000002a0 e7 fa 4c 28 cf 16 0d 28 40 e9 f2 9a 11 22 fc 8a |..L(...(@...."..|
+000002b0 2c 52 f7 36 af 1a cf d7 8a f8 17 19 9f ed 9d 1d |,R.6............|
+000002c0 43 f9 e2 fb 0f dd ca d6 1d 4c 03 4e 25 8d 5c 4c |C........L.N%.\L|
+000002d0 95 98 02 db cf ea 44 2a ad 36 74 e3 08 07 e3 9a |......D*.6t.....|
+000002e0 50 6c dc 46 a1 f5 84 9b 65 7f 48 94 b5 de cc a9 |Pl.F....e.H.....|
+000002f0 cf ee 0e 31 f2 f8 6f 8f 19 4b 29 14 b4 32 1d 21 |...1..o..K)..2.!|
+00000300 02 d2 da 64 68 e8 a1 72 cc ee 64 48 d8 74 e5 64 |...dh..r..dH.t.d|
+00000310 90 b3 50 cc 3e 25 0e b1 88 53 14 03 03 00 01 01 |..P.>%...S......|
+00000320 16 03 03 00 40 6a 61 6b 3e ea 63 2c b8 26 95 e2 |....@jak>.c,.&..|
+00000330 5f 83 e3 c3 cd c3 b7 a8 0b 76 81 8a 5b 46 ff 41 |_........v..[F.A|
+00000340 c2 02 eb 21 85 31 b9 ba 2e 30 e7 6e 8d 1c 49 15 |...!.1...0.n..I.|
+00000350 af a0 a7 67 62 b7 42 8c fa a8 04 8c 23 7a 3d 39 |...gb.B.....#z=9|
+00000360 74 18 70 2b 99 |t.p+.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 64 d5 a4 78 e9 |..........$d..x.|
-00000010 f1 1d d1 34 f7 b3 95 87 18 f6 cf 65 c6 f0 02 08 |...4.......e....|
-00000020 69 f5 6d aa f2 da fc 2c ac fc aa f8 25 aa 50 17 |i.m....,....%.P.|
-00000030 03 03 00 21 9f 94 f8 78 46 58 2c 21 0d 30 04 89 |...!...xFX,!.0..|
-00000040 bd 35 03 dc 04 b6 0f 6f 22 65 db 3d 8d 96 00 0c |.5.....o"e.=....|
-00000050 db bf e5 b3 59 15 03 03 00 16 a6 35 f2 07 5e 32 |....Y......5..^2|
-00000060 4e 09 e4 31 3a f6 4a 83 c2 03 db b9 bf b0 eb 6d |N..1:.J........m|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 a6 5b 7c b0 91 |............[|..|
+00000020 53 f6 d5 e4 34 71 4f 64 2a 03 9d 75 62 d9 8d a8 |S...4qOd*..ub...|
+00000030 39 7b e1 d8 31 80 26 db 14 f3 3a 52 66 7d 12 31 |9{..1.&...:Rf}.1|
+00000040 29 14 7f a1 39 b6 1c e0 c9 55 6e 17 03 03 00 40 |)...9....Un....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 5e 00 64 9b 25 cd 74 94 b7 65 6e 83 8e 5b 68 e8 |^.d.%.t..en..[h.|
+00000070 59 4c f0 31 8b f2 0c 59 2a ff 11 8e 43 d4 73 fd |YL.1...Y*...C.s.|
+00000080 b3 2a 76 59 25 52 32 76 bd 2e 1d 4d 0a 53 d7 c2 |.*vY%R2v...M.S..|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 23 96 6e 7d 41 bb 51 4f 40 52 07 |.....#.n}A.QO@R.|
+000000b0 90 cc 6c bd c0 bb 99 d4 8a 91 7b 8a f3 24 ef 71 |..l.......{..$.q|
+000000c0 20 d4 98 b0 14 | ....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
index 903272b644..091de9081e 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -1,76 +1,83 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 9a 56 e0 d9 b8 |....[...W...V...|
-00000010 ac d5 88 c7 2f d1 87 1b 44 c6 ff 7b 4f 6f f0 2a |..../...D..{Oo.*|
-00000020 56 a1 9e 46 86 4b 6f 91 29 29 3b 00 00 04 00 05 |V..F.Ko.));.....|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 41 24 db 27 37 |....]...Y..A$.'7|
+00000010 2e 1e a8 61 b7 7f 08 f1 83 84 fb d5 a2 96 e0 53 |...a...........S|
+00000020 1a 2b cd 8e 50 38 7b a5 64 d8 92 00 00 04 00 2f |.+..P8{.d....../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................|
-00000010 86 10 00 00 82 00 80 3a 72 91 a2 c3 ba 83 75 1b |.......:r.....u.|
-00000020 d3 f6 1c 07 7f 92 a8 b0 1f 47 42 cc 8d 4e 7e 1e |.........GB..N~.|
-00000030 23 49 44 29 53 19 9f 3b 5c bb 5d ed 6c d9 49 5d |#ID)S..;\.].l.I]|
-00000040 6e f9 d1 59 9d 40 67 b3 0c ee 41 85 6c 4a 4d 3b |n..Y.@g...A.lJM;|
-00000050 c1 e6 c8 7f 93 15 cb 2a 17 64 da 70 f3 2a c3 7c |.......*.d.p.*.||
-00000060 a2 02 48 19 fb 74 5a dc 52 0d 80 6b ed c0 8c 15 |..H..tZ.R..k....|
-00000070 3e 3b 34 7c 55 6e 95 e0 d1 4a 7f b0 bc 33 67 a7 |>;4|Un...J...3g.|
-00000080 3b 40 bb eb 83 58 4a fb fb 01 9b 0d fa ef 83 c4 |;@...XJ.........|
-00000090 87 10 75 0c a7 ad 91 14 03 03 00 01 01 16 03 03 |..u.............|
-000000a0 00 24 18 ce de 8d ab c1 6e 3b 0b 51 fe 94 ae 0a |.$......n;.Q....|
-000000b0 39 9c 4d a2 90 53 d4 1e 5f f6 96 5a 51 f2 39 c1 |9.M..S.._..ZQ.9.|
-000000c0 d6 06 c0 4e 58 99 |...NX.|
+00000010 86 10 00 00 82 00 80 61 2e 6b ad 77 48 8d 2f 0e |.......a.k.wH./.|
+00000020 e6 27 64 fd 95 22 72 68 80 8e 2b 0e b2 0f cc be |.'d.."rh..+.....|
+00000030 19 31 93 1d d3 0a fb 00 da 50 26 66 17 59 6b e9 |.1.......P&f.Yk.|
+00000040 7e 16 4e 24 ba 68 0a 0c 69 2f 03 74 34 50 12 85 |~.N$.h..i/.t4P..|
+00000050 4a f0 6c 52 d4 dd 13 18 c7 a4 9d ea f0 c6 94 d9 |J.lR............|
+00000060 ae fe 19 6c 83 dd ed 38 e3 d2 21 18 e6 76 11 e7 |...l...8..!..v..|
+00000070 62 13 8b 56 65 e0 f6 61 d9 db 7c 7b 5b 57 13 3d |b..Ve..a..|{[W.=|
+00000080 58 64 67 8d 9f 3f 6a a0 70 c5 c6 d0 db eb 17 3f |Xdg..?j.p......?|
+00000090 6c 58 d7 c3 ba ec 4c 14 03 03 00 01 01 16 03 03 |lX....L.........|
+000000a0 00 40 6e 24 1b a4 b3 e7 d4 c2 7e cb bd 82 2d 4c |.@n$......~...-L|
+000000b0 a8 f1 5e 81 c8 61 a6 2c 6a e3 6d 30 7f fa c7 f3 |..^..a.,j.m0....|
+000000c0 f6 b1 b1 4f 0b 23 9a fd 66 81 48 97 4b 0f 88 07 |...O.#..f.H.K...|
+000000d0 37 7b 97 b0 62 6c 2a e1 47 65 e9 f9 cd c1 79 99 |7{..bl*.Ge....y.|
+000000e0 6d 84 |m.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 8b 7e 57 f3 7d |..........$.~W.}|
-00000010 ab 44 f0 c7 53 2d 39 08 14 32 12 4e 4b 45 9a e3 |.D..S-9..2.NKE..|
-00000020 1c 43 36 16 59 a0 4b e4 78 43 d2 a5 dc 96 b1 17 |.C6.Y.K.xC......|
-00000030 03 03 00 21 54 89 75 23 de 7d c7 c6 80 a6 a6 69 |...!T.u#.}.....i|
-00000040 d0 a8 95 77 71 a0 89 34 f4 c3 31 73 bb b0 ac d7 |...wq..4..1s....|
-00000050 e5 e4 83 4b 10 15 03 03 00 16 0d 44 43 67 21 cc |...K.......DCg!.|
-00000060 6c c1 7e 72 99 aa 7f a1 de 10 0b 36 ae 05 d9 9e |l.~r.......6....|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 40 c6 62 4e 26 |...........@.bN&|
+00000020 e7 32 09 ba d6 3b 71 79 8e 75 ee fb af 09 db c5 |.2...;qy.u......|
+00000030 a5 8b cd 1f 90 f3 65 86 4a b4 b1 9a e8 1e 80 f6 |......e.J.......|
+00000040 ad db bd c2 9f ec 98 42 0b 37 30 17 03 03 00 40 |.......B.70....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 a9 74 3c 13 87 f4 cf 77 be 07 c2 a1 e0 47 4e 52 |.t<....w.....GNR|
+00000070 c2 86 da 08 c2 93 21 80 4c 19 51 cc 0d 76 49 75 |......!.L.Q..vIu|
+00000080 0b 48 3d e0 e2 01 93 4b f1 73 91 17 aa 00 b5 71 |.H=....K.s.....q|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 1f 2f 2d d7 39 06 c4 59 49 80 66 |....../-.9..YI.f|
+000000b0 6c 35 2e a7 45 ee 0a 05 4b 1e 7f 78 5d cd 24 2c |l5..E...K..x].$,|
+000000c0 0a 3e 55 1c 7d |.>U.}|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
index 8b04a5ad4d..b412980e2a 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -1,13 +1,12 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 ec 8e d0 43 01 |..............C.|
-00000010 8e 81 3f d8 1f 7e 96 f1 de 4c 94 18 09 1d c5 8c |..?..~...L......|
-00000020 3a 58 68 5b 3e 7d 46 66 fe 04 74 00 00 04 c0 0a |:Xh[>}Ff..t.....|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 f0 4f 82 cc 2a |....s...o...O..*|
+00000010 27 0b 7f 2e e4 af 6d ba 4e fe 61 99 fc 0a 44 ee |'.....m.N.a...D.|
+00000020 c0 4e 7b 3a 7c f0 6d 12 b7 7d 9e 00 00 04 c0 0a |.N{:|.m..}......|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -45,43 +44,39 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......|
-00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B|
-000002a0 01 08 89 99 1c 91 97 fb e8 5b 69 5f f5 36 66 d6 |.........[i_.6f.|
-000002b0 dd 53 04 09 c8 7f c1 25 28 8c 28 57 55 3a 95 3f |.S.....%(.(WU:.?|
-000002c0 ab 09 47 9a 27 74 83 84 44 cf 86 b7 5e 7f fe db |..G.'t..D...^...|
-000002d0 05 33 3c 1a b7 f6 bc ff 0d 33 e4 ec 3c e2 1d e2 |.3<......3..<...|
-000002e0 6e ab 02 42 00 92 4e 45 a7 86 e4 bd 40 82 b7 04 |n..B..NE....@...|
-000002f0 12 fe 34 ab e3 c9 4a 05 1f 4e 58 79 67 58 94 53 |..4...J..NXygX.S|
-00000300 e8 1b ba 60 76 92 00 99 a7 5f 0a 98 cb e3 1e de |...`v...._......|
-00000310 0c df 18 76 58 d5 e1 f1 ef a5 da 9a a3 62 77 50 |...vX........bwP|
-00000320 37 d0 22 d0 31 90 16 03 03 00 04 0e 00 00 00 |7.".1..........|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b7 0c 00 |{j.9....*.......|
+00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.|
+00000280 2d d4 82 80 01 6b e6 8c 6a 2a b3 09 1b 0d 86 e6 |-....k..j*......|
+00000290 62 92 85 46 d9 e3 b2 e9 f1 5e 77 c2 27 fd 2b 68 |b..F.....^w.'.+h|
+000002a0 6a e1 3d e2 42 d2 86 96 42 b1 3b 50 7b e2 2c 34 |j.=.B...B.;P{.,4|
+000002b0 d3 e7 f6 14 89 48 eb 5c 9a 98 98 ab f3 db 85 06 |.....H.\........|
+000002c0 cb 02 42 00 df 42 94 63 a5 ff 43 a5 20 5d 83 09 |..B..B.c..C. ]..|
+000002d0 88 7d 10 ff ec 32 33 28 1d 43 b2 d2 bf 39 0c 63 |.}...23(.C...9.c|
+000002e0 9a c0 f8 0e 9f 71 a7 9a 5d 27 1a 5c f2 36 80 b3 |.....q..]'.\.6..|
+000002f0 71 0f d3 c0 fd 0d 5d 02 90 c4 9d 90 db 74 ad f6 |q.....]......t..|
+00000300 22 8f 6b 9d 55 16 03 03 00 04 0e 00 00 00 |".k.U.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 9e 94 25 4f 70 |....F...BA...%Op|
-00000010 a8 e0 87 3a 09 6c 58 4f 5e 76 d9 63 dc c3 d5 63 |...:.lXO^v.c...c|
-00000020 be f2 75 ff 23 23 79 6b 82 fe 56 f5 b9 7a 55 55 |..u.##yk..V..zUU|
-00000030 32 3b ee c5 f0 1f 7b e9 82 01 21 8d 06 03 48 95 |2;....{...!...H.|
-00000040 21 b8 fa 9d 18 2a 08 9c 71 a8 4d 14 03 03 00 01 |!....*..q.M.....|
-00000050 01 16 03 03 00 40 31 f0 7b 5f e8 94 a3 7f b0 12 |.....@1.{_......|
-00000060 a9 80 87 26 eb cf b6 87 61 e7 5b 9b 36 3d 11 bb |...&....a.[.6=..|
-00000070 21 55 5c f7 e8 f3 b7 1e f2 06 0d c5 a9 8d f8 48 |!U\............H|
-00000080 c2 2b 8f 83 be 17 4f ec ff 8e 24 44 74 25 09 40 |.+....O...$Dt%.@|
-00000090 90 fd 70 4d fb bb |..pM..|
+00000000 16 03 03 00 25 10 00 00 21 20 af 52 73 d4 46 4d |....%...! .Rs.FM|
+00000010 bc 0e dd 56 1f 7f 72 ce 6c 99 b9 64 53 7d 53 8d |...V..r.l..dS}S.|
+00000020 0c a4 75 8c 83 3b 4b 76 2d 4f 14 03 03 00 01 01 |..u..;Kv-O......|
+00000030 16 03 03 00 40 a0 ef 9f 54 a8 ab 7c 5b 4a a1 b2 |....@...T..|[J..|
+00000040 5d 5b 6a d7 a7 32 35 46 58 d0 ba 38 6f 94 6e 9a |][j..25FX..8o.n.|
+00000050 41 16 82 ed 4d 39 c4 ff 06 bf 2c 67 47 70 56 4e |A...M9....,gGpVN|
+00000060 c5 ac 7f a0 5d d9 89 82 7a d9 36 07 55 b3 20 f4 |....]...z.6.U. .|
+00000070 b2 73 cf c3 7d |.s..}|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 13 eb 4e 56 3d |.............NV=|
-00000020 1b 10 2e e8 08 65 b9 53 9e 56 49 b7 e9 25 35 94 |.....e.S.VI..%5.|
-00000030 c7 df 7d f7 78 2e f3 8b 9c 2b 9d 42 90 91 5c 97 |..}.x....+.B..\.|
-00000040 22 20 ca 6d a2 83 b3 d8 b3 71 64 17 03 03 00 40 |" .m.....qd....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 73 5f db 9e 08 |...........s_...|
+00000020 10 38 3b c0 95 6b dd fc 16 b2 d1 db 63 13 ca d5 |.8;..k......c...|
+00000030 b5 be 5a 1d 74 b5 75 f3 a2 63 59 be a7 d0 ab 0d |..Z.t.u..cY.....|
+00000040 d3 43 83 8a 1d 59 ed fd ea f0 b9 17 03 03 00 40 |.C...Y.........@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 97 f1 c4 2e bf 6d 85 d5 3d 4b 4a 8b ee 53 08 5a |.....m..=KJ..S.Z|
-00000070 db 8b 75 49 d9 cb db e3 86 90 ac 93 ce e7 9a 70 |..uI...........p|
-00000080 4c dc 4a f4 c9 f6 b5 fd f0 3f 9f e9 f9 c3 b3 c6 |L.J......?......|
+00000060 cf 20 4f 4f bf c4 00 05 1e ca 7f 6f 69 77 e9 52 |. OO.......oiw.R|
+00000070 14 61 02 6d f1 c0 ad 7c 1a 34 cf b2 7a 58 4a 70 |.a.m...|.4..zXJp|
+00000080 11 36 5f e9 21 62 cb eb 8f e7 11 04 bf 66 03 69 |.6_.!b.......f.i|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 5e b1 b7 21 7d 89 65 66 17 d8 79 |.....^..!}.ef..y|
-000000b0 26 db ad 08 28 2c e7 7a c4 ec 93 19 4f c8 bb 5c |&...(,.z....O..\|
-000000c0 c2 9e 09 56 07 |...V.|
+000000a0 00 00 00 00 00 f5 35 92 09 6c 45 c0 27 95 98 a9 |......5..lE.'...|
+000000b0 86 56 53 1f a8 01 d5 0b 79 0e 91 15 3b 9a 07 21 |.VS.....y...;..!|
+000000c0 cb ce f0 2b 6a |...+j|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
index 276050873e..feced4bb8f 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 03 6e cc 37 81 0a |...._...[..n.7..|
-00000010 b9 fe 58 30 8e 32 61 3c b1 38 1e 2b f6 ab 44 ee |..X0.2a<.8.+..D.|
-00000020 f2 cc fe 6e fe 40 65 49 d9 ba aa 00 00 04 00 05 |...n.@eI........|
-00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .|
-00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 61 01 00 00 5d 03 03 b1 be 1f 18 b6 |....a...].......|
+00000010 a2 5d 4f 2f a0 e5 3b c4 4a 2d 76 bd 98 92 32 85 |.]O/..;.J-v...2.|
+00000020 9d 6b 9e 10 4b fc 03 7b fb bc e4 00 00 04 00 2f |.k..K..{......./|
+00000030 00 ff 01 00 00 30 00 23 00 00 00 0d 00 20 00 1e |.....0.#..... ..|
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000060 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 04 0e 00 00 00 |.........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 5d f3 3b c6 24 |...........].;.$|
-00000010 34 17 eb e1 6c de fa cd ed 6f 42 74 01 5f 4b 22 |4...l....oBt._K"|
-00000020 9e 79 da 68 9f e9 f8 af 84 6b b7 38 52 f3 5e a1 |.y.h.....k.8R.^.|
-00000030 e2 aa d1 48 15 1e 39 6e 18 59 3e dc 57 4a fb b1 |...H..9n.Y>.WJ..|
-00000040 18 18 40 ae 84 da d8 76 50 65 3b a5 d9 7a 72 b1 |..@....vPe;..zr.|
-00000050 51 07 65 08 0e 1d 05 f5 47 a8 7d 79 89 1e fe 00 |Q.e.....G.}y....|
-00000060 89 af 01 7f 4d 0c 11 d7 02 cf 88 7b be 03 c5 65 |....M......{...e|
-00000070 44 77 32 56 5c da 01 53 d1 dd d9 b4 5f 42 85 da |Dw2V\..S...._B..|
-00000080 82 0b 95 59 45 a3 7a 48 d4 00 22 14 03 03 00 01 |...YE.zH..".....|
-00000090 01 16 03 03 00 24 dd 06 a2 4b a0 8e 8b 31 f2 26 |.....$...K...1.&|
-000000a0 b2 6f d4 5d ff 34 eb 31 42 16 e7 c2 26 3d f7 16 |.o.].4.1B...&=..|
-000000b0 ed bd 41 4b 6f d4 03 fb b7 83 |..AKo.....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 8f f0 5a 2f 01 |.............Z/.|
+00000010 99 79 e6 f2 a0 31 a4 02 d8 c0 1e 70 e8 67 58 bd |.y...1.....p.gX.|
+00000020 a0 2a 37 3a 3c 2d 45 53 e7 d2 7d 94 16 ea 10 5c |.*7:<-ES..}....\|
+00000030 07 91 36 87 ab f6 d1 7a c7 40 a7 7f 23 1b ef 33 |..6....z.@..#..3|
+00000040 80 ea 7d 75 d3 62 de 7d d2 6b cf 90 54 0f e7 02 |..}u.b.}.k..T...|
+00000050 03 85 ef 38 f4 e9 88 8f e4 7c 8c ac 95 e6 88 f4 |...8.....|......|
+00000060 05 f7 c7 89 4a 64 de 34 5f 09 c2 84 19 36 c1 42 |....Jd.4_....6.B|
+00000070 ea 03 69 38 7e 32 10 8a b5 cf c7 2f 8e c6 5f 29 |..i8~2...../.._)|
+00000080 4e 8a 8e d4 17 6c 9c 18 7b ea df 14 03 03 00 01 |N....l..{.......|
+00000090 01 16 03 03 00 40 5f 50 47 5a 97 52 9d 11 b5 db |.....@_PGZ.R....|
+000000a0 ab 7b b9 e3 74 52 c5 cd f4 73 18 cf 12 c4 fe 07 |.{..tR...s......|
+000000b0 88 5f a9 18 7a 12 23 67 ec 72 07 9f 19 b5 bf 52 |._..z.#g.r.....R|
+000000c0 2f dd 26 66 25 98 8c 5a 07 0f 26 c1 b0 38 6c 01 |/.&f%..Z..&..8l.|
+000000d0 e4 f4 ee dd b3 72 |.....r|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c b5 83 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 |o,..aMQ_3FH.....|
-00000040 b1 aa c9 b1 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 |....a*.......&zu|
-00000050 f1 19 99 db 36 d8 32 f0 94 61 4f 8f ed 80 33 51 |....6.2..aO...3Q|
-00000060 f3 c6 15 84 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe |....k3..O..|'m..|
-00000070 41 8e b2 92 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae |A......l.uw.:...|
-00000080 f8 b9 6b 10 f9 85 da 14 03 03 00 01 01 16 03 03 |..k.............|
-00000090 00 24 70 bd b9 24 02 ce 69 8a 07 c7 c8 7e cf b7 |.$p..$..i....~..|
-000000a0 4e 2b e2 dc 47 fc f7 3a c8 2d ab a0 9a ed 27 d9 |N+..G..:.-....'.|
-000000b0 71 ea 45 29 d6 25 17 03 03 00 21 d9 28 ee 99 04 |q.E).%....!.(...|
-000000c0 35 ff ca 3d 30 3f 76 fb 08 1a 56 73 f5 72 c3 fa |5..=0?v...Vs.r..|
-000000d0 cd 9e 3c 1b 3f 43 4d 56 92 38 9e a6 15 03 03 00 |..<.?CMV.8......|
-000000e0 16 6f 55 57 7b 81 6f 7d fa 90 76 0b 5b 6d 95 35 |.oUW{.o}..v.[m.5|
-000000f0 39 9f a8 c9 dc b7 80 |9......|
+00000030 6f 2c 9f 83 61 0b b1 b7 9e 10 2d 0c 56 e8 70 66 |o,..a.....-.V.pf|
+00000040 ad de b1 15 74 2f 8b 08 8c 96 bb 4b 1b 4e dd 81 |....t/.....K.N..|
+00000050 0e bf 84 4d 43 8f c0 7e a0 7f be c0 59 bf 83 26 |...MC..~....Y..&|
+00000060 0f a2 22 52 2c 33 94 5a 77 54 f3 b5 f2 22 51 d5 |.."R,3.ZwT..."Q.|
+00000070 24 c2 60 c3 2e 0f 9c 5e 33 3b e8 7c 52 2a 76 08 |$.`....^3;.|R*v.|
+00000080 58 ac 47 98 bc 36 b6 14 03 03 00 01 01 16 03 03 |X.G..6..........|
+00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............|
+000000a0 00 00 31 fa c3 6c 95 c0 86 a5 55 30 41 c3 2d 6b |..1..l....U0A.-k|
+000000b0 a5 00 0b af 33 63 de 80 01 3d 7a 38 8e a7 f4 b1 |....3c...=z8....|
+000000c0 2d bb e3 1d 1a b4 61 18 b5 d9 d1 7f d1 9a e7 e8 |-.....a.........|
+000000d0 49 ee 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |I.....@.........|
+000000e0 00 00 00 00 00 00 00 a6 d5 e4 a8 9b d3 7d 72 1c |.............}r.|
+000000f0 ff 14 03 68 34 c9 ca 0d 2e 80 a1 09 f7 92 f6 86 |...h4...........|
+00000100 44 22 e8 1c ea e9 dd cc a7 92 9a 72 ec 22 5b 82 |D".........r."[.|
+00000110 7b 43 02 f7 fa 59 7b 15 03 03 00 30 00 00 00 00 |{C...Y{....0....|
+00000120 00 00 00 00 00 00 00 00 00 00 00 00 5f ab 03 1d |............_...|
+00000130 08 72 07 6d 78 66 5b 18 ec 3a b7 ea 75 96 ce 95 |.r.mxf[..:..u...|
+00000140 0c c9 6f 86 91 14 30 d6 2e 5d b1 b4 |..o...0..]..|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index b5eb6c785c..467e332489 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 03 54 25 f9 0f b8 |...._...[..T%...|
-00000010 2d 52 a0 17 b6 62 1c 60 38 31 30 67 f1 55 9c c8 |-R...b.`810g.U..|
-00000020 d3 74 65 bf cd 34 fb 6f f2 60 7c 00 00 04 00 05 |.te..4.o.`|.....|
-00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .|
-00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 61 01 00 00 5d 03 03 91 2f b7 db 1e |....a...].../...|
+00000010 41 ac c6 17 1d 0f 0c 8e 86 15 e0 de e9 c8 6b f5 |A.............k.|
+00000020 69 c7 bf ad ff 63 58 2b b1 79 a6 00 00 04 00 2f |i....cX+.y...../|
+00000030 00 ff 01 00 00 30 00 23 00 00 00 0d 00 20 00 1e |.....0.#..... ..|
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000060 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 04 0e 00 00 00 |.........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 19 db c8 25 14 |..............%.|
-00000010 e0 7b 6e 87 7b 59 2d 85 8b 47 ce 31 d7 3a 53 06 |.{n.{Y-..G.1.:S.|
-00000020 ff cf 89 ae 45 fd 59 d2 50 c2 31 33 48 81 a8 d7 |....E.Y.P.13H...|
-00000030 47 36 b9 bd 8d f3 f9 f8 c2 6d 6a 8a 6b c4 e5 53 |G6.......mj.k..S|
-00000040 24 52 40 66 49 a9 56 74 4c 94 bc 85 5b 79 5a e1 |$R@fI.VtL...[yZ.|
-00000050 66 3c 42 d8 ca e1 3f c5 36 b8 b5 8c b2 ea 87 68 |f<B...?.6......h|
-00000060 70 eb e3 da 27 fe ed f5 d0 4a c7 fe 46 0b 0f 29 |p...'....J..F..)|
-00000070 19 41 ef dd a9 85 8a 67 02 41 04 30 20 07 09 55 |.A.....g.A.0 ..U|
-00000080 ff 92 44 f1 59 49 39 dd fa d7 a0 14 03 03 00 01 |..D.YI9.........|
-00000090 01 16 03 03 00 24 82 b5 7b d1 7c 03 93 88 fd 97 |.....$..{.|.....|
-000000a0 54 b7 ff 39 a7 11 c3 cd 53 f3 1c 6c ed ab b6 a0 |T..9....S..l....|
-000000b0 1c b9 89 f0 1a f8 5f 15 7f 85 |......_...|
+00000000 16 03 03 00 86 10 00 00 82 00 80 c5 0c 17 b1 b2 |................|
+00000010 65 0b b7 7b 45 6f cb 7d b4 9c 5c 82 3a 1a 75 11 |e..{Eo.}..\.:.u.|
+00000020 22 6f 41 3a 81 e2 81 2e 74 f8 70 61 fd e1 7c ce |"oA:....t.pa..|.|
+00000030 bf 06 d7 29 77 07 b3 9d cc 33 25 53 17 12 43 ae |...)w....3%S..C.|
+00000040 4f df ad a4 3e 49 6e 97 50 b6 23 d0 fa 3d a6 bc |O...>In.P.#..=..|
+00000050 38 d8 5f 2b 45 a7 d0 aa cd b1 39 03 8f 62 9e 46 |8._+E.....9..b.F|
+00000060 50 d4 83 1d b8 76 41 29 d4 40 9a 65 41 8d 1c f0 |P....vA).@.eA...|
+00000070 d4 4d 88 d2 5e 42 ec c8 86 d6 fd df 65 d8 f1 82 |.M..^B......e...|
+00000080 8f 6a 80 31 1a 0e fc 13 2b 90 a8 14 03 03 00 01 |.j.1....+.......|
+00000090 01 16 03 03 00 40 50 ad ed 91 c4 6a ed f8 aa 06 |.....@P....j....|
+000000a0 9e 13 03 38 bf 83 ef 4b 8e d5 89 d4 a3 f8 d9 8d |...8...K........|
+000000b0 bb 88 72 a6 16 f6 5d d5 ca 55 bb e4 76 47 08 35 |..r...]..U..vG.5|
+000000c0 b9 fb 92 a4 0a b9 36 d7 62 44 81 e8 cf db ad 9a |......6.bD......|
+000000d0 6d 72 c0 af 70 bd |mr..p.|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c b5 83 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 |o,..a.Ue*.8.._A.|
-00000040 45 e4 f8 4b 3b 08 44 df 0b 72 11 93 cd d4 ff 36 |E..K;.D..r.....6|
-00000050 0f 4f 3a a9 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 |.O:.L.........-'|
-00000060 39 a8 82 84 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f |9....3.H..X.`e<?|
-00000070 17 9d 6a eb 50 cd 65 04 bb c7 28 c8 0d 57 44 52 |..j.P.e...(..WDR|
-00000080 e0 17 de df f3 13 b1 14 03 03 00 01 01 16 03 03 |................|
-00000090 00 24 5a 41 90 0a eb d9 6b 02 68 3d 98 12 1d fa |.$ZA....k.h=....|
-000000a0 46 7d 73 ea 8e 49 72 a5 2f 04 40 5c 7d 03 c7 3a |F}s..Ir./.@\}..:|
-000000b0 6e 50 7c 87 bb 13 17 03 03 00 21 46 da ec ad 52 |nP|.......!F...R|
-000000c0 ea 5a 01 89 15 77 79 af 86 02 b5 89 c8 97 dc f7 |.Z...wy.........|
-000000d0 ac 73 09 87 7a 61 57 d6 9b 17 10 af 15 03 03 00 |.s..zaW.........|
-000000e0 16 bb 20 22 ad 6e 65 66 8c d6 07 e3 82 5f ac 1e |.. ".nef....._..|
-000000f0 ec 54 72 eb 2d c5 af |.Tr.-..|
+00000030 6f 2c 9f 83 61 2e fe 48 fe f6 bb 98 a0 6f b0 be |o,..a..H.....o..|
+00000040 9e 86 d7 b2 f2 67 c7 44 c7 3d e4 2b de d0 f4 d2 |.....g.D.=.+....|
+00000050 17 51 84 8e 7a a7 80 c4 65 14 f7 49 09 68 15 56 |.Q..z...e..I.h.V|
+00000060 68 32 41 d1 6f 33 94 a1 3a c9 37 20 5d e6 b0 6f |h2A.o3..:.7 ]..o|
+00000070 37 0a 10 e3 28 e1 34 b6 6d e6 7a 44 24 7f 2f cf |7...(.4.m.zD$./.|
+00000080 1b ae dd 4c d0 11 75 14 03 03 00 01 01 16 03 03 |...L..u.........|
+00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............|
+000000a0 00 00 7e 4a 31 e8 7d c6 eb 34 56 3b 62 0c 11 a2 |..~J1.}..4V;b...|
+000000b0 f0 bd 9b 9a 4c c9 39 2d ed 21 dd 0c 72 3a 92 e1 |....L.9-.!..r:..|
+000000c0 0f b3 7f 71 c5 cf 2a 6f 68 bc 8e 84 7e d5 10 2e |...q..*oh...~...|
+000000d0 c3 d4 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |......@.........|
+000000e0 00 00 00 00 00 00 00 43 76 cc 74 b3 1c 89 c0 6b |.......Cv.t....k|
+000000f0 96 f7 2c 84 c1 0a 6e d6 7f b4 76 76 2c 2f 74 6a |..,...n...vv,/tj|
+00000100 c7 4e 18 69 1c 97 cd ca f2 7a 33 01 3e 6f bb 54 |.N.i.....z3.>o.T|
+00000110 49 4e 8e 1d f4 13 74 15 03 03 00 30 00 00 00 00 |IN....t....0....|
+00000120 00 00 00 00 00 00 00 00 00 00 00 00 2d 70 b1 13 |............-p..|
+00000130 a9 e3 72 ca 05 8e 8d b7 f4 97 de 58 46 aa 2a 9c |..r........XF.*.|
+00000140 2f 8c 3e 59 7b 64 e5 51 61 7f a6 39 |/.>Y{d.Qa..9|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
index 23b6c5be8c..af50381abc 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -1,77 +1,76 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 1e c8 d0 4c b2 |....[...W.....L.|
-00000010 8d 37 e1 88 c7 0f e0 6a 21 3c 5e 8a bf fa 97 1f |.7.....j!<^.....|
-00000020 5b 28 bc 6d 47 32 0a 6b f7 11 f5 00 00 04 00 0a |[(.mG2.k........|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 0c fb 72 82 e5 |....]...Y....r..|
+00000010 9a 04 90 c8 0d 73 25 9a 3f 88 e3 48 71 a2 33 3e |.....s%.?..Hq.3>|
+00000020 90 32 74 bc 12 38 d6 3a d3 11 1d 00 00 04 00 0a |.2t..8.:........|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 4d c2 e0 9b 40 |...........M...@|
-00000010 44 52 aa 55 06 71 0b bc 17 89 3a 94 d8 d0 1d ed |DR.U.q....:.....|
-00000020 70 d3 21 30 1b be 97 e0 72 30 60 05 de 9a a9 dd |p.!0....r0`.....|
-00000030 8c 0c 81 78 3a 15 9c 1c c6 22 81 0a 10 57 d1 9a |...x:...."...W..|
-00000040 17 5c 74 9e 58 79 4b f1 70 d9 d9 21 d8 79 64 fa |.\t.XyK.p..!.yd.|
-00000050 aa a5 e6 93 2a 16 57 23 a7 17 fb 71 b6 c2 d3 5b |....*.W#...q...[|
-00000060 3d 22 50 16 47 17 5f 15 e8 f1 30 da 10 69 84 25 |="P.G._...0..i.%|
-00000070 05 d0 b5 f0 e8 69 72 4e 93 d3 7c 1a 01 6d 37 fb |.....irN..|..m7.|
-00000080 cf e1 af f9 da dd 71 56 9b 08 24 14 03 03 00 01 |......qV..$.....|
-00000090 01 16 03 03 00 30 53 ab b5 09 5a 36 36 df b1 ed |.....0S...Z66...|
-000000a0 d2 69 5c 45 0b a9 02 8f 6d 25 d4 01 da 5f 27 ab |.i\E....m%..._'.|
-000000b0 ba 89 6e ee d8 91 24 f8 5e ca 6e 4d 51 41 88 3c |..n...$.^.nMQA.<|
-000000c0 f8 67 b4 fb d3 cb |.g....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 04 90 54 41 b9 |.............TA.|
+00000010 22 12 39 d9 1d 0b b8 6c d4 b3 8a ec 78 42 80 a5 |".9....l....xB..|
+00000020 03 c9 2a 9e 95 6f a0 28 3a 5c e9 59 28 ba 49 9b |..*..o.(:\.Y(.I.|
+00000030 37 63 61 3f c4 ac ba 55 6b 85 a5 27 ed 37 b9 25 |7ca?...Uk..'.7.%|
+00000040 04 cf 84 ad 43 6b ab 13 fa 72 29 b8 01 d9 aa 0c |....Ck...r).....|
+00000050 be b1 9a c4 5a 05 3d 2d 71 b4 72 f5 3a 77 fb 6b |....Z.=-q.r.:w.k|
+00000060 45 b0 5b 00 f8 1e f9 70 7f a4 64 c9 1e 35 56 0b |E.[....p..d..5V.|
+00000070 68 07 4c 04 95 f4 ca b1 0a b3 25 2b 93 2d be 80 |h.L.......%+.-..|
+00000080 76 15 75 07 23 ee 25 f3 1b a8 2f 14 03 03 00 01 |v.u.#.%.../.....|
+00000090 01 16 03 03 00 30 e5 cd 56 75 e6 a4 58 e5 33 cc |.....0..Vu..X.3.|
+000000a0 95 23 e0 7f 01 f2 45 21 bb 7d 7c 17 1f 59 7c f9 |.#....E!.}|..Y|.|
+000000b0 38 05 a3 95 4d 9b f2 3f 9d 84 2c 31 15 8b 4d d4 |8...M..?..,1..M.|
+000000c0 17 3c 62 2b f6 71 |.<b+.q|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....|
-00000010 00 00 00 50 83 52 65 2d 6e 76 aa 8d 2d 46 06 12 |...P.Re-nv..-F..|
-00000020 1a e7 25 79 28 61 9e 2d 07 0b fb 3c 77 38 d8 b0 |..%y(a.-...<w8..|
-00000030 af ca 86 8a 51 07 4d 83 39 81 9b 17 03 03 00 30 |....Q.M.9......0|
-00000040 00 00 00 00 00 00 00 00 a1 ea 74 b2 7b fc 3f 9d |..........t.{.?.|
-00000050 bc eb 9d 09 a2 56 4a ff d4 fd 00 23 0b e6 69 62 |.....VJ....#..ib|
-00000060 0e 4c 82 43 3f 21 8f b8 fd 5c ce 37 6c 57 d2 98 |.L.C?!...\.7lW..|
-00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 dc 47 cc |.... .........G.|
-00000080 34 eb 9e 7f d0 8f 5a 32 e6 6d 76 15 18 cc 8d 21 |4.....Z2.mv....!|
-00000090 43 91 81 31 81 |C..1.|
+00000010 00 00 00 b3 85 c2 1b ac 9e c2 01 f7 0f 76 6d 09 |.............vm.|
+00000020 5c 4f 9f a6 89 1b 56 e3 05 0b 7e 0d 9d 6b 36 35 |\O....V...~..k65|
+00000030 49 99 aa 4c 14 3b 69 2a 87 71 7d 17 03 03 00 30 |I..L.;i*.q}....0|
+00000040 00 00 00 00 00 00 00 00 15 65 d4 be e5 1b c9 29 |.........e.....)|
+00000050 e9 3a c4 22 72 f8 0c 40 c7 f5 45 a1 a3 c8 a8 64 |.:."r..@..E....d|
+00000060 22 4c 6c 79 3f 32 66 d4 05 09 a8 d4 d8 a8 f3 c7 |"Lly?2f.........|
+00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 fc 8d c6 |.... ...........|
+00000080 3d b1 c4 9f 30 26 e3 b9 46 8f ce 9f 7e 5b 1e a3 |=...0&..F...~[..|
+00000090 d0 98 64 3c 0d |..d<.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
index 66155e76d3..813f7489c8 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 5a ba 29 44 35 |....[...W..Z.)D5|
-00000010 c4 48 64 61 06 84 70 5c b5 65 ad 01 9b b2 29 0d |.Hda..p\.e....).|
-00000020 d1 46 17 3a 27 fb 92 d8 aa 21 aa 00 00 04 00 2f |.F.:'....!...../|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 7a e5 86 e2 0a |....]...Y..z....|
+00000010 53 e7 ba 32 d1 57 47 ed 45 29 1b 33 2c 58 33 8f |S..2.WG.E).3,X3.|
+00000020 36 2c 50 6f f9 c7 3b 12 40 23 e2 00 00 04 00 2f |6,Po..;.@#...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 ad e8 09 aa 07 |................|
-00000010 c0 3c 8b 39 d2 a8 bd ca 59 eb cf 0a de 33 3e d2 |.<.9....Y....3>.|
-00000020 4f 76 1f 7a 96 50 b3 52 6b 04 9e 6f f1 06 2b 4a |Ov.z.P.Rk..o..+J|
-00000030 7f 01 f2 51 a3 a7 1e f6 20 a7 27 4e 97 68 61 98 |...Q.... .'N.ha.|
-00000040 9f fd bd aa e8 e6 80 4d 9a 65 51 35 11 44 e4 2c |.......M.eQ5.D.,|
-00000050 a2 47 33 d1 b6 b7 d5 40 c0 17 34 ff e2 12 8e 00 |.G3....@..4.....|
-00000060 41 e6 4f 3e 56 2f d9 30 6b d9 99 e3 9f ce 10 ba |A.O>V/.0k.......|
-00000070 7c 95 3b 49 c9 5f 1e 97 37 90 e4 da 9a e0 01 5f ||.;I._..7......_|
-00000080 b8 6f 95 19 40 0f ca 63 76 6b 2a 14 03 03 00 01 |.o..@..cvk*.....|
-00000090 01 16 03 03 00 40 86 cb f5 69 1b ee 67 6e 3b be |.....@...i..gn;.|
-000000a0 e0 de 22 06 8c d4 f4 98 a6 45 1c 2f e5 f0 b4 25 |.."......E./...%|
-000000b0 f4 c0 87 7f e8 1c 2c 1d 20 52 50 fe dc a3 0c 22 |......,. RP...."|
-000000c0 b7 7f d3 9c 42 b8 23 d0 3e fd 93 be a2 50 28 dd |....B.#.>....P(.|
-000000d0 79 f3 c6 90 c7 bb |y.....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 8f 13 d1 23 1b |..............#.|
+00000010 8d 28 c7 a3 97 66 9f 8a c1 13 a1 c9 3b 25 93 7a |.(...f......;%.z|
+00000020 ea 54 58 fc 57 41 ca 92 77 99 13 01 61 e4 73 90 |.TX.WA..w...a.s.|
+00000030 c7 f1 2b 5e 5e 79 cf 69 7d 6b 3f 6e 5f 2e b0 f5 |..+^^y.i}k?n_...|
+00000040 f7 53 2b 46 15 92 6c 20 95 6b 44 6a 0a 3d 0b 56 |.S+F..l .kDj.=.V|
+00000050 66 53 ff 55 ec 38 10 cf 76 2c 0e ab 45 7a 02 6a |fS.U.8..v,..Ez.j|
+00000060 75 07 11 80 6c d0 57 79 ed d6 4b b8 a0 04 91 a0 |u...l.Wy..K.....|
+00000070 d4 4b 76 38 9c b3 a6 2e 0c 3e 63 a8 18 15 c9 ab |.Kv8.....>c.....|
+00000080 54 69 cd e5 6f 3c 56 a6 5f a7 e0 14 03 03 00 01 |Ti..o<V._.......|
+00000090 01 16 03 03 00 40 06 07 16 b4 7f fa 1a 8f 9b 1a |.....@..........|
+000000a0 a3 23 ba 5f ce ff 0a 70 b1 11 2b 84 77 7a 78 1a |.#._...p..+.wzx.|
+000000b0 6c 32 93 6c 31 e8 e5 26 12 97 14 33 a9 77 71 19 |l2.l1..&...3.wq.|
+000000c0 0b 20 5d 8f 3c 71 0d a4 b9 94 aa ff 42 8e d3 2d |. ].<q......B..-|
+000000d0 7e 57 3b 35 41 cc |~W;5A.|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 70 e5 19 ef 25 |...........p...%|
-00000020 05 0b 02 79 2b 79 49 e6 2c ad c0 e7 03 b3 40 68 |...y+yI.,.....@h|
-00000030 67 98 31 7c 7e 85 86 a8 5c de 72 3f d1 59 12 20 |g.1|~...\.r?.Y. |
-00000040 87 95 44 57 64 35 03 f5 68 61 20 17 03 03 00 40 |..DWd5..ha ....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 51 27 cd 07 6e |...........Q'..n|
+00000020 72 c8 17 ba e7 62 7c d0 49 55 e7 e6 c5 2c 93 39 |r....b|.IU...,.9|
+00000030 55 02 f5 fa 9a 7a 6f c5 79 6f ff 0f 4b b9 3d ad |U....zo.yo..K.=.|
+00000040 23 c7 53 ad 13 2d d6 da 83 d0 67 17 03 03 00 40 |#.S..-....g....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 1b 17 7c bb 04 4f 31 7b da 40 5e 93 64 97 4a 8d |..|..O1{.@^.d.J.|
-00000070 98 cf 77 2d 01 53 37 53 2c 59 8f ca ac 65 ae f3 |..w-.S7S,Y...e..|
-00000080 f8 d4 ae 67 74 c8 72 21 67 51 9a 1b 71 f2 0e 04 |...gt.r!gQ..q...|
+00000060 f5 09 3b 69 c2 1f f8 03 78 1b 13 57 ca 92 96 eb |..;i....x..W....|
+00000070 f8 71 30 09 5a 68 01 47 96 b1 5b 7d b7 57 5e 70 |.q0.Zh.G..[}.W^p|
+00000080 00 77 bb 55 32 7b d9 a5 f7 e2 a8 6d 4b d6 be c6 |.w.U2{.....mK...|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 fd 36 99 3d c7 44 1b 30 39 4a a7 |......6.=.D.09J.|
-000000b0 40 43 e3 01 2b 22 3d c6 8c a1 0d 73 d5 16 d2 25 |@C..+"=....s...%|
-000000c0 19 c8 d7 76 ee |...v.|
+000000a0 00 00 00 00 00 58 1e a0 14 82 8d e4 c5 92 35 79 |.....X........5y|
+000000b0 3b 5e 3a fe 97 18 db 27 19 7e b5 14 8c 01 fb 6a |;^:....'.~.....j|
+000000c0 e4 26 96 e6 de |.&...|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
index a6e7a079a7..4e52915ac5 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -1,86 +1,79 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 19 c7 02 a0 bf |................|
-00000010 5a fb c2 d4 f5 68 0a 19 0f 5e 3a 6b c5 88 17 0b |Z....h...^:k....|
-00000020 35 ff df ee 06 32 ad 32 99 0e c9 00 00 04 c0 2f |5....2.2......./|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 4e 1a d7 67 e4 |....s...o..N..g.|
+00000010 d1 11 85 bc 62 59 da 8f ea d0 a0 2b 9b d3 47 aa |....bY.....+..G.|
+00000020 d0 39 6f 3f 42 dc 7c 16 bb 25 ef 00 00 04 c0 2f |.9o?B.|..%...../|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 97 53 |.h.A.Vk.Z......S|
-00000300 cc 1f a2 55 e2 52 69 a6 b3 78 4f 7e 34 3e 37 e4 |...U.Ri..xO~4>7.|
-00000310 e0 bb 15 ff 96 f8 1d 9c 11 03 2c 68 ca 6d 2b 3c |..........,h.m+<|
-00000320 b3 96 64 21 d6 3f 81 42 07 c0 1b 85 7e a9 65 54 |..d!.?.B....~.eT|
-00000330 23 89 33 c1 71 b9 29 72 47 8a 0e 71 75 20 d7 b6 |#.3.q.)rG..qu ..|
-00000340 9d c2 ac c1 a8 dc 6c 0e 7e 29 93 fc b2 68 83 2e |......l.~)...h..|
-00000350 e1 fe e5 eb 54 d7 c3 30 f2 8f 9d 91 49 48 4f 84 |....T..0....IHO.|
-00000360 1a d5 47 75 27 bf c8 09 65 4a a8 7c 65 a0 d0 23 |..Gu'...eJ.|e..#|
-00000370 9f 26 d6 57 62 cb e1 06 64 90 16 73 1b d4 16 03 |.&.Wb...d..s....|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 b2 49 30 60 b7 0c 48 cb 9f 1c 75 |t.....I0`..H...u|
+000002d0 a6 b0 b0 7b 5e e6 f9 bc 5a 49 d4 51 e2 76 4c 01 |...{^...ZI.Q.vL.|
+000002e0 55 bd 37 cf 86 75 4f 33 9b fd 3c fc bb da 81 a9 |U.7..uO3..<.....|
+000002f0 26 7b 82 31 c5 51 0f d4 e8 fa a3 16 45 19 c8 40 |&{.1.Q......E..@|
+00000300 23 fa 32 bc 05 36 fb a7 a2 d9 6f e7 bc b8 27 0b |#.2..6....o...'.|
+00000310 2a 9e 7b 95 fd b4 c0 2e f0 73 fe fb a2 ea 20 a2 |*.{......s.... .|
+00000320 73 73 96 c8 bc 82 58 09 84 fc f4 09 2a c8 68 cb |ss....X.....*.h.|
+00000330 66 b0 de 2c 78 7a d4 ec 06 f1 1c 52 03 5a 69 24 |f..,xz.....R.Zi$|
+00000340 c4 e6 bb 68 f4 16 03 03 00 04 0e 00 00 00 |...h..........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1a 94 a7 1a 36 |....F...BA.....6|
-00000010 d1 ca ad d7 e8 64 03 84 b4 a6 9f dc 30 a2 a3 60 |.....d......0..`|
-00000020 a0 5a 1f a0 3d 8e d1 b8 96 75 37 ee a6 3f d6 ad |.Z..=....u7..?..|
-00000030 93 b6 7d 58 99 53 04 4b 6e c6 7f 04 bf 60 f9 ba |..}X.S.Kn....`..|
-00000040 e7 b8 04 73 10 77 ff 22 93 b2 7b 14 03 03 00 01 |...s.w."..{.....|
-00000050 01 16 03 03 00 28 29 6b 2b 14 21 a7 e4 84 c0 9d |.....()k+.!.....|
-00000060 92 07 cd dd 0b eb c1 b0 76 06 71 48 46 93 b8 05 |........v.qHF...|
-00000070 1a 2b 53 14 da 34 ac 05 4c cc 4d 47 12 28 |.+S..4..L.MG.(|
+00000000 16 03 03 00 25 10 00 00 21 20 41 d4 8d 53 2e 47 |....%...! A..S.G|
+00000010 b8 35 ba 86 3c 41 07 2e c1 a0 9d c2 e9 11 d8 20 |.5..<A......... |
+00000020 a1 fa 0a ff 28 64 5b af c3 67 14 03 03 00 01 01 |....(d[..g......|
+00000030 16 03 03 00 28 78 fd 19 36 4d a7 ca ab ba 06 6b |....(x..6M.....k|
+00000040 3f a5 79 17 2f 2b ec f6 19 db 17 1a 52 ea 72 0b |?.y./+......R.r.|
+00000050 01 af 56 8b 14 8f 8a 04 f3 ff ea fe 33 |..V.........3|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
-00000010 00 00 00 b9 c9 6f cb 58 df 1c a1 0a 79 4e fa 8f |.....o.X....yN..|
-00000020 41 55 8a 0a f8 d1 83 88 28 fb 44 00 8a a5 11 39 |AU......(.D....9|
-00000030 5b d4 83 17 03 03 00 25 00 00 00 00 00 00 00 01 |[......%........|
-00000040 85 4f 2a 54 aa c0 ce 7b 1e 4e e4 64 56 57 68 5e |.O*T...{.N.dVWh^|
-00000050 fa 41 67 8a da 9d f4 78 a6 c6 13 76 7c 15 03 03 |.Ag....x...v|...|
-00000060 00 1a 00 00 00 00 00 00 00 02 38 71 21 c6 82 bc |..........8q!...|
-00000070 2e 37 14 1d 15 2f 74 9d 7c 99 d8 66 |.7.../t.|..f|
+00000010 00 00 00 ec 99 e0 9a 83 28 94 e6 72 4f be 28 24 |........(..rO.($|
+00000020 64 bd 9d 86 79 cc ab 05 15 39 06 6e da 0c b8 4e |d...y....9.n...N|
+00000030 6c a9 f3 17 03 03 00 25 00 00 00 00 00 00 00 01 |l......%........|
+00000040 9a d7 b0 54 dd 3c ae 8e 3f 1f 41 68 a5 01 a0 da |...T.<..?.Ah....|
+00000050 e8 8e 90 55 1a 11 f0 70 8d a3 af a4 29 15 03 03 |...U...p....)...|
+00000060 00 1a 00 00 00 00 00 00 00 02 a8 96 cb 16 d7 b1 |................|
+00000070 41 7e bc 0e 01 8f cc 47 40 e5 c7 2a |A~.....G@..*|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
index cc94ac745c..36be9da0d0 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
@@ -1,86 +1,79 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 55 9b 71 e2 46 |...........U.q.F|
-00000010 88 58 c4 16 6a 6e 14 3d 3a 5a f9 fe ec 68 71 24 |.X..jn.=:Z...hq$|
-00000020 d0 06 6f a1 56 8f d6 15 42 6b ba 00 00 04 c0 30 |..o.V...Bk.....0|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 b7 d2 dc fe 53 |....s...o......S|
+00000010 d6 13 08 19 be 30 22 17 db a7 06 9b 62 82 14 38 |.....0".....b..8|
+00000020 2e 68 70 08 02 7d 22 64 13 75 f5 00 00 04 c0 30 |.hp..}"d.u.....0|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7f 44 |.h.A.Vk.Z......D|
-00000300 af 7b 21 01 6b f0 1c 75 d3 6b 28 99 68 e1 0e d3 |.{!.k..u.k(.h...|
-00000310 a8 cb 5a 2e 23 ad d7 92 73 46 5b 66 88 bd f1 d6 |..Z.#...sF[f....|
-00000320 5d 52 d1 07 53 88 9c 64 e3 ce 80 b3 39 7f 9e 2b |]R..S..d....9..+|
-00000330 0a 02 a7 e1 3e 00 70 51 3b b4 52 d1 3c 4a e9 f7 |....>.pQ;.R.<J..|
-00000340 0f 85 fa ff d7 ba 96 fc 77 8e 66 8d c6 4c b8 c2 |........w.f..L..|
-00000350 a5 d3 ad 72 f0 8c ba d2 bf 1c 81 7b 4e d5 9e 80 |...r.......{N...|
-00000360 7e b2 90 a0 2f d6 ad c2 33 43 da 46 b0 22 40 ff |~.../...3C.F."@.|
-00000370 df 95 b3 1e f1 97 b9 7b 61 3c 78 d9 ae cb 16 03 |.......{a<x.....|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 b8 c4 6a be 2a dd 47 03 7b 84 72 |t......j.*.G.{.r|
+000002d0 0b a4 c0 a7 2e b5 a4 be c7 6a 2a 8b d0 23 6f b5 |.........j*..#o.|
+000002e0 bc 0e ba 3c f5 9d a3 90 b0 af 80 11 bd 22 b5 7b |...<.........".{|
+000002f0 3c 53 f8 54 d0 b4 b0 53 28 75 0d 15 58 88 c2 90 |<S.T...S(u..X...|
+00000300 69 ea e0 08 aa 07 93 15 ae ed e5 a8 3d 2d 9c 62 |i...........=-.b|
+00000310 1d 40 26 7d 0e d3 23 52 71 71 ff ea 18 f9 0a eb |.@&}..#Rqq......|
+00000320 78 8a 8f 9e 12 8c 0b 33 a8 ee 42 76 16 29 58 ec |x......3..Bv.)X.|
+00000330 ea 6d 22 48 0d d0 68 c3 97 8d e9 ec cd 10 f6 47 |.m"H..h........G|
+00000340 c9 9d 42 12 54 16 03 03 00 04 0e 00 00 00 |..B.T.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 d8 85 85 d2 78 |....F...BA.....x|
-00000010 27 a5 0a bb 10 67 ec a9 d8 11 f0 ba b9 d7 21 39 |'....g........!9|
-00000020 ed c7 0a a0 a2 69 ab fb 9b 15 e0 d7 ec ca 97 c8 |.....i..........|
-00000030 c0 b2 66 0b 2c 68 37 ac f0 34 fa 3a 07 dd f2 ae |..f.,h7..4.:....|
-00000040 8e f6 e3 eb de 08 1f 56 e5 66 eb 14 03 03 00 01 |.......V.f......|
-00000050 01 16 03 03 00 28 f5 2d 89 00 0c 9d d9 0e 54 1b |.....(.-......T.|
-00000060 71 84 4d c7 bb 98 36 8c 29 b6 06 d8 7b df d9 92 |q.M...6.)...{...|
-00000070 01 00 16 44 5e e3 db f3 8f b7 fa 43 0c f7 |...D^......C..|
+00000000 16 03 03 00 25 10 00 00 21 20 20 df 4a b8 02 4f |....%...! .J..O|
+00000010 31 db 22 90 59 57 20 23 e1 72 8d 28 60 b3 f2 77 |1.".YW #.r.(`..w|
+00000020 db 3a ce 64 5a a5 63 94 be 09 14 03 03 00 01 01 |.:.dZ.c.........|
+00000030 16 03 03 00 28 de 72 f3 c3 b2 aa b4 9b b7 fe 35 |....(.r........5|
+00000040 3b 25 af 74 47 d3 49 39 07 d9 70 37 30 d0 b7 47 |;%.tG.I9..p70..G|
+00000050 bf ad 97 08 44 59 a7 3c 12 f2 4a 2d 7c |....DY.<..J-||
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
-00000010 00 00 00 a4 82 dc d1 67 ed 17 ae 22 13 0d ac d2 |.......g..."....|
-00000020 f4 58 44 5b b4 c6 25 29 80 b6 bc 63 0e 67 22 6e |.XD[..%)...c.g"n|
-00000030 18 92 48 17 03 03 00 25 00 00 00 00 00 00 00 01 |..H....%........|
-00000040 a0 fe 37 25 fb 4d 29 96 f9 01 67 19 d8 83 26 68 |..7%.M)...g...&h|
-00000050 d0 e8 58 2c ef 90 a3 b5 26 51 26 a9 28 15 03 03 |..X,....&Q&.(...|
-00000060 00 1a 00 00 00 00 00 00 00 02 91 4b d5 54 4a ef |...........K.TJ.|
-00000070 22 88 ab b7 a2 bb 20 5a b2 3e 7b 36 |"..... Z.>{6|
+00000010 00 00 00 16 18 e1 e8 d4 c0 d1 19 3a 50 10 85 fc |...........:P...|
+00000020 fc 3e 27 54 e4 57 b6 e7 c4 25 d5 4e 10 ad 0f ff |.>'T.W...%.N....|
+00000030 ad 45 8c 17 03 03 00 25 00 00 00 00 00 00 00 01 |.E.....%........|
+00000040 50 b8 af 5f a2 3e 0f f7 f0 81 1f 32 69 39 2f f2 |P.._.>.....2i9/.|
+00000050 47 28 80 fb d0 46 d4 b7 a2 ba e3 71 ea 15 03 03 |G(...F.....q....|
+00000060 00 1a 00 00 00 00 00 00 00 02 c4 64 7a 81 b3 3a |...........dz..:|
+00000070 2c 71 35 ec f7 0c 52 36 20 2c eb fe |,q5...R6 ,..|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
index c55f891866..e49d1bcbbc 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -1,73 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 ec 96 78 51 74 |....[...W....xQt|
-00000010 1b f2 21 ad f2 4f 50 aa 67 f1 20 e2 4f d3 4d 0e |..!..OP.g. .O.M.|
-00000020 54 91 df 91 d8 81 e3 75 bb 20 c2 00 00 04 00 05 |T......u. ......|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 55 3e 1a 3f cc |....]...Y..U>.?.|
+00000010 14 18 07 db 5e 97 15 33 62 9d de 56 7b ea 52 bf |....^..3b..V{.R.|
+00000020 a3 ce c2 75 3f 52 0a 2f 3e 99 07 00 00 04 00 05 |...u?R./>.......|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 05 4b 04 74 76 |............K.tv|
-00000010 73 3a 92 04 4d 8b 3b 59 c2 43 c5 f4 07 e8 bc a3 |s:..M.;Y.C......|
-00000020 62 44 b7 80 9f 8f bc 43 8a 67 09 64 a7 93 9f f9 |bD.....C.g.d....|
-00000030 2c 55 03 4b e5 87 9d 18 a2 c3 48 4f 02 6e e0 23 |,U.K......HO.n.#|
-00000040 0b 2f 57 81 e4 38 50 11 d6 b1 71 4f c2 e5 a4 03 |./W..8P...qO....|
-00000050 34 a4 eb a1 42 47 79 05 bc 7b b8 26 5b c1 f9 82 |4...BGy..{.&[...|
-00000060 fc 58 49 eb 04 52 fe 57 3c ed 5c 2b d8 fe 49 d7 |.XI..R.W<.\+..I.|
-00000070 d2 2e 6c e8 74 74 0d 87 b3 f6 2d f0 ff 03 f0 2d |..l.tt....-....-|
-00000080 c8 a2 20 89 3f 3f 11 e1 fb 93 85 14 03 03 00 01 |.. .??..........|
-00000090 01 16 03 03 00 24 9a 81 c0 9e 76 b6 3d 78 37 8e |.....$....v.=x7.|
-000000a0 ab 33 48 93 bb 0d f4 86 3c ff 72 28 10 35 c2 10 |.3H.....<.r(.5..|
-000000b0 f0 a0 ff 0c 20 f3 c4 29 83 a6 |.... ..)..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 a7 55 0a e7 33 |............U..3|
+00000010 8e be 5a 3a b4 f4 06 6e fc 0e 42 6e f3 0c 01 5a |..Z:...n..Bn...Z|
+00000020 65 73 36 bd cd be 0f 65 2f d2 88 1a f0 5e f8 07 |es6....e/....^..|
+00000030 c1 fe 5f 5f d6 f5 fa 79 24 44 0d 33 4f e6 74 88 |..__...y$D.3O.t.|
+00000040 86 f1 76 84 29 b4 f2 ae eb 9b 00 a2 6a e4 97 58 |..v.).......j..X|
+00000050 8b 2e 04 8f 8f 5e fe b4 9d 38 1d 8d 40 a4 9b a2 |.....^...8..@...|
+00000060 17 50 8a e5 39 c9 e9 41 3e 0d 9c 42 2c 7a 88 bf |.P..9..A>..B,z..|
+00000070 f7 09 4e 27 0b fe cc 53 13 07 d5 7e 0e e6 02 3c |..N'...S...~...<|
+00000080 8a 3f f9 03 df b6 65 a0 77 ee 50 14 03 03 00 01 |.?....e.w.P.....|
+00000090 01 16 03 03 00 24 5f 41 3e 38 05 08 74 62 5b 4e |.....$_A>8..tb[N|
+000000a0 94 55 98 74 5c 65 1a 4c 49 08 1d 77 d7 f0 12 47 |.U.t\e.LI..w...G|
+000000b0 d2 ef a6 31 5c 36 03 b5 b5 9d |...1\6....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 93 15 62 c5 2b |..........$..b.+|
-00000010 4f 8a d7 0f 70 1f 9d 11 fc 8f 9a a9 b7 d7 44 50 |O...p.........DP|
-00000020 6e 0e 5b d7 3b de 15 7d 17 35 31 42 1f a4 40 17 |n.[.;..}.51B..@.|
-00000030 03 03 00 21 a9 ca 73 e9 ce 2d 21 ef 7d bc 40 91 |...!..s..-!.}.@.|
-00000040 41 c9 53 62 af 09 8e b4 37 0f fa ab b7 76 8f 5b |A.Sb....7....v.[|
-00000050 7d 0f 04 48 49 15 03 03 00 16 76 b1 d7 91 88 6f |}..HI.....v....o|
-00000060 b4 e7 a4 f1 d2 c2 ac 50 db 31 ae 5c f7 53 a1 68 |.......P.1.\.S.h|
+00000000 14 03 03 00 01 01 16 03 03 00 24 6f 68 a2 c0 4d |..........$oh..M|
+00000010 f4 cb c0 e5 8b 19 f9 2e 46 c3 3b 92 eb a9 42 8b |........F.;...B.|
+00000020 03 4a e2 62 9d f1 c0 39 b1 63 61 08 15 b0 ca 17 |.J.b...9.ca.....|
+00000030 03 03 00 21 50 9e 16 ce 7e af 8f 43 d1 1c 30 37 |...!P...~..C..07|
+00000040 85 e9 68 3a 9c 7e 26 90 dc 14 b1 ec 91 20 2b 4a |..h:.~&...... +J|
+00000050 24 b4 fa b1 50 15 03 03 00 16 59 74 08 41 73 01 |$...P.....Yt.As.|
+00000060 22 19 0b 35 6b 4d ee d2 15 50 42 de cc cf cc 09 |"..5kM...PB.....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
index 521376cedd..366ca8f75d 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,37 +1,41 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 f7 01 00 00 f3 03 03 35 70 0b ed 1c |...........5p...|
-00000010 83 57 b1 7b 0a 47 ce d4 07 3a 49 96 93 4c a1 83 |.W.{.G...:I..L..|
-00000020 4b ab b7 ab 7d b0 14 be dd 91 92 20 09 34 b7 de |K...}...... .4..|
-00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.|
-00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 04 00 05 |1.=L.O,m..uo....|
-00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...|
-00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
-00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..|
-00000080 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 b1 aa c9 b1 |aMQ_3FH.........|
-00000090 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 f1 19 99 db |a*.......&zu....|
-000000a0 36 d8 32 f0 94 61 4f 8f ed 80 33 51 f3 c6 15 84 |6.2..aO...3Q....|
-000000b0 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe 41 8e b2 92 |k3..O..|'m..A...|
-000000c0 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae f8 b9 6b 10 |...l.uw.:.....k.|
-000000d0 f9 85 da 00 0d 00 20 00 1e 06 01 06 02 06 03 05 |...... .........|
-000000e0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
-000000f0 03 02 01 02 02 02 03 00 0f 00 01 01 |............|
+00000000 16 03 01 00 f9 01 00 00 f5 03 03 23 77 58 99 0e |...........#wX..|
+00000010 44 ed 63 44 e4 e4 eb d1 83 c3 9c d0 24 12 a3 b9 |D.cD........$...|
+00000020 55 6b 4d da bf 84 9d 35 de 43 a0 20 7b 93 cb d3 |UkM....5.C. {...|
+00000030 c5 ce 5e d5 aa 48 91 a4 b2 c2 d7 72 09 0d 21 78 |..^..H.....r..!x|
+00000040 f0 ac 7a ed 9a a9 ad dd 51 8b b2 1c 00 04 00 2f |..z.....Q....../|
+00000050 00 ff 01 00 00 a8 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 61 |...........o,..a|
+00000080 0b b1 b7 9e 10 2d 0c 56 e8 70 66 ad de b1 15 74 |.....-.V.pf....t|
+00000090 2f 8b 08 8c 96 bb 4b 1b 4e dd 81 0e bf 84 4d 43 |/.....K.N.....MC|
+000000a0 8f c0 7e a0 7f be c0 59 bf 83 26 0f a2 22 52 2c |..~....Y..&.."R,|
+000000b0 33 94 5a 77 54 f3 b5 f2 22 51 d5 24 c2 60 c3 2e |3.ZwT..."Q.$.`..|
+000000c0 0f 9c 5e 33 3b e8 7c 52 2a 76 08 58 ac 47 98 bc |..^3;.|R*v.X.G..|
+000000d0 36 b6 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |6.... ..........|
+000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000f0 02 01 02 02 02 03 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 20 09 34 b7 de |........... .4..|
-00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.|
-00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 05 00 00 |1.=L.O,m..uo....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 7b 93 cb d3 |........... {...|
+00000030 c5 ce 5e d5 aa 48 91 a4 b2 c2 d7 72 09 0d 21 78 |..^..H.....r..!x|
+00000040 f0 ac 7a ed 9a a9 ad dd 51 8b b2 1c 00 2f 00 00 |..z.....Q..../..|
00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
-00000060 24 18 67 37 5a c6 ea 3f 5f 06 2d c3 f1 2a ff d3 |$.g7Z..?_.-..*..|
-00000070 45 ce fe 38 1a e6 39 25 e7 e5 01 4d 6e fd 23 af |E..8..9%...Mn.#.|
-00000080 dc 67 1b 1d e2 |.g...|
+00000060 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
+00000070 00 ac d9 95 88 c6 37 e8 3c 24 d8 d9 15 46 25 c6 |......7.<$...F%.|
+00000080 32 0c 75 80 11 3d 89 53 1c 7a b1 78 6a c1 1a d7 |2.u..=.S.z.xj...|
+00000090 91 6e c2 55 99 84 11 43 cd 62 99 3b 28 1b 2e 08 |.n.U...C.b.;(...|
+000000a0 a8 |.|
>>> Flow 3 (client to server)
-00000000 14 03 03 00 01 01 16 03 03 00 24 b5 75 e6 1d 1d |..........$.u...|
-00000010 cb 2c 5d 9f d1 07 de 23 11 84 c2 59 50 55 72 27 |.,]....#...YPUr'|
-00000020 f2 5e 34 e2 c1 53 bf 21 5f f4 c4 2c f1 e1 7a |.^4..S.!_..,..z|
+00000000 14 03 03 00 01 01 16 03 03 00 40 67 fd 43 2a 0b |..........@g.C*.|
+00000010 14 6b 89 53 84 a8 04 62 d6 30 af 68 eb 8e 2a de |.k.S...b.0.h..*.|
+00000020 67 c9 40 af 8b ac dd 29 a4 20 e4 da b0 dd c3 05 |g.@....). ......|
+00000030 82 83 8f 75 77 db 6c fe e7 20 54 e3 eb 51 31 68 |...uw.l.. T..Q1h|
+00000040 da 11 a3 6d a1 34 d9 f5 d1 ef c9 |...m.4.....|
>>> Flow 4 (server to client)
-00000000 17 03 03 00 21 93 92 dd 07 a3 8f 3d 34 6d b8 94 |....!......=4m..|
-00000010 a7 6f 18 27 e7 cd 30 0a 08 4f b6 9b cb 43 93 27 |.o.'..0..O...C.'|
-00000020 b6 8b 83 ae d6 8a 15 03 03 00 16 68 a1 a4 f8 66 |...........h...f|
-00000030 8a c0 e7 d3 97 83 cb 35 94 84 7a e6 47 3c 97 8c |.......5..z.G<..|
-00000040 69 |i|
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 ee e2 75 6f 78 b0 88 1a 8b 9b 91 |.......uox......|
+00000020 c9 8c 3b ae a5 93 71 12 55 66 f8 09 a5 1f 4b 1b |..;...q.Uf....K.|
+00000030 c2 fe 65 8b 3d d9 dc fa af dc 29 1b 83 da e0 6a |..e.=.....)....j|
+00000040 4b cd d0 dc 27 |K...'|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
index c3cd2efeb9..34748371cf 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 f7 01 00 00 f3 03 03 2b 89 3f 02 47 |...........+.?.G|
-00000010 f6 14 64 3b 64 08 84 6e 9c e1 c9 4d 4f 30 92 06 |..d;d..n...MO0..|
-00000020 d1 19 58 5d 93 30 41 4d a6 2c f6 20 53 3c e7 f4 |..X].0AM.,. S<..|
-00000030 23 7e 59 b1 32 c4 2d db 0b 6f ab 64 4a 72 c9 31 |#~Y.2.-..o.dJr.1|
-00000040 d9 b9 38 a8 b4 4e 0c 39 f8 f4 61 7a 00 04 00 05 |..8..N.9..az....|
-00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...|
-00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
-00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..|
-00000080 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 45 e4 f8 4b |a.Ue*.8.._A.E..K|
-00000090 3b 08 44 df 0b 72 11 93 cd d4 ff 36 0f 4f 3a a9 |;.D..r.....6.O:.|
-000000a0 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 39 a8 82 84 |L.........-'9...|
-000000b0 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f 17 9d 6a eb |.3.H..X.`e<?..j.|
-000000c0 50 cd 65 04 bb c7 28 c8 0d 57 44 52 e0 17 de df |P.e...(..WDR....|
-000000d0 f3 13 b1 00 0d 00 20 00 1e 06 01 06 02 06 03 05 |...... .........|
-000000e0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
-000000f0 03 02 01 02 02 02 03 00 0f 00 01 01 |............|
+00000000 16 03 01 00 f9 01 00 00 f5 03 03 e8 59 b4 a7 b2 |............Y...|
+00000010 77 86 57 47 0d d7 7b 2b c1 a2 04 fd 8d 4d e4 f5 |w.WG..{+.....M..|
+00000020 be e2 65 8e 28 9a fe c3 19 fc 43 20 40 38 fb 60 |..e.(.....C @8.`|
+00000030 f8 2f 36 f4 85 1d ee f1 53 f2 90 cf 3c 58 36 cd |./6.....S...<X6.|
+00000040 bd 22 b4 0c 92 a9 17 56 f9 b4 dd 9b 00 04 00 2f |.".....V......./|
+00000050 00 ff 01 00 00 a8 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 61 |...........o,..a|
+00000080 2e fe 48 fe f6 bb 98 a0 6f b0 be 9e 86 d7 b2 f2 |..H.....o.......|
+00000090 67 c7 44 c7 3d e4 2b de d0 f4 d2 17 51 84 8e 7a |g.D.=.+.....Q..z|
+000000a0 a7 80 c4 65 14 f7 49 09 68 15 56 68 32 41 d1 6f |...e..I.h.Vh2A.o|
+000000b0 33 94 a1 3a c9 37 20 5d e6 b0 6f 37 0a 10 e3 28 |3..:.7 ]..o7...(|
+000000c0 e1 34 b6 6d e6 7a 44 24 7f 2f cf 1b ae dd 4c d0 |.4.m.zD$./....L.|
+000000d0 11 75 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |.u... ..........|
+000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000f0 02 01 02 02 02 03 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 ab d9 61 5e d3 |.............a^.|
-00000010 87 d7 eb 21 12 6f f9 61 dd 8b de 76 d7 14 70 2f |...!.o.a...v..p/|
-00000020 9c 0f 3c d4 4c 77 41 e2 ac 73 18 c3 0f 66 f2 b1 |..<.LwA..s...f..|
-00000030 fd 4b 1e d9 cb 5c 94 16 4d c2 98 f9 0d 55 f7 79 |.K...\..M....U.y|
-00000040 e2 8d 2c 87 96 e7 10 fb 78 fb ce 27 5d 9f ac 97 |..,.....x..']...|
-00000050 d6 54 6f 0c 78 dc 7b 2e 49 4c e2 42 24 b9 3d de |.To.x.{.IL.B$.=.|
-00000060 89 5f 1a 40 54 33 11 96 89 6f 59 25 5e 89 60 40 |._.@T3...oY%^.`@|
-00000070 83 8c 0e 92 0e 7d 68 9d 17 74 ba 39 e8 6f e3 43 |.....}h..t.9.o.C|
-00000080 44 80 e6 62 4b 35 43 21 5b eb 32 14 03 03 00 01 |D..bK5C![.2.....|
-00000090 01 16 03 03 00 24 77 1a b5 2c 88 d7 a6 83 f5 30 |.....$w..,.....0|
-000000a0 a0 c3 b4 45 a6 af 9b c2 ac 55 cf 73 4f a0 ba e5 |...E.....U.sO...|
-000000b0 2a be 9c 97 d2 d2 0b e9 95 0e |*.........|
+00000000 16 03 03 00 86 10 00 00 82 00 80 5e 04 66 f2 27 |...........^.f.'|
+00000010 99 3b f8 15 9f b8 4a ab 8c 32 10 0d 5b c9 5b 0b |.;....J..2..[.[.|
+00000020 04 69 dc 2b 9e bb 28 38 b6 a0 0f 32 ae 8c 96 64 |.i.+..(8...2...d|
+00000030 63 97 6b b6 63 94 45 84 03 28 d1 d8 85 2f a7 bb |c.k.c.E..(.../..|
+00000040 be ca 3e f5 30 27 e1 fd e5 cc bc b5 61 3d 26 8d |..>.0'......a=&.|
+00000050 0e 93 dd 78 07 5c fe 1b a9 57 c7 ce e6 df eb 28 |...x.\...W.....(|
+00000060 74 ce 12 f3 df 3f c0 9e 54 b6 e0 b0 ea f7 08 c6 |t....?..T.......|
+00000070 e1 9b cb e7 e9 41 b0 b4 68 2f f2 9b 1a 0a e3 17 |.....A..h/......|
+00000080 df d7 18 ff 95 ca 36 07 32 ff f9 14 03 03 00 01 |......6.2.......|
+00000090 01 16 03 03 00 40 cb c3 74 05 82 ab 93 07 a2 8b |.....@..t.......|
+000000a0 24 27 c0 21 3e d1 15 12 9a 85 20 5b f5 7e 7e 0a |$'.!>..... [.~~.|
+000000b0 a0 8e b2 de aa 25 2a b3 3d 12 1b 01 45 ec 36 53 |.....%*.=...E.6S|
+000000c0 32 1d 81 c7 1d a6 96 c2 a9 2e af fa 90 6e 76 bb |2............nv.|
+000000d0 a2 bc 43 91 c9 ca |..C...|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 a9 ae 0c a5 ed |..........$.....|
-00000010 51 10 d9 14 71 41 40 bd be f5 44 98 11 2f d8 0f |Q...qA@...D../..|
-00000020 4d 42 bf 28 53 bf 02 7e d6 16 92 7f dd 03 ec 17 |MB.(S..~........|
-00000030 03 03 00 21 46 c2 68 a1 6a 35 67 e7 7d 62 71 43 |...!F.h.j5g.}bqC|
-00000040 6b ea d6 fc 22 fc 2d ad 45 d6 6d 98 9e e5 88 a0 |k...".-.E.m.....|
-00000050 ac 80 f7 6f 05 15 03 03 00 16 0c ae f4 fc 0e 09 |...o............|
-00000060 0b 09 73 69 83 0d 00 89 39 ff f6 20 4e 2b 88 3d |..si....9.. N+.=|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 7f 39 4c 83 d4 |............9L..|
+00000020 ca a2 7a a8 eb 3e 45 18 6e 33 3d 6f eb 2d 4f 72 |..z..>E.n3=o.-Or|
+00000030 35 ee c3 f8 22 fd 39 28 47 23 55 16 6c 47 80 b7 |5...".9(G#U.lG..|
+00000040 65 31 15 f6 89 79 96 bd 6a df 1d 17 03 03 00 40 |e1...y..j......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 0c ea 0d 87 9a 24 d5 cc 26 9a a2 32 df 04 24 7d |.....$..&..2..$}|
+00000070 45 ed 35 4e 5b a0 57 c1 c7 f1 0f 8b b0 f9 49 85 |E.5N[.W.......I.|
+00000080 d6 e6 36 26 d5 f3 e4 00 76 d0 d6 20 be b3 31 e5 |..6&....v.. ..1.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 6c 51 e9 c2 e8 4f 43 e2 ce 01 9d |.....lQ...OC....|
+000000b0 d9 6f d7 c7 bf 16 d9 28 ca 8a ea 5e d5 84 ba 55 |.o.....(...^...U|
+000000c0 b7 23 9d 79 28 |.#.y(|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
index ae52ac2ae1..852cc63d03 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 07 0f b6 b9 cc |....o...k.......|
-00000010 db 23 57 92 d0 9b 37 72 9d ad 9a 0d 17 6b dd b8 |.#W...7r.....k..|
-00000020 81 b7 7c 54 dd 68 fe 4e 28 00 39 00 00 04 00 2f |..|T.h.N(.9..../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 35 8f 03 0b f4 |....q...m..5....|
+00000010 81 dd d7 ec 8b cc 85 bd 07 5b 83 16 cc 6e b2 67 |.........[...n.g|
+00000020 fd 33 69 81 14 9a 14 9d 37 43 5a 00 00 04 00 2f |.3i.....7CZ..../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |.....@.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 72 6a 6f a8 c9 |...........rjo..|
-00000010 3e 4c 33 da 92 23 97 68 fc 4e ca 74 77 98 f3 88 |>L3..#.h.N.tw...|
-00000020 ba a0 55 b6 a0 6f ff c8 db 2b 90 17 1f 45 bc 26 |..U..o...+...E.&|
-00000030 62 6e b9 91 96 b9 03 5d eb f2 a2 59 87 7b 81 4a |bn.....]...Y.{.J|
-00000040 0c f9 e2 23 60 e3 c7 4d 53 4f 3a 1f c5 5f dd 15 |...#`..MSO:.._..|
-00000050 cc 78 c5 21 fd 33 02 68 77 7c 8d 5f e8 80 a7 84 |.x.!.3.hw|._....|
-00000060 a7 2c b3 1f 64 df 8a 63 e9 b3 24 02 c1 6a 94 bd |.,..d..c..$..j..|
-00000070 a1 62 e5 32 e5 d9 83 25 0d 0f 1a 02 90 8a cd 79 |.b.2...%.......y|
-00000080 1c bd 4a c2 f4 5d a0 24 c6 c1 ae 14 03 03 00 01 |..J..].$........|
-00000090 01 16 03 03 00 40 1f 1a 17 47 15 25 5b 3d 5f e5 |.....@...G.%[=_.|
-000000a0 f4 d9 64 47 5f 80 09 f7 dd 5a ff 58 19 08 b5 db |..dG_....Z.X....|
-000000b0 38 88 a4 44 07 01 fb 80 1d 89 b2 d4 af 95 80 b3 |8..D............|
-000000c0 75 13 82 0e 24 12 1d 5c 29 72 1d 21 d4 69 16 e0 |u...$..\)r.!.i..|
-000000d0 b5 4b 46 62 fe f7 |.KFb..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 4c 15 46 23 91 |...........L.F#.|
+00000010 a0 d8 6c 45 f0 49 7e 70 84 9f bf 53 3d 68 2c cc |..lE.I~p...S=h,.|
+00000020 20 3f 28 bd cf e6 6e fd e6 90 ff 87 14 82 65 00 | ?(...n.......e.|
+00000030 d6 b6 ef 5a 0c d6 30 76 88 d2 37 33 39 de 00 b4 |...Z..0v..739...|
+00000040 ec dd 30 3b f6 88 ff 4c b2 98 75 77 fd c3 61 38 |..0;...L..uw..a8|
+00000050 2d 00 f7 14 d8 a4 37 22 c0 db 8a bd 12 0b b8 cc |-.....7"........|
+00000060 37 82 78 d3 0e f2 0b 9b 51 c5 26 c5 e2 ce 3e 0e |7.x.....Q.&...>.|
+00000070 04 34 39 83 a8 f5 65 ff 40 d9 9b 4a 11 6b b3 d2 |.49...e.@..J.k..|
+00000080 f7 02 78 a9 7c f4 69 56 3a a4 98 14 03 03 00 01 |..x.|.iV:.......|
+00000090 01 16 03 03 00 40 d6 90 b3 07 d1 a1 c1 12 35 07 |.....@........5.|
+000000a0 4e c0 df 4b 17 cc fa 49 47 c9 22 c3 6f 70 fa ee |N..K...IG.".op..|
+000000b0 cf b3 61 d6 06 54 cd ce c2 15 17 8a a0 f6 5c 43 |..a..T........\C|
+000000c0 7c 92 ce 89 d4 96 53 d0 c7 e6 9a 24 bc 5a 83 e5 ||.....S....$.Z..|
+000000d0 9c 65 72 e7 80 a4 |.er...|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 a0 61 69 4c 9d |............aiL.|
+00000020 68 f3 f8 f6 a0 ef 1b f4 a2 f5 83 fa 03 87 ad 67 |h..............g|
+00000030 7e 9f df c6 ce 9f 69 ce 22 fc de 91 0d 18 00 fb |~.....i.".......|
+00000040 c1 5d a1 2d bb 89 29 4f f6 de 57 17 03 03 00 40 |.].-..)O..W....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 bb 54 f4 80 69 1d 3b 9c e7 9c 1a fb 4e 3d c1 02 |.T..i.;.....N=..|
+00000070 d3 05 86 35 47 61 59 aa 45 54 ae a2 59 4c 75 8c |...5GaY.ET..YLu.|
+00000080 8d a9 7d 7f a0 4b d9 65 7a 53 ef 7e ed a3 fa 9e |..}..K.ezS.~....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 cc fd 0f cb 74 a5 36 ce c1 cd 54 |.........t.6...T|
+000000b0 6f 66 81 c0 ab ff 72 ea f3 1f a6 b7 ef 46 45 68 |of....r......FEh|
+000000c0 9b 0b 7f 4f 46 |...OF|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
index 7ac8dc92a7..b35cd8de26 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 fe d6 ce b5 1b |....o...k.......|
-00000010 1c 50 0c db 9c 35 5d 0e f2 ee 57 3f 65 83 9f 28 |.P...5]...W?e..(|
-00000020 96 50 1c e0 7f 95 f9 17 39 4f c3 00 00 04 00 2f |.P......9O...../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 31 c7 3f 2b 99 |....q...m..1.?+.|
+00000010 95 d8 d5 b7 91 ab 95 c6 09 35 0c 2b bd b6 94 1e |.........5.+....|
+00000020 64 4a 2d b6 43 23 a0 01 e7 93 22 00 00 04 00 2f |dJ-.C#...."..../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |.....@.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 6f bc 33 c8 2d |...........o.3.-|
-00000010 5a 50 65 2f 06 1a 45 16 9e 5b ab 97 43 b1 9e 96 |ZPe/..E..[..C...|
-00000020 b5 4a fe c3 7c e8 e4 07 ea 00 47 d2 51 23 11 ae |.J..|.....G.Q#..|
-00000030 11 a8 79 71 b9 c6 82 17 40 ae c7 fc cd 05 4d 6d |..yq....@.....Mm|
-00000040 cb bc f1 ce 30 d0 10 37 4a e6 aa d3 14 fb bc 62 |....0..7J......b|
-00000050 eb 6c fa ec e1 e1 dd 63 39 95 0b 87 71 a0 83 ba |.l.....c9...q...|
-00000060 bf 25 f8 a9 d3 c4 35 e1 88 23 85 56 c6 f4 0b 10 |.%....5..#.V....|
-00000070 d1 70 f8 0a 3d a1 08 17 ce 27 2d 4c a7 c5 b5 0d |.p..=....'-L....|
-00000080 f2 43 b7 b9 02 21 7a eb 40 d2 66 14 03 03 00 01 |.C...!z.@.f.....|
-00000090 01 16 03 03 00 40 0a 93 47 0b 6e 40 ff cd 09 a5 |.....@..G.n@....|
-000000a0 bc a4 c5 a8 c3 1c 0a fb d4 2e 8a 2f 0c f3 d6 e1 |.........../....|
-000000b0 de 1f 56 2f 09 61 2d 31 d5 b1 29 6b f2 18 8b f2 |..V/.a-1..)k....|
-000000c0 0c 0e 09 5f ec 11 56 af 44 8b e5 2d 09 68 eb c2 |..._..V.D..-.h..|
-000000d0 91 4d 04 b2 10 02 |.M....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 c9 3a 9d ea e3 |............:...|
+00000010 19 f1 07 77 61 ef 5a aa ed 0f 26 b4 7a 45 db 05 |...wa.Z...&.zE..|
+00000020 bd 51 77 f5 ee 7b c1 83 9c 95 49 7b 70 5e 5b fe |.Qw..{....I{p^[.|
+00000030 25 d2 3d 64 74 b8 a4 97 fd cb b9 75 7b 8f b0 59 |%.=dt......u{..Y|
+00000040 30 bf b3 41 ce 54 83 0a ca 29 49 5a fe 29 4c 53 |0..A.T...)IZ.)LS|
+00000050 fb d6 6e 46 d9 f7 31 17 d6 ee f9 ac 41 82 22 11 |..nF..1.....A.".|
+00000060 a7 34 07 41 50 43 2f 83 f6 1f c6 c0 9d 4a 67 5a |.4.APC/......JgZ|
+00000070 af 44 59 c0 00 33 be 24 f7 0a a4 fe 76 6b 03 05 |.DY..3.$....vk..|
+00000080 2e ec 4d 49 db 6e e5 0a 5f af 09 14 03 03 00 01 |..MI.n.._.......|
+00000090 01 16 03 03 00 40 ad 89 4d 25 a2 ce 98 8c cf b6 |.....@..M%......|
+000000a0 f5 f4 76 6b e7 71 66 4a f9 a7 67 fb 1d 6c a7 83 |..vk.qfJ..g..l..|
+000000b0 3b 1d 6a af 65 f2 c1 1d 97 03 5b c2 34 ee 3b 8e |;.j.e.....[.4.;.|
+000000c0 cc bd 8f 3a b8 9b 4f 90 3f de 1e 97 1e 8e 61 37 |...:..O.?.....a7|
+000000d0 2d 30 35 84 3b 26 |-05.;&|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 fe 23 de 33 4b |............#.3K|
+00000020 55 f2 8e 73 09 ba ae f1 12 bd f7 15 75 90 8f 19 |U..s........u...|
+00000030 1b 19 b6 3f 2c 19 47 87 a9 43 d5 1e 85 fb 0c 90 |...?,.G..C......|
+00000040 c8 18 72 8f 08 6f 48 43 3c 5c 5a 17 03 03 00 40 |..r..oHC<\Z....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 4d 44 d7 eb a3 94 00 74 90 9d c0 bd 8e 11 eb b6 |MD.....t........|
+00000070 93 43 c6 14 0d ba c2 aa f0 f5 2d 85 9a 7c 27 44 |.C........-..|'D|
+00000080 fc d8 46 76 b2 21 4f 70 1a 9a df 9e 3a 8f a3 58 |..Fv.!Op....:..X|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 91 0f c3 2a 98 79 57 39 3c 68 98 |........*.yW9<h.|
+000000b0 df 36 12 de e5 15 ee cb 80 ce 33 d9 20 95 33 38 |.6........3. .38|
+000000c0 8b d8 ed 8f 9b |.....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
index 32c0d4a545..8ba207b253 100644
--- a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 64 29 6e 67 3d |....o...k..d)ng=|
-00000010 5a 13 48 8a ae a5 67 6b 2f 5b 76 d2 c1 df 23 c6 |Z.H...gk/[v...#.|
-00000020 f9 52 26 33 ce 0b 03 f6 53 a7 db 00 00 04 00 2f |.R&3....S....../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 f8 16 6b 20 c3 |....q...m....k .|
+00000010 a4 cf fc ca 04 47 7a f9 cc d9 cf 4a 15 ff 6e 82 |.....Gz....J..n.|
+00000020 14 6a 91 91 7f f1 f4 42 e6 7c d4 00 00 04 00 2f |.j.....B.|...../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |.....@.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 7b 3b b8 73 f0 |...........{;.s.|
-00000010 78 2c 75 91 ee 4a ac 6e 9d 08 8e ef dd 52 fb 38 |x,u..J.n.....R.8|
-00000020 d7 6f b3 39 8a 8c 3c dc 4b e0 a9 2b 0b de 9a d6 |.o.9..<.K..+....|
-00000030 38 72 ae 0f 76 87 4b f6 45 17 f6 fa b2 5a 07 30 |8r..v.K.E....Z.0|
-00000040 5b ef e7 40 e0 95 98 bf 8d 8d 5e 7a 6a ea 2d 2e |[..@......^zj.-.|
-00000050 9c 99 e4 47 6b 4f 16 32 fb 0d a7 01 36 2e 06 f2 |...GkO.2....6...|
-00000060 65 74 b6 ed 07 51 60 7a 98 d6 77 36 f4 c7 f6 b1 |et...Q`z..w6....|
-00000070 f1 6a 3e 38 7c 79 5c c6 b4 53 5c 85 fb 0b 2c f9 |.j>8|y\..S\...,.|
-00000080 2c 60 97 c8 73 f7 22 ef 52 4c 10 14 03 03 00 01 |,`..s.".RL......|
-00000090 01 16 03 03 00 40 4c 73 6e 5e 66 9d 53 2e fa b7 |.....@Lsn^f.S...|
-000000a0 90 2d 52 55 13 d2 67 28 aa 1a 6f 62 42 ef 2f 4d |.-RU..g(..obB./M|
-000000b0 04 1d ef 64 8f 1a 70 c0 d0 bf 06 72 ee db 3e 43 |...d..p....r..>C|
-000000c0 7f ed 37 bb a1 62 0c c5 c8 a9 c0 51 8f 77 95 b3 |..7..b.....Q.w..|
-000000d0 72 7e 01 89 c4 32 |r~...2|
+00000000 16 03 03 00 86 10 00 00 82 00 80 80 e8 00 cc 09 |................|
+00000010 fc 87 20 9f 2a 38 33 6f cb 61 71 86 6d 55 6a 87 |.. .*83o.aq.mUj.|
+00000020 e0 22 78 62 4e 3b 98 5c 87 fd 3b 1c 73 d3 77 7e |."xbN;.\..;.s.w~|
+00000030 a4 c3 6f d4 6d 82 65 40 0e 70 2f 24 e9 7d ff 49 |..o.m.e@.p/$.}.I|
+00000040 c7 bd 45 44 af ae a5 7a 06 06 5e 1e ce 31 73 4b |..ED...z..^..1sK|
+00000050 4a 38 f0 11 ba 32 58 ab a5 94 12 13 30 83 95 85 |J8...2X.....0...|
+00000060 f5 7e 8d a7 cc 6d 19 14 f9 b0 dc 64 e5 4d b1 7d |.~...m.....d.M.}|
+00000070 e6 95 d4 4a 7f 85 11 5b a7 c9 32 84 c2 ec 2e c3 |...J...[..2.....|
+00000080 40 fe 5c e2 cf 5b 96 8a 72 9f 9f 14 03 03 00 01 |@.\..[..r.......|
+00000090 01 16 03 03 00 40 a8 d2 5b 24 28 2b 86 1e c1 2e |.....@..[$(+....|
+000000a0 6f da 7a ac 6b bf 02 ea 10 5d 9c 71 fb 19 eb 17 |o.z.k....].q....|
+000000b0 19 b2 07 7c b9 df d0 6d 9f 80 cf 37 a0 2a 18 c9 |...|...m...7.*..|
+000000c0 e9 b5 9f 94 42 6a 6b 33 55 fb 6d 94 3b 79 ed 26 |....Bjk3U.m.;y.&|
+000000d0 5c 5a 7f 68 2c d8 |\Z.h,.|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 18 e9 b5 96 14 |................|
+00000020 38 98 d4 23 cd e5 32 0e 09 ae b3 3b 90 a4 4d c2 |8..#..2....;..M.|
+00000030 e5 a8 df 72 e8 97 0b 67 cb 87 f4 d0 3e 52 ca d1 |...r...g....>R..|
+00000040 28 94 ed 88 6c cb 62 53 b2 a1 04 17 03 03 00 40 |(...l.bS.......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 0e e3 b0 da 4b 19 ca 29 7b 1d c8 e3 0d d7 f2 97 |....K..){.......|
+00000070 b0 0b 6e f0 d2 4b f0 c4 ca 87 75 3c ae 66 e1 b3 |..n..K....u<.f..|
+00000080 06 e3 e6 90 54 fd 31 f7 5d 3b 6f de 0f d5 e4 09 |....T.1.];o.....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 ee a1 b0 94 b5 86 71 73 66 14 ac |...........qsf..|
+000000b0 5c 4e 1b 67 27 af db b6 e3 44 15 38 b1 f5 e0 13 |\N.g'....D.8....|
+000000c0 a5 e1 82 c0 6a |....j|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM
new file mode 100644
index 0000000000..89587e9b8d
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 73 01 00 00 6f 03 03 33 6d f4 4a 4b |....s...o..3m.JK|
+00000010 48 35 ef 62 e9 bd 66 90 7e 73 62 bf 93 51 3d 90 |H5.b..f.~sb..Q=.|
+00000020 9e f1 17 ae bd 24 28 54 44 50 8e 00 00 04 c0 2f |.....$(TDP...../|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 61 aa 96 74 97 9f 2a 81 df 73 4d |t....a..t..*..sM|
+000002d0 58 fb 8b 34 d9 51 02 1d 30 45 98 11 fa 20 cc 48 |X..4.Q..0E... .H|
+000002e0 18 8d 92 4a bc bf 34 c2 52 cc 7b 7d 93 32 f9 98 |...J..4.R.{}.2..|
+000002f0 eb d0 6d 58 4c 24 71 f1 78 cc ee 4d f8 26 26 d3 |..mXL$q.x..M.&&.|
+00000300 b0 1c 46 67 ff 75 fc b5 b3 75 31 f3 9d d6 51 07 |..Fg.u...u1...Q.|
+00000310 7a c1 2f 52 3f 88 23 f2 90 74 d0 77 6d 2b c7 31 |z./R?.#..t.wm+.1|
+00000320 3d 81 a8 b9 84 a6 8f 96 25 91 e8 31 3b e9 20 b8 |=.......%..1;. .|
+00000330 c4 11 68 da 58 0a ee 79 de fe 32 29 d6 24 b0 56 |..h.X..y..2).$.V|
+00000340 ab e8 b5 57 fc 16 03 03 00 04 0e 00 00 00 |...W..........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 eb 0e 38 40 3f 32 |....%...! ..8@?2|
+00000010 a4 95 fb c4 de e5 82 9a 4b 46 37 de 29 e5 6b e6 |........KF7.).k.|
+00000020 44 bf f0 af 0c 62 19 bd 5c 0e 14 03 03 00 01 01 |D....b..\.......|
+00000030 16 03 03 00 28 67 ad 91 f6 8d 8a 39 f7 f2 a6 42 |....(g.....9...B|
+00000040 f2 8c 2f 1d b3 1d dd f1 88 65 7e 66 d2 d9 70 09 |../......e~f..p.|
+00000050 4e 12 90 0d 0b d5 a5 a6 20 bc 32 63 05 |N....... .2c.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 56 b1 b8 16 9a 27 c6 ee d4 7f b7 68 83 |...V....'.....h.|
+00000020 43 3b 04 92 ec cc c7 db 82 f8 7d 04 64 1d 55 cf |C;........}.d.U.|
+00000030 02 69 ac 17 03 03 00 25 00 00 00 00 00 00 00 01 |.i.....%........|
+00000040 d6 69 51 5d 3b 00 93 c2 a6 19 97 7d bf a9 d9 96 |.iQ];......}....|
+00000050 43 1d ae 32 c3 52 1a f0 18 ba 10 4c e0 15 03 03 |C..2.R.....L....|
+00000060 00 1a 00 00 00 00 00 00 00 02 1e 8a 5e 37 c0 b1 |............^7..|
+00000070 0d 1e c9 6a 90 23 d6 4c 5c 47 5b bf |...j.#.L\G[.|
diff --git a/libgo/go/crypto/tls/ticket.go b/libgo/go/crypto/tls/ticket.go
index 7be50ce68c..3e7aa93c82 100644
--- a/libgo/go/crypto/tls/ticket.go
+++ b/libgo/go/crypto/tls/ticket.go
@@ -126,11 +126,7 @@ func (s *sessionState) unmarshal(data []byte) bool {
data = data[certLen:]
}
- if len(data) > 0 {
- return false
- }
-
- return true
+ return len(data) == 0
}
func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
index 4bedd7682d..615d1e5576 100644
--- a/libgo/go/crypto/tls/tls.go
+++ b/libgo/go/crypto/tls/tls.go
@@ -5,9 +5,9 @@
// Package tls partially implements TLS 1.2, as specified in RFC 5246.
package tls
-// BUG(agl): The crypto/tls package does not implement countermeasures
-// against Lucky13 attacks on CBC-mode encryption. See
-// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
import (
@@ -47,14 +47,13 @@ type listener struct {
}
// Accept waits for and returns the next incoming TLS connection.
-// The returned connection c is a *tls.Conn.
-func (l *listener) Accept() (c net.Conn, err error) {
- c, err = l.Listener.Accept()
+// The returned connection is of type *Conn.
+func (l *listener) Accept() (net.Conn, error) {
+ c, err := l.Listener.Accept()
if err != nil {
- return
+ return nil, err
}
- c = Server(c, l.config)
- return
+ return Server(c, l.config), nil
}
// NewListener creates a Listener which accepts connections from an inner
@@ -103,7 +102,7 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
timeout := dialer.Timeout
if !dialer.Deadline.IsZero() {
- deadlineTimeout := dialer.Deadline.Sub(time.Now())
+ deadlineTimeout := time.Until(dialer.Deadline)
if timeout == 0 || deadlineTimeout < timeout {
timeout = deadlineTimeout
}
@@ -136,9 +135,9 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
// from the hostname we're connecting to.
if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
- c := *config
+ c := config.Clone()
c.ServerName = hostname
- config = &c
+ config = c
}
conn := Client(rawConn, config)
@@ -171,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 {
@@ -210,12 +210,12 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
if len(cert.Certificate) == 0 {
if len(skippedBlockTypes) == 0 {
- return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input"))
- } else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
- return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
- } else {
- return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ return fail(errors.New("tls: failed to find any PEM data in certificate input"))
+ }
+ if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+ return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
}
+ return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
}
skippedBlockTypes = skippedBlockTypes[:0]
@@ -224,12 +224,12 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
if len(skippedBlockTypes) == 0 {
- return fail(errors.New("crypto/tls: failed to find any PEM data in key input"))
- } else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
- return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key"))
- } else {
- return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ return fail(errors.New("tls: failed to find any PEM data in key input"))
}
+ if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+ return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
+ }
+ return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
}
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
break
@@ -254,22 +254,21 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
case *rsa.PublicKey:
priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
if !ok {
- return fail(errors.New("crypto/tls: private key type does not match public key type"))
+ return fail(errors.New("tls: private key type does not match public key type"))
}
if pub.N.Cmp(priv.N) != 0 {
- return fail(errors.New("crypto/tls: private key does not match public key"))
+ return fail(errors.New("tls: private key does not match public key"))
}
case *ecdsa.PublicKey:
priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
if !ok {
- return fail(errors.New("crypto/tls: private key type does not match public key type"))
-
+ return fail(errors.New("tls: private key type does not match public key type"))
}
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
- return fail(errors.New("crypto/tls: private key does not match public key"))
+ return fail(errors.New("tls: private key does not match public key"))
}
default:
- return fail(errors.New("crypto/tls: unknown public key algorithm"))
+ return fail(errors.New("tls: unknown public key algorithm"))
}
return cert, nil
@@ -287,12 +286,12 @@ func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
case *rsa.PrivateKey, *ecdsa.PrivateKey:
return key, nil
default:
- return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
+ return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
}
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
- return nil, errors.New("crypto/tls: failed to parse private key")
+ return nil, errors.New("tls: failed to parse private key")
}
diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go
index 5cc14278a0..86812f0c97 100644
--- a/libgo/go/crypto/tls/tls_test.go
+++ b/libgo/go/crypto/tls/tls_test.go
@@ -6,11 +6,16 @@ package tls
import (
"bytes"
+ "crypto/x509"
"errors"
"fmt"
"internal/testenv"
"io"
+ "io/ioutil"
+ "math"
"net"
+ "os"
+ "reflect"
"strings"
"testing"
"time"
@@ -92,6 +97,7 @@ var keyPairTests = []struct {
}
func TestX509KeyPair(t *testing.T) {
+ t.Parallel()
var pem []byte
for _, test := range keyPairTests {
pem = []byte(test.cert + test.key)
@@ -146,7 +152,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")
@@ -188,18 +194,25 @@ func TestDialTimeout(t *testing.T) {
t.Fatal("DialWithTimeout completed successfully")
}
- if !strings.Contains(err.Error(), "timed out") {
- t.Errorf("resulting error not a timeout: %s", err)
+ if !isTimeoutError(err) {
+ t.Errorf("resulting error not a timeout: %v\nType %T: %#v", err, err, err)
}
}
+func isTimeoutError(err error) bool {
+ if ne, ok := err.(net.Error); ok {
+ return ne.Timeout()
+ }
+ return false
+}
+
// tests that Conn.Read returns (non-zero, io.EOF) instead of
// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
// behind the application data in the buffer.
func TestConnReadNonzeroAndEOF(t *testing.T) {
// This test is racy: it assumes that after a write to a
// localhost TCP connection, the peer TCP connection can
- // immediately read it. Because it's racy, we skip this test
+ // immediately read it. Because it's racy, we skip this test
// in short mode, and then retry it several times with an
// increasing sleep in between our final write (via srv.Close
// below) and the following read.
@@ -228,8 +241,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
srvCh <- nil
return
}
- serverConfig := *testConfig
- srv := Server(sconn, &serverConfig)
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
serr = fmt.Errorf("handshake: %v", err)
srvCh <- nil
@@ -238,8 +251,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
srvCh <- srv
}()
- clientConfig := *testConfig
- conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ clientConfig := testConfig.Clone()
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
}
@@ -280,20 +293,22 @@ func TestTLSUniqueMatches(t *testing.T) {
for i := 0; i < 2; i++ {
sconn, err := ln.Accept()
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
- serverConfig := *testConfig
- srv := Server(sconn, &serverConfig)
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
serverTLSUniques <- srv.ConnectionState().TLSUnique
}
}()
- clientConfig := *testConfig
+ clientConfig := testConfig.Clone()
clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
}
@@ -302,7 +317,7 @@ func TestTLSUniqueMatches(t *testing.T) {
}
conn.Close()
- conn, err = Dial("tcp", ln.Addr().String(), &clientConfig)
+ conn, err = Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
}
@@ -381,8 +396,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
srvCh <- nil
return
}
- serverConfig := *testConfig
- srv := Server(sconn, &serverConfig)
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
serr = fmt.Errorf("handshake: %v", err)
srvCh <- nil
@@ -401,8 +416,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
Conn: cconn,
}
- clientConfig := *testConfig
- tconn := Client(conn, &clientConfig)
+ clientConfig := testConfig.Clone()
+ tconn := Client(conn, clientConfig)
if err := tconn.Handshake(); err != nil {
t.Fatal(err)
}
@@ -445,6 +460,220 @@ func TestConnCloseBreakingWrite(t *testing.T) {
}
}
+func TestConnCloseWrite(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ clientDoneChan := make(chan struct{})
+
+ serverCloseWrite := func() error {
+ sconn, err := ln.Accept()
+ if err != nil {
+ return fmt.Errorf("accept: %v", err)
+ }
+ defer sconn.Close()
+
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ return fmt.Errorf("handshake: %v", err)
+ }
+ defer srv.Close()
+
+ data, err := ioutil.ReadAll(srv)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+
+ if err := srv.CloseWrite(); err != nil {
+ return fmt.Errorf("server CloseWrite: %v", err)
+ }
+
+ // Wait for clientCloseWrite to finish, so we know we
+ // tested the CloseWrite before we defer the
+ // sconn.Close above, which would also cause the
+ // client to unblock like CloseWrite.
+ <-clientDoneChan
+ return nil
+ }
+
+ clientCloseWrite := func() error {
+ defer close(clientDoneChan)
+
+ clientConfig := testConfig.Clone()
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ return err
+ }
+ if err := conn.Handshake(); err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ if err := conn.CloseWrite(); err != nil {
+ return fmt.Errorf("client CloseWrite: %v", err)
+ }
+
+ if _, err := conn.Write([]byte{0}); err != errShutdown {
+ return fmt.Errorf("CloseWrite error = %v; want errShutdown", err)
+ }
+
+ data, err := ioutil.ReadAll(conn)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+ return nil
+ }
+
+ errChan := make(chan error, 2)
+
+ go func() { errChan <- serverCloseWrite() }()
+ go func() { errChan <- clientCloseWrite() }()
+
+ for i := 0; i < 2; i++ {
+ select {
+ case err := <-errChan:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("deadlock")
+ }
+ }
+
+ // Also test CloseWrite being called before the handshake is
+ // finished:
+ {
+ ln2 := newLocalListener(t)
+ defer ln2.Close()
+
+ netConn, err := net.Dial("tcp", ln2.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer netConn.Close()
+ conn := Client(netConn, testConfig.Clone())
+
+ if err := conn.CloseWrite(); err != errEarlyCloseWrite {
+ t.Errorf("CloseWrite error = %v; want errEarlyCloseWrite", err)
+ }
+ }
+}
+
+func TestCloneFuncFields(t *testing.T) {
+ const expectedCount = 5
+ called := 0
+
+ c1 := Config{
+ Time: func() time.Time {
+ called |= 1 << 0
+ return time.Time{}
+ },
+ GetCertificate: func(*ClientHelloInfo) (*Certificate, error) {
+ called |= 1 << 1
+ return nil, nil
+ },
+ GetClientCertificate: func(*CertificateRequestInfo) (*Certificate, error) {
+ called |= 1 << 2
+ return nil, nil
+ },
+ GetConfigForClient: func(*ClientHelloInfo) (*Config, error) {
+ called |= 1 << 3
+ return nil, nil
+ },
+ VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
+ called |= 1 << 4
+ return nil
+ },
+ }
+
+ c2 := c1.Clone()
+
+ c2.Time()
+ c2.GetCertificate(nil)
+ c2.GetClientCertificate(nil)
+ c2.GetConfigForClient(nil)
+ c2.VerifyPeerCertificate(nil, nil)
+
+ if called != (1<<expectedCount)-1 {
+ t.Fatalf("expected %d calls but saw calls %b", expectedCount, called)
+ }
+}
+
+func TestCloneNonFuncFields(t *testing.T) {
+ var c1 Config
+ v := reflect.ValueOf(&c1).Elem()
+
+ typ := v.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ f := v.Field(i)
+ if !f.CanSet() {
+ // unexported field; not cloned.
+ continue
+ }
+
+ // testing/quick can't handle functions or interfaces and so
+ // isn't used here.
+ switch fn := typ.Field(i).Name; fn {
+ case "Rand":
+ f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
+ case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate":
+ // DeepEqual can't compare functions. If you add a
+ // function field to this list, you must also change
+ // TestCloneFuncFields to ensure that the func field is
+ // cloned.
+ case "Certificates":
+ f.Set(reflect.ValueOf([]Certificate{
+ {Certificate: [][]byte{{'b'}}},
+ }))
+ case "NameToCertificate":
+ f.Set(reflect.ValueOf(map[string]*Certificate{"a": nil}))
+ case "RootCAs", "ClientCAs":
+ f.Set(reflect.ValueOf(x509.NewCertPool()))
+ case "ClientSessionCache":
+ f.Set(reflect.ValueOf(NewLRUClientSessionCache(10)))
+ case "KeyLogWriter":
+ f.Set(reflect.ValueOf(io.Writer(os.Stdout)))
+ case "NextProtos":
+ f.Set(reflect.ValueOf([]string{"a", "b"}))
+ case "ServerName":
+ f.Set(reflect.ValueOf("b"))
+ case "ClientAuth":
+ f.Set(reflect.ValueOf(VerifyClientCertIfGiven))
+ case "InsecureSkipVerify", "SessionTicketsDisabled", "DynamicRecordSizingDisabled", "PreferServerCipherSuites":
+ f.Set(reflect.ValueOf(true))
+ case "MinVersion", "MaxVersion":
+ f.Set(reflect.ValueOf(uint16(VersionTLS12)))
+ case "SessionTicketKey":
+ f.Set(reflect.ValueOf([32]byte{}))
+ case "CipherSuites":
+ f.Set(reflect.ValueOf([]uint16{1, 2}))
+ case "CurvePreferences":
+ f.Set(reflect.ValueOf([]CurveID{CurveP256}))
+ case "Renegotiation":
+ f.Set(reflect.ValueOf(RenegotiateOnceAsClient))
+ default:
+ t.Errorf("all fields must be accounted for, but saw unknown field %q", fn)
+ }
+ }
+
+ c2 := c1.Clone()
+ // DeepEqual also compares unexported fields, thus c2 needs to have run
+ // serverInit in order to be DeepEqual to c1. Cloning it and discarding
+ // the result is sufficient.
+ c2.Clone()
+
+ if !reflect.DeepEqual(&c1, c2) {
+ t.Errorf("clone failed to copy a field")
+ }
+}
+
// changeImplConn is a net.Conn which can change its Write and Close
// methods.
type changeImplConn struct {
@@ -466,3 +695,163 @@ 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
+
+ // Less than 64KB because Windows appears to use a TCP rwin < 64KB.
+ // See Issue #15899.
+ const bufsize = 32 << 10
+
+ go func() {
+ buf := make([]byte, bufsize)
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ // panic rather than synchronize to avoid benchmark overhead
+ // (cannot call b.Fatal in goroutine)
+ panic(fmt.Errorf("accept: %v", err))
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = nil // the defaults may prefer faster ciphers
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ panic(fmt.Errorf("handshake: %v", err))
+ }
+ if _, err := io.CopyBuffer(srv, srv, buf); err != nil {
+ panic(fmt.Errorf("copy buffer: %v", err))
+ }
+ }
+ }()
+
+ b.SetBytes(totalBytes)
+ clientConfig := testConfig.Clone()
+ clientConfig.CipherSuites = nil // the defaults may prefer faster ciphers
+ clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+
+ buf := make([]byte, bufsize)
+ 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
+
+ go func() {
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ // panic rather than synchronize to avoid benchmark overhead
+ // (cannot call b.Fatal in goroutine)
+ panic(fmt.Errorf("accept: %v", err))
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(&slowConn{sconn, bps}, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ panic(fmt.Errorf("handshake: %v", err))
+ }
+ io.Copy(srv, srv)
+ }
+ }()
+
+ clientConfig := testConfig.Clone()
+ 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")
+ })
+ }
+ }
+}
diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go
index 2362e84688..71ffbdf0e0 100644
--- a/libgo/go/crypto/x509/cert_pool.go
+++ b/libgo/go/crypto/x509/cert_pool.go
@@ -6,6 +6,8 @@ package x509
import (
"encoding/pem"
+ "errors"
+ "runtime"
)
// CertPool is a set of certificates.
@@ -18,12 +20,24 @@ type CertPool struct {
// NewCertPool returns a new, empty CertPool.
func NewCertPool() *CertPool {
return &CertPool{
- make(map[string][]int),
- make(map[string][]int),
- nil,
+ bySubjectKeyId: make(map[string][]int),
+ byName: make(map[string][]int),
}
}
+// SystemCertPool returns a copy of the system cert pool.
+//
+// Any mutations to the returned pool are not written to disk and do
+// not affect any other pool.
+func SystemCertPool() (*CertPool, error) {
+ if runtime.GOOS == "windows" {
+ // Issue 16736, 18609:
+ return nil, errors.New("crypto/x509: system root pool is not available on Windows")
+ }
+
+ return loadSystemRoots()
+}
+
// findVerifiedParents attempts to find certificates in s which have signed the
// given certificate. If any candidates were rejected then errCert will be set
// to one of them, arbitrarily, and err will contain the reason that it was
@@ -52,6 +66,21 @@ func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCer
return
}
+func (s *CertPool) contains(cert *Certificate) bool {
+ if s == nil {
+ return false
+ }
+
+ candidates := s.byName[string(cert.RawSubject)]
+ for _, c := range candidates {
+ if s.certs[c].Equal(cert) {
+ return true
+ }
+ }
+
+ return false
+}
+
// AddCert adds a certificate to a pool.
func (s *CertPool) AddCert(cert *Certificate) {
if cert == nil {
@@ -59,10 +88,8 @@ func (s *CertPool) AddCert(cert *Certificate) {
}
// Check that the certificate isn't being added twice.
- for _, c := range s.certs {
- if c.Equal(cert) {
- return
- }
+ if s.contains(cert) {
+ return
}
n := len(s.certs)
@@ -107,10 +134,10 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
// Subjects returns a list of the DER-encoded subjects of
// all of the certificates in the pool.
-func (s *CertPool) Subjects() (res [][]byte) {
- res = make([][]byte, len(s.certs))
+func (s *CertPool) Subjects() [][]byte {
+ res := make([][]byte, len(s.certs))
for i, c := range s.certs {
res[i] = c.RawSubject
}
- return
+ return res
}
diff --git a/libgo/go/crypto/x509/pem_decrypt.go b/libgo/go/crypto/x509/pem_decrypt.go
index 49ceadb436..0388d63e14 100644
--- a/libgo/go/crypto/x509/pem_decrypt.go
+++ b/libgo/go/crypto/x509/pem_decrypt.go
@@ -42,7 +42,7 @@ type rfc1423Algo struct {
}
// rfc1423Algos holds a slice of the possible ways to encrypt a PEM
-// block. The ivSize numbers were taken from the OpenSSL source.
+// block. The ivSize numbers were taken from the OpenSSL source.
var rfc1423Algos = []rfc1423Algo{{
cipher: PEMCipherDES,
name: "DES-CBC",
diff --git a/libgo/go/crypto/x509/pkcs1.go b/libgo/go/crypto/x509/pkcs1.go
index acebe35139..df20a44204 100644
--- a/libgo/go/crypto/x509/pkcs1.go
+++ b/libgo/go/crypto/x509/pkcs1.go
@@ -36,15 +36,14 @@ type pkcs1AdditionalRSAPrime struct {
}
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
-func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
+func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
var priv pkcs1PrivateKey
rest, err := asn1.Unmarshal(der, &priv)
if len(rest) > 0 {
- err = asn1.SyntaxError{Msg: "trailing data"}
- return
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
}
if err != nil {
- return
+ return nil, err
}
if priv.Version > 1 {
@@ -55,7 +54,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
return nil, errors.New("x509: private key contains zero or negative value")
}
- key = new(rsa.PrivateKey)
+ key := new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
N: priv.N,
@@ -80,7 +79,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
}
key.Precompute()
- return
+ return key, nil
}
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go
index ba19989cba..b304a3f63c 100644
--- a/libgo/go/crypto/x509/pkcs8.go
+++ b/libgo/go/crypto/x509/pkcs8.go
@@ -13,7 +13,7 @@ import (
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
-// and RFC5208.
+// and RFC 5208.
type pkcs8 struct {
Version int
Algo pkix.AlgorithmIdentifier
@@ -21,8 +21,8 @@ type pkcs8 struct {
// optional attributes omitted.
}
-// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
-// http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208.
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key.
+// See RFC 5208.
func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
var privKey pkcs8
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go
index 1b3e3c0440..39fd78df59 100644
--- a/libgo/go/crypto/x509/pkix/pkix.go
+++ b/libgo/go/crypto/x509/pkix/pkix.go
@@ -64,34 +64,36 @@ func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
if len(rdn) == 0 {
continue
}
- atv := rdn[0]
- n.Names = append(n.Names, atv)
- value, ok := atv.Value.(string)
- if !ok {
- continue
- }
- t := atv.Type
- if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
- switch t[3] {
- case 3:
- n.CommonName = value
- case 5:
- n.SerialNumber = value
- case 6:
- n.Country = append(n.Country, value)
- case 7:
- n.Locality = append(n.Locality, value)
- case 8:
- n.Province = append(n.Province, value)
- case 9:
- n.StreetAddress = append(n.StreetAddress, value)
- case 10:
- n.Organization = append(n.Organization, value)
- case 11:
- n.OrganizationalUnit = append(n.OrganizationalUnit, value)
- case 17:
- n.PostalCode = append(n.PostalCode, value)
+ for _, atv := range rdn {
+ n.Names = append(n.Names, atv)
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
}
}
}
@@ -177,7 +179,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool {
// 5280, section 5.1.
type TBSCertificateList struct {
Raw asn1.RawContent
- Version int `asn1:"optional,default:1"`
+ Version int `asn1:"optional,default:0"`
Signature AlgorithmIdentifier
Issuer RDNSequence
ThisUpdate time.Time
diff --git a/libgo/go/crypto/x509/root.go b/libgo/go/crypto/x509/root.go
index 8aae14e09e..787d955be4 100644
--- a/libgo/go/crypto/x509/root.go
+++ b/libgo/go/crypto/x509/root.go
@@ -7,11 +7,16 @@ package x509
import "sync"
var (
- once sync.Once
- systemRoots *CertPool
+ once sync.Once
+ systemRoots *CertPool
+ systemRootsErr error
)
func systemRootsPool() *CertPool {
once.Do(initSystemRoots)
return systemRoots
}
+
+func initSystemRoots() {
+ systemRoots, systemRootsErr = loadSystemRoots()
+}
diff --git a/libgo/go/crypto/x509/root_cgo_darwin.go b/libgo/go/crypto/x509/root_cgo_darwin.go
index bf4a5cdfee..8e80533590 100644
--- a/libgo/go/crypto/x509/root_cgo_darwin.go
+++ b/libgo/go/crypto/x509/root_cgo_darwin.go
@@ -7,30 +7,28 @@
package x509
/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
#cgo LDFLAGS: -framework CoreFoundation -framework Security
+#include <errno.h>
+#include <sys/sysctl.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
-// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-//
-// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
-// we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots) {
+// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6
+// which still works on OS X 10.8 (Mountain Lion).
+// It lacks support for admin & user cert domains.
+// See golang.org/issue/16473
+int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) {
if (pemRoots == NULL) {
return -1;
}
-
CFArrayRef certs = NULL;
OSStatus err = SecTrustCopyAnchorCertificates(&certs);
if (err != noErr) {
return -1;
}
-
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
int i, ncerts = CFArrayGetCount(certs);
for (i = 0; i < ncerts; i++) {
@@ -39,7 +37,6 @@ int FetchPEMRoots(CFDataRef *pemRoots) {
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.
@@ -47,33 +44,193 @@ int FetchPEMRoots(CFDataRef *pemRoots) {
if (err != noErr) {
continue;
}
-
if (data != NULL) {
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
CFRelease(data);
}
}
-
CFRelease(certs);
+ *pemRoots = combinedData;
+ return 0;
+}
+
+// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion
+// or older. We only support Mountain Lion and higher, but we'll at least try our
+// best on older machines and continue to use the old code path.
+//
+// See golang.org/issue/16473
+int useOldCode() {
+ char str[256];
+ size_t size = sizeof(str);
+ memset(str, 0, size);
+ sysctlbyname("kern.osrelease", str, &size, NULL, 0);
+ // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*.
+ // We never supported things before that.
+ return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0;
+}
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+// Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
+//
+// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
+// be released (using CFRelease) after we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
+ if (useOldCode()) {
+ return FetchPEMRoots_MountainLion(pemRoots);
+ }
+
+ // 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 };
+
+ int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
+ if (pemRoots == NULL) {
+ return -1;
+ }
+
+ // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
+ // but the Go linker's internal linking mode can't handle CFSTR relocations.
+ // Create our own dynamic string instead and release it below.
+ CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
+
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ for (int i = 0; i < numDomains; i++) {
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
+ if (err != noErr) {
+ continue;
+ }
+
+ CFIndex numCerts = CFArrayGetCount(certs);
+ for (int j = 0; j < numCerts; j++) {
+ CFDataRef data = NULL;
+ CFErrorRef errRef = NULL;
+ CFArrayRef trustSettings = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
+ if (cert == NULL) {
+ continue;
+ }
+ // We only want trusted certs.
+ int untrusted = 0;
+ if (i != 0) {
+ // Certs found in the system domain are always trusted. If the user
+ // configures "Never Trust" on such a cert, it will also be found in the
+ // admin or user domain, causing it to be added to untrustedPemRoots. The
+ // Go code will then clean this up.
+ // Trust may be stored in any of the domains. According to Apple's
+ // SecTrustServer.c, "user trust settings overrule admin trust settings",
+ // so take the last trust settings array we find.
+ // Skip the system domain since it is always trusted.
+ for (int k = 1; k < numDomains; k++) {
+ CFArrayRef domainTrustSettings = NULL;
+ err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
+ if (err == errSecSuccess && domainTrustSettings != NULL) {
+ if (trustSettings) {
+ CFRelease(trustSettings);
+ }
+ trustSettings = domainTrustSettings;
+ }
+ }
+ if (trustSettings == NULL) {
+ // "this certificate must be verified to a known trusted certificate"; aka not a root.
+ continue;
+ }
+ for (CFIndex k = 0; k < CFArrayGetCount(trustSettings); k++) {
+ CFNumberRef cfNum;
+ CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, k);
+ if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
+ SInt32 result = 0;
+ CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
+ // TODO: The rest of the dictionary specifies conditions for evaluation.
+ if (result == kSecTrustSettingsResultDeny) {
+ untrusted = 1;
+ }
+ }
+ }
+ CFRelease(trustSettings);
+ }
+ // 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;
+ }
+
+ // 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) {
+ CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
+ CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+ CFRelease(certs);
+ }
+ CFRelease(policy);
*pemRoots = combinedData;
+ *untrustedPemRoots = combinedUntrustedData;
return 0;
}
*/
import "C"
-import "unsafe"
+import (
+ "errors"
+ "unsafe"
+)
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
var data C.CFDataRef = nil
- err := C.FetchPEMRoots(&data)
+ var untrustedData C.CFDataRef = nil
+ err := C.FetchPEMRoots(&data, &untrustedData)
if err == -1 {
- return
+ // TODO: better error message
+ return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
}
defer C.CFRelease(C.CFTypeRef(data))
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
roots.AppendCertsFromPEM(buf)
- systemRoots = roots
+ if untrustedData == nil {
+ return roots, nil
+ }
+ defer C.CFRelease(C.CFTypeRef(untrustedData))
+ buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
+ untrustedRoots := NewCertPool()
+ untrustedRoots.AppendCertsFromPEM(buf)
+
+ trustedRoots := NewCertPool()
+ for _, c := range roots.certs {
+ if !untrustedRoots.contains(c) {
+ trustedRoots.AddCert(c)
+ }
+ }
+ return trustedRoots, nil
}
diff --git a/libgo/go/crypto/x509/root_darwin.go b/libgo/go/crypto/x509/root_darwin.go
index 78de56c221..66cdb5ea26 100644
--- a/libgo/go/crypto/x509/root_darwin.go
+++ b/libgo/go/crypto/x509/root_darwin.go
@@ -6,20 +6,239 @@
package x509
-import "os/exec"
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha1"
+ "encoding/pem"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "sync"
+)
+
+var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
+// This code is only used when compiling without cgo.
+// It is here, instead of root_nocgo_darwin.go, so that tests can check it
+// even if the tests are run with cgo enabled.
+// The linker will not include these unused functions in binaries built with cgo enabled.
+
+// execSecurityRoots finds the macOS list of trusted root certificates
+// using only command-line tools. This is our fallback path when cgo isn't available.
+//
+// The strategy is as follows:
+//
+// 1. Run "security trust-settings-export" and "security
+// trust-settings-export -d" to discover the set of certs with some
+// user-tweaked trust policy. We're too lazy to parse the XML (at
+// least at this stage of Go 1.8) to understand what the trust
+// policy actually is. We just learn that there is _some_ policy.
+//
+// 2. Run "security find-certificate" to dump the list of system root
+// CAs in PEM format.
+//
+// 3. For each dumped cert, conditionally verify it with "security
+// verify-cert" if that cert was in the set discovered in Step 1.
+// Without the Step 1 optimization, running "security verify-cert"
+// 150-200 times takes 3.5 seconds. With the optimization, the
+// whole process takes about 180 milliseconds with 1 untrusted root
+// CA. (Compared to 110ms in the cgo path)
func execSecurityRoots() (*CertPool, error) {
+ hasPolicy, err := getCertsWithTrustPolicy()
+ if err != nil {
+ return nil, err
+ }
+ if debugExecDarwinRoots {
+ println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
+ }
+
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
data, err := cmd.Output()
if err != nil {
return nil, err
}
- roots := NewCertPool()
- roots.AppendCertsFromPEM(data)
+ var (
+ mu sync.Mutex
+ roots = NewCertPool()
+ numVerified int // number of execs of 'security verify-cert', for debug stats
+ )
+
+ blockCh := make(chan *pem.Block)
+ var wg sync.WaitGroup
+
+ // Using 4 goroutines to pipe into verify-cert seems to be
+ // about the best we can do. The verify-cert binary seems to
+ // just RPC to another server with coarse locking anyway, so
+ // running 16 at a time for instance doesn't help at all. Due
+ // to the "if hasPolicy" check below, though, we will rarely
+ // (or never) call verify-cert on stock macOS systems, though.
+ // The hope is that we only call verify-cert when the user has
+ // tweaked their trust policy. These 4 goroutines are only
+ // defensive in the pathological case of many trust edits.
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for block := range blockCh {
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ continue
+ }
+ sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
+
+ valid := true
+ verifyChecks := 0
+ if hasPolicy[sha1CapHex] {
+ verifyChecks++
+ if !verifyCertWithSystem(block, cert) {
+ valid = false
+ }
+ }
+
+ mu.Lock()
+ numVerified += verifyChecks
+ if valid {
+ roots.AddCert(cert)
+ }
+ mu.Unlock()
+ }
+ }()
+ }
+ for len(data) > 0 {
+ var block *pem.Block
+ block, data = pem.Decode(data)
+ if block == nil {
+ break
+ }
+ if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+ continue
+ }
+ blockCh <- block
+ }
+ close(blockCh)
+ wg.Wait()
+
+ if debugExecDarwinRoots {
+ mu.Lock()
+ defer mu.Unlock()
+ println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
+ }
+
return roots, nil
}
+
+func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
+ data := pem.EncodeToMemory(block)
+
+ f, err := ioutil.TempFile("", "cert")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
+ return false
+ }
+ defer os.Remove(f.Name())
+ if _, err := f.Write(data); err != nil {
+ fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+ return false
+ }
+ if err := f.Close(); err != nil {
+ fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+ return false
+ }
+ cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
+ var stderr bytes.Buffer
+ if debugExecDarwinRoots {
+ cmd.Stderr = &stderr
+ }
+ if err := cmd.Run(); err != nil {
+ if debugExecDarwinRoots {
+ println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
+ }
+ return false
+ }
+ if debugExecDarwinRoots {
+ println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
+ }
+ return true
+}
+
+// getCertsWithTrustPolicy returns the set of certs that have a
+// possibly-altered trust policy. The keys of the map are capitalized
+// sha1 hex of the raw cert.
+// They are the certs that should be checked against `security
+// verify-cert` to see whether the user altered the default trust
+// settings. This code is only used for cgo-disabled builds.
+func getCertsWithTrustPolicy() (map[string]bool, error) {
+ set := map[string]bool{}
+ td, err := ioutil.TempDir("", "x509trustpolicy")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(td)
+ run := func(file string, args ...string) error {
+ file = filepath.Join(td, file)
+ args = append(args, file)
+ cmd := exec.Command("/usr/bin/security", args...)
+ var stderr bytes.Buffer
+ cmd.Stderr = &stderr
+ if err := cmd.Run(); err != nil {
+ // If there are no trust settings, the
+ // `security trust-settings-export` command
+ // fails with:
+ // exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
+ // Rather than match on English substrings that are probably
+ // localized on macOS, just interpret any failure to mean that
+ // there are no trust settings.
+ if debugExecDarwinRoots {
+ println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
+ }
+ return nil
+ }
+
+ f, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ // Gather all the runs of 40 capitalized hex characters.
+ br := bufio.NewReader(f)
+ var hexBuf bytes.Buffer
+ for {
+ b, err := br.ReadByte()
+ isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
+ if isHex {
+ hexBuf.WriteByte(b)
+ } else {
+ if hexBuf.Len() == 40 {
+ set[hexBuf.String()] = true
+ }
+ hexBuf.Reset()
+ }
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+ }
+ if err := run("user", "trust-settings-export"); err != nil {
+ return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
+ }
+ if err := run("admin", "trust-settings-export", "-d"); err != nil {
+ return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
+ }
+ return set, nil
+}
diff --git a/libgo/go/crypto/x509/root_darwin_arm_gen.go b/libgo/go/crypto/x509/root_darwin_arm_gen.go
index 5817158c33..fc2488adc6 100644
--- a/libgo/go/crypto/x509/root_darwin_arm_gen.go
+++ b/libgo/go/crypto/x509/root_darwin_arm_gen.go
@@ -184,8 +184,9 @@ const header = `
package x509
-func initSystemRoots() {
- systemRoots = NewCertPool()
- systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+func loadSystemRoots() (*CertPool, error) {
+ p := NewCertPool()
+ p.AppendCertsFromPEM([]byte(systemRootsPEM))
+ return p, nil
}
`
diff --git a/libgo/go/crypto/x509/root_darwin_armx.go b/libgo/go/crypto/x509/root_darwin_armx.go
index 37675b48a3..ad1c53d8a4 100644
--- a/libgo/go/crypto/x509/root_darwin_armx.go
+++ b/libgo/go/crypto/x509/root_darwin_armx.go
@@ -10,9 +10,10 @@
package x509
-func initSystemRoots() {
- systemRoots = NewCertPool()
- systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+func loadSystemRoots() (*CertPool, error) {
+ p := NewCertPool()
+ p.AppendCertsFromPEM([]byte(systemRootsPEM))
+ return p, nil
}
const systemRootsPEM = `
diff --git a/libgo/go/crypto/x509/root_linux.go b/libgo/go/crypto/x509/root_linux.go
index cfeca6958c..aa1785e4c6 100644
--- a/libgo/go/crypto/x509/root_linux.go
+++ b/libgo/go/crypto/x509/root_linux.go
@@ -6,8 +6,9 @@ package x509
// Possible certificate files; stop after finding one.
var certFiles = []string{
- "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
- "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
- "/etc/ssl/ca-bundle.pem", // OpenSUSE
- "/etc/pki/tls/cacert.pem", // OpenELEC
+ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
+ "/etc/ssl/ca-bundle.pem", // OpenSUSE
+ "/etc/pki/tls/cacert.pem", // OpenELEC
+ "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
}
diff --git a/libgo/go/crypto/x509/root_nocgo_darwin.go b/libgo/go/crypto/x509/root_nocgo_darwin.go
index d00e257662..2ac4666aff 100644
--- a/libgo/go/crypto/x509/root_nocgo_darwin.go
+++ b/libgo/go/crypto/x509/root_nocgo_darwin.go
@@ -6,6 +6,6 @@
package x509
-func initSystemRoots() {
- systemRoots, _ = execSecurityRoots()
+func loadSystemRoots() (*CertPool, error) {
+ return execSecurityRoots()
}
diff --git a/libgo/go/crypto/x509/root_plan9.go b/libgo/go/crypto/x509/root_plan9.go
index 9965caadee..ebeb7dfccd 100644
--- a/libgo/go/crypto/x509/root_plan9.go
+++ b/libgo/go/crypto/x509/root_plan9.go
@@ -6,7 +6,10 @@
package x509
-import "io/ioutil"
+import (
+ "io/ioutil"
+ "os"
+)
// Possible certificate files; stop after finding one.
var certFiles = []string{
@@ -17,17 +20,18 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, nil
}
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
+ var bestErr error
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
- systemRoots = roots
- return
+ return roots, nil
+ }
+ if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) {
+ bestErr = err
}
}
-
- // All of the files failed to load. systemRoots will be nil which will
- // trigger a specific error at verification time.
+ return nil, bestErr
}
diff --git a/libgo/go/crypto/x509/root_unix.go b/libgo/go/crypto/x509/root_unix.go
index 9f06f9dabb..7bcb3d63d1 100644
--- a/libgo/go/crypto/x509/root_unix.go
+++ b/libgo/go/crypto/x509/root_unix.go
@@ -6,7 +6,10 @@
package x509
-import "io/ioutil"
+import (
+ "io/ioutil"
+ "os"
+)
// Possible directories with certificate files; stop after successfully
// reading at least one file from a directory.
@@ -19,20 +22,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, nil
}
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
+ var firstErr error
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
- systemRoots = roots
- return
+ return roots, nil
+ }
+ if firstErr == nil && !os.IsNotExist(err) {
+ firstErr = err
}
}
for _, directory := range certDirectories {
fis, err := ioutil.ReadDir(directory)
if err != nil {
+ if firstErr == nil && !os.IsNotExist(err) {
+ firstErr = err
+ }
continue
}
rootsAdded := false
@@ -43,11 +52,9 @@ func initSystemRoots() {
}
}
if rootsAdded {
- systemRoots = roots
- return
+ return roots, nil
}
}
- // All of the files failed to load. systemRoots will be nil which will
- // trigger a specific error at verification time.
+ return nil, firstErr
}
diff --git a/libgo/go/crypto/x509/root_windows.go b/libgo/go/crypto/x509/root_windows.go
index 81018b78fe..a936fec7d8 100644
--- a/libgo/go/crypto/x509/root_windows.go
+++ b/libgo/go/crypto/x509/root_windows.go
@@ -179,7 +179,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
}
// CertGetCertificateChain will traverse Windows's root stores
- // in an attempt to build a verified certificate chain. Once
+ // in an attempt to build a verified certificate chain. Once
// it has found a verified chain, it stops. MSDN docs on
// CERT_CHAIN_CONTEXT:
//
@@ -225,5 +225,42 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return chains, nil
}
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
+ // TODO: restore this functionality on Windows. We tried to do
+ // it in Go 1.8 but had to revert it. See Issue 18609.
+ // Returning (nil, nil) was the old behavior, prior to CL 30578.
+ return nil, nil
+
+ const CRYPT_E_NOT_FOUND = 0x80092004
+
+ store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertCloseStore(store, 0)
+
+ roots := NewCertPool()
+ var cert *syscall.CertContext
+ for {
+ cert, err = syscall.CertEnumCertificatesInStore(store, cert)
+ if err != nil {
+ if errno, ok := err.(syscall.Errno); ok {
+ if errno == CRYPT_E_NOT_FOUND {
+ break
+ }
+ }
+ return nil, err
+ }
+ if cert == nil {
+ break
+ }
+ // Copy the buf, since ParseCertificate does not create its own copy.
+ buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
+ buf2 := make([]byte, cert.Length)
+ copy(buf2, buf)
+ if c, err := ParseCertificate(buf2); err == nil {
+ roots.AddCert(c)
+ }
+ }
+ return roots, nil
}
diff --git a/libgo/go/crypto/x509/sec1.go b/libgo/go/crypto/x509/sec1.go
index 1424dea99e..33f376c072 100644
--- a/libgo/go/crypto/x509/sec1.go
+++ b/libgo/go/crypto/x509/sec1.go
@@ -17,9 +17,9 @@ const ecPrivKeyVersion = 1
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
// References:
-// RFC5915
+// RFC 5915
// SEC1 - http://www.secg.org/sec1-v2.pdf
-// Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
+// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
// most cases it is not.
type ecPrivateKey struct {
Version int
@@ -29,7 +29,7 @@ type ecPrivateKey struct {
}
// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
-func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error) {
+func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) {
return parseECPrivateKey(nil, der)
}
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 27e9bbfbcc..29345a1755 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -5,6 +5,7 @@
package x509
import (
+ "bytes"
"errors"
"fmt"
"net"
@@ -33,6 +34,9 @@ const (
// IncompatibleUsage results when the certificate's key usage indicates
// that it may only be used for a different purpose.
IncompatibleUsage
+ // NameMismatch results when the subject name of a parent certificate
+ // does not match the issuer name in the child.
+ NameMismatch
)
// CertificateInvalidError results when an odd error occurs. Users of this
@@ -54,6 +58,8 @@ func (e CertificateInvalidError) Error() string {
return "x509: too many intermediates for path length constraint"
case IncompatibleUsage:
return "x509: certificate specifies an incompatible key usage"
+ case NameMismatch:
+ return "x509: issuer name does not match subject from issuing certificate"
}
return "x509: unknown error"
}
@@ -87,12 +93,16 @@ func (h HostnameError) Error() string {
valid = c.Subject.CommonName
}
}
+
+ if len(valid) == 0 {
+ return "x509: certificate is not valid for any names, but wanted to match " + h.Host
+ }
return "x509: certificate is valid for " + valid + ", not " + h.Host
}
// UnknownAuthorityError results when the certificate issuer is unknown
type UnknownAuthorityError struct {
- cert *Certificate
+ Cert *Certificate
// hintErr contains an error that may be helpful in determining why an
// authority wasn't found.
hintErr error
@@ -108,8 +118,9 @@ func (e UnknownAuthorityError) Error() string {
if len(certName) == 0 {
if len(e.hintCert.Subject.Organization) > 0 {
certName = e.hintCert.Subject.Organization[0]
+ } else {
+ certName = "serial:" + e.hintCert.SerialNumber.String()
}
- certName = "serial:" + e.hintCert.SerialNumber.String()
}
s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
}
@@ -117,10 +128,16 @@ func (e UnknownAuthorityError) Error() string {
}
// SystemRootsError results when we fail to load the system root certificates.
-type SystemRootsError struct{}
+type SystemRootsError struct {
+ Err error
+}
-func (SystemRootsError) Error() string {
- return "x509: failed to load system roots and no roots provided"
+func (se SystemRootsError) Error() string {
+ msg := "x509: failed to load system roots and no roots provided"
+ if se.Err != nil {
+ return msg + "; " + se.Err.Error()
+ }
+ return msg
}
// errNotParsed is returned when a certificate without ASN.1 contents is
@@ -136,7 +153,7 @@ type VerifyOptions struct {
CurrentTime time.Time // if zero, the current time is used
// KeyUsage specifies which Extended Key Usage values are acceptable.
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
- // constraint down the chain which mirrors Windows CryptoAPI behaviour,
+ // constraint down the chain which mirrors Windows CryptoAPI behavior,
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
KeyUsages []ExtKeyUsage
}
@@ -147,8 +164,40 @@ const (
rootCertificate
)
+func matchNameConstraint(domain, constraint string) bool {
+ // The meaning of zero length constraints is not specified, but this
+ // code follows NSS and accepts them as valid for everything.
+ if len(constraint) == 0 {
+ return true
+ }
+
+ if len(domain) < len(constraint) {
+ return false
+ }
+
+ prefixLen := len(domain) - len(constraint)
+ if !strings.EqualFold(domain[prefixLen:], constraint) {
+ return false
+ }
+
+ if prefixLen == 0 {
+ return true
+ }
+
+ isSubdomain := domain[prefixLen-1] == '.'
+ constraintHasLeadingDot := constraint[0] == '.'
+ return isSubdomain != constraintHasLeadingDot
+}
+
// isValid performs validity checks on the c.
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
+ if len(currentChain) > 0 {
+ child := currentChain[len(currentChain)-1]
+ if !bytes.Equal(child.RawIssuer, c.RawSubject) {
+ return CertificateInvalidError{c, NameMismatch}
+ }
+ }
+
now := opts.CurrentTime
if now.IsZero() {
now = time.Now()
@@ -159,12 +208,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
if len(c.PermittedDNSDomains) > 0 {
ok := false
- for _, domain := range c.PermittedDNSDomains {
- if opts.DNSName == domain ||
- (strings.HasSuffix(opts.DNSName, domain) &&
- len(opts.DNSName) >= 1+len(domain) &&
- opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
- ok = true
+ for _, constraint := range c.PermittedDNSDomains {
+ ok = matchNameConstraint(opts.DNSName, constraint)
+ if ok {
break
}
}
@@ -179,7 +225,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// being valid for encryption only, but no-one noticed. Another
// European CA marked its signature keys as not being valid for
// signatures. A different CA marked its own trusted root certificate
- // as being invalid for certificate signing. Another national CA
+ // as being invalid for certificate signing. Another national CA
// distributed a certificate to be used to encrypt data for the
// country’s tax authority that was marked as only being usable for
// digital signatures but not for encryption. Yet another CA reversed
@@ -216,7 +262,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
// Platform-specific verification needs the ASN.1 contents so
- // this makes the behaviour consistent across platforms.
+ // this makes the behavior consistent across platforms.
if len(c.Raw) == 0 {
return nil, errNotParsed
}
@@ -240,7 +286,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
if opts.Roots == nil {
opts.Roots = systemRootsPool()
if opts.Roots == nil {
- return nil, SystemRootsError{}
+ return nil, SystemRootsError{systemRootsErr}
}
}
@@ -256,9 +302,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
}
}
- candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
- if err != nil {
- return
+ var candidateChains [][]*Certificate
+ if opts.Roots.contains(c) {
+ candidateChains = append(candidateChains, []*Certificate{c})
+ } else {
+ if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
+ return nil, err
+ }
}
keyUsages := opts.KeyUsages
@@ -296,8 +346,16 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
+nextRoot:
for _, rootNum := range possibleRoots {
root := opts.Roots.certs[rootNum]
+
+ for _, cert := range currentChain {
+ if cert.Equal(root) {
+ continue nextRoot
+ }
+ }
+
err = root.isValid(rootCertificate, currentChain, opts)
if err != nil {
continue
@@ -310,7 +368,7 @@ nextIntermediate:
for _, intermediateNum := range possibleIntermediates {
intermediate := opts.Intermediates.certs[intermediateNum]
for _, cert := range currentChain {
- if cert == intermediate {
+ if cert.Equal(intermediate) {
continue nextIntermediate
}
}
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index 694c14023b..15c4091444 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -8,6 +8,7 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"errors"
+ "fmt"
"runtime"
"strings"
"testing"
@@ -103,10 +104,6 @@ var verifyTests = []verifyTest{
expectedChains: [][]string{
{"Google", "Google Internet Authority", "GeoTrust"},
- // TODO(agl): this is ok, but it would be nice if the
- // chain building didn't visit the same SPKI
- // twice.
- {"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"},
},
// CAPI doesn't build the chain with the duplicated GeoTrust
// entry so the results don't match. Thus we skip this test
@@ -129,12 +126,8 @@ var verifyTests = []verifyTest{
roots: []string{startComRoot},
currentTime: 1302726541,
- // Skip when using systemVerify, since Windows
- // can only return a single chain to us (for now).
- systemSkip: true,
expectedChains: [][]string{
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
- {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
},
},
{
@@ -235,6 +228,41 @@ var verifyTests = []verifyTest{
},
},
},
+ {
+ // Putting a certificate as a root directly should work as a
+ // way of saying “exactly thisâ€.
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "foo.example",
+ systemSkip: true,
+
+ expectedChains: [][]string{
+ {"Acme Co"},
+ },
+ },
+ {
+ // Putting a certificate as a root directly should not skip
+ // other checks however.
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "notfoo.example",
+ systemSkip: true,
+
+ errorCallback: expectHostnameError,
+ },
+ {
+ // The issuer name in the leaf doesn't exactly match the
+ // subject name in the root. Go does not perform
+ // canonicalization and so should reject this. See issue 14955.
+ leaf: issuerSubjectMatchLeaf,
+ roots: []string{issuerSubjectMatchRoot},
+ currentTime: 1475787715,
+ systemSkip: true,
+
+ errorCallback: expectSubjectIssuerMismatcthError,
+ },
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -262,10 +290,15 @@ func expectUsageError(t *testing.T, i int, err error) (ok bool) {
}
func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {
- if _, ok := err.(UnknownAuthorityError); !ok {
+ e, ok := err.(UnknownAuthorityError)
+ if !ok {
t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err)
return false
}
+ if e.Cert == nil {
+ t.Errorf("#%d: error was UnknownAuthorityError, but missing Cert: %s", i, err)
+ return false
+ }
return true
}
@@ -289,6 +322,14 @@ func expectHashError(t *testing.T, i int, err error) bool {
return true
}
+func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NameMismatch {
+ t.Errorf("#%d: error was not a NameMismatch: %s", i, err)
+ return false
+ }
+ return true
+}
+
func certificateFromPEM(pemBytes string) (*Certificate, error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
@@ -382,7 +423,7 @@ func testVerify(t *testing.T, useSystemRoots bool) {
continue
}
for k, cert := range chain {
- if strings.Index(nameToKey(&cert.Subject), expectedChain[k]) == -1 {
+ if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
continue TryNextExpected
}
}
@@ -650,50 +691,6 @@ um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
-----END CERTIFICATE-----`
-const startComRootSHA256 = `-----BEGIN CERTIFICATE-----
-MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
-F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
-ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
-ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
-aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
-YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
-c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
-d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
-CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
-wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
-Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
-0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
-pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
-CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
-P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
-1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
-KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
-JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
-8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
-fyWl8kgAwKQB2j8=
------END CERTIFICATE-----`
-
const smimeLeaf = `-----BEGIN CERTIFICATE-----
MIIFBjCCA+6gAwIBAgISESFvrjT8XcJTEe6rBlPptILlMA0GCSqGSIb3DQEBBQUA
MFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSowKAYD
@@ -1132,3 +1129,253 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----`
+
+const selfSigned = `-----BEGIN CERTIFICATE-----
+MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
+NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
+pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
+w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
+WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
+YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
+NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
+C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
+4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
+UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
+pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
+vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
+cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchRoot = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 161640039802297062 (0x23e42c281e55ae6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O=Golang, CN=Root ca
+ Validity
+ Not Before: Jan 1 00:00:00 2015 GMT
+ Not After : Jan 1 00:00:00 2025 GMT
+ Subject: O=Golang, CN=Root ca
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:e9:0e:7f:11:0c:e6:5a:e6:86:83:70:f6:51:07:
+ 2e:02:78:11:f5:b2:24:92:38:ee:26:62:02:c7:94:
+ f1:3e:a1:77:6a:c0:8f:d5:22:68:b6:5d:e2:4c:da:
+ e0:85:11:35:c2:92:72:49:8d:81:b4:88:97:6b:b7:
+ fc:b2:44:5b:d9:4d:06:70:f9:0c:c6:8f:e9:b3:df:
+ a3:6a:84:6c:43:59:be:9d:b2:d0:76:9b:c3:d7:fa:
+ 99:59:c3:b8:e5:f3:53:03:bd:49:d6:b3:cc:a2:43:
+ fe:ad:c2:0b:b9:01:b8:56:29:94:03:24:a7:0d:28:
+ 21:29:a9:ae:94:5b:4a:f9:9f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
+ Signature Algorithm: sha256WithRSAEncryption
+ 6f:84:df:49:e0:99:d4:71:66:1d:32:86:56:cb:ea:5a:6b:0e:
+ 00:6a:d1:5a:6e:1f:06:23:07:ff:cb:d1:1a:74:e4:24:43:0b:
+ aa:2a:a0:73:75:25:82:bc:bf:3f:a9:f8:48:88:ac:ed:3a:94:
+ 3b:0d:d3:88:c8:67:44:61:33:df:71:6c:c5:af:ed:16:8c:bf:
+ 82:f9:49:bb:e3:2a:07:53:36:37:25:77:de:91:a4:77:09:7f:
+ 6f:b2:91:58:c4:05:89:ea:8e:fa:e1:3b:19:ef:f8:f6:94:b7:
+ 7b:27:e6:e4:84:dd:2b:f5:93:f5:3c:d8:86:c5:38:01:56:5c:
+ 9f:6d
+-----BEGIN CERTIFICATE-----
+MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
+ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
+siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
+JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
+EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG
+VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn
+RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
+eyfm5ITdK/WT9TzYhsU4AVZcn20=
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchLeaf = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 16785088708916013734 (0xe8f09d3fe25beaa6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O=Golang, CN=Root CA
+ Validity
+ Not Before: Jan 1 00:00:00 2015 GMT
+ Not After : Jan 1 00:00:00 2025 GMT
+ Subject: O=Golang, CN=Leaf
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:db:46:7d:93:2e:12:27:06:48:bc:06:28:21:ab:
+ 7e:c4:b6:a2:5d:fe:1e:52:45:88:7a:36:47:a5:08:
+ 0d:92:42:5b:c2:81:c0:be:97:79:98:40:fb:4f:6d:
+ 14:fd:2b:13:8b:c2:a5:2e:67:d8:d4:09:9e:d6:22:
+ 38:b7:4a:0b:74:73:2b:c2:34:f1:d1:93:e5:96:d9:
+ 74:7b:f3:58:9f:6c:61:3c:c0:b0:41:d4:d9:2b:2b:
+ 24:23:77:5b:1c:3b:bd:75:5d:ce:20:54:cf:a1:63:
+ 87:1d:1e:24:c4:f3:1d:1a:50:8b:aa:b6:14:43:ed:
+ 97:a7:75:62:f4:14:c8:52:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Key Identifier:
+ 9F:91:16:1F:43:43:3E:49:A6:DE:6D:B6:80:D7:9F:60
+ X509v3 Authority Key Identifier:
+ keyid:40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 8d:86:05:da:89:f5:1d:c5:16:14:41:b9:34:87:2b:5c:38:99:
+ e3:d9:5a:5b:7a:5b:de:0b:5c:08:45:09:6f:1c:9d:31:5f:08:
+ ca:7a:a3:99:da:83:0b:22:be:4f:02:35:91:4e:5d:5c:37:bf:
+ 89:22:58:7d:30:76:d2:2f:d0:a0:ee:77:9e:77:c0:d6:19:eb:
+ ec:a0:63:35:6a:80:9b:80:1a:80:de:64:bc:40:38:3c:22:69:
+ ad:46:26:a2:3d:ea:f4:c2:92:49:16:03:96:ae:64:21:b9:7c:
+ ee:64:91:47:81:aa:b4:0c:09:2b:12:1a:b2:f3:af:50:b3:b1:
+ ce:24
+-----BEGIN CERTIFICATE-----
+MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
+BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
+NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e
+UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx
+0ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU
+Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf
+Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
+hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
+ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
+vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
+-----END CERTIFICATE-----
+`
+
+var unknownAuthorityErrorTests = []struct {
+ cert string
+ expected string
+}{
+ {selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
+ {selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
+ {selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
+}
+
+func TestUnknownAuthorityError(t *testing.T) {
+ for i, tt := range unknownAuthorityErrorTests {
+ der, _ := pem.Decode([]byte(tt.cert))
+ if der == nil {
+ t.Errorf("#%d: Unable to decode PEM block", i)
+ }
+ c, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Errorf("#%d: Unable to parse certificate -> %s", i, err)
+ }
+ uae := &UnknownAuthorityError{
+ Cert: c,
+ hintErr: fmt.Errorf("empty"),
+ hintCert: c,
+ }
+ actual := uae.Error()
+ if strings.Compare(actual, tt.expected) != 0 {
+ t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
+ }
+ }
+}
+
+var nameConstraintTests = []struct {
+ constraint, domain string
+ shouldMatch bool
+}{
+ {"", "anything.com", true},
+ {"example.com", "example.com", true},
+ {"example.com", "ExAmPle.coM", true},
+ {"example.com", "exampl1.com", false},
+ {"example.com", "www.ExAmPle.coM", true},
+ {"example.com", "notexample.com", false},
+ {".example.com", "example.com", false},
+ {".example.com", "www.example.com", true},
+ {".example.com", "www..example.com", false},
+}
+
+func TestNameConstraints(t *testing.T) {
+ for i, test := range nameConstraintTests {
+ result := matchNameConstraint(test.domain, test.constraint)
+ if result != test.shouldMatch {
+ t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
+ }
+ }
+}
+
+const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
+MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
+CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
+gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
+8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
++G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
+czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
+tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
+AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
+MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
+XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
+dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
+v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
+jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
+fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
+IuYkJwt6w+LH/9HZgf8=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
+CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
+7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
+8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
+gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
+xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
+g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
+46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
+CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
+A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
+bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
+wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
+rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
+DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
+29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
+MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
+fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
+35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
+2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
+S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
+kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
+AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
+AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
+BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
+4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
+9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
+w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
+4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
+8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
+-----END CERTIFICATE-----`
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index d9288bb30e..949ce01856 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -36,6 +36,12 @@ type pkixPublicKey struct {
// ParsePKIXPublicKey parses a DER encoded public key. These values are
// typically found in PEM blocks with "BEGIN PUBLIC KEY".
+//
+// Supported key types include RSA, DSA, and ECDSA. Unknown key
+// types result in an error.
+//
+// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey,
+// or *ecdsa.PublicKey.
func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
var pki publicKeyInfo
if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
@@ -61,9 +67,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
return nil, pkix.AlgorithmIdentifier{}, err
}
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
- // This is a NULL parameters value which is technically
- // superfluous, but most other code includes it and, by
- // doing this, we match their public key hashes.
+ // This is a NULL parameters value which is required by
+ // https://tools.ietf.org/html/rfc3279#section-2.3.1.
publicKeyAlgorithm.Parameters = asn1.RawValue{
Tag: 5,
}
@@ -120,7 +125,7 @@ type certificate struct {
type tbsCertificate struct {
Raw asn1.RawContent
- Version int `asn1:"optional,explicit,default:1,tag:0"`
+ Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
@@ -173,21 +178,36 @@ const (
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
+ SHA256WithRSAPSS
+ SHA384WithRSAPSS
+ SHA512WithRSAPSS
)
+func (algo SignatureAlgorithm) isRSAPSS() bool {
+ switch algo {
+ case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
+ return true
+ default:
+ return false
+ }
+}
+
var algoName = [...]string{
- MD2WithRSA: "MD2-RSA",
- MD5WithRSA: "MD5-RSA",
- SHA1WithRSA: "SHA1-RSA",
- SHA256WithRSA: "SHA256-RSA",
- SHA384WithRSA: "SHA384-RSA",
- SHA512WithRSA: "SHA512-RSA",
- DSAWithSHA1: "DSA-SHA1",
- DSAWithSHA256: "DSA-SHA256",
- ECDSAWithSHA1: "ECDSA-SHA1",
- ECDSAWithSHA256: "ECDSA-SHA256",
- ECDSAWithSHA384: "ECDSA-SHA384",
- ECDSAWithSHA512: "ECDSA-SHA512",
+ MD2WithRSA: "MD2-RSA",
+ MD5WithRSA: "MD5-RSA",
+ SHA1WithRSA: "SHA1-RSA",
+ SHA256WithRSA: "SHA256-RSA",
+ SHA384WithRSA: "SHA384-RSA",
+ SHA512WithRSA: "SHA512-RSA",
+ SHA256WithRSAPSS: "SHA256-RSAPSS",
+ SHA384WithRSAPSS: "SHA384-RSAPSS",
+ SHA512WithRSAPSS: "SHA512-RSAPSS",
+ DSAWithSHA1: "DSA-SHA1",
+ DSAWithSHA256: "DSA-SHA256",
+ ECDSAWithSHA1: "ECDSA-SHA1",
+ ECDSAWithSHA256: "ECDSA-SHA256",
+ ECDSAWithSHA384: "ECDSA-SHA384",
+ ECDSAWithSHA512: "ECDSA-SHA512",
}
func (algo SignatureAlgorithm) String() string {
@@ -263,12 +283,24 @@ var (
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
- oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
+
+ oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
+ oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
+ oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
+
+ oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
+
+ // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
+ // but it's specified by ISO. Microsoft's makecert.exe has been known
+ // to produce certificates with this OID.
+ oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
)
var signatureAlgorithmDetails = []struct {
@@ -280,9 +312,13 @@ var signatureAlgorithmDetails = []struct {
{MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
{MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
{SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
{SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
{SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
{SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+ {SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA256},
+ {SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA384},
+ {SHA512WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA512},
{DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
{DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
{ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
@@ -291,12 +327,115 @@ var signatureAlgorithmDetails = []struct {
{ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
}
-func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
- for _, details := range signatureAlgorithmDetails {
- if oid.Equal(details.oid) {
- return details.algo
+// pssParameters reflects the parameters in an AlgorithmIdentifier that
+// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
+type pssParameters struct {
+ // The following three fields are not marked as
+ // optional because the default values specify SHA-1,
+ // which is no longer suitable for use in signatures.
+ Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
+ MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
+ SaltLength int `asn1:"explicit,tag:2"`
+ TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
+}
+
+// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
+// in an AlgorithmIdentifier that specifies RSA PSS.
+func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
+ var hashOID asn1.ObjectIdentifier
+
+ switch hashFunc {
+ case crypto.SHA256:
+ hashOID = oidSHA256
+ case crypto.SHA384:
+ hashOID = oidSHA384
+ case crypto.SHA512:
+ hashOID = oidSHA512
+ }
+
+ params := pssParameters{
+ Hash: pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.RawValue{
+ Tag: 5, /* ASN.1 NULL */
+ },
+ },
+ MGF: pkix.AlgorithmIdentifier{
+ Algorithm: oidMGF1,
+ },
+ SaltLength: hashFunc.Size(),
+ TrailerField: 1,
+ }
+
+ mgf1Params := pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.RawValue{
+ Tag: 5, /* ASN.1 NULL */
+ },
+ }
+
+ var err error
+ params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
+ if err != nil {
+ panic(err)
+ }
+
+ serialized, err := asn1.Marshal(params)
+ if err != nil {
+ panic(err)
+ }
+
+ return asn1.RawValue{FullBytes: serialized}
+}
+
+func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
+ if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
+ for _, details := range signatureAlgorithmDetails {
+ if ai.Algorithm.Equal(details.oid) {
+ return details.algo
+ }
}
+ return UnknownSignatureAlgorithm
+ }
+
+ // RSA PSS is special because it encodes important parameters
+ // in the Parameters.
+
+ var params pssParameters
+ if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
+ return UnknownSignatureAlgorithm
+ }
+
+ var mgf1HashFunc pkix.AlgorithmIdentifier
+ if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
+ return UnknownSignatureAlgorithm
+ }
+
+ // PSS is greatly overburdened with options. This code forces
+ // them into three buckets by requiring that the MGF1 hash
+ // function always match the message hash function (as
+ // recommended in
+ // https://tools.ietf.org/html/rfc3447#section-8.1), that the
+ // salt length matches the hash length, and that the trailer
+ // field has the default value.
+ asn1NULL := []byte{0x05, 0x00}
+ if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) ||
+ !params.MGF.Algorithm.Equal(oidMGF1) ||
+ !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
+ !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) ||
+ params.TrailerField != 1 {
+ return UnknownSignatureAlgorithm
}
+
+ switch {
+ case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
+ return SHA256WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
+ return SHA384WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
+ return SHA512WithRSAPSS
+ }
+
return UnknownSignatureAlgorithm
}
@@ -635,7 +774,7 @@ var entrustBrokenSPKI = []byte{
// CheckSignatureFrom verifies that the signature on c is a valid signature
// from parent.
-func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
// RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not
@@ -663,7 +802,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
// CheckSignature verifies that signature is a valid signature over signed from
// c's public key.
-func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
return checkSignature(algo, signed, signature, c.PublicKey)
}
@@ -675,11 +814,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
switch algo {
case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1:
hashType = crypto.SHA1
- case SHA256WithRSA, DSAWithSHA256, ECDSAWithSHA256:
+ case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256:
hashType = crypto.SHA256
- case SHA384WithRSA, ECDSAWithSHA384:
+ case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384:
hashType = crypto.SHA384
- case SHA512WithRSA, ECDSAWithSHA512:
+ case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512:
hashType = crypto.SHA512
case MD2WithRSA, MD5WithRSA:
return InsecureAlgorithmError(algo)
@@ -697,7 +836,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
switch pub := publicKey.(type) {
case *rsa.PublicKey:
- return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ if algo.isRSAPSS() {
+ return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
+ } else {
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ }
case *dsa.PublicKey:
dsaSig := new(dsaSignature)
if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
@@ -731,8 +874,8 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
}
// CheckCRLSignature checks that the signature in crl is from c.
-func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err error) {
- algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
+ algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
@@ -781,10 +924,19 @@ type distributionPointName struct {
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
+// asn1Null is the ASN.1 encoding of a NULL value.
+var asn1Null = []byte{5, 0}
+
func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
+ // RSA public keys must have a NULL in the parameters
+ // (https://tools.ietf.org/html/rfc3279#section-2.3.1).
+ if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) {
+ return nil, errors.New("x509: RSA key missing NULL parameters")
+ }
+
p := new(rsaPublicKey)
rest, err := asn1.Unmarshal(asn1Data, p)
if err != nil {
@@ -931,7 +1083,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.Signature = in.SignatureValue.RightAlign()
out.SignatureAlgorithm =
- getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)
+ getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm)
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
@@ -1127,7 +1279,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
return nil, err
} else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 authority key-id")
+ return nil, errors.New("x509: trailing data after X.509 key-id")
}
out.SubjectKeyId = keyid
@@ -1539,6 +1691,9 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
err = errors.New("x509: cannot sign with hash function requested")
return
}
+ if requestedSigAlgo.isRSAPSS() {
+ sigAlgo.Parameters = rsaPSSParameters(hashFunc)
+ }
found = true
break
}
@@ -1571,6 +1726,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
+ if template.SerialNumber == nil {
+ return nil, errors.New("x509: no SerialNumber given")
+ }
+
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
if err != nil {
return nil, err
@@ -1581,21 +1740,21 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, err
}
- if len(parent.SubjectKeyId) > 0 {
- template.AuthorityKeyId = parent.SubjectKeyId
- }
-
- extensions, err := buildExtensions(template)
+ asn1Issuer, err := subjectBytes(parent)
if err != nil {
return
}
- asn1Issuer, err := subjectBytes(parent)
+ asn1Subject, err := subjectBytes(template)
if err != nil {
return
}
- asn1Subject, err := subjectBytes(template)
+ if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
+ template.AuthorityKeyId = parent.SubjectKeyId
+ }
+
+ extensions, err := buildExtensions(template)
if err != nil {
return
}
@@ -1623,8 +1782,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
h.Write(tbsCertContents)
digest := h.Sum(nil)
+ var signerOpts crypto.SignerOpts
+ signerOpts = hashFunc
+ if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
+ signerOpts = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ Hash: hashFunc,
+ }
+ }
+
var signature []byte
- signature, err = key.Sign(rand, digest, hashFunc)
+ signature, err = key.Sign(rand, digest, signerOpts)
if err != nil {
return
}
@@ -1648,7 +1816,7 @@ var pemType = "X509 CRL"
// encoded CRLs will appear where they should be DER encoded, so this function
// will transparently handle PEM encoding as long as there isn't any leading
// garbage.
-func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
+func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
block, _ := pem.Decode(crlBytes)
if block != nil && block.Type == pemType {
@@ -1659,8 +1827,8 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
}
// ParseDERCRL parses a DER encoded CRL from the given bytes.
-func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
- certList = new(pkix.CertificateList)
+func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
+ certList := new(pkix.CertificateList)
if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
return nil, err
} else if len(rest) != 0 {
@@ -1682,13 +1850,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
return nil, err
}
+ // Force revocation times to UTC per RFC 5280.
+ revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts))
+ for i, rc := range revokedCerts {
+ rc.RevocationTime = rc.RevocationTime.UTC()
+ revokedCertsUTC[i] = rc
+ }
+
tbsCertList := pkix.TBSCertificateList{
Version: 1,
Signature: signatureAlgorithm,
Issuer: c.Subject.ToRDNSequence(),
ThisUpdate: now.UTC(),
NextUpdate: expiry.UTC(),
- RevokedCertificates: revokedCerts,
+ RevokedCertificates: revokedCertsUTC,
}
// Authority Key Id
@@ -1790,12 +1965,15 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
var rawAttributes []asn1.RawValue
b, err := asn1.Marshal(attributes)
+ if err != nil {
+ return nil, err
+ }
rest, err := asn1.Unmarshal(b, &rawAttributes)
if err != nil {
return nil, err
}
if len(rest) != 0 {
- return nil, errors.New("x509: failed to unmarshall raw CSR Attributes")
+ return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
}
return rawAttributes, nil
}
@@ -1847,8 +2025,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.
//
@@ -2026,7 +2204,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
RawSubject: in.TBSCSR.Subject.FullBytes,
Signature: in.SignatureValue.RightAlign(),
- SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm),
+ SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm),
PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
@@ -2065,7 +2243,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
return out, nil
}
-// CheckSignature verifies that the signature on c is a valid signature
-func (c *CertificateRequest) CheckSignature() (err error) {
+// CheckSignature reports whether the signature on c is valid.
+func (c *CertificateRequest) CheckSignature() error {
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
index d1ef0274bc..b085dad90f 100644
--- a/libgo/go/crypto/x509/x509_test.go
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -24,6 +24,8 @@ import (
"net"
"os/exec"
"reflect"
+ "runtime"
+ "strings"
"testing"
"time"
)
@@ -85,17 +87,35 @@ FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
-----END PUBLIC KEY-----
`
-var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
-MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
-fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
-/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
-RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
-EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
-IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
-tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+var pemPrivateKey = `
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCxoeCUW5KJxNPxMp+KmCxKLc1Zv9Ny+4CFqcUXVUYH69L3mQ7v
+IWrJ9GBfcaA7BPQqUlWxWM+OCEQZH1EZNIuqRMNQVuIGCbz5UQ8w6tS0gcgdeGX7
+J7jgCQ4RK3F/PuCM38QBLaHx988qG8NMc6VKErBjctCXFHQt14lerd5KpQIDAQAB
+AoGAYrf6Hbk+mT5AI33k2Jt1kcweodBP7UkExkPxeuQzRVe0KVJw0EkcFhywKpr1
+V5eLMrILWcJnpyHE5slWwtFHBG6a5fLaNtsBBtcAIfqTQ0Vfj5c6SzVaJv0Z5rOd
+7gQF6isy3t3w9IF3We9wXQKzT6q5ypPGdm6fciKQ8RnzREkCQQDZwppKATqQ41/R
+vhSj90fFifrGE6aVKC1hgSpxGQa4oIdsYYHwMzyhBmWW9Xv/R+fPyr8ZwPxp2c12
+33QwOLPLAkEA0NNUb+z4ebVVHyvSwF5jhfJxigim+s49KuzJ1+A2RaSApGyBZiwS
+rWvWkB471POAKUYt5ykIWVZ83zcceQiNTwJBAMJUFQZX5GDqWFc/zwGoKkeR49Yi
+MTXIvf7Wmv6E++eFcnT461FlGAUHRV+bQQXGsItR/opIG7mGogIkVXa3E1MCQARX
+AAA7eoZ9AEHflUeuLn9QJI/r0hyQQLEtrpwv6rDT1GCWaLII5HJ6NUFVf4TTcqxo
+6vdM4QGKTJoO+SaCyP0CQFdpcxSAuzpFcKv0IlJ8XzS/cy+mweCMwyJ1PFEc4FX6
+wg/HcAJWY60xZTJDFN+Qfx8ZQvBEin6c2/h+zZi5IVY=
-----END RSA PRIVATE KEY-----
`
+var testPrivateKey *rsa.PrivateKey
+
+func init() {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+
+ var err error
+ if testPrivateKey, err = ParsePKCS1PrivateKey(block.Bytes); err != nil {
+ panic("Failed to parse private key: " + err.Error())
+ }
+}
+
func bigFromString(s string) *big.Int {
ret := new(big.Int)
ret.SetString(s, 10)
@@ -116,13 +136,13 @@ func bigFromHexString(s string) *big.Int {
var rsaPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
- N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ N: bigFromString("124737666279038955318614287965056875799409043964547386061640914307192830334599556034328900586693254156136128122194531292927142396093148164407300419162827624945636708870992355233833321488652786796134504707628792159725681555822420087112284637501705261187690946267527866880072856272532711620639179596808018872997"),
E: 65537,
},
- D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ D: bigFromString("69322600686866301945688231018559005300304807960033948687567105312977055197015197977971637657636780793670599180105424702854759606794705928621125408040473426339714144598640466128488132656829419518221592374964225347786430566310906679585739468938549035854760501049443920822523780156843263434219450229353270690889"),
Primes: []*big.Int{
- bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
- bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+ bigFromString("11405025354575369741595561190164746858706645478381139288033759331174478411254205003127028642766986913445391069745480057674348716675323735886284176682955723"),
+ bigFromString("10937079261204603443118731009201819560867324167189758120988909645641782263430128449826989846631183550578761324239709121189827307416350485191350050332642639"),
},
}
@@ -314,12 +334,6 @@ var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be13
func TestCreateSelfSignedCertificate(t *testing.T) {
random := rand.Reader
- block, _ := pem.Decode([]byte(pemPrivateKey))
- rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- t.Fatalf("Failed to parse private key: %s", err)
- }
-
ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key: %s", err)
@@ -331,10 +345,13 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
checkSig bool
sigAlgo SignatureAlgorithm
}{
- {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
- {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
- {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+ {"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, SHA1WithRSA},
+ {"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+ {"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSA},
{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
+ {"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, SHA256WithRSAPSS},
+ {"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSAPSS},
+ {"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
}
testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -488,7 +505,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: ExtraExtensions didn't override SubjectKeyId", test.name)
}
- if bytes.Index(derBytes, extraExtensionData) == -1 {
+ if !bytes.Contains(derBytes, extraExtensionData) {
t.Errorf("%s: didn't find extra extension in DER output", test.name)
}
@@ -756,16 +773,76 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
}
}
+var rsaPSSSelfSignedPEM = `-----BEGIN CERTIFICATE-----
+MIIGHjCCA9KgAwIBAgIBdjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
+oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAwbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMB4XDTEzMDUxNDA1MDczMFoXDTI5MDUxNDA1MDczMFowbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx/E3WRVxcCDXhoST
+8nVSLjW6hwM4Ni99AegWzcGtfGFo0zjFA1Cl5URqxauvYu3gQgQHBGA1CovWeGrl
+yVSRzOL1imcYsSgLOcnhVYB3Xcrof4ebv9+W+TwNdc9YzAwcj8rNd5nP6PKXIQ+W
+PCkEOXdyb80YEnxuT+NPjkVfFSPBS7QYZpvT2fwy4fZ0eh48253+7VleSmTO0mqj
+7TlzaG56q150SLZbhpOd8jD8bM/wACnLCPR88wj4hCcDLEwoLyY85HJCTIQQMnoT
+UpqyzEeupPREIm6yi4d8C9YqIWFn2YTnRcWcmMaJLzq+kYwKoudfnoC6RW2vzZXn
+defQs68IZuK+uALu9G3JWGPgu0CQGj0JNDT8zkiDV++4eNrZczWKjr1YnAL+VbLK
+bApwL2u19l2WDpfUklimhWfraqHNIUKU6CjZOG31RzXcplIj0mtqs0E1r7r357Es
+yFoB28iNo4cz1lCulh0E4WJzWzLZcT4ZspHHRCFyvYnXoibXEV1nULq8ByKKG0FS
+7nn4SseoV+8PvjHLPhmHGMvi4mxkbcXdV3wthHT1/HXdqY84A4xHWt1+sB/TpTek
+tDhFlEfcUygvTu58UtOnysomOVVeERmi7WSujfzKsGJAJYeetiA5R+zX7BxeyFVE
+qW0zh1Tkwh0S8LRe5diJh4+6FG0CAwEAAaNfMF0wHQYDVR0OBBYEFD+oahaikBTV
+Urk81Uz7kRS2sx0aMA4GA1UdDwEB/wQEAwIBBjAYBgNVHSAEETAPMA0GCyqDCIaP
+fgYFAQEBMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYJKoZIhvcNAQEKMDSgDzANBglg
+hkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IC
+AQAaxWBQn5CZuNBfyzL57mn31ukHUFd61OMROSX3PT7oCv1Dy+C2AdRlxOcbN3/n
+li0yfXUUqiY3COlLAHKRlkr97mLtxEFoJ0R8nVN2IQdChNQM/XSCzSGyY8NVa1OR
+TTpEWLnexJ9kvIdbFXwUqdTnAkOI0m7Rg8j+E+lRRHg1xDAA1qKttrtUj3HRQWf3
+kNTu628SiMvap6aIdncburaK56MP7gkR1Wr/ichOfjIA3Jgw2PapI31i0GqeMd66
+U1+lC9FeyMAJpuSVp/SoiYzYo+79SFcVoM2yw3yAnIKg7q9GLYYqzncdykT6C06c
+15gWFI6igmReAsD9ITSvYh0jLrLHfEYcPTOD3ZXJ4EwwHtWSoO3gq1EAtOYKu/Lv
+C8zfBsZcFdsHvsSiYeBU8Oioe42mguky3Ax9O7D805Ek6R68ra07MW/G4YxvV7IN
+2BfSaYy8MX9IG0ZMIOcoc0FeF5xkFmJ7kdrlTaJzC0IE9PNxNaH5QnOAFB8vxHcO
+FioUxb6UKdHcPLR1VZtAdTdTMjSJxUqD/35Cdfqs7oDJXz8f6TXO2Tdy6G++YUs9
+qsGZWxzFvvkXUkQSl0dQQ5jO/FtUJcAVXVVp20LxPemfatAHpW31WdJYeWSQWky2
++f9b5TXKXVyjlUL7uHxowWrT2AtTchDH22wTEtqLEF9Z3Q==
+-----END CERTIFICATE-----`
+
+func TestRSAPSSSelfSigned(t *testing.T) {
+ der, _ := pem.Decode([]byte(rsaPSSSelfSignedPEM))
+ if der == nil {
+ t.Fatal("Failed to find PEM block")
+ }
+
+ cert, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatal(err)
+ }
+}
+
const pemCertificate = `-----BEGIN CERTIFICATE-----
-MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
-AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
-BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
-SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
-fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
-/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
-ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
-YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
-0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+MIIDATCCAemgAwIBAgIRAKQkkrFx1T/dgB/Go/xBM5swDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTcyMDM2MDdaFw0xNzA4MTcyMDM2
+MDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDAoJtjG7M6InsWwIo+l3qq9u+g2rKFXNu9/mZ24XQ8XhV6PUR+5HQ4
+jUFWC58ExYhottqK5zQtKGkw5NuhjowFUgWB/VlNGAUBHtJcWR/062wYrHBYRxJH
+qVXOpYKbIWwFKoXu3hcpg/CkdOlDWGKoZKBCwQwUBhWE7MDhpVdQ+ZljUJWL+FlK
+yQK5iRsJd5TGJ6VUzLzdT4fmN2DzeK6GLeyMpVpU3sWV90JJbxWQ4YrzkKzYhMmB
+EcpXTG2wm+ujiHU/k2p8zlf8Sm7VBM/scmnMFt0ynNXop4FWvJzEm1G0xD2t+e2I
+5Utr04dOZPCgkm++QJgYhtZvgW7ZZiGTAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKC
+EHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBADpqKQxrthH5InC7
+X96UP0OJCu/lLEMkrjoEWYIQaFl7uLPxKH5AmQPH4lYwF7u7gksR7owVG9QU9fs6
+1fK7II9CVgCd/4tZ0zm98FmU4D0lHGtPARrrzoZaqVZcAvRnFTlPX5pFkPhVjjai
+/mkxX9LpD8oK1445DFHxK5UjLMmPIIWd8EOi+v5a+hgGwnJpoW7hntSl8kHMtTmy
+fnnktsblSUV4lRCit0ymC7Ojhe+gzCCwkgs5kDzVVag+tnl/0e2DloIjASwOhpbH
+KVcg7fBd484ht/sS+l0dsB4KDOSpd8JzVDMF8OZqlaydizoJO0yWr9GbCN1+OKq5
+EhLrEqU=
-----END CERTIFICATE-----`
func TestCRLCreation(t *testing.T) {
@@ -774,17 +851,31 @@ func TestCRLCreation(t *testing.T) {
block, _ = pem.Decode([]byte(pemCertificate))
cert, _ := ParseCertificate(block.Bytes)
- now := time.Unix(1000, 0)
+ loc := time.FixedZone("Oz/Atlantis", int((2 * time.Hour).Seconds()))
+
+ now := time.Unix(1000, 0).In(loc)
+ nowUTC := now.UTC()
expiry := time.Unix(10000, 0)
revokedCerts := []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(1),
+ RevocationTime: nowUTC,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ // RevocationTime should be converted to UTC before marshaling.
RevocationTime: now,
},
+ }
+ expectedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: nowUTC,
+ },
{
SerialNumber: big.NewInt(42),
- RevocationTime: now,
+ RevocationTime: nowUTC,
},
}
@@ -793,10 +884,14 @@ func TestCRLCreation(t *testing.T) {
t.Errorf("error creating CRL: %s", err)
}
- _, err = ParseDERCRL(crlBytes)
+ parsedCRL, err := ParseDERCRL(crlBytes)
if err != nil {
t.Errorf("error reparsing CRL: %s", err)
}
+ if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
+ t.Errorf("RevokedCertificates mismatch: got %v; want %v.",
+ parsedCRL.TBSCertList.RevokedCertificates, expectedCerts)
+ }
}
func fromBase64(in string) []byte {
@@ -862,7 +957,7 @@ func TestParsePEMCRL(t *testing.T) {
func TestImports(t *testing.T) {
testenv.MustHaveGoRun(t)
- if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
+ if err := exec.Command(testenv.GoToolPath(t), "run", "x509_test_import.go").Run(); err != nil {
t.Errorf("failed to run x509_test_import.go: %s", err)
}
}
@@ -874,12 +969,6 @@ const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RF
func TestCreateCertificateRequest(t *testing.T) {
random := rand.Reader
- block, _ := pem.Decode([]byte(pemPrivateKey))
- rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- t.Fatalf("Failed to parse private key: %s", err)
- }
-
ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key: %s", err)
@@ -900,7 +989,7 @@ func TestCreateCertificateRequest(t *testing.T) {
priv interface{}
sigAlgo SignatureAlgorithm
}{
- {"RSA", rsaPriv, SHA1WithRSA},
+ {"RSA", testPrivateKey, SHA1WithRSA},
{"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
{"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
{"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
@@ -951,13 +1040,7 @@ func TestCreateCertificateRequest(t *testing.T) {
}
func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
- block, _ := pem.Decode([]byte(pemPrivateKey))
- rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- t.Fatal(err)
- }
-
- derBytes, err := CreateCertificateRequest(rand.Reader, template, rsaPriv)
+ derBytes, err := CreateCertificateRequest(rand.Reader, template, testPrivateKey)
if err != nil {
t.Fatal(err)
}
@@ -1113,13 +1196,25 @@ func TestCriticalFlagInCSRRequestedExtensions(t *testing.T) {
}
}
-func TestMaxPathLen(t *testing.T) {
- block, _ := pem.Decode([]byte(pemPrivateKey))
- rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+// serialiseAndParse generates a self-signed certificate from template and
+// returns a parsed version of it.
+func serialiseAndParse(t *testing.T, template *Certificate) *Certificate {
+ derBytes, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey)
if err != nil {
- t.Fatalf("Failed to parse private key: %s", err)
+ t.Fatalf("failed to create certificate: %s", err)
+ return nil
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ return nil
}
+ return cert
+}
+
+func TestMaxPathLen(t *testing.T) {
template := &Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
@@ -1132,23 +1227,7 @@ func TestMaxPathLen(t *testing.T) {
IsCA: true,
}
- serialiseAndParse := func(template *Certificate) *Certificate {
- derBytes, err := CreateCertificate(rand.Reader, template, template, &rsaPriv.PublicKey, rsaPriv)
- if err != nil {
- t.Fatalf("failed to create certificate: %s", err)
- return nil
- }
-
- cert, err := ParseCertificate(derBytes)
- if err != nil {
- t.Fatalf("failed to parse certificate: %s", err)
- return nil
- }
-
- return cert
- }
-
- cert1 := serialiseAndParse(template)
+ cert1 := serialiseAndParse(t, template)
if m := cert1.MaxPathLen; m != -1 {
t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m)
}
@@ -1157,7 +1236,7 @@ func TestMaxPathLen(t *testing.T) {
}
template.MaxPathLen = 1
- cert2 := serialiseAndParse(template)
+ cert2 := serialiseAndParse(t, template)
if m := cert2.MaxPathLen; m != 1 {
t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m)
}
@@ -1167,7 +1246,7 @@ func TestMaxPathLen(t *testing.T) {
template.MaxPathLen = 0
template.MaxPathLenZero = true
- cert3 := serialiseAndParse(template)
+ cert3 := serialiseAndParse(t, template)
if m := cert3.MaxPathLen; m != 0 {
t.Errorf("Setting MaxPathLenZero didn't work, got %d", m)
}
@@ -1176,6 +1255,30 @@ func TestMaxPathLen(t *testing.T) {
}
}
+func TestNoAuthorityKeyIdInSelfSignedCert(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ }
+
+ if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) != 0 {
+ t.Fatalf("self-signed certificate contained default authority key id")
+ }
+
+ template.AuthorityKeyId = []byte{1, 2, 3, 4}
+ if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) == 0 {
+ t.Fatalf("self-signed certificate erased explicit authority key id")
+ }
+}
+
func TestASN1BitLength(t *testing.T) {
tests := []struct {
bytes []byte
@@ -1271,3 +1374,115 @@ func TestMD5(t *testing.T) {
t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
}
}
+
+// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifer
+// parameters are omitted rather than being an ASN.1 NULL.
+const certMissingRSANULL = `
+-----BEGIN CERTIFICATE-----
+MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
+bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
+MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
+MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
+hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
+ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
+E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
+p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
+hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
+GFGNEH5PlGffo05wc46QkYU=
+-----END CERTIFICATE-----`
+
+func TestRSAMissingNULLParameters(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMissingRSANULL))
+ if _, err := ParseCertificate(block.Bytes); err == nil {
+ t.Error("unexpected success when parsing certificate with missing RSA NULL parameter")
+ } else if !strings.Contains(err.Error(), "missing NULL") {
+ t.Errorf("unrecognised error when parsing certificate with missing RSA NULL parameter: %s", err)
+ }
+}
+
+const certISOOID = `
+-----BEGIN CERTIFICATE-----
+MIIB5TCCAVKgAwIBAgIQtwyL3RPWV7dJQp34HwZG9DAJBgUrDgMCHQUAMBExDzAN
+BgNVBAMTBm15dGVzdDAeFw0xNjA4MDkyMjExMDVaFw0zOTEyMzEyMzU5NTlaMBEx
+DzANBgNVBAMTBm15dGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArzIH
+GsyDB3ohIGkkvijF2PTRUX1bvOtY1eUUpjwHyu0twpAKSuaQv2Ha+/63+aHe8O86
+BT+98wjXFX6RFSagtAujo80rIF2dSm33BGt18pDN8v6zp93dnAm0jRaSQrHJ75xw
+5O+S1oEYR1LtUoFJy6qB104j6aINBAgOiLIKiMkCAwEAAaNGMEQwQgYDVR0BBDsw
+OYAQVuYVQ/WDjdGSkZRlTtJDNKETMBExDzANBgNVBAMTBm15dGVzdIIQtwyL3RPW
+V7dJQp34HwZG9DAJBgUrDgMCHQUAA4GBABngrSkH7vG5lY4sa4AZF59lAAXqBVJE
+J4TBiKC62hCdZv18rBleP6ETfhbPg7pTs8p4ebQbpmtNxRS9Lw3MzQ8Ya5Ybwzj2
+NwBSyCtCQl7mrEg4nJqJl4A2EUhnET/oVxU0oTV/SZ3ziGXcY1oG1s6vidV7TZTu
+MCRtdSdaM7g3
+-----END CERTIFICATE-----`
+
+func TestISOOIDInCertificate(t *testing.T) {
+ block, _ := pem.Decode([]byte(certISOOID))
+ if cert, err := ParseCertificate(block.Bytes); err != nil {
+ t.Errorf("certificate with ISO OID failed to parse: %s", err)
+ } else if cert.SignatureAlgorithm == UnknownSignatureAlgorithm {
+ t.Errorf("ISO OID not recognised in certificate")
+ }
+}
+
+// certMultipleRDN contains a RelativeDistinguishedName with two elements (the
+// common name and serial number). This particular certificate was the first
+// such certificate in the “Pilot†Certificate Transparency log.
+const certMultipleRDN = `
+-----BEGIN CERTIFICATE-----
+MIIFRzCCBC+gAwIBAgIEOl59NTANBgkqhkiG9w0BAQUFADA9MQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMREwDwYDVQQLEwhzaWdvdi1j
+YTAeFw0xMjExMTYxMDUyNTdaFw0xNzExMTYxMjQ5MDVaMIGLMQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMRkwFwYDVQQLExB3ZWItY2Vy
+dGlmaWNhdGVzMRAwDgYDVQQLEwdTZXJ2ZXJzMTIwFAYDVQQFEw0xMjM2NDg0MDEw
+MDEwMBoGA1UEAxMTZXBvcnRhbC5tc3MuZWR1cy5zaTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMrNkZH9MPuBTjMGNk3sJX8V+CkFx/4ru7RTlLS6dlYM
+098dtSfJ3s2w0p/1NB9UmR8j0yS0Kg6yoZ3ShsSO4DWBtcQD8820a6BYwqxxQTNf
+HSRZOc+N/4TQrvmK6t4k9Aw+YEYTMrWOU4UTeyhDeCcUsBdh7HjfWsVaqNky+2sv
+oic3zP5gF+2QfPkvOoHT3FLR8olNhViIE6Kk3eFIEs4dkq/ZzlYdLb8pHQoj/sGI
+zFmA5AFvm1HURqOmJriFjBwaCtn8AVEYOtQrnUCzJYu1ex8azyS2ZgYMX0u8A5Z/
+y2aMS/B2W+H79WcgLpK28vPwe7vam0oFrVytAd+u65ECAwEAAaOCAf4wggH6MA4G
+A1UdDwEB/wQEAwIFoDBABgNVHSAEOTA3MDUGCisGAQQBr1kBAwMwJzAlBggrBgEF
+BQcCARYZaHR0cDovL3d3dy5jYS5nb3Yuc2kvY3BzLzAfBgNVHREEGDAWgRRwb2Rw
+b3JhLm1pemtzQGdvdi5zaTCB8QYDVR0fBIHpMIHmMFWgU6BRpE8wTTELMAkGA1UE
+BhMCc2kxGzAZBgNVBAoTEnN0YXRlLWluc3RpdHV0aW9uczERMA8GA1UECxMIc2ln
+b3YtY2ExDjAMBgNVBAMTBUNSTDM5MIGMoIGJoIGGhldsZGFwOi8veDUwMC5nb3Yu
+c2kvb3U9c2lnb3YtY2Esbz1zdGF0ZS1pbnN0aXR1dGlvbnMsYz1zaT9jZXJ0aWZp
+Y2F0ZVJldm9jYXRpb25MaXN0P2Jhc2WGK2h0dHA6Ly93d3cuc2lnb3YtY2EuZ292
+LnNpL2NybC9zaWdvdi1jYS5jcmwwKwYDVR0QBCQwIoAPMjAxMjExMTYxMDUyNTda
+gQ8yMDE3MTExNjEyNDkwNVowHwYDVR0jBBgwFoAUHvjUU2uzgwbpBAZXAvmlv8ZY
+PHIwHQYDVR0OBBYEFGI1Duuu+wTGDZka/xHNbwcbM69ZMAkGA1UdEwQCMAAwGQYJ
+KoZIhvZ9B0EABAwwChsEVjcuMQMCA6gwDQYJKoZIhvcNAQEFBQADggEBAHny0K1y
+BQznrzDu3DDpBcGYguKU0dvU9rqsV1ua4nxkriSMWjgsX6XJFDdDW60I3P4VWab5
+ag5fZzbGqi8kva/CzGgZh+CES0aWCPy+4Gb8lwOTt+854/laaJvd6kgKTER7z7U9
+9C86Ch2y4sXNwwwPJ1A9dmrZJZOcJjS/WYZgwaafY2Hdxub5jqPE5nehwYUPVu9R
+uH6/skk4OEKcfOtN0hCnISOVuKYyS4ANARWRG5VGHIH06z3lGUVARFRJ61gtAprd
+La+fgSS+LVZ+kU2TkeoWAKvGq8MAgDq4D4Xqwekg7WKFeuyusi/NI5rm40XgjBMF
+DF72IUofoVt7wo0=
+-----END CERTIFICATE-----`
+
+func TestMultipleRDN(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMultipleRDN))
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ t.Fatalf("certificate with two elements in an RDN failed to parse: %v", err)
+ }
+
+ if want := "eportal.mss.edus.si"; cert.Subject.CommonName != want {
+ t.Errorf("got common name of %q, but want %q", cert.Subject.CommonName, want)
+ }
+
+ if want := "1236484010010"; cert.Subject.SerialNumber != want {
+ t.Errorf("got serial number of %q, but want %q", cert.Subject.SerialNumber, want)
+ }
+}
+
+func TestSystemCertPool(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("not implemented on Windows; Issue 16736, 18609")
+ }
+ _, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go
index 740fd9d6e7..ea2f377810 100644
--- a/libgo/go/database/sql/convert.go
+++ b/libgo/go/database/sql/convert.go
@@ -13,16 +13,36 @@ import (
"reflect"
"strconv"
"time"
+ "unicode"
+ "unicode/utf8"
)
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+func describeNamedValue(nv *driver.NamedValue) string {
+ if len(nv.Name) == 0 {
+ return fmt.Sprintf("$%d", nv.Ordinal)
+ }
+ return fmt.Sprintf("with name %q", nv.Name)
+}
+
+func validateNamedValueName(name string) error {
+ if len(name) == 0 {
+ return nil
+ }
+ r, _ := utf8.DecodeRuneInString(name)
+ if unicode.IsLetter(r) {
+ return nil
+ }
+ return fmt.Errorf("name %q does not begin with a letter", name)
+}
+
// driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values.
//
// The statement ds may be nil, if no statement is available.
-func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
- dargs := make([]driver.Value, len(args))
+func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) {
+ nvargs := make([]driver.NamedValue, len(args))
var si driver.Stmt
if ds != nil {
si = ds.si
@@ -33,26 +53,45 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
if !ok {
for n, arg := range args {
var err error
- dargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ nv := &nvargs[n]
+ nv.Ordinal = n + 1
+ if np, ok := arg.(NamedArg); ok {
+ if err := validateNamedValueName(np.Name); err != nil {
+ return nil, err
+ }
+ arg = np.Value
+ nvargs[n].Name = np.Name
+ }
+ nv.Value, err = driver.DefaultParameterConverter.ConvertValue(arg)
+
if err != nil {
- return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting Exec argument %s type: %v", describeNamedValue(nv), err)
}
}
- return dargs, nil
+ return nvargs, nil
}
// Let the Stmt convert its own arguments.
for n, arg := range args {
+ nv := &nvargs[n]
+ nv.Ordinal = n + 1
+ if np, ok := arg.(NamedArg); ok {
+ if err := validateNamedValueName(np.Name); err != nil {
+ return nil, err
+ }
+ arg = np.Value
+ nv.Name = np.Name
+ }
// First, see if the value itself knows how to convert
- // itself to a driver type. For example, a NullString
+ // itself to a driver type. For example, a NullString
// struct changing into a string or nil.
- if svi, ok := arg.(driver.Valuer); ok {
- sv, err := svi.Value()
+ if vr, ok := arg.(driver.Valuer); ok {
+ sv, err := callValuerValue(vr)
if err != nil {
- return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err)
+ return nil, fmt.Errorf("sql: argument %s from Value: %v", describeNamedValue(nv), err)
}
if !driver.IsValue(sv) {
- return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv)
+ return nil, fmt.Errorf("sql: argument %s: non-subset type %T returned from Value", describeNamedValue(nv), sv)
}
arg = sv
}
@@ -66,18 +105,18 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
// same error.
var err error
ds.Lock()
- dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ nv.Value, err = cc.ColumnConverter(n).ConvertValue(arg)
ds.Unlock()
if err != nil {
- return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err)
}
- if !driver.IsValue(dargs[n]) {
- return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
- arg, dargs[n])
+ if !driver.IsValue(nv.Value) {
+ return nil, fmt.Errorf("sql: for argument %s, driver ColumnConverter error converted %T to unsupported type %T",
+ describeNamedValue(nv), arg, nv.Value)
}
}
- return dargs, nil
+ return nvargs, nil
}
// convertAssign copies to dest the value in src, converting it if possible.
@@ -217,7 +256,12 @@ func convertAssign(dest, src interface{}) error {
dv := reflect.Indirect(dpv)
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
- dv.Set(sv)
+ switch b := src.(type) {
+ case []byte:
+ dv.Set(reflect.ValueOf(cloneBytes(b)))
+ default:
+ dv.Set(sv)
+ }
return nil
}
@@ -325,3 +369,25 @@ func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
}
return
}
+
+var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+// Issue 8415.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This function is mirrored in the database/sql/driver package.
+func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go
index 342875e190..4dfab1f6be 100644
--- a/libgo/go/database/sql/convert_test.go
+++ b/libgo/go/database/sql/convert_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"reflect"
"runtime"
+ "strings"
"testing"
"time"
)
@@ -377,3 +378,97 @@ func TestRawBytesAllocs(t *testing.T) {
t.Fatalf("allocs = %v; want max 1", n)
}
}
+
+// https://github.com/golang/go/issues/13905
+func TestUserDefinedBytes(t *testing.T) {
+ type userDefinedBytes []byte
+ var u userDefinedBytes
+ v := []byte("foo")
+
+ convertAssign(&u, v)
+ if &u[0] == &v[0] {
+ t.Fatal("userDefinedBytes got potentially dirty driver memory")
+ }
+}
+
+type Valuer_V string
+
+func (v Valuer_V) Value() (driver.Value, error) {
+ return strings.ToUpper(string(v)), nil
+}
+
+type Valuer_P string
+
+func (p *Valuer_P) Value() (driver.Value, error) {
+ if p == nil {
+ return "nil-to-str", nil
+ }
+ return strings.ToUpper(string(*p)), nil
+}
+
+func TestDriverArgs(t *testing.T) {
+ var nilValuerVPtr *Valuer_V
+ var nilValuerPPtr *Valuer_P
+ var nilStrPtr *string
+ tests := []struct {
+ args []interface{}
+ want []driver.NamedValue
+ }{
+ 0: {
+ args: []interface{}{Valuer_V("foo")},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "FOO",
+ },
+ },
+ },
+ 1: {
+ args: []interface{}{nilValuerVPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: nil,
+ },
+ },
+ },
+ 2: {
+ args: []interface{}{nilValuerPPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "nil-to-str",
+ },
+ },
+ },
+ 3: {
+ args: []interface{}{"plain-str"},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "plain-str",
+ },
+ },
+ },
+ 4: {
+ args: []interface{}{nilStrPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: nil,
+ },
+ },
+ },
+ }
+ for i, tt := range tests {
+ ds := new(driverStmt)
+ got, err := driverArgs(ds, tt.args)
+ if err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("test[%d]: got %v, want %v", i, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/database/sql/ctxutil.go b/libgo/go/database/sql/ctxutil.go
new file mode 100644
index 0000000000..bd652b5462
--- /dev/null
+++ b/libgo/go/database/sql/ctxutil.go
@@ -0,0 +1,149 @@
+// 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 sql
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+)
+
+func ctxDriverPrepare(ctx context.Context, ci driver.Conn, query string) (driver.Stmt, error) {
+ if ciCtx, is := ci.(driver.ConnPrepareContext); is {
+ return ciCtx.PrepareContext(ctx, query)
+ }
+ si, err := ci.Prepare(query)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ si.Close()
+ return nil, ctx.Err()
+ }
+ }
+ return si, err
+}
+
+func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvdargs []driver.NamedValue) (driver.Result, error) {
+ if execerCtx, is := execer.(driver.ExecerContext); is {
+ return execerCtx.ExecContext(ctx, query, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ return execer.Exec(query, dargs)
+}
+
+func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) {
+ if queryerCtx, is := queryer.(driver.QueryerContext); is {
+ ret, err := queryerCtx.QueryContext(ctx, query, nvdargs)
+ return ret, err
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ return queryer.Query(query, dargs)
+}
+
+func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Result, error) {
+ if siCtx, is := si.(driver.StmtExecContext); is {
+ return siCtx.ExecContext(ctx, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ return si.Exec(dargs)
+}
+
+func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Rows, error) {
+ if siCtx, is := si.(driver.StmtQueryContext); is {
+ return siCtx.QueryContext(ctx, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ return si.Query(dargs)
+}
+
+var errLevelNotSupported = errors.New("sql: selected isolation level is not supported")
+
+func ctxDriverBegin(ctx context.Context, opts *TxOptions, ci driver.Conn) (driver.Tx, error) {
+ if ciCtx, is := ci.(driver.ConnBeginTx); is {
+ dopts := driver.TxOptions{}
+ if opts != nil {
+ dopts.Isolation = driver.IsolationLevel(opts.Isolation)
+ dopts.ReadOnly = opts.ReadOnly
+ }
+ return ciCtx.BeginTx(ctx, dopts)
+ }
+
+ if ctx.Done() == context.Background().Done() {
+ return ci.Begin()
+ }
+
+ if opts != nil {
+ // Check the transaction level. If the transaction level is non-default
+ // then return an error here as the BeginTx driver value is not supported.
+ if opts.Isolation != LevelDefault {
+ return nil, errors.New("sql: driver does not support non-default isolation level")
+ }
+
+ // If a read-only transaction is requested return an error as the
+ // BeginTx driver value is not supported.
+ if opts.ReadOnly {
+ return nil, errors.New("sql: driver does not support read-only transactions")
+ }
+ }
+
+ txi, err := ci.Begin()
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ txi.Rollback()
+ return nil, ctx.Err()
+ }
+ }
+ return txi, err
+}
+
+func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
+ dargs := make([]driver.Value, len(named))
+ for n, param := range named {
+ if len(param.Name) > 0 {
+ return nil, errors.New("sql: driver does not support the use of Named Parameters")
+ }
+ dargs[n] = param.Value
+ }
+ return dargs, nil
+}
diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go
index eca25f29a0..d66196fd48 100644
--- a/libgo/go/database/sql/driver/driver.go
+++ b/libgo/go/database/sql/driver/driver.go
@@ -8,7 +8,11 @@
// Most code should use package sql.
package driver
-import "errors"
+import (
+ "context"
+ "errors"
+ "reflect"
+)
// Value is a value that drivers must be able to handle.
// It is either nil or an instance of one of these types:
@@ -17,10 +21,25 @@ import "errors"
// float64
// bool
// []byte
-// string [*] everywhere except from Rows.Next.
+// string
// time.Time
type Value interface{}
+// NamedValue holds both the value name and value.
+type NamedValue struct {
+ // If the Name is not empty it should be used for the parameter identifier and
+ // not the ordinal position.
+ //
+ // Name will not have a symbol prefix.
+ Name string
+
+ // Ordinal position of the parameter starting from one and is always set.
+ Ordinal int
+
+ // Value is the parameter value.
+ Value Value
+}
+
// Driver is the interface that must be implemented by a database
// driver.
type Driver interface {
@@ -54,6 +73,17 @@ var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
// you shouldn't return ErrBadConn.
var ErrBadConn = errors.New("driver: bad connection")
+// Pinger is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement Pinger, the sql package's DB.Ping and
+// DB.PingContext will check if there is at least one Conn available.
+//
+// If Conn.Ping returns ErrBadConn, DB.Ping and DB.PingContext will remove
+// the Conn from pool.
+type Pinger interface {
+ Ping(ctx context.Context) error
+}
+
// Execer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Execer, the sql package's DB.Exec will
@@ -61,10 +91,25 @@ var ErrBadConn = errors.New("driver: bad connection")
// statement.
//
// Exec may return ErrSkip.
+//
+// Deprecated: Drivers should implement ExecerContext instead (or additionally).
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
+// ExecerContext is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement ExecerContext, the sql package's DB.Exec will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// ExecerContext may return ErrSkip.
+//
+// ExecerContext must honor the context timeout and return when the context is canceled.
+type ExecerContext interface {
+ ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
+}
+
// Queryer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Queryer, the sql package's DB.Query will
@@ -72,10 +117,25 @@ type Execer interface {
// statement.
//
// Query may return ErrSkip.
+//
+// Deprecated: Drivers should implement QueryerContext instead (or additionally).
type Queryer interface {
Query(query string, args []Value) (Rows, error)
}
+// QueryerContext is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement QueryerContext, the sql package's DB.Query will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// QueryerContext may return ErrSkip.
+//
+// QueryerContext must honor the context timeout and return when the context is canceled.
+type QueryerContext interface {
+ QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
+}
+
// Conn is a connection to a database. It is not used concurrently
// by multiple goroutines.
//
@@ -95,9 +155,50 @@ type Conn interface {
Close() error
// Begin starts and returns a new transaction.
+ //
+ // Deprecated: Drivers should implement ConnBeginTx instead (or additionally).
Begin() (Tx, error)
}
+// ConnPrepareContext enhances the Conn interface with context.
+type ConnPrepareContext interface {
+ // PrepareContext returns a prepared statement, bound to this connection.
+ // context is for the preparation of the statement,
+ // it must not store the context within the statement itself.
+ PrepareContext(ctx context.Context, query string) (Stmt, error)
+}
+
+// IsolationLevel is the transaction isolation level stored in TxOptions.
+//
+// This type should be considered identical to sql.IsolationLevel along
+// with any values defined on it.
+type IsolationLevel int
+
+// TxOptions holds the transaction options.
+//
+// This type should be considered identical to sql.TxOptions.
+type TxOptions struct {
+ Isolation IsolationLevel
+ ReadOnly bool
+}
+
+// ConnBeginTx enhances the Conn interface with context and TxOptions.
+type ConnBeginTx interface {
+ // BeginTx starts and returns a new transaction.
+ // If the context is canceled by the user the sql package will
+ // call Tx.Rollback before discarding and closing the connection.
+ //
+ // This must check opts.Isolation to determine if there is a set
+ // isolation level. If the driver does not support a non-default
+ // level and one is set or if there is a non-default isolation level
+ // that is not supported, an error must be returned.
+ //
+ // This must also check opts.ReadOnly to determine if the read-only
+ // value is true to either set the read-only transaction property if supported
+ // or return an error if it is not supported.
+ BeginTx(ctx context.Context, opts TxOptions) (Tx, error)
+}
+
// Result is the result of a query execution.
type Result interface {
// LastInsertId returns the database's auto-generated ID
@@ -132,19 +233,41 @@ type Stmt interface {
// Exec executes a query that doesn't return rows, such
// as an INSERT or UPDATE.
+ //
+ // Deprecated: Drivers should implement StmtExecContext instead (or additionally).
Exec(args []Value) (Result, error)
// Query executes a query that may return rows, such as a
// SELECT.
+ //
+ // Deprecated: Drivers should implement StmtQueryContext instead (or additionally).
Query(args []Value) (Rows, error)
}
+// StmtExecContext enhances the Stmt interface by providing Exec with context.
+type StmtExecContext interface {
+ // ExecContext executes a query that doesn't return rows, such
+ // as an INSERT or UPDATE.
+ //
+ // ExecContext must honor the context timeout and return when it is canceled.
+ ExecContext(ctx context.Context, args []NamedValue) (Result, error)
+}
+
+// StmtQueryContext enhances the Stmt interface by providing Query with context.
+type StmtQueryContext interface {
+ // QueryContext executes a query that may return rows, such as a
+ // SELECT.
+ //
+ // QueryContext must honor the context timeout and return when it is canceled.
+ QueryContext(ctx context.Context, args []NamedValue) (Rows, error)
+}
+
// ColumnConverter may be optionally implemented by Stmt if the
// statement is aware of its own columns' types and can convert from
// any type to a driver Value.
type ColumnConverter interface {
// ColumnConverter returns a ValueConverter for the provided
- // column index. If the type of a specific column isn't known
+ // column index. If the type of a specific column isn't known
// or shouldn't be handled specially, DefaultValueConverter
// can be returned.
ColumnConverter(idx int) ValueConverter
@@ -154,7 +277,7 @@ type ColumnConverter interface {
type Rows interface {
// Columns returns the names of the columns. The number of
// columns of the result is inferred from the length of the
- // slice. If a particular column name isn't known, an empty
+ // slice. If a particular column name isn't known, an empty
// string should be returned for that entry.
Columns() []string
@@ -165,14 +288,80 @@ type Rows interface {
// the provided slice. The provided slice will be the same
// size as the Columns() are wide.
//
- // The dest slice may be populated only with
- // a driver Value type, but excluding string.
- // All string values must be converted to []byte.
- //
// Next should return io.EOF when there are no more rows.
Next(dest []Value) error
}
+// RowsNextResultSet extends the Rows interface by providing a way to signal
+// the driver to advance to the next result set.
+type RowsNextResultSet interface {
+ Rows
+
+ // HasNextResultSet is called at the end of the current result set and
+ // reports whether there is another result set after the current one.
+ HasNextResultSet() bool
+
+ // NextResultSet advances the driver to the next result set even
+ // if there are remaining rows in the current result set.
+ //
+ // NextResultSet should return io.EOF when there are no more result sets.
+ NextResultSet() error
+}
+
+// RowsColumnTypeScanType may be implemented by Rows. It should return
+// the value type that can be used to scan types into. For example, the database
+// column type "bigint" this should return "reflect.TypeOf(int64(0))".
+type RowsColumnTypeScanType interface {
+ Rows
+ ColumnTypeScanType(index int) reflect.Type
+}
+
+// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
+// database system type name without the length. Type names should be uppercase.
+// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
+// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
+// "TIMESTAMP".
+type RowsColumnTypeDatabaseTypeName interface {
+ Rows
+ ColumnTypeDatabaseTypeName(index int) string
+}
+
+// RowsColumnTypeLength may be implemented by Rows. It should return the length
+// of the column type if the column is a variable length type. If the column is
+// not a variable length type ok should return false.
+// If length is not limited other than system limits, it should return math.MaxInt64.
+// The following are examples of returned values for various types:
+// TEXT (math.MaxInt64, true)
+// varchar(10) (10, true)
+// nvarchar(10) (10, true)
+// decimal (0, false)
+// int (0, false)
+// bytea(30) (30, true)
+type RowsColumnTypeLength interface {
+ Rows
+ ColumnTypeLength(index int) (length int64, ok bool)
+}
+
+// RowsColumnTypeNullable may be implemented by Rows. The nullable value should
+// be true if it is known the column may be null, or false if the column is known
+// to be not nullable.
+// If the column nullability is unknown, ok should be false.
+type RowsColumnTypeNullable interface {
+ Rows
+ ColumnTypeNullable(index int) (nullable, ok bool)
+}
+
+// RowsColumnTypePrecisionScale may be implemented by Rows. It should return
+// the precision and scale for decimal types. If not applicable, ok should be false.
+// The following are examples of returned values for various types:
+// decimal(38, 4) (38, 4, true)
+// int (0, 0, false)
+// decimal (math.MaxInt64, math.MaxInt64, true)
+type RowsColumnTypePrecisionScale interface {
+ Rows
+ ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool)
+}
+
// Tx is a transaction.
type Tx interface {
Commit() error
diff --git a/libgo/go/database/sql/driver/types.go b/libgo/go/database/sql/driver/types.go
index bc54784989..8b3cb6c8f6 100644
--- a/libgo/go/database/sql/driver/types.go
+++ b/libgo/go/database/sql/driver/types.go
@@ -15,7 +15,7 @@ import (
//
// Various implementations of ValueConverter are provided by the
// driver package to provide consistent implementations of conversions
-// between drivers. The ValueConverters have several uses:
+// between drivers. The ValueConverters have several uses:
//
// * converting from the Value types as provided by the sql package
// into a database table's specific column type and making sure it
@@ -172,28 +172,21 @@ func (n NotNull) ConvertValue(v interface{}) (Value, error) {
}
// IsValue reports whether v is a valid Value parameter type.
-// Unlike IsScanValue, IsValue permits the string type.
func IsValue(v interface{}) bool {
- if IsScanValue(v) {
+ if v == nil {
return true
}
- if _, ok := v.(string); ok {
+ switch v.(type) {
+ case []byte, bool, float64, int64, string, time.Time:
return true
}
return false
}
-// IsScanValue reports whether v is a valid Value scan type.
-// Unlike IsValue, IsScanValue does not permit the string type.
+// IsScanValue is equivalent to IsValue.
+// It exists for compatibility.
func IsScanValue(v interface{}) bool {
- if v == nil {
- return true
- }
- switch v.(type) {
- case int64, float64, []byte, bool, time.Time:
- return true
- }
- return false
+ return IsValue(v)
}
// DefaultParameterConverter is the default implementation of
@@ -205,9 +198,9 @@ func IsScanValue(v interface{}) bool {
// Value method is used to return a Value. As a fallback, the provided
// argument's underlying type is used to convert it to a Value:
// underlying integer types are converted to int64, floats to float64,
-// and strings to []byte. If the argument is a nil pointer,
-// ConvertValue returns a nil Value. If the argument is a non-nil
-// pointer, it is dereferenced and ConvertValue is called
+// bool, string, and []byte to themselves. If the argument is a nil
+// pointer, ConvertValue returns a nil Value. If the argument is a
+// non-nil pointer, it is dereferenced and ConvertValue is called
// recursively. Other types are an error.
var DefaultParameterConverter defaultConverter
@@ -215,13 +208,35 @@ type defaultConverter struct{}
var _ ValueConverter = defaultConverter{}
+var valuerReflectType = reflect.TypeOf((*Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+// Issue 8415.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This function is mirrored in the database/sql package.
+func callValuerValue(vr Valuer) (v Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
+
func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
if IsValue(v) {
return v, nil
}
- if svi, ok := v.(Valuer); ok {
- sv, err := svi.Value()
+ if vr, ok := v.(Valuer); ok {
+ sv, err := callValuerValue(vr)
if err != nil {
return nil, err
}
@@ -252,6 +267,16 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
return int64(u64), nil
case reflect.Float32, reflect.Float64:
return rv.Float(), nil
+ case reflect.Bool:
+ return rv.Bool(), nil
+ case reflect.Slice:
+ ek := rv.Type().Elem().Kind()
+ if ek == reflect.Uint8 {
+ return rv.Bytes(), nil
+ }
+ return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
+ case reflect.String:
+ return rv.String(), nil
}
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
}
diff --git a/libgo/go/database/sql/driver/types_test.go b/libgo/go/database/sql/driver/types_test.go
index 1ce0ff0654..0379bf8892 100644
--- a/libgo/go/database/sql/driver/types_test.go
+++ b/libgo/go/database/sql/driver/types_test.go
@@ -20,6 +20,16 @@ type valueConverterTest struct {
var now = time.Now()
var answer int64 = 42
+type (
+ i int64
+ f float64
+ b bool
+ bs []byte
+ s string
+ t time.Time
+ is []int
+)
+
var valueConverterTests = []valueConverterTest{
{Bool, "true", true, ""},
{Bool, "True", true, ""},
@@ -41,6 +51,12 @@ var valueConverterTests = []valueConverterTest{
{DefaultParameterConverter, (*int64)(nil), nil, ""},
{DefaultParameterConverter, &answer, answer, ""},
{DefaultParameterConverter, &now, now, ""},
+ {DefaultParameterConverter, i(9), int64(9), ""},
+ {DefaultParameterConverter, f(0.1), float64(0.1), ""},
+ {DefaultParameterConverter, b(true), true, ""},
+ {DefaultParameterConverter, bs{1}, []byte{1}, ""},
+ {DefaultParameterConverter, s("a"), "a", ""},
+ {DefaultParameterConverter, is{1}, nil, "unsupported type driver.is, a slice of int"},
}
func TestValueConverters(t *testing.T) {
diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go
index b5ff121358..4b15f5bec7 100644
--- a/libgo/go/database/sql/fakedb_test.go
+++ b/libgo/go/database/sql/fakedb_test.go
@@ -5,11 +5,13 @@
package sql
import (
+ "context"
"database/sql/driver"
"errors"
"fmt"
"io"
"log"
+ "reflect"
"sort"
"strconv"
"strings"
@@ -32,12 +34,18 @@ var _ = log.Printf
// where types are: "string", [u]int{8,16,32,64}, "bool"
// INSERT|<tablename>|col=val,col2=val2,col3=?
// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
+// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?param1,filtercol2=?param2
//
// Any of these can be preceded by PANIC|<method>|, to cause the
// named method on fakeStmt to panic.
//
+// Any of these can be proceeded by WAIT|<duration>|, to cause the
+// named method on fakeStmt to sleep for the specified duration.
+//
+// Multiple of these can be combined when separated with a semicolon.
+//
// When opening a fakeDriver's database, it starts empty with no
-// tables. All tables and data are stored in memory only.
+// tables. All tables and data are stored in memory only.
type fakeDriver struct {
mu sync.Mutex // guards 3 following fields
openCount int // conn opens
@@ -51,7 +59,6 @@ type fakeDB struct {
name string
mu sync.Mutex
- free []*fakeConn
tables map[string]*table
badConn bool
}
@@ -76,12 +83,6 @@ type row struct {
cols []interface{} // must be same size as its table colname + coltype
}
-func (r *row) clone() *row {
- nrow := &row{cols: make([]interface{}, len(r.cols))}
- copy(nrow.cols, r.cols)
- return nrow
-}
-
type fakeConn struct {
db *fakeDB // where to return ourselves to
@@ -108,6 +109,12 @@ type fakeTx struct {
c *fakeConn
}
+type boundCol struct {
+ Column string
+ Placeholder string
+ Ordinal int
+}
+
type fakeStmt struct {
c *fakeConn
q string // just for debugging
@@ -115,6 +122,9 @@ type fakeStmt struct {
cmd string
table string
panic string
+ wait time.Duration
+
+ next *fakeStmt // used for returning multiple results.
closed bool
@@ -123,7 +133,7 @@ type fakeStmt struct {
colValue []interface{} // used by INSERT (mix of strings and "?" for bound params)
placeholders int // used by INSERT/SELECT: number of ? params
- whereCol []string // used by SELECT (all placeholders)
+ whereCol []boundCol // used by SELECT (all placeholders)
placeholderConverter []driver.ValueConverter // used by INSERT
}
@@ -342,18 +352,23 @@ func (c *fakeConn) Close() (err error) {
return nil
}
-func checkSubsetTypes(args []driver.Value) error {
- for n, arg := range args {
- switch arg.(type) {
+func checkSubsetTypes(args []driver.NamedValue) error {
+ for _, arg := range args {
+ switch arg.Value.(type) {
case int64, float64, bool, nil, []byte, string, time.Time:
default:
- return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
+ return fmt.Errorf("fakedb_test: invalid argument ordinal %[1]d: %[2]v, type %[2]T", arg.Ordinal, arg.Value)
}
}
return nil
}
func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ // Ensure that ExecContext is called if available.
+ panic("ExecContext was not called.")
+}
+
+func (c *fakeConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args are of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
@@ -366,6 +381,11 @@ func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error
}
func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ // Ensure that ExecContext is called if available.
+ panic("QueryContext was not called.")
+}
+
+func (c *fakeConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args are of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
@@ -384,12 +404,13 @@ func errf(msg string, args ...interface{}) error {
// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=?
// (note that where columns must always contain ? marks,
// just a limitation for fakedb)
-func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 3 {
stmt.Close()
return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
}
stmt.table = parts[0]
+
stmt.colName = strings.Split(parts[1], ",")
for n, colspec := range strings.Split(parts[2], ",") {
if colspec == "" {
@@ -406,19 +427,19 @@ func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, e
stmt.Close()
return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
}
- if value != "?" {
+ if !strings.HasPrefix(value, "?") {
stmt.Close()
return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
stmt.table, column)
}
- stmt.whereCol = append(stmt.whereCol, column)
stmt.placeholders++
+ stmt.whereCol = append(stmt.whereCol, boundCol{Column: column, Placeholder: value, Ordinal: stmt.placeholders})
}
return stmt, nil
}
// parts are table|col=type,col2=type2
-func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 2 {
stmt.Close()
return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
@@ -437,7 +458,7 @@ func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
// parts are table|col=?,col2=val
-func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 2 {
stmt.Close()
return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
@@ -457,7 +478,7 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
stmt.colName = append(stmt.colName, column)
- if value != "?" {
+ if !strings.HasPrefix(value, "?") {
var subsetVal interface{}
// Convert to driver subset type
switch ctype {
@@ -480,7 +501,7 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
} else {
stmt.placeholders++
stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype))
- stmt.colValue = append(stmt.colValue, "?")
+ stmt.colValue = append(stmt.colValue, value)
}
}
return stmt, nil
@@ -490,6 +511,10 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
var hookPrepareBadConn func() bool
func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
+ panic("use PrepareContext")
+}
+
+func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
c.numPrepare++
if c.db == nil {
panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
@@ -499,38 +524,72 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
return nil, driver.ErrBadConn
}
- parts := strings.Split(query, "|")
- if len(parts) < 1 {
- return nil, errf("empty query")
- }
- stmt := &fakeStmt{q: query, c: c}
- if len(parts) >= 3 && parts[0] == "PANIC" {
- stmt.panic = parts[1]
- parts = parts[2:]
- }
- cmd := parts[0]
- stmt.cmd = cmd
- parts = parts[1:]
+ var firstStmt, prev *fakeStmt
+ for _, query := range strings.Split(query, ";") {
+ parts := strings.Split(query, "|")
+ if len(parts) < 1 {
+ return nil, errf("empty query")
+ }
+ stmt := &fakeStmt{q: query, c: c}
+ if firstStmt == nil {
+ firstStmt = stmt
+ }
+ if len(parts) >= 3 {
+ switch parts[0] {
+ case "PANIC":
+ stmt.panic = parts[1]
+ parts = parts[2:]
+ case "WAIT":
+ wait, err := time.ParseDuration(parts[1])
+ if err != nil {
+ return nil, errf("expected section after WAIT to be a duration, got %q %v", parts[1], err)
+ }
+ parts = parts[2:]
+ stmt.wait = wait
+ }
+ }
+ cmd := parts[0]
+ stmt.cmd = cmd
+ parts = parts[1:]
+
+ if stmt.wait > 0 {
+ wait := time.NewTimer(stmt.wait)
+ select {
+ case <-wait.C:
+ case <-ctx.Done():
+ wait.Stop()
+ return nil, ctx.Err()
+ }
+ }
- c.incrStat(&c.stmtsMade)
- switch cmd {
- case "WIPE":
- // Nothing
- case "SELECT":
- return c.prepareSelect(stmt, parts)
- case "CREATE":
- return c.prepareCreate(stmt, parts)
- case "INSERT":
- return c.prepareInsert(stmt, parts)
- case "NOSERT":
- // Do all the prep-work like for an INSERT but don't actually insert the row.
- // Used for some of the concurrent tests.
- return c.prepareInsert(stmt, parts)
- default:
- stmt.Close()
- return nil, errf("unsupported command type %q", cmd)
+ c.incrStat(&c.stmtsMade)
+ var err error
+ switch cmd {
+ case "WIPE":
+ // Nothing
+ case "SELECT":
+ stmt, err = c.prepareSelect(stmt, parts)
+ case "CREATE":
+ stmt, err = c.prepareCreate(stmt, parts)
+ case "INSERT":
+ stmt, err = c.prepareInsert(stmt, parts)
+ case "NOSERT":
+ // Do all the prep-work like for an INSERT but don't actually insert the row.
+ // Used for some of the concurrent tests.
+ stmt, err = c.prepareInsert(stmt, parts)
+ default:
+ stmt.Close()
+ return nil, errf("unsupported command type %q", cmd)
+ }
+ if err != nil {
+ return nil, err
+ }
+ if prev != nil {
+ prev.next = stmt
+ }
+ prev = stmt
}
- return stmt, nil
+ return firstStmt, nil
}
func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
@@ -557,6 +616,9 @@ func (s *fakeStmt) Close() error {
s.c.incrStat(&s.c.stmtsClosed)
s.closed = true
}
+ if s.next != nil {
+ s.next.Close()
+ }
return nil
}
@@ -566,6 +628,9 @@ var errClosed = errors.New("fakedb: statement has been closed")
var hookExecBadConn func() bool
func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
+ panic("Using ExecContext")
+}
+func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
if s.panic == "Exec" {
panic(s.panic)
}
@@ -582,6 +647,16 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
return nil, err
}
+ if s.wait > 0 {
+ time.Sleep(s.wait)
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+
db := s.c.db
switch s.cmd {
case "WIPE":
@@ -606,7 +681,7 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
// When doInsert is true, add the row to the table.
// When doInsert is false do prep-work and error checking, but don't
// actually add the row to the table.
-func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result, error) {
+func (s *fakeStmt) execInsert(args []driver.NamedValue, doInsert bool) (driver.Result, error) {
db := s.c.db
if len(args) != s.placeholders {
panic("error in pkg db; should only get here if size is correct")
@@ -632,8 +707,18 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname)
}
var val interface{}
- if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" {
- val = args[argPos]
+ if strvalue, ok := s.colValue[n].(string); ok && strings.HasPrefix(strvalue, "?") {
+ if strvalue == "?" {
+ val = args[argPos].Value
+ } else {
+ // Assign value from argument placeholder name.
+ for _, a := range args {
+ if a.Name == strvalue[1:] {
+ val = a.Value
+ break
+ }
+ }
+ }
argPos++
} else {
val = s.colValue[n]
@@ -653,6 +738,10 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
var hookQueryBadConn func() bool
func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
+ panic("Use QueryContext")
+}
+
+func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
if s.panic == "Query" {
panic(s.panic)
}
@@ -674,65 +763,101 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
panic("error in pkg db; should only get here if size is correct")
}
- db.mu.Lock()
- t, ok := db.table(s.table)
- db.mu.Unlock()
- if !ok {
- return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
- }
+ setMRows := make([][]*row, 0, 1)
+ setColumns := make([][]string, 0, 1)
+ setColType := make([][]string, 0, 1)
- if s.table == "magicquery" {
- if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1] == "millis" {
- if args[0] == "sleep" {
- time.Sleep(time.Duration(args[1].(int64)) * time.Millisecond)
- }
+ for {
+ db.mu.Lock()
+ t, ok := db.table(s.table)
+ db.mu.Unlock()
+ if !ok {
+ return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
}
- }
-
- t.mu.Lock()
- defer t.mu.Unlock()
- colIdx := make(map[string]int) // select column name -> column index in table
- for _, name := range s.colName {
- idx := t.columnIndex(name)
- if idx == -1 {
- return nil, fmt.Errorf("fakedb: unknown column name %q", name)
+ if s.table == "magicquery" {
+ if len(s.whereCol) == 2 && s.whereCol[0].Column == "op" && s.whereCol[1].Column == "millis" {
+ if args[0].Value == "sleep" {
+ time.Sleep(time.Duration(args[1].Value.(int64)) * time.Millisecond)
+ }
+ }
}
- colIdx[name] = idx
- }
- mrows := []*row{}
-rows:
- for _, trow := range t.rows {
- // Process the where clause, skipping non-match rows. This is lazy
- // and just uses fmt.Sprintf("%v") to test equality. Good enough
- // for test code.
- for widx, wcol := range s.whereCol {
- idx := t.columnIndex(wcol)
+ t.mu.Lock()
+
+ colIdx := make(map[string]int) // select column name -> column index in table
+ for _, name := range s.colName {
+ idx := t.columnIndex(name)
if idx == -1 {
- return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
+ t.mu.Unlock()
+ return nil, fmt.Errorf("fakedb: unknown column name %q", name)
}
- tcol := trow.cols[idx]
- if bs, ok := tcol.([]byte); ok {
- // lazy hack to avoid sprintf %v on a []byte
- tcol = string(bs)
+ colIdx[name] = idx
+ }
+
+ mrows := []*row{}
+ rows:
+ for _, trow := range t.rows {
+ // Process the where clause, skipping non-match rows. This is lazy
+ // and just uses fmt.Sprintf("%v") to test equality. Good enough
+ // for test code.
+ for _, wcol := range s.whereCol {
+ idx := t.columnIndex(wcol.Column)
+ if idx == -1 {
+ t.mu.Unlock()
+ return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
+ }
+ tcol := trow.cols[idx]
+ if bs, ok := tcol.([]byte); ok {
+ // lazy hack to avoid sprintf %v on a []byte
+ tcol = string(bs)
+ }
+ var argValue interface{}
+ if wcol.Placeholder == "?" {
+ argValue = args[wcol.Ordinal-1].Value
+ } else {
+ // Assign arg value from placeholder name.
+ for _, a := range args {
+ if a.Name == wcol.Placeholder[1:] {
+ argValue = a.Value
+ break
+ }
+ }
+ }
+ if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", argValue) {
+ continue rows
+ }
}
- if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) {
- continue rows
+ mrow := &row{cols: make([]interface{}, len(s.colName))}
+ for seli, name := range s.colName {
+ mrow.cols[seli] = trow.cols[colIdx[name]]
}
+ mrows = append(mrows, mrow)
}
- mrow := &row{cols: make([]interface{}, len(s.colName))}
- for seli, name := range s.colName {
- mrow.cols[seli] = trow.cols[colIdx[name]]
+
+ var colType []string
+ for _, column := range s.colName {
+ colType = append(colType, t.coltype[t.columnIndex(column)])
+ }
+
+ t.mu.Unlock()
+
+ setMRows = append(setMRows, mrows)
+ setColumns = append(setColumns, s.colName)
+ setColType = append(setColType, colType)
+
+ if s.next == nil {
+ break
}
- mrows = append(mrows, mrow)
+ s = s.next
}
cursor := &rowsCursor{
- pos: -1,
- rows: mrows,
- cols: s.colName,
- errPos: -1,
+ posRow: -1,
+ rows: setMRows,
+ cols: setColumns,
+ colType: setColType,
+ errPos: -1,
}
return cursor, nil
}
@@ -767,10 +892,12 @@ func (tx *fakeTx) Rollback() error {
}
type rowsCursor struct {
- cols []string
- pos int
- rows []*row
- closed bool
+ cols [][]string
+ colType [][]string
+ posSet int
+ posRow int
+ rows [][]*row
+ closed bool
// errPos and err are for making Next return early with error.
errPos int
@@ -793,7 +920,11 @@ func (rc *rowsCursor) Close() error {
}
func (rc *rowsCursor) Columns() []string {
- return rc.cols
+ return rc.cols[rc.posSet]
+}
+
+func (rc *rowsCursor) ColumnTypeScanType(index int) reflect.Type {
+ return colTypeToReflectType(rc.colType[rc.posSet][index])
}
var rowsCursorNextHook func(dest []driver.Value) error
@@ -806,14 +937,14 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
if rc.closed {
return errors.New("fakedb: cursor is closed")
}
- rc.pos++
- if rc.pos == rc.errPos {
+ rc.posRow++
+ if rc.posRow == rc.errPos {
return rc.err
}
- if rc.pos >= len(rc.rows) {
+ if rc.posRow >= len(rc.rows[rc.posSet]) {
return io.EOF // per interface spec
}
- for i, v := range rc.rows[rc.pos].cols {
+ for i, v := range rc.rows[rc.posSet][rc.posRow].cols {
// TODO(bradfitz): convert to subset types? naah, I
// think the subset types should only be input to
// driver, but the sql package should be able to handle
@@ -838,6 +969,19 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
return nil
}
+func (rc *rowsCursor) HasNextResultSet() bool {
+ return rc.posSet < len(rc.rows)-1
+}
+
+func (rc *rowsCursor) NextResultSet() error {
+ if rc.HasNextResultSet() {
+ rc.posSet++
+ rc.posRow = -1
+ return nil
+ }
+ return io.EOF // Per interface spec.
+}
+
// fakeDriverString is like driver.String, but indirects pointers like
// DefaultValueConverter.
//
@@ -889,3 +1033,29 @@ func converterForType(typ string) driver.ValueConverter {
}
panic("invalid fakedb column type of " + typ)
}
+
+func colTypeToReflectType(typ string) reflect.Type {
+ switch typ {
+ case "bool":
+ return reflect.TypeOf(false)
+ case "nullbool":
+ return reflect.TypeOf(NullBool{})
+ case "int32":
+ return reflect.TypeOf(int32(0))
+ case "string":
+ return reflect.TypeOf("")
+ case "nullstring":
+ return reflect.TypeOf(NullString{})
+ case "int64":
+ return reflect.TypeOf(int64(0))
+ case "nullint64":
+ return reflect.TypeOf(NullInt64{})
+ case "float64":
+ return reflect.TypeOf(float64(0))
+ case "nullfloat64":
+ return reflect.TypeOf(NullFloat64{})
+ case "datetime":
+ return reflect.TypeOf(time.Time{})
+ }
+ panic("invalid fakedb column type of " + typ)
+}
diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go
index d8e7cb77af..c016681fca 100644
--- a/libgo/go/database/sql/sql.go
+++ b/libgo/go/database/sql/sql.go
@@ -8,15 +8,20 @@
// The sql package must be used in conjunction with a database driver.
// See https://golang.org/s/sqldrivers for a list of drivers.
//
-// For more usage examples, see the wiki page at
+// Drivers that do not support context cancelation will not return until
+// after the query is completed.
+//
+// For usage examples, see the wiki page at
// https://golang.org/s/sqlwiki.
package sql
import (
+ "context"
"database/sql/driver"
"errors"
"fmt"
"io"
+ "reflect"
"runtime"
"sort"
"sync"
@@ -66,6 +71,75 @@ func Drivers() []string {
return list
}
+// A NamedArg is a named argument. NamedArg values may be used as
+// arguments to Query or Exec and bind to the corresponding named
+// parameter in the SQL statement.
+//
+// For a more concise way to create NamedArg values, see
+// the Named function.
+type NamedArg struct {
+ _Named_Fields_Required struct{}
+
+ // Name is the name of the parameter placeholder.
+ //
+ // If empty, the ordinal position in the argument list will be
+ // used.
+ //
+ // Name must omit any symbol prefix.
+ Name string
+
+ // Value is the value of the parameter.
+ // It may be assigned the same value types as the query
+ // arguments.
+ Value interface{}
+}
+
+// Named provides a more concise way to create NamedArg values.
+//
+// Example usage:
+//
+// db.ExecContext(ctx, `
+// delete from Invoice
+// where
+// TimeCreated < @end
+// and TimeCreated >= @start;`,
+// sql.Named("start", startTime),
+// sql.Named("end", endTime),
+// )
+func Named(name string, value interface{}) NamedArg {
+ // This method exists because the go1compat promise
+ // doesn't guarantee that structs don't grow more fields,
+ // so unkeyed struct literals are a vet error. Thus, we don't
+ // want to allow sql.NamedArg{name, value}.
+ return NamedArg{Name: name, Value: value}
+}
+
+// IsolationLevel is the transaction isolation level used in TxOptions.
+type IsolationLevel int
+
+// Various isolation levels that drivers may support in BeginTx.
+// If a driver does not support a given isolation level an error may be returned.
+//
+// See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
+const (
+ LevelDefault IsolationLevel = iota
+ LevelReadUncommitted
+ LevelReadCommitted
+ LevelWriteCommitted
+ LevelRepeatableRead
+ LevelSnapshot
+ LevelSerializable
+ LevelLinearizable
+)
+
+// TxOptions holds the transaction options to be used in DB.BeginTx.
+type TxOptions struct {
+ // Isolation is the transaction isolation level.
+ // If zero, the driver or database's default level is used.
+ Isolation IsolationLevel
+ ReadOnly bool
+}
+
// RawBytes is a byte slice that holds a reference to memory owned by
// the database itself. After a Scan into a RawBytes, the slice is only
// valid until the next call to Next, Scan, or Close.
@@ -199,7 +273,7 @@ type Scanner interface {
// time.Time
// nil - for NULL values
//
- // An error should be returned if the value can not be stored
+ // An error should be returned if the value cannot be stored
// without loss of information.
Scan(src interface{}) error
}
@@ -231,8 +305,9 @@ type DB struct {
mu sync.Mutex // protects following fields
freeConn []*driverConn
- connRequests []chan connRequest
- numOpen int // number of opened and pending open connections
+ connRequests map[uint64]chan connRequest
+ nextRequest uint64 // Next key to use in connRequests.
+ numOpen int // number of opened and pending open connections
// Used to signal the need for new connections
// a goroutine running connectionOpener() reads on this chan and
// maybeOpenNewConnections sends on the chan (one send per needed connection)
@@ -272,7 +347,7 @@ type driverConn struct {
ci driver.Conn
closed bool
finalClosed bool // ci.Close has been called
- openStmt map[driver.Stmt]bool
+ openStmt map[*driverStmt]bool
// guarded by db.mu
inUse bool
@@ -284,10 +359,10 @@ func (dc *driverConn) releaseConn(err error) {
dc.db.putConn(dc, err)
}
-func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
+func (dc *driverConn) removeOpenStmt(ds *driverStmt) {
dc.Lock()
defer dc.Unlock()
- delete(dc.openStmt, si)
+ delete(dc.openStmt, ds)
}
func (dc *driverConn) expired(timeout time.Duration) bool {
@@ -297,28 +372,23 @@ func (dc *driverConn) expired(timeout time.Duration) bool {
return dc.createdAt.Add(timeout).Before(nowFunc())
}
-func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
- si, err := dc.ci.Prepare(query)
- if err == nil {
- // Track each driverConn's open statements, so we can close them
- // before closing the conn.
- //
- // TODO(bradfitz): let drivers opt out of caring about
- // stmt closes if the conn is about to close anyway? For now
- // do the safe thing, in case stmts need to be closed.
- //
- // TODO(bradfitz): after Go 1.2, closing driver.Stmts
- // should be moved to driverStmt, using unique
- // *driverStmts everywhere (including from
- // *Stmt.connStmt, instead of returning a
- // driver.Stmt), using driverStmt as a pointer
- // everywhere, and making it a finalCloser.
- if dc.openStmt == nil {
- dc.openStmt = make(map[driver.Stmt]bool)
- }
- dc.openStmt[si] = true
+func (dc *driverConn) prepareLocked(ctx context.Context, query string) (*driverStmt, error) {
+ si, err := ctxDriverPrepare(ctx, dc.ci, query)
+ if err != nil {
+ return nil, err
}
- return si, err
+
+ // Track each driverConn's open statements, so we can close them
+ // before closing the conn.
+ //
+ // Wrap all driver.Stmt is *driverStmt to ensure they are only closed once.
+ if dc.openStmt == nil {
+ dc.openStmt = make(map[*driverStmt]bool)
+ }
+ ds := &driverStmt{Locker: dc, si: si}
+ dc.openStmt[ds] = true
+
+ return ds, nil
}
// the dc.db's Mutex is held.
@@ -350,17 +420,26 @@ func (dc *driverConn) Close() error {
}
func (dc *driverConn) finalClose() error {
- dc.Lock()
+ var err error
- for si := range dc.openStmt {
- si.Close()
+ // Each *driverStmt has a lock to the dc. Copy the list out of the dc
+ // before calling close on each stmt.
+ var openStmt []*driverStmt
+ withLock(dc, func() {
+ openStmt = make([]*driverStmt, 0, len(dc.openStmt))
+ for ds := range dc.openStmt {
+ openStmt = append(openStmt, ds)
+ }
+ dc.openStmt = nil
+ })
+ for _, ds := range openStmt {
+ ds.Close()
}
- dc.openStmt = nil
-
- err := dc.ci.Close()
- dc.ci = nil
- dc.finalClosed = true
- dc.Unlock()
+ withLock(dc, func() {
+ dc.finalClosed = true
+ err = dc.ci.Close()
+ dc.ci = nil
+ })
dc.db.mu.Lock()
dc.db.numOpen--
@@ -377,12 +456,21 @@ func (dc *driverConn) finalClose() error {
type driverStmt struct {
sync.Locker // the *driverConn
si driver.Stmt
+ closed bool
+ closeErr error // return value of previous Close call
}
+// Close ensures dirver.Stmt is only closed once any always returns the same
+// result.
func (ds *driverStmt) Close() error {
ds.Lock()
defer ds.Unlock()
- return ds.si.Close()
+ if ds.closed {
+ return ds.closeErr
+ }
+ ds.closed = true
+ ds.closeErr = ds.si.Close()
+ return ds.closeErr
}
// depSet is a finalCloser's outstanding dependencies
@@ -485,27 +573,46 @@ func Open(driverName, dataSourceName string) (*DB, error) {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
db := &DB{
- driver: driveri,
- dsn: dataSourceName,
- openerCh: make(chan struct{}, connectionRequestQueueSize),
- lastPut: make(map[*driverConn]string),
+ driver: driveri,
+ dsn: dataSourceName,
+ openerCh: make(chan struct{}, connectionRequestQueueSize),
+ lastPut: make(map[*driverConn]string),
+ connRequests: make(map[uint64]chan connRequest),
}
go db.connectionOpener()
return db, nil
}
-// Ping verifies a connection to the database is still alive,
+// PingContext verifies a connection to the database is still alive,
// establishing a connection if necessary.
-func (db *DB) Ping() error {
- // TODO(bradfitz): give drivers an optional hook to implement
- // this in a more efficient or more reliable way, if they
- // have one.
- dc, err := db.conn(cachedOrNewConn)
+func (db *DB) PingContext(ctx context.Context) error {
+ var dc *driverConn
+ var err error
+
+ for i := 0; i < maxBadConnRetries; i++ {
+ dc, err = db.conn(ctx, cachedOrNewConn)
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ if err == driver.ErrBadConn {
+ dc, err = db.conn(ctx, alwaysNewConn)
+ }
if err != nil {
return err
}
- db.putConn(dc, nil)
- return nil
+
+ if pinger, ok := dc.ci.(driver.Pinger); ok {
+ err = pinger.Ping(ctx)
+ }
+ db.putConn(dc, err)
+ return err
+}
+
+// Ping verifies a connection to the database is still alive,
+// establishing a connection if necessary.
+func (db *DB) Ping() error {
+ return db.PingContext(context.Background())
}
// Close closes the database, releasing any open resources.
@@ -718,6 +825,9 @@ func (db *DB) maybeOpenNewConnections() {
for numRequests > 0 {
db.numOpen++ // optimistically
numRequests--
+ if db.closed {
+ return
+ }
db.openerCh <- struct{}{}
}
}
@@ -773,13 +883,28 @@ type connRequest struct {
var errDBClosed = errors.New("sql: database is closed")
+// nextRequestKeyLocked returns the next connection request key.
+// It is assumed that nextRequest will not overflow.
+func (db *DB) nextRequestKeyLocked() uint64 {
+ next := db.nextRequest
+ db.nextRequest++
+ return next
+}
+
// conn returns a newly-opened or cached *driverConn.
-func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
+func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
db.mu.Lock()
if db.closed {
db.mu.Unlock()
return nil, errDBClosed
}
+ // Check if the context is expired.
+ select {
+ default:
+ case <-ctx.Done():
+ db.mu.Unlock()
+ return nil, ctx.Err()
+ }
lifetime := db.maxLifetime
// Prefer a free connection, if possible.
@@ -797,23 +922,42 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
return conn, nil
}
- // Out of free connections or we were asked not to use one. If we're not
+ // Out of free connections or we were asked not to use one. If we're not
// allowed to open any more connections, make a request and wait.
if db.maxOpen > 0 && db.numOpen >= db.maxOpen {
// Make the connRequest channel. It's buffered so that the
// connectionOpener doesn't block while waiting for the req to be read.
req := make(chan connRequest, 1)
- db.connRequests = append(db.connRequests, req)
+ reqKey := db.nextRequestKeyLocked()
+ db.connRequests[reqKey] = req
db.mu.Unlock()
- ret, ok := <-req
- if !ok {
- return nil, errDBClosed
- }
- if ret.err == nil && ret.conn.expired(lifetime) {
- ret.conn.Close()
- return nil, driver.ErrBadConn
+
+ // Timeout the connection request with the context.
+ select {
+ case <-ctx.Done():
+ // Remove the connection request and ensure no value has been sent
+ // on it after removing.
+ db.mu.Lock()
+ delete(db.connRequests, reqKey)
+ db.mu.Unlock()
+ select {
+ default:
+ case ret, ok := <-req:
+ if ok {
+ db.putConn(ret.conn, ret.err)
+ }
+ }
+ return nil, ctx.Err()
+ case ret, ok := <-req:
+ if !ok {
+ return nil, errDBClosed
+ }
+ if ret.err == nil && ret.conn.expired(lifetime) {
+ ret.conn.Close()
+ return nil, driver.ErrBadConn
+ }
+ return ret.conn, ret.err
}
- return ret.conn, ret.err
}
db.numOpen++ // optimistically
@@ -838,29 +982,25 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
return dc, nil
}
-var (
- errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
- errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy")
-)
-
// putConnHook is a hook for testing.
var putConnHook func(*DB, *driverConn)
-// noteUnusedDriverStatement notes that si is no longer used and should
+// noteUnusedDriverStatement notes that ds is no longer used and should
// be closed whenever possible (when c is next not in use), unless c is
// already closed.
-func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) {
+func (db *DB) noteUnusedDriverStatement(c *driverConn, ds *driverStmt) {
db.mu.Lock()
defer db.mu.Unlock()
if c.inUse {
c.onPut = append(c.onPut, func() {
- si.Close()
+ ds.Close()
})
} else {
c.Lock()
- defer c.Unlock()
- if !c.finalClosed {
- si.Close()
+ fc := c.finalClosed
+ c.Unlock()
+ if !fc {
+ ds.Close()
}
}
}
@@ -920,16 +1060,19 @@ func (db *DB) putConn(dc *driverConn, err error) {
// If a connRequest was fulfilled or the *driverConn was placed in the
// freeConn list, then true is returned, otherwise false is returned.
func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
+ if db.closed {
+ return false
+ }
if db.maxOpen > 0 && db.numOpen > db.maxOpen {
return false
}
if c := len(db.connRequests); c > 0 {
- req := db.connRequests[0]
- // This copy is O(n) but in practice faster than a linked list.
- // TODO: consider compacting it down less often and
- // moving the base instead?
- copy(db.connRequests, db.connRequests[1:])
- db.connRequests = db.connRequests[:c-1]
+ var req chan connRequest
+ var reqKey uint64
+ for reqKey, req = range db.connRequests {
+ break
+ }
+ delete(db.connRequests, reqKey) // Remove from pending requests.
if err == nil {
dc.inUse = true
}
@@ -951,40 +1094,53 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
// connection to be opened.
const maxBadConnRetries = 2
-// Prepare creates a prepared statement for later queries or executions.
+// PrepareContext creates a prepared statement for later queries or executions.
// Multiple queries or executions may be run concurrently from the
// returned statement.
// The caller must call the statement's Close method
// when the statement is no longer needed.
-func (db *DB) Prepare(query string) (*Stmt, error) {
+//
+// The provided context is used for the preparation of the statement, not for the
+// execution of the statement.
+func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
var stmt *Stmt
var err error
for i := 0; i < maxBadConnRetries; i++ {
- stmt, err = db.prepare(query, cachedOrNewConn)
+ stmt, err = db.prepare(ctx, query, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.prepare(query, alwaysNewConn)
+ return db.prepare(ctx, query, alwaysNewConn)
}
return stmt, err
}
-func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
+func (db *DB) Prepare(query string) (*Stmt, error) {
+ return db.PrepareContext(context.Background(), query)
+}
+
+func (db *DB) prepare(ctx context.Context, query string, strategy connReuseStrategy) (*Stmt, error) {
// TODO: check if db.driver supports an optional
// driver.Preparer interface and call that instead, if so,
// otherwise we make a prepared statement that's bound
// to a connection, and to execute this prepared statement
// we either need to use this connection (if it's free), else
// get a new connection + re-prepare + execute on that one.
- dc, err := db.conn(strategy)
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- dc.Lock()
- si, err := dc.prepareLocked(query)
- dc.Unlock()
+ var ds *driverStmt
+ withLock(dc, func() {
+ ds, err = dc.prepareLocked(ctx, query)
+ })
if err != nil {
db.putConn(dc, err)
return nil, err
@@ -992,7 +1148,7 @@ func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
stmt := &Stmt{
db: db,
query: query,
- css: []connStmt{{dc, si}},
+ css: []connStmt{{dc, ds}},
lastNumClosed: atomic.LoadUint64(&db.numClosed),
}
db.addDep(stmt, stmt)
@@ -1000,25 +1156,31 @@ func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
return stmt, nil
}
-// Exec executes a query without returning any rows.
+// ExecContext executes a query without returning any rows.
// The args are for any placeholder parameters in the query.
-func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
+func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
var res Result
var err error
for i := 0; i < maxBadConnRetries; i++ {
- res, err = db.exec(query, args, cachedOrNewConn)
+ res, err = db.exec(ctx, query, args, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.exec(query, args, alwaysNewConn)
+ return db.exec(ctx, query, args, alwaysNewConn)
}
return res, err
}
-func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
- dc, err := db.conn(strategy)
+// Exec executes a query without returning any rows.
+// The args are for any placeholder parameters in the query.
+func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
+ return db.ExecContext(context.Background(), query, args...)
+}
+
+func (db *DB) exec(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
@@ -1027,13 +1189,15 @@ func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy)
}()
if execer, ok := dc.ci.(driver.Execer); ok {
- dargs, err := driverArgs(nil, args)
+ var dargs []driver.NamedValue
+ dargs, err = driverArgs(nil, args)
if err != nil {
return nil, err
}
- dc.Lock()
- resi, err := execer.Exec(query, dargs)
- dc.Unlock()
+ var resi driver.Result
+ withLock(dc, func() {
+ resi, err = ctxDriverExec(ctx, execer, query, dargs)
+ })
if err != driver.ErrSkip {
if err != nil {
return nil, err
@@ -1042,54 +1206,63 @@ func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy)
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
- defer withLock(dc, func() { si.Close() })
- return resultFromStatement(driverStmt{dc, si}, args...)
+ ds := &driverStmt{Locker: dc, si: si}
+ defer ds.Close()
+ return resultFromStatement(ctx, ds, args...)
}
-// Query executes a query that returns rows, typically a SELECT.
+// QueryContext executes a query that returns rows, typically a SELECT.
// The args are for any placeholder parameters in the query.
-func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
var rows *Rows
var err error
for i := 0; i < maxBadConnRetries; i++ {
- rows, err = db.query(query, args, cachedOrNewConn)
+ rows, err = db.query(ctx, query, args, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.query(query, args, alwaysNewConn)
+ return db.query(ctx, query, args, alwaysNewConn)
}
return rows, err
}
-func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
- ci, err := db.conn(strategy)
+// Query executes a query that returns rows, typically a SELECT.
+// The args are for any placeholder parameters in the query.
+func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+ return db.QueryContext(context.Background(), query, args...)
+}
+
+func (db *DB) query(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
+ ci, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- return db.queryConn(ci, ci.releaseConn, query, args)
+ return db.queryConn(ctx, ci, ci.releaseConn, query, args)
}
// queryConn executes a query on the given connection.
// The connection gets released by the releaseConn function.
-func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
+func (db *DB) queryConn(ctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
if queryer, ok := dc.ci.(driver.Queryer); ok {
dargs, err := driverArgs(nil, args)
if err != nil {
releaseConn(err)
return nil, err
}
- dc.Lock()
- rowsi, err := queryer.Query(query, dargs)
- dc.Unlock()
+ var rowsi driver.Rows
+ withLock(dc, func() {
+ rowsi, err = ctxDriverQuery(ctx, queryer, query, dargs)
+ })
if err != driver.ErrSkip {
if err != nil {
releaseConn(err)
@@ -1102,24 +1275,25 @@ func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, a
releaseConn: releaseConn,
rowsi: rowsi,
}
+ rows.initContextClose(ctx)
return rows, nil
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ var err error
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
releaseConn(err)
return nil, err
}
- ds := driverStmt{dc, si}
- rowsi, err := rowsiFromStatement(ds, args...)
+ ds := &driverStmt{Locker: dc, si: si}
+ rowsi, err := rowsiFromStatement(ctx, ds, args...)
if err != nil {
- dc.Lock()
- si.Close()
- dc.Unlock()
+ ds.Close()
releaseConn(err)
return nil, err
}
@@ -1130,53 +1304,84 @@ func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, a
dc: dc,
releaseConn: releaseConn,
rowsi: rowsi,
- closeStmt: si,
+ closeStmt: ds,
}
+ rows.initContextClose(ctx)
return rows, nil
}
+// QueryRowContext executes a query that is expected to return at most one row.
+// QueryRowContext always returns a non-nil value. Errors are deferred until
+// Row's Scan method is called.
+func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := db.QueryContext(ctx, query, args...)
+ return &Row{rows: rows, err: err}
+}
+
// QueryRow executes a query that is expected to return at most one row.
// QueryRow always returns a non-nil value. Errors are deferred until
// Row's Scan method is called.
func (db *DB) QueryRow(query string, args ...interface{}) *Row {
- rows, err := db.Query(query, args...)
- return &Row{rows: rows, err: err}
+ return db.QueryRowContext(context.Background(), query, args...)
}
-// Begin starts a transaction. The isolation level is dependent on
-// the driver.
-func (db *DB) Begin() (*Tx, error) {
+// BeginTx starts a transaction.
+//
+// The provided context is used until the transaction is committed or rolled back.
+// If the context is canceled, the sql package will roll back
+// the transaction. Tx.Commit will return an error if the context provided to
+// BeginTx is canceled.
+//
+// The provided TxOptions is optional and may be nil if defaults should be used.
+// If a non-default isolation level is used that the driver doesn't support,
+// an error will be returned.
+func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
var tx *Tx
var err error
for i := 0; i < maxBadConnRetries; i++ {
- tx, err = db.begin(cachedOrNewConn)
+ tx, err = db.begin(ctx, opts, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.begin(alwaysNewConn)
+ return db.begin(ctx, opts, alwaysNewConn)
}
return tx, err
}
-func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) {
- dc, err := db.conn(strategy)
+// Begin starts a transaction. The default isolation level is dependent on
+// the driver.
+func (db *DB) Begin() (*Tx, error) {
+ return db.BeginTx(context.Background(), nil)
+}
+
+func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- dc.Lock()
- txi, err := dc.ci.Begin()
- dc.Unlock()
+ var txi driver.Tx
+ withLock(dc, func() {
+ txi, err = ctxDriverBegin(ctx, opts, dc.ci)
+ })
if err != nil {
db.putConn(dc, err)
return nil, err
}
- return &Tx{
- db: db,
- dc: dc,
- txi: txi,
- }, nil
+
+ // Schedule the transaction to rollback when the context is cancelled.
+ // The cancel function in Tx will be called after done is set to true.
+ ctx, cancel := context.WithCancel(ctx)
+ tx = &Tx{
+ db: db,
+ dc: dc,
+ txi: txi,
+ cancel: cancel,
+ ctx: ctx,
+ }
+ go tx.awaitDone()
+ return tx, nil
}
// Driver returns the database's underlying driver.
@@ -1197,60 +1402,112 @@ func (db *DB) Driver() driver.Driver {
type Tx struct {
db *DB
+ // closemu prevents the transaction from closing while there
+ // is an active query. It is held for read during queries
+ // and exclusively during close.
+ closemu sync.RWMutex
+
// dc is owned exclusively until Commit or Rollback, at which point
// it's returned with putConn.
dc *driverConn
txi driver.Tx
- // done transitions from false to true exactly once, on Commit
+ // done transitions from 0 to 1 exactly once, on Commit
// or Rollback. once done, all operations fail with
// ErrTxDone.
- done bool
+ // Use atomic operations on value when checking value.
+ done int32
- // All Stmts prepared for this transaction. These will be closed after the
+ // All Stmts prepared for this transaction. These will be closed after the
// transaction has been committed or rolled back.
stmts struct {
sync.Mutex
v []*Stmt
}
+
+ // cancel is called after done transitions from false to true.
+ cancel func()
+
+ // ctx lives for the life of the transaction.
+ ctx context.Context
+}
+
+// awaitDone blocks until the context in Tx is canceled and rolls back
+// the transaction if it's not already done.
+func (tx *Tx) awaitDone() {
+ // Wait for either the transaction to be committed or rolled
+ // back, or for the associated context to be closed.
+ <-tx.ctx.Done()
+
+ // Discard and close the connection used to ensure the
+ // transaction is closed and the resources are released. This
+ // rollback does nothing if the transaction has already been
+ // committed or rolled back.
+ tx.rollback(true)
+}
+
+func (tx *Tx) isDone() bool {
+ return atomic.LoadInt32(&tx.done) != 0
}
+// ErrTxDone is returned by any operation that is performed on a transaction
+// that has already been committed or rolled back.
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
+// close returns the connection to the pool and
+// must only be called by Tx.rollback or Tx.Commit.
func (tx *Tx) close(err error) {
- if tx.done {
- panic("double close") // internal error
- }
- tx.done = true
+ tx.closemu.Lock()
+ defer tx.closemu.Unlock()
+
tx.db.putConn(tx.dc, err)
+ tx.cancel()
tx.dc = nil
tx.txi = nil
}
-func (tx *Tx) grabConn() (*driverConn, error) {
- if tx.done {
+// hookTxGrabConn specifies an optional hook to be called on
+// a successful call to (*Tx).grabConn. For tests.
+var hookTxGrabConn func()
+
+func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ if tx.isDone() {
return nil, ErrTxDone
}
+ if hookTxGrabConn != nil { // test hook
+ hookTxGrabConn()
+ }
return tx.dc, nil
}
// Closes all Stmts prepared for this transaction.
func (tx *Tx) closePrepared() {
tx.stmts.Lock()
+ defer tx.stmts.Unlock()
for _, stmt := range tx.stmts.v {
stmt.Close()
}
- tx.stmts.Unlock()
}
// Commit commits the transaction.
func (tx *Tx) Commit() error {
- if tx.done {
+ if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
return ErrTxDone
}
- tx.dc.Lock()
- err := tx.txi.Commit()
- tx.dc.Unlock()
+ select {
+ default:
+ case <-tx.ctx.Done():
+ return tx.ctx.Err()
+ }
+ var err error
+ withLock(tx.dc, func() {
+ err = tx.txi.Commit()
+ })
if err != driver.ErrBadConn {
tx.closePrepared()
}
@@ -1258,49 +1515,67 @@ func (tx *Tx) Commit() error {
return err
}
-// Rollback aborts the transaction.
-func (tx *Tx) Rollback() error {
- if tx.done {
+// rollback aborts the transaction and optionally forces the pool to discard
+// the connection.
+func (tx *Tx) rollback(discardConn bool) error {
+ if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
return ErrTxDone
}
- tx.dc.Lock()
- err := tx.txi.Rollback()
- tx.dc.Unlock()
+ var err error
+ withLock(tx.dc, func() {
+ err = tx.txi.Rollback()
+ })
if err != driver.ErrBadConn {
tx.closePrepared()
}
+ if discardConn {
+ err = driver.ErrBadConn
+ }
tx.close(err)
return err
}
+// Rollback aborts the transaction.
+func (tx *Tx) Rollback() error {
+ return tx.rollback(false)
+}
+
// Prepare creates a prepared statement for use within a transaction.
//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
//
// To use an existing prepared statement on this transaction, see Tx.Stmt.
-func (tx *Tx) Prepare(query string) (*Stmt, error) {
+//
+// The provided context will be used for the preparation of the context, not
+// for the execution of the returned statement. The returned statement
+// will run in the transaction context.
+func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+ tx.closemu.RLock()
+ defer tx.closemu.RUnlock()
+
// TODO(bradfitz): We could be more efficient here and either
// provide a method to take an existing Stmt (created on
// perhaps a different Conn), and re-create it on this Conn if
// necessary. Or, better: keep a map in DB of query string to
// Stmts, and have Stmt.Execute do the right thing and
// re-prepare if the Conn in use doesn't have that prepared
- // statement. But we'll want to avoid caching the statement
+ // statement. But we'll want to avoid caching the statement
// in the case where we only call conn.Prepare implicitly
// (such as in db.Exec or tx.Exec), but the caller package
// can't be holding a reference to the returned statement.
// Perhaps just looking at the reference count (by noting
// Stmt.Close) would be enough. We might also want a finalizer
// on Stmt to drop the reference count.
- dc, err := tx.grabConn()
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
@@ -1308,7 +1583,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
stmt := &Stmt{
db: tx.db,
tx: tx,
- txsi: &driverStmt{
+ txds: &driverStmt{
Locker: dc,
si: si,
},
@@ -1320,7 +1595,17 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
return stmt, nil
}
-// Stmt returns a transaction-specific prepared statement from
+// Prepare creates a prepared statement for use within a transaction.
+//
+// The returned statement operates within the transaction and can no longer
+// be used once the transaction has been committed or rolled back.
+//
+// To use an existing prepared statement on this transaction, see Tx.Stmt.
+func (tx *Tx) Prepare(query string) (*Stmt, error) {
+ return tx.PrepareContext(context.Background(), query)
+}
+
+// StmtContext returns a transaction-specific prepared statement from
// an existing statement.
//
// Example:
@@ -1328,30 +1613,34 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
// ...
// tx, err := db.Begin()
// ...
-// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+// res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203)
//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
-func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
+func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
+ tx.closemu.RLock()
+ defer tx.closemu.RUnlock()
+
// TODO(bradfitz): optimize this. Currently this re-prepares
- // each time. This is fine for now to illustrate the API but
+ // each time. This is fine for now to illustrate the API but
// we should really cache already-prepared statements
// per-Conn. See also the big comment in Tx.Prepare.
if tx.db != stmt.db {
return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
}
- dc, err := tx.grabConn()
+ dc, err := tx.grabConn(ctx)
if err != nil {
return &Stmt{stickyErr: err}
}
- dc.Lock()
- si, err := dc.ci.Prepare(stmt.query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
+ })
txs := &Stmt{
db: tx.db,
tx: tx,
- txsi: &driverStmt{
+ txds: &driverStmt{
Locker: dc,
si: si,
},
@@ -1364,10 +1653,29 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
return txs
}
-// Exec executes a query that doesn't return rows.
+// Stmt returns a transaction-specific prepared statement from
+// an existing statement.
+//
+// Example:
+// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
+// ...
+// tx, err := db.Begin()
+// ...
+// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+//
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
+func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+ return tx.StmtContext(context.Background(), stmt)
+}
+
+// ExecContext executes a query that doesn't return rows.
// For example: an INSERT and UPDATE.
-func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
- dc, err := tx.grabConn()
+func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
+ tx.closemu.RLock()
+ defer tx.closemu.RUnlock()
+
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
@@ -1377,9 +1685,10 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
if err != nil {
return nil, err
}
- dc.Lock()
- resi, err := execer.Exec(query, dargs)
- dc.Unlock()
+ var resi driver.Result
+ withLock(dc, func() {
+ resi, err = ctxDriverExec(ctx, execer, query, dargs)
+ })
if err == nil {
return driverResult{dc, resi}, nil
}
@@ -1388,39 +1697,62 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
- defer withLock(dc, func() { si.Close() })
+ ds := &driverStmt{Locker: dc, si: si}
+ defer ds.Close()
- return resultFromStatement(driverStmt{dc, si}, args...)
+ return resultFromStatement(ctx, ds, args...)
}
-// Query executes a query that returns rows, typically a SELECT.
-func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
- dc, err := tx.grabConn()
+// Exec executes a query that doesn't return rows.
+// For example: an INSERT and UPDATE.
+func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
+ return tx.ExecContext(context.Background(), query, args...)
+}
+
+// QueryContext executes a query that returns rows, typically a SELECT.
+func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ tx.closemu.RLock()
+ defer tx.closemu.RUnlock()
+
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
releaseConn := func(error) {}
- return tx.db.queryConn(dc, releaseConn, query, args)
+ return tx.db.queryConn(ctx, dc, releaseConn, query, args)
+}
+
+// Query executes a query that returns rows, typically a SELECT.
+func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
+ return tx.QueryContext(context.Background(), query, args...)
+}
+
+// QueryRowContext executes a query that is expected to return at most one row.
+// QueryRowContext always returns a non-nil value. Errors are deferred until
+// Row's Scan method is called.
+func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := tx.QueryContext(ctx, query, args...)
+ return &Row{rows: rows, err: err}
}
// QueryRow executes a query that is expected to return at most one row.
// QueryRow always returns a non-nil value. Errors are deferred until
// Row's Scan method is called.
func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
- rows, err := tx.Query(query, args...)
- return &Row{rows: rows, err: err}
+ return tx.QueryRowContext(context.Background(), query, args...)
}
// connStmt is a prepared statement on a particular connection.
type connStmt struct {
dc *driverConn
- si driver.Stmt
+ ds *driverStmt
}
// Stmt is a prepared statement.
@@ -1435,15 +1767,15 @@ type Stmt struct {
// If in a transaction, else both nil:
tx *Tx
- txsi *driverStmt
+ txds *driverStmt
mu sync.Mutex // protects the rest of the fields
closed bool
// css is a list of underlying driver statement interfaces
- // that are valid on particular connections. This is only
+ // that are valid on particular connections. This is only
// used if tx == nil and one is found that has idle
- // connections. If tx != nil, txsi is always used.
+ // connections. If tx != nil, txsi is always used.
css []connStmt
// lastNumClosed is copied from db.numClosed when Stmt is created
@@ -1451,15 +1783,15 @@ type Stmt struct {
lastNumClosed uint64
}
-// Exec executes a prepared statement with the given arguments and
+// ExecContext executes a prepared statement with the given arguments and
// returns a Result summarizing the effect of the statement.
-func (s *Stmt) Exec(args ...interface{}) (Result, error) {
+func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
var res Result
for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, si, err := s.connStmt()
+ _, releaseConn, ds, err := s.connStmt(ctx)
if err != nil {
if err == driver.ErrBadConn {
continue
@@ -1467,7 +1799,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return nil, err
}
- res, err = resultFromStatement(driverStmt{dc, si}, args...)
+ res, err = resultFromStatement(ctx, ds, args...)
releaseConn(err)
if err != driver.ErrBadConn {
return res, err
@@ -1476,13 +1808,19 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return nil, driver.ErrBadConn
}
-func driverNumInput(ds driverStmt) int {
+// Exec executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+func (s *Stmt) Exec(args ...interface{}) (Result, error) {
+ return s.ExecContext(context.Background(), args...)
+}
+
+func driverNumInput(ds *driverStmt) int {
ds.Lock()
defer ds.Unlock() // in case NumInput panics
return ds.si.NumInput()
}
-func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
+func resultFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}) (Result, error) {
want := driverNumInput(ds)
// -1 means the driver doesn't know how to count the number of
@@ -1492,14 +1830,15 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
- dargs, err := driverArgs(&ds, args)
+ dargs, err := driverArgs(ds, args)
if err != nil {
return nil, err
}
ds.Lock()
defer ds.Unlock()
- resi, err := ds.si.Exec(dargs)
+
+ resi, err := ctxDriverStmtExec(ctx, ds.si, dargs)
if err != nil {
return nil, err
}
@@ -1535,7 +1874,7 @@ func (s *Stmt) removeClosedStmtLocked() {
// connStmt returns a free driver connection on which to execute the
// statement, a function to call to release the connection, and a
// statement bound to that connection.
-func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.Stmt, err error) {
+func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
if err = s.stickyErr; err != nil {
return
}
@@ -1550,19 +1889,18 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
// transaction was created on.
if s.tx != nil {
s.mu.Unlock()
- ci, err = s.tx.grabConn() // blocks, waiting for the connection.
+ ci, err = s.tx.grabConn(ctx) // blocks, waiting for the connection.
if err != nil {
return
}
releaseConn = func(error) {}
- return ci, releaseConn, s.txsi.si, nil
+ return ci, releaseConn, s.txds, nil
}
s.removeClosedStmtLocked()
s.mu.Unlock()
- // TODO(bradfitz): or always wait for one? make configurable later?
- dc, err := s.db.conn(cachedOrNewConn)
+ dc, err := s.db.conn(ctx, cachedOrNewConn)
if err != nil {
return nil, nil, nil, err
}
@@ -1571,36 +1909,36 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
for _, v := range s.css {
if v.dc == dc {
s.mu.Unlock()
- return dc, dc.releaseConn, v.si, nil
+ return dc, dc.releaseConn, v.ds, nil
}
}
s.mu.Unlock()
// No luck; we need to prepare the statement on this connection
- dc.Lock()
- si, err = dc.prepareLocked(s.query)
- dc.Unlock()
+ withLock(dc, func() {
+ ds, err = dc.prepareLocked(ctx, s.query)
+ })
if err != nil {
s.db.putConn(dc, err)
return nil, nil, nil, err
}
s.mu.Lock()
- cs := connStmt{dc, si}
+ cs := connStmt{dc, ds}
s.css = append(s.css, cs)
s.mu.Unlock()
- return dc, dc.releaseConn, si, nil
+ return dc, dc.releaseConn, ds, nil
}
-// Query executes a prepared query statement with the given arguments
+// QueryContext executes a prepared query statement with the given arguments
// and returns the query results as a *Rows.
-func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
+func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
var rowsi driver.Rows
for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, si, err := s.connStmt()
+ dc, releaseConn, ds, err := s.connStmt(ctx)
if err != nil {
if err == driver.ErrBadConn {
continue
@@ -1608,7 +1946,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return nil, err
}
- rowsi, err = rowsiFromStatement(driverStmt{dc, si}, args...)
+ rowsi, err = rowsiFromStatement(ctx, ds, args...)
if err == nil {
// Note: ownership of ci passes to the *Rows, to be freed
// with releaseConn.
@@ -1617,6 +1955,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
rowsi: rowsi,
// releaseConn set below
}
+ rows.initContextClose(ctx)
s.db.addDep(s, rows)
rows.releaseConn = func(err error) {
releaseConn(err)
@@ -1633,10 +1972,17 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return nil, driver.ErrBadConn
}
-func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
- ds.Lock()
- want := ds.si.NumInput()
- ds.Unlock()
+// Query executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
+ return s.QueryContext(context.Background(), args...)
+}
+
+func rowsiFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}) (driver.Rows, error) {
+ var want int
+ withLock(ds, func() {
+ want = ds.si.NumInput()
+ })
// -1 means the driver doesn't know how to count the number of
// placeholders, so we won't sanity check input here and instead let the
@@ -1645,21 +1991,22 @@ func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error)
return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
}
- dargs, err := driverArgs(&ds, args)
+ dargs, err := driverArgs(ds, args)
if err != nil {
return nil, err
}
ds.Lock()
- rowsi, err := ds.si.Query(dargs)
- ds.Unlock()
+ defer ds.Unlock()
+
+ rowsi, err := ctxDriverStmtQuery(ctx, ds.si, dargs)
if err != nil {
return nil, err
}
return rowsi, nil
}
-// QueryRow executes a prepared query statement with the given arguments.
+// QueryRowContext executes a prepared query statement with the given arguments.
// If an error occurs during the execution of the statement, that error will
// be returned by a call to Scan on the returned *Row, which is always non-nil.
// If the query selects no rows, the *Row's Scan will return ErrNoRows.
@@ -1669,15 +2016,30 @@ func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error)
// Example usage:
//
// var name string
-// err := nameByUseridStmt.QueryRow(id).Scan(&name)
-func (s *Stmt) QueryRow(args ...interface{}) *Row {
- rows, err := s.Query(args...)
+// err := nameByUseridStmt.QueryRowContext(ctx, id).Scan(&name)
+func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
+ rows, err := s.QueryContext(ctx, args...)
if err != nil {
return &Row{err: err}
}
return &Row{rows: rows}
}
+// QueryRow executes a prepared query statement with the given arguments.
+// If an error occurs during the execution of the statement, that error will
+// be returned by a call to Scan on the returned *Row, which is always non-nil.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
+//
+// Example usage:
+//
+// var name string
+// err := nameByUseridStmt.QueryRow(id).Scan(&name)
+func (s *Stmt) QueryRow(args ...interface{}) *Row {
+ return s.QueryRowContext(context.Background(), args...)
+}
+
// Close closes the statement.
func (s *Stmt) Close() error {
s.closemu.Lock()
@@ -1692,13 +2054,11 @@ func (s *Stmt) Close() error {
return nil
}
s.closed = true
+ s.mu.Unlock()
if s.tx != nil {
- err := s.txsi.Close()
- s.mu.Unlock()
- return err
+ return s.txds.Close()
}
- s.mu.Unlock()
return s.db.removeDep(s, s)
}
@@ -1708,8 +2068,8 @@ func (s *Stmt) finalClose() error {
defer s.mu.Unlock()
if s.css != nil {
for _, v := range s.css {
- s.db.noteUnusedDriverStatement(v.dc, v.si)
- v.dc.removeOpenStmt(v.si)
+ s.db.noteUnusedDriverStatement(v.dc, v.ds)
+ v.dc.removeOpenStmt(v.ds)
}
s.css = nil
}
@@ -1734,29 +2094,110 @@ type Rows struct {
dc *driverConn // owned; must call releaseConn when closed to release
releaseConn func(error)
rowsi driver.Rows
+ cancel func() // called when Rows is closed, may be nil.
+ closeStmt *driverStmt // if non-nil, statement to Close on close
+
+ // closemu prevents Rows from closing while there
+ // is an active streaming result. It is held for read during non-close operations
+ // and exclusively during close.
+ //
+ // closemu guards lasterr and closed.
+ closemu sync.RWMutex
+ closed bool
+ lasterr error // non-nil only if closed is true
- closed bool
- lastcols []driver.Value
- lasterr error // non-nil only if closed is true
- closeStmt driver.Stmt // if non-nil, statement to Close on close
+ // lastcols is only used in Scan, Next, and NextResultSet which are expected
+ // not not be called concurrently.
+ lastcols []driver.Value
}
-// Next prepares the next result row for reading with the Scan method. It
+func (rs *Rows) initContextClose(ctx context.Context) {
+ ctx, rs.cancel = context.WithCancel(ctx)
+ go rs.awaitDone(ctx)
+}
+
+// awaitDone blocks until the rows are closed or the context canceled.
+func (rs *Rows) awaitDone(ctx context.Context) {
+ <-ctx.Done()
+ rs.close(ctx.Err())
+}
+
+// Next prepares the next result row for reading with the Scan method. It
// returns true on success, or false if there is no next result row or an error
-// happened while preparing it. Err should be consulted to distinguish between
+// happened while preparing it. Err should be consulted to distinguish between
// the two cases.
//
// Every call to Scan, even the first one, must be preceded by a call to Next.
func (rs *Rows) Next() bool {
+ var doClose, ok bool
+ withLock(rs.closemu.RLocker(), func() {
+ doClose, ok = rs.nextLocked()
+ })
+ if doClose {
+ rs.Close()
+ }
+ return ok
+}
+
+func (rs *Rows) nextLocked() (doClose, ok bool) {
if rs.closed {
- return false
+ return false, false
}
if rs.lastcols == nil {
rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
}
rs.lasterr = rs.rowsi.Next(rs.lastcols)
if rs.lasterr != nil {
- rs.Close()
+ // Close the connection if there is a driver error.
+ if rs.lasterr != io.EOF {
+ return true, false
+ }
+ nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
+ if !ok {
+ return true, false
+ }
+ // The driver is at the end of the current result set.
+ // Test to see if there is another result set after the current one.
+ // Only close Rows if there is no further result sets to read.
+ if !nextResultSet.HasNextResultSet() {
+ doClose = true
+ }
+ return doClose, false
+ }
+ return false, true
+}
+
+// NextResultSet prepares the next result set for reading. It returns true if
+// there is further result sets, or false if there is no further result set
+// or if there is an error advancing to it. The Err method should be consulted
+// to distinguish between the two cases.
+//
+// After calling NextResultSet, the Next method should always be called before
+// scanning. If there are further result sets they may not have rows in the result
+// set.
+func (rs *Rows) NextResultSet() bool {
+ var doClose bool
+ defer func() {
+ if doClose {
+ rs.Close()
+ }
+ }()
+ rs.closemu.RLock()
+ defer rs.closemu.RUnlock()
+
+ if rs.closed {
+ return false
+ }
+
+ rs.lastcols = nil
+ nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
+ if !ok {
+ doClose = true
+ return false
+ }
+ rs.lasterr = nextResultSet.NextResultSet()
+ if rs.lasterr != nil {
+ doClose = true
return false
}
return true
@@ -1765,6 +2206,8 @@ func (rs *Rows) Next() bool {
// Err returns the error, if any, that was encountered during iteration.
// Err may be called after an explicit or implicit Close.
func (rs *Rows) Err() error {
+ rs.closemu.RLock()
+ defer rs.closemu.RUnlock()
if rs.lasterr == io.EOF {
return nil
}
@@ -1775,6 +2218,8 @@ func (rs *Rows) Err() error {
// Columns returns an error if the rows are closed, or if the rows
// are from QueryRow and there was a deferred error.
func (rs *Rows) Columns() ([]string, error) {
+ rs.closemu.RLock()
+ defer rs.closemu.RUnlock()
if rs.closed {
return nil, errors.New("sql: Rows are closed")
}
@@ -1784,6 +2229,109 @@ func (rs *Rows) Columns() ([]string, error) {
return rs.rowsi.Columns(), nil
}
+// ColumnTypes returns column information such as column type, length,
+// and nullable. Some information may not be available from some drivers.
+func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
+ rs.closemu.RLock()
+ defer rs.closemu.RUnlock()
+ if rs.closed {
+ return nil, errors.New("sql: Rows are closed")
+ }
+ if rs.rowsi == nil {
+ return nil, errors.New("sql: no Rows available")
+ }
+ return rowsColumnInfoSetup(rs.rowsi), nil
+}
+
+// ColumnType contains the name and type of a column.
+type ColumnType struct {
+ name string
+
+ hasNullable bool
+ hasLength bool
+ hasPrecisionScale bool
+
+ nullable bool
+ length int64
+ databaseType string
+ precision int64
+ scale int64
+ scanType reflect.Type
+}
+
+// Name returns the name or alias of the column.
+func (ci *ColumnType) Name() string {
+ return ci.name
+}
+
+// Length returns the column type length for variable length column types such
+// as text and binary field types. If the type length is unbounded the value will
+// be math.MaxInt64 (any database limits will still apply).
+// If the column type is not variable length, such as an int, or if not supported
+// by the driver ok is false.
+func (ci *ColumnType) Length() (length int64, ok bool) {
+ return ci.length, ci.hasLength
+}
+
+// DecimalSize returns the scale and precision of a decimal type.
+// If not applicable or if not supported ok is false.
+func (ci *ColumnType) DecimalSize() (precision, scale int64, ok bool) {
+ return ci.precision, ci.scale, ci.hasPrecisionScale
+}
+
+// ScanType returns a Go type suitable for scanning into using Rows.Scan.
+// If a driver does not support this property ScanType will return
+// the type of an empty interface.
+func (ci *ColumnType) ScanType() reflect.Type {
+ return ci.scanType
+}
+
+// Nullable returns whether the column may be null.
+// If a driver does not support this property ok will be false.
+func (ci *ColumnType) Nullable() (nullable, ok bool) {
+ return ci.nullable, ci.hasNullable
+}
+
+// DatabaseTypeName returns the database system name of the column type. If an empty
+// string is returned the driver type name is not supported.
+// Consult your driver documentation for a list of driver data types. Length specifiers
+// are not included.
+// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
+func (ci *ColumnType) DatabaseTypeName() string {
+ return ci.databaseType
+}
+
+func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType {
+ names := rowsi.Columns()
+
+ list := make([]*ColumnType, len(names))
+ for i := range list {
+ ci := &ColumnType{
+ name: names[i],
+ }
+ list[i] = ci
+
+ if prop, ok := rowsi.(driver.RowsColumnTypeScanType); ok {
+ ci.scanType = prop.ColumnTypeScanType(i)
+ } else {
+ ci.scanType = reflect.TypeOf(new(interface{})).Elem()
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeDatabaseTypeName); ok {
+ ci.databaseType = prop.ColumnTypeDatabaseTypeName(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeLength); ok {
+ ci.length, ci.hasLength = prop.ColumnTypeLength(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeNullable); ok {
+ ci.nullable, ci.hasNullable = prop.ColumnTypeNullable(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypePrecisionScale); ok {
+ ci.precision, ci.scale, ci.hasPrecisionScale = prop.ColumnTypePrecisionScale(i)
+ }
+ }
+ return list
+}
+
// Scan copies the columns in the current row into the values pointed
// at by dest. The number of values in dest must be the same as the
// number of columns in Rows.
@@ -1836,9 +2384,13 @@ func (rs *Rows) Columns() ([]string, error) {
// For scanning into *bool, the source may be true, false, 1, 0, or
// string inputs parseable by strconv.ParseBool.
func (rs *Rows) Scan(dest ...interface{}) error {
+ rs.closemu.RLock()
if rs.closed {
+ rs.closemu.RUnlock()
return errors.New("sql: Rows are closed")
}
+ rs.closemu.RUnlock()
+
if rs.lastcols == nil {
return errors.New("sql: Scan called without calling Next")
}
@@ -1854,20 +2406,39 @@ func (rs *Rows) Scan(dest ...interface{}) error {
return nil
}
-var rowsCloseHook func(*Rows, *error)
+// rowsCloseHook returns a function so tests may install the
+// hook throug a test only mutex.
+var rowsCloseHook = func() func(*Rows, *error) { return nil }
-// Close closes the Rows, preventing further enumeration. If Next returns
-// false, the Rows are closed automatically and it will suffice to check the
+// Close closes the Rows, preventing further enumeration. If Next is called
+// and returns false and there are no further result sets,
+// the Rows are closed automatically and it will suffice to check the
// result of Err. Close is idempotent and does not affect the result of Err.
func (rs *Rows) Close() error {
+ return rs.close(nil)
+}
+
+func (rs *Rows) close(err error) error {
+ rs.closemu.Lock()
+ defer rs.closemu.Unlock()
+
if rs.closed {
return nil
}
rs.closed = true
- err := rs.rowsi.Close()
- if fn := rowsCloseHook; fn != nil {
+
+ if rs.lasterr == nil {
+ rs.lasterr = err
+ }
+
+ err = rs.rowsi.Close()
+ if fn := rowsCloseHook(); fn != nil {
fn(rs, &err)
}
+ if rs.cancel != nil {
+ rs.cancel()
+ }
+
if rs.closeStmt != nil {
rs.closeStmt.Close()
}
@@ -1898,8 +2469,8 @@ func (r *Row) Scan(dest ...interface{}) error {
// the Rows in our defer, when we return from this function.
// the contract with the driver.Next(...) interface is that it
// can return slices into read-only temporary memory that's
- // only valid until the next Scan/Close. But the TODO is that
- // for a lot of drivers, this copy will be unnecessary. We
+ // only valid until the next Scan/Close. But the TODO is that
+ // for a lot of drivers, this copy will be unnecessary. We
// should provide an optional interface for drivers to
// implement to say, "don't worry, the []bytes that I return
// from Next will not be modified again." (for instance, if
diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go
index 8ec70d99b0..450e5f1f8c 100644
--- a/libgo/go/database/sql/sql_test.go
+++ b/libgo/go/database/sql/sql_test.go
@@ -5,6 +5,7 @@
package sql
import (
+ "context"
"database/sql/driver"
"errors"
"fmt"
@@ -13,6 +14,7 @@ import (
"runtime"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -23,6 +25,17 @@ func init() {
c *driverConn
}
freedFrom := make(map[dbConn]string)
+ var mu sync.Mutex
+ getFreedFrom := func(c dbConn) string {
+ mu.Lock()
+ defer mu.Unlock()
+ return freedFrom[c]
+ }
+ setFreedFrom := func(c dbConn, s string) {
+ mu.Lock()
+ defer mu.Unlock()
+ freedFrom[c] = s
+ }
putConnHook = func(db *DB, c *driverConn) {
idx := -1
for i, v := range db.freeConn {
@@ -35,10 +48,10 @@ func init() {
// print before panic, as panic may get lost due to conflicting panic
// (all goroutines asleep) elsewhere, since we might not unlock
// the mutex in freeConn here.
- println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
+ println("double free of conn. conflicts are:\nA) " + getFreedFrom(dbConn{db, c}) + "\n\nand\nB) " + stack())
panic("double free of conn.")
}
- freedFrom[dbConn{db, c}] = stack()
+ setFreedFrom(dbConn{db, c}, stack())
}
}
@@ -140,11 +153,13 @@ func closeDB(t testing.TB, db *DB) {
if err != nil {
t.Fatalf("error closing DB: %v", err)
}
- db.mu.Lock()
- count := db.numOpen
- db.mu.Unlock()
- if count != 0 {
- t.Fatalf("%d connections still open after closing DB", db.numOpen)
+
+ var numOpen int
+ if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+ numOpen = db.numOpenConns()
+ return numOpen == 0
+ }) {
+ t.Fatalf("%d connections still open after closing DB", numOpen)
}
}
@@ -182,6 +197,12 @@ func (db *DB) numFreeConns() int {
return len(db.freeConn)
}
+func (db *DB) numOpenConns() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return db.numOpen
+}
+
// clearAllConns closes all connections in db.
func (db *DB) clearAllConns(t *testing.T) {
db.SetMaxIdleConns(0)
@@ -260,6 +281,338 @@ func TestQuery(t *testing.T) {
}
}
+// TestQueryContext tests canceling the context while scanning the rows.
+func TestQueryContext(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ rows, err := db.QueryContext(ctx, "SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ index := 0
+ for rows.Next() {
+ if index == 2 {
+ cancel()
+ waitForRowsClose(t, rows, 5*time.Second)
+ }
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ if index == 2 {
+ break
+ }
+ t.Fatalf("Scan: %v", err)
+ }
+ if index == 2 && err == nil {
+ t.Fatal("expected an error on last scan")
+ }
+ got = append(got, r)
+ index++
+ }
+ select {
+ case <-ctx.Done():
+ if err := ctx.Err(); err != context.Canceled {
+ t.Fatalf("context err = %v; want context.Canceled")
+ }
+ default:
+ t.Fatalf("context err = nil; want context.Canceled")
+ }
+ want := []row{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ waitForRowsClose(t, rows, 5*time.Second)
+ waitForFree(t, db, 5*time.Second, 1)
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
+ deadline := time.Now().Add(waitFor)
+ for time.Now().Before(deadline) {
+ if fn() {
+ return true
+ }
+ time.Sleep(checkEvery)
+ }
+ return false
+}
+
+// waitForFree checks db.numFreeConns until either it equals want or
+// the maxWait time elapses.
+func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
+ var numFree int
+ if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+ numFree = db.numFreeConns()
+ return numFree == want
+ }) {
+ t.Fatalf("free conns after hitting EOF = %d; want %d", numFree, want)
+ }
+}
+
+func waitForRowsClose(t *testing.T, rows *Rows, maxWait time.Duration) {
+ if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+ rows.closemu.RLock()
+ defer rows.closemu.RUnlock()
+ return rows.closed
+ }) {
+ t.Fatal("failed to close rows")
+ }
+}
+
+// TestQueryContextWait ensures that rows and all internal statements are closed when
+// a query context is closed during execution.
+func TestQueryContextWait(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+
+ // TODO(kardianos): convert this from using a timeout to using an explicit
+ // cancel when the query signals that is is "executing" the query.
+ ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
+ defer cancel()
+
+ // This will trigger the *fakeConn.Prepare method which will take time
+ // performing the query. The ctxDriverPrepare func will check the context
+ // after this and close the rows and return an error.
+ _, err := db.QueryContext(ctx, "WAIT|1s|SELECT|people|age,name|")
+ if err != context.DeadlineExceeded {
+ t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
+ }
+
+ // Verify closed rows connection after error condition.
+ waitForFree(t, db, 5*time.Second, 1)
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ // TODO(kardianos): if the context timeouts before the db.QueryContext
+ // executes this check may fail. After adjusting how the context
+ // is canceled above revert this back to a Fatal error.
+ t.Logf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+// TestTxContextWait tests the transaction behavior when the tx context is canceled
+// during execution of the query.
+func TestTxContextWait(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
+
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ // Guard against the context being canceled before BeginTx completes.
+ if err == context.DeadlineExceeded {
+ t.Skip("tx context canceled prior to first use")
+ }
+ t.Fatal(err)
+ }
+
+ // This will trigger the *fakeConn.Prepare method which will take time
+ // performing the query. The ctxDriverPrepare func will check the context
+ // after this and close the rows and return an error.
+ _, err = tx.QueryContext(ctx, "WAIT|1s|SELECT|people|age,name|")
+ if err != context.DeadlineExceeded {
+ t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
+ }
+
+ waitForFree(t, db, 5*time.Second, 0)
+}
+
+func TestMultiResultSetQuery(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+ rows, err := db.Query("SELECT|people|age,name|;SELECT|people|name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row1 struct {
+ age int
+ name string
+ }
+ type row2 struct {
+ name string
+ }
+ got1 := []row1{}
+ for rows.Next() {
+ var r row1
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got1 = append(got1, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want1 := []row1{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ {age: 3, name: "Chris"},
+ }
+ if !reflect.DeepEqual(got1, want1) {
+ t.Errorf("mismatch.\n got1: %#v\nwant: %#v", got1, want1)
+ }
+
+ if !rows.NextResultSet() {
+ t.Errorf("expected another result set")
+ }
+
+ got2 := []row2{}
+ for rows.Next() {
+ var r row2
+ err = rows.Scan(&r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got2 = append(got2, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want2 := []row2{
+ {name: "Alice"},
+ {name: "Bob"},
+ {name: "Chris"},
+ }
+ if !reflect.DeepEqual(got2, want2) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got2, want2)
+ }
+ if rows.NextResultSet() {
+ t.Errorf("expected no more result sets")
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ waitForFree(t, db, 5*time.Second, 1)
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func TestQueryNamedArg(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+ rows, err := db.Query(
+ // Ensure the name and age parameters only match on placeholder name, not position.
+ "SELECT|people|age,name|name=?name,age=?age",
+ Named("age", 2),
+ Named("name", "Bob"),
+ )
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ for rows.Next() {
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got = append(got, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want := []row{
+ {age: 2, name: "Bob"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ if n := db.numFreeConns(); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func TestPoolExhaustOnCancel(t *testing.T) {
+ if testing.Short() {
+ t.Skip("long test")
+ }
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ max := 3
+
+ db.SetMaxOpenConns(max)
+
+ // First saturate the connection pool.
+ // Then start new requests for a connection that is cancelled after it is requested.
+
+ var saturate, saturateDone sync.WaitGroup
+ saturate.Add(max)
+ saturateDone.Add(max)
+
+ for i := 0; i < max; i++ {
+ go func() {
+ saturate.Done()
+ rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ rows.Close()
+ saturateDone.Done()
+ }()
+ }
+
+ saturate.Wait()
+
+ // Now cancel the request while it is waiting.
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
+ defer cancel()
+
+ for i := 0; i < max; i++ {
+ ctxReq, cancelReq := context.WithCancel(ctx)
+ go func() {
+ time.Sleep(time.Millisecond * 100)
+ cancelReq()
+ }()
+ err := db.PingContext(ctxReq)
+ if err != context.Canceled {
+ t.Fatalf("PingContext (Exhaust): %v", err)
+ }
+ }
+
+ saturateDone.Wait()
+
+ // Now try to open a normal connection.
+ err := db.PingContext(ctx)
+ if err != nil {
+ t.Fatalf("PingContext (Normal): %v", err)
+ }
+}
+
func TestByteOwnership(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -317,6 +670,56 @@ func TestRowsColumns(t *testing.T) {
}
}
+func TestRowsColumnTypes(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ tt, err := rows.ColumnTypes()
+ if err != nil {
+ t.Fatalf("ColumnTypes: %v", err)
+ }
+
+ types := make([]reflect.Type, len(tt))
+ for i, tp := range tt {
+ st := tp.ScanType()
+ if st == nil {
+ t.Errorf("scantype is null for column %q", tp.Name())
+ continue
+ }
+ types[i] = st
+ }
+ values := make([]interface{}, len(tt))
+ for i := range values {
+ values[i] = reflect.New(types[i]).Interface()
+ }
+ ct := 0
+ for rows.Next() {
+ err = rows.Scan(values...)
+ if err != nil {
+ t.Fatalf("failed to scan values in %v", err)
+ }
+ ct++
+ if ct == 0 {
+ if values[0].(string) != "Bob" {
+ t.Errorf("Expected Bob, got %v", values[0])
+ }
+ if values[1].(int) != 2 {
+ t.Errorf("Expected 2, got %v", values[1])
+ }
+ }
+ }
+ if ct != 3 {
+ t.Errorf("expected 3 rows, got %d", ct)
+ }
+
+ if err := rows.Close(); err != nil {
+ t.Errorf("error closing rows: %s", err)
+ }
+}
+
func TestQueryRow(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -367,6 +770,37 @@ func TestQueryRow(t *testing.T) {
}
}
+func TestTxRollbackCommitErr(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = tx.Rollback()
+ if err != nil {
+ t.Errorf("expected nil error from Rollback; got %v", err)
+ }
+ err = tx.Commit()
+ if err != ErrTxDone {
+ t.Errorf("expected %q from Commit; got %q", ErrTxDone, err)
+ }
+
+ tx, err = db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = tx.Commit()
+ if err != nil {
+ t.Errorf("expected nil error from Commit; got %v", err)
+ }
+ err = tx.Rollback()
+ if err != ErrTxDone {
+ t.Errorf("expected %q from Rollback; got %q", ErrTxDone, err)
+ }
+}
+
func TestStatementErrorAfterClose(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -439,7 +873,7 @@ func TestStatementClose(t *testing.T) {
msg string
}{
{&Stmt{stickyErr: want}, "stickyErr not propagated"},
- {&Stmt{tx: &Tx{}, txsi: &driverStmt{&sync.Mutex{}, stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
+ {&Stmt{tx: &Tx{}, txds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
}
for _, test := range tests {
if err := test.stmt.Close(); err != want {
@@ -513,8 +947,8 @@ func TestExec(t *testing.T) {
{[]interface{}{7, 9}, ""},
// Invalid conversions:
- {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument #1's type: sql/driver: value 4294967295 overflows int32"},
- {[]interface{}{"Brad", "strconv fail"}, "sql: converting argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+ {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument $2 type: sql/driver: value 4294967295 overflows int32"},
+ {[]interface{}{"Brad", "strconv fail"}, `sql: converting argument $2 type: sql/driver: value "strconv fail" can't be converted to int32`},
// Wrong number of args:
{[]interface{}{}, "sql: expected 2 arguments, got 0"},
@@ -788,6 +1222,24 @@ func TestQueryRowClosingStmt(t *testing.T) {
}
}
+var atomicRowsCloseHook atomic.Value // of func(*Rows, *error)
+
+func init() {
+ rowsCloseHook = func() func(*Rows, *error) {
+ fn, _ := atomicRowsCloseHook.Load().(func(*Rows, *error))
+ return fn
+ }
+}
+
+func setRowsCloseHook(fn func(*Rows, *error)) {
+ if fn == nil {
+ // Can't change an atomic.Value back to nil, so set it to this
+ // no-op func instead.
+ fn = func(*Rows, *error) {}
+ }
+ atomicRowsCloseHook.Store(fn)
+}
+
// Test issue 6651
func TestIssue6651(t *testing.T) {
db := newTestDB(t, "people")
@@ -800,6 +1252,7 @@ func TestIssue6651(t *testing.T) {
return fmt.Errorf(want)
}
defer func() { rowsCursorNextHook = nil }()
+
err := db.QueryRow("SELECT|people|name|").Scan(&v)
if err == nil || err.Error() != want {
t.Errorf("error = %q; want %q", err, want)
@@ -807,10 +1260,10 @@ func TestIssue6651(t *testing.T) {
rowsCursorNextHook = nil
want = "error in rows.Close"
- rowsCloseHook = func(rows *Rows, err *error) {
+ setRowsCloseHook(func(rows *Rows, err *error) {
*err = fmt.Errorf(want)
- }
- defer func() { rowsCloseHook = nil }()
+ })
+ defer setRowsCloseHook(nil)
err = db.QueryRow("SELECT|people|name|").Scan(&v)
if err == nil || err.Error() != want {
t.Errorf("error = %q; want %q", err, want)
@@ -911,7 +1364,7 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
if err == nil {
// TODO: this test fails, but it's just because
// fakeConn implements the optional Execer interface,
- // so arguably this is the correct behavior. But
+ // so arguably this is the correct behavior. But
// maybe I should flesh out the fakeConn.Exec
// implementation so this properly fails.
// t.Errorf("expected error inserting nil name with Exec")
@@ -1159,17 +1612,19 @@ func TestMaxOpenConnsOnBusy(t *testing.T) {
db.SetMaxOpenConns(3)
- conn0, err := db.conn(cachedOrNewConn)
+ ctx := context.Background()
+
+ conn0, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
- conn1, err := db.conn(cachedOrNewConn)
+ conn1, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
- conn2, err := db.conn(cachedOrNewConn)
+ conn2, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
@@ -1203,7 +1658,11 @@ func TestPendingConnsAfterErr(t *testing.T) {
tryOpen = maxOpen*2 + 2
)
- db := newTestDB(t, "people")
+ // No queries will be run.
+ db, err := Open("test", fakeDBName)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
defer closeDB(t, db)
defer func() {
for k, v := range db.lastPut {
@@ -1215,31 +1674,31 @@ func TestPendingConnsAfterErr(t *testing.T) {
db.SetMaxIdleConns(0)
errOffline := errors.New("db offline")
+
defer func() { setHookOpenErr(nil) }()
errs := make(chan error, tryOpen)
- unblock := make(chan struct{})
+ var opening sync.WaitGroup
+ opening.Add(tryOpen)
+
setHookOpenErr(func() error {
- <-unblock // block until all connections are in flight
+ // Wait for all connections to enqueue.
+ opening.Wait()
return errOffline
})
- var opening sync.WaitGroup
- opening.Add(tryOpen)
for i := 0; i < tryOpen; i++ {
go func() {
opening.Done() // signal one connection is in flight
- _, err := db.Exec("INSERT|people|name=Julia,age=19")
+ _, err := db.Exec("will never run")
errs <- err
}()
}
- opening.Wait() // wait for all workers to begin running
- time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
- close(unblock) // let all workers proceed
+ opening.Wait() // wait for all workers to begin running
- const timeout = 100 * time.Millisecond
+ const timeout = 5 * time.Second
to := time.NewTimer(timeout)
defer to.Stop()
@@ -1254,6 +1713,24 @@ func TestPendingConnsAfterErr(t *testing.T) {
t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
}
}
+
+ // Wait a reasonable time for the database to close all connections.
+ tick := time.NewTicker(3 * time.Millisecond)
+ defer tick.Stop()
+ for {
+ select {
+ case <-tick.C:
+ db.mu.Lock()
+ if db.numOpen == 0 {
+ db.mu.Unlock()
+ return
+ }
+ db.mu.Unlock()
+ case <-to.C:
+ // Closing the database will check for numOpen and fail the test.
+ return
+ }
+ }
}
func TestSingleOpenConn(t *testing.T) {
@@ -1459,7 +1936,9 @@ func TestStmtCloseDeps(t *testing.T) {
db.dumpDeps(t)
}
- if len(stmt.css) > nquery {
+ if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+ return len(stmt.css) <= nquery
+ }) {
t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
}
@@ -1591,7 +2070,7 @@ func TestStmtCloseOrder(t *testing.T) {
_, err := db.Query("SELECT|non_existent|name|")
if err == nil {
- t.Fatal("Quering non-existent table should fail")
+ t.Fatal("Querying non-existent table should fail")
}
}
@@ -1615,6 +2094,8 @@ func TestManyErrBadConn(t *testing.T) {
}
}()
+ db.mu.Lock()
+ defer db.mu.Unlock()
if db.numOpen != nconn {
t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
} else if len(db.freeConn) != nconn {
@@ -2203,10 +2684,10 @@ func TestIssue6081(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- rowsCloseHook = func(rows *Rows, err *error) {
+ setRowsCloseHook(func(rows *Rows, err *error) {
*err = driver.ErrBadConn
- }
- defer func() { rowsCloseHook = nil }()
+ })
+ defer setRowsCloseHook(nil)
for i := 0; i < 10; i++ {
rows, err := stmt.Query()
if err != nil {
@@ -2234,6 +2715,100 @@ func TestIssue6081(t *testing.T) {
}
}
+// TestIssue18429 attempts to stress rolling back the transaction from a
+// context cancel while simultaneously calling Tx.Rollback. Rolling back from a
+// context happens concurrently so tx.rollback and tx.Commit must guard against
+// double entry.
+//
+// In the test, a context is canceled while the query is in process so
+// the internal rollback will run concurrently with the explicitly called
+// Tx.Rollback.
+func TestIssue18429(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ ctx := context.Background()
+ sem := make(chan bool, 20)
+ var wg sync.WaitGroup
+
+ const milliWait = 30
+
+ for i := 0; i < 100; i++ {
+ sem <- true
+ wg.Add(1)
+ go func() {
+ defer func() {
+ <-sem
+ wg.Done()
+ }()
+ qwait := (time.Duration(rand.Intn(milliWait)) * time.Millisecond).String()
+
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(rand.Intn(milliWait))*time.Millisecond)
+ defer cancel()
+
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return
+ }
+ // This is expected to give a cancel error many, but not all the time.
+ // Test failure will happen with a panic or other race condition being
+ // reported.
+ rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
+ if rows != nil {
+ rows.Close()
+ }
+ // This call will race with the context cancel rollback to complete
+ // if the rollback itself isn't guarded.
+ tx.Rollback()
+ }()
+ }
+ wg.Wait()
+}
+
+// TestIssue18719 closes the context right before use. The sql.driverConn
+// will nil out the ci on close in a lock, but if another process uses it right after
+// it will panic with on the nil ref.
+//
+// See https://golang.org/cl/35550 .
+func TestIssue18719(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ hookTxGrabConn = func() {
+ cancel()
+
+ // Wait for the context to cancel and tx to rollback.
+ for tx.isDone() == false {
+ time.Sleep(time.Millisecond * 3)
+ }
+ }
+ defer func() { hookTxGrabConn = nil }()
+
+ // This call will grab the connection and cancel the context
+ // after it has done so. Code after must deal with the canceled state.
+ rows, err := tx.QueryContext(ctx, "SELECT|people|name|")
+ if err != nil {
+ rows.Close()
+ t.Fatalf("expected error %v but got %v", nil, err)
+ }
+
+ // Rows may be ignored because it will be closed when the context is canceled.
+
+ // Do not explicitly rollback. The rollback will happen from the
+ // canceled context.
+
+ cancel()
+ waitForRowsClose(t, rows, 5*time.Second)
+}
+
func TestConcurrency(t *testing.T) {
doConcurrentTest(t, new(concurrentDBQueryTest))
doConcurrentTest(t, new(concurrentDBExecTest))
@@ -2277,7 +2852,8 @@ func TestConnectionLeak(t *testing.T) {
go func() {
r, err := db.Query("SELECT|people|name|")
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
r.Close()
wg.Done()
@@ -2297,6 +2873,97 @@ func TestConnectionLeak(t *testing.T) {
wg.Wait()
}
+// badConn implements a bad driver.Conn, for TestBadDriver.
+// The Exec method panics.
+type badConn struct{}
+
+func (bc badConn) Prepare(query string) (driver.Stmt, error) {
+ return nil, errors.New("badConn Prepare")
+}
+
+func (bc badConn) Close() error {
+ return nil
+}
+
+func (bc badConn) Begin() (driver.Tx, error) {
+ return nil, errors.New("badConn Begin")
+}
+
+func (bc badConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ panic("badConn.Exec")
+}
+
+// badDriver is a driver.Driver that uses badConn.
+type badDriver struct{}
+
+func (bd badDriver) Open(name string) (driver.Conn, error) {
+ return badConn{}, nil
+}
+
+// Issue 15901.
+func TestBadDriver(t *testing.T) {
+ Register("bad", badDriver{})
+ db, err := Open("bad", "ignored")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ if r := recover(); r == nil {
+ t.Error("expected panic")
+ } else {
+ if want := "badConn.Exec"; r.(string) != want {
+ t.Errorf("panic was %v, expected %v", r, want)
+ }
+ }
+ }()
+ defer db.Close()
+ db.Exec("ignored")
+}
+
+type pingDriver struct {
+ fails bool
+}
+
+type pingConn struct {
+ badConn
+ driver *pingDriver
+}
+
+var pingError = errors.New("Ping failed")
+
+func (pc pingConn) Ping(ctx context.Context) error {
+ if pc.driver.fails {
+ return pingError
+ }
+ return nil
+}
+
+var _ driver.Pinger = pingConn{}
+
+func (pd *pingDriver) Open(name string) (driver.Conn, error) {
+ return pingConn{driver: pd}, nil
+}
+
+func TestPing(t *testing.T) {
+ driver := &pingDriver{}
+ Register("ping", driver)
+
+ db, err := Open("ping", "ignored")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := db.Ping(); err != nil {
+ t.Errorf("err was %#v, expected nil", err)
+ return
+ }
+
+ driver.fails = true
+ if err := db.Ping(); err != pingError {
+ t.Errorf("err was %#v, expected pingError", err)
+ }
+}
+
func BenchmarkConcurrentDBExec(b *testing.B) {
b.ReportAllocs()
ct := new(concurrentDBExecTest)
diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go
index 2ade0bd76a..24d266db10 100644
--- a/libgo/go/debug/dwarf/buf.go
+++ b/libgo/go/debug/dwarf/buf.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -22,16 +22,16 @@ type buf struct {
err error
}
-// Data format, other than byte order. This affects the handling of
+// Data format, other than byte order. This affects the handling of
// certain field formats.
type dataFormat interface {
- // DWARF version number. Zero means unknown.
+ // DWARF version number. Zero means unknown.
version() int
// 64-bit DWARF format?
dwarf64() (dwarf64 bool, isKnown bool)
- // Size of an address, in bytes. Zero means unknown.
+ // Size of an address, in bytes. Zero means unknown.
addrsize() int
}
@@ -157,7 +157,7 @@ func (b *buf) addr() uint64 {
case 4:
return uint64(b.uint32())
case 8:
- return uint64(b.uint64())
+ return b.uint64()
}
b.error("unknown address size")
return 0
diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go
index 2170db1e32..04d8c506b0 100644
--- a/libgo/go/debug/dwarf/const.go
+++ b/libgo/go/debug/dwarf/const.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index 5ca86679fa..80bf14cb22 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -243,7 +243,7 @@ type Field struct {
Class Class
}
-// A Class is the DWARF 4 class of an attibute value.
+// A Class is the DWARF 4 class of an attribute value.
//
// In general, a given attribute's value may take on one of several
// possible classes defined by DWARF, each of which leads to a
@@ -506,7 +506,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
}
// A Reader allows reading Entry structures from a DWARF ``info'' section.
-// The Entry structures are arranged in a tree. The Reader's Next function
+// The Entry structures are arranged in a tree. The Reader's Next function
// return successive entries from a pre-order traversal of the tree.
// If an entry has children, its Children field will be true, and the children
// follow, terminated by an Entry with Tag 0.
@@ -598,7 +598,7 @@ func (r *Reader) Next() (*Entry, error) {
}
// SkipChildren skips over the child entries associated with
-// the last Entry returned by Next. If that Entry did not have
+// the last Entry returned by Next. If that Entry did not have
// children or Next has not been called, SkipChildren is a no-op.
func (r *Reader) SkipChildren() {
if r.err != nil || !r.lastChildren {
@@ -625,14 +625,134 @@ func (r *Reader) SkipChildren() {
}
}
-// clone returns a copy of the reader. This is used by the typeReader
+// clone returns a copy of the reader. This is used by the typeReader
// interface.
func (r *Reader) clone() typeReader {
return r.d.Reader()
}
-// offset returns the current buffer offset. This is used by the
+// offset returns the current buffer offset. This is used by the
// typeReader interface.
func (r *Reader) offset() Offset {
return r.b.off
}
+
+// SeekPC returns the Entry for the compilation unit that includes pc,
+// and positions the reader to read the children of that unit. If pc
+// is not covered by any unit, SeekPC returns ErrUnknownPC and the
+// position of the reader is undefined.
+//
+// Because compilation units can describe multiple regions of the
+// executable, in the worst case SeekPC must search through all the
+// ranges in all the compilation units. Each call to SeekPC starts the
+// search at the compilation unit of the last call, so in general
+// looking up a series of PCs will be faster if they are sorted. If
+// the caller wishes to do repeated fast PC lookups, it should build
+// an appropriate index using the Ranges method.
+func (r *Reader) SeekPC(pc uint64) (*Entry, error) {
+ unit := r.unit
+ for i := 0; i < len(r.d.unit); i++ {
+ if unit >= len(r.d.unit) {
+ unit = 0
+ }
+ r.err = nil
+ r.lastChildren = false
+ r.unit = unit
+ u := &r.d.unit[unit]
+ r.b = makeBuf(r.d, u, "info", u.off, u.data)
+ e, err := r.Next()
+ if err != nil {
+ return nil, err
+ }
+ ranges, err := r.d.Ranges(e)
+ if err != nil {
+ return nil, err
+ }
+ for _, pcs := range ranges {
+ if pcs[0] <= pc && pc < pcs[1] {
+ return e, nil
+ }
+ }
+ unit++
+ }
+ return nil, ErrUnknownPC
+}
+
+// Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
+// Only some entry types, such as TagCompileUnit or TagSubprogram, have PC
+// ranges; for others, this will return nil with no error.
+func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
+ var ret [][2]uint64
+
+ low, lowOK := e.Val(AttrLowpc).(uint64)
+
+ var high uint64
+ var highOK bool
+ highField := e.AttrField(AttrHighpc)
+ if highField != nil {
+ switch highField.Class {
+ case ClassAddress:
+ high, highOK = highField.Val.(uint64)
+ case ClassConstant:
+ off, ok := highField.Val.(int64)
+ if ok {
+ high = low + uint64(off)
+ highOK = true
+ }
+ }
+ }
+
+ if lowOK && highOK {
+ ret = append(ret, [2]uint64{low, high})
+ }
+
+ ranges, rangesOK := e.Val(AttrRanges).(int64)
+ if rangesOK && d.ranges != nil {
+ // The initial base address is the lowpc attribute
+ // of the enclosing compilation unit.
+ // Although DWARF specifies the lowpc attribute,
+ // comments in gdb/dwarf2read.c say that some versions
+ // of GCC use the entrypc attribute, so we check that too.
+ var cu *Entry
+ if e.Tag == TagCompileUnit {
+ cu = e
+ } else {
+ i := d.offsetToUnit(e.Offset)
+ if i == -1 {
+ return nil, errors.New("no unit for entry")
+ }
+ u := &d.unit[i]
+ b := makeBuf(d, u, "info", u.off, u.data)
+ cu = b.entry(u.atable, u.base)
+ if b.err != nil {
+ return nil, b.err
+ }
+ }
+
+ var base uint64
+ if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
+ base = cuEntry
+ } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
+ base = cuLow
+ }
+
+ u := &d.unit[d.offsetToUnit(e.Offset)]
+ buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
+ for len(buf.data) > 0 {
+ low = buf.addr()
+ high = buf.addr()
+
+ if low == 0 && high == 0 {
+ break
+ }
+
+ if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
+ base = high
+ } else {
+ ret = append(ret, [2]uint64{base + low, base + high})
+ }
+ }
+ }
+
+ return ret, nil
+}
diff --git a/libgo/go/debug/dwarf/entry_test.go b/libgo/go/debug/dwarf/entry_test.go
index 8bd2d2a8ad..58a5d570be 100644
--- a/libgo/go/debug/dwarf/entry_test.go
+++ b/libgo/go/debug/dwarf/entry_test.go
@@ -6,6 +6,7 @@ package dwarf_test
import (
. "debug/dwarf"
+ "reflect"
"testing"
)
@@ -34,3 +35,103 @@ func TestSplit(t *testing.T) {
t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
}
}
+
+// wantRange maps from a PC to the ranges of the compilation unit
+// containing that PC.
+type wantRange struct {
+ pc uint64
+ ranges [][2]uint64
+}
+
+func TestReaderSeek(t *testing.T) {
+ want := []wantRange{
+ {0x40059d, [][2]uint64{{0x40059d, 0x400601}}},
+ {0x400600, [][2]uint64{{0x40059d, 0x400601}}},
+ {0x400601, [][2]uint64{{0x400601, 0x400611}}},
+ {0x4005f0, [][2]uint64{{0x40059d, 0x400601}}}, // loop test
+ {0x10, nil},
+ {0x400611, nil},
+ }
+ testRanges(t, "testdata/line-gcc.elf", want)
+}
+
+func TestRangesSection(t *testing.T) {
+ want := []wantRange{
+ {0x400500, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+ {0x400400, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+ {0x400548, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+ {0x400407, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+ {0x400408, nil},
+ {0x400449, nil},
+ {0x4003ff, nil},
+ }
+ testRanges(t, "testdata/ranges.elf", want)
+}
+
+func testRanges(t *testing.T, name string, want []wantRange) {
+ d := elfData(t, name)
+ r := d.Reader()
+ for _, w := range want {
+ entry, err := r.SeekPC(w.pc)
+ if err != nil {
+ if w.ranges != nil {
+ t.Errorf("%s: missing Entry for %#x", name, w.pc)
+ }
+ if err != ErrUnknownPC {
+ t.Errorf("%s: expected ErrUnknownPC for %#x, got %v", name, w.pc, err)
+ }
+ continue
+ }
+
+ ranges, err := d.Ranges(entry)
+ if err != nil {
+ t.Errorf("%s: %v", name, err)
+ continue
+ }
+ if !reflect.DeepEqual(ranges, w.ranges) {
+ t.Errorf("%s: for %#x got %x, expected %x", name, w.pc, ranges, w.ranges)
+ }
+ }
+}
+
+func TestReaderRanges(t *testing.T) {
+ d := elfData(t, "testdata/line-gcc.elf")
+
+ subprograms := []struct {
+ name string
+ ranges [][2]uint64
+ }{
+ {"f1", [][2]uint64{{0x40059d, 0x4005e7}}},
+ {"main", [][2]uint64{{0x4005e7, 0x400601}}},
+ {"f2", [][2]uint64{{0x400601, 0x400611}}},
+ }
+
+ r := d.Reader()
+ i := 0
+ for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
+ if entry.Tag != TagSubprogram {
+ continue
+ }
+
+ if i > len(subprograms) {
+ t.Fatalf("too many subprograms (expected at most %d)", i)
+ }
+
+ if got := entry.Val(AttrName).(string); got != subprograms[i].name {
+ t.Errorf("subprogram %d name is %s, expected %s", i, got, subprograms[i].name)
+ }
+ ranges, err := d.Ranges(entry)
+ if err != nil {
+ t.Errorf("subprogram %d: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(ranges, subprograms[i].ranges) {
+ t.Errorf("subprogram %d ranges are %x, expected %x", i, ranges, subprograms[i].ranges)
+ }
+ i++
+ }
+
+ if i < len(subprograms) {
+ t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms))
+ }
+}
diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go
index ca64bbd7f3..ed82feef92 100644
--- a/libgo/go/debug/dwarf/line.go
+++ b/libgo/go/debug/dwarf/line.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -361,7 +361,7 @@ func (r *LineReader) step(entry *LineEntry) bool {
// Special opcode [DWARF2 6.2.5.1, DWARF4 6.2.5.1]
adjustedOpcode := opcode - r.opcodeBase
r.advancePC(adjustedOpcode / r.lineRange)
- lineDelta := r.lineBase + int(adjustedOpcode)%r.lineRange
+ lineDelta := r.lineBase + adjustedOpcode%r.lineRange
r.state.Line += lineDelta
goto emit
}
diff --git a/libgo/go/debug/dwarf/line_test.go b/libgo/go/debug/dwarf/line_test.go
index 4104b5d49b..cc363f5478 100644
--- a/libgo/go/debug/dwarf/line_test.go
+++ b/libgo/go/debug/dwarf/line_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
index c1b3f37aca..0e9c01c2e9 100644
--- a/libgo/go/debug/dwarf/open.go
+++ b/libgo/go/debug/dwarf/open.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -78,9 +78,9 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
return d, nil
}
-// AddTypes will add one .debug_types section to the DWARF data. A
+// AddTypes will add one .debug_types section to the DWARF data. A
// typical object with DWARF version 4 debug info will have multiple
-// .debug_types sections. The name is used for error reporting only,
+// .debug_types sections. The name is used for error reporting only,
// and serves to distinguish one .debug_types section from another.
func (d *Data) AddTypes(name string, types []byte) error {
return d.parseTypes(name, types)
diff --git a/libgo/go/debug/dwarf/testdata/ranges.c b/libgo/go/debug/dwarf/testdata/ranges.c
new file mode 100644
index 0000000000..2f208e591c
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/ranges.c
@@ -0,0 +1,25 @@
+// gcc -g -O2 -freorder-blocks-and-partition
+
+const char *arr[10000];
+const char *hot = "hot";
+const char *cold = "cold";
+
+__attribute__((noinline))
+void fn(int path) {
+ int i;
+
+ if (path) {
+ for (i = 0; i < sizeof arr / sizeof arr[0]; i++) {
+ arr[i] = hot;
+ }
+ } else {
+ for (i = 0; i < sizeof arr / sizeof arr[0]; i++) {
+ arr[i] = cold;
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ fn(argc);
+ return 0;
+}
diff --git a/libgo/go/debug/dwarf/testdata/ranges.elf b/libgo/go/debug/dwarf/testdata/ranges.elf
new file mode 100644
index 0000000000..7f54138cff
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/ranges.elf
Binary files differ
diff --git a/libgo/go/debug/dwarf/testdata/typedef.c b/libgo/go/debug/dwarf/testdata/typedef.c
index f05f01564f..4780a0b2ba 100644
--- a/libgo/go/debug/dwarf/testdata/typedef.c
+++ b/libgo/go/debug/dwarf/testdata/typedef.c
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index c76a472d78..9b39078a6f 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -356,7 +356,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
}
// Get Type referred to by Entry's AttrType field.
- // Set err if error happens. Not having a type is an error.
+ // Set err if error happens. Not having a type is an error.
typeOf := func(e *Entry) Type {
tval := e.Val(AttrType)
var t Type
@@ -549,7 +549,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
bito = f.ByteOffset * 8
}
if bito == lastFieldBitOffset && t.Kind != "union" {
- // Last field was zero width. Fix array length.
+ // Last field was zero width. Fix array length.
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
zeroArray(lastFieldType)
}
@@ -560,7 +560,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
if t.Kind != "union" {
b, ok := e.Val(AttrByteSize).(int64)
if ok && b*8 == lastFieldBitOffset {
- // Final field must be zero width. Fix array length.
+ // Final field must be zero width. Fix array length.
zeroArray(lastFieldType)
}
}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
index ad6308deba..0283466f08 100644
--- a/libgo/go/debug/dwarf/type_test.go
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -34,7 +34,7 @@ var typedefTests = map[string]string{
}
// As Apple converts gcc to a clang-based front end
-// they keep breaking the DWARF output. This map lists the
+// they keep breaking the DWARF output. This map lists the
// conversion from real answer to Apple answer.
var machoBug = map[string]string{
"func(*char, ...) void": "func(*char) void",
diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go
index 0f4e07ebf7..652e02d917 100644
--- a/libgo/go/debug/dwarf/typeunit.go
+++ b/libgo/go/debug/dwarf/typeunit.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -9,11 +9,11 @@ import (
"strconv"
)
-// Parse the type units stored in a DWARF4 .debug_types section. Each
+// Parse the type units stored in a DWARF4 .debug_types section. Each
// type unit defines a single primary type and an 8-byte signature.
// Other sections may then use formRefSig8 to refer to the type.
-// The typeUnit format is a single type with a signature. It holds
+// The typeUnit format is a single type with a signature. It holds
// the same data as a compilation unit.
type typeUnit struct {
unit
@@ -76,7 +76,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
data: b.bytes(int(n - (b.off - hdroff))),
atable: atable,
asize: int(asize),
- vers: int(vers),
+ vers: vers,
is64: dwarf64,
},
toff: Offset(toff),
@@ -101,7 +101,7 @@ func (d *Data) sigToType(sig uint64) (Type, error) {
b := makeBuf(d, tu, tu.name, tu.off, tu.data)
r := &typeUnitReader{d: d, tu: tu, b: b}
- t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type), nil)
+ t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil)
if err != nil {
return nil, err
}
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index ceb6cdbff3..e45aed7ad1 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
index 6086b54b9f..6e6c801a49 100644
--- a/libgo/go/debug/elf/elf.go
+++ b/libgo/go/debug/elf/elf.go
@@ -15,7 +15,7 @@
*
* Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
* Copyright (c) 2001 David E. O'Brien
- * Portions Copyright 2009 The Go Authors. All rights reserved.
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1285,7 +1285,7 @@ const (
R_MIPS_LITERAL R_MIPS = 8 /* Reference to literal section */
R_MIPS_GOT16 R_MIPS = 9 /* Reference to global offset table */
R_MIPS_PC16 R_MIPS = 10 /* 16 bit PC relative reference */
- R_MIPS_CALL16 R_MIPS = 11 /* 16 bit call thru glbl offset tbl */
+ R_MIPS_CALL16 R_MIPS = 11 /* 16 bit call through glbl offset tbl */
R_MIPS_GPREL32 R_MIPS = 12
R_MIPS_SHIFT5 R_MIPS = 16
R_MIPS_SHIFT6 R_MIPS = 17
@@ -1725,37 +1725,71 @@ var rppc64Strings = []intName{
func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) }
func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
-// Relocation types for s390
+// Relocation types for s390x processors.
type R_390 int
const (
- R_390_NONE R_390 = 0
- R_390_8 R_390 = 1
- R_390_12 R_390 = 2
- R_390_16 R_390 = 3
- R_390_32 R_390 = 4
- R_390_PC32 R_390 = 5
- R_390_GOT12 R_390 = 6
- R_390_GOT32 R_390 = 7
- R_390_PLT32 R_390 = 8
- R_390_COPY R_390 = 9
- R_390_GLOB_DAT R_390 = 10
- R_390_JMP_SLOT R_390 = 11
- R_390_RELATIVE R_390 = 12
- R_390_GOTOFF R_390 = 13
- R_390_GOTPC R_390 = 14
- R_390_GOT16 R_390 = 15
- R_390_PC16 R_390 = 16
- R_390_PC16DBL R_390 = 17
- R_390_PLT16DBL R_390 = 18
- R_390_PC32DBL R_390 = 19
- R_390_PLT32DBL R_390 = 20
- R_390_GOTPCDBL R_390 = 21
- R_390_64 R_390 = 22
- R_390_PC64 R_390 = 23
- R_390_GOT64 R_390 = 24
- R_390_PLT64 R_390 = 25
- R_390_GOTENT R_390 = 26
+ R_390_NONE R_390 = 0
+ R_390_8 R_390 = 1
+ R_390_12 R_390 = 2
+ R_390_16 R_390 = 3
+ R_390_32 R_390 = 4
+ R_390_PC32 R_390 = 5
+ R_390_GOT12 R_390 = 6
+ R_390_GOT32 R_390 = 7
+ R_390_PLT32 R_390 = 8
+ R_390_COPY R_390 = 9
+ R_390_GLOB_DAT R_390 = 10
+ R_390_JMP_SLOT R_390 = 11
+ R_390_RELATIVE R_390 = 12
+ R_390_GOTOFF R_390 = 13
+ R_390_GOTPC R_390 = 14
+ R_390_GOT16 R_390 = 15
+ R_390_PC16 R_390 = 16
+ R_390_PC16DBL R_390 = 17
+ R_390_PLT16DBL R_390 = 18
+ R_390_PC32DBL R_390 = 19
+ R_390_PLT32DBL R_390 = 20
+ R_390_GOTPCDBL R_390 = 21
+ R_390_64 R_390 = 22
+ R_390_PC64 R_390 = 23
+ R_390_GOT64 R_390 = 24
+ R_390_PLT64 R_390 = 25
+ R_390_GOTENT R_390 = 26
+ R_390_GOTOFF16 R_390 = 27
+ R_390_GOTOFF64 R_390 = 28
+ R_390_GOTPLT12 R_390 = 29
+ R_390_GOTPLT16 R_390 = 30
+ R_390_GOTPLT32 R_390 = 31
+ R_390_GOTPLT64 R_390 = 32
+ R_390_GOTPLTENT R_390 = 33
+ R_390_GOTPLTOFF16 R_390 = 34
+ R_390_GOTPLTOFF32 R_390 = 35
+ R_390_GOTPLTOFF64 R_390 = 36
+ R_390_TLS_LOAD R_390 = 37
+ R_390_TLS_GDCALL R_390 = 38
+ R_390_TLS_LDCALL R_390 = 39
+ R_390_TLS_GD32 R_390 = 40
+ R_390_TLS_GD64 R_390 = 41
+ R_390_TLS_GOTIE12 R_390 = 42
+ R_390_TLS_GOTIE32 R_390 = 43
+ R_390_TLS_GOTIE64 R_390 = 44
+ R_390_TLS_LDM32 R_390 = 45
+ R_390_TLS_LDM64 R_390 = 46
+ R_390_TLS_IE32 R_390 = 47
+ R_390_TLS_IE64 R_390 = 48
+ R_390_TLS_IEENT R_390 = 49
+ R_390_TLS_LE32 R_390 = 50
+ R_390_TLS_LE64 R_390 = 51
+ R_390_TLS_LDO32 R_390 = 52
+ R_390_TLS_LDO64 R_390 = 53
+ R_390_TLS_DTPMOD R_390 = 54
+ R_390_TLS_DTPOFF R_390 = 55
+ R_390_TLS_TPOFF R_390 = 56
+ R_390_20 R_390 = 57
+ R_390_GOT20 R_390 = 58
+ R_390_GOTPLT20 R_390 = 59
+ R_390_TLS_GOTIE20 R_390 = 60
)
var r390Strings = []intName{
@@ -1786,6 +1820,40 @@ var r390Strings = []intName{
{24, "R_390_GOT64"},
{25, "R_390_PLT64"},
{26, "R_390_GOTENT"},
+ {27, "R_390_GOTOFF16"},
+ {28, "R_390_GOTOFF64"},
+ {29, "R_390_GOTPLT12"},
+ {30, "R_390_GOTPLT16"},
+ {31, "R_390_GOTPLT32"},
+ {32, "R_390_GOTPLT64"},
+ {33, "R_390_GOTPLTENT"},
+ {34, "R_390_GOTPLTOFF16"},
+ {35, "R_390_GOTPLTOFF32"},
+ {36, "R_390_GOTPLTOFF64"},
+ {37, "R_390_TLS_LOAD"},
+ {38, "R_390_TLS_GDCALL"},
+ {39, "R_390_TLS_LDCALL"},
+ {40, "R_390_TLS_GD32"},
+ {41, "R_390_TLS_GD64"},
+ {42, "R_390_TLS_GOTIE12"},
+ {43, "R_390_TLS_GOTIE32"},
+ {44, "R_390_TLS_GOTIE64"},
+ {45, "R_390_TLS_LDM32"},
+ {46, "R_390_TLS_LDM64"},
+ {47, "R_390_TLS_IE32"},
+ {48, "R_390_TLS_IE64"},
+ {49, "R_390_TLS_IEENT"},
+ {50, "R_390_TLS_LE32"},
+ {51, "R_390_TLS_LE64"},
+ {52, "R_390_TLS_LDO32"},
+ {53, "R_390_TLS_LDO64"},
+ {54, "R_390_TLS_DTPMOD"},
+ {55, "R_390_TLS_DTPOFF"},
+ {56, "R_390_TLS_TPOFF"},
+ {57, "R_390_20"},
+ {58, "R_390_GOT20"},
+ {59, "R_390_GOTPLT20"},
+ {60, "R_390_TLS_GOTIE20"},
}
func (i R_390) String() string { return stringName(uint32(i), r390Strings, false) }
@@ -1962,7 +2030,7 @@ type Prog32 struct {
Align uint32 /* Alignment in memory and file. */
}
-// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
+// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
type Dyn32 struct {
Tag int32 /* Entry type. */
Val uint32 /* Integer/Address value. */
@@ -1992,8 +2060,8 @@ type Rela32 struct {
Addend int32 /* Addend. */
}
-func R_SYM32(info uint32) uint32 { return uint32(info >> 8) }
-func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) }
+func R_SYM32(info uint32) uint32 { return info >> 8 }
+func R_TYPE32(info uint32) uint32 { return info & 0xff }
func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
// ELF32 Symbol.
@@ -2063,7 +2131,7 @@ type Prog64 struct {
Align uint64 /* Alignment in memory and file. */
}
-// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
+// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
type Dyn64 struct {
Tag int64 /* Entry type. */
Val uint64 /* Integer/address value */
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
index e3c51bb717..f8985a8992 100644
--- a/libgo/go/debug/elf/elf_test.go
+++ b/libgo/go/debug/elf/elf_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index b028772bfb..8eeab65df8 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
switch f.Class {
case ELFCLASS32:
hdr := new(Header32)
- sr.Seek(0, os.SEEK_SET)
+ sr.Seek(0, io.SeekStart)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
@@ -288,13 +288,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
shstrndx = int(hdr.Shstrndx)
case ELFCLASS64:
hdr := new(Header64)
- sr.Seek(0, os.SEEK_SET)
+ sr.Seek(0, io.SeekStart)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
f.Type = Type(hdr.Type)
f.Machine = Machine(hdr.Machine)
- f.Entry = uint64(hdr.Entry)
+ f.Entry = hdr.Entry
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
@@ -315,7 +315,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
f.Progs = make([]*Prog, phnum)
for i := 0; i < phnum; i++ {
off := phoff + int64(i)*int64(phentsize)
- sr.Seek(off, os.SEEK_SET)
+ sr.Seek(off, io.SeekStart)
p := new(Prog)
switch f.Class {
case ELFCLASS32:
@@ -341,12 +341,12 @@ func NewFile(r io.ReaderAt) (*File, error) {
p.ProgHeader = ProgHeader{
Type: ProgType(ph.Type),
Flags: ProgFlag(ph.Flags),
- Off: uint64(ph.Off),
- Vaddr: uint64(ph.Vaddr),
- Paddr: uint64(ph.Paddr),
- Filesz: uint64(ph.Filesz),
- Memsz: uint64(ph.Memsz),
- Align: uint64(ph.Align),
+ Off: ph.Off,
+ Vaddr: ph.Vaddr,
+ Paddr: ph.Paddr,
+ Filesz: ph.Filesz,
+ Memsz: ph.Memsz,
+ Align: ph.Align,
}
}
p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
@@ -359,7 +359,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
names := make([]uint32, shnum)
for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize)
- sr.Seek(off, os.SEEK_SET)
+ sr.Seek(off, io.SeekStart)
s := new(Section)
switch f.Class {
case ELFCLASS32:
@@ -374,8 +374,8 @@ func NewFile(r io.ReaderAt) (*File, error) {
Addr: uint64(sh.Addr),
Offset: uint64(sh.Off),
FileSize: uint64(sh.Size),
- Link: uint32(sh.Link),
- Info: uint32(sh.Info),
+ Link: sh.Link,
+ Info: sh.Info,
Addralign: uint64(sh.Addralign),
Entsize: uint64(sh.Entsize),
}
@@ -388,13 +388,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
- Offset: uint64(sh.Off),
- FileSize: uint64(sh.Size),
- Addr: uint64(sh.Addr),
- Link: uint32(sh.Link),
- Info: uint32(sh.Info),
- Addralign: uint64(sh.Addralign),
- Entsize: uint64(sh.Entsize),
+ Offset: sh.Off,
+ FileSize: sh.Size,
+ Addr: sh.Addr,
+ Link: sh.Link,
+ Info: sh.Info,
+ Addralign: sh.Addralign,
+ Entsize: sh.Entsize,
}
}
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
@@ -579,7 +579,7 @@ func (f *File) Section(name string) *Section {
}
// applyRelocations applies relocations to dst. rels is a relocations section
-// in RELA format.
+// in REL or RELA format.
func (f *File) applyRelocations(dst []byte, rels []byte) error {
switch {
case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
@@ -594,10 +594,14 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
return f.applyRelocationsPPC(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
return f.applyRelocationsPPC64(dst, rels)
+ case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
+ return f.applyRelocationsMIPS(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
return f.applyRelocationsMIPS64(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_S390:
- return f.applyRelocationsS390x(dst, rels)
+ return f.applyRelocationss390x(dst, rels)
+ case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
+ return f.applyRelocationsSPARC64(dst, rels)
default:
return errors.New("applyRelocations: not implemented")
}
@@ -861,6 +865,44 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
+ // 8 is the size of Rel32.
+ if len(rels)%8 != 0 {
+ return errors.New("length of relocation section is not a multiple of 8")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rel Rel32
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rel)
+ symNo := rel.Info >> 8
+ t := R_MIPS(rel.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+
+ switch t {
+ case R_MIPS_32:
+ if rel.Off+4 >= uint32(len(dst)) {
+ continue
+ }
+ val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
+ val += uint32(sym.Value)
+ f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+ }
+ }
+
+ return nil
+}
+
func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
// 24 is the size of Rela64.
if len(rels)%24 != 0 {
@@ -913,7 +955,7 @@ func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
return nil
}
-func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
+func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
// 24 is the size of Rela64.
if len(rels)%24 != 0 {
return errors.New("length of relocation section is not a multiple of 24")
@@ -924,7 +966,7 @@ func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
return err
}
- b := bytes.NewBuffer(rels)
+ b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
@@ -936,18 +978,71 @@ func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
continue
}
sym := &symbols[symNo-1]
+ switch SymType(sym.Info & 0xf) {
+ case STT_SECTION, STT_NOTYPE:
+ break
+ default:
+ continue
+ }
switch t {
case R_390_64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)+uint64(sym.Value))
+ val := sym.Value + uint64(rela.Addend)
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
case R_390_32:
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)+uint32(sym.Value))
+ val := uint32(sym.Value) + uint32(rela.Addend)
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
+ }
+ }
+
+ return nil
+}
+
+func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_SPARC(rela.Info & 0xff)
+
+ if symNo == 0 || symNo > uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_SPARC_64, R_SPARC_UA64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_SPARC_32, R_SPARC_UA32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
}
}
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
index 5c0df0f1e9..58bdf277d3 100644
--- a/libgo/go/debug/elf/file_test.go
+++ b/libgo/go/debug/elf/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -473,6 +473,82 @@ var relocationTests = []relocationTest{
},
},
{
+ "testdata/go-relocation-test-gcc531-s390x.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: int64(58), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc620-sparc64.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc492-mipsle.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc540-mips.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C11 5.4.0 20160609 -meb -mips32 -mtune=mips32r2 -mfpxx -mllsc -mno-shared -mabi=32 -g -gdwarf-2", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: uint64(0x5c), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
"testdata/go-relocation-test-gcc493-mips64le.obj",
[]relocationTestEntry{
{0, &dwarf.Entry{
@@ -636,7 +712,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 {
@@ -649,11 +725,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)
@@ -669,7 +745,7 @@ func TestCompressedSection(t *testing.T) {
if end > int64(len(buf)) {
end = int64(len(buf))
}
- n, err := sf.Read(buf[pos:end])
+ n, err := io.ReadFull(sf, buf[pos:end])
if err != nil {
t.Fatal(err)
}
diff --git a/libgo/go/debug/elf/reader.go b/libgo/go/debug/elf/reader.go
index 17b57165bc..eab437318d 100644
--- a/libgo/go/debug/elf/reader.go
+++ b/libgo/go/debug/elf/reader.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -63,11 +63,11 @@ func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
var newOffset int64
switch whence {
- case 0:
+ case io.SeekStart:
newOffset = offset
- case 1:
+ case io.SeekCurrent:
newOffset = r.offset + offset
- case 2:
+ case io.SeekEnd:
newOffset = r.size + offset
default:
return 0, os.ErrInvalid
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj
new file mode 100644
index 0000000000..a5fbcfbbdd
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj
new file mode 100644
index 0000000000..caacb9b90a
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc540-mips.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc540-mips.obj
new file mode 100644
index 0000000000..270c777596
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc540-mips.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj
new file mode 100644
index 0000000000..d65c23e1cb
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/hello-world-core.gz b/libgo/go/debug/elf/testdata/hello-world-core.gz
index 806af6edbc..6d76ab0934 100644
--- a/libgo/go/debug/elf/testdata/hello-world-core.gz
+++ b/libgo/go/debug/elf/testdata/hello-world-core.gz
Binary files differ
diff --git a/libgo/go/debug/gosym/pclntab.go b/libgo/go/debug/gosym/pclntab.go
index 6620aefb05..ba1cf8b699 100644
--- a/libgo/go/debug/gosym/pclntab.go
+++ b/libgo/go/debug/gosym/pclntab.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -53,7 +53,7 @@ const oldQuantum = 1
func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
// The PC/line table can be thought of as a sequence of
// <pc update>* <line update>
- // batches. Each update batch results in a (pc, line) pair,
+ // batches. Each update batch results in a (pc, line) pair,
// where line applies to every PC from pc up to but not
// including the pc of the next pair.
//
@@ -167,7 +167,7 @@ func (t *LineTable) go12Init() {
// Check header: 4-byte magic, two zeros, pc quantum, pointer size.
t.go12 = -1 // not Go 1.2 until proven otherwise
if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
- (t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
+ (t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) || // pc quantum
(t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
return
}
@@ -207,8 +207,8 @@ func (t *LineTable) go12Funcs() []Func {
funcs := make([]Func, n)
for i := range funcs {
f := &funcs[i]
- f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
- f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+ f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
+ f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
f.LineTable = t
f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
@@ -295,9 +295,6 @@ func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
// off is the offset to the beginning of the pc-value table,
// and entry is the start PC for the corresponding function.
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
- if off == 0 {
- return -1
- }
p := t.Data[off:]
val := int32(-1)
diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go
index 8d4aa547a0..7e7cee6793 100644
--- a/libgo/go/debug/gosym/pclntab_test.go
+++ b/libgo/go/debug/gosym/pclntab_test.go
@@ -1,10 +1,11 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gosym
import (
+ "bytes"
"debug/elf"
"internal/testenv"
"io/ioutil"
@@ -36,13 +37,28 @@ func dotest(t *testing.T) {
// the resulting binary looks like it was built from pclinetest.s,
// but we have renamed it to keep it away from the go tool.
pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
- cmd := exec.Command("go", "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
t.Fatal(err)
}
- cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
+
+ // 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(testenv.GoToolPath(t), "tool", "link", "-H", "linux",
"-o", pclinetestBinary, pclinetestBinary+".o")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -111,8 +127,6 @@ func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
return f, tab
}
-var goarch = os.Getenv("O")
-
func TestLineFromAline(t *testing.T) {
skipIfNotELF(t)
@@ -210,6 +224,7 @@ func TestPCLine(t *testing.T) {
defer endtest()
f, tab := crack(pclinetestBinary, t)
+ defer f.Close()
text := f.Section(".text")
textdat, err := text.Data()
if err != nil {
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
index 46f0783344..f5f9963095 100644
--- a/libgo/go/debug/gosym/symtab.go
+++ b/libgo/go/debug/gosym/symtab.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,7 +8,7 @@
package gosym
// The table format is a variant of the format used in Plan 9's a.out
-// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// format, documented at https://9p.io/magic/man2html/6/a.out.
// The best reference for the differences between the Plan 9 format
// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
@@ -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.
@@ -103,7 +112,7 @@ type Obj struct {
* Symbol tables
*/
-// Table represents a Go symbol table. It stores all of the
+// Table represents a Go symbol table. It stores all of the
// symbols decoded from the program and provides methods to translate
// between symbols, names, and addresses.
type Table struct {
@@ -294,8 +303,8 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
t.Syms = t.Syms[0 : n+1]
ts := &t.Syms[n]
ts.Type = s.typ
- ts.Value = uint64(s.value)
- ts.GoType = uint64(s.gotype)
+ ts.Value = s.value
+ ts.GoType = s.gotype
switch s.typ {
default:
// rewrite name to use . instead of · (c2 b7)
@@ -353,7 +362,7 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
}
// Count text symbols and attach frame sizes, parameters, and
- // locals to them. Also, find object file boundaries.
+ // locals to them. Also, find object file boundaries.
lastf := 0
for i := 0; i < len(t.Syms); i++ {
sym := &t.Syms[i]
@@ -503,7 +512,7 @@ func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
}
// LineToPC looks up the first program counter on the given line in
-// the named file. It returns UnknownPathError or UnknownLineError if
+// the named file. It returns UnknownPathError or UnknownLineError if
// there is an error looking up this line.
func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
obj, ok := t.Files[file]
diff --git a/libgo/go/debug/gosym/symtab_test.go b/libgo/go/debug/gosym/symtab_test.go
new file mode 100644
index 0000000000..08e86336b8
--- /dev/null
+++ b/libgo/go/debug/gosym/symtab_test.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gosym
+
+import (
+ "fmt"
+ "testing"
+)
+
+func assertString(t *testing.T, dsc, out, tgt string) {
+ if out != tgt {
+ t.Fatalf("Expected: %q Actual: %q for %s", tgt, out, dsc)
+ }
+}
+
+func TestStandardLibPackage(t *testing.T) {
+ s1 := Sym{Name: "io.(*LimitedReader).Read"}
+ s2 := Sym{Name: "io.NewSectionReader"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "io")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "io")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LimitedReader)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestStandardLibPathPackage(t *testing.T) {
+ s1 := Sym{Name: "debug/gosym.(*LineTable).PCToLine"}
+ s2 := Sym{Name: "debug/gosym.NewTable"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "debug/gosym")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "debug/gosym")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LineTable)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestRemotePackage(t *testing.T) {
+ s1 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.(*FlagSet).PrintDefaults"}
+ s2 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.PrintDefaults"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*FlagSet)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
diff --git a/libgo/go/debug/macho/fat.go b/libgo/go/debug/macho/fat.go
index 93b8315263..6bd730dc0b 100644
--- a/libgo/go/debug/macho/fat.go
+++ b/libgo/go/debug/macho/fat.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -122,18 +122,18 @@ func NewFatFile(r io.ReaderAt) (*FatFile, error) {
// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
// universal binary.
-func OpenFat(name string) (ff *FatFile, err error) {
+func OpenFat(name string) (*FatFile, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
- ff, err = NewFatFile(f)
+ ff, err := NewFatFile(f)
if err != nil {
f.Close()
return nil, err
}
ff.closer = f
- return
+ return ff, nil
}
func (ff *FatFile) Close() error {
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index a7599aa5b2..223346f10d 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -474,7 +474,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the ones the debug/dwarf package uses.
// Don't bother loading others.
- var names = [...]string{"abbrev", "info", "line", "str"}
+ var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
var dat [len(names)][]byte
for i, name := range names {
name = "__debug_" + name
@@ -489,8 +489,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
dat[i] = b
}
- abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
- return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+ abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+ return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
}
// ImportedSymbols returns the names of all symbols
diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go
index 4797780ce7..9ff6c5d96e 100644
--- a/libgo/go/debug/macho/file_test.go
+++ b/libgo/go/debug/macho/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go
index d9678c8eda..40ac74e9a1 100644
--- a/libgo/go/debug/macho/macho.go
+++ b/libgo/go/debug/macho/macho.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -145,7 +145,7 @@ type Section32 struct {
Reserve2 uint32
}
-// A Section32 is a 64-bit Mach-O section header.
+// A Section64 is a 64-bit Mach-O section header.
type Section64 struct {
Name [16]byte
Seg [16]byte
@@ -291,26 +291,3 @@ func stringName(i uint32, names []intName, goSyntax bool) string {
}
return strconv.FormatUint(uint64(i), 10)
}
-
-func flagName(i uint32, names []intName, goSyntax bool) string {
- s := ""
- for _, n := range names {
- if n.i&i == n.i {
- if len(s) > 0 {
- s += "+"
- }
- if goSyntax {
- s += "macho."
- }
- s += n.s
- i -= n.i
- }
- }
- if len(s) == 0 {
- return "0x" + strconv.FormatUint(uint64(i), 16)
- }
- if i != 0 {
- s += "+0x" + strconv.FormatUint(uint64(i), 16)
- }
- return s
-}
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
index 3df4ae7368..87f225cb39 100644
--- a/libgo/go/debug/pe/file.go
+++ b/libgo/go/debug/pe/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,95 +8,26 @@ package pe
import (
"debug/dwarf"
"encoding/binary"
- "errors"
"fmt"
"io"
"os"
- "strconv"
)
+// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap.
+const seekStart = 0
+
// A File represents an open PE file.
type File struct {
FileHeader
OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
Sections []*Section
- Symbols []*Symbol
+ Symbols []*Symbol // COFF symbols with auxiliary symbol records removed
+ COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
+ StringTable StringTable
closer io.Closer
}
-type SectionHeader struct {
- Name string
- VirtualSize uint32
- VirtualAddress uint32
- Size uint32
- Offset uint32
- PointerToRelocations uint32
- PointerToLineNumbers uint32
- NumberOfRelocations uint16
- NumberOfLineNumbers uint16
- Characteristics uint32
-}
-
-type Section struct {
- SectionHeader
-
- // Embed ReaderAt for ReadAt method.
- // Do not embed SectionReader directly
- // to avoid having Read and Seek.
- // If a client wants Read and Seek it must use
- // Open() to avoid fighting over the seek offset
- // with other clients.
- io.ReaderAt
- sr *io.SectionReader
-}
-
-type Symbol struct {
- Name string
- Value uint32
- SectionNumber int16
- Type uint16
- StorageClass uint8
-}
-
-type ImportDirectory struct {
- OriginalFirstThunk uint32
- TimeDateStamp uint32
- ForwarderChain uint32
- Name uint32
- FirstThunk uint32
-
- dll string
-}
-
-// Data reads and returns the contents of the PE section.
-func (s *Section) Data() ([]byte, error) {
- dat := make([]byte, s.sr.Size())
- n, err := s.sr.ReadAt(dat, 0)
- if n == len(dat) {
- err = nil
- }
- return dat[0:n], err
-}
-
-// Open returns a new ReadSeeker reading the PE section.
-func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
-
-type FormatError struct {
- off int64
- msg string
- val interface{}
-}
-
-func (e *FormatError) Error() string {
- msg := e.msg
- if e.val != nil {
- msg += fmt.Sprintf(" '%v'", e.val)
- }
- msg += fmt.Sprintf(" in record at byte %#x", e.off)
- return msg
-}
-
// Open opens the named file using os.Open and prepares it for use as a PE binary.
func Open(name string) (*File, error) {
f, err := os.Open(name)
@@ -129,6 +60,8 @@ var (
sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
)
+// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance)
+
// NewFile creates a new File for accessing a PE binary in an underlying reader.
func NewFile(r io.ReaderAt) (*File, error) {
f := new(File)
@@ -144,66 +77,42 @@ func NewFile(r io.ReaderAt) (*File, error) {
var sign [4]byte
r.ReadAt(sign[:], signoff)
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
- return nil, errors.New("Invalid PE File Format.")
+ return nil, fmt.Errorf("Invalid PE COFF file signature of %v.", sign)
}
base = signoff + 4
} else {
base = int64(0)
}
- sr.Seek(base, os.SEEK_SET)
+ sr.Seek(base, seekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
- if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
- return nil, errors.New("Invalid PE File Format.")
+ switch f.FileHeader.Machine {
+ case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386:
+ default:
+ return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x.", f.FileHeader.Machine)
}
- var ss []byte
- if f.FileHeader.NumberOfSymbols > 0 {
- // Get COFF string table, which is located at the end of the COFF symbol table.
- sr.Seek(int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
- var l uint32
- if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
- return nil, err
- }
- ss = make([]byte, l)
- if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols)); err != nil {
- return nil, err
- }
+ var err error
- // Process COFF symbol table.
- sr.Seek(int64(f.FileHeader.PointerToSymbolTable), os.SEEK_SET)
- aux := uint8(0)
- for i := 0; i < int(f.FileHeader.NumberOfSymbols); i++ {
- cs := new(COFFSymbol)
- if err := binary.Read(sr, binary.LittleEndian, cs); err != nil {
- return nil, err
- }
- if aux > 0 {
- aux--
- continue
- }
- var name string
- if cs.Name[0] == 0 && cs.Name[1] == 0 && cs.Name[2] == 0 && cs.Name[3] == 0 {
- si := int(binary.LittleEndian.Uint32(cs.Name[4:]))
- name, _ = getString(ss, si)
- } else {
- name = cstring(cs.Name[:])
- }
- aux = cs.NumberOfAuxSymbols
- s := &Symbol{
- Name: name,
- Value: cs.Value,
- SectionNumber: cs.SectionNumber,
- Type: cs.Type,
- StorageClass: cs.StorageClass,
- }
- f.Symbols = append(f.Symbols, s)
- }
+ // Read string table.
+ f.StringTable, err = readStringTable(&f.FileHeader, sr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Read symbol table.
+ f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
+ if err != nil {
+ return nil, err
+ }
+ f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
+ if err != nil {
+ return nil, err
}
// Read optional header.
- sr.Seek(base, os.SEEK_SET)
+ sr.Seek(base, seekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
@@ -235,12 +144,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
return nil, err
}
- var name string
- if sh.Name[0] == '\x2F' {
- si, _ := strconv.Atoi(cstring(sh.Name[1:]))
- name, _ = getString(ss, si)
- } else {
- name = cstring(sh.Name[0:])
+ name, err := sh.fullName(f.StringTable)
+ if err != nil {
+ return nil, err
}
s := new(Section)
s.SectionHeader = SectionHeader{
@@ -255,18 +161,34 @@ func NewFile(r io.ReaderAt) (*File, error) {
NumberOfLineNumbers: sh.NumberOfLineNumbers,
Characteristics: sh.Characteristics,
}
- s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+ r2 := r
+ if sh.PointerToRawData == 0 { // .bss must have all 0s
+ r2 = zeroReaderAt{}
+ }
+ s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
s.ReaderAt = s.sr
f.Sections[i] = s
}
+ for i := range f.Sections {
+ var err error
+ f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
+ if err != nil {
+ return nil, err
+ }
+ }
+
return f, nil
}
-func cstring(b []byte) string {
- var i int
- for i = 0; i < len(b) && b[i] != 0; i++ {
+// zeroReaderAt is ReaderAt that reads 0s.
+type zeroReaderAt struct{}
+
+// ReadAt writes len(p) 0s into p.
+func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
+ for i := range p {
+ p[i] = 0
}
- return string(b[0:i])
+ return len(p), nil
}
// getString extracts a string from symbol string table.
@@ -298,7 +220,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the ones the debug/dwarf package uses.
// Don't bother loading others.
- var names = [...]string{"abbrev", "info", "line", "str"}
+ var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
var dat [len(names)][]byte
for i, name := range names {
name = ".debug_" + name
@@ -316,8 +238,20 @@ func (f *File) DWARF() (*dwarf.Data, error) {
dat[i] = b
}
- abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
- return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+ abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+ return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+}
+
+// TODO(brainman): document ImportDirectory once we decide what to do with it.
+
+type ImportDirectory struct {
+ OriginalFirstThunk uint32
+ TimeDateStamp uint32
+ ForwarderChain uint32
+ Name uint32
+ FirstThunk uint32
+
+ dll string
}
// ImportedSymbols returns the names of all symbols
@@ -347,6 +281,12 @@ func (f *File) ImportedSymbols() ([]string, error) {
}
ida = append(ida, dt)
}
+ // TODO(brainman): this needs to be rewritten
+ // ds.Data() return contets of .idata section. Why store in variable called "names"?
+ // Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere.
+ // getString does not extracts a string from symbol string table (as getString doco says).
+ // Why ds.Data() called again and again in the loop?
+ // Needs test before rewrite.
names, _ := ds.Data()
var all []string
for _, dt := range ida {
@@ -395,3 +335,12 @@ func (f *File) ImportedLibraries() ([]string, error) {
// cgo -dynimport don't use this for windows PE, so just return.
return nil, nil
}
+
+// FormatError is unused.
+// The type is retained for compatibility.
+type FormatError struct {
+}
+
+func (e *FormatError) Error() string {
+ return "unknown error"
+}
diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go
index 316a569ede..5a740c8705 100644
--- a/libgo/go/debug/pe/file_test.go
+++ b/libgo/go/debug/pe/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,6 +6,7 @@ package pe
import (
"debug/dwarf"
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -104,6 +105,41 @@ var fileTests = []fileTest{
},
},
{
+ file: "testdata/gcc-386-mingw-no-symbols-exec",
+ hdr: FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
+ opthdr: &OptionalHeader32{0x10b, 0x2, 0x18, 0xe00, 0x1e00, 0x200, 0x1280, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x9000, 0x400, 0x5306, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+ [16]DataDirectory{
+ {0x0, 0x0},
+ {0x6000, 0x378},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x8004, 0x18},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x60b8, 0x7c},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ },
+ },
+ sections: []*SectionHeader{
+ {".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
+ {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
+ {".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ },
+ hasNoDwarfInfo: true,
+ },
+ {
file: "testdata/gcc-amd64-mingw-obj",
hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
sections: []*SectionHeader{
@@ -271,7 +307,7 @@ func main() {
src := filepath.Join(tmpdir, "a.go")
exe := filepath.Join(tmpdir, "a.exe")
err = ioutil.WriteFile(src, []byte(prog), 0644)
- output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
+ output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
if err != nil {
t.Fatalf("building test executable failed: %s %s", err, output)
}
@@ -307,3 +343,75 @@ func main() {
}
t.Fatal("main.main not found")
}
+
+func TestBSSHasZeros(t *testing.T) {
+ testenv.MustHaveExec(t)
+
+ if runtime.GOOS != "windows" {
+ t.Skip("skipping windows only test")
+ }
+ gccpath, err := exec.LookPath("gcc")
+ if err != nil {
+ t.Skip("skipping test: gcc is missing")
+ }
+
+ tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ srcpath := filepath.Join(tmpdir, "a.c")
+ src := `
+#include <stdio.h>
+
+int zero = 0;
+
+int
+main(void)
+{
+ printf("%d\n", zero);
+ return 0;
+}
+`
+ err = ioutil.WriteFile(srcpath, []byte(src), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ objpath := filepath.Join(tmpdir, "a.obj")
+ cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build object file: %v - %v", err, string(out))
+ }
+
+ f, err := Open(objpath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+
+ var bss *Section
+ for _, sect := range f.Sections {
+ if sect.Name == ".bss" {
+ bss = sect
+ break
+ }
+ }
+ if bss == nil {
+ t.Fatal("could not find .bss section")
+ }
+ data, err := bss.Data()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(data) == 0 {
+ t.Fatalf("%s file .bss section cannot be empty", objpath)
+ }
+ for _, b := range data {
+ if b != 0 {
+ t.Fatalf(".bss section has non zero bytes: %v", data)
+ }
+ }
+}
diff --git a/libgo/go/debug/pe/pe.go b/libgo/go/debug/pe/pe.go
index 8e90b1b513..8050d59c70 100644
--- a/libgo/go/debug/pe/pe.go
+++ b/libgo/go/debug/pe/pe.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -86,30 +86,6 @@ type OptionalHeader64 struct {
DataDirectory [16]DataDirectory
}
-type SectionHeader32 struct {
- Name [8]uint8
- VirtualSize uint32
- VirtualAddress uint32
- SizeOfRawData uint32
- PointerToRawData uint32
- PointerToRelocations uint32
- PointerToLineNumbers uint32
- NumberOfRelocations uint16
- NumberOfLineNumbers uint16
- Characteristics uint32
-}
-
-const COFFSymbolSize = 18
-
-type COFFSymbol struct {
- Name [8]uint8
- Value uint32
- SectionNumber int16
- Type uint16
- StorageClass uint8
- NumberOfAuxSymbols uint8
-}
-
const (
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
IMAGE_FILE_MACHINE_AM33 = 0x1d3
diff --git a/libgo/go/debug/pe/section.go b/libgo/go/debug/pe/section.go
new file mode 100644
index 0000000000..b641158ecc
--- /dev/null
+++ b/libgo/go/debug/pe/section.go
@@ -0,0 +1,111 @@
+// 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 pe
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+// SectionHeader32 represents real PE COFF section header.
+type SectionHeader32 struct {
+ Name [8]uint8
+ VirtualSize uint32
+ VirtualAddress uint32
+ SizeOfRawData uint32
+ PointerToRawData uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+// fullName finds real name of section sh. Normally name is stored
+// in sh.Name, but if it is longer then 8 characters, it is stored
+// in COFF string table st instead.
+func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
+ if sh.Name[0] != '/' {
+ return cstring(sh.Name[:]), nil
+ }
+ i, err := strconv.Atoi(cstring(sh.Name[1:]))
+ if err != nil {
+ return "", err
+ }
+ return st.String(uint32(i))
+}
+
+// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
+
+// Reloc represents a PE COFF relocation.
+// Each section contains its own relocation list.
+type Reloc struct {
+ VirtualAddress uint32
+ SymbolTableIndex uint32
+ Type uint16
+}
+
+func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
+ if sh.NumberOfRelocations <= 0 {
+ return nil, nil
+ }
+ _, err := r.Seek(int64(sh.PointerToRelocations), seekStart)
+ if err != nil {
+ return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
+ }
+ relocs := make([]Reloc, sh.NumberOfRelocations)
+ err = binary.Read(r, binary.LittleEndian, relocs)
+ if err != nil {
+ return nil, fmt.Errorf("fail to read section relocations: %v", err)
+ }
+ return relocs, nil
+}
+
+// SectionHeader is similar to SectionHeader32 with Name
+// field replaced by Go string.
+type SectionHeader struct {
+ Name string
+ VirtualSize uint32
+ VirtualAddress uint32
+ Size uint32
+ Offset uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+// Section provides access to PE COFF section.
+type Section struct {
+ SectionHeader
+ Relocs []Reloc
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the PE section s.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the PE section s.
+func (s *Section) Open() io.ReadSeeker {
+ return io.NewSectionReader(s.sr, 0, 1<<63-1)
+}
diff --git a/libgo/go/debug/pe/string.go b/libgo/go/debug/pe/string.go
new file mode 100644
index 0000000000..c30255f341
--- /dev/null
+++ b/libgo/go/debug/pe/string.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+)
+
+// cstring converts ASCII byte sequence b to string.
+// It stops once it finds 0 or reaches end of b.
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[:i])
+}
+
+// StringTable is a COFF string table.
+type StringTable []byte
+
+func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) {
+ // COFF string table is located right after COFF symbol table.
+ if fh.PointerToSymbolTable <= 0 {
+ return nil, nil
+ }
+ offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
+ _, err := r.Seek(int64(offset), seekStart)
+ if err != nil {
+ return nil, fmt.Errorf("fail to seek to string table: %v", err)
+ }
+ var l uint32
+ err = binary.Read(r, binary.LittleEndian, &l)
+ if err != nil {
+ return nil, fmt.Errorf("fail to read string table length: %v", err)
+ }
+ // string table length includes itself
+ if l <= 4 {
+ return nil, nil
+ }
+ l -= 4
+ buf := make([]byte, l)
+ _, err = io.ReadFull(r, buf)
+ if err != nil {
+ return nil, fmt.Errorf("fail to read string table: %v", err)
+ }
+ return StringTable(buf), nil
+}
+
+// TODO(brainman): decide if start parameter should be int instead of uint32
+
+// String extracts string from COFF string table st at offset start.
+func (st StringTable) String(start uint32) (string, error) {
+ // start includes 4 bytes of string table length
+ if start < 4 {
+ return "", fmt.Errorf("offset %d is before the start of string table", start)
+ }
+ start -= 4
+ if int(start) > len(st) {
+ return "", fmt.Errorf("offset %d is beyond the end of string table", start)
+ }
+ return cstring(st[start:]), nil
+}
diff --git a/libgo/go/debug/pe/symbol.go b/libgo/go/debug/pe/symbol.go
new file mode 100644
index 0000000000..7fa5948641
--- /dev/null
+++ b/libgo/go/debug/pe/symbol.go
@@ -0,0 +1,98 @@
+// 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 pe
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+)
+
+const COFFSymbolSize = 18
+
+// COFFSymbol represents single COFF symbol table record.
+type COFFSymbol struct {
+ Name [8]uint8
+ Value uint32
+ SectionNumber int16
+ Type uint16
+ StorageClass uint8
+ NumberOfAuxSymbols uint8
+}
+
+func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
+ if fh.PointerToSymbolTable == 0 {
+ return nil, nil
+ }
+ if fh.NumberOfSymbols <= 0 {
+ return nil, nil
+ }
+ _, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
+ if err != nil {
+ return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
+ }
+ syms := make([]COFFSymbol, fh.NumberOfSymbols)
+ err = binary.Read(r, binary.LittleEndian, syms)
+ if err != nil {
+ return nil, fmt.Errorf("fail to read symbol table: %v", err)
+ }
+ return syms, nil
+}
+
+// isSymNameOffset checks symbol name if it is encoded as offset into string table.
+func isSymNameOffset(name [8]byte) (bool, uint32) {
+ if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
+ return true, binary.LittleEndian.Uint32(name[4:])
+ }
+ return false, 0
+}
+
+// FullName finds real name of symbol sym. Normally name is stored
+// in sym.Name, but if it is longer then 8 characters, it is stored
+// in COFF string table st instead.
+func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
+ if ok, offset := isSymNameOffset(sym.Name); ok {
+ return st.String(offset)
+ }
+ return cstring(sym.Name[:]), nil
+}
+
+func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
+ if len(allsyms) == 0 {
+ return nil, nil
+ }
+ syms := make([]*Symbol, 0)
+ aux := uint8(0)
+ for _, sym := range allsyms {
+ if aux > 0 {
+ aux--
+ continue
+ }
+ name, err := sym.FullName(st)
+ if err != nil {
+ return nil, err
+ }
+ aux = sym.NumberOfAuxSymbols
+ s := &Symbol{
+ Name: name,
+ Value: sym.Value,
+ SectionNumber: sym.SectionNumber,
+ Type: sym.Type,
+ StorageClass: sym.StorageClass,
+ }
+ syms = append(syms, s)
+ }
+ return syms, nil
+}
+
+// Symbol is similar to COFFSymbol with Name field replaced
+// by Go string. Symbol also does not have NumberOfAuxSymbols.
+type Symbol struct {
+ Name string
+ Value uint32
+ SectionNumber int16
+ Type uint16
+ StorageClass uint8
+}
diff --git a/libgo/go/debug/pe/testdata/gcc-386-mingw-no-symbols-exec b/libgo/go/debug/pe/testdata/gcc-386-mingw-no-symbols-exec
new file mode 100644
index 0000000000..329dca60b9
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/gcc-386-mingw-no-symbols-exec
Binary files differ
diff --git a/libgo/go/debug/plan9obj/file.go b/libgo/go/debug/plan9obj/file.go
index b11ed86f18..c78e35d000 100644
--- a/libgo/go/debug/plan9obj/file.go
+++ b/libgo/go/debug/plan9obj/file.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/plan9obj/file_test.go b/libgo/go/debug/plan9obj/file_test.go
index cfd7a61d1c..7e107bca2f 100644
--- a/libgo/go/debug/plan9obj/file_test.go
+++ b/libgo/go/debug/plan9obj/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/debug/plan9obj/plan9obj.go b/libgo/go/debug/plan9obj/plan9obj.go
index af9858562f..7a194514c2 100644
--- a/libgo/go/debug/plan9obj/plan9obj.go
+++ b/libgo/go/debug/plan9obj/plan9obj.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
index 4d7193873a..d42eb0ab00 100644
--- a/libgo/go/encoding/ascii85/ascii85.go
+++ b/libgo/go/encoding/ascii85/ascii85.go
@@ -20,7 +20,7 @@ import (
//
// The encoding handles 4-byte chunks, using a special encoding
// for the last fragment, so Encode is not appropriate for use on
-// individual blocks of a large data stream. Use NewEncoder() instead.
+// individual blocks of a large data stream. Use NewEncoder() instead.
//
// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
// Encode does not add these.
@@ -85,7 +85,7 @@ func Encode(dst, src []byte) int {
// MaxEncodedLen returns the maximum length of an encoding of n source bytes.
func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
-// NewEncoder returns a new ascii85 stream encoder. Data written to
+// NewEncoder returns a new ascii85 stream encoder. Data written to
// the returned writer will be encoded and then written to w.
// Ascii85 encodings operate in 32-bit blocks; when finished
// writing, the caller must Close the returned encoder to flush any
@@ -294,7 +294,7 @@ func (d *decoder) Read(p []byte) (n int, err error) {
}
}
- // Out of input, out of decoded output. Check errors.
+ // Out of input, out of decoded output. Check errors.
if d.err != nil {
return 0, d.err
}
diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go
index 8bafefd52b..044f74ab46 100644
--- a/libgo/go/encoding/asn1/asn1.go
+++ b/libgo/go/encoding/asn1/asn1.go
@@ -393,7 +393,7 @@ func isPrintable(b byte) bool {
// byte slice and returns it.
func parseIA5String(bytes []byte) (ret string, err error) {
for _, b := range bytes {
- if b >= 0x80 {
+ if b >= utf8.RuneSelf {
err = SyntaxError{"IA5String contains invalid character"}
return
}
@@ -461,6 +461,11 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
if err != nil {
return
}
+ // Tags should be encoded in minimal form.
+ if ret.tag < 0x1f {
+ err = SyntaxError{"non-minimal tag"}
+ return
+ }
}
if offset >= len(bytes) {
err = SyntaxError{"truncated tag or length"}
@@ -836,6 +841,13 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
case reflect.Struct:
structType := fieldType
+ for i := 0; i < structType.NumField(); i++ {
+ if structType.Field(i).PkgPath != "" {
+ err = StructuralError{"struct contains unexported fields"}
+ return
+ }
+ }
+
if structType.NumField() > 0 &&
structType.Field(0).Type == rawContentsType {
bytes := bytes[initOffset:offset]
@@ -964,7 +976,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// The following tags on struct fields have special meaning to Unmarshal:
//
// application specifies that a APPLICATION tag is used
-// default:x sets the default value for optional integer fields
+// default:x sets the default value for optional integer fields (only used if optional is also present)
// explicit specifies that an additional, explicit tag wraps the implicit one
// optional marks the field as ASN.1 OPTIONAL
// set causes a SET, rather than a SEQUENCE type to be expected
diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go
index e0e833123b..9976656df8 100644
--- a/libgo/go/encoding/asn1/asn1_test.go
+++ b/libgo/go/encoding/asn1/asn1_test.go
@@ -132,9 +132,13 @@ func TestParseBigInt(t *testing.T) {
if ret.String() != test.base10 {
t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
}
- fw := newForkableWriter()
- marshalBigInt(fw, ret)
- result := fw.Bytes()
+ e, err := makeBigInt(ret)
+ if err != nil {
+ t.Errorf("%d: err=%q", i, err)
+ continue
+ }
+ result := make([]byte, e.Len())
+ e.Encode(result)
if !bytes.Equal(result, test.in) {
t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
}
@@ -364,7 +368,7 @@ var tagAndLengthData = []tagAndLengthTest{
{[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
{[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
{[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
- {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+ {[]byte{0x1f, 0x1f, 0x00}, true, tagAndLength{0, 31, 0, false}},
{[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
{[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
{[]byte{0x00, 0x81, 0x80}, true, tagAndLength{0, 0, 128, false}},
@@ -382,6 +386,8 @@ var tagAndLengthData = []tagAndLengthTest{
{[]byte{0xa0, 0x81, 0x7f}, false, tagAndLength{}},
// Tag numbers which would overflow int32 are rejected. (The value below is 2^31.)
{[]byte{0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00}, false, tagAndLength{}},
+ // Long tag number form may not be used for tags that fit in short form.
+ {[]byte{0x1f, 0x1e, 0x00}, false, tagAndLength{}},
}
func TestParseTagAndLength(t *testing.T) {
@@ -961,7 +967,7 @@ func TestUnmarshalInvalidUTF8(t *testing.T) {
func TestMarshalNilValue(t *testing.T) {
nilValueTestData := []interface{}{
nil,
- struct{ v interface{} }{},
+ struct{ V interface{} }{},
}
for i, test := range nilValueTestData {
if _, err := Marshal(test); err == nil {
@@ -969,3 +975,32 @@ func TestMarshalNilValue(t *testing.T) {
}
}
}
+
+type unexported struct {
+ X int
+ y int
+}
+
+type exported struct {
+ X int
+ Y int
+}
+
+func TestUnexportedStructField(t *testing.T) {
+ want := StructuralError{"struct contains unexported fields"}
+
+ _, err := Marshal(unexported{X: 5, y: 1})
+ if err != want {
+ t.Errorf("got %v, want %v", err, want)
+ }
+
+ bs, err := Marshal(exported{X: 5, Y: 1})
+ if err != nil {
+ t.Fatal(err)
+ }
+ var u unexported
+ _, err = Unmarshal(bs, &u)
+ if err != want {
+ t.Errorf("got %v, want %v", err, want)
+ }
+}
diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go
index 6e858584a6..225fd0849c 100644
--- a/libgo/go/encoding/asn1/marshal.go
+++ b/libgo/go/encoding/asn1/marshal.go
@@ -5,77 +5,125 @@
package asn1
import (
- "bytes"
"errors"
"fmt"
- "io"
"math/big"
"reflect"
"time"
"unicode/utf8"
)
-// A forkableWriter is an in-memory buffer that can be
-// 'forked' to create new forkableWriters that bracket the
-// original. After
-// pre, post := w.fork()
-// the overall sequence of bytes represented is logically w+pre+post.
-type forkableWriter struct {
- *bytes.Buffer
- pre, post *forkableWriter
+var (
+ byte00Encoder encoder = byteEncoder(0x00)
+ byteFFEncoder encoder = byteEncoder(0xff)
+)
+
+// encoder represents a ASN.1 element that is waiting to be marshaled.
+type encoder interface {
+ // Len returns the number of bytes needed to marshal this element.
+ Len() int
+ // Encode encodes this element by writing Len() bytes to dst.
+ Encode(dst []byte)
+}
+
+type byteEncoder byte
+
+func (c byteEncoder) Len() int {
+ return 1
}
-func newForkableWriter() *forkableWriter {
- return &forkableWriter{new(bytes.Buffer), nil, nil}
+func (c byteEncoder) Encode(dst []byte) {
+ dst[0] = byte(c)
}
-func (f *forkableWriter) fork() (pre, post *forkableWriter) {
- if f.pre != nil || f.post != nil {
- panic("have already forked")
+type bytesEncoder []byte
+
+func (b bytesEncoder) Len() int {
+ return len(b)
+}
+
+func (b bytesEncoder) Encode(dst []byte) {
+ if copy(dst, b) != len(b) {
+ panic("internal error")
}
- f.pre = newForkableWriter()
- f.post = newForkableWriter()
- return f.pre, f.post
}
-func (f *forkableWriter) Len() (l int) {
- l += f.Buffer.Len()
- if f.pre != nil {
- l += f.pre.Len()
+type stringEncoder string
+
+func (s stringEncoder) Len() int {
+ return len(s)
+}
+
+func (s stringEncoder) Encode(dst []byte) {
+ if copy(dst, s) != len(s) {
+ panic("internal error")
}
- if f.post != nil {
- l += f.post.Len()
+}
+
+type multiEncoder []encoder
+
+func (m multiEncoder) Len() int {
+ var size int
+ for _, e := range m {
+ size += e.Len()
}
- return
+ return size
}
-func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
- n, err = out.Write(f.Bytes())
- if err != nil {
- return
+func (m multiEncoder) Encode(dst []byte) {
+ var off int
+ for _, e := range m {
+ e.Encode(dst[off:])
+ off += e.Len()
}
+}
- var nn int
+type taggedEncoder struct {
+ // scratch contains temporary space for encoding the tag and length of
+ // an element in order to avoid extra allocations.
+ scratch [8]byte
+ tag encoder
+ body encoder
+}
- if f.pre != nil {
- nn, err = f.pre.writeTo(out)
- n += nn
- if err != nil {
- return
- }
+func (t *taggedEncoder) Len() int {
+ return t.tag.Len() + t.body.Len()
+}
+
+func (t *taggedEncoder) Encode(dst []byte) {
+ t.tag.Encode(dst)
+ t.body.Encode(dst[t.tag.Len():])
+}
+
+type int64Encoder int64
+
+func (i int64Encoder) Len() int {
+ n := 1
+
+ for i > 127 {
+ n++
+ i >>= 8
}
- if f.post != nil {
- nn, err = f.post.writeTo(out)
- n += nn
+ for i < -128 {
+ n++
+ i >>= 8
}
- return
+
+ return n
}
-func marshalBase128Int(out *forkableWriter, n int64) (err error) {
+func (i int64Encoder) Encode(dst []byte) {
+ n := i.Len()
+
+ for j := 0; j < n; j++ {
+ dst[j] = byte(i >> uint((n-1-j)*8))
+ }
+}
+
+func base128IntLength(n int64) int {
if n == 0 {
- err = out.WriteByte(0)
- return
+ return 1
}
l := 0
@@ -83,54 +131,33 @@ func marshalBase128Int(out *forkableWriter, n int64) (err error) {
l++
}
+ return l
+}
+
+func appendBase128Int(dst []byte, n int64) []byte {
+ l := base128IntLength(n)
+
for i := l - 1; i >= 0; i-- {
o := byte(n >> uint(i*7))
o &= 0x7f
if i != 0 {
o |= 0x80
}
- err = out.WriteByte(o)
- if err != nil {
- return
- }
- }
-
- return nil
-}
-func marshalInt64(out *forkableWriter, i int64) (err error) {
- n := int64Length(i)
-
- for ; n > 0; n-- {
- err = out.WriteByte(byte(i >> uint((n-1)*8)))
- if err != nil {
- return
- }
+ dst = append(dst, o)
}
- return nil
+ return dst
}
-func int64Length(i int64) (numBytes int) {
- numBytes = 1
-
- for i > 127 {
- numBytes++
- i >>= 8
+func makeBigInt(n *big.Int) (encoder, error) {
+ if n == nil {
+ return nil, StructuralError{"empty integer"}
}
- for i < -128 {
- numBytes++
- i >>= 8
- }
-
- return
-}
-
-func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
if n.Sign() < 0 {
// A negative number has to be converted to two's-complement
- // form. So we'll subtract 1 and invert. If the
+ // form. So we'll invert and subtract 1. If the
// most-significant-bit isn't set then we'll need to pad the
// beginning with 0xff in order to keep the number negative.
nMinus1 := new(big.Int).Neg(n)
@@ -140,41 +167,31 @@ func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
bytes[i] ^= 0xff
}
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
- err = out.WriteByte(0xff)
- if err != nil {
- return
- }
+ return multiEncoder([]encoder{byteFFEncoder, bytesEncoder(bytes)}), nil
}
- _, err = out.Write(bytes)
+ return bytesEncoder(bytes), nil
} else if n.Sign() == 0 {
// Zero is written as a single 0 zero rather than no bytes.
- err = out.WriteByte(0x00)
+ return byte00Encoder, nil
} else {
bytes := n.Bytes()
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
// We'll have to pad this with 0x00 in order to stop it
// looking like a negative number.
- err = out.WriteByte(0)
- if err != nil {
- return
- }
+ return multiEncoder([]encoder{byte00Encoder, bytesEncoder(bytes)}), nil
}
- _, err = out.Write(bytes)
+ return bytesEncoder(bytes), nil
}
- return
}
-func marshalLength(out *forkableWriter, i int) (err error) {
+func appendLength(dst []byte, i int) []byte {
n := lengthLength(i)
for ; n > 0; n-- {
- err = out.WriteByte(byte(i >> uint((n-1)*8)))
- if err != nil {
- return
- }
+ dst = append(dst, byte(i>>uint((n-1)*8)))
}
- return nil
+ return dst
}
func lengthLength(i int) (numBytes int) {
@@ -186,123 +203,104 @@ func lengthLength(i int) (numBytes int) {
return
}
-func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
+func appendTagAndLength(dst []byte, t tagAndLength) []byte {
b := uint8(t.class) << 6
if t.isCompound {
b |= 0x20
}
if t.tag >= 31 {
b |= 0x1f
- err = out.WriteByte(b)
- if err != nil {
- return
- }
- err = marshalBase128Int(out, int64(t.tag))
- if err != nil {
- return
- }
+ dst = append(dst, b)
+ dst = appendBase128Int(dst, int64(t.tag))
} else {
b |= uint8(t.tag)
- err = out.WriteByte(b)
- if err != nil {
- return
- }
+ dst = append(dst, b)
}
if t.length >= 128 {
l := lengthLength(t.length)
- err = out.WriteByte(0x80 | byte(l))
- if err != nil {
- return
- }
- err = marshalLength(out, t.length)
- if err != nil {
- return
- }
+ dst = append(dst, 0x80|byte(l))
+ dst = appendLength(dst, t.length)
} else {
- err = out.WriteByte(byte(t.length))
- if err != nil {
- return
- }
+ dst = append(dst, byte(t.length))
}
- return nil
+ return dst
}
-func marshalBitString(out *forkableWriter, b BitString) (err error) {
- paddingBits := byte((8 - b.BitLength%8) % 8)
- err = out.WriteByte(paddingBits)
- if err != nil {
- return
- }
- _, err = out.Write(b.Bytes)
- return
+type bitStringEncoder BitString
+
+func (b bitStringEncoder) Len() int {
+ return len(b.Bytes) + 1
}
-func marshalObjectIdentifier(out *forkableWriter, oid []int) (err error) {
- if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
- return StructuralError{"invalid object identifier"}
+func (b bitStringEncoder) Encode(dst []byte) {
+ dst[0] = byte((8 - b.BitLength%8) % 8)
+ if copy(dst[1:], b.Bytes) != len(b.Bytes) {
+ panic("internal error")
}
+}
- err = marshalBase128Int(out, int64(oid[0]*40+oid[1]))
- if err != nil {
- return
+type oidEncoder []int
+
+func (oid oidEncoder) Len() int {
+ l := base128IntLength(int64(oid[0]*40 + oid[1]))
+ for i := 2; i < len(oid); i++ {
+ l += base128IntLength(int64(oid[i]))
}
+ return l
+}
+
+func (oid oidEncoder) Encode(dst []byte) {
+ dst = appendBase128Int(dst[:0], int64(oid[0]*40+oid[1]))
for i := 2; i < len(oid); i++ {
- err = marshalBase128Int(out, int64(oid[i]))
- if err != nil {
- return
- }
+ dst = appendBase128Int(dst, int64(oid[i]))
}
+}
- return
+func makeObjectIdentifier(oid []int) (e encoder, err error) {
+ if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
+ return nil, StructuralError{"invalid object identifier"}
+ }
+
+ return oidEncoder(oid), nil
}
-func marshalPrintableString(out *forkableWriter, s string) (err error) {
- b := []byte(s)
- for _, c := range b {
- if !isPrintable(c) {
- return StructuralError{"PrintableString contains invalid character"}
+func makePrintableString(s string) (e encoder, err error) {
+ for i := 0; i < len(s); i++ {
+ if !isPrintable(s[i]) {
+ return nil, StructuralError{"PrintableString contains invalid character"}
}
}
- _, err = out.Write(b)
- return
+ return stringEncoder(s), nil
}
-func marshalIA5String(out *forkableWriter, s string) (err error) {
- b := []byte(s)
- for _, c := range b {
- if c > 127 {
- return StructuralError{"IA5String contains invalid character"}
+func makeIA5String(s string) (e encoder, err error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] > 127 {
+ return nil, StructuralError{"IA5String contains invalid character"}
}
}
- _, err = out.Write(b)
- return
+ return stringEncoder(s), nil
}
-func marshalUTF8String(out *forkableWriter, s string) (err error) {
- _, err = out.Write([]byte(s))
- return
+func makeUTF8String(s string) encoder {
+ return stringEncoder(s)
}
-func marshalTwoDigits(out *forkableWriter, v int) (err error) {
- err = out.WriteByte(byte('0' + (v/10)%10))
- if err != nil {
- return
- }
- return out.WriteByte(byte('0' + v%10))
+func appendTwoDigits(dst []byte, v int) []byte {
+ return append(dst, byte('0'+(v/10)%10), byte('0'+v%10))
}
-func marshalFourDigits(out *forkableWriter, v int) (err error) {
+func appendFourDigits(dst []byte, v int) []byte {
var bytes [4]byte
for i := range bytes {
bytes[3-i] = '0' + byte(v%10)
v /= 10
}
- _, err = out.Write(bytes[:])
- return
+ return append(dst, bytes[:]...)
}
func outsideUTCRange(t time.Time) bool {
@@ -310,80 +308,75 @@ func outsideUTCRange(t time.Time) bool {
return year < 1950 || year >= 2050
}
-func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
+func makeUTCTime(t time.Time) (e encoder, err error) {
+ dst := make([]byte, 0, 18)
+
+ dst, err = appendUTCTime(dst, t)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytesEncoder(dst), nil
+}
+
+func makeGeneralizedTime(t time.Time) (e encoder, err error) {
+ dst := make([]byte, 0, 20)
+
+ dst, err = appendGeneralizedTime(dst, t)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytesEncoder(dst), nil
+}
+
+func appendUTCTime(dst []byte, t time.Time) (ret []byte, err error) {
year := t.Year()
switch {
case 1950 <= year && year < 2000:
- err = marshalTwoDigits(out, int(year-1900))
+ dst = appendTwoDigits(dst, year-1900)
case 2000 <= year && year < 2050:
- err = marshalTwoDigits(out, int(year-2000))
+ dst = appendTwoDigits(dst, year-2000)
default:
- return StructuralError{"cannot represent time as UTCTime"}
- }
- if err != nil {
- return
+ return nil, StructuralError{"cannot represent time as UTCTime"}
}
- return marshalTimeCommon(out, t)
+ return appendTimeCommon(dst, t), nil
}
-func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+func appendGeneralizedTime(dst []byte, t time.Time) (ret []byte, err error) {
year := t.Year()
if year < 0 || year > 9999 {
- return StructuralError{"cannot represent time as GeneralizedTime"}
- }
- if err = marshalFourDigits(out, year); err != nil {
- return
+ return nil, StructuralError{"cannot represent time as GeneralizedTime"}
}
- return marshalTimeCommon(out, t)
+ dst = appendFourDigits(dst, year)
+
+ return appendTimeCommon(dst, t), nil
}
-func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+func appendTimeCommon(dst []byte, t time.Time) []byte {
_, month, day := t.Date()
- err = marshalTwoDigits(out, int(month))
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, day)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, int(month))
+ dst = appendTwoDigits(dst, day)
hour, min, sec := t.Clock()
- err = marshalTwoDigits(out, hour)
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, min)
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, sec)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, hour)
+ dst = appendTwoDigits(dst, min)
+ dst = appendTwoDigits(dst, sec)
_, offset := t.Zone()
switch {
case offset/60 == 0:
- err = out.WriteByte('Z')
- return
+ return append(dst, 'Z')
case offset > 0:
- err = out.WriteByte('+')
+ dst = append(dst, '+')
case offset < 0:
- err = out.WriteByte('-')
- }
-
- if err != nil {
- return
+ dst = append(dst, '-')
}
offsetMinutes := offset / 60
@@ -391,13 +384,10 @@ func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
offsetMinutes = -offsetMinutes
}
- err = marshalTwoDigits(out, offsetMinutes/60)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, offsetMinutes/60)
+ dst = appendTwoDigits(dst, offsetMinutes%60)
- err = marshalTwoDigits(out, offsetMinutes%60)
- return
+ return dst
}
func stripTagAndLength(in []byte) []byte {
@@ -408,114 +398,130 @@ func stripTagAndLength(in []byte) []byte {
return in[offset:]
}
-func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
+func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error) {
switch value.Type() {
case flagType:
- return nil
+ return bytesEncoder(nil), nil
case timeType:
t := value.Interface().(time.Time)
if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
- return marshalGeneralizedTime(out, t)
- } else {
- return marshalUTCTime(out, t)
+ return makeGeneralizedTime(t)
}
+ return makeUTCTime(t)
case bitStringType:
- return marshalBitString(out, value.Interface().(BitString))
+ return bitStringEncoder(value.Interface().(BitString)), nil
case objectIdentifierType:
- return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+ return makeObjectIdentifier(value.Interface().(ObjectIdentifier))
case bigIntType:
- return marshalBigInt(out, value.Interface().(*big.Int))
+ return makeBigInt(value.Interface().(*big.Int))
}
switch v := value; v.Kind() {
case reflect.Bool:
if v.Bool() {
- return out.WriteByte(255)
- } else {
- return out.WriteByte(0)
+ return byteFFEncoder, nil
}
+ return byte00Encoder, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return marshalInt64(out, int64(v.Int()))
+ return int64Encoder(v.Int()), nil
case reflect.Struct:
t := v.Type()
+ for i := 0; i < t.NumField(); i++ {
+ if t.Field(i).PkgPath != "" {
+ return nil, StructuralError{"struct contains unexported fields"}
+ }
+ }
+
startingField := 0
+ n := t.NumField()
+ if n == 0 {
+ return bytesEncoder(nil), nil
+ }
+
// If the first element of the structure is a non-empty
// RawContents, then we don't bother serializing the rest.
- if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
+ if t.Field(0).Type == rawContentsType {
s := v.Field(0)
if s.Len() > 0 {
- bytes := make([]byte, s.Len())
- for i := 0; i < s.Len(); i++ {
- bytes[i] = uint8(s.Index(i).Uint())
- }
+ bytes := s.Bytes()
/* The RawContents will contain the tag and
* length fields but we'll also be writing
* those ourselves, so we strip them out of
* bytes */
- _, err = out.Write(stripTagAndLength(bytes))
- return
- } else {
- startingField = 1
+ return bytesEncoder(stripTagAndLength(bytes)), nil
}
+
+ startingField = 1
}
- for i := startingField; i < t.NumField(); i++ {
- var pre *forkableWriter
- pre, out = out.fork()
- err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
- if err != nil {
- return
+ switch n1 := n - startingField; n1 {
+ case 0:
+ return bytesEncoder(nil), nil
+ case 1:
+ return makeField(v.Field(startingField), parseFieldParameters(t.Field(startingField).Tag.Get("asn1")))
+ default:
+ m := make([]encoder, n1)
+ for i := 0; i < n1; i++ {
+ m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1")))
+ if err != nil {
+ return nil, err
+ }
}
+
+ return multiEncoder(m), nil
}
- return
case reflect.Slice:
sliceType := v.Type()
if sliceType.Elem().Kind() == reflect.Uint8 {
- bytes := make([]byte, v.Len())
- for i := 0; i < v.Len(); i++ {
- bytes[i] = uint8(v.Index(i).Uint())
- }
- _, err = out.Write(bytes)
- return
+ return bytesEncoder(v.Bytes()), nil
}
var fp fieldParameters
- for i := 0; i < v.Len(); i++ {
- var pre *forkableWriter
- pre, out = out.fork()
- err = marshalField(pre, v.Index(i), fp)
- if err != nil {
- return
+
+ switch l := v.Len(); l {
+ case 0:
+ return bytesEncoder(nil), nil
+ case 1:
+ return makeField(v.Index(0), fp)
+ default:
+ m := make([]encoder, l)
+
+ for i := 0; i < l; i++ {
+ m[i], err = makeField(v.Index(i), fp)
+ if err != nil {
+ return nil, err
+ }
}
+
+ return multiEncoder(m), nil
}
- return
case reflect.String:
switch params.stringType {
case TagIA5String:
- return marshalIA5String(out, v.String())
+ return makeIA5String(v.String())
case TagPrintableString:
- return marshalPrintableString(out, v.String())
+ return makePrintableString(v.String())
default:
- return marshalUTF8String(out, v.String())
+ return makeUTF8String(v.String()), nil
}
}
- return StructuralError{"unknown Go type"}
+ return nil, StructuralError{"unknown Go type"}
}
-func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
+func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
if !v.IsValid() {
- return fmt.Errorf("asn1: cannot marshal nil value")
+ return nil, fmt.Errorf("asn1: cannot marshal nil value")
}
// If the field is an interface{} then recurse into it.
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
- return marshalField(out, v.Elem(), params)
+ return makeField(v.Elem(), params)
}
if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
- return
+ return bytesEncoder(nil), nil
}
if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
@@ -523,46 +529,45 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
defaultValue.SetInt(*params.defaultValue)
if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
- return
+ return bytesEncoder(nil), nil
}
}
// If no default value is given then the zero value for the type is
// assumed to be the default value. This isn't obviously the correct
- // behaviour, but it's what Go has traditionally done.
+ // behavior, but it's what Go has traditionally done.
if params.optional && params.defaultValue == nil {
if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
- return
+ return bytesEncoder(nil), nil
}
}
if v.Type() == rawValueType {
rv := v.Interface().(RawValue)
if len(rv.FullBytes) != 0 {
- _, err = out.Write(rv.FullBytes)
- } else {
- err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
- if err != nil {
- return
- }
- _, err = out.Write(rv.Bytes)
+ return bytesEncoder(rv.FullBytes), nil
}
- return
+
+ t := new(taggedEncoder)
+
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}))
+ t.body = bytesEncoder(rv.Bytes)
+
+ return t, nil
}
tag, isCompound, ok := getUniversalType(v.Type())
if !ok {
- err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
- return
+ return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
}
class := ClassUniversal
if params.timeType != 0 && tag != TagUTCTime {
- return StructuralError{"explicit time type given to non-time member"}
+ return nil, StructuralError{"explicit time type given to non-time member"}
}
if params.stringType != 0 && tag != TagPrintableString {
- return StructuralError{"explicit string type given to non-string member"}
+ return nil, StructuralError{"explicit string type given to non-string member"}
}
switch tag {
@@ -574,7 +579,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
for _, r := range v.String() {
if r >= utf8.RuneSelf || !isPrintable(byte(r)) {
if !utf8.ValidString(v.String()) {
- return errors.New("asn1: string not valid UTF-8")
+ return nil, errors.New("asn1: string not valid UTF-8")
}
tag = TagUTF8String
break
@@ -591,46 +596,46 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
if params.set {
if tag != TagSequence {
- return StructuralError{"non sequence tagged as set"}
+ return nil, StructuralError{"non sequence tagged as set"}
}
tag = TagSet
}
- tags, body := out.fork()
+ t := new(taggedEncoder)
- err = marshalBody(body, v, params)
+ t.body, err = makeBody(v, params)
if err != nil {
- return
+ return nil, err
}
- bodyLen := body.Len()
+ bodyLen := t.body.Len()
- var explicitTag *forkableWriter
if params.explicit {
- explicitTag, tags = tags.fork()
- }
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
- if !params.explicit && params.tag != nil {
- // implicit tag.
- tag = *params.tag
- class = ClassContextSpecific
- }
+ tt := new(taggedEncoder)
- err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
- if err != nil {
- return
- }
+ tt.body = t
- if params.explicit {
- err = marshalTagAndLength(explicitTag, tagAndLength{
+ tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{
class: ClassContextSpecific,
tag: *params.tag,
- length: bodyLen + tags.Len(),
+ length: bodyLen + t.tag.Len(),
isCompound: true,
- })
+ }))
+
+ return tt, nil
+ }
+
+ if params.tag != nil {
+ // implicit tag.
+ tag = *params.tag
+ class = ClassContextSpecific
}
- return err
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
+
+ return t, nil
}
// Marshal returns the ASN.1 encoding of val.
@@ -643,13 +648,11 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
// printable: causes strings to be marshaled as ASN.1, PrintableString strings.
// utf8: causes strings to be marshaled as ASN.1, UTF8 strings
func Marshal(val interface{}) ([]byte, error) {
- var out bytes.Buffer
- v := reflect.ValueOf(val)
- f := newForkableWriter()
- err := marshalField(f, v, fieldParameters{})
+ e, err := makeField(reflect.ValueOf(val), fieldParameters{})
if err != nil {
return nil, err
}
- _, err = f.writeTo(&out)
- return out.Bytes(), err
+ b := make([]byte, e.Len())
+ e.Encode(b)
+ return b, nil
}
diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go
index cdca8aa336..10db1aa575 100644
--- a/libgo/go/encoding/asn1/marshal_test.go
+++ b/libgo/go/encoding/asn1/marshal_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/hex"
"math/big"
+ "strings"
"testing"
"time"
)
@@ -167,9 +168,42 @@ func TestMarshal(t *testing.T) {
}
}
+type marshalErrTest struct {
+ in interface{}
+ err string
+}
+
+var marshalErrTests = []marshalErrTest{
+ {bigIntStruct{nil}, "empty integer"},
+}
+
+func TestMarshalError(t *testing.T) {
+ for i, test := range marshalErrTests {
+ _, err := Marshal(test.in)
+ if err == nil {
+ t.Errorf("#%d should fail, but success", i)
+ continue
+ }
+
+ if !strings.Contains(err.Error(), test.err) {
+ t.Errorf("#%d got: %v want %v", i, err, test.err)
+ }
+ }
+}
+
func TestInvalidUTF8(t *testing.T) {
_, err := Marshal(string([]byte{0xff, 0xff}))
if err == nil {
t.Errorf("invalid UTF8 string was accepted")
}
}
+
+func BenchmarkMarshal(b *testing.B) {
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ for _, test := range marshalTests {
+ Marshal(test.in)
+ }
+ }
+}
diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go
index 5a9e86919d..c193e65e1b 100644
--- a/libgo/go/encoding/base32/base32.go
+++ b/libgo/go/encoding/base32/base32.go
@@ -17,7 +17,7 @@ import (
*/
// An Encoding is a radix 32 encoding/decoding scheme, defined by a
-// 32-character alphabet. The most common is the "base32" encoding
+// 32-character alphabet. The most common is the "base32" encoding
// introduced for SASL GSSAPI and standardized in RFC 4648.
// The alternate "base32hex" encoding is used in DNSSEC.
type Encoding struct {
@@ -66,7 +66,7 @@ var removeNewlinesMapper = func(r rune) rune {
//
// The encoding pads the output to a multiple of 8 bytes,
// so Encode is not appropriate for use on individual blocks
-// of a large data stream. Use NewEncoder() instead.
+// of a large data stream. Use NewEncoder() instead.
func (enc *Encoding) Encode(dst, src []byte) {
if len(src) == 0 {
return
@@ -208,7 +208,7 @@ func (e *encoder) Close() error {
return e.err
}
-// NewEncoder returns a new base32 stream encoder. Data written to
+// NewEncoder returns a new base32 stream encoder. Data written to
// the returned writer will be encoded using enc and then written to w.
// Base32 encodings operate in 5-byte blocks; when finished
// writing, the caller must Close the returned encoder to flush any
@@ -313,9 +313,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
return n, end, nil
}
-// Decode decodes src using the encoding enc. It writes at most
+// Decode decodes src using the encoding enc. It writes at most
// DecodedLen(len(src)) bytes to dst and returns the number of bytes
-// written. If src contains invalid base32 data, it will return the
+// written. If src contains invalid base32 data, it will return the
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go
index 5a68f06e1c..66a48a3f6f 100644
--- a/libgo/go/encoding/base32/base32_test.go
+++ b/libgo/go/encoding/base32/base32_test.go
@@ -171,7 +171,7 @@ func TestDecodeCorrupt(t *testing.T) {
_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
if tc.offset == -1 {
if err != nil {
- t.Error("Decoder wrongly detected coruption in", tc.input)
+ t.Error("Decoder wrongly detected corruption in", tc.input)
}
continue
}
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index 1bda804c38..d2efad4518 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -15,7 +15,7 @@ import (
*/
// An Encoding is a radix 64 encoding/decoding scheme, defined by a
-// 64-character alphabet. The most common encoding is the "base64"
+// 64-character alphabet. The most common encoding is the "base64"
// encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
// (RFC 1421). RFC 4648 also defines an alternate encoding, which is
// the standard encoding with - and _ substituted for + and /.
@@ -23,6 +23,7 @@ type Encoding struct {
encode [64]byte
decodeMap [256]byte
padChar rune
+ strict bool
}
const (
@@ -62,6 +63,14 @@ func (enc Encoding) WithPadding(padding rune) *Encoding {
return &enc
}
+// Strict creates a new encoding identical to enc except with
+// strict decoding enabled. In this mode, the decoder requires that
+// trailing padding bits are zero, as described in RFC 4648 section 3.5.
+func (enc Encoding) Strict() *Encoding {
+ enc.strict = true
+ return &enc
+}
+
// StdEncoding is the standard base64 encoding, as defined in
// RFC 4648.
var StdEncoding = NewEncoding(encodeStd)
@@ -89,7 +98,7 @@ var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
//
// The encoding pads the output to a multiple of 4 bytes,
// so Encode is not appropriate for use on individual blocks
-// of a large data stream. Use NewEncoder() instead.
+// of a large data stream. Use NewEncoder() instead.
func (enc *Encoding) Encode(dst, src []byte) {
if len(src) == 0 {
return
@@ -213,7 +222,7 @@ func (e *encoder) Close() error {
return e.err
}
-// NewEncoder returns a new base64 stream encoder. Data written to
+// NewEncoder returns a new base64 stream encoder. Data written to
// the returned writer will be encoded using enc and then written to w.
// Base64 encodings operate in 4-byte blocks; when finished
// writing, the caller must Close the returned encoder to flush any
@@ -311,15 +320,24 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// Convert 4x 6bit source bytes into 3 bytes
val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
+ dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16)
switch dlen {
case 4:
- dst[2] = byte(val >> 0)
+ dst[2] = dbuf[2]
+ dbuf[2] = 0
fallthrough
case 3:
- dst[1] = byte(val >> 8)
+ dst[1] = dbuf[1]
+ if enc.strict && dbuf[2] != 0 {
+ return n, end, CorruptInputError(si - 1)
+ }
+ dbuf[1] = 0
fallthrough
case 2:
- dst[0] = byte(val >> 16)
+ dst[0] = dbuf[0]
+ if enc.strict && (dbuf[1] != 0 || dbuf[2] != 0) {
+ return n, end, CorruptInputError(si - 2)
+ }
}
dst = dst[dinc:]
n += dlen - 1
@@ -328,9 +346,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
return n, end, err
}
-// Decode decodes src using the encoding enc. It writes at most
+// Decode decodes src using the encoding enc. It writes at most
// DecodedLen(len(src)) bytes to dst and returns the number of bytes
-// written. If src contains invalid base64 data, it will return the
+// written. If src contains invalid base64 data, it will return the
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
@@ -459,7 +477,7 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
func (enc *Encoding) DecodedLen(n int) int {
if enc.padChar == NoPadding {
// Unpadded data may end with partial block of 2-3 characters.
- return (n*6 + 7) / 8
+ return n * 6 / 8
}
// Padded base64 should always be a multiple of 4 characters in length.
return n / 4 * 3
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index fc6a1ea654..e2e1d59f3c 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -85,6 +85,11 @@ var encodingTests = []encodingTest{
{RawStdEncoding, rawRef},
{RawURLEncoding, rawUrlRef},
{funnyEncoding, funnyRef},
+ {StdEncoding.Strict(), stdRef},
+ {URLEncoding.Strict(), urlRef},
+ {RawStdEncoding.Strict(), rawRef},
+ {RawURLEncoding.Strict(), rawUrlRef},
+ {funnyEncoding.Strict(), funnyRef},
}
var bigtest = testpair{
@@ -221,7 +226,7 @@ func TestDecodeCorrupt(t *testing.T) {
_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
if tc.offset == -1 {
if err != nil {
- t.Error("Decoder wrongly detected coruption in", tc.input)
+ t.Error("Decoder wrongly detected corruption in", tc.input)
}
continue
}
@@ -234,6 +239,51 @@ func TestDecodeCorrupt(t *testing.T) {
}
}
+func TestEncodedLen(t *testing.T) {
+ for _, tt := range []struct {
+ enc *Encoding
+ n int
+ want int
+ }{
+ {RawStdEncoding, 0, 0},
+ {RawStdEncoding, 1, 2},
+ {RawStdEncoding, 2, 3},
+ {RawStdEncoding, 3, 4},
+ {RawStdEncoding, 7, 10},
+ {StdEncoding, 0, 0},
+ {StdEncoding, 1, 4},
+ {StdEncoding, 2, 4},
+ {StdEncoding, 3, 4},
+ {StdEncoding, 4, 8},
+ {StdEncoding, 7, 12},
+ } {
+ if got := tt.enc.EncodedLen(tt.n); got != tt.want {
+ t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want)
+ }
+ }
+}
+
+func TestDecodedLen(t *testing.T) {
+ for _, tt := range []struct {
+ enc *Encoding
+ n int
+ want int
+ }{
+ {RawStdEncoding, 0, 0},
+ {RawStdEncoding, 2, 1},
+ {RawStdEncoding, 3, 2},
+ {RawStdEncoding, 4, 3},
+ {RawStdEncoding, 10, 7},
+ {StdEncoding, 0, 0},
+ {StdEncoding, 4, 3},
+ {StdEncoding, 8, 6},
+ } {
+ if got := tt.enc.DecodedLen(tt.n); got != tt.want {
+ t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want)
+ }
+ }
+}
+
func TestBig(t *testing.T) {
n := 3*1000 + 1
raw := make([]byte, n)
@@ -391,6 +441,22 @@ func TestDecoderIssue7733(t *testing.T) {
}
}
+func TestDecoderIssue15656(t *testing.T) {
+ _, err := StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
+ want := CorruptInputError(22)
+ if !reflect.DeepEqual(want, err) {
+ t.Errorf("Error = %v; want CorruptInputError(22)", err)
+ }
+ _, err = StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDA==")
+ if err != nil {
+ t.Errorf("Error = %v; want nil", err)
+ }
+ _, err = StdEncoding.DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
+ if err != nil {
+ t.Errorf("Error = %v; want nil", err)
+ }
+}
+
func BenchmarkEncodeToString(b *testing.B) {
data := make([]byte, 8192)
b.SetBytes(int64(len(data)))
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index 1c2577b68d..3834254596 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,7 +7,7 @@
//
// Numbers are translated by reading and writing fixed-size values.
// A fixed-size value is either a fixed-size arithmetic
-// type (int8, uint8, int16, float32, complex64, ...)
+// type (bool, int8, uint8, int16, float32, complex64, ...)
// or an array or struct containing only fixed-size values.
//
// The varint functions encode and decode single integer values using
@@ -48,18 +48,24 @@ var BigEndian bigEndian
type littleEndian struct{}
-func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+func (littleEndian) 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 (littleEndian) 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 (littleEndian) 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 (littleEndian) 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)
@@ -67,11 +73,13 @@ func (littleEndian) PutUint32(b []byte, v uint32) {
}
func (littleEndian) 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
}
func (littleEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
@@ -88,18 +96,24 @@ func (littleEndian) GoString() string { return "binary.LittleEndian" }
type bigEndian struct{}
-func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+func (bigEndian) 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 (bigEndian) 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 (bigEndian) 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 (bigEndian) 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)
@@ -107,11 +121,13 @@ func (bigEndian) PutUint32(b []byte, v uint32) {
}
func (bigEndian) 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
}
func (bigEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
@@ -131,6 +147,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// of fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
+// When decoding boolean values, a zero byte is decoded as false, and
+// any other non-zero byte is decoded as true.
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
@@ -153,6 +171,8 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
return err
}
switch data := data.(type) {
+ case *bool:
+ *data = b[0] != 0
case *int8:
*data = int8(b[0])
case *uint8:
@@ -169,8 +189,12 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
*data = int64(order.Uint64(bs))
case *uint64:
*data = order.Uint64(bs)
- case []int8:
+ case []bool:
for i, x := range bs { // Easier to loop over the input for 8-bit values.
+ data[i] = x != 0
+ }
+ case []int8:
+ for i, x := range bs {
data[i] = int8(x)
}
case []uint8:
@@ -227,6 +251,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Write writes the binary representation of data into w.
// Data must be a fixed-size value or a slice of fixed-size
// values, or a pointer to such data.
+// Boolean values encode as one byte: 1 for true, and 0 for false.
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
// When writing structs, zero values are written for fields
@@ -242,6 +267,26 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
bs = b[:n]
}
switch v := data.(type) {
+ case *bool:
+ if *v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case bool:
+ if v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case []bool:
+ for i, x := range v {
+ if x {
+ bs[i] = 1
+ } else {
+ bs[i] = 0
+ }
+ }
case *int8:
b[0] = byte(*v)
case int8:
@@ -253,7 +298,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
case *uint8:
b[0] = *v
case uint8:
- b[0] = byte(v)
+ b[0] = v
case []uint8:
bs = v
case *int16:
@@ -362,7 +407,8 @@ func sizeof(t reflect.Type) int {
}
return sum
- case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ case reflect.Bool,
+ reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
return int(t.Size())
@@ -379,6 +425,21 @@ type coder struct {
type decoder coder
type encoder coder
+func (d *decoder) bool() bool {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x != 0
+}
+
+func (e *encoder) bool(x bool) {
+ if x {
+ e.buf[0] = 1
+ } else {
+ e.buf[0] = 0
+ }
+ e.buf = e.buf[1:]
+}
+
func (d *decoder) uint8() uint8 {
x := d.buf[0]
d.buf = d.buf[1:]
@@ -469,6 +530,9 @@ func (d *decoder) value(v reflect.Value) {
d.value(v.Index(i))
}
+ case reflect.Bool:
+ v.SetBool(d.bool())
+
case reflect.Int8:
v.SetInt(int64(d.int8()))
case reflect.Int16:
@@ -531,6 +595,9 @@ func (e *encoder) value(v reflect.Value) {
e.value(v.Index(i))
}
+ case reflect.Bool:
+ e.bool(v.Bool())
+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v.Type().Kind() {
case reflect.Int8:
@@ -593,7 +660,7 @@ func (e *encoder) skip(v reflect.Value) {
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
func intDataSize(data interface{}) int {
switch data := data.(type) {
- case int8, uint8, *int8, *uint8:
+ case bool, int8, uint8, *bool, *int8, *uint8:
return 1
case []int8:
return len(data)
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index 7fd36fa4ef..fc7f2765ef 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -27,6 +27,8 @@ type Struct struct {
Complex64 complex64
Complex128 complex128
Array [4]uint8
+ Bool bool
+ BoolArray [4]bool
}
type T struct {
@@ -58,6 +60,9 @@ var s = Struct{
),
[4]uint8{0x43, 0x44, 0x45, 0x46},
+
+ true,
+ [4]bool{true, false, true, false},
}
var big = []byte{
@@ -76,6 +81,9 @@ var big = []byte{
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var little = []byte{
@@ -94,6 +102,9 @@ var little = []byte{
58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
@@ -141,6 +152,25 @@ func TestWriteSlice(t *testing.T) {
checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
}
+func TestReadBool(t *testing.T) {
+ var res bool
+ var err error
+ err = Read(bytes.NewReader([]byte{0}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, false)
+ res = false
+ err = Read(bytes.NewReader([]byte{1}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+ res = false
+ err = Read(bytes.NewReader([]byte{2}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+}
+
+func TestReadBoolSlice(t *testing.T) {
+ slice := make([]bool, 4)
+ err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice)
+ checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true})
+}
+
// Addresses of arrays are easier to manipulate with reflection than are slices.
var intArrays = []interface{}{
&[100]int8{},
@@ -266,7 +296,7 @@ func TestBlankFields(t *testing.T) {
}
// An attempt to read into a struct with an unexported field will
-// panic. This is probably not the best choice, but at this point
+// panic. This is probably not the best choice, but at this point
// anything else would be an API change.
type Unexported struct {
@@ -339,6 +369,33 @@ func TestReadTruncated(t *testing.T) {
}
}
+func testUint64SmallSliceLengthPanics() (panicked bool) {
+ defer func() {
+ panicked = recover() != nil
+ }()
+ b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
+ LittleEndian.Uint64(b[:4])
+ return false
+}
+
+func testPutUint64SmallSliceLengthPanics() (panicked bool) {
+ defer func() {
+ panicked = recover() != nil
+ }()
+ b := [8]byte{}
+ LittleEndian.PutUint64(b[:4], 0x0102030405060708)
+ return false
+}
+
+func TestEarlyBoundsChecks(t *testing.T) {
+ if testUint64SmallSliceLengthPanics() != true {
+ t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
+ }
+ if testPutUint64SmallSliceLengthPanics() != true {
+ t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
+ }
+}
+
type byteSliceReader struct {
remain []byte
}
@@ -373,8 +430,8 @@ func BenchmarkReadStruct(b *testing.B) {
Read(bsr, BigEndian, &t)
}
b.StopTimer()
- if !reflect.DeepEqual(s, t) {
- b.Fatal("no match")
+ if b.N > 0 && !reflect.DeepEqual(s, t) {
+ b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s)
}
}
@@ -395,18 +452,17 @@ func BenchmarkReadInts(b *testing.B) {
Read(r, BigEndian, &ls.Uint32)
Read(r, BigEndian, &ls.Uint64)
}
-
+ b.StopTimer()
want := s
want.Float32 = 0
want.Float64 = 0
want.Complex64 = 0
want.Complex128 = 0
- for i := range want.Array {
- want.Array[i] = 0
- }
- b.StopTimer()
- if !reflect.DeepEqual(ls, want) {
- panic("no match")
+ want.Array = [4]uint8{0, 0, 0, 0}
+ want.Bool = false
+ want.BoolArray = [4]bool{false, false, false, false}
+ if b.N > 0 && !reflect.DeepEqual(ls, want) {
+ b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
}
}
@@ -427,7 +483,7 @@ func BenchmarkWriteInts(b *testing.B) {
Write(w, BigEndian, s.Uint64)
}
b.StopTimer()
- if !bytes.Equal(buf.Bytes(), big[:30]) {
+ if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
}
}
diff --git a/libgo/go/encoding/binary/varint.go b/libgo/go/encoding/binary/varint.go
index 3a2dfa3c74..d7a75f99b1 100644
--- a/libgo/go/encoding/binary/varint.go
+++ b/libgo/go/encoding/binary/varint.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go
index a6bb780bf2..c8c4ca7758 100644
--- a/libgo/go/encoding/csv/reader.go
+++ b/libgo/go/encoding/csv/reader.go
@@ -3,6 +3,8 @@
// license that can be found in the LICENSE file.
// Package csv reads and writes comma-separated values (CSV) files.
+// There are many kinds of CSV files; this package supports the format
+// described in RFC 4180.
//
// A csv file contains zero or more records of one or more fields per record.
// Each record is separated by the newline character. The final record may
@@ -14,11 +16,11 @@
//
// Carriage returns before newline characters are silently removed.
//
-// Blank lines are ignored. A line with only whitespace characters (excluding
+// Blank lines are ignored. A line with only whitespace characters (excluding
// the ending newline character) is not considered a blank line.
//
// Fields which start and stop with the quote character " are called
-// quoted-fields. The beginning and ending quote are not part of the
+// quoted-fields. The beginning and ending quote are not part of the
// field.
//
// The source:
@@ -84,32 +86,42 @@ var (
// The exported fields can be changed to customize the details before the
// first call to Read or ReadAll.
//
-// Comma is the field delimiter. It defaults to ','.
//
-// Comment, if not 0, is the comment character. Lines beginning with the
-// Comment character are ignored.
-//
-// If FieldsPerRecord is positive, Read requires each record to
-// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
-// the number of fields in the first record, so that future records must
-// have the same field count. If FieldsPerRecord is negative, no check is
-// made and records may have a variable number of fields.
-//
-// If LazyQuotes is true, a quote may appear in an unquoted field and a
-// non-doubled quote may appear in a quoted field.
-//
-// If TrimLeadingSpace is true, leading white space in a field is ignored.
type Reader struct {
- Comma rune // field delimiter (set to ',' by NewReader)
- Comment rune // comment character for start of line
- FieldsPerRecord int // number of expected fields per record
- LazyQuotes bool // allow lazy quotes
- TrailingComma bool // ignored; here for backwards compatibility
- TrimLeadingSpace bool // trim leading space
- line int
- column int
- r *bufio.Reader
- field bytes.Buffer
+ // Comma is the field delimiter.
+ // It is set to comma (',') by NewReader.
+ Comma rune
+ // Comment, if not 0, is the comment character. Lines beginning with the
+ // Comment character without preceding whitespace are ignored.
+ // With leading whitespace the Comment character becomes part of the
+ // field, even if TrimLeadingSpace is true.
+ Comment rune
+ // FieldsPerRecord is the number of expected fields per record.
+ // If FieldsPerRecord is positive, Read requires each record to
+ // have the given number of fields. If FieldsPerRecord is 0, Read sets it to
+ // the number of fields in the first record, so that future records must
+ // have the same field count. If FieldsPerRecord is negative, no check is
+ // made and records may have a variable number of fields.
+ FieldsPerRecord int
+ // If LazyQuotes is true, a quote may appear in an unquoted field and a
+ // non-doubled quote may appear in a quoted field.
+ LazyQuotes bool
+ TrailingComma bool // ignored; here for backwards compatibility
+ // If TrimLeadingSpace is true, leading white space in a field is ignored.
+ // This is done even if the field delimiter, Comma, is white space.
+ TrimLeadingSpace bool
+
+ line int
+ column int
+ r *bufio.Reader
+ // lineBuffer holds the unescaped fields read by readField, one after another.
+ // The fields can be accessed by using the indexes in fieldIndexes.
+ // Example: for the row `a,"b","c""d",e` lineBuffer will contain `abc"de` and
+ // fieldIndexes will contain the indexes 0, 1, 2, 5.
+ lineBuffer bytes.Buffer
+ // Indexes of fields inside lineBuffer
+ // The i'th field starts at offset fieldIndexes[i] in lineBuffer.
+ fieldIndexes []int
}
// NewReader returns a new Reader that reads from r.
@@ -129,8 +141,12 @@ func (r *Reader) error(err error) error {
}
}
-// Read reads one record from r. The record is a slice of strings with each
-// string representing one field.
+// Read reads one record (a slice of fields) from r.
+// If the record has an unexpected number of fields,
+// Read returns the record along with the error ErrFieldCount.
+// Except for that case, Read always returns either a non-nil
+// record or a non-nil error, but not both.
+// If there is no data left to be read, Read returns nil, io.EOF.
func (r *Reader) Read() (record []string, err error) {
for {
record, err = r.parseRecord()
@@ -177,7 +193,7 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
func (r *Reader) readRune() (rune, error) {
r1, _, err := r.r.ReadRune()
- // Handle \r\n here. We make the simplifying assumption that
+ // Handle \r\n here. We make the simplifying assumption that
// anytime \r is followed by \n that it can be folded to \n.
// We will not detect files which contain both \r\n and bare \n.
if r1 == '\r' {
@@ -208,13 +224,13 @@ func (r *Reader) skip(delim rune) error {
// parseRecord reads and parses a single csv record from r.
func (r *Reader) parseRecord() (fields []string, err error) {
- // Each record starts on a new line. We increment our line
+ // Each record starts on a new line. We increment our line
// number (lines start at 1, not 0) and set column to -1
// so as we increment in readRune it points to the character we read.
r.line++
r.column = -1
- // Peek at the first rune. If it is an error we are done.
+ // Peek at the first rune. If it is an error we are done.
// If we support comments and it is the comment character
// then skip to the end of line.
@@ -228,31 +244,54 @@ func (r *Reader) parseRecord() (fields []string, err error) {
}
r.r.UnreadRune()
+ r.lineBuffer.Reset()
+ r.fieldIndexes = r.fieldIndexes[:0]
+
// At this point we have at least one field.
for {
+ idx := r.lineBuffer.Len()
+
haveField, delim, err := r.parseField()
if haveField {
- // If FieldsPerRecord is greater then 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)
- }
- fields = append(fields, r.field.String())
+ r.fieldIndexes = append(r.fieldIndexes, idx)
}
+
if delim == '\n' || err == io.EOF {
- return fields, err
- } else if err != nil {
+ if len(r.fieldIndexes) == 0 {
+ return nil, err
+ }
+ break
+ }
+
+ if err != nil {
return nil, err
}
}
+
+ fieldCount := len(r.fieldIndexes)
+ // Using this approach (creating a single string and taking slices of it)
+ // means that a single reference to any of the fields will retain the whole
+ // string. The risk of a nontrivial space leak caused by this is considered
+ // minimal and a tradeoff for better performance through the combined
+ // allocations.
+ line := r.lineBuffer.String()
+ fields = make([]string, fieldCount)
+
+ for i, idx := range r.fieldIndexes {
+ if i == fieldCount-1 {
+ fields[i] = line[idx:]
+ } else {
+ fields[i] = line[idx:r.fieldIndexes[i+1]]
+ }
+ }
+
+ return fields, nil
}
-// parseField parses the next field in the record. The read field is
-// located in r.field. Delim is the first character not part of the field
+// parseField parses the next field in the record. The read field is
+// appended to r.lineBuffer. Delim is the first character not part of the field
// (r.Comma or '\n').
func (r *Reader) parseField() (haveField bool, delim rune, err error) {
- r.field.Reset()
-
r1, err := r.readRune()
for err == nil && r.TrimLeadingSpace && r1 != '\n' && unicode.IsSpace(r1) {
r1, err = r.readRune()
@@ -305,19 +344,19 @@ func (r *Reader) parseField() (haveField bool, delim rune, err error) {
return false, 0, r.error(ErrQuote)
}
// accept the bare quote
- r.field.WriteRune('"')
+ r.lineBuffer.WriteRune('"')
}
case '\n':
r.line++
r.column = -1
}
- r.field.WriteRune(r1)
+ r.lineBuffer.WriteRune(r1)
}
default:
// unquoted field
for {
- r.field.WriteRune(r1)
+ r.lineBuffer.WriteRune(r1)
r1, err = r.readRune()
if err != nil || r1 == r.Comma {
break
diff --git a/libgo/go/encoding/csv/reader_test.go b/libgo/go/encoding/csv/reader_test.go
index be1002d034..7b3aca4c5f 100644
--- a/libgo/go/encoding/csv/reader_test.go
+++ b/libgo/go/encoding/csv/reader_test.go
@@ -5,6 +5,7 @@
package csv
import (
+ "io"
"reflect"
"strings"
"testing"
@@ -292,8 +293,52 @@ func TestRead(t *testing.T) {
}
}
-func BenchmarkRead(b *testing.B) {
- data := `x,y,z,w
+// nTimes is an io.Reader which yields the string s n times.
+type nTimes struct {
+ s string
+ n int
+ off int
+}
+
+func (r *nTimes) Read(p []byte) (n int, err error) {
+ for {
+ if r.n <= 0 || r.s == "" {
+ return n, io.EOF
+ }
+ n0 := copy(p, r.s[r.off:])
+ p = p[n0:]
+ n += n0
+ r.off += n0
+ if r.off == len(r.s) {
+ r.off = 0
+ r.n--
+ }
+ if len(p) == 0 {
+ return
+ }
+ }
+}
+
+// benchmarkRead measures reading the provided CSV rows data.
+// initReader, if non-nil, modifies the Reader before it's used.
+func benchmarkRead(b *testing.B, initReader func(*Reader), rows string) {
+ b.ReportAllocs()
+ r := NewReader(&nTimes{s: rows, n: b.N})
+ if initReader != nil {
+ initReader(r)
+ }
+ for {
+ _, err := r.Read()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+const benchmarkCSVData = `x,y,z,w
x,y,z,
x,y,,
x,,,
@@ -305,11 +350,22 @@ x,,,
"","","",""
`
- for i := 0; i < b.N; i++ {
- _, err := NewReader(strings.NewReader(data)).ReadAll()
+func BenchmarkRead(b *testing.B) {
+ benchmarkRead(b, nil, benchmarkCSVData)
+}
- if err != nil {
- b.Fatalf("could not read data: %s", err)
- }
- }
+func BenchmarkReadWithFieldsPerRecord(b *testing.B) {
+ benchmarkRead(b, func(r *Reader) { r.FieldsPerRecord = 4 }, benchmarkCSVData)
+}
+
+func BenchmarkReadWithoutFieldsPerRecord(b *testing.B) {
+ benchmarkRead(b, func(r *Reader) { r.FieldsPerRecord = -1 }, benchmarkCSVData)
+}
+
+func BenchmarkReadLargeFields(b *testing.B) {
+ benchmarkRead(b, nil, strings.Repeat(`xxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+xxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvv
+,,zzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+`, 3))
}
diff --git a/libgo/go/encoding/csv/writer.go b/libgo/go/encoding/csv/writer.go
index 353d91f238..84b7aa1ed1 100644
--- a/libgo/go/encoding/csv/writer.go
+++ b/libgo/go/encoding/csv/writer.go
@@ -15,7 +15,7 @@ import (
// A Writer writes records to a CSV encoded file.
//
// As returned by NewWriter, a Writer writes records terminated by a
-// newline and uses ',' as the field delimiter. The exported fields can be
+// newline and uses ',' as the field delimiter. The exported fields can be
// changed to customize the details before the first call to Write or WriteAll.
//
// Comma is the field delimiter.
@@ -37,27 +37,28 @@ func NewWriter(w io.Writer) *Writer {
// Writer writes a single CSV record to w along with any necessary quoting.
// A record is a slice of strings with each string being one field.
-func (w *Writer) Write(record []string) (err error) {
+func (w *Writer) Write(record []string) error {
for n, field := range record {
if n > 0 {
- if _, err = w.w.WriteRune(w.Comma); err != nil {
- return
+ if _, err := w.w.WriteRune(w.Comma); err != nil {
+ return err
}
}
// If we don't have to have a quoted field then just
// write out the field and continue to the next field.
if !w.fieldNeedsQuotes(field) {
- if _, err = w.w.WriteString(field); err != nil {
- return
+ if _, err := w.w.WriteString(field); err != nil {
+ return err
}
continue
}
- if err = w.w.WriteByte('"'); err != nil {
- return
+ if err := w.w.WriteByte('"'); err != nil {
+ return err
}
for _, r1 := range field {
+ var err error
switch r1 {
case '"':
_, err = w.w.WriteString(`""`)
@@ -75,20 +76,21 @@ func (w *Writer) Write(record []string) (err error) {
_, err = w.w.WriteRune(r1)
}
if err != nil {
- return
+ return err
}
}
- if err = w.w.WriteByte('"'); err != nil {
- return
+ if err := w.w.WriteByte('"'); err != nil {
+ return err
}
}
+ var err error
if w.UseCRLF {
_, err = w.w.WriteString("\r\n")
} else {
err = w.w.WriteByte('\n')
}
- return
+ return err
}
// Flush writes any buffered data to the underlying io.Writer.
@@ -104,9 +106,9 @@ func (w *Writer) Error() error {
}
// WriteAll writes multiple CSV records to w using Write and then calls Flush.
-func (w *Writer) WriteAll(records [][]string) (err error) {
+func (w *Writer) WriteAll(records [][]string) error {
for _, record := range records {
- err = w.Write(record)
+ err := w.Write(record)
if err != nil {
return err
}
@@ -130,7 +132,7 @@ func (w *Writer) fieldNeedsQuotes(field string) bool {
if field == "" {
return false
}
- if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") {
return true
}
diff --git a/libgo/go/encoding/encoding.go b/libgo/go/encoding/encoding.go
index 6d218071b7..cc5a536996 100644
--- a/libgo/go/encoding/encoding.go
+++ b/libgo/go/encoding/encoding.go
@@ -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.
diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go
index 8efcdc78ff..d4002cbcca 100644
--- a/libgo/go/encoding/gob/codec_test.go
+++ b/libgo/go/encoding/gob/codec_test.go
@@ -970,7 +970,7 @@ func TestBadRecursiveType(t *testing.T) {
err := NewEncoder(b).Encode(&rec)
if err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.Error(), "recursive") < 0 {
+ } else if !strings.Contains(err.Error(), "recursive") {
t.Error("expected recursive type error; got", err)
}
// Can't test decode easily because we can't encode one, so we can't pass one to a Decoder.
@@ -1253,7 +1253,7 @@ func TestIgnoreInterface(t *testing.T) {
if item2.I != item1.I {
t.Error("normal int did not decode correctly")
}
- if item2.F != item2.F {
+ if item2.F != item1.F {
t.Error("normal float did not decode correctly")
}
}
@@ -1280,7 +1280,7 @@ func TestUnexportedFields(t *testing.T) {
if err != nil {
t.Fatal("decode error:", err)
}
- if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ if u0.A != u1.A || u0.B != u1.B || u0.D != u1.D {
t.Errorf("u1->u0: expected %v; got %v", u0, u1)
}
if u1.c != 1234. {
diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go
index 536bbdb5ac..d69d36f516 100644
--- a/libgo/go/encoding/gob/debug.go
+++ b/libgo/go/encoding/gob/debug.go
@@ -7,7 +7,7 @@
package gob
-// This file is not normally included in the gob package. Used only for debugging the package itself.
+// This file is not normally included in the gob package. Used only for debugging the package itself.
// Except for reading uints, it is an implementation of a reader that is independent of
// the one implemented by Decoder.
// To enable the Debug function, delete the +build ignore line above and do
@@ -241,7 +241,7 @@ func (deb *debugger) delimitedMessage(indent tab) bool {
// loadBlock preps us to read a message
// of the length specified next in the input. It returns
// the length of the block. The argument tells whether
-// an EOF is acceptable now. If it is and one is found,
+// an EOF is acceptable now. If it is and one is found,
// the return value is negative.
func (deb *debugger) loadBlock(eofOK bool) int {
n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF
@@ -339,7 +339,7 @@ func (deb *debugger) string() string {
return string(b)
}
-// delta returns the field delta at the input point. The expect argument,
+// delta returns the field delta at the input point. The expect argument,
// if non-negative, identifies what the value should be.
func (deb *debugger) delta(expect int) int {
delta := int(deb.uint64())
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index 3b0dca86f3..9645dc5790 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -216,10 +216,10 @@ func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) {
}
// Since the encoder writes no zeros, if we arrive at a decoder we have
-// a value to extract and store. The field number has already been read
+// a value to extract and store. The field number has already been read
// (it's how we knew to call this decoder).
// Each decoder is responsible for handling any indirections associated
-// with the data structure. If any pointer so reached is nil, allocation must
+// with the data structure. If any pointer so reached is nil, allocation must
// be done.
// decAlloc takes a value and returns a settable value that can
@@ -308,9 +308,9 @@ func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
}
// Floating-point numbers are transmitted as uint64s holding the bits
-// of the underlying representation. They are sent byte-reversed, with
+// of the underlying representation. They are sent byte-reversed, with
// the exponent end coming out first, so integer floating point numbers
-// (for example) transmit more compactly. This routine does the
+// (for example) transmit more compactly. This routine does the
// unswizzling.
func float64FromBits(u uint64) float64 {
var v uint64
@@ -332,7 +332,7 @@ func float32FromBits(u uint64, ovfl error) float64 {
if av < 0 {
av = -av
}
- // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
+ // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
error_(ovfl)
}
@@ -421,7 +421,7 @@ func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
// Execution engine
// The encoder engine is an array of instructions indexed by field number of the incoming
-// decoder. It is executed with random access according to field number.
+// decoder. It is executed with random access according to field number.
type decEngine struct {
instr []decInstr
numInstr int // the number of active instructions
@@ -442,7 +442,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value refl
}
// decodeStruct decodes a top-level struct and stores it in value.
-// Indir is for the value, not the type. At the time of the call it may
+// Indir is for the value, not the type. At the time of the call it may
// differ from ut.indir, which was computed when the engine was built.
// This state cannot arise for decodeSingle, which is called directly
// from the user's value, not from the innards of an engine.
@@ -536,7 +536,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value,
}
// decodeArray decodes an array and stores it in value.
-// The length is an unsigned integer preceding the elements. Even though the length is redundant
+// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
if n := state.decodeUint(); n != uint64(length) {
@@ -645,10 +645,10 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
errorf("invalid type name length %d: exceeds input size", nr)
}
n := int(nr)
- name := string(state.b.Bytes()[:n])
+ name := state.b.Bytes()[:n]
state.b.Drop(n)
// Allocate the destination interface value.
- if name == "" {
+ if len(name) == 0 {
// Copy the nil interface value to the target.
value.Set(reflect.Zero(value.Type()))
return
@@ -658,7 +658,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
}
// The concrete type must be registered.
registerLock.RLock()
- typ, ok := nameToConcreteType[name]
+ typ, ok := nameToConcreteType[string(name)]
registerLock.RUnlock()
if !ok {
errorf("name not registered for interface: %q", name)
@@ -1075,7 +1075,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
return
}
-// compileDec compiles the decoder engine for a value. If the value is not a struct,
+// compileDec compiles the decoder engine for a value. If the value is not a struct,
// it calls out to compileSingle.
func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
defer catchError(&err)
diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go
index c453e9ba39..c182941773 100644
--- a/libgo/go/encoding/gob/decoder.go
+++ b/libgo/go/encoding/gob/decoder.go
@@ -130,9 +130,9 @@ func (dec *Decoder) nextUint() uint64 {
// decodeTypeSequence parses:
// TypeSequence
// (TypeDefinition DelimitedTypeDefinition*)?
-// and returns the type id of the next value. It returns -1 at
+// and returns the type id of the next value. It returns -1 at
// EOF. Upon return, the remainder of dec.buf is the value to be
-// decoded. If this is an interface value, it can be ignored by
+// decoded. If this is an interface value, it can be ignored by
// resetting that buffer.
func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
for dec.err == nil {
@@ -150,7 +150,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// Type definition for (-id) follows.
dec.recvType(-id)
// When decoding an interface, after a type there may be a
- // DelimitedValue still in the buffer. Skip its count.
+ // DelimitedValue still in the buffer. Skip its count.
// (Alternatively, the buffer is empty and the byte count
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
@@ -177,7 +177,7 @@ func (dec *Decoder) Decode(e interface{}) error {
}
value := reflect.ValueOf(e)
// If e represents a value as opposed to a pointer, the answer won't
- // get back to the caller. Make sure it's a pointer.
+ // get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
dec.err = errors.New("gob: attempt to decode into a non-pointer")
return dec.err
@@ -187,7 +187,7 @@ func (dec *Decoder) Decode(e interface{}) error {
// DecodeValue reads the next value from the input stream.
// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
-// Otherwise, it stores the value into v. In that case, v must represent
+// Otherwise, it stores the value into v. In that case, v must represent
// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
// If the input is at EOF, DecodeValue returns io.EOF and
// does not modify v.
diff --git a/libgo/go/encoding/gob/doc.go b/libgo/go/encoding/gob/doc.go
index cf878f4502..1536574fed 100644
--- a/libgo/go/encoding/gob/doc.go
+++ b/libgo/go/encoding/gob/doc.go
@@ -17,7 +17,8 @@ Basics
A stream of gobs is self-describing. Each data item in the stream is preceded by
a specification of its type, expressed in terms of a small set of predefined
types. Pointers are not transmitted, but the things they point to are
-transmitted; that is, the values are flattened. Recursive types work fine, but
+transmitted; that is, the values are flattened. Nil pointers are not permitted,
+as they have no value. Recursive types work fine, but
recursive values (data with cycles) are problematic. This may change.
To use gobs, create an Encoder and present it with a series of data items as
@@ -254,6 +255,12 @@ In summary, a gob stream looks like
where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
+Compatibility: Any future changes to the package will endeavor to maintain
+compatibility with streams encoded using previous versions. That is, any released
+version of this package should be able to decode data written with any previously
+released version, subject to issues such as security fixes. See the Go compatibility
+document for background: https://golang.org/doc/go1compat
+
See "Gobs of data" for a design discussion of the gob wire format:
https://blog.golang.org/gobs-of-data
*/
diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go
index 96052ef33b..50cd6adb46 100644
--- a/libgo/go/encoding/gob/encode.go
+++ b/libgo/go/encoding/gob/encode.go
@@ -96,7 +96,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) {
enc.freeList = e
}
-// Unsigned integers have a two-state encoding. If the number is less
+// Unsigned integers have a two-state encoding. If the number is less
// than 128 (0 through 0x7F), its value is written directly.
// Otherwise the value is written in big-endian byte order preceded
// by the byte length, negated.
@@ -127,7 +127,7 @@ func (state *encoderState) encodeInt(i int64) {
} else {
x = uint64(i << 1)
}
- state.encodeUint(uint64(x))
+ state.encodeUint(x)
}
// encOp is the signature of an encoding operator for a given type.
@@ -152,8 +152,8 @@ func (state *encoderState) update(instr *encInstr) {
// Each encoder for a composite is responsible for handling any
// indirections associated with the elements of the data structure.
-// If any pointer so reached is nil, no bytes are written. If the
-// data item is zero, no bytes are written. Single values - ints,
+// If any pointer so reached is nil, no bytes are written. If the
+// data item is zero, no bytes are written. Single values - ints,
// strings etc. - are indirected before calling their encoders.
// Otherwise, the output (for a scalar) is the field number, as an
// encoded integer, followed by the field data in its appropriate
@@ -203,9 +203,9 @@ func encUint(i *encInstr, state *encoderState, v reflect.Value) {
// floatBits returns a uint64 holding the bits of a floating-point number.
// Floating-point numbers are transmitted as uint64s holding the bits
-// of the underlying representation. They are sent byte-reversed, with
+// of the underlying representation. They are sent byte-reversed, with
// the exponent end coming out first, so integer floating point numbers
-// (for example) transmit more compactly. This routine does the
+// (for example) transmit more compactly. This routine does the
// swizzling.
func floatBits(f float64) uint64 {
u := math.Float64bits(f)
@@ -272,7 +272,7 @@ func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) {
// Execution engine
// encEngine an array of instructions indexed by field number of the encoding
-// data, typically a struct. It is executed top to bottom, walking the struct.
+// data, typically a struct. It is executed top to bottom, walking the struct.
type encEngine struct {
instr []encInstr
}
@@ -297,7 +297,7 @@ func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.
defer enc.freeEncoderState(state)
state.fieldnum = singletonField
// There is no surrounding struct to frame the transmission, so we must
- // generate data even if the item is zero. To do this, set sendZero.
+ // generate data even if the item is zero. To do this, set sendZero.
state.sendZero = true
instr := &engine.instr[singletonField]
if instr.indir > 0 {
@@ -386,7 +386,7 @@ func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encO
// encodeInterface encodes the interface value iv.
// To send an interface, we send a string identifying the concrete type, followed
// by the type identifier (which might require defining that type right now), followed
-// by the concrete value. A nil value gets sent as the empty string for the name,
+// by the concrete value. A nil value gets sent as the empty string for the name,
// followed by no value.
func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
// Gobs can encode nil interface values but not typed interface
@@ -417,7 +417,7 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
enc.sendTypeDescriptor(enc.writer(), state, ut)
// Send the type id.
enc.sendTypeId(state, ut)
- // Encode the value into a new buffer. Any nested type definitions
+ // Encode the value into a new buffer. Any nested type definitions
// should be written to b, before the encoded value.
enc.pushWriter(b)
data := encBufferPool.Get().(*encBuffer)
diff --git a/libgo/go/encoding/gob/encoder.go b/libgo/go/encoding/gob/encoder.go
index 62d0f42e81..40ec81b6e6 100644
--- a/libgo/go/encoding/gob/encoder.go
+++ b/libgo/go/encoding/gob/encoder.go
@@ -170,6 +170,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
// Encode transmits the data item represented by the empty interface value,
// guaranteeing that all necessary type information has been transmitted first.
+// Passing a nil pointer to Encoder will panic, as they cannot be transmitted by gob.
func (enc *Encoder) Encode(e interface{}) error {
return enc.EncodeValue(reflect.ValueOf(e))
}
@@ -191,7 +192,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use
return
}
// If the type info has still not been transmitted, it means we have
- // a singleton basic type (int, []byte etc.) at top level. We don't
+ // a singleton basic type (int, []byte etc.) at top level. We don't
// need to send the type info but we do need to update enc.sent.
if !sent {
info, err := getTypeInfo(ut)
@@ -212,9 +213,11 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
// EncodeValue transmits the data item represented by the reflection value,
// guaranteeing that all necessary type information has been transmitted first.
+// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob.
func (enc *Encoder) EncodeValue(value reflect.Value) error {
- // Gobs contain values. They cannot represent nil pointers, which
- // have no value to encode.
+ if value.Kind() == reflect.Invalid {
+ return errors.New("gob: cannot encode nil value")
+ }
if value.Kind() == reflect.Ptr && value.IsNil() {
panic("gob: cannot encode nil pointer of type " + value.Type().String())
}
diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go
index 570d79696b..9256848b50 100644
--- a/libgo/go/encoding/gob/encoder_test.go
+++ b/libgo/go/encoding/gob/encoder_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
+ "io/ioutil"
"reflect"
"strings"
"testing"
@@ -280,7 +281,7 @@ func TestValueError(t *testing.T) {
}
t4p := &Type4{3}
var t4 Type4 // note: not a pointer.
- if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 {
+ if err := encAndDec(t4p, t4); err == nil || !strings.Contains(err.Error(), "pointer") {
t.Error("expected error about pointer; got", err)
}
}
@@ -388,7 +389,7 @@ func TestSingletons(t *testing.T) {
t.Errorf("expected error decoding %v: %s", test.in, test.err)
continue
case err != nil && test.err != "":
- if strings.Index(err.Error(), test.err) < 0 {
+ if !strings.Contains(err.Error(), test.err) {
t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
}
continue
@@ -414,7 +415,7 @@ func TestStructNonStruct(t *testing.T) {
var ns NonStruct
if err := encAndDec(s, &ns); err == nil {
t.Error("should get error for struct/non-struct")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("for struct/non-struct expected type error; got", err)
}
// Now try the other way
@@ -424,7 +425,7 @@ func TestStructNonStruct(t *testing.T) {
}
if err := encAndDec(ns, &s); err == nil {
t.Error("should get error for non-struct/struct")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("for non-struct/struct expected type error; got", err)
}
}
@@ -439,8 +440,8 @@ func (this *interfaceIndirectTestT) F() bool {
return true
}
-// A version of a bug reported on golang-nuts. Also tests top-level
-// slice of interfaces. The issue was registering *T caused T to be
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
// stored as the concrete type.
func TestInterfaceIndirect(t *testing.T) {
Register(&interfaceIndirectTestT{})
@@ -463,7 +464,7 @@ func TestInterfaceIndirect(t *testing.T) {
// Also, when the ignored object contains an interface value, it may define
// types. Make sure that skipping the value still defines the types by using
-// the encoder/decoder pair to send a value afterwards. If an interface
+// the encoder/decoder pair to send a value afterwards. If an interface
// is sent, its type in the test is always NewType0, so this checks that the
// encoder and decoder don't skew with respect to type definitions.
@@ -603,10 +604,6 @@ type Bug1Elem struct {
type Bug1StructMap map[string]Bug1Elem
-func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) error {
- return nil
-}
-
func TestMapBug1(t *testing.T) {
in := make(Bug1StructMap)
in["val1"] = Bug1Elem{"elem1", 1}
@@ -833,32 +830,97 @@ func TestPtrToMapOfMap(t *testing.T) {
}
}
+// Test that untyped nils generate an error, not a panic.
+// See Issue 16204.
+func TestCatchInvalidNilValue(t *testing.T) {
+ encodeErr, panicErr := encodeAndRecover(nil)
+ if panicErr != nil {
+ t.Fatalf("panicErr=%v, should not panic encoding untyped nil", panicErr)
+ }
+ if encodeErr == nil {
+ t.Errorf("got err=nil, want non-nil error when encoding untyped nil value")
+ } else if !strings.Contains(encodeErr.Error(), "nil value") {
+ t.Errorf("expected 'nil value' error; got err=%v", encodeErr)
+ }
+}
+
// A top-level nil pointer generates a panic with a helpful string-valued message.
func TestTopLevelNilPointer(t *testing.T) {
- errMsg := topLevelNilPanic(t)
- if errMsg == "" {
+ var ip *int
+ encodeErr, panicErr := encodeAndRecover(ip)
+ if encodeErr != nil {
+ t.Fatal("error in encode:", encodeErr)
+ }
+ if panicErr == nil {
t.Fatal("top-level nil pointer did not panic")
}
+ errMsg := panicErr.Error()
if !strings.Contains(errMsg, "nil pointer") {
t.Fatal("expected nil pointer error, got:", errMsg)
}
}
-func topLevelNilPanic(t *testing.T) (panicErr string) {
+func encodeAndRecover(value interface{}) (encodeErr, panicErr error) {
defer func() {
e := recover()
- if err, ok := e.(string); ok {
- panicErr = err
+ if e != nil {
+ switch err := e.(type) {
+ case error:
+ panicErr = err
+ default:
+ panicErr = fmt.Errorf("%v", err)
+ }
}
}()
- var ip *int
- buf := new(bytes.Buffer)
- if err := NewEncoder(buf).Encode(ip); err != nil {
- t.Fatal("error in encode:", err)
- }
+
+ encodeErr = NewEncoder(ioutil.Discard).Encode(value)
return
}
+func TestNilPointerPanics(t *testing.T) {
+ var (
+ nilStringPtr *string
+ intMap = make(map[int]int)
+ intMapPtr = &intMap
+ nilIntMapPtr *map[int]int
+ zero int
+ nilBoolChannel chan bool
+ nilBoolChannelPtr *chan bool
+ nilStringSlice []string
+ stringSlice = make([]string, 1)
+ nilStringSlicePtr *[]string
+ )
+
+ testCases := []struct {
+ value interface{}
+ mustPanic bool
+ }{
+ {nilStringPtr, true},
+ {intMap, false},
+ {intMapPtr, false},
+ {nilIntMapPtr, true},
+ {zero, false},
+ {nilStringSlice, false},
+ {stringSlice, false},
+ {nilStringSlicePtr, true},
+ {nilBoolChannel, false},
+ {nilBoolChannelPtr, true},
+ }
+
+ for _, tt := range testCases {
+ _, panicErr := encodeAndRecover(tt.value)
+ if tt.mustPanic {
+ if panicErr == nil {
+ t.Errorf("expected panic with input %#v, did not panic", tt.value)
+ }
+ continue
+ }
+ if panicErr != nil {
+ t.Fatalf("expected no panic with input %#v, got panic=%v", tt.value, panicErr)
+ }
+ }
+}
+
func TestNilPointerInsideInterface(t *testing.T) {
var ip *int
si := struct {
@@ -913,7 +975,7 @@ func TestMutipleEncodingsOfBadType(t *testing.T) {
// There was an error check comparing the length of the input with the
// length of the slice being decoded. It was wrong because the next
// thing in the input might be a type definition, which would lead to
-// an incorrect length check. This test reproduces the corner case.
+// an incorrect length check. This test reproduces the corner case.
type Z struct {
}
diff --git a/libgo/go/encoding/gob/error.go b/libgo/go/encoding/gob/error.go
index 92cc0c615e..8b5265c278 100644
--- a/libgo/go/encoding/gob/error.go
+++ b/libgo/go/encoding/gob/error.go
@@ -9,7 +9,7 @@ import "fmt"
// Errors in decoding and encoding are handled using panic and recover.
// Panics caused by user error (that is, everything except run-time panics
// such as "index out of bounds" errors) do not leave the file that caused
-// them, but are instead turned into plain error returns. Encoding and
+// them, but are instead turned into plain error returns. Encoding and
// decoding functions and methods that do not return an error either use
// panic to report an error or are guaranteed error-free.
@@ -30,7 +30,7 @@ func error_(err error) {
}
// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
-// plain error. It overwrites the error return of the function that deferred its call.
+// plain error. It overwrites the error return of the function that deferred its call.
func catchError(err *error) {
if e := recover(); e != nil {
ge, ok := e.(gobError)
diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go
index eb76b481d1..ecc91eef1f 100644
--- a/libgo/go/encoding/gob/gobencdec_test.go
+++ b/libgo/go/encoding/gob/gobencdec_test.go
@@ -376,7 +376,7 @@ func TestGobEncoderIndirectArrayField(t *testing.T) {
}
// As long as the fields have the same name and implement the
-// interface, we can cross-connect them. Not sure it's useful
+// interface, we can cross-connect them. Not sure it's useful
// and may even be bad but it works and it's hard to prevent
// without exposing the contents of the object, which would
// defeat the purpose.
@@ -434,7 +434,7 @@ func TestGobEncoderValueEncoder(t *testing.T) {
}
// Test that we can use a value then a pointer type of a GobEncoder
-// in the same encoded value. Bug 4647.
+// in the same encoded value. Bug 4647.
func TestGobEncoderValueThenPointer(t *testing.T) {
v := ValueGobber("forty-two")
w := ValueGobber("six-by-nine")
@@ -548,7 +548,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
}
- if strings.Index(err.Error(), "type") < 0 {
+ if !strings.Contains(err.Error(), "type") {
t.Fatal("expected type error; got", err)
}
// Non-encoder to GobDecoder: error
@@ -562,7 +562,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
}
- if strings.Index(err.Error(), "type") < 0 {
+ if !strings.Contains(err.Error(), "type") {
t.Fatal("expected type error; got", err)
}
}
diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go
index cf5cec0703..c27f7e9707 100644
--- a/libgo/go/encoding/gob/type.go
+++ b/libgo/go/encoding/gob/type.go
@@ -17,7 +17,7 @@ import (
)
// userTypeInfo stores the information associated with a type the user has handed
-// to the package. It's computed once and stored in a map keyed by reflection
+// to the package. It's computed once and stored in a map keyed by reflection
// type.
type userTypeInfo struct {
user reflect.Type // the type the user handed us
@@ -44,7 +44,7 @@ var (
)
// validType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, err will be non-nil. To be used when the error handler
+// If the user type is not valid, err will be non-nil. To be used when the error handler
// is not set up.
func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
userTypeLock.RLock()
@@ -64,7 +64,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
ut.base = rt
ut.user = rt
// A type that is just a cycle of pointers (such as type T *T) cannot
- // be represented in gobs, which need some concrete data. We use a
+ // be represented in gobs, which need some concrete data. We use a
// cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
// pp 539-540. As we step through indirections, run another type at
// half speed. If they meet up, there's a cycle.
@@ -493,7 +493,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
// For arrays, maps, and slices, we set the type id after the elements
// are constructed. This is to retain the order of type id allocation after
// a fix made to handle recursive types, which changed the order in
- // which types are built. Delaying the setting in this way preserves
+ // which types are built. Delaying the setting in this way preserves
// type ids while allowing recursive types to be described. Structs,
// done below, were already handling recursion correctly so they
// assign the top-level id before those of the field.
@@ -597,7 +597,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, error) {
// getType returns the Gob type describing the given reflect.Type.
// Should be called only when handling GobEncoders/Decoders,
-// which may be pointers. All other types are handled through the
+// which may be pointers. All other types are handled through the
// base type, never a pointer.
// typeLock must be held.
func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {
@@ -642,7 +642,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// For bootstrapping purposes, we assume that the recipient knows how
// to decode a wireType; it is exactly the wireType struct here, interpreted
// using the gob rules for sending a structure, except that we assume the
-// ids for wireType and structType etc. are known. The relevant pieces
+// ids for wireType and structType etc. are known. The relevant pieces
// are built in encode.go's init() function.
// To maintain binary compatibility, if you extend this type, always put
// the new fields last.
@@ -789,7 +789,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
//
// Note: Since gobs can be stored permanently, it is good design
// to guarantee the encoding used by a GobEncoder is stable as the
-// software evolves. For instance, it might make sense for GobEncode
+// software evolves. For instance, it might make sense for GobEncode
// to include a version number in the encoding.
type GobEncoder interface {
// GobEncode returns a byte slice representing the encoding of the
@@ -838,8 +838,8 @@ func RegisterName(name string, value interface{}) {
}
// Register records a type, identified by a value for that type, under its
-// internal type name. That name will identify the concrete type of a value
-// sent or received as an interface variable. Only types that will be
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
// transferred as implementations of interface values need to be registered.
// Expecting to be used only during initialization, it panics if the mapping
// between types and names is not a bijection.
diff --git a/libgo/go/encoding/hex/example_test.go b/libgo/go/encoding/hex/example_test.go
new file mode 100644
index 0000000000..fb1554eba7
--- /dev/null
+++ b/libgo/go/encoding/hex/example_test.go
@@ -0,0 +1,100 @@
+// 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 hex_test
+
+import (
+ "encoding/hex"
+ "fmt"
+ "log"
+ "os"
+)
+
+func ExampleEncode() {
+ src := []byte("Hello Gopher!")
+
+ dst := make([]byte, hex.EncodedLen(len(src)))
+ hex.Encode(dst, src)
+
+ fmt.Printf("%s\n", dst)
+
+ // Output:
+ // 48656c6c6f20476f7068657221
+}
+
+func ExampleDecode() {
+ src := []byte("48656c6c6f20476f7068657221")
+
+ dst := make([]byte, hex.DecodedLen(len(src)))
+ n, err := hex.Decode(dst, src)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", dst[:n])
+
+ // Output:
+ // Hello Gopher!
+}
+
+func ExampleDecodeString() {
+ const s = "48656c6c6f20476f7068657221"
+ decoded, err := hex.DecodeString(s)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", decoded)
+
+ // Output:
+ // Hello Gopher!
+}
+
+func ExampleDump() {
+ content := []byte("Go is an open source programming language.")
+
+ fmt.Printf("%s", hex.Dump(content))
+
+ // Output:
+ // 00000000 47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|
+ // 00000010 75 72 63 65 20 70 72 6f 67 72 61 6d 6d 69 6e 67 |urce programming|
+ // 00000020 20 6c 61 6e 67 75 61 67 65 2e | language.|
+}
+
+func ExampleDumper() {
+ lines := []string{
+ "Go is an open source programming language.",
+ "\n",
+ "We encourage all Go users to subscribe to golang-announce.",
+ }
+
+ stdoutDumper := hex.Dumper(os.Stdout)
+
+ defer stdoutDumper.Close()
+
+ for _, line := range lines {
+ stdoutDumper.Write([]byte(line))
+ }
+
+ // Output:
+ // 00000000 47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|
+ // 00000010 75 72 63 65 20 70 72 6f 67 72 61 6d 6d 69 6e 67 |urce programming|
+ // 00000020 20 6c 61 6e 67 75 61 67 65 2e 0a 57 65 20 65 6e | language..We en|
+ // 00000030 63 6f 75 72 61 67 65 20 61 6c 6c 20 47 6f 20 75 |courage all Go u|
+ // 00000040 73 65 72 73 20 74 6f 20 73 75 62 73 63 72 69 62 |sers to subscrib|
+ // 00000050 65 20 74 6f 20 67 6f 6c 61 6e 67 2d 61 6e 6e 6f |e to golang-anno|
+ // 00000060 75 6e 63 65 2e |unce.|
+}
+
+func ExampleEncodeToString() {
+ src := []byte("Hello")
+ encodedStr := hex.EncodeToString(src)
+
+ fmt.Printf("%s\n", encodedStr)
+
+ // Output:
+ // 48656c6c6f
+}
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
index d1fc7024a9..b43c1c4b45 100644
--- a/libgo/go/encoding/hex/hex.go
+++ b/libgo/go/encoding/hex/hex.go
@@ -12,13 +12,17 @@ import (
"io"
)
-const hextable = "0123456789abcdef"
+var hextable = [16]byte{
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f',
+}
// EncodedLen returns the length of an encoding of n source bytes.
+// Specifically, it returns n * 2.
func EncodedLen(n int) int { return n * 2 }
// Encode encodes src into EncodedLen(len(src))
-// bytes of dst. As a convenience, it returns the number
+// bytes of dst. As a convenience, it returns the number
// of bytes written to dst, but this value is always EncodedLen(len(src)).
// Encode implements hexadecimal encoding.
func Encode(dst, src []byte) int {
@@ -40,12 +44,15 @@ func (e InvalidByteError) Error() string {
return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
}
+// DecodedLen returns the length of a decoding of x source bytes.
+// Specifically, it returns x / 2.
func DecodedLen(x int) int { return x / 2 }
-// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
-// number of bytes written to dst.
+// Decode decodes src into DecodedLen(len(src)) bytes,
+// returning the actual number of bytes written to dst.
//
-// If Decode encounters invalid input, it returns an error describing the failure.
+// Decode expects that src contain only hexadecimal
+// characters and that src should have an even length.
func Decode(dst, src []byte) (int, error) {
if len(src)%2 == 1 {
return 0, ErrLength
@@ -105,7 +112,7 @@ func Dump(data []byte) string {
dumper := Dumper(&buf)
dumper.Write(data)
dumper.Close()
- return string(buf.Bytes())
+ return buf.String()
}
// Dumper returns a WriteCloser that writes a hex dump of all written data to
diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go
index b969636cd5..64dabbd10a 100644
--- a/libgo/go/encoding/hex/hex_test.go
+++ b/libgo/go/encoding/hex/hex_test.go
@@ -6,6 +6,7 @@ package hex
import (
"bytes"
+ "fmt"
"testing"
)
@@ -151,3 +152,18 @@ var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a
00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE|
`)
+
+var sink []byte
+
+func BenchmarkEncode(b *testing.B) {
+ for _, size := range []int{256, 1024, 4096, 16384} {
+ src := bytes.Repeat([]byte{2, 3, 5, 7, 9, 11, 13, 17}, size/8)
+ sink = make([]byte, 2*size)
+
+ b.Run(fmt.Sprintf("%v", size), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Encode(sink, src)
+ }
+ })
+ }
+}
diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go
index ed89d1156e..cd7380b1ef 100644
--- a/libgo/go/encoding/json/bench_test.go
+++ b/libgo/go/encoding/json/bench_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -158,7 +158,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
var r codeResponse
if err := Unmarshal(codeJSON, &r); err != nil {
- b.Fatal("Unmmarshal:", err)
+ b.Fatal("Unmarshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
@@ -173,7 +173,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
var r codeResponse
for i := 0; i < b.N; i++ {
if err := Unmarshal(codeJSON, &r); err != nil {
- b.Fatal("Unmmarshal:", err)
+ b.Fatal("Unmarshal:", err)
}
}
}
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 539d952ad6..77fc4607db 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -29,11 +29,18 @@ import (
// with the following additional rules:
//
// To unmarshal JSON into a pointer, Unmarshal first handles the case of
-// the JSON being the JSON literal null. In that case, Unmarshal sets
-// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
-// the value pointed at by the pointer. If the pointer is nil, Unmarshal
+// the JSON being the JSON literal null. In that case, Unmarshal sets
+// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
+// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
+// To unmarshal JSON into a value implementing the Unmarshaler interface,
+// Unmarshal calls that value's UnmarshalJSON method, including
+// when the input is a JSON null.
+// Otherwise, if the value implements encoding.TextUnmarshaler
+// and the input is a JSON quoted string, Unmarshal calls that value's
+// UnmarshalText method with the unquoted form of the string.
+//
// To unmarshal JSON into a struct, Unmarshal matches incoming object
// keys to the keys used by Marshal (either the struct field name or its tag),
// preferring an exact match but also accepting a case-insensitive match.
@@ -61,10 +68,11 @@ import (
// If the JSON array is smaller than the Go array,
// the additional Go array elements are set to zero values.
//
-// To unmarshal a JSON object into a string-keyed map, Unmarshal first
-// establishes a map to 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.
+// 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
+// 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, 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
@@ -96,11 +104,14 @@ func Unmarshal(data []byte, v interface{}) error {
return d.unmarshal(v)
}
-// Unmarshaler is the interface implemented by objects
+// Unmarshaler is the interface implemented by types
// that can unmarshal a JSON description of themselves.
// The input can be assumed to be a valid encoding of
// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
+//
+// By convention, to approximate the behavior of Unmarshal itself,
+// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
@@ -111,9 +122,14 @@ type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
+ Struct string // name of the struct type containing the field
+ Field string // name of the field holding the Go value
}
func (e *UnmarshalTypeError) Error() string {
+ if e.Struct != "" || e.Field != "" {
+ return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String()
+ }
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
}
@@ -247,10 +263,14 @@ func isValidNumber(s string) bool {
// decodeState represents the state while decoding a JSON value.
type decodeState struct {
- data []byte
- off int // read offset in data
- scan scanner
- nextscan scanner // for calls to nextValue
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ errorContext struct { // provides context for type errors
+ Struct string
+ Field string
+ }
savedError error
useNumber bool
}
@@ -264,22 +284,37 @@ func (d *decodeState) init(data []byte) *decodeState {
d.data = data
d.off = 0
d.savedError = nil
+ d.errorContext.Struct = ""
+ d.errorContext.Field = ""
return d
}
// error aborts the decoding by panicking with err.
func (d *decodeState) error(err error) {
- panic(err)
+ panic(d.addErrorContext(err))
}
// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
func (d *decodeState) saveError(err error) {
if d.savedError == nil {
- d.savedError = err
+ d.savedError = d.addErrorContext(err)
}
}
+// addErrorContext returns a new error enhanced with information from d.errorContext
+func (d *decodeState) addErrorContext(err error) error {
+ if d.errorContext.Struct != "" || d.errorContext.Field != "" {
+ switch err := err.(type) {
+ case *UnmarshalTypeError:
+ err.Struct = d.errorContext.Struct
+ err.Field = d.errorContext.Field
+ return err
+ }
+ }
+ return err
+}
+
// next cuts off and returns the next full JSON value in d.data[d.off:].
// The next value is known to be an object or array, not a literal.
func (d *decodeState) next() []byte {
@@ -433,8 +468,10 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
if u, ok := v.Interface().(Unmarshaler); ok {
return u, nil, reflect.Value{}
}
- if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
- return nil, u, reflect.Value{}
+ if !decodingNull {
+ if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
+ return nil, u, reflect.Value{}
+ }
}
}
v = v.Elem()
@@ -456,7 +493,7 @@ func (d *decodeState) array(v reflect.Value) {
return
}
if ut != nil {
- d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next()
return
@@ -475,7 +512,7 @@ func (d *decodeState) array(v reflect.Value) {
// Otherwise it's invalid.
fallthrough
default:
- d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next()
return
@@ -534,7 +571,7 @@ func (d *decodeState) array(v reflect.Value) {
if i < v.Len() {
if v.Kind() == reflect.Array {
- // Array. Zero the rest.
+ // Array. Zero the rest.
z := reflect.Zero(v.Type().Elem())
for ; i < v.Len(); i++ {
v.Index(i).Set(z)
@@ -549,6 +586,7 @@ func (d *decodeState) array(v reflect.Value) {
}
var nullLiteral = []byte("null")
+var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte ('{') of the object has been read already.
@@ -564,7 +602,7 @@ func (d *decodeState) object(v reflect.Value) {
return
}
if ut != nil {
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next() // skip over { } in input
return
@@ -577,24 +615,34 @@ func (d *decodeState) object(v reflect.Value) {
return
}
- // Check type of target: struct or map[string]T
+ // Check type of target:
+ // struct or
+ // map[T1]T2 where T1 is string, an integer type,
+ // or an encoding.TextUnmarshaler
switch v.Kind() {
case reflect.Map:
- // map must have string kind
+ // 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 {
- 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{Value: "object", Type: v.Type(), Offset: int64(d.off)})
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
}
if v.IsNil() {
v.Set(reflect.MakeMap(t))
}
case reflect.Struct:
-
+ // ok
default:
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next() // skip over { } in input
return
@@ -659,6 +707,8 @@ func (d *decodeState) object(v reflect.Value) {
}
subv = subv.Field(i)
}
+ d.errorContext.Field = f.name
+ d.errorContext.Struct = v.Type().Name()
}
}
@@ -670,7 +720,6 @@ func (d *decodeState) object(v reflect.Value) {
d.error(errPhase)
}
- // Read value.
if destring {
switch qv := d.valueQuoted().(type) {
case nil:
@@ -687,7 +736,37 @@ func (d *decodeState) object(v reflect.Value) {
// Write value back to map;
// if using struct, subv points into struct already.
if v.Kind() == reflect.Map {
- kv := reflect.ValueOf(key).Convert(v.Type().Key())
+ kt := v.Type().Key()
+ var kv reflect.Value
+ switch {
+ case kt.Kind() == reflect.String:
+ 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:
+ 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{Value: "number " + s, Type: kt, Offset: 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{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
+ return
+ }
+ kv = reflect.ValueOf(n).Convert(kt)
+ default:
+ panic("json: Unexpected key type") // should never occur
+ }
+ }
v.SetMapIndex(kv, subv)
}
@@ -699,6 +778,9 @@ func (d *decodeState) object(v reflect.Value) {
if op != scanObjectValue {
d.error(errPhase)
}
+
+ d.errorContext.Struct = ""
+ d.errorContext.Field = ""
}
}
@@ -725,7 +807,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
- return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
+ return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)}
}
return f, nil
}
@@ -744,8 +826,8 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
return
}
- wantptr := item[0] == 'n' // null
- u, ut, pv := d.indirect(v, wantptr)
+ isNull := item[0] == 'n' // null
+ u, ut, pv := d.indirect(v, isNull)
if u != nil {
err := u.UnmarshalJSON(item)
if err != nil {
@@ -758,7 +840,16 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ var val string
+ switch item[0] {
+ case 'n':
+ val = "null"
+ case 't', 'f':
+ val = "bool"
+ default:
+ val = "number"
+ }
+ d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.off)})
}
return
}
@@ -781,19 +872,31 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
switch c := item[0]; c {
case 'n': // null
+ // The main parser checks that only true and false can reach here,
+ // but if this was a quoted string input, it could be anything.
+ if fromQuoted && string(item) != "null" {
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ break
+ }
switch v.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
v.Set(reflect.Zero(v.Type()))
// otherwise, ignore null for primitives/string
}
case 't', 'f': // true, false
- value := c == 't'
+ value := item[0] == 't'
+ // The main parser checks that only true and false can reach here,
+ // but if this was a quoted string input, it could be anything.
+ if fromQuoted && string(item) != "true" && string(item) != "false" {
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ break
+ }
switch v.Kind() {
default:
if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
}
case reflect.Bool:
v.SetBool(value)
@@ -801,7 +904,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(value))
} else {
- d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
}
}
@@ -816,10 +919,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
}
switch v.Kind() {
default:
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
case reflect.Slice:
if v.Type().Elem().Kind() != reflect.Uint8 {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
break
}
b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@@ -835,7 +938,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(string(s)))
} else {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
}
}
@@ -860,7 +963,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+ d.error(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
}
case reflect.Interface:
n, err := d.convertNumber(s)
@@ -869,7 +972,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
break
}
if v.NumMethod() != 0 {
- d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
break
}
v.Set(reflect.ValueOf(n))
@@ -877,7 +980,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || v.OverflowInt(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetInt(n)
@@ -885,7 +988,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(s, 10, 64)
if err != nil || v.OverflowUint(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetUint(n)
@@ -893,7 +996,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Float32, reflect.Float64:
n, err := strconv.ParseFloat(s, v.Type().Bits())
if err != nil || v.OverflowFloat(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetFloat(n)
@@ -902,7 +1005,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
}
// The xxxInterface routines build up a value to be stored
-// in an empty interface. They are not strictly necessary,
+// in an empty interface. They are not strictly necessary,
// but they avoid the weight of reflection in this common case.
// valueInterface is like value but returns interface{}
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index 9546ae459c..bd38ddd319 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -7,10 +7,14 @@ package json
import (
"bytes"
"encoding"
+ "errors"
"fmt"
"image"
+ "math"
+ "math/big"
"net"
"reflect"
+ "strconv"
"strings"
"testing"
"time"
@@ -30,6 +34,11 @@ type V struct {
F1 interface{}
F2 int32
F3 Number
+ F4 *VOuter
+}
+
+type VOuter struct {
+ V V
}
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
@@ -52,6 +61,8 @@ type tx struct {
x int
}
+type u8 uint8
+
// A type that can unmarshal itself.
type unmarshaler struct {
@@ -68,16 +79,20 @@ type ustruct struct {
}
type unmarshalerText struct {
- T bool
+ A, B string
}
// needed for re-marshaling tests
-func (u *unmarshalerText) MarshalText() ([]byte, error) {
- return []byte(""), nil
+func (u unmarshalerText) MarshalText() ([]byte, error) {
+ return []byte(u.A + ":" + u.B), nil
}
func (u *unmarshalerText) UnmarshalText(b []byte) error {
- *u = unmarshalerText{true} // All we need to see that UnmarshalText is called.
+ pos := bytes.Index(b, []byte(":"))
+ if pos == -1 {
+ return errors.New("missing separator")
+ }
+ u.A, u.B = string(b[:pos]), string(b[pos+1:])
return nil
}
@@ -87,6 +102,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
@@ -95,12 +133,16 @@ var (
umslicep = new([]unmarshaler)
umstruct = ustruct{unmarshaler{true}}
- um0T, um1T unmarshalerText // target2 of unmarshaling
- umpT = &um1T
- umtrueT = unmarshalerText{true}
- umsliceT = []unmarshalerText{{true}}
- umslicepT = new([]unmarshalerText)
- umstructT = ustructText{unmarshalerText{true}}
+ um0T, um1T unmarshalerText // target2 of unmarshaling
+ umpType = &um1T
+ umtrueXY = unmarshalerText{"x", "y"}
+ umsliceXY = []unmarshalerText{{"x", "y"}}
+ umslicepType = new([]unmarshalerText)
+ umstructType = new(ustructText)
+ umstructXY = ustructText{unmarshalerText{"x", "y"}}
+
+ ummapType = map[unmarshalerText]bool{}
+ ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true}
)
// Test data structures for anonymous fields.
@@ -202,14 +244,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"`
@@ -225,6 +259,131 @@ 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
+}
+
+type B struct {
+ B bool `json:",string"`
+}
+
var unmarshalTests = []unmarshalTest{
// basic types
{in: `true`, ptr: new(bool), out: true},
@@ -240,7 +399,7 @@ var unmarshalTests = []unmarshalTest{
{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
{in: "null", ptr: new(interface{}), out: nil},
- {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
+ {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
@@ -302,14 +461,81 @@ var unmarshalTests = []unmarshalTest{
{in: `{"T":false}`, ptr: &ump, out: &umtrue},
{in: `[{"T":false}]`, ptr: &umslice, out: umslice},
{in: `[{"T":false}]`, ptr: &umslicep, out: &umslice},
- {in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct},
+ {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct},
// UnmarshalText interface test
- {in: `"X"`, ptr: &um0T, out: umtrueT}, // use "false" so test will fail if custom unmarshaler is not called
- {in: `"X"`, ptr: &umpT, out: &umtrueT},
- {in: `["X"]`, ptr: &umsliceT, out: umsliceT},
- {in: `["X"]`, ptr: &umslicepT, out: &umsliceT},
- {in: `{"M":"X"}`, ptr: &umstructT, out: umstructT},
+ {in: `"x:y"`, ptr: &um0T, out: umtrueXY},
+ {in: `"x:y"`, ptr: &umpType, out: &umtrueXY},
+ {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY},
+ {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY},
+ {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY},
+
+ // 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{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2},
+ },
+ {
+ in: `{"256":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2},
+ },
+ {
+ in: `{"128":"abc"}`,
+ ptr: new(map[int8]string),
+ err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2},
+ },
+ {
+ in: `{"-1":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 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},
// Overwriting of data.
// This is different from package xml, but it's what we've always done.
@@ -426,12 +652,147 @@ var unmarshalTests = []unmarshalTest{
out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
},
- // issue 8305
+ // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now.
{
in: `{"2009-11-10T23:00:00Z": "hello world"}`,
ptr: &map[time.Time]string{},
- err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},
+ out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"},
+ },
+
+ // issue 8305
+ {
+ in: `{"2009-11-10T23:00:00Z": "hello world"}`,
+ ptr: &map[Point]string{},
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1},
+ },
+ {
+ in: `{"asdf": "hello world"}`,
+ ptr: &map[unmarshaler]string{},
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 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,
+ },
+
+ {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
+ {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
+ {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
+ {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
+ {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
+ {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
+ {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
+ {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
+ {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
+ {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
+ {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
+
+ {
+ in: `{"V": {"F2": "hello"}}`,
+ ptr: new(VOuter),
+ err: &UnmarshalTypeError{
+ Value: "string",
+ Struct: "V",
+ Field: "F2",
+ Type: reflect.TypeOf(int32(0)),
+ Offset: 20,
+ },
+ },
+ {
+ in: `{"V": {"F4": {}, "F2": "hello"}}`,
+ ptr: new(VOuter),
+ err: &UnmarshalTypeError{
+ Value: "string",
+ Struct: "V",
+ Field: "F2",
+ Type: reflect.TypeOf(int32(0)),
+ Offset: 30,
+ },
+ },
+
+ // issue 15146.
+ // invalid inputs in wrongStringTests below.
+ {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},
+ {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true},
+ {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)},
+ {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)},
+ {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
+ {in: `{"B": "null"}`, ptr: new(B), out: B{false}},
+ {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
}
func TestMarshal(t *testing.T) {
@@ -565,13 +926,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 {
@@ -1161,40 +1525,148 @@ func TestInterfaceSet(t *testing.T) {
}
}
+type NullTest struct {
+ Bool bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint uint
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Float32 float32
+ Float64 float64
+ String string
+ PBool *bool
+ Map map[string]string
+ Slice []string
+ Interface interface{}
+
+ PRaw *RawMessage
+ PTime *time.Time
+ PBigInt *big.Int
+ PText *MustNotUnmarshalText
+ PBuffer *bytes.Buffer // has methods, just not relevant ones
+ PStruct *struct{}
+
+ Raw RawMessage
+ Time time.Time
+ BigInt big.Int
+ Text MustNotUnmarshalText
+ Buffer bytes.Buffer
+ Struct struct{}
+}
+
+type NullTestStrings struct {
+ Bool bool `json:",string"`
+ Int int `json:",string"`
+ Int8 int8 `json:",string"`
+ Int16 int16 `json:",string"`
+ Int32 int32 `json:",string"`
+ Int64 int64 `json:",string"`
+ Uint uint `json:",string"`
+ Uint8 uint8 `json:",string"`
+ Uint16 uint16 `json:",string"`
+ Uint32 uint32 `json:",string"`
+ Uint64 uint64 `json:",string"`
+ Float32 float32 `json:",string"`
+ Float64 float64 `json:",string"`
+ String string `json:",string"`
+ PBool *bool `json:",string"`
+ Map map[string]string `json:",string"`
+ Slice []string `json:",string"`
+ Interface interface{} `json:",string"`
+
+ PRaw *RawMessage `json:",string"`
+ PTime *time.Time `json:",string"`
+ PBigInt *big.Int `json:",string"`
+ PText *MustNotUnmarshalText `json:",string"`
+ PBuffer *bytes.Buffer `json:",string"`
+ PStruct *struct{} `json:",string"`
+
+ Raw RawMessage `json:",string"`
+ Time time.Time `json:",string"`
+ BigInt big.Int `json:",string"`
+ Text MustNotUnmarshalText `json:",string"`
+ Buffer bytes.Buffer `json:",string"`
+ Struct struct{} `json:",string"`
+}
+
// JSON null values should be ignored for primitives and string values instead of resulting in an error.
// Issue 2540
func TestUnmarshalNulls(t *testing.T) {
+ // Unmarshal docs:
+ // The JSON null value unmarshals into an interface, map, pointer, or slice
+ // by setting that Go value to nil. Because null is often used in JSON to mean
+ // ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+ // on the value and produces no error.
+
jsonData := []byte(`{
- "Bool" : null,
- "Int" : null,
- "Int8" : null,
- "Int16" : null,
- "Int32" : null,
- "Int64" : null,
- "Uint" : null,
- "Uint8" : null,
- "Uint16" : null,
- "Uint32" : null,
- "Uint64" : null,
- "Float32" : null,
- "Float64" : null,
- "String" : null}`)
-
- nulls := All{
- Bool: true,
- Int: 2,
- Int8: 3,
- Int16: 4,
- Int32: 5,
- Int64: 6,
- Uint: 7,
- Uint8: 8,
- Uint16: 9,
- Uint32: 10,
- Uint64: 11,
- Float32: 12.1,
- Float64: 13.1,
- String: "14"}
+ "Bool" : null,
+ "Int" : null,
+ "Int8" : null,
+ "Int16" : null,
+ "Int32" : null,
+ "Int64" : null,
+ "Uint" : null,
+ "Uint8" : null,
+ "Uint16" : null,
+ "Uint32" : null,
+ "Uint64" : null,
+ "Float32" : null,
+ "Float64" : null,
+ "String" : null,
+ "PBool": null,
+ "Map": null,
+ "Slice": null,
+ "Interface": null,
+ "PRaw": null,
+ "PTime": null,
+ "PBigInt": null,
+ "PText": null,
+ "PBuffer": null,
+ "PStruct": null,
+ "Raw": null,
+ "Time": null,
+ "BigInt": null,
+ "Text": null,
+ "Buffer": null,
+ "Struct": null
+ }`)
+ nulls := NullTest{
+ Bool: true,
+ Int: 2,
+ Int8: 3,
+ Int16: 4,
+ Int32: 5,
+ Int64: 6,
+ Uint: 7,
+ Uint8: 8,
+ Uint16: 9,
+ Uint32: 10,
+ Uint64: 11,
+ Float32: 12.1,
+ Float64: 13.1,
+ String: "14",
+ PBool: new(bool),
+ Map: map[string]string{},
+ Slice: []string{},
+ Interface: new(MustNotUnmarshalJSON),
+ PRaw: new(RawMessage),
+ PTime: new(time.Time),
+ PBigInt: new(big.Int),
+ PText: new(MustNotUnmarshalText),
+ PStruct: new(struct{}),
+ PBuffer: new(bytes.Buffer),
+ Raw: RawMessage("123"),
+ Time: time.Unix(123456789, 0),
+ BigInt: *big.NewInt(123),
+ }
+
+ before := nulls.Time.String()
err := Unmarshal(jsonData, &nulls)
if err != nil {
@@ -1203,9 +1675,61 @@ func TestUnmarshalNulls(t *testing.T) {
if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
-
t.Errorf("Unmarshal of null values affected primitives")
}
+
+ if nulls.PBool != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBool")
+ }
+ if nulls.Map != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Map")
+ }
+ if nulls.Slice != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Slice")
+ }
+ if nulls.Interface != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Interface")
+ }
+ if nulls.PRaw != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PRaw")
+ }
+ if nulls.PTime != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PTime")
+ }
+ if nulls.PBigInt != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBigInt")
+ }
+ if nulls.PText != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PText")
+ }
+ if nulls.PBuffer != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBuffer")
+ }
+ if nulls.PStruct != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PStruct")
+ }
+
+ if string(nulls.Raw) != "null" {
+ t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw))
+ }
+ if nulls.Time.String() != before {
+ t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String())
+ }
+ if nulls.BigInt.String() != "123" {
+ t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String())
+ }
+}
+
+type MustNotUnmarshalJSON struct{}
+
+func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error {
+ return errors.New("MustNotUnmarshalJSON was used")
+}
+
+type MustNotUnmarshalText struct{}
+
+func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
+ return errors.New("MustNotUnmarshalText was used")
}
func TestStringKind(t *testing.T) {
@@ -1231,8 +1755,8 @@ func TestStringKind(t *testing.T) {
}
}
-// Custom types with []byte as underlying type could not be marshalled
-// and then unmarshalled.
+// Custom types with []byte as underlying type could not be marshaled
+// and then unmarshaled.
// Issue 8962.
func TestByteKind(t *testing.T) {
type byteKind []byte
@@ -1270,7 +1794,7 @@ func TestSliceOfCustomByte(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(a, b) {
- t.Fatal("expected %v == %v", a, b)
+ t.Fatalf("expected %v == %v", a, b)
}
}
@@ -1444,7 +1968,7 @@ var invalidUnmarshalTextTests = []struct {
{nil, "json: Unmarshal(nil)"},
{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
{(*int)(nil), "json: Unmarshal(nil *int)"},
- {new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"},
+ {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"},
}
func TestInvalidUnmarshalText(t *testing.T) {
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index 69ac7e03c8..8f21ddaed9 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -1,9 +1,9 @@
-// Copyright 2010 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 json implements encoding and decoding of JSON objects as defined in
-// RFC 4627. The mapping between JSON objects and Go values is described
+// Package json implements encoding and decoding of JSON as defined in
+// RFC 4627. The mapping between JSON and Go values is described
// in the documentation for the Marshal and Unmarshal functions.
//
// See "JSON and Go" for an introduction to this package:
@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"unicode"
"unicode/utf8"
)
@@ -33,7 +34,7 @@ import (
// and is not a nil pointer, Marshal calls its MarshalJSON method
// to produce JSON. If no MarshalJSON method is present but the
// value implements encoding.TextMarshaler instead, Marshal calls
-// its MarshalText method.
+// its MarshalText method and encodes the result as a JSON string.
// The nil pointer exception is not strictly necessary
// but mimics a similar, necessary exception in the behavior of
// UnmarshalJSON.
@@ -49,24 +50,33 @@ import (
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
// Ampersand "&" is also escaped to "\u0026" for the same reason.
+// This escaping can be disabled using an Encoder that had SetEscapeHTML(false)
+// called on it.
//
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string, and a nil slice
-// encodes as the null JSON object.
+// encodes as the null JSON value.
//
-// Struct values encode as JSON objects. Each exported struct field
-// becomes a member of the object unless
-// - the field's tag is "-", or
-// - the field is empty and its tag specifies the "omitempty" option.
-// The empty values are false, 0, any
-// nil pointer or interface value, and any array, slice, map, or string of
-// length zero. The object's default key string is the struct field name
-// but can be specified in the struct field's tag value. The "json" key in
-// the struct field's tag value is the key name, followed by an optional comma
-// and options. Examples:
+// Struct values encode as JSON objects.
+// Each exported struct field becomes a member of the object, using the
+// field name as the object key, unless the field is omitted for one of the
+// reasons given below.
//
-// // Field is ignored by this package.
-// Field int `json:"-"`
+// The encoding of each struct field can be customized by the format string
+// stored under the "json" key in the struct field's tag.
+// The format string gives the name of the field, possibly followed by a
+// comma-separated list of options. The name may be empty in order to
+// specify options without overriding the default field name.
+//
+// The "omitempty" option specifies that the field should be omitted
+// from the encoding if the field has an empty value, defined as
+// false, 0, a nil pointer, a nil interface value, and any empty array,
+// slice, map, or string.
+//
+// As a special case, if the field tag is "-", the field is always omitted.
+// Note that a field with name "-" can still be generated using the tag "-,".
+//
+// Examples of struct field tags and their meanings:
//
// // Field appears in JSON as key "myName".
// Field int `json:"myName"`
@@ -81,6 +91,12 @@ import (
// // Note the leading comma.
// Field int `json:",omitempty"`
//
+// // Field is ignored by this package.
+// Field int `json:"-"`
+//
+// // Field appears in JSON as key "-".
+// Field int `json:"-,"`
+//
// The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. It applies only to fields of string, floating point,
// integer, or boolean types. This extra level of encoding is sometimes used
@@ -89,8 +105,8 @@ import (
// Int64String int64 `json:",string"`
//
// The key name will be used if it's a non-empty string consisting of
-// only Unicode letters, digits, dollar signs, percent signs, hyphens,
-// underscores and slashes.
+// only Unicode letters, digits, and ASCII punctuation except quotation
+// marks, backslash, and comma.
//
// Anonymous struct fields are usually marshaled as if their inner exported fields
// were fields in the outer struct, subject to the usual Go visibility rules amended
@@ -108,7 +124,9 @@ import (
//
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
// even if there are multiple untagged fields that would otherwise conflict.
+//
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
+//
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
//
// Handling of anonymous struct fields is new in Go 1.1.
@@ -116,27 +134,31 @@ 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 be string; 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 object.
+// A nil pointer encodes as the null JSON value.
//
// Interface values encode as the value contained in the interface.
-// A nil interface value encodes as the null JSON object.
+// A nil interface value encodes as the null JSON value.
//
// Channel, complex, and function values cannot be encoded in JSON.
// Attempting to encode such a value causes Marshal to return
// an UnsupportedTypeError.
//
// JSON cannot represent cyclic data structures and Marshal does not
-// handle them. Passing cyclic structures to Marshal will result in
+// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func Marshal(v interface{}) ([]byte, error) {
e := &encodeState{}
- err := e.marshal(v)
+ err := e.marshal(v, encOpts{escapeHTML: true})
if err != nil {
return nil, err
}
@@ -192,7 +214,7 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) {
}
}
-// Marshaler is the interface implemented by objects that
+// Marshaler is the interface implemented by types that
// can marshal themselves into valid JSON.
type Marshaler interface {
MarshalJSON() ([]byte, error)
@@ -259,7 +281,7 @@ func newEncodeState() *encodeState {
return new(encodeState)
}
-func (e *encodeState) marshal(v interface{}) (err error) {
+func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
@@ -271,7 +293,7 @@ func (e *encodeState) marshal(v interface{}) (err error) {
err = r.(error)
}
}()
- e.reflectValue(reflect.ValueOf(v))
+ e.reflectValue(reflect.ValueOf(v), opts)
return nil
}
@@ -297,11 +319,18 @@ func isEmptyValue(v reflect.Value) bool {
return false
}
-func (e *encodeState) reflectValue(v reflect.Value) {
- valueEncoder(v)(e, v, false)
+func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
+ valueEncoder(v)(e, v, opts)
+}
+
+type encOpts struct {
+ // quoted causes primitive fields to be encoded inside JSON strings.
+ quoted bool
+ // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings.
+ escapeHTML bool
}
-type encoderFunc func(e *encodeState, v reflect.Value, quoted bool)
+type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
var encoderCache struct {
sync.RWMutex
@@ -325,7 +354,7 @@ func typeEncoder(t reflect.Type) encoderFunc {
// To deal with recursive types, populate the map with an
// indirect func before we build it. This type waits on the
- // real func (f) to be ready and then calls it. This indirect
+ // real func (f) to be ready and then calls it. This indirect
// func is only used for recursive types.
encoderCache.Lock()
if encoderCache.m == nil {
@@ -333,9 +362,9 @@ func typeEncoder(t reflect.Type) encoderFunc {
}
var wg sync.WaitGroup
wg.Add(1)
- encoderCache.m[t] = func(e *encodeState, v reflect.Value, quoted bool) {
+ encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) {
wg.Wait()
- f(e, v, quoted)
+ f(e, v, opts)
}
encoderCache.Unlock()
@@ -405,27 +434,31 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
}
}
-func invalidValueEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {
e.WriteString("null")
}
-func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Kind() == reflect.Ptr && v.IsNil() {
e.WriteString("null")
return
}
- m := v.Interface().(Marshaler)
+ m, ok := v.Interface().(Marshaler)
+ if !ok {
+ e.WriteString("null")
+ return
+ }
b, err := m.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
- err = compact(&e.Buffer, b, true)
+ err = compact(&e.Buffer, b, opts.escapeHTML)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err})
}
}
-func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
va := v.Addr()
if va.IsNil() {
e.WriteString("null")
@@ -442,7 +475,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
}
}
-func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Kind() == reflect.Ptr && v.IsNil() {
e.WriteString("null")
return
@@ -452,10 +485,10 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
if err != nil {
e.error(&MarshalerError{v.Type(), err})
}
- e.stringBytes(b)
+ e.stringBytes(b, opts.escapeHTML)
}
-func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
va := v.Addr()
if va.IsNil() {
e.WriteString("null")
@@ -466,11 +499,11 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
if err != nil {
e.error(&MarshalerError{v.Type(), err})
}
- e.stringBytes(b)
+ e.stringBytes(b, opts.escapeHTML)
}
-func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
- if quoted {
+func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) {
+ if opts.quoted {
e.WriteByte('"')
}
if v.Bool() {
@@ -478,46 +511,70 @@ func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
} else {
e.WriteString("false")
}
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
}
-func intEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {
b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
e.Write(b)
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
}
-func uintEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
e.Write(b)
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
}
type floatEncoder int // number of bits
-func (bits floatEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
f := v.Float()
if math.IsInf(f, 0) || math.IsNaN(f) {
e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
}
- b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits))
- if quoted {
+
+ // Convert as if by ES6 number to string conversion.
+ // This matches most other JSON generators.
+ // See golang.org/issue/6384 and golang.org/issue/14135.
+ // Like fmt %g, but the exponent cutoffs are different
+ // and exponents themselves are not padded to two digits.
+ b := e.scratch[:0]
+ abs := math.Abs(f)
+ fmt := byte('f')
+ // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
+ if abs != 0 {
+ if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
+ fmt = 'e'
+ }
+ }
+ b = strconv.AppendFloat(b, f, fmt, -1, int(bits))
+ if fmt == 'e' {
+ // clean up e-09 to e-9
+ n := len(b)
+ if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
+ b[n-2] = b[n-1]
+ b = b[:n-1]
+ }
+ }
+
+ if opts.quoted {
e.WriteByte('"')
}
e.Write(b)
- if quoted {
+ if opts.quoted {
e.WriteByte('"')
}
}
@@ -527,7 +584,7 @@ var (
float64Encoder = (floatEncoder(64)).encode
)
-func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Type() == numberType {
numStr := v.String()
// In Go1.5 the empty string encodes to "0", while this is not a valid number literal
@@ -541,26 +598,26 @@ func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
e.WriteString(numStr)
return
}
- if quoted {
+ if opts.quoted {
sb, err := Marshal(v.String())
if err != nil {
e.error(err)
}
- e.string(string(sb))
+ e.string(string(sb), opts.escapeHTML)
} else {
- e.string(v.String())
+ e.string(v.String(), opts.escapeHTML)
}
}
-func interfaceEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.IsNil() {
e.WriteString("null")
return
}
- e.reflectValue(v.Elem())
+ e.reflectValue(v.Elem(), opts)
}
-func unsupportedTypeEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {
e.error(&UnsupportedTypeError{v.Type()})
}
@@ -569,7 +626,7 @@ type structEncoder struct {
fieldEncs []encoderFunc
}
-func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
e.WriteByte('{')
first := true
for i, f := range se.fields {
@@ -582,9 +639,10 @@ func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
} else {
e.WriteByte(',')
}
- e.string(f.name)
+ e.string(f.name, opts.escapeHTML)
e.WriteByte(':')
- se.fieldEncs[i](e, fv, f.quoted)
+ opts.quoted = f.quoted
+ se.fieldEncs[i](e, fv, opts)
}
e.WriteByte('}')
}
@@ -605,34 +663,50 @@ type mapEncoder struct {
elemEnc encoderFunc
}
-func (me *mapEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if v.IsNil() {
e.WriteString("null")
return
}
e.WriteByte('{')
- var sv stringValues = v.MapKeys()
- sort.Sort(sv)
- for i, k := range sv {
+
+ // Extract and sort the keys.
+ keys := v.MapKeys()
+ sv := make([]reflectWithString, len(keys))
+ for i, v := range keys {
+ sv[i].v = v
+ if err := sv[i].resolve(); err != nil {
+ e.error(&MarshalerError{v.Type(), err})
+ }
+ }
+ sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s })
+
+ for i, kv := range sv {
if i > 0 {
e.WriteByte(',')
}
- e.string(k.String())
+ e.string(kv.s, opts.escapeHTML)
e.WriteByte(':')
- me.elemEnc(e, v.MapIndex(k), false)
+ me.elemEnc(e, v.MapIndex(kv.v), opts)
}
e.WriteByte('}')
}
func newMapEncoder(t reflect.Type) encoderFunc {
- if t.Key().Kind() != reflect.String {
- 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
}
-func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) {
+func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) {
if v.IsNil() {
e.WriteString("null")
return
@@ -659,18 +733,21 @@ type sliceEncoder struct {
arrayEnc encoderFunc
}
-func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if v.IsNil() {
e.WriteString("null")
return
}
- se.arrayEnc(e, v, false)
+ se.arrayEnc(e, v, opts)
}
func newSliceEncoder(t reflect.Type) encoderFunc {
// Byte slices get special treatment; arrays don't.
if t.Elem().Kind() == reflect.Uint8 {
- return encodeByteSlice
+ p := reflect.PtrTo(t.Elem())
+ if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
+ return encodeByteSlice
+ }
}
enc := &sliceEncoder{newArrayEncoder(t)}
return enc.encode
@@ -680,14 +757,14 @@ type arrayEncoder struct {
elemEnc encoderFunc
}
-func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
e.WriteByte('[')
n := v.Len()
for i := 0; i < n; i++ {
if i > 0 {
e.WriteByte(',')
}
- ae.elemEnc(e, v.Index(i), false)
+ ae.elemEnc(e, v.Index(i), opts)
}
e.WriteByte(']')
}
@@ -701,12 +778,12 @@ type ptrEncoder struct {
elemEnc encoderFunc
}
-func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if v.IsNil() {
e.WriteString("null")
return
}
- pe.elemEnc(e, v.Elem(), quoted)
+ pe.elemEnc(e, v.Elem(), opts)
}
func newPtrEncoder(t reflect.Type) encoderFunc {
@@ -718,11 +795,11 @@ type condAddrEncoder struct {
canAddrEnc, elseEnc encoderFunc
}
-func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if v.CanAddr() {
- ce.canAddrEnc(e, v, quoted)
+ ce.canAddrEnc(e, v, opts)
} else {
- ce.elseEnc(e, v, quoted)
+ ce.elseEnc(e, v, opts)
}
}
@@ -775,23 +852,40 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type {
return t
}
-// stringValues is a slice of reflect.Value holding *reflect.StringValue.
-// It implements the methods to sort by string.
-type stringValues []reflect.Value
+type reflectWithString struct {
+ v reflect.Value
+ s string
+}
-func (sv stringValues) Len() int { return len(sv) }
-func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
-func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
-func (sv stringValues) get(i int) string { return sv[i].String() }
+func (w *reflectWithString) resolve() error {
+ if w.v.Kind() == reflect.String {
+ w.s = w.v.String()
+ return nil
+ }
+ 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")
+}
// NOTE: keep in sync with stringBytes below.
-func (e *encodeState) string(s string) int {
+func (e *encodeState) string(s string, escapeHTML bool) int {
len0 := e.Len()
e.WriteByte('"')
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
+ if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
i++
continue
}
@@ -812,10 +906,11 @@ func (e *encodeState) string(s string) int {
e.WriteByte('\\')
e.WriteByte('t')
default:
- // This encodes bytes < 0x20 except for \n and \r,
- // as well as <, > and &. The latter are escaped because they
- // can lead to security holes when user-controlled strings
- // are rendered into JSON and served to some browsers.
+ // This encodes bytes < 0x20 except for \t, \n and \r.
+ // If escapeHTML is set, it also escapes <, >, and &
+ // because they can lead to security holes when
+ // user-controlled strings are rendered into JSON
+ // and served to some browsers.
e.WriteString(`\u00`)
e.WriteByte(hex[b>>4])
e.WriteByte(hex[b&0xF])
@@ -861,13 +956,13 @@ func (e *encodeState) string(s string) int {
}
// NOTE: keep in sync with string above.
-func (e *encodeState) stringBytes(s []byte) int {
+func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int {
len0 := e.Len()
e.WriteByte('"')
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
+ if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
i++
continue
}
@@ -888,10 +983,11 @@ func (e *encodeState) stringBytes(s []byte) int {
e.WriteByte('\\')
e.WriteByte('t')
default:
- // This encodes bytes < 0x20 except for \n and \r,
- // as well as <, >, and &. The latter are escaped because they
- // can lead to security holes when user-controlled strings
- // are rendered into JSON and served to some browsers.
+ // This encodes bytes < 0x20 except for \t, \n and \r.
+ // If escapeHTML is set, it also escapes <, >, and &
+ // because they can lead to security holes when
+ // user-controlled strings are rendered into JSON
+ // and served to some browsers.
e.WriteString(`\u00`)
e.WriteByte(hex[b>>4])
e.WriteByte(hex[b&0xF])
@@ -955,28 +1051,6 @@ func fillField(f field) field {
return f
}
-// byName sorts field by name, breaking ties with depth,
-// then breaking ties with "name came from json tag", then
-// breaking ties with index sequence.
-type byName []field
-
-func (x byName) Len() int { return len(x) }
-
-func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-
-func (x byName) Less(i, j int) bool {
- if x[i].name != x[j].name {
- return x[i].name < x[j].name
- }
- if len(x[i].index) != len(x[j].index) {
- return len(x[i].index) < len(x[j].index)
- }
- if x[i].tag != x[j].tag {
- return x[i].tag
- }
- return byIndex(x).Less(i, j)
-}
-
// byIndex sorts field by index sequence.
type byIndex []field
@@ -1094,7 +1168,22 @@ func typeFields(t reflect.Type) []field {
}
}
- sort.Sort(byName(fields))
+ sort.Slice(fields, func(i, j int) bool {
+ x := fields
+ // sort field by name, breaking ties with depth, then
+ // breaking ties with "name came from json tag", then
+ // breaking ties with index sequence.
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+ })
// Delete all fields that are hidden by the Go rules for embedded fields,
// except that fields with JSON tags are promoted.
@@ -1169,15 +1258,14 @@ func dominantField(fields []field) (field, bool) {
}
var fieldCache struct {
- sync.RWMutex
- m map[reflect.Type][]field
+ value atomic.Value // map[reflect.Type][]field
+ mu sync.Mutex // used only by writers
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
- fieldCache.RLock()
- f := fieldCache.m[t]
- fieldCache.RUnlock()
+ m, _ := fieldCache.value.Load().(map[reflect.Type][]field)
+ f := m[t]
if f != nil {
return f
}
@@ -1189,11 +1277,14 @@ func cachedTypeFields(t reflect.Type) []field {
f = []field{}
}
- fieldCache.Lock()
- if fieldCache.m == nil {
- fieldCache.m = map[reflect.Type][]field{}
+ fieldCache.mu.Lock()
+ m, _ = fieldCache.value.Load().(map[reflect.Type][]field)
+ newM := make(map[reflect.Type][]field, len(m)+1)
+ for k, v := range m {
+ newM[k] = v
}
- fieldCache.m[t] = f
- fieldCache.Unlock()
+ newM[t] = f
+ fieldCache.value.Store(newM)
+ fieldCache.mu.Unlock()
return f
}
diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go
index c00491e00c..6d574cfc47 100644
--- a/libgo/go/encoding/json/encode_test.go
+++ b/libgo/go/encoding/json/encode_test.go
@@ -6,8 +6,12 @@ package json
import (
"bytes"
+ "fmt"
+ "log"
"math"
"reflect"
+ "regexp"
+ "strconv"
"testing"
"unicode"
)
@@ -289,6 +293,44 @@ type BugX struct {
BugB
}
+// Issue 16042. Even if a nil interface value is passed in
+// as long as it implements MarshalJSON, it should be marshaled.
+type nilMarshaler string
+
+func (nm *nilMarshaler) MarshalJSON() ([]byte, error) {
+ if nm == nil {
+ return Marshal("0zenil0")
+ }
+ return Marshal("zenil:" + string(*nm))
+}
+
+// Issue 16042.
+func TestNilMarshal(t *testing.T) {
+ testCases := []struct {
+ v interface{}
+ want string
+ }{
+ {v: nil, want: `null`},
+ {v: new(float64), want: `0`},
+ {v: []interface{}(nil), want: `null`},
+ {v: []string(nil), want: `null`},
+ {v: map[string]string(nil), want: `null`},
+ {v: []byte(nil), want: `null`},
+ {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`},
+ {v: struct{ M Marshaler }{}, want: `{"M":null}`},
+ {v: struct{ M Marshaler }{(*nilMarshaler)(nil)}, want: `{"M":"0zenil0"}`},
+ {v: struct{ M interface{} }{(*nilMarshaler)(nil)}, want: `{"M":null}`},
+ }
+
+ for _, tt := range testCases {
+ out, err := Marshal(tt.v)
+ if err != nil || string(out) != tt.want {
+ t.Errorf("Marshal(%#v) = %#q, %#v, want %#q, nil", tt.v, out, err, tt.want)
+ continue
+ }
+ }
+}
+
// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
v := BugB{
@@ -374,66 +416,47 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
}
func TestStringBytes(t *testing.T) {
+ t.Parallel()
// Test that encodeState.stringBytes and encodeState.string use the same encoding.
- es := &encodeState{}
var r []rune
for i := '\u0000'; i <= unicode.MaxRune; i++ {
r = append(r, i)
}
s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
- es.string(s)
- esBytes := &encodeState{}
- esBytes.stringBytes([]byte(s))
+ for _, escapeHTML := range []bool{true, false} {
+ es := &encodeState{}
+ es.string(s, escapeHTML)
- enc := es.Buffer.String()
- encBytes := esBytes.Buffer.String()
- if enc != encBytes {
- i := 0
- for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
- i++
- }
- enc = enc[i:]
- encBytes = encBytes[i:]
- i = 0
- for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
- i++
- }
- enc = enc[:len(enc)-i]
- encBytes = encBytes[:len(encBytes)-i]
-
- if len(enc) > 20 {
- enc = enc[:20] + "..."
- }
- if len(encBytes) > 20 {
- encBytes = encBytes[:20] + "..."
- }
-
- t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
- }
-}
-
-func TestIssue6458(t *testing.T) {
- type Foo struct {
- M RawMessage
- }
- x := Foo{RawMessage(`"foo"`)}
+ esBytes := &encodeState{}
+ esBytes.stringBytes([]byte(s), escapeHTML)
- b, err := Marshal(&x)
- if err != nil {
- t.Fatal(err)
- }
- if want := `{"M":"foo"}`; string(b) != want {
- t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
- }
+ enc := es.Buffer.String()
+ encBytes := esBytes.Buffer.String()
+ if enc != encBytes {
+ i := 0
+ for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
+ i++
+ }
+ enc = enc[i:]
+ encBytes = encBytes[i:]
+ i = 0
+ for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
+ i++
+ }
+ enc = enc[:len(enc)-i]
+ encBytes = encBytes[:len(encBytes)-i]
- b, err = Marshal(x)
- if err != nil {
- t.Fatal(err)
- }
+ if len(enc) > 20 {
+ enc = enc[:20] + "..."
+ }
+ if len(encBytes) > 20 {
+ encBytes = encBytes[:20] + "..."
+ }
- if want := `{"M":"ImZvbyI="}`; string(b) != want {
- t.Errorf("Marshal(x) = %#q; want %#q", b, want)
+ t.Errorf("with escapeHTML=%t, encodings differ at %#q vs %#q",
+ escapeHTML, enc, encBytes)
+ }
}
}
@@ -478,7 +501,7 @@ func TestEncodePointerString(t *testing.T) {
t.Fatalf("Unmarshal: %v", err)
}
if back.N == nil {
- t.Fatalf("Unmarshalled nil N field")
+ t.Fatalf("Unmarshaled nil N field")
}
if *back.N != 42 {
t.Fatalf("*N = %d; want 42", *back.N)
@@ -536,3 +559,278 @@ func TestEncodeString(t *testing.T) {
}
}
}
+
+type jsonbyte byte
+
+func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }
+
+type textbyte byte
+
+func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }
+
+type jsonint int
+
+func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }
+
+type textint int
+
+func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }
+
+func tenc(format string, a ...interface{}) ([]byte, error) {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, format, a...)
+ return buf.Bytes(), nil
+}
+
+// Issue 13783
+func TestEncodeBytekind(t *testing.T) {
+ testdata := []struct {
+ data interface{}
+ want string
+ }{
+ {byte(7), "7"},
+ {jsonbyte(7), `{"JB":7}`},
+ {textbyte(4), `"TB:4"`},
+ {jsonint(5), `{"JI":5}`},
+ {textint(1), `"TI:1"`},
+ {[]byte{0, 1}, `"AAE="`},
+ {[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},
+ {[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},
+ {[]textbyte{2, 3}, `["TB:2","TB:3"]`},
+ {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},
+ {[]textint{9, 3}, `["TI:9","TI:3"]`},
+ {[]int{9, 3}, `[9,3]`},
+ }
+ for _, d := range testdata {
+ js, err := Marshal(d.data)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ got, want := string(js), d.want
+ if got != want {
+ t.Errorf("got %s, want %s", got, want)
+ }
+ }
+}
+
+func TestTextMarshalerMapKeysAreSorted(t *testing.T) {
+ b, err := Marshal(map[unmarshalerText]int{
+ {"x", "y"}: 1,
+ {"y", "x"}: 2,
+ {"a", "z"}: 3,
+ {"z", "a"}: 4,
+ })
+ if err != nil {
+ t.Fatalf("Failed to Marshal text.Marshaler: %v", err)
+ }
+ const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}`
+ if string(b) != want {
+ t.Errorf("Marshal map with text.Marshaler keys: got %#q, want %#q", b, want)
+ }
+}
+
+var re = regexp.MustCompile
+
+// syntactic checks on form of marshaled floating point numbers.
+var badFloatREs = []*regexp.Regexp{
+ re(`p`), // no binary exponential notation
+ re(`^\+`), // no leading + sign
+ re(`^-?0[^.]`), // no unnecessary leading zeros
+ re(`^-?\.`), // leading zero required before decimal point
+ re(`\.(e|$)`), // no trailing decimal
+ re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction
+ re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa
+ re(`e[0-9]`), // positive exponent must be signed
+ re(`e[+-]0`), // exponent must not have leading zeros
+ re(`e-[1-6]$`), // not tiny enough for exponential notation
+ re(`e+(.|1.|20)$`), // not big enough for exponential notation
+ re(`^-?0\.0000000`), // too tiny, should use exponential notation
+ re(`^-?[0-9]{22}`), // too big, should use exponential notation
+ re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer
+ re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal
+ // below here for float32 only
+ re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer
+ re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal
+}
+
+func TestMarshalFloat(t *testing.T) {
+ t.Parallel()
+ nfail := 0
+ test := func(f float64, bits int) {
+ vf := interface{}(f)
+ if bits == 32 {
+ f = float64(float32(f)) // round
+ vf = float32(f)
+ }
+ bout, err := Marshal(vf)
+ if err != nil {
+ t.Errorf("Marshal(%T(%g)): %v", vf, vf, err)
+ nfail++
+ return
+ }
+ out := string(bout)
+
+ // result must convert back to the same float
+ g, err := strconv.ParseFloat(out, bits)
+ if err != nil {
+ t.Errorf("Marshal(%T(%g)) = %q, cannot parse back: %v", vf, vf, out, err)
+ nfail++
+ return
+ }
+ if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±0
+ t.Errorf("Marshal(%T(%g)) = %q (is %g, not %g)", vf, vf, out, float32(g), vf)
+ nfail++
+ return
+ }
+
+ bad := badFloatREs
+ if bits == 64 {
+ bad = bad[:len(bad)-2]
+ }
+ for _, re := range bad {
+ if re.MatchString(out) {
+ t.Errorf("Marshal(%T(%g)) = %q, must not match /%s/", vf, vf, out, re)
+ nfail++
+ return
+ }
+ }
+ }
+
+ var (
+ bigger = math.Inf(+1)
+ smaller = math.Inf(-1)
+ )
+
+ var digits = "1.2345678901234567890123"
+ for i := len(digits); i >= 2; i-- {
+ for exp := -30; exp <= 30; exp++ {
+ for _, sign := range "+-" {
+ for bits := 32; bits <= 64; bits += 32 {
+ s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp)
+ f, err := strconv.ParseFloat(s, bits)
+ if err != nil {
+ log.Fatal(err)
+ }
+ next := math.Nextafter
+ if bits == 32 {
+ next = func(g, h float64) float64 {
+ return float64(math.Nextafter32(float32(g), float32(h)))
+ }
+ }
+ test(f, bits)
+ test(next(f, bigger), bits)
+ test(next(f, smaller), bits)
+ if nfail > 50 {
+ t.Fatalf("stopping test early")
+ }
+ }
+ }
+ }
+ }
+ test(0, 64)
+ test(math.Copysign(0, -1), 64)
+ test(0, 32)
+ test(math.Copysign(0, -1), 32)
+}
+
+func TestMarshalRawMessageValue(t *testing.T) {
+ type (
+ T1 struct {
+ M RawMessage `json:",omitempty"`
+ }
+ T2 struct {
+ M *RawMessage `json:",omitempty"`
+ }
+ )
+
+ var (
+ rawNil = RawMessage(nil)
+ rawEmpty = RawMessage([]byte{})
+ rawText = RawMessage([]byte(`"foo"`))
+ )
+
+ tests := []struct {
+ in interface{}
+ want string
+ ok bool
+ }{
+ // Test with nil RawMessage.
+ {rawNil, "null", true},
+ {&rawNil, "null", true},
+ {[]interface{}{rawNil}, "[null]", true},
+ {&[]interface{}{rawNil}, "[null]", true},
+ {[]interface{}{&rawNil}, "[null]", true},
+ {&[]interface{}{&rawNil}, "[null]", true},
+ {struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
+ {&struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
+ {struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
+ {&struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
+ {map[string]interface{}{"M": rawNil}, `{"M":null}`, true},
+ {&map[string]interface{}{"M": rawNil}, `{"M":null}`, true},
+ {map[string]interface{}{"M": &rawNil}, `{"M":null}`, true},
+ {&map[string]interface{}{"M": &rawNil}, `{"M":null}`, true},
+ {T1{rawNil}, "{}", true},
+ {T2{&rawNil}, `{"M":null}`, true},
+ {&T1{rawNil}, "{}", true},
+ {&T2{&rawNil}, `{"M":null}`, true},
+
+ // Test with empty, but non-nil, RawMessage.
+ {rawEmpty, "", false},
+ {&rawEmpty, "", false},
+ {[]interface{}{rawEmpty}, "", false},
+ {&[]interface{}{rawEmpty}, "", false},
+ {[]interface{}{&rawEmpty}, "", false},
+ {&[]interface{}{&rawEmpty}, "", false},
+ {struct{ X RawMessage }{rawEmpty}, "", false},
+ {&struct{ X RawMessage }{rawEmpty}, "", false},
+ {struct{ X *RawMessage }{&rawEmpty}, "", false},
+ {&struct{ X *RawMessage }{&rawEmpty}, "", false},
+ {map[string]interface{}{"nil": rawEmpty}, "", false},
+ {&map[string]interface{}{"nil": rawEmpty}, "", false},
+ {map[string]interface{}{"nil": &rawEmpty}, "", false},
+ {&map[string]interface{}{"nil": &rawEmpty}, "", false},
+ {T1{rawEmpty}, "{}", true},
+ {T2{&rawEmpty}, "", false},
+ {&T1{rawEmpty}, "{}", true},
+ {&T2{&rawEmpty}, "", false},
+
+ // Test with RawMessage with some text.
+ //
+ // The tests below marked with Issue6458 used to generate "ImZvbyI=" instead "foo".
+ // This behavior was intentionally changed in Go 1.8.
+ // See https://github.com/golang/go/issues/14493#issuecomment-255857318
+ {rawText, `"foo"`, true}, // Issue6458
+ {&rawText, `"foo"`, true},
+ {[]interface{}{rawText}, `["foo"]`, true}, // Issue6458
+ {&[]interface{}{rawText}, `["foo"]`, true}, // Issue6458
+ {[]interface{}{&rawText}, `["foo"]`, true},
+ {&[]interface{}{&rawText}, `["foo"]`, true},
+ {struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {&struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true},
+ {struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
+ {&struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
+ {map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {&map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true},
+ {&map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true},
+ {T1{rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {T2{&rawText}, `{"M":"foo"}`, true},
+ {&T1{rawText}, `{"M":"foo"}`, true},
+ {&T2{&rawText}, `{"M":"foo"}`, true},
+ }
+
+ for i, tt := range tests {
+ b, err := Marshal(tt.in)
+ if ok := (err == nil); ok != tt.ok {
+ if err != nil {
+ t.Errorf("test %d, unexpected failure: %v", i, err)
+ } else {
+ t.Errorf("test %d, unexpected success", i)
+ }
+ }
+ if got := string(b); got != tt.want {
+ t.Errorf("test %d, Marshal(%#v) = %q, want %q", i, tt.in, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/encoding/json/example_marshaling_test.go b/libgo/go/encoding/json/example_marshaling_test.go
new file mode 100644
index 0000000000..1c4f783a69
--- /dev/null
+++ b/libgo/go/encoding/json/example_marshaling_test.go
@@ -0,0 +1,75 @@
+// 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 json_test
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "strings"
+)
+
+type Animal int
+
+const (
+ Unknown Animal = iota
+ Gopher
+ Zebra
+)
+
+func (a *Animal) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ switch strings.ToLower(s) {
+ default:
+ *a = Unknown
+ case "gopher":
+ *a = Gopher
+ case "zebra":
+ *a = Zebra
+ }
+
+ return nil
+}
+
+func (a Animal) MarshalJSON() ([]byte, error) {
+ var s string
+ switch a {
+ default:
+ s = "unknown"
+ case Gopher:
+ s = "gopher"
+ case Zebra:
+ s = "zebra"
+ }
+
+ return json.Marshal(s)
+}
+
+func Example_customMarshalJSON() {
+ blob := `["gopher","armadillo","zebra","unknown","gopher","bee","gopher","zebra"]`
+ var zoo []Animal
+ if err := json.Unmarshal([]byte(blob), &zoo); err != nil {
+ log.Fatal(err)
+ }
+
+ census := make(map[Animal]int)
+ for _, animal := range zoo {
+ census[animal] += 1
+ }
+
+ fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras: %d\n* Unknown: %d\n",
+ census[Gopher], census[Zebra], census[Unknown])
+
+ // Output:
+ // Zoo Census:
+ // * Gophers: 3
+ // * Zebras: 2
+ // * Unknown: 3
+}
diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go
index 7cd9f4db18..fba19548c9 100644
--- a/libgo/go/encoding/json/indent.go
+++ b/libgo/go/encoding/json/indent.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/encoding/json/number_test.go b/libgo/go/encoding/json/number_test.go
index 4e63cf9c74..4b86999638 100644
--- a/libgo/go/encoding/json/number_test.go
+++ b/libgo/go/encoding/json/number_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/encoding/json/scanner.go b/libgo/go/encoding/json/scanner.go
index ee6622e8cf..a6d8706c73 100644
--- a/libgo/go/encoding/json/scanner.go
+++ b/libgo/go/encoding/json/scanner.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -132,7 +132,7 @@ const (
// These values are stored in the parseState stack.
// They give the current state of a composite value
-// being scanned. If the parser is inside a nested value
+// being scanned. If the parser is inside a nested value
// the parseState describes the nested state, outermost at entry 0.
const (
parseObjectKey = iota // parsing object key (before colon)
diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go
index 66383ef0ef..c5c1be31f1 100644
--- a/libgo/go/encoding/json/scanner_test.go
+++ b/libgo/go/encoding/json/scanner_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -119,6 +119,7 @@ func TestCompactBig(t *testing.T) {
}
func TestIndentBig(t *testing.T) {
+ t.Parallel()
initBig()
var buf bytes.Buffer
if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go
index 8ddcf4d279..95e30ce36d 100644
--- a/libgo/go/encoding/json/stream.go
+++ b/libgo/go/encoding/json/stream.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -10,7 +10,7 @@ import (
"io"
)
-// A Decoder reads and decodes JSON objects from an input stream.
+// A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
r io.Reader
buf []byte
@@ -148,7 +148,7 @@ func (dec *Decoder) refill() error {
dec.buf = newBuf
}
- // Read. Delay error for next iteration (after scan).
+ // Read. Delay error for next iteration (after scan).
n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
dec.buf = dec.buf[0 : len(dec.buf)+n]
@@ -164,15 +164,20 @@ func nonSpace(b []byte) bool {
return false
}
-// An Encoder writes JSON objects to an output stream.
+// An Encoder writes JSON values to an output stream.
type Encoder struct {
- w io.Writer
- err error
+ w io.Writer
+ err error
+ escapeHTML bool
+
+ indentBuf *bytes.Buffer
+ indentPrefix string
+ indentValue string
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{w: w}
+ return &Encoder{w: w, escapeHTML: true}
}
// Encode writes the JSON encoding of v to the stream,
@@ -185,7 +190,7 @@ func (enc *Encoder) Encode(v interface{}) error {
return enc.err
}
e := newEncodeState()
- err := e.marshal(v)
+ err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
if err != nil {
return err
}
@@ -198,21 +203,55 @@ func (enc *Encoder) Encode(v interface{}) error {
// digits coming.
e.WriteByte('\n')
- if _, err = enc.w.Write(e.Bytes()); err != nil {
+ b := e.Bytes()
+ 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 {
+ return err
+ }
+ b = enc.indentBuf.Bytes()
+ }
+ if _, err = enc.w.Write(b); err != nil {
enc.err = err
}
encodeStatePool.Put(e)
return err
}
-// RawMessage is a raw encoded JSON object.
+// 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
+}
+
+// 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.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte
-// MarshalJSON returns *m as the JSON encoding of m.
-func (m *RawMessage) MarshalJSON() ([]byte, error) {
- return *m, nil
+// MarshalJSON returns m as the JSON encoding of m.
+func (m RawMessage) MarshalJSON() ([]byte, error) {
+ if m == nil {
+ return []byte("null"), nil
+ }
+ return m, nil
}
// UnmarshalJSON sets *m to a copy of data.
diff --git a/libgo/go/encoding/json/stream_test.go b/libgo/go/encoding/json/stream_test.go
index c2e30408cd..84edeb187c 100644
--- a/libgo/go/encoding/json/stream_test.go
+++ b/libgo/go/encoding/json/stream_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -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)
@@ -57,6 +60,69 @@ func TestEncoder(t *testing.T) {
}
}
+var streamEncodedIndent = `0.1
+"hello"
+null
+true
+false
+[
+>."a",
+>."b",
+>."c"
+>]
+{
+>."ß": "long s",
+>."K": "Kelvin"
+>}
+3.14
+`
+
+func TestEncoderIndent(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ enc.SetIndent(">", ".")
+ for _, v := range streamTest {
+ enc.Encode(v)
+ }
+ if have, want := buf.String(), streamEncodedIndent; have != want {
+ t.Error("indented encoding mismatch")
+ diff(t, []byte(have), []byte(want))
+ }
+}
+
+func TestEncoderSetEscapeHTML(t *testing.T) {
+ var c C
+ var ct CText
+ for _, tt := range []struct {
+ name string
+ v interface{}
+ wantEscape string
+ want string
+ }{
+ {"c", c, `"\u003c\u0026\u003e"`, `"<&>"`},
+ {"ct", ct, `"\"\u003c\u0026\u003e\""`, `"\"<&>\""`},
+ {`"<&>"`, "<&>", `"\u003c\u0026\u003e"`, `"<&>"`},
+ } {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ if err := enc.Encode(tt.v); err != nil {
+ t.Fatalf("Encode(%s): %s", tt.name, err)
+ }
+ if got := strings.TrimSpace(buf.String()); got != tt.wantEscape {
+ t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape)
+ }
+ buf.Reset()
+ enc.SetEscapeHTML(false)
+ if err := enc.Encode(tt.v); err != nil {
+ t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err)
+ }
+ if got := strings.TrimSpace(buf.String()); got != tt.want {
+ t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q",
+ tt.name, got, tt.want)
+ }
+ }
+}
+
func TestDecoder(t *testing.T) {
for i := 0; i <= len(streamTest); i++ {
// Use stream without newlines as input,
diff --git a/libgo/go/encoding/json/tables.go b/libgo/go/encoding/json/tables.go
new file mode 100644
index 0000000000..10acdc18c6
--- /dev/null
+++ b/libgo/go/encoding/json/tables.go
@@ -0,0 +1,218 @@
+// 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 json
+
+import "unicode/utf8"
+
+// safeSet holds the value true if the ASCII character with the given array
+// position can be represented inside a JSON string without any further
+// escaping.
+//
+// All values are true except for the ASCII control characters (0-31), the
+// double quote ("), and the backslash character ("\").
+var safeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': 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,
+ ':': true,
+ ';': true,
+ '<': true,
+ '=': 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,
+ '\\': false,
+ ']': 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,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
+
+// htmlSafeSet holds the value true if the ASCII character with the given
+// array position can be safely represented inside a JSON string, embedded
+// inside of HTML <script> tags, without any additional escaping.
+//
+// All values are true except for the ASCII control characters (0-31), the
+// double quote ("), the backslash character ("\"), HTML opening and closing
+// tags ("<" and ">"), and the ampersand ("&").
+var htmlSafeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': false,
+ '\'': 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,
+ ':': true,
+ ';': true,
+ '<': false,
+ '=': true,
+ '>': false,
+ '?': 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,
+ '\\': false,
+ ']': 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,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
diff --git a/libgo/go/encoding/json/tagkey_test.go b/libgo/go/encoding/json/tagkey_test.go
index 85bb4ba837..f77c49c764 100644
--- a/libgo/go/encoding/json/tagkey_test.go
+++ b/libgo/go/encoding/json/tagkey_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -44,6 +44,10 @@ type punctuationTag struct {
V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
}
+type dashTag struct {
+ V string `json:"-,"`
+}
+
type emptyTag struct {
W string
}
@@ -80,6 +84,7 @@ var structTagObjectKeyTests = []struct {
{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
{miscPlaneTag{"ã„ã‚ã¯ã«ã»ã¸ã¨"}, "ã„ã‚ã¯ã«ã»ã¸ã¨", "色ã¯åŒ‚ã¸ã©"},
+ {dashTag{"foo"}, "foo", "-"},
{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
diff --git a/libgo/go/encoding/json/tags_test.go b/libgo/go/encoding/json/tags_test.go
index 91fb18831e..8ba8ddd5f8 100644
--- a/libgo/go/encoding/json/tags_test.go
+++ b/libgo/go/encoding/json/tags_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/encoding/json/testdata/code.json.gz b/libgo/go/encoding/json/testdata/code.json.gz
index 0e2895b53a..1572a92bfb 100644
--- a/libgo/go/encoding/json/testdata/code.json.gz
+++ b/libgo/go/encoding/json/testdata/code.json.gz
Binary files differ
diff --git a/libgo/go/encoding/pem/example_test.go b/libgo/go/encoding/pem/example_test.go
new file mode 100644
index 0000000000..ffd962bd68
--- /dev/null
+++ b/libgo/go/encoding/pem/example_test.go
@@ -0,0 +1,46 @@
+// 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 pem_test
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "log"
+)
+
+func ExampleDecode() {
+ var pubPEMData = []byte(`
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
+WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
+CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
+qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
+yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
+nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
+6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
+TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
+a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
+PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
+yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
+AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
+-----END PUBLIC KEY-----
+and some more`)
+
+ block, rest := pem.Decode(pubPEMData)
+ if block == nil || block.Type != "PUBLIC KEY" {
+ log.Fatal("failed to decode PEM block containing public key")
+ }
+
+ pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Got a %T, with remaining data: %q", pub, rest)
+ // Output: Got a *rsa.PublicKey, with remaining data: "and some more"
+}
diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go
index 506196b1db..fbf49997d5 100644
--- a/libgo/go/encoding/pem/pem.go
+++ b/libgo/go/encoding/pem/pem.go
@@ -119,19 +119,36 @@ func Decode(data []byte) (p *Block, rest []byte) {
rest = next
}
- var endIndex int
+ var endIndex, endTrailerIndex int
+
// If there were no headers, the END line might occur
// immediately, without a leading newline.
if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) {
endIndex = 0
+ endTrailerIndex = len(pemEnd) - 1
} else {
endIndex = bytes.Index(rest, pemEnd)
+ endTrailerIndex = endIndex + len(pemEnd)
}
if endIndex < 0 {
return decodeError(data, rest)
}
+ // After the "-----" of the ending line should be the same type and a
+ // final five dashes.
+ endTrailer := rest[endTrailerIndex:]
+ endTrailerLen := len(typeLine) + len(pemEndOfLine)
+ if len(endTrailer) < endTrailerLen {
+ return decodeError(data, rest)
+ }
+
+ endTrailer = endTrailer[:endTrailerLen]
+ if !bytes.HasPrefix(endTrailer, typeLine) ||
+ !bytes.HasSuffix(endTrailer, pemEndOfLine) {
+ return decodeError(data, rest)
+ }
+
base64Data := removeWhitespace(rest[:endIndex])
p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
@@ -150,7 +167,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
func decodeError(data, rest []byte) (*Block, []byte) {
// If we get here then we have rejected a likely looking, but
// ultimately invalid PEM block. We need to start over from a new
- // position. We have consumed the preamble line and will have consumed
+ // position. We have consumed the preamble line and will have consumed
// any lines which could be header lines. However, a valid preamble
// line is not a valid header line, therefore we cannot have consumed
// the preamble line for the any subsequent block. Thus, we will always
diff --git a/libgo/go/encoding/pem/pem_test.go b/libgo/go/encoding/pem/pem_test.go
index 958dbc1a3a..6321dec382 100644
--- a/libgo/go/encoding/pem/pem_test.go
+++ b/libgo/go/encoding/pem/pem_test.go
@@ -78,6 +78,48 @@ func TestDecode(t *testing.T) {
}
}
+const pemTooFewEndingDashes = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END FOO----`
+
+const pemWrongEndingType = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END BAR-----`
+
+const pemMissingEndingSpace = `
+-----BEGIN FOO-----
+dGVzdA==
+-----ENDBAR-----`
+
+var badPEMTests = []struct {
+ name string
+ input string
+}{
+ {
+ "too few trailing dashes",
+ pemTooFewEndingDashes,
+ },
+ {
+ "incorrect ending type",
+ pemWrongEndingType,
+ },
+ {
+ "missing ending space",
+ pemMissingEndingSpace,
+ },
+}
+
+func TestBadDecode(t *testing.T) {
+ for _, test := range badPEMTests {
+ result, _ := Decode([]byte(test.input))
+ if result != nil {
+ t.Errorf("unexpected success while parsing %q", test.name)
+ }
+ }
+}
+
func TestEncode(t *testing.T) {
r := EncodeToMemory(privateKey2)
if string(r) != pemPrivateKey2 {
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go
index 8ebd693030..4c6ba8c1a5 100644
--- a/libgo/go/encoding/xml/marshal.go
+++ b/libgo/go/encoding/xml/marshal.go
@@ -24,21 +24,21 @@ const (
// Marshal returns the XML encoding of v.
//
-// Marshal handles an array or slice by marshalling each of the elements.
-// Marshal handles a pointer by marshalling the value it points at or, if the
-// pointer is nil, by writing nothing. Marshal handles an interface value by
-// marshalling the value it contains or, if the interface value is nil, by
-// writing nothing. Marshal handles all other data by writing one or more XML
+// Marshal handles an array or slice by marshaling each of the elements.
+// Marshal handles a pointer by marshaling the value it points at or, if the
+// pointer is nil, by writing nothing. Marshal handles an interface value by
+// marshaling the value it contains or, if the interface value is nil, by
+// writing nothing. Marshal handles all other data by writing one or more XML
// elements containing the data.
//
// The name for the XML elements is taken from, in order of preference:
// - the tag on the XMLName field, if the data is a struct
-// - the value of the XMLName field of type xml.Name
+// - the value of the XMLName field of type Name
// - the tag of the struct field used to obtain the data
// - the name of the struct field used to obtain the data
-// - the name of the marshalled type
+// - the name of the marshaled type
//
-// The XML element for a struct contains marshalled elements for each of the
+// The XML element for a struct contains marshaled elements for each of the
// exported fields of the struct, with these exceptions:
// - the XMLName field, described above, is omitted.
// - a field with tag "-" is omitted.
@@ -51,9 +51,9 @@ const (
// - a field with tag ",cdata" is written as character data
// wrapped in one or more <![CDATA[ ... ]]> tags, not as an XML element.
// - a field with tag ",innerxml" is written verbatim, not subject
-// to the usual marshalling procedure.
+// to the usual marshaling procedure.
// - a field with tag ",comment" is written as an XML comment, not
-// subject to the usual marshalling procedure. It must not contain
+// subject to the usual marshaling procedure. It must not contain
// the "--" string within it.
// - a field with a tag including the "omitempty" option is omitted
// if the field value is empty. The empty values are false, 0, any
@@ -63,7 +63,7 @@ const (
// value were part of the outer struct.
//
// If a field uses a tag "a>b>c", then the element c will be nested inside
-// parent elements a and b. Fields that appear next to each other that name
+// parent elements a and b. Fields that appear next to each other that name
// the same parent will be enclosed in one XML element.
//
// See MarshalIndent for an example.
@@ -175,10 +175,9 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
}
var (
- begComment = []byte("<!--")
- endComment = []byte("-->")
- endProcInst = []byte("?>")
- endDirective = []byte(">")
+ begComment = []byte("<!--")
+ endComment = []byte("-->")
+ endProcInst = []byte("?>")
)
// EncodeToken writes the given XML token to the stream.
@@ -217,7 +216,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
return p.cachedWriteError()
case ProcInst:
// First token to be encoded which is also a ProcInst with target of xml
- // is the xml declaration. The only ProcInst where target of xml is allowed.
+ // is the xml declaration. The only ProcInst where target of xml is allowed.
if t.Target == "xml" && p.Buffered() != 0 {
return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
}
@@ -495,7 +494,6 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
continue
}
fv := finfo.value(val)
- name := Name{Space: finfo.xmlns, Local: finfo.name}
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
continue
@@ -505,69 +503,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
continue
}
- if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) {
- attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
- if err != nil {
- return err
- }
- if attr.Name.Local != "" {
- start.Attr = append(start.Attr, attr)
- }
- continue
- }
-
- if fv.CanAddr() {
- pv := fv.Addr()
- if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
- attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
- if err != nil {
- return err
- }
- if attr.Name.Local != "" {
- start.Attr = append(start.Attr, attr)
- }
- continue
- }
- }
-
- if fv.CanInterface() && fv.Type().Implements(textMarshalerType) {
- text, err := fv.Interface().(encoding.TextMarshaler).MarshalText()
- if err != nil {
- return err
- }
- start.Attr = append(start.Attr, Attr{name, string(text)})
- continue
- }
-
- if fv.CanAddr() {
- pv := fv.Addr()
- if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
- text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
- if err != nil {
- return err
- }
- start.Attr = append(start.Attr, Attr{name, string(text)})
- continue
- }
- }
-
- // Dereference or skip nil pointer, interface values.
- switch fv.Kind() {
- case reflect.Ptr, reflect.Interface:
- if fv.IsNil() {
- continue
- }
- fv = fv.Elem()
- }
-
- s, b, err := p.marshalSimple(fv.Type(), fv)
- if err != nil {
+ name := Name{Space: finfo.xmlns, Local: finfo.name}
+ if err := p.marshalAttr(&start, name, fv); err != nil {
return err
}
- if b != nil {
- s = string(b)
- }
- start.Attr = append(start.Attr, Attr{name, s})
}
if err := p.writeStart(&start); err != nil {
@@ -597,6 +536,90 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
return p.cachedWriteError()
}
+// marshalAttr marshals an attribute with the given name and value, adding to start.Attr.
+func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
+ if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
+ attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
+ if err != nil {
+ return err
+ }
+ if attr.Name.Local != "" {
+ start.Attr = append(start.Attr, attr)
+ }
+ return nil
+ }
+
+ if val.CanAddr() {
+ pv := val.Addr()
+ if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
+ attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
+ if err != nil {
+ return err
+ }
+ if attr.Name.Local != "" {
+ start.Attr = append(start.Attr, attr)
+ }
+ return nil
+ }
+ }
+
+ if val.CanInterface() && val.Type().Implements(textMarshalerType) {
+ text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return err
+ }
+ start.Attr = append(start.Attr, Attr{name, string(text)})
+ return nil
+ }
+
+ if val.CanAddr() {
+ pv := val.Addr()
+ if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
+ text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return err
+ }
+ start.Attr = append(start.Attr, Attr{name, string(text)})
+ return nil
+ }
+ }
+
+ // Dereference or skip nil pointer, interface values.
+ switch val.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ if val.IsNil() {
+ return nil
+ }
+ val = val.Elem()
+ }
+
+ // Walk slices.
+ if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
+ n := val.Len()
+ for i := 0; i < n; i++ {
+ if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ if val.Type() == attrType {
+ start.Attr = append(start.Attr, val.Interface().(Attr))
+ return nil
+ }
+
+ s, b, err := p.marshalSimple(val.Type(), val)
+ if err != nil {
+ return err
+ }
+ if b != nil {
+ s = string(b)
+ }
+ start.Attr = append(start.Attr, Attr{name, s})
+ return nil
+}
+
// defaultStart returns the default start element to use,
// given the reflect type, field info, and start template.
func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
@@ -752,6 +775,20 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []
var ddBytes = []byte("--")
+// indirect drills into interfaces and pointers, returning the pointed-at value.
+// If it encounters a nil interface or pointer, indirect returns that nil value.
+// This can turn into an infinite loop given a cyclic chain,
+// but it matches the Go 1 behavior.
+func indirect(vf reflect.Value) reflect.Value {
+ for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
+ if vf.IsNil() {
+ return vf
+ }
+ vf = vf.Elem()
+ }
+ return vf
+}
+
func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{p: p}
for i := range tinfo.fields {
@@ -761,14 +798,6 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
}
vf := finfo.value(val)
- // Dereference or skip nil pointer, interface values.
- switch vf.Kind() {
- case reflect.Ptr, reflect.Interface:
- if !vf.IsNil() {
- vf = vf.Elem()
- }
- }
-
switch finfo.flags & fMode {
case fCDATA, fCharData:
emit := EscapeText
@@ -801,7 +830,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
}
}
+
var scratch [64]byte
+ vf = indirect(vf)
switch vf.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
@@ -836,6 +867,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
if err := s.trim(finfo.parents); err != nil {
return err
}
+ vf = indirect(vf)
k := vf.Kind()
if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@@ -850,14 +882,14 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
switch k {
case reflect.String:
s := vf.String()
- dashDash = strings.Index(s, "--") >= 0
+ dashDash = strings.Contains(s, "--")
dashLast = s[len(s)-1] == '-'
if !dashDash {
p.WriteString(s)
}
case reflect.Slice:
b := vf.Bytes()
- dashDash = bytes.Index(b, ddBytes) >= 0
+ dashDash = bytes.Contains(b, ddBytes)
dashLast = b[len(b)-1] == '-'
if !dashDash {
p.Write(b)
@@ -876,6 +908,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
case fInnerXml:
+ vf = indirect(vf)
iface := vf.Interface()
switch raw := iface.(type) {
case []byte:
@@ -949,8 +982,8 @@ type parentStack struct {
}
// trim updates the XML context to match the longest common prefix of the stack
-// and the given parents. A closing tag will be written for every parent
-// popped. Passing a zero slice or nil will close all the elements.
+// and the given parents. A closing tag will be written for every parent
+// popped. Passing a zero slice or nil will close all the elements.
func (s *parentStack) trim(parents []string) error {
split := 0
for ; split < len(parents) && split < len(s.stack); split++ {
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index fe8b16fe43..0126146d33 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -199,6 +199,17 @@ type AttrTest struct {
Bytes []byte `xml:",attr"`
}
+type AttrsTest struct {
+ Attrs []Attr `xml:",any,attr"`
+ Int int `xml:",attr"`
+ Named int `xml:"int,attr"`
+ Float float64 `xml:",attr"`
+ Uint8 uint8 `xml:",attr"`
+ Bool bool `xml:",attr"`
+ Str string `xml:",attr"`
+ Bytes []byte `xml:",attr"`
+}
+
type OmitAttrTest struct {
Int int `xml:",attr,omitempty"`
Named int `xml:"int,attr,omitempty"`
@@ -207,6 +218,7 @@ type OmitAttrTest struct {
Bool bool `xml:",attr,omitempty"`
Str string `xml:",attr,omitempty"`
Bytes []byte `xml:",attr,omitempty"`
+ PStr *string `xml:",attr,omitempty"`
}
type OmitFieldTest struct {
@@ -217,6 +229,7 @@ type OmitFieldTest struct {
Bool bool `xml:",omitempty"`
Str string `xml:",omitempty"`
Bytes []byte `xml:",omitempty"`
+ PStr *string `xml:",omitempty"`
Ptr *PresenceTest `xml:",omitempty"`
}
@@ -317,6 +330,10 @@ func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
return Attr{name, "hello world"}, nil
}
+func (m *MyMarshalerAttrTest) UnmarshalXMLAttr(attr Attr) error {
+ return nil
+}
+
type MarshalerStruct struct {
Foo MyMarshalerAttrTest `xml:",attr"`
}
@@ -369,21 +386,158 @@ func ifaceptr(x interface{}) interface{} {
return &x
}
+func stringptr(x string) *string {
+ return &x
+}
+
+type T1 struct{}
+type T2 struct{}
+type T3 struct{}
+
+type IndirComment struct {
+ T1 T1
+ Comment *string `xml:",comment"`
+ T2 T2
+}
+
+type DirectComment struct {
+ T1 T1
+ Comment string `xml:",comment"`
+ T2 T2
+}
+
+type IfaceComment struct {
+ T1 T1
+ Comment interface{} `xml:",comment"`
+ T2 T2
+}
+
+type IndirChardata struct {
+ T1 T1
+ Chardata *string `xml:",chardata"`
+ T2 T2
+}
+
+type DirectChardata struct {
+ T1 T1
+ Chardata string `xml:",chardata"`
+ T2 T2
+}
+
+type IfaceChardata struct {
+ T1 T1
+ Chardata interface{} `xml:",chardata"`
+ T2 T2
+}
+
+type IndirCDATA struct {
+ T1 T1
+ CDATA *string `xml:",cdata"`
+ T2 T2
+}
+
+type DirectCDATA struct {
+ T1 T1
+ CDATA string `xml:",cdata"`
+ T2 T2
+}
+
+type IfaceCDATA struct {
+ T1 T1
+ CDATA interface{} `xml:",cdata"`
+ T2 T2
+}
+
+type IndirInnerXML struct {
+ T1 T1
+ InnerXML *string `xml:",innerxml"`
+ T2 T2
+}
+
+type DirectInnerXML struct {
+ T1 T1
+ InnerXML string `xml:",innerxml"`
+ T2 T2
+}
+
+type IfaceInnerXML struct {
+ T1 T1
+ InnerXML interface{} `xml:",innerxml"`
+ T2 T2
+}
+
+type IndirElement struct {
+ T1 T1
+ Element *string
+ T2 T2
+}
+
+type DirectElement struct {
+ T1 T1
+ Element string
+ T2 T2
+}
+
+type IfaceElement struct {
+ T1 T1
+ Element interface{}
+ T2 T2
+}
+
+type IndirOmitEmpty struct {
+ T1 T1
+ OmitEmpty *string `xml:",omitempty"`
+ T2 T2
+}
+
+type DirectOmitEmpty struct {
+ T1 T1
+ OmitEmpty string `xml:",omitempty"`
+ T2 T2
+}
+
+type IfaceOmitEmpty struct {
+ T1 T1
+ OmitEmpty interface{} `xml:",omitempty"`
+ T2 T2
+}
+
+type IndirAny struct {
+ T1 T1
+ Any *string `xml:",any"`
+ T2 T2
+}
+
+type DirectAny struct {
+ T1 T1
+ Any string `xml:",any"`
+ T2 T2
+}
+
+type IfaceAny struct {
+ T1 T1
+ Any interface{} `xml:",any"`
+ T2 T2
+}
+
var (
nameAttr = "Sarah"
ageAttr = uint(12)
contentsAttr = "lorem ipsum"
+ empty = ""
)
// Unless explicitly stated as such (or *Plain), all of the
// tests below are two-way tests. When introducing new tests,
// please try to make them two-way as well to ensure that
-// marshalling and unmarshalling are as symmetrical as feasible.
+// marshaling and unmarshaling are as symmetrical as feasible.
var marshalTests = []struct {
- Value interface{}
- ExpectXML string
- MarshalOnly bool
- UnmarshalOnly bool
+ Value interface{}
+ ExpectXML string
+ MarshalOnly bool
+ MarshalError string
+ UnmarshalOnly bool
+ UnmarshalError string
}{
// Test nil marshals to nothing
{Value: nil, ExpectXML: ``, MarshalOnly: true},
@@ -823,6 +977,53 @@ var marshalTests = []struct {
` Bool="false" Str="" Bytes=""></AttrTest>`,
},
{
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Answer"}, Value: "42"},
+ {Name: Name{Local: "Int"}, Value: "8"},
+ {Name: Name{Local: "int"}, Value: "9"},
+ {Name: Name{Local: "Float"}, Value: "23.5"},
+ {Name: Name{Local: "Uint8"}, Value: "255"},
+ {Name: Name{Local: "Bool"}, Value: "true"},
+ {Name: Name{Local: "Str"}, Value: "str"},
+ {Name: Name{Local: "Bytes"}, Value: "byt"},
+ },
+ },
+ ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Answer"}, Value: "42"},
+ },
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ },
+ ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt"></AttrsTest>`,
+ },
+ {
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Int"}, Value: "0"},
+ {Name: Name{Local: "int"}, Value: "0"},
+ {Name: Name{Local: "Float"}, Value: "0"},
+ {Name: Name{Local: "Uint8"}, Value: "0"},
+ {Name: Name{Local: "Bool"}, Value: "false"},
+ {Name: Name{Local: "Str"}},
+ {Name: Name{Local: "Bytes"}},
+ },
+ Bytes: []byte{},
+ },
+ ExpectXML: `<AttrsTest Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes="" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
+ MarshalOnly: true,
+ },
+ {
Value: &OmitAttrTest{
Int: 8,
Named: 9,
@@ -831,9 +1032,10 @@ var marshalTests = []struct {
Bool: true,
Str: "str",
Bytes: []byte("byt"),
+ PStr: &empty,
},
ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
- ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
+ ` Bool="true" Str="str" Bytes="byt" PStr=""></OmitAttrTest>`,
},
{
Value: &OmitAttrTest{},
@@ -864,6 +1066,7 @@ var marshalTests = []struct {
Bool: true,
Str: "str",
Bytes: []byte("byt"),
+ PStr: &empty,
Ptr: &PresenceTest{},
},
ExpectXML: `<OmitFieldTest>` +
@@ -874,6 +1077,7 @@ var marshalTests = []struct {
`<Bool>true</Bool>` +
`<Str>str</Str>` +
`<Bytes>byt</Bytes>` +
+ `<PStr></PStr>` +
`<Ptr></Ptr>` +
`</OmitFieldTest>`,
},
@@ -1065,6 +1269,382 @@ var marshalTests = []struct {
ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
},
+ // Test pointer indirection in various kinds of fields.
+ // https://golang.org/issue/19063
+ {
+ ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
+ Value: &IndirComment{Comment: stringptr("hi")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
+ Value: &IndirComment{Comment: stringptr("")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
+ Value: &IndirComment{Comment: nil},
+ MarshalError: "xml: bad type for comment field of xml.IndirComment",
+ },
+ {
+ ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
+ Value: &IndirComment{Comment: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
+ Value: &IfaceComment{Comment: "hi"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
+ Value: &IfaceComment{Comment: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
+ Value: &IfaceComment{Comment: nil},
+ MarshalError: "xml: bad type for comment field of xml.IfaceComment",
+ },
+ {
+ ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
+ Value: &IfaceComment{Comment: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
+ Value: &DirectComment{Comment: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
+ Value: &DirectComment{Comment: string("")},
+ },
+ {
+ ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
+ Value: &IndirChardata{Chardata: stringptr("hi")},
+ },
+ {
+ ExpectXML: `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
+ Value: &IndirChardata{Chardata: stringptr("hi")},
+ UnmarshalOnly: true, // marshals without CDATA
+ },
+ {
+ ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
+ Value: &IndirChardata{Chardata: stringptr("")},
+ },
+ {
+ ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
+ Value: &IndirChardata{Chardata: nil},
+ MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
+ },
+ {
+ ExpectXML: `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
+ Value: &IfaceChardata{Chardata: string("hi")},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
+ Value: &IfaceChardata{Chardata: string("hi")},
+ UnmarshalOnly: true, // marshals without CDATA
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
+ Value: &IfaceChardata{Chardata: string("")},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
+ Value: &IfaceChardata{Chardata: nil},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
+ Value: &DirectChardata{Chardata: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
+ Value: &DirectChardata{Chardata: string("hi")},
+ UnmarshalOnly: true, // marshals without CDATA
+ },
+ {
+ ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
+ Value: &DirectChardata{Chardata: string("")},
+ },
+ {
+ ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
+ Value: &IndirCDATA{CDATA: stringptr("hi")},
+ },
+ {
+ ExpectXML: `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
+ Value: &IndirCDATA{CDATA: stringptr("hi")},
+ UnmarshalOnly: true, // marshals with CDATA
+ },
+ {
+ ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
+ Value: &IndirCDATA{CDATA: stringptr("")},
+ },
+ {
+ ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
+ Value: &IndirCDATA{CDATA: nil},
+ MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
+ },
+ {
+ ExpectXML: `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
+ Value: &IfaceCDATA{CDATA: string("hi")},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
+ Value: &IfaceCDATA{CDATA: string("hi")},
+ UnmarshalOnly: true, // marshals with CDATA
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
+ Value: &IfaceCDATA{CDATA: string("")},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
+ Value: &IfaceCDATA{CDATA: nil},
+ UnmarshalError: "cannot unmarshal into interface {}",
+ },
+ {
+ ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
+ Value: &DirectCDATA{CDATA: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
+ Value: &DirectCDATA{CDATA: string("hi")},
+ UnmarshalOnly: true, // marshals with CDATA
+ },
+ {
+ ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
+ Value: &DirectCDATA{CDATA: string("")},
+ },
+ {
+ ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
+ Value: &IndirInnerXML{InnerXML: stringptr("<hi/>")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
+ Value: &IndirInnerXML{InnerXML: stringptr("")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
+ Value: &IndirInnerXML{InnerXML: nil},
+ },
+ {
+ ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
+ Value: &IndirInnerXML{InnerXML: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
+ Value: &IfaceInnerXML{InnerXML: "<hi/>"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
+ Value: &IfaceInnerXML{InnerXML: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
+ Value: &IfaceInnerXML{InnerXML: nil},
+ },
+ {
+ ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
+ Value: &IfaceInnerXML{InnerXML: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
+ Value: &DirectInnerXML{InnerXML: string("<hi/>")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
+ Value: &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
+ Value: &DirectInnerXML{InnerXML: string("")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
+ Value: &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
+ Value: &IndirElement{Element: stringptr("hi")},
+ },
+ {
+ ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
+ Value: &IndirElement{Element: stringptr("")},
+ },
+ {
+ ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
+ Value: &IndirElement{Element: nil},
+ },
+ {
+ ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
+ Value: &IfaceElement{Element: "hi"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
+ Value: &IfaceElement{Element: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
+ Value: &IfaceElement{Element: nil},
+ },
+ {
+ ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
+ Value: &IfaceElement{Element: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
+ Value: &DirectElement{Element: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
+ Value: &DirectElement{Element: string("")},
+ },
+ {
+ ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
+ Value: &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
+ },
+ {
+ // Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
+ ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
+ Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
+ Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
+ Value: &IndirOmitEmpty{OmitEmpty: nil},
+ },
+ {
+ ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
+ Value: &IfaceOmitEmpty{OmitEmpty: "hi"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
+ Value: &IfaceOmitEmpty{OmitEmpty: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
+ Value: &IfaceOmitEmpty{OmitEmpty: nil},
+ },
+ {
+ ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
+ Value: &IfaceOmitEmpty{OmitEmpty: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
+ Value: &DirectOmitEmpty{OmitEmpty: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
+ Value: &DirectOmitEmpty{OmitEmpty: string("")},
+ },
+ {
+ ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
+ Value: &IndirAny{Any: stringptr("hi")},
+ },
+ {
+ ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
+ Value: &IndirAny{Any: stringptr("")},
+ },
+ {
+ ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
+ Value: &IndirAny{Any: nil},
+ },
+ {
+ ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
+ Value: &IfaceAny{Any: "hi"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
+ Value: &IfaceAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
+ Value: &IfaceAny{Any: nil},
+ },
+ {
+ ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
+ Value: &IfaceAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
+ Value: &DirectAny{Any: string("hi")},
+ },
+ {
+ ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
+ Value: &DirectAny{Any: string("")},
+ },
+ {
+ ExpectXML: `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
+ Value: &IndirAny{Any: stringptr("hi")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
+ Value: &IndirAny{Any: stringptr("")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
+ Value: &IndirAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
+ Value: &IfaceAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
+ Value: &IfaceAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
+ Value: &IfaceAny{Any: nil},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
+ Value: &DirectAny{Any: string("hi")},
+ UnmarshalOnly: true,
+ },
+ {
+ ExpectXML: `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
+ Value: &DirectAny{Any: string("")},
+ UnmarshalOnly: true,
+ },
}
func TestMarshal(t *testing.T) {
@@ -1074,7 +1654,17 @@ func TestMarshal(t *testing.T) {
}
data, err := Marshal(test.Value)
if err != nil {
- t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
+ if test.MarshalError == "" {
+ t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
+ continue
+ }
+ if !strings.Contains(err.Error(), test.MarshalError) {
+ t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError)
+ }
+ continue
+ }
+ if test.MarshalError != "" {
+ t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError)
continue
}
if got, want := string(data), test.ExpectXML; got != want {
@@ -1092,7 +1682,7 @@ type AttrParent struct {
}
type BadAttr struct {
- Name []string `xml:"name,attr"`
+ Name map[string]string `xml:"name,attr"`
}
var marshalErrorTests = []struct {
@@ -1128,8 +1718,8 @@ var marshalErrorTests = []struct {
Err: `xml: X>Y chain not valid with attr flag`,
},
{
- Value: BadAttr{[]string{"X", "Y"}},
- Err: `xml: unsupported type: []string`,
+ Value: BadAttr{map[string]string{"X": "Y"}},
+ Err: `xml: unsupported type: map[string]string`,
},
}
@@ -1200,8 +1790,16 @@ func TestUnmarshal(t *testing.T) {
}
if err != nil {
- t.Errorf("#%d: unexpected error: %#v", i, err)
- } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+ if test.UnmarshalError == "" {
+ t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err)
+ continue
+ }
+ if !strings.Contains(err.Error(), test.UnmarshalError) {
+ t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError)
+ }
+ continue
+ }
+ if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
}
}
@@ -1732,7 +2330,7 @@ func TestDecodeEncode(t *testing.T) {
in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
<?Target Instruction?>
<root>
-</root>
+</root>
`)
dec := NewDecoder(&in)
enc := NewEncoder(&out)
@@ -1823,3 +2421,17 @@ func TestSimpleUseOfEncodeToken(t *testing.T) {
t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
}
}
+
+// Issue 16158. Decoder.unmarshalAttr ignores the return value of copyValue.
+func TestIssue16158(t *testing.T) {
+ const data = `<foo b="HELLOWORLD"></foo>`
+ err := Unmarshal([]byte(data), &struct {
+ B byte `xml:"b,attr,omitempty"`
+ }{})
+
+ // For Go 1.8.1 we've restored the old "no errors reported" behavior.
+ // We'll try again in Go 1.9 to report errors.
+ if err != nil {
+ t.Errorf("Unmarshal: expected nil, got error")
+ }
+}
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index 77b4c7b495..799b57e9d1 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -27,7 +27,7 @@ import (
// discarded.
//
// Because Unmarshal uses the reflect package, it can only assign
-// to exported (upper case) fields. Unmarshal uses a case-sensitive
+// to exported (upper case) fields. Unmarshal uses a case-sensitive
// comparison to match XML element names to tag values and struct
// field names.
//
@@ -37,9 +37,9 @@ import (
//
// * If the struct has a field of type []byte or string with tag
// ",innerxml", Unmarshal accumulates the raw XML nested inside the
-// element in that field. The rest of the rules still apply.
+// element in that field. The rest of the rules still apply.
//
-// * If the struct has a field named XMLName of type xml.Name,
+// * If the struct has a field named XMLName of type Name,
// Unmarshal records the element name in that field.
//
// * If the XMLName field has an associated tag of the form
@@ -52,6 +52,11 @@ import (
// the explicit name in a struct field tag of the form "name,attr",
// Unmarshal records the attribute value in that field.
//
+// * If the XML element has an attribute not handled by the previous
+// rule and the struct has a field with an associated tag containing
+// ",any,attr", Unmarshal records the attribute value in the first
+// such field.
+//
// * If the XML element contains character data, that data is
// accumulated in the first struct field that has tag ",chardata".
// The struct field may have type []byte or string.
@@ -59,7 +64,7 @@ import (
//
// * If the XML element contains comments, they are accumulated in
// the first struct field that has tag ",comment". The struct
-// field may have type []byte or string. If there is no such
+// field may have type []byte or string. If there is no such
// field, the comments are discarded.
//
// * If the XML element contains a sub-element whose name matches
@@ -85,7 +90,7 @@ import (
// * An anonymous struct field is handled as if the fields of its
// value were part of the outer struct.
//
-// * A struct field with tag "-" is never unmarshalled into.
+// * A struct field with tag "-" is never unmarshaled into.
//
// Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or
@@ -94,19 +99,23 @@ import (
// Unmarshal maps an attribute value to a string or []byte by saving
// the value in the string or slice.
//
-// Unmarshal maps an XML element to a slice by extending the length of
-// the slice and mapping the element to the newly created value.
+// Unmarshal maps an attribute value to an Attr by saving the attribute,
+// including its name, in the Attr.
+//
+// Unmarshal maps an XML element or attribute value to a slice by
+// extending the length of the slice and mapping the element or attribute
+// to the newly created value.
//
// Unmarshal maps an XML element or attribute value to a bool by
// setting it to the boolean value represented by the string.
//
// Unmarshal maps an XML element or attribute value to an integer or
// floating-point field by setting the field to the result of
-// interpreting the string value in decimal. There is no check for
+// interpreting the string value in decimal. There is no check for
// overflow.
//
-// Unmarshal maps an XML element to an xml.Name by recording the
-// element name.
+// Unmarshal maps an XML element to a Name by recording the element
+// name.
//
// Unmarshal maps an XML element to a pointer by setting the pointer
// to a freshly allocated value and then mapping the element to that value.
@@ -115,13 +124,13 @@ func Unmarshal(data []byte, v interface{}) error {
return NewDecoder(bytes.NewReader(data)).Decode(v)
}
-// Decode works like xml.Unmarshal, except it reads the decoder
+// Decode works like Unmarshal, except it reads the decoder
// stream to find the start element.
func (d *Decoder) Decode(v interface{}) error {
return d.DecodeElement(v, nil)
}
-// DecodeElement works like xml.Unmarshal except that it takes
+// DecodeElement works like Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.
@@ -133,7 +142,7 @@ func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
return d.unmarshal(val.Elem(), start)
}
-// An UnmarshalError represents an error in the unmarshalling process.
+// An UnmarshalError represents an error in the unmarshaling process.
type UnmarshalError string
func (e UnmarshalError) Error() string { return string(e) }
@@ -232,7 +241,6 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
}
val = val.Elem()
}
-
if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
// This is an unmarshaler with a non-pointer receiver,
// so it's likely to be incorrect, but we do what we're told.
@@ -258,11 +266,31 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
}
}
+ if val.Type().Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
+ // Slice of element values.
+ // Grow slice.
+ n := val.Len()
+ val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
+
+ // Recur to read element into slice.
+ if err := p.unmarshalAttr(val.Index(n), attr); err != nil {
+ val.SetLen(n)
+ return err
+ }
+ return nil
+ }
+
+ if val.Type() == attrType {
+ val.Set(reflect.ValueOf(attr))
+ return nil
+ }
+
copyValue(val, []byte(attr.Value))
return nil
}
var (
+ attrType = reflect.TypeOf(Attr{})
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
@@ -359,16 +387,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
// Slice of element values.
// Grow slice.
n := v.Len()
- if n >= v.Cap() {
- ncap := 2 * n
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(typ, n, ncap)
- reflect.Copy(new, v)
- v.Set(new)
- }
- v.SetLen(n + 1)
+ v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem())))
// Recur to read element into slice.
if err := p.unmarshal(v.Index(n), start); err != nil {
@@ -415,22 +434,40 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
// Assign attributes.
- // Also, determine whether we need to save character data or comments.
- for i := range tinfo.fields {
- finfo := &tinfo.fields[i]
- switch finfo.flags & fMode {
- case fAttr:
- strv := finfo.value(sv)
- // Look for attribute.
- for _, a := range start.Attr {
+ for _, a := range start.Attr {
+ handled := false
+ any := -1
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ switch finfo.flags & fMode {
+ case fAttr:
+ strv := finfo.value(sv)
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
if err := p.unmarshalAttr(strv, a); err != nil {
return err
}
- break
+ handled = true
}
+
+ case fAny | fAttr:
+ if any == -1 {
+ any = i
+ }
+ }
+ }
+ if !handled && any >= 0 {
+ finfo := &tinfo.fields[any]
+ strv := finfo.value(sv)
+ if err := p.unmarshalAttr(strv, a); err != nil {
+ return err
}
+ }
+ }
+ // Determine whether we need to save character data or comments.
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ switch finfo.flags & fMode {
case fCDATA, fCharData:
if !saveData.IsValid() {
saveData = finfo.value(sv)
@@ -546,7 +583,9 @@ Loop:
case reflect.String:
t.SetString(string(saveXMLData))
case reflect.Slice:
- t.Set(reflect.ValueOf(saveXMLData))
+ if t.Type().Elem().Kind() == reflect.Uint8 {
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
}
return nil
diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go
index 7a98092803..273c303d16 100644
--- a/libgo/go/encoding/xml/read_test.go
+++ b/libgo/go/encoding/xml/read_test.go
@@ -705,7 +705,7 @@ func TestUnmarshalIntoInterface(t *testing.T) {
}
pea, ok := pod.Pea.(*Pea)
if !ok {
- t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+ t.Fatalf("unmarshaled into wrong type: have %T want *Pea", pod.Pea)
}
have, want := pea.Cotelydon, "Green stuff"
if have != want {
@@ -733,3 +733,22 @@ func TestMalformedComment(t *testing.T) {
}
}
}
+
+type IXField struct {
+ Five int `xml:"five"`
+ NotInnerXML []string `xml:",innerxml"`
+}
+
+// Issue 15600. ",innerxml" on a field that can't hold it.
+func TestInvalidInnerXMLType(t *testing.T) {
+ v := new(IXField)
+ if err := Unmarshal([]byte(`<tag><five>5</five><innertag/></tag>`), v); err != nil {
+ t.Errorf("Unmarshal failed: got %v", err)
+ }
+ if v.Five != 5 {
+ t.Errorf("Five = %v, want 5", v.Five)
+ }
+ if v.NotInnerXML != nil {
+ t.Errorf("NotInnerXML = %v, want nil", v.NotInnerXML)
+ }
+}
diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go
index 6483c8dbe6..6623c78308 100644
--- a/libgo/go/encoding/xml/typeinfo.go
+++ b/libgo/go/encoding/xml/typeinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -48,7 +48,7 @@ var tinfoLock sync.RWMutex
var nameType = reflect.TypeOf(Name{})
// getTypeInfo returns the typeInfo structure with details necessary
-// for marshalling and unmarshalling typ.
+// for marshaling and unmarshaling typ.
func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tinfoLock.RLock()
tinfo, ok := tinfoMap[typ]
@@ -151,7 +151,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
switch mode := finfo.flags & fMode; mode {
case 0:
finfo.flags |= fElement
- case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny:
+ case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr:
if f.Name == "XMLName" || tag != "" && mode != fAttr {
valid = false
}
@@ -214,7 +214,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
}
// If the field type has an XMLName field, the names must match
- // so that the behavior of both marshalling and unmarshalling
+ // so that the behavior of both marshaling and unmarshaling
// is straightforward and unambiguous.
if finfo.flags&fElement != 0 {
ftyp := f.Type
@@ -334,7 +334,7 @@ Loop:
return nil
}
-// A TagPathError represents an error in the unmarshalling process
+// A TagPathError represents an error in the unmarshaling process
// caused by the use of field tags with conflicting paths.
type TagPathError struct {
Struct reflect.Type
diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go
index 45f4157318..9a3b792955 100644
--- a/libgo/go/encoding/xml/xml.go
+++ b/libgo/go/encoding/xml/xml.go
@@ -219,7 +219,7 @@ func NewDecoder(r io.Reader) *Decoder {
//
// Slices of bytes in the returned token data refer to the
// parser's internal buffer and remain valid only until the next
-// call to Token. To acquire a copy of the bytes, call CopyToken
+// call to Token. To acquire a copy of the bytes, call CopyToken
// or the token's Copy method.
//
// Token expands self-closing elements such as <br/>
@@ -237,10 +237,11 @@ func NewDecoder(r io.Reader) *Decoder {
// set to the URL identifying its name space when known.
// If Token encounters an unrecognized name space prefix,
// it uses the prefix as the Space rather than report an error.
-func (d *Decoder) Token() (t Token, err error) {
+func (d *Decoder) Token() (Token, error) {
+ var t Token
+ var err error
if d.stk != nil && d.stk.kind == stkEOF {
- err = io.EOF
- return
+ return nil, io.EOF
}
if d.nextToken != nil {
t = d.nextToken
@@ -249,7 +250,7 @@ func (d *Decoder) Token() (t Token, err error) {
if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF {
err = d.syntaxError("unexpected EOF")
}
- return
+ return t, err
}
if !d.Strict {
@@ -292,7 +293,7 @@ func (d *Decoder) Token() (t Token, err error) {
}
t = t1
}
- return
+ return t, err
}
const xmlURL = "http://www.w3.org/XML/1998/namespace"
@@ -331,7 +332,7 @@ func (d *Decoder) switchToReader(r io.Reader) {
}
// Parsing state - stack holds old name space translations
-// and the current set of open elements. The translations to pop when
+// and the current set of open elements. The translations to pop when
// ending a given tag are *below* it on the stack, which is
// more work but forced on us by XML.
type stack struct {
@@ -1229,7 +1230,7 @@ func isNameString(s string) bool {
// These tables were generated by cut and paste from Appendix B of
// the XML spec at http://www.xml.com/axml/testaxml.htm
-// and then reformatting. First corresponds to (Letter | '_' | ':')
+// and then reformatting. First corresponds to (Letter | '_' | ':')
// and second corresponds to NameChar.
var first = &unicode.RangeTable{
diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go
index 5d5e4bf970..f43a5e7eeb 100644
--- a/libgo/go/encoding/xml/xml_test.go
+++ b/libgo/go/encoding/xml/xml_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -184,8 +184,6 @@ const nonStrictInput = `
<tag>&0a;</tag>
`
-var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"}
-
var nonStrictTokens = []Token{
CharData("\n"),
StartElement{Name{"", "tag"}, []Attr{}},
@@ -652,10 +650,6 @@ func TestDisallowedCharacters(t *testing.T) {
}
}
-type procInstEncodingTest struct {
- expect, got string
-}
-
var procInstTests = []struct {
input string
expect [2]string
@@ -803,3 +797,37 @@ func TestIssue12417(t *testing.T) {
}
}
}
+
+func TestIssue19333(t *testing.T) {
+ type X struct {
+ XMLName Name `xml:"X"`
+ A int `xml:",attr"`
+ C int
+ }
+
+ var tests = []struct {
+ input string
+ ok bool
+ }{
+ {`<X></X>`, true},
+ {`<X A=""></X>`, true},
+ {`<X A="bad"></X>`, true},
+ {`<X></X>`, true},
+ {`<X><C></C></X>`, false},
+ {`<X><C/></X>`, false},
+ {`<X><C>bad</C></X>`, false},
+ }
+
+ for _, tt := range tests {
+ err := Unmarshal([]byte(tt.input), new(X))
+ if tt.ok {
+ if err != nil {
+ t.Errorf("%s: unexpected error: %v", tt.input, err)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("%s: unexpected success", tt.input)
+ }
+ }
+ }
+}
diff --git a/libgo/go/errors/errors.go b/libgo/go/errors/errors.go
index 3085a7962c..b8a46921be 100644
--- a/libgo/go/errors/errors.go
+++ b/libgo/go/errors/errors.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/errors/errors_test.go b/libgo/go/errors/errors_test.go
index 63c05d7185..cf4df90b69 100644
--- a/libgo/go/errors/errors_test.go
+++ b/libgo/go/errors/errors_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat b/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
deleted file mode 100644
index a5ebb1eb28..0000000000
--- a/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
+++ /dev/null
Binary files differ
diff --git a/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat b/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat
deleted file mode 100644
index 2f40e83bab..0000000000
--- a/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat
+++ /dev/null
@@ -1,8 +0,0 @@
-#data
-FOO&#x000D;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO ZOO"
diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go
index 24c2d6b29a..7339fa00b7 100644
--- a/libgo/go/expvar/expvar.go
+++ b/libgo/go/expvar/expvar.go
@@ -15,7 +15,7 @@
// memstats runtime.Memstats
//
// The package is sometimes only imported for the side effect of
-// registering its HTTP handler and the above variables. To use it
+// registering its HTTP handler and the above variables. To use it
// this way, link this package into your program:
// import _ "expvar"
//
@@ -38,6 +38,9 @@ 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
}
@@ -46,6 +49,10 @@ type Int struct {
i int64
}
+func (v *Int) Value() int64 {
+ return atomic.LoadInt64(&v.i)
+}
+
func (v *Int) String() string {
return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
}
@@ -63,6 +70,10 @@ type Float struct {
f uint64
}
+func (v *Float) Value() float64 {
+ return math.Float64frombits(atomic.LoadUint64(&v.f))
+}
+
func (v *Float) String() string {
return strconv.FormatFloat(
math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
@@ -216,10 +227,20 @@ type String struct {
s string
}
-func (v *String) String() string {
+func (v *String) Value() string {
v.mu.RLock()
defer v.mu.RUnlock()
- return strconv.Quote(v.s)
+ return v.s
+}
+
+// String implements the Val interface. To get the unquoted string
+// use Value.
+func (v *String) String() string {
+ v.mu.RLock()
+ s := v.s
+ v.mu.RUnlock()
+ b, _ := json.Marshal(s)
+ return string(b)
}
func (v *String) Set(value string) {
@@ -232,6 +253,10 @@ func (v *String) Set(value string) {
// and formatting the returned value using JSON.
type Func func() interface{}
+func (f Func) Value() interface{} {
+ return f()
+}
+
func (f Func) String() string {
v, _ := json.Marshal(f())
return string(v)
@@ -258,7 +283,8 @@ func Publish(name string, v Var) {
sort.Strings(varKeys)
}
-// Get retrieves a named exported variable.
+// Get retrieves a named exported variable. It returns nil if the name has
+// not been registered.
func Get(name string) Var {
mutex.RLock()
defer mutex.RUnlock()
@@ -316,6 +342,13 @@ func expvarHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "\n}\n")
}
+// Handler returns the expvar HTTP Handler.
+//
+// This is only needed to install the handler in a non-standard location.
+func Handler() http.Handler {
+ return http.HandlerFunc(expvarHandler)
+}
+
func cmdline() interface{} {
return os.Args
}
diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go
index 8bc633e4a9..0efa8643c0 100644
--- a/libgo/go/expvar/expvar_test.go
+++ b/libgo/go/expvar/expvar_test.go
@@ -7,13 +7,12 @@ package expvar
import (
"bytes"
"encoding/json"
- "math"
"net"
"net/http/httptest"
+ "reflect"
"runtime"
"strconv"
"sync"
- "sync/atomic"
"testing"
)
@@ -26,6 +25,14 @@ func RemoveAll() {
varKeys = nil
}
+func TestNil(t *testing.T) {
+ RemoveAll()
+ val := Get("missing")
+ if val != nil {
+ t.Errorf("got %v, want nil", val)
+ }
+}
+
func TestInt(t *testing.T) {
RemoveAll()
reqs := NewInt("requests")
@@ -50,6 +57,10 @@ func TestInt(t *testing.T) {
if reqs.i != -2 {
t.Errorf("reqs.i = %v, want -2", reqs.i)
}
+
+ if v, want := reqs.Value(), int64(-2); v != want {
+ t.Errorf("reqs.Value() = %q, want %q", v, want)
+ }
}
func BenchmarkIntAdd(b *testing.B) {
@@ -72,10 +83,6 @@ func BenchmarkIntSet(b *testing.B) {
})
}
-func (v *Float) val() float64 {
- return math.Float64frombits(atomic.LoadUint64(&v.f))
-}
-
func TestFloat(t *testing.T) {
RemoveAll()
reqs := NewFloat("requests-float")
@@ -88,8 +95,8 @@ func TestFloat(t *testing.T) {
reqs.Add(1.5)
reqs.Add(1.25)
- if v := reqs.val(); v != 2.75 {
- t.Errorf("reqs.val() = %v, want 2.75", v)
+ if v := reqs.Value(); v != 2.75 {
+ t.Errorf("reqs.Value() = %v, want 2.75", v)
}
if s := reqs.String(); s != "2.75" {
@@ -97,8 +104,8 @@ func TestFloat(t *testing.T) {
}
reqs.Add(-2)
- if v := reqs.val(); v != 0.75 {
- t.Errorf("reqs.val() = %v, want 0.75", v)
+ if v := reqs.Value(); v != 0.75 {
+ t.Errorf("reqs.Value() = %v, want 0.75", v)
}
}
@@ -134,8 +141,18 @@ func TestString(t *testing.T) {
t.Errorf("name.s = %q, want \"Mike\"", name.s)
}
- if s := name.String(); s != "\"Mike\"" {
- t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s)
+ if s, want := name.String(), `"Mike"`; s != want {
+ t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
+ }
+
+ if s, want := name.Value(), "Mike"; s != want {
+ t.Errorf("from %q, name.Value() = %q, want %q", name.s, s, want)
+ }
+
+ // Make sure we produce safe JSON output.
+ name.Set(`<`)
+ if s, want := name.String(), "\"\\u003c\""; s != want {
+ t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
}
}
@@ -163,7 +180,7 @@ func TestMapCounter(t *testing.T) {
if x := colors.m["blue"].(*Int).i; x != 4 {
t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
}
- if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
+ if x := colors.m[`green "midori"`].(*Float).Value(); x != 4.125 {
t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
}
@@ -228,6 +245,9 @@ func TestFunc(t *testing.T) {
if s, exp := f.String(), `["a","b"]`; s != exp {
t.Errorf(`f.String() = %q, want %q`, s, exp)
}
+ if v := f.Value(); !reflect.DeepEqual(v, x) {
+ t.Errorf(`f.Value() = %q, want %q`, v, x)
+ }
x = 17
if s, exp := f.String(), `17`; s != exp {
diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go
index 56cda58b36..edbe83c664 100644
--- a/libgo/go/flag/export_test.go
+++ b/libgo/go/flag/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -13,5 +13,6 @@ import "os"
// exit the program.
func ResetForTesting(usage func()) {
CommandLine = NewFlagSet(os.Args[0], ContinueOnError)
+ CommandLine.Usage = commandLineUsage
Usage = usage
}
diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go
index 3abc80e9c6..bbbc55a279 100644
--- a/libgo/go/flag/flag.go
+++ b/libgo/go/flag/flag.go
@@ -68,6 +68,7 @@ import (
"fmt"
"io"
"os"
+ "reflect"
"sort"
"strconv"
"time"
@@ -93,7 +94,7 @@ func (b *boolValue) Set(s string) error {
func (b *boolValue) Get() interface{} { return bool(*b) }
-func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
+func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
func (b *boolValue) IsBoolFlag() bool { return true }
@@ -120,7 +121,7 @@ func (i *intValue) Set(s string) error {
func (i *intValue) Get() interface{} { return int(*i) }
-func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
+func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
// -- int64 Value
type int64Value int64
@@ -138,7 +139,7 @@ func (i *int64Value) Set(s string) error {
func (i *int64Value) Get() interface{} { return int64(*i) }
-func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
+func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }
// -- uint Value
type uintValue uint
@@ -156,7 +157,7 @@ func (i *uintValue) Set(s string) error {
func (i *uintValue) Get() interface{} { return uint(*i) }
-func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
+func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }
// -- uint64 Value
type uint64Value uint64
@@ -174,7 +175,7 @@ func (i *uint64Value) Set(s string) error {
func (i *uint64Value) Get() interface{} { return uint64(*i) }
-func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
+func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
// -- string Value
type stringValue string
@@ -191,7 +192,7 @@ func (s *stringValue) Set(val string) error {
func (s *stringValue) Get() interface{} { return string(*s) }
-func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
+func (s *stringValue) String() string { return string(*s) }
// -- float64 Value
type float64Value float64
@@ -209,7 +210,7 @@ func (f *float64Value) Set(s string) error {
func (f *float64Value) Get() interface{} { return float64(*f) }
-func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
// -- time.Duration Value
type durationValue time.Duration
@@ -237,6 +238,8 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() }
// rather than using the next command-line argument.
//
// Set is called once, in command line order, for each flag present.
+// The flag package may call the String method with a zero-valued receiver,
+// such as a nil pointer.
type Value interface {
String() string
Set(string) error
@@ -261,7 +264,7 @@ const (
PanicOnError // Call panic with a descriptive error.
)
-// A FlagSet represents a set of defined flags. The zero value of a FlagSet
+// A FlagSet represents a set of defined flags. The zero value of a FlagSet
// has no name and has ContinueOnError error handling.
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
@@ -324,7 +327,7 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
}
// VisitAll visits the command-line flags in lexicographical order, calling
-// fn for each. It visits all flags, even those not set.
+// fn for each. It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) {
CommandLine.VisitAll(fn)
}
@@ -338,7 +341,7 @@ func (f *FlagSet) Visit(fn func(*Flag)) {
}
// Visit visits the command-line flags in lexicographical order, calling fn
-// for each. It visits only those flags that have been set.
+// for each. It visits only those flags that have been set.
func Visit(fn func(*Flag)) {
CommandLine.Visit(fn)
}
@@ -378,7 +381,21 @@ func Set(name, value string) error {
// isZeroValue guesses whether the string represents the zero
// value for a flag. It is not accurate but in practice works OK.
-func isZeroValue(value string) bool {
+func isZeroValue(flag *Flag, value string) bool {
+ // Build a zero value of the flag's Value type, and see if the
+ // result of calling its String method equals the value passed in.
+ // This works unless the Value type is itself an interface type.
+ typ := reflect.TypeOf(flag.Value)
+ var z reflect.Value
+ if typ.Kind() == reflect.Ptr {
+ z = reflect.New(typ.Elem())
+ } else {
+ z = reflect.Zero(typ)
+ }
+ if value == z.Interface().(Value).String() {
+ return true
+ }
+
switch value {
case "false":
return true
@@ -449,7 +466,7 @@ func (f *FlagSet) PrintDefaults() {
s += "\n \t"
}
s += usage
- if !isZeroValue(flag.DefValue) {
+ if !isZeroValue(flag, flag.DefValue) {
if _, ok := flag.Value.(*stringValue); ok {
// put quotes on the value
s += fmt.Sprintf(" (default %q)", flag.DefValue)
@@ -485,7 +502,7 @@ func PrintDefaults() {
}
// defaultUsage is the default function to print a usage message.
-func defaultUsage(f *FlagSet) {
+func (f *FlagSet) defaultUsage() {
if f.name == "" {
fmt.Fprintf(f.out(), "Usage:\n")
} else {
@@ -514,7 +531,7 @@ func (f *FlagSet) NFlag() int { return len(f.actual) }
// NFlag returns the number of command-line flags that have been set.
func NFlag() int { return len(CommandLine.actual) }
-// Arg returns the i'th argument. Arg(0) is the first remaining argument
+// Arg returns the i'th argument. Arg(0) is the first remaining argument
// after flags have been processed. Arg returns an empty string if the
// requested element does not exist.
func (f *FlagSet) Arg(i int) string {
@@ -524,7 +541,7 @@ func (f *FlagSet) Arg(i int) string {
return f.args[i]
}
-// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
+// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
// after flags have been processed. Arg returns an empty string if the
// requested element does not exist.
func Arg(i int) string {
@@ -804,11 +821,7 @@ func (f *FlagSet) failf(format string, a ...interface{}) error {
// or the appropriate default usage function otherwise.
func (f *FlagSet) usage() {
if f.Usage == nil {
- if f == CommandLine {
- Usage()
- } else {
- defaultUsage(f)
- }
+ f.defaultUsage()
} else {
f.Usage()
}
@@ -890,7 +903,7 @@ func (f *FlagSet) parseOne() (bool, error) {
}
// Parse parses flag definitions from the argument list, which should not
-// include the command name. Must be called after all flags in the FlagSet
+// include the command name. Must be called after all flags in the FlagSet
// are defined and before flags are accessed by the program.
// The return value will be ErrHelp if -help or -h were set but not defined.
func (f *FlagSet) Parse(arguments []string) error {
@@ -938,6 +951,18 @@ func Parsed() bool {
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
+func init() {
+ // Override generic FlagSet default Usage with call to global Usage.
+ // Note: This is not CommandLine.Usage = Usage,
+ // because we want any eventual call to use any updated value of Usage,
+ // not the value it has when this line is run.
+ CommandLine.Usage = commandLineUsage
+}
+
+func commandLineUsage() {
+ Usage()
+}
+
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
@@ -945,6 +970,7 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
name: name,
errorHandling: errorHandling,
}
+ f.Usage = f.defaultUsage
return f
}
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index 4eea48eb6b..a2faecb36e 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -48,13 +48,10 @@
Pointer:
%p base 16 notation, with leading 0x
- There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
- Similarly, there is no need to specify the size of the operand (int8, int64).
-
The default format for %v is:
bool: %t
int, int8 etc.: %d
- uint, uint8 etc.: %d, %x if printed with %#v
+ uint, uint8 etc.: %d, %#x if printed with %#v
float32, complex64, etc: %g
string: %s
chan: %p
@@ -62,7 +59,7 @@
For compound objects, the elements are printed using these rules, recursively,
laid out like this:
struct: {field0 field1 ...}
- array, slice: [elem0 elem1 ...]
+ array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
@@ -95,10 +92,10 @@
For floating-point values, width sets the minimum width of the field and
precision sets the number of places after the decimal, if appropriate,
- except that for %g/%G it sets the total number of digits. For example,
- given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
- The default precision for %e and %f is 6; for %g it is the smallest
- number of digits necessary to identify the value uniquely.
+ except that for %g/%G precision sets the total number of significant
+ digits. For example, given 12.345 the format %6.3f prints 12.345 while
+ %.3g prints 12.3. The default precision for %e and %f is 6; for %g it
+ is the smallest number of digits necessary to identify the value uniquely.
For complex numbers, the width and precision apply to the two
components independently and the result is parenthesized, so %f applied
@@ -177,6 +174,9 @@
that type has a String method. Such pathologies are rare, however,
and the package does not protect against them.
+ When printing a struct, fmt cannot and therefore does not invoke
+ formatting methods such as Error or String on unexported fields.
+
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
@@ -210,7 +210,7 @@
Too many arguments: %!(EXTRA type=value)
Printf("hi", "guys"): hi%!(EXTRA string=guys)
Too few arguments: %!verb(MISSING)
- Printf("hi%d"): hi %!d(MISSING)
+ Printf("hi%d"): hi%!d(MISSING)
Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
@@ -247,31 +247,42 @@
Scanln, Fscanln and Sscanln stop scanning at a newline and
require that the items be followed by a newline or EOF.
- Scanf, Fscanf and Sscanf require that (after skipping spaces)
- newlines in the format are matched by newlines in the input
- and vice versa. This behavior differs from the corresponding
- routines in C, which uniformly treat newlines as spaces.
-
- When scanning with Scanf, Fscanf, and Sscanf, all non-empty
- runs of space characters (except newline) are equivalent
- to a single space in both the format and the input. With
- that proviso, text in the format string must match the input
- text; scanning stops if it does not, with the return value
- of the function indicating the number of arguments scanned.
-
Scanf, Fscanf, and Sscanf parse the arguments according to a
- format string, analogous to that of Printf. For example, %x
- will scan an integer as a hexadecimal number, and %v will scan
- the default representation format for the value.
-
- The formats behave analogously to those of Printf with the
- following exceptions:
-
- %p is not implemented
- %T is not implemented
- %e %E %f %F %g %G are all equivalent and scan any floating point or complex value
- %s and %v on strings scan a space-delimited token
- Flags # and + are not implemented.
+ format string, analogous to that of Printf. In the text that
+ follows, 'space' means any Unicode whitespace character
+ except newline.
+
+ In the format string, a verb introduced by the % character
+ consumes and parses input; these verbs are described in more
+ detail below. A character other than %, space, or newline in
+ the format consumes exactly that input character, which must
+ be present. A newline with zero or more spaces before it in
+ the format string consumes zero or more spaces in the input
+ followed by a single newline or the end of the input. A space
+ following a newline in the format string consumes zero or more
+ spaces in the input. Otherwise, any run of one or more spaces
+ in the format string consumes as many spaces as possible in
+ the input. Unless the run of spaces in the format string
+ appears adjacent to a newline, the run must consume at least
+ one space from the input or find the end of the input.
+
+ The handling of spaces and newlines differs from that of C's
+ scanf family: in C, newlines are treated as any other space,
+ and it is never an error when a run of spaces in the format
+ string finds no spaces to consume in the input.
+
+ The verbs behave analogously to those of Printf.
+ For example, %x will scan an integer as a hexadecimal number,
+ and %v will scan the default representation format for the value.
+ The Printf verbs %p and %T and the flags # and + are not implemented,
+ and the verbs %e %E %f %F %g and %G are all equivalent and scan any
+ floating-point or complex value.
+
+ Input processed by verbs is implicitly space-delimited: the
+ implementation of every verb except %c starts by discarding
+ leading spaces from the remaining input, and the %s verb
+ (and %v reading into a string) stops consuming input at the first
+ space or newline character.
The familiar base-setting prefixes 0 (octal) and 0x
(hexadecimal) are accepted when scanning integers without
@@ -300,6 +311,9 @@
All arguments to be scanned must be either pointers to basic
types or implementations of the Scanner interface.
+ Like Scanf and Fscanf, Sscanf need not consume its entire input.
+ There is no way to recover how much of the input string Sscanf used.
+
Note: Fscan etc. can read one character (rune) past the input
they return, which means that a loop calling a scan routine
may skip some of the input. This is usually a problem only
diff --git a/libgo/go/fmt/export_test.go b/libgo/go/fmt/export_test.go
index 89d57ee6ce..14163a29af 100644
--- a/libgo/go/fmt/export_test.go
+++ b/libgo/go/fmt/export_test.go
@@ -1,7 +1,8 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fmt
var IsSpace = isSpace
+var Parsenum = parsenum
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index ea6392feb6..ce00456c7b 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -48,13 +48,18 @@ func TestFmtInterface(t *testing.T) {
}
}
-const b32 uint32 = 1<<32 - 1
-const b64 uint64 = 1<<64 - 1
+var (
+ NaN = math.NaN()
+ posInf = math.Inf(1)
+ negInf = math.Inf(-1)
-var array = [5]int{1, 2, 3, 4, 5}
-var iarray = [4]interface{}{1, "hello", 2.5, nil}
-var slice = array[:]
-var islice = iarray[:]
+ intVar = 0
+
+ array = [5]int{1, 2, 3, 4, 5}
+ iarray = [4]interface{}{1, "hello", 2.5, nil}
+ slice = array[:]
+ islice = iarray[:]
+)
type A struct {
i int
@@ -112,9 +117,11 @@ var bslice = barray[:]
type byteStringer byte
-func (byteStringer) String() string { return "X" }
+func (byteStringer) String() string {
+ return "X"
+}
-var byteStringerSlice = []byteStringer{97, 98, 99, 100}
+var byteStringerSlice = []byteStringer{'h', 'e', 'l', 'l', 'o'}
type byteFormatter byte
@@ -122,9 +129,7 @@ func (byteFormatter) Format(f State, _ rune) {
Fprint(f, "X")
}
-var byteFormatterSlice = []byteFormatter{97, 98, 99, 100}
-
-var b byte
+var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'}
var fmtTests = []struct {
fmt string
@@ -141,6 +146,10 @@ var fmtTests = []struct {
{"%x", "abc", "616263"},
{"%x", "\xff\xf0\x0f\xff", "fff00fff"},
{"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
+ {"%x", "", ""},
+ {"% x", "", ""},
+ {"%#x", "", ""},
+ {"%# x", "", ""},
{"%x", "xyz", "78797a"},
{"%X", "xyz", "78797A"},
{"% x", "xyz", "78 79 7a"},
@@ -152,10 +161,16 @@ var fmtTests = []struct {
// basic bytes
{"%s", []byte("abc"), "abc"},
+ {"%s", [3]byte{'a', 'b', 'c'}, "abc"},
+ {"%s", &[3]byte{'a', 'b', 'c'}, "&abc"},
{"%q", []byte("abc"), `"abc"`},
{"%x", []byte("abc"), "616263"},
{"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"},
{"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
+ {"%x", []byte(""), ""},
+ {"% x", []byte(""), ""},
+ {"%#x", []byte(""), ""},
+ {"%# x", []byte(""), ""},
{"%x", []byte("xyz"), "78797a"},
{"%X", []byte("xyz"), "78797A"},
{"% x", []byte("xyz"), "78 79 7a"},
@@ -166,29 +181,112 @@ var fmtTests = []struct {
{"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
// escaped strings
- {"%#q", `abc`, "`abc`"},
- {"%#q", `"`, "`\"`"},
- {"1 %#q", `\n`, "1 `\\n`"},
- {"2 %#q", "\n", `2 "\n"`},
- {"%q", `"`, `"\""`},
- {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"%q", "", `""`},
+ {"%#q", "", "``"},
+ {"%q", "\"", `"\""`},
+ {"%#q", "\"", "`\"`"},
+ {"%q", "`", `"` + "`" + `"`},
+ {"%#q", "`", `"` + "`" + `"`},
+ {"%q", "\n", `"\n"`},
+ {"%#q", "\n", `"\n"`},
+ {"%q", `\n`, `"\\n"`},
+ {"%#q", `\n`, "`\\n`"},
+ {"%q", "abc", `"abc"`},
+ {"%#q", "abc", "`abc`"},
+ {"%q", "日本語", `"日本語"`},
+ {"%+q", "日本語", `"\u65e5\u672c\u8a9e"`},
+ {"%#q", "日本語", "`日本語`"},
+ {"%#+q", "日本語", "`日本語`"},
+ {"%q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%#q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%#+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%q", "☺", `"☺"`},
+ {"% q", "☺", `"☺"`}, // The space modifier should have no effect.
+ {"%+q", "☺", `"\u263a"`},
+ {"%#q", "☺", "`☺`"},
+ {"%#+q", "☺", "`☺`"},
+ {"%10q", "⌘", ` "⌘"`},
+ {"%+10q", "⌘", ` "\u2318"`},
+ {"%-10q", "⌘", `"⌘" `},
+ {"%+-10q", "⌘", `"\u2318" `},
+ {"%010q", "⌘", `0000000"⌘"`},
+ {"%+010q", "⌘", `00"\u2318"`},
+ {"%-010q", "⌘", `"⌘" `}, // 0 has no effect when - is present.
+ {"%+-010q", "⌘", `"\u2318" `},
+ {"%#8q", "\n", ` "\n"`},
+ {"%#+8q", "\r", ` "\r"`},
+ {"%#-8q", "\t", "` ` "},
+ {"%#+-8q", "\b", `"\b" `},
{"%q", "abc\xffdef", `"abc\xffdef"`},
- {"%q", "\u263a", `"☺"`},
- {"%+q", "\u263a", `"\u263a"`},
+ {"%+q", "abc\xffdef", `"abc\xffdef"`},
+ {"%#q", "abc\xffdef", `"abc\xffdef"`},
+ {"%#+q", "abc\xffdef", `"abc\xffdef"`},
+ // Runes that are not printable.
{"%q", "\U0010ffff", `"\U0010ffff"`},
+ {"%+q", "\U0010ffff", `"\U0010ffff"`},
+ {"%#q", "\U0010ffff", "`ô¿¿`"},
+ {"%#+q", "\U0010ffff", "`ô¿¿`"},
+ // Runes that are not valid.
+ {"%q", string(0x110000), `"�"`},
+ {"%+q", string(0x110000), `"\ufffd"`},
+ {"%#q", string(0x110000), "`�`"},
+ {"%#+q", string(0x110000), "`�`"},
+
+ // characters
+ {"%c", uint('x'), "x"},
+ {"%c", 0xe4, "ä"},
+ {"%c", 0x672c, "本"},
+ {"%c", 'æ—¥', "æ—¥"},
+ {"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect.
+ {"%3c", '⌘', " ⌘"},
+ {"%-3c", '⌘', "⌘ "},
+ // Runes that are not printable.
+ {"%c", '\U00000e00', "\u0e00"},
+ {"%c", '\U0010ffff', "\U0010ffff"},
+ // Runes that are not valid.
+ {"%c", -1, "�"},
+ {"%c", 0xDC80, "�"},
+ {"%c", rune(0x110000), "�"},
+ {"%c", int64(0xFFFFFFFFF), "�"},
+ {"%c", uint64(0xFFFFFFFFF), "�"},
// escaped characters
- {"%q", 'x', `'x'`},
- {"%q", 0, `'\x00'`},
- {"%q", '\n', `'\n'`},
- {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
- {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
- {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
- {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+ {"%q", uint(0), `'\x00'`},
+ {"%+q", uint(0), `'\x00'`},
{"%q", '"', `'"'`},
+ {"%+q", '"', `'"'`},
{"%q", '\'', `'\''`},
- {"%q", "\u263a", `"☺"`},
- {"%+q", "\u263a", `"\u263a"`},
+ {"%+q", '\'', `'\''`},
+ {"%q", '`', "'`'"},
+ {"%+q", '`', "'`'"},
+ {"%q", 'x', `'x'`},
+ {"%+q", 'x', `'x'`},
+ {"%q", 'ÿ', `'ÿ'`},
+ {"%+q", 'ÿ', `'\u00ff'`},
+ {"%q", '\n', `'\n'`},
+ {"%+q", '\n', `'\n'`},
+ {"%q", '☺', `'☺'`},
+ {"%+q", '☺', `'\u263a'`},
+ {"% q", '☺', `'☺'`}, // The space modifier should have no effect.
+ {"%.0q", '☺', `'☺'`}, // Specifying precision should have no effect.
+ {"%10q", '⌘', ` '⌘'`},
+ {"%+10q", '⌘', ` '\u2318'`},
+ {"%-10q", '⌘', `'⌘' `},
+ {"%+-10q", '⌘', `'\u2318' `},
+ {"%010q", '⌘', `0000000'⌘'`},
+ {"%+010q", '⌘', `00'\u2318'`},
+ {"%-010q", '⌘', `'⌘' `}, // 0 has no effect when - is present.
+ {"%+-010q", '⌘', `'\u2318' `},
+ // Runes that are not printable.
+ {"%q", '\U00000e00', `'\u0e00'`},
+ {"%q", '\U0010ffff', `'\U0010ffff'`},
+ // Runes that are not valid.
+ {"%q", int32(-1), "%!q(int32=-1)"},
+ {"%q", 0xDC80, `'�'`},
+ {"%q", rune(0x110000), "%!q(int32=1114112)"},
+ {"%q", int64(0xFFFFFFFFF), "%!q(int64=68719476735)"},
+ {"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68719476735)"},
// width
{"%5s", "abc", " abc"},
@@ -199,57 +297,99 @@ var fmtTests = []struct {
{"%08q", "abc", `000"abc"`},
{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
+ {"%.0s", "日本語日本語", ""},
{"%.5s", "日本語日本語", "日本語日本"},
+ {"%.10s", "日本語日本語", "日本語日本語"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
- {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
+ {"%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"},
{"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
- {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
+ {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), "6162636465"},
{"%.3q", "日本語日本語", `"日本語"`},
{"%.3q", []byte("日本語日本語"), `"日本語"`},
{"%.1q", "日本語", `"日"`},
{"%.1q", []byte("日本語"), `"日"`},
- {"%.1x", "日本語", `e6`},
- {"%.1X", []byte("日本語"), `E6`},
+ {"%.1x", "日本語", "e6"},
+ {"%.1X", []byte("日本語"), "E6"},
{"%10.1q", "日本語日本語", ` "日"`},
- {"%3c", '⌘', " ⌘"},
- {"%5q", '\u2026', ` '…'`},
{"%10v", nil, " <nil>"},
{"%-10v", nil, "<nil> "},
// integers
- {"%d", 12345, "12345"},
- {"%d", -12345, "-12345"},
+ {"%d", uint(12345), "12345"},
+ {"%d", int(-12345), "-12345"},
+ {"%d", ^uint8(0), "255"},
+ {"%d", ^uint16(0), "65535"},
+ {"%d", ^uint32(0), "4294967295"},
+ {"%d", ^uint64(0), "18446744073709551615"},
+ {"%d", int8(-1 << 7), "-128"},
+ {"%d", int16(-1 << 15), "-32768"},
+ {"%d", int32(-1 << 31), "-2147483648"},
+ {"%d", int64(-1 << 63), "-9223372036854775808"},
+ {"%.d", 0, ""},
+ {"%.0d", 0, ""},
+ {"%6.0d", 0, " "},
+ {"%06.0d", 0, " "},
+ {"% d", 12345, " 12345"},
+ {"%+d", 12345, "+12345"},
+ {"%+d", -12345, "-12345"},
+ {"%b", 7, "111"},
+ {"%b", -6, "-110"},
+ {"%b", ^uint32(0), "11111111111111111111111111111111"},
+ {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"},
+ {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
+ {"%o", 01234, "1234"},
+ {"%#o", 01234, "01234"},
+ {"%o", ^uint32(0), "37777777777"},
+ {"%o", ^uint64(0), "1777777777777777777777"},
+ {"%#X", 0, "0X0"},
+ {"%x", 0x12abcdef, "12abcdef"},
+ {"%X", 0x12abcdef, "12ABCDEF"},
+ {"%x", ^uint32(0), "ffffffff"},
+ {"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"},
+ {"%.20b", 7, "00000000000000000111"},
{"%10d", 12345, " 12345"},
{"%10d", -12345, " -12345"},
{"%+10d", 12345, " +12345"},
{"%010d", 12345, "0000012345"},
{"%010d", -12345, "-000012345"},
- {"%-10d", 12345, "12345 "},
- {"%010.3d", 1, " 001"},
- {"%010.3d", -1, " -001"},
- {"%+d", 12345, "+12345"},
- {"%+d", -12345, "-12345"},
- {"%+d", 0, "+0"},
- {"% d", 0, " 0"},
- {"% d", 12345, " 12345"},
- {"%.0d", 0, ""},
- {"%.d", 0, ""},
+ {"%20.8d", 1234, " 00001234"},
+ {"%20.8d", -1234, " -00001234"},
+ {"%020.8d", 1234, " 00001234"},
+ {"%020.8d", -1234, " -00001234"},
+ {"%-20.8d", 1234, "00001234 "},
+ {"%-20.8d", -1234, "-00001234 "},
+ {"%-#20.8x", 0x1234abc, "0x01234abc "},
+ {"%-#20.8X", 0x1234abc, "0X01234ABC "},
+ {"%-#20.8o", 01234, "00001234 "},
+
+ // Test correct f.intbuf overflow checks.
+ {"%068d", 1, zeroFill("", 68, "1")},
+ {"%068d", -1, zeroFill("-", 67, "1")},
+ {"%#.68x", 42, zeroFill("0x", 68, "2a")},
+ {"%.68d", -42, zeroFill("-", 68, "42")},
+ {"%+.68d", 42, zeroFill("+", 68, "42")},
+ {"% .68d", 42, zeroFill(" ", 68, "42")},
+ {"% +.68d", 42, zeroFill("+", 68, "42")},
// unicode format
- {"%U", 0x1, "U+0001"},
- {"%U", uint(0x1), "U+0001"},
- {"%.8U", 0x2, "U+00000002"},
- {"%U", 0x1234, "U+1234"},
- {"%U", 0x12345, "U+12345"},
- {"%10.6U", 0xABC, " U+000ABC"},
- {"%-10.6U", 0xABC, "U+000ABC "},
+ {"%U", 0, "U+0000"},
+ {"%U", -1, "U+FFFFFFFFFFFFFFFF"},
{"%U", '\n', `U+000A`},
{"%#U", '\n', `U+000A`},
- {"%U", 'x', `U+0078`},
- {"%#U", 'x', `U+0078 'x'`},
+ {"%+U", 'x', `U+0078`}, // Plus flag should have no effect.
+ {"%# U", 'x', `U+0078 'x'`}, // Space flag should have no effect.
+ {"%#.2U", 'x', `U+0078 'x'`}, // Precisions below 4 should print 4 digits.
{"%U", '\u263a', `U+263A`},
{"%#U", '\u263a', `U+263A '☺'`},
+ {"%U", '\U0001D6C2', `U+1D6C2`},
+ {"%#U", '\U0001D6C2', `U+1D6C2 'ð›‚'`},
+ {"%#14.6U", '⌘', " U+002318 '⌘'"},
+ {"%#-14.6U", '⌘', "U+002318 '⌘' "},
+ {"%#014.6U", '⌘', " U+002318 '⌘'"},
+ {"%#-014.6U", '⌘', "U+002318 '⌘' "},
+ {"%.68U", uint(42), zeroFill("U+", 68, "2A")},
+ {"%#.68U", 'æ—¥', zeroFill("U+", 68, "65E5") + " 'æ—¥'"},
// floats
{"%+.3e", 0.0, "+0.000e+00"},
@@ -259,6 +399,12 @@ var fmtTests = []struct {
{"%+.3F", float32(-1.0), "-1.000"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
+ {"%-07.2f", 1.0, "1.00 "},
+ {"%-07.2f", -1.0, "-1.00 "},
+ {"%+-07.2f", 1.0, "+1.00 "},
+ {"%+-07.2f", -1.0, "-1.00 "},
+ {"%-+07.2f", 1.0, "+1.00 "},
+ {"%-+07.2f", -1.0, "-1.00 "},
{"%+10.2f", +1.0, " +1.00"},
{"%+10.2f", -1.0, " -1.00"},
{"% .3E", -1.0, "-1.000E+00"},
@@ -270,8 +416,36 @@ var fmtTests = []struct {
{"% .3g", 1.0, " 1"},
{"%b", float32(1.0), "8388608p-23"},
{"%b", 1.0, "4503599627370496p-52"},
+ // Precision has no effect for binary float format.
+ {"%.4b", float32(1.0), "8388608p-23"},
+ {"%.4b", -1.0, "-4503599627370496p-52"},
+ // Test correct f.intbuf boundary checks.
+ {"%.68f", 1.0, zeroFill("1.", 68, "")},
+ {"%.68f", -1.0, zeroFill("-1.", 68, "")},
+ // float infinites and NaNs
+ {"%f", posInf, "+Inf"},
+ {"%.1f", negInf, "-Inf"},
+ {"% f", NaN, " NaN"},
+ {"%20f", posInf, " +Inf"},
+ {"% 20F", posInf, " Inf"},
+ {"% 20e", negInf, " -Inf"},
+ {"%+20E", negInf, " -Inf"},
+ {"% +20g", negInf, " -Inf"},
+ {"%+-20G", posInf, "+Inf "},
+ {"%20e", NaN, " NaN"},
+ {"% +20E", NaN, " +NaN"},
+ {"% -20g", NaN, " NaN "},
+ {"%+-20G", NaN, "+NaN "},
+ // Zero padding does not apply to infinities and NaN.
+ {"%+020e", posInf, " +Inf"},
+ {"%-020f", negInf, "-Inf "},
+ {"%-020E", NaN, "NaN "},
// complex values
+ {"%.f", 0i, "(0+0i)"},
+ {"% .f", 0i, "( 0+0i)"},
+ {"%+.f", 0i, "(+0+0i)"},
+ {"% +.f", 0i, "(+0+0i)"},
{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
{"%+.3f", 0i, "(+0.000+0.000i)"},
{"%+.3g", 0i, "(+0+0i)"},
@@ -290,35 +464,33 @@ var fmtTests = []struct {
{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
{"%.3g", -1 - 2i, "(-1-2i)"},
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+ {"%+.3g", 1 + 2i, "(+1+2i)"},
{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
- {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
- {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
-
- // erroneous formats
- {"", 2, "%!(EXTRA int=2)"},
- {"%d", "hello", "%!d(string=hello)"},
+ {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+ // Precision has no effect for binary complex format.
+ {"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
+ {"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+ // complex infinites and NaNs
+ {"%f", complex(posInf, posInf), "(+Inf+Infi)"},
+ {"%f", complex(negInf, negInf), "(-Inf-Infi)"},
+ {"%f", complex(NaN, NaN), "(NaN+NaNi)"},
+ {"%.1f", complex(posInf, posInf), "(+Inf+Infi)"},
+ {"% f", complex(posInf, posInf), "( Inf+Infi)"},
+ {"% f", complex(negInf, negInf), "(-Inf-Infi)"},
+ {"% f", complex(NaN, NaN), "( NaN+NaNi)"},
+ {"%8e", complex(posInf, posInf), "( +Inf +Infi)"},
+ {"% 8E", complex(posInf, posInf), "( Inf +Infi)"},
+ {"%+8f", complex(negInf, negInf), "( -Inf -Infi)"},
+ {"% +8g", complex(negInf, negInf), "( -Inf -Infi)"},
+ {"% -8G", complex(NaN, NaN), "( NaN +NaN i)"},
+ {"%+-8b", complex(NaN, NaN), "(+NaN +NaN i)"},
+ // Zero padding does not apply to infinities and NaN.
+ {"%08f", complex(posInf, posInf), "( +Inf +Infi)"},
+ {"%-08g", complex(negInf, negInf), "(-Inf -Inf i)"},
+ {"%-08G", complex(NaN, NaN), "(NaN +NaN i)"},
// old test/fmt_test.go
- {"%d", 1234, "1234"},
- {"%d", -1234, "-1234"},
- {"%d", uint(1234), "1234"},
- {"%d", uint32(b32), "4294967295"},
- {"%d", uint64(b64), "18446744073709551615"},
- {"%o", 01234, "1234"},
- {"%#o", 01234, "01234"},
- {"%o", uint32(b32), "37777777777"},
- {"%o", uint64(b64), "1777777777777777777777"},
- {"%x", 0x1234abcd, "1234abcd"},
- {"%#x", 0x1234abcd, "0x1234abcd"},
- {"%x", b32 - 0x1234567, "fedcba98"},
- {"%X", 0x1234abcd, "1234ABCD"},
- {"%X", b32 - 0x1234567, "FEDCBA98"},
- {"%#X", 0, "0X0"},
- {"%x", b64, "ffffffffffffffff"},
- {"%b", 7, "111"},
- {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
- {"%b", -6, "-110"},
{"%e", 1.0, "1.000000e+00"},
{"%e", 1234.5678e3, "1.234568e+06"},
{"%e", 1234.5678e-8, "1.234568e-05"},
@@ -345,19 +517,6 @@ var fmtTests = []struct {
{"%G", -7.0, "-7"},
{"%G", -1e-9, "-1E-09"},
{"%G", float32(-1e-9), "-1E-09"},
- {"%c", 'x', "x"},
- {"%c", 0xe4, "ä"},
- {"%c", 0x672c, "本"},
- {"%c", 'æ—¥', "æ—¥"},
- {"%20.8d", 1234, " 00001234"},
- {"%20.8d", -1234, " -00001234"},
- {"%20d", 1234, " 1234"},
- {"%-20.8d", 1234, "00001234 "},
- {"%-20.8d", -1234, "-00001234 "},
- {"%-#20.8x", 0x1234abc, "0x01234abc "},
- {"%-#20.8X", 0x1234abc, "0X01234ABC "},
- {"%-#20.8o", 01234, "00001234 "},
- {"%.20b", 7, "00000000000000000111"},
{"%20.5s", "qwertyuiop", " qwert"},
{"%.5s", "qwertyuiop", "qwert"},
{"%-20.5s", "qwertyuiop", "qwert "},
@@ -377,9 +536,6 @@ var fmtTests = []struct {
{"%g", 1.23456789e3, "1234.56789"},
{"%g", 1.23456789e-3, "0.00123456789"},
{"%g", 1.23456789e20, "1.23456789e+20"},
- {"%20e", math.Inf(1), " +Inf"},
- {"%-20f", math.Inf(-1), "-Inf "},
- {"%20g", math.NaN(), " NaN"},
// arrays
{"%v", array, "[1 2 3 4 5]"},
@@ -396,13 +552,44 @@ var fmtTests = []struct {
{"%v", &slice, "&[1 2 3 4 5]"},
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
{"%v", &bslice, "&[1 2 3 4 5]"},
- {"%v", []byte{1}, "[1]"},
- {"%v", []byte{}, "[]"},
+
+ // byte arrays and slices with %b,%c,%d,%o,%U and %v
+ {"%b", [3]byte{65, 66, 67}, "[1000001 1000010 1000011]"},
+ {"%c", [3]byte{65, 66, 67}, "[A B C]"},
+ {"%d", [3]byte{65, 66, 67}, "[65 66 67]"},
+ {"%o", [3]byte{65, 66, 67}, "[101 102 103]"},
+ {"%U", [3]byte{65, 66, 67}, "[U+0041 U+0042 U+0043]"},
+ {"%v", [3]byte{65, 66, 67}, "[65 66 67]"},
+ {"%v", [1]byte{123}, "[123]"},
+ {"%012v", []byte{}, "[]"},
+ {"%#012v", []byte{}, "[]byte{}"},
+ {"%6v", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"},
+ {"%-6v", []byte{1, 11, 111}, "[1 11 111 ]"},
+ {"%-06v", []byte{1, 11, 111}, "[1 11 111 ]"},
+ {"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"},
+ {"%#6v", []byte{1, 11, 111}, "[]byte{ 0x1, 0xb, 0x6f}"},
+ {"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"},
+ {"%#-6v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
+ {"%#-06v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
+ // f.space should and f.plus should not have an effect with %v.
+ {"% v", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%+v", [3]byte{1, 11, 111}, "[1 11 111]"},
+ {"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1 , 0xb , 0x6f }"},
+ {"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"},
+ // f.space and f.plus should have an effect with %d.
+ {"% d", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"},
+ {"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"},
+ {"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"},
+
+ // floates with %v
+ {"%v", 1.2345678, "1.2345678"},
+ {"%v", float32(1.2345678), "1.2345678"},
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
{"%v", complex64(1 + 2i), "(1+2i)"},
- {"%v", complex128(1 + 2i), "(1+2i)"},
// structs
{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
@@ -418,11 +605,14 @@ var fmtTests = []struct {
{"%x", I(23), `3c32333e`},
{"%#x", I(23), `0x3c32333e`},
{"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
- {"%d", I(23), `23`}, // Stringer applies only to string formats.
+ // Stringer applies only to string formats.
+ {"%d", I(23), `23`},
+ // Stringer applies to the extracted value.
+ {"%s", reflect.ValueOf(I(23)), `<23>`},
// go syntax
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
- {"%#v", &b, "(*uint8)(0xPTR)"},
+ {"%#v", new(byte), "(*uint8)(0xPTR)"},
{"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
{"%#v", make(chan int), "(chan int)(0xPTR)"},
{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
@@ -442,8 +632,20 @@ var fmtTests = []struct {
{"%#v", "foo", `"foo"`},
{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
- {"%#v", []byte(nil), "[]byte(nil)"},
{"%#v", []int32(nil), "[]int32(nil)"},
+ {"%#v", 1.2345678, "1.2345678"},
+ {"%#v", float32(1.2345678), "1.2345678"},
+ // Only print []byte and []uint8 as type []byte if they appear at the top level.
+ {"%#v", []byte(nil), "[]byte(nil)"},
+ {"%#v", []uint8(nil), "[]byte(nil)"},
+ {"%#v", []byte{}, "[]byte{}"},
+ {"%#v", []uint8{}, "[]byte{}"},
+ {"%#v", reflect.ValueOf([]byte{}), "[]uint8{}"},
+ {"%#v", reflect.ValueOf([]uint8{}), "[]uint8{}"},
+ {"%#v", &[]byte{}, "&[]uint8{}"},
+ {"%#v", &[]byte{}, "&[]uint8{}"},
+ {"%#v", [3]byte{}, "[3]uint8{0x0, 0x0, 0x0}"},
+ {"%#v", [3]uint8{}, "[3]uint8{0x0, 0x0, 0x0}"},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -453,30 +655,61 @@ var fmtTests = []struct {
{"%q", []string{"a", "b"}, `["a" "b"]`},
{"% 02x", []byte{1}, "01"},
{"% 02x", []byte{1, 2, 3}, "01 02 03"},
+
// Padding with byte slices.
- {"%x", []byte{}, ""},
- {"%02x", []byte{}, "00"},
+ {"%2x", []byte{}, " "},
+ {"%#2x", []byte{}, " "},
{"% 02x", []byte{}, "00"},
- {"%08x", []byte{0xab}, "000000ab"},
- {"% 08x", []byte{0xab}, "000000ab"},
- {"%08x", []byte{0xab, 0xcd}, "0000abcd"},
- {"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
+ {"%# 02x", []byte{}, "00"},
+ {"%-2x", []byte{}, " "},
+ {"%-02x", []byte{}, " "},
{"%8x", []byte{0xab}, " ab"},
{"% 8x", []byte{0xab}, " ab"},
- {"%8x", []byte{0xab, 0xcd}, " abcd"},
- {"% 8x", []byte{0xab, 0xcd}, " ab cd"},
+ {"%#8x", []byte{0xab}, " 0xab"},
+ {"%# 8x", []byte{0xab}, " 0xab"},
+ {"%08x", []byte{0xab}, "000000ab"},
+ {"% 08x", []byte{0xab}, "000000ab"},
+ {"%#08x", []byte{0xab}, "00000xab"},
+ {"%# 08x", []byte{0xab}, "00000xab"},
+ {"%10x", []byte{0xab, 0xcd}, " abcd"},
+ {"% 10x", []byte{0xab, 0xcd}, " ab cd"},
+ {"%#10x", []byte{0xab, 0xcd}, " 0xabcd"},
+ {"%# 10x", []byte{0xab, 0xcd}, " 0xab 0xcd"},
+ {"%010x", []byte{0xab, 0xcd}, "000000abcd"},
+ {"% 010x", []byte{0xab, 0xcd}, "00000ab cd"},
+ {"%#010x", []byte{0xab, 0xcd}, "00000xabcd"},
+ {"%# 010x", []byte{0xab, 0xcd}, "00xab 0xcd"},
+ {"%-10X", []byte{0xab}, "AB "},
+ {"% -010X", []byte{0xab}, "AB "},
+ {"%#-10X", []byte{0xab, 0xcd}, "0XABCD "},
+ {"%# -010X", []byte{0xab, 0xcd}, "0XAB 0XCD "},
// Same for strings
- {"%x", "", ""},
- {"%02x", "", "00"},
+ {"%2x", "", " "},
+ {"%#2x", "", " "},
{"% 02x", "", "00"},
- {"%08x", "\xab", "000000ab"},
- {"% 08x", "\xab", "000000ab"},
- {"%08x", "\xab\xcd", "0000abcd"},
- {"% 08x", "\xab\xcd", "000ab cd"},
+ {"%# 02x", "", "00"},
+ {"%-2x", "", " "},
+ {"%-02x", "", " "},
{"%8x", "\xab", " ab"},
{"% 8x", "\xab", " ab"},
- {"%8x", "\xab\xcd", " abcd"},
- {"% 8x", "\xab\xcd", " ab cd"},
+ {"%#8x", "\xab", " 0xab"},
+ {"%# 8x", "\xab", " 0xab"},
+ {"%08x", "\xab", "000000ab"},
+ {"% 08x", "\xab", "000000ab"},
+ {"%#08x", "\xab", "00000xab"},
+ {"%# 08x", "\xab", "00000xab"},
+ {"%10x", "\xab\xcd", " abcd"},
+ {"% 10x", "\xab\xcd", " ab cd"},
+ {"%#10x", "\xab\xcd", " 0xabcd"},
+ {"%# 10x", "\xab\xcd", " 0xab 0xcd"},
+ {"%010x", "\xab\xcd", "000000abcd"},
+ {"% 010x", "\xab\xcd", "00000ab cd"},
+ {"%#010x", "\xab\xcd", "00000xabcd"},
+ {"%# 010x", "\xab\xcd", "00xab 0xcd"},
+ {"%-10X", "\xab", "AB "},
+ {"% -010X", "\xab", "AB "},
+ {"%#-10X", "\xab\xcd", "0XABCD "},
+ {"%# -010X", "\xab\xcd", "0XAB 0XCD "},
// renamings
{"%v", renamedBool(true), "true"},
@@ -495,7 +728,8 @@ var fmtTests = []struct {
{"%x", renamedString("thing"), "7468696e67"},
{"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
{"%q", renamedBytes([]byte("hello")), `"hello"`},
- {"%x", []renamedUint8{'a', 'b', 'c'}, "616263"},
+ {"%x", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656c6c6f"},
+ {"%X", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656C6C6F"},
{"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"},
{"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`},
{"%v", renamedFloat32(22), "22"},
@@ -513,79 +747,72 @@ var fmtTests = []struct {
{"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
// %T
+ {"%T", byte(0), "uint8"},
+ {"%T", reflect.ValueOf(nil), "reflect.Value"},
{"%T", (4 - 3i), "complex128"},
{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
- {"%T", intVal, "int"},
- {"%6T", &intVal, " *int"},
+ {"%T", intVar, "int"},
+ {"%6T", &intVar, " *int"},
{"%10T", nil, " <nil>"},
{"%-10T", nil, "<nil> "},
- // %p
- {"p0=%p", new(int), "p0=0xPTR"},
- {"p1=%s", &pValue, "p1=String(p)"}, // String method...
- {"p2=%p", &pValue, "p2=0xPTR"}, // ... not called with %p
- {"p3=%p", (*int)(nil), "p3=0x0"},
- {"p4=%#p", new(int), "p4=PTR"},
-
+ // %p with pointers
+ {"%p", (*int)(nil), "0x0"},
+ {"%#p", (*int)(nil), "0"},
+ {"%p", &intVar, "0xPTR"},
+ {"%#p", &intVar, "PTR"},
+ {"%p", &array, "0xPTR"},
+ {"%p", &slice, "0xPTR"},
+ {"%8.2p", (*int)(nil), " 0x00"},
+ {"%-20.16p", &intVar, "0xPTR "},
// %p on non-pointers
{"%p", make(chan int), "0xPTR"},
{"%p", make(map[int]int), "0xPTR"},
- {"%p", make([]int, 1), "0xPTR"},
- {"%p", 27, "%!p(int=27)"}, // not a pointer at all
-
- // %q on pointers
- {"%q", (*int)(nil), "%!q(*int=<nil>)"},
- {"%q", new(int), "%!q(*int=0xPTR)"},
-
- // %v on pointers formats 0 as <nil>
+ {"%p", func() {}, "0xPTR"},
+ {"%p", 27, "%!p(int=27)"}, // not a pointer at all
+ {"%p", nil, "%!p(<nil>)"}, // nil on its own has no type ...
+ {"%#p", nil, "%!p(<nil>)"}, // ... and hence is not a pointer type.
+ // pointers with specified base
+ {"%b", &intVar, "PTR_b"},
+ {"%d", &intVar, "PTR_d"},
+ {"%o", &intVar, "PTR_o"},
+ {"%x", &intVar, "PTR_x"},
+ {"%X", &intVar, "PTR_X"},
+ // %v on pointers
+ {"%v", nil, "<nil>"},
+ {"%#v", nil, "<nil>"},
{"%v", (*int)(nil), "<nil>"},
- {"%v", new(int), "0xPTR"},
-
- // %d etc. pointers use specified base.
- {"%d", new(int), "PTR_d"},
- {"%o", new(int), "PTR_o"},
- {"%x", new(int), "PTR_x"},
+ {"%#v", (*int)(nil), "(*int)(nil)"},
+ {"%v", &intVar, "0xPTR"},
+ {"%#v", &intVar, "(*int)(0xPTR)"},
+ {"%8.2v", (*int)(nil), " <nil>"},
+ {"%-20.16v", &intVar, "0xPTR "},
+ // string method on pointer
+ {"%s", &pValue, "String(p)"}, // String method...
+ {"%p", &pValue, "0xPTR"}, // ... is not called with %p.
// %d on Stringer should give integer if possible
{"%s", time.Time{}.Month(), "January"},
{"%d", time.Time{}.Month(), "1"},
// erroneous things
+ {"", nil, "%!(EXTRA <nil>)"},
+ {"", 2, "%!(EXTRA int=2)"},
+ {"no args", "hello", "no args%!(EXTRA string=hello)"},
{"%s %", "hello", "hello %!(NOVERB)"},
{"%s %.2", "hello", "hello %!(NOVERB)"},
- {"%d", "hello", "%!d(string=hello)"},
- {"no args", "hello", "no args%!(EXTRA string=hello)"},
- {"%s", nil, "%!s(<nil>)"},
- {"%T", nil, "<nil>"},
- {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
+ // Extra argument errors should format without flags set.
+ {"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"},
// The "<nil>" show up because maps are printed by
// first obtaining a list of keys and then looking up
- // each key. Since NaNs can be map keys but cannot
+ // each key. Since NaNs can be map keys but cannot
// be fetched directly, the lookup fails and returns a
// zero reflect.Value, which formats as <nil>.
// This test is just to check that it shows the two NaNs at all.
- {"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
-
- // Used to crash because nByte didn't allow for a sign.
- {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
-
- // Used to panic.
- {"%0100d", 1, zeroFill("", 100, "1")},
- {"%0100d", -1, zeroFill("-", 99, "1")},
- {"%0.100f", 1.0, zeroFill("1.", 100, "")},
- {"%0.100f", -1.0, zeroFill("-1.", 100, "")},
-
- // Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign.
- {"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
- {"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
- {"%#.80U", 'æ—¥', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 'æ—¥'"},
- {"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"},
- {"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
- {"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
- {"% +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+ {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN:<nil> NaN:<nil>]"},
// Comparison of padding rules with C printf.
/*
@@ -599,14 +826,16 @@ var fmtTests = []struct {
"[%7.2f]",
"[% 7.2f]",
"[%+7.2f]",
+ "[% +7.2f]",
"[%07.2f]",
"[% 07.2f]",
"[%+07.2f]",
+ "[% +07.2f]"
};
int main(void) {
int i;
- for(i = 0; i < 9; i++) {
+ for(i = 0; i < 11; i++) {
printf("%s: ", format[i]);
printf(format[i], 1.0);
printf(" ");
@@ -622,9 +851,12 @@ var fmtTests = []struct {
[%7.2f]: [ 1.00] [ -1.00]
[% 7.2f]: [ 1.00] [ -1.00]
[%+7.2f]: [ +1.00] [ -1.00]
+ [% +7.2f]: [ +1.00] [ -1.00]
[%07.2f]: [0001.00] [-001.00]
[% 07.2f]: [ 001.00] [-001.00]
[%+07.2f]: [+001.00] [-001.00]
+ [% +07.2f]: [+001.00] [-001.00]
+
*/
{"%.2f", 1.0, "1.00"},
{"%.2f", -1.0, "-1.00"},
@@ -638,26 +870,35 @@ var fmtTests = []struct {
{"% 7.2f", -1.0, " -1.00"},
{"%+7.2f", 1.0, " +1.00"},
{"%+7.2f", -1.0, " -1.00"},
+ {"% +7.2f", 1.0, " +1.00"},
+ {"% +7.2f", -1.0, " -1.00"},
{"%07.2f", 1.0, "0001.00"},
{"%07.2f", -1.0, "-001.00"},
{"% 07.2f", 1.0, " 001.00"},
{"% 07.2f", -1.0, "-001.00"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
+ {"% +07.2f", 1.0, "+001.00"},
+ {"% +07.2f", -1.0, "-001.00"},
// Complex numbers: exhaustively tested in TestComplexFormatting.
{"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
- // Zero padding does not apply to infinities.
- {"%020f", math.Inf(-1), " -Inf"},
- {"%020f", math.Inf(+1), " +Inf"},
- {"% 020f", math.Inf(-1), " -Inf"},
- {"% 020f", math.Inf(+1), " Inf"},
- {"%+020f", math.Inf(-1), " -Inf"},
- {"%+020f", math.Inf(+1), " +Inf"},
- {"%20f", -1.0, " -1.000000"},
- // Make sure we can handle very large widths.
- {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
+
+ // Use spaces instead of zero if padding to the right.
+ {"%0-5s", "abc", "abc "},
+ {"%-05.1f", 1.0, "1.0 "},
+
+ // float and complex formatting should not change the padding width
+ // for other elements. See issue 14642.
+ {"%06v", []interface{}{+10.0, 10}, "[000010 000010]"},
+ {"%06v", []interface{}{-10.0, 10}, "[-00010 000010]"},
+ {"%06v", []interface{}{+10.0 + 10i, 10}, "[(000010+00010i) 000010]"},
+ {"%06v", []interface{}{-10.0 + 10i, 10}, "[(-00010+00010i) 000010]"},
+
+ // integer formatting should not alter padding for other elements.
+ {"%03.6v", []interface{}{1, 2.0, "x"}, "[000001 002 00x]"},
+ {"%03.0v", []interface{}{0, 2.0, "x"}, "[ 002 000]"},
// Complex fmt used to leave the plus flag set for future entries in the array
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -667,27 +908,6 @@ var fmtTests = []struct {
// Incomplete format specification caused crash.
{"%.", 3, "%!.(int=3)"},
- // Used to panic with out-of-bounds for very large numeric representations.
- // nByte is set to handle one bit per uint64 in %b format, with a negative number.
- // See issue 6777.
- {"%#064x", 1, zeroFill("0x", 64, "1")},
- {"%#064x", -1, zeroFill("-0x", 63, "1")},
- {"%#064b", 1, zeroFill("", 64, "1")},
- {"%#064b", -1, zeroFill("-", 63, "1")},
- {"%#064o", 1, zeroFill("", 64, "1")},
- {"%#064o", -1, zeroFill("-", 63, "1")},
- {"%#064d", 1, zeroFill("", 64, "1")},
- {"%#064d", -1, zeroFill("-", 63, "1")},
- // Test that we handle the crossover above the size of uint64
- {"%#072x", 1, zeroFill("0x", 72, "1")},
- {"%#072x", -1, zeroFill("-0x", 71, "1")},
- {"%#072b", 1, zeroFill("", 72, "1")},
- {"%#072b", -1, zeroFill("-", 71, "1")},
- {"%#072o", 1, zeroFill("", 72, "1")},
- {"%#072o", -1, zeroFill("-", 71, "1")},
- {"%#072d", 1, zeroFill("", 72, "1")},
- {"%#072d", -1, zeroFill("-", 71, "1")},
-
// Padding for complex numbers. Has been bad, then fixed, then bad again.
{"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
{"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
@@ -699,19 +919,21 @@ var fmtTests = []struct {
{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
// []T where type T is a byte with a Stringer method.
- {"%v", byteStringerSlice, "[X X X X]"},
- {"%s", byteStringerSlice, "abcd"},
- {"%q", byteStringerSlice, "\"abcd\""},
- {"%x", byteStringerSlice, "61626364"},
- {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"},
+ {"%v", byteStringerSlice, "[X X X X X]"},
+ {"%s", byteStringerSlice, "hello"},
+ {"%q", byteStringerSlice, "\"hello\""},
+ {"%x", byteStringerSlice, "68656c6c6f"},
+ {"%X", byteStringerSlice, "68656C6C6F"},
+ {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"},
// And the same for Formatter.
- {"%v", byteFormatterSlice, "[X X X X]"},
- {"%s", byteFormatterSlice, "abcd"},
- {"%q", byteFormatterSlice, "\"abcd\""},
- {"%x", byteFormatterSlice, "61626364"},
+ {"%v", byteFormatterSlice, "[X X X X X]"},
+ {"%s", byteFormatterSlice, "hello"},
+ {"%q", byteFormatterSlice, "\"hello\""},
+ {"%x", byteFormatterSlice, "68656c6c6f"},
+ {"%X", byteFormatterSlice, "68656C6C6F"},
// This next case seems wrong, but the docs say the Formatter wins here.
- {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+ {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X, X}"},
// reflect.Value handled specially in Go 1.5, making it possible to
// see inside non-exported fields (which cannot be accessed with Interface()).
@@ -726,6 +948,32 @@ var fmtTests = []struct {
// invalid reflect.Value doesn't crash.
{"%v", reflect.Value{}, "<invalid reflect.Value>"},
+ {"%v", &reflect.Value{}, "<invalid Value>"},
+ {"%v", SI{reflect.Value{}}, "{<invalid Value>}"},
+
+ // Tests to check that not supported verbs generate an error string.
+ {"%☠", nil, "%!☠(<nil>)"},
+ {"%☠", interface{}(nil), "%!☠(<nil>)"},
+ {"%☠", int(0), "%!☠(int=0)"},
+ {"%☠", uint(0), "%!☠(uint=0)"},
+ {"%☠", []byte{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+ {"%☠", []uint8{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+ {"%☠", [1]byte{0}, "[%!☠(uint8=0)]"},
+ {"%☠", [1]uint8{0}, "[%!☠(uint8=0)]"},
+ {"%☠", "hello", "%!☠(string=hello)"},
+ {"%☠", 1.2345678, "%!☠(float64=1.2345678)"},
+ {"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"},
+ {"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"},
+ {"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"},
+ {"%☠", &intVar, "%!☠(*int=0xPTR)"},
+ {"%☠", make(chan int), "%!☠(chan int=0xPTR)"},
+ {"%☠", func() {}, "%!☠(func()=0xPTR)"},
+ {"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(fmt_test.renamedInt=0)"},
+ {"%☠", SI{renamedInt(0)}, "{%!☠(fmt_test.renamedInt=0)}"},
+ {"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(fmt_test.I=1) %!☠(fmt_test.G=2)]"},
+ {"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"},
+ {"%☠", reflect.Value{}, "<invalid reflect.Value>"},
+ {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(<nil>)]"},
}
// zeroFill generates zero-filled strings of the specified width. The length
@@ -737,27 +985,37 @@ func zeroFill(prefix string, width int, suffix string) string {
func TestSprintf(t *testing.T) {
for _, tt := range fmtTests {
s := Sprintf(tt.fmt, tt.val)
- if i := strings.Index(tt.out, "PTR"); i >= 0 {
- pattern := "PTR"
- chars := "0123456789abcdefABCDEF"
+ i := strings.Index(tt.out, "PTR")
+ if i >= 0 && i < len(s) {
+ var pattern, chars string
switch {
- case strings.HasPrefix(tt.out[i:], "PTR_d"):
- pattern = "PTR_d"
- chars = chars[:10]
+ case strings.HasPrefix(tt.out[i:], "PTR_b"):
+ pattern = "PTR_b"
+ chars = "01"
case strings.HasPrefix(tt.out[i:], "PTR_o"):
pattern = "PTR_o"
- chars = chars[:8]
+ chars = "01234567"
+ case strings.HasPrefix(tt.out[i:], "PTR_d"):
+ pattern = "PTR_d"
+ chars = "0123456789"
case strings.HasPrefix(tt.out[i:], "PTR_x"):
pattern = "PTR_x"
+ chars = "0123456789abcdef"
+ case strings.HasPrefix(tt.out[i:], "PTR_X"):
+ pattern = "PTR_X"
+ chars = "0123456789ABCDEF"
+ default:
+ pattern = "PTR"
+ chars = "0123456789abcdefABCDEF"
}
- j := i
- for ; j < len(s); j++ {
- c := s[j]
- if !strings.ContainsRune(chars, rune(c)) {
+ p := s[:i] + pattern
+ for j := i; j < len(s); j++ {
+ if !strings.ContainsRune(chars, rune(s[j])) {
+ p += s[j:]
break
}
}
- s = s[0:i] + pattern + s[j:]
+ s = p
}
if s != tt.out {
if _, ok := tt.val.(string); ok {
@@ -775,7 +1033,7 @@ func TestSprintf(t *testing.T) {
// thing as if done by hand with two singleton prints.
func TestComplexFormatting(t *testing.T) {
var yesNo = []bool{true, false}
- var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
+ var values = []float64{1, 0, -1, posInf, negInf, NaN}
for _, plus := range yesNo {
for _, zero := range yesNo {
for _, space := range yesNo {
@@ -869,6 +1127,14 @@ func TestReorder(t *testing.T) {
}
}
+func BenchmarkSprintfPadding(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%16f", 1.0)
+ }
+ })
+}
+
func BenchmarkSprintfEmpty(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
@@ -885,6 +1151,22 @@ func BenchmarkSprintfString(b *testing.B) {
})
}
+func BenchmarkSprintfTruncateString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%.3s", "日本語日本語日本語")
+ }
+ })
+}
+
+func BenchmarkSprintfQuoteString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%q", "日本語日本語日本語")
+ }
+ })
+}
+
func BenchmarkSprintfInt(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
@@ -917,6 +1199,66 @@ func BenchmarkSprintfFloat(b *testing.B) {
})
}
+func BenchmarkSprintfComplex(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%f", 5.23184+5.23184i)
+ }
+ })
+}
+
+func BenchmarkSprintfBoolean(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%t", true)
+ }
+ })
+}
+
+func BenchmarkSprintfHexString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("% #x", "0123456789abcdef")
+ }
+ })
+}
+
+func BenchmarkSprintfHexBytes(b *testing.B) {
+ data := []byte("0123456789abcdef")
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("% #x", data)
+ }
+ })
+}
+
+func BenchmarkSprintfBytes(b *testing.B) {
+ data := []byte("0123456789abcdef")
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%v", data)
+ }
+ })
+}
+
+func BenchmarkSprintfStringer(b *testing.B) {
+ stringer := I(12345)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%v", stringer)
+ }
+ })
+}
+
+func BenchmarkSprintfStructure(b *testing.B) {
+ s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}}
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%#v", s)
+ }
+ })
+}
+
func BenchmarkManyArgs(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var buf bytes.Buffer
@@ -1221,18 +1563,23 @@ func TestWidthAndPrecision(t *testing.T) {
}
}
-// Panic is a type that panics in String.
-type Panic struct {
+// PanicS is a type that panics in String.
+type PanicS struct {
message interface{}
}
// Value receiver.
-func (p Panic) GoString() string {
+func (p PanicS) String() string {
panic(p.message)
}
+// PanicGo is a type that panics in GoString.
+type PanicGo struct {
+ message interface{}
+}
+
// Value receiver.
-func (p Panic) String() string {
+func (p PanicGo) GoString() string {
panic(p.message)
}
@@ -1252,13 +1599,15 @@ var panictests = []struct {
out string
}{
// String
- {"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case
- {"%s", Panic{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
- {"%s", Panic{3}, "%!s(PANIC=3)"},
+ {"%s", (*PanicS)(nil), "<nil>"}, // nil pointer special case
+ {"%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
+ {"%s", PanicS{3}, "%!s(PANIC=3)"},
// GoString
- {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
- {"%#v", Panic{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
- {"%#v", Panic{3}, "%!v(PANIC=3)"},
+ {"%#v", (*PanicGo)(nil), "<nil>"}, // nil pointer special case
+ {"%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
+ {"%#v", PanicGo{3}, "%!v(PANIC=3)"},
+ // Issue 18282. catchPanic should not clear fmtFlags permanently.
+ {"%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!v(PANIC=3), %!v(PANIC=3)}"},
// Format
{"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
{"%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
@@ -1400,3 +1749,26 @@ func TestFormatterFlags(t *testing.T) {
}
}
}
+
+func TestParsenum(t *testing.T) {
+ testCases := []struct {
+ s string
+ start, end int
+ num int
+ isnum bool
+ newi int
+ }{
+ {"a123", 0, 4, 0, false, 0},
+ {"1234", 1, 1, 0, false, 1},
+ {"123a", 0, 4, 123, true, 3},
+ {"12a3", 0, 4, 12, true, 2},
+ {"1234", 0, 4, 1234, true, 4},
+ {"1a234", 1, 3, 0, false, 1},
+ }
+ for _, tt := range testCases {
+ num, isnum, newi := Parsenum(tt.s, tt.start, tt.end)
+ if num != tt.num || isnum != tt.isnum || newi != tt.newi {
+ t.Errorf("parsenum(%q, %d, %d) = %d, %v, %d, want %d, %v, %d", tt.s, tt.start, tt.end, num, isnum, newi, tt.num, tt.isnum, tt.newi)
+ }
+ }
+}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index 517b18f7d4..f77048338a 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -5,18 +5,13 @@
package fmt
import (
- "math"
"strconv"
"unicode/utf8"
)
const (
- // %b of an int64, plus a sign.
- // Hex can add 0x and we handle it specially.
- nByte = 65
-
- ldigits = "0123456789abcdef"
- udigits = "0123456789ABCDEF"
+ ldigits = "0123456789abcdefx"
+ udigits = "0123456789ABCDEFX"
)
const (
@@ -24,16 +19,6 @@ const (
unsigned = false
)
-var padZeroBytes = make([]byte, nByte)
-var padSpaceBytes = make([]byte, nByte)
-
-func init() {
- for i := 0; i < nByte; i++ {
- padZeroBytes[i] = '0'
- padSpaceBytes[i] = ' '
- }
-}
-
// flags placed in a separate struct for easy clearing.
type fmtFlags struct {
widPresent bool
@@ -42,8 +27,6 @@ type fmtFlags struct {
plus bool
sharp bool
space bool
- unicode bool
- uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
@@ -56,12 +39,16 @@ type fmtFlags struct {
// A fmt is the raw formatter used by Printf etc.
// It prints into a buffer that must be set up separately.
type fmt struct {
- intbuf [nByte]byte
- buf *buffer
- // width, precision
- wid int
- prec int
+ buf *buffer
+
fmtFlags
+
+ wid int // width
+ prec int // precision
+
+ // intbuf is large enough to store %b of an int64 with a sign and
+ // avoids padding at the end of the struct on 32 bit architectures.
+ intbuf [68]byte
}
func (f *fmt) clearflags() {
@@ -73,176 +60,213 @@ func (f *fmt) init(buf *buffer) {
f.clearflags()
}
-// computePadding computes left and right padding widths (only one will be non-zero).
-func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
- left := !f.minus
- w := f.wid
- if w < 0 {
- left = false
- w = -w
- }
- w -= width
- if w > 0 {
- if left && f.zero {
- return padZeroBytes, w, 0
- }
- if left {
- return padSpaceBytes, w, 0
- } else {
- // can't be zero padding on the right
- return padSpaceBytes, 0, w
- }
- }
- return
-}
-
// writePadding generates n bytes of padding.
-func (f *fmt) writePadding(n int, padding []byte) {
- for n > 0 {
- m := n
- if m > nByte {
- m = nByte
- }
- f.buf.Write(padding[0:m])
- n -= m
+func (f *fmt) writePadding(n int) {
+ if n <= 0 { // No padding bytes needed.
+ return
}
+ buf := *f.buf
+ oldLen := len(buf)
+ newLen := oldLen + n
+ // Make enough room for padding.
+ if newLen > cap(buf) {
+ buf = make(buffer, cap(buf)*2+n)
+ copy(buf, *f.buf)
+ }
+ // Decide which byte the padding should be filled with.
+ padByte := byte(' ')
+ if f.zero {
+ padByte = byte('0')
+ }
+ // Fill padding with padByte.
+ padding := buf[oldLen:newLen]
+ for i := range padding {
+ padding[i] = padByte
+ }
+ *f.buf = buf[:newLen]
}
-// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) pad(b []byte) {
if !f.widPresent || f.wid == 0 {
f.buf.Write(b)
return
}
- padding, left, right := f.computePadding(utf8.RuneCount(b))
- if left > 0 {
- f.writePadding(left, padding)
- }
- f.buf.Write(b)
- if right > 0 {
- f.writePadding(right, padding)
+ width := f.wid - utf8.RuneCount(b)
+ if !f.minus {
+ // left padding
+ f.writePadding(width)
+ f.buf.Write(b)
+ } else {
+ // right padding
+ f.buf.Write(b)
+ f.writePadding(width)
}
}
-// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) padString(s string) {
if !f.widPresent || f.wid == 0 {
f.buf.WriteString(s)
return
}
- padding, left, right := f.computePadding(utf8.RuneCountInString(s))
- if left > 0 {
- f.writePadding(left, padding)
- }
- f.buf.WriteString(s)
- if right > 0 {
- f.writePadding(right, padding)
+ width := f.wid - utf8.RuneCountInString(s)
+ if !f.minus {
+ // left padding
+ f.writePadding(width)
+ f.buf.WriteString(s)
+ } else {
+ // right padding
+ f.buf.WriteString(s)
+ f.writePadding(width)
}
}
-var (
- trueBytes = []byte("true")
- falseBytes = []byte("false")
-)
-
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
- f.pad(trueBytes)
+ f.padString("true")
} else {
- f.pad(falseBytes)
+ f.padString("false")
}
}
-// integer; interprets prec but not wid. Once formatted, result is sent to pad()
-// and then flags are cleared.
-func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
- // precision of 0 and value of 0 means "print nothing"
- if f.precPresent && f.prec == 0 && a == 0 {
- return
+// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
+func (f *fmt) fmt_unicode(u uint64) {
+ buf := f.intbuf[0:]
+
+ // With default precision set the maximum needed buf length is 18
+ // for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
+ // into the already allocated intbuf with a capacity of 68 bytes.
+ prec := 4
+ if f.precPresent && f.prec > 4 {
+ prec = f.prec
+ // Compute space needed for "U+" , number, " '", character, "'".
+ width := 2 + prec + 2 + utf8.UTFMax + 1
+ if width > len(buf) {
+ buf = make([]byte, width)
+ }
}
- negative := signedness == signed && a < 0
+ // Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
+ i := len(buf)
+
+ // For %#U we want to add a space and a quoted character at the end of the buffer.
+ if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
+ i--
+ buf[i] = '\''
+ i -= utf8.RuneLen(rune(u))
+ utf8.EncodeRune(buf[i:], rune(u))
+ i--
+ buf[i] = '\''
+ i--
+ buf[i] = ' '
+ }
+ // Format the Unicode code point u as a hexadecimal number.
+ for u >= 16 {
+ i--
+ buf[i] = udigits[u&0xF]
+ prec--
+ u >>= 4
+ }
+ i--
+ buf[i] = udigits[u]
+ prec--
+ // Add zeros in front of the number until requested precision is reached.
+ for prec > 0 {
+ i--
+ buf[i] = '0'
+ prec--
+ }
+ // Add a leading "U+".
+ i--
+ buf[i] = '+'
+ i--
+ buf[i] = 'U'
+
+ oldZero := f.zero
+ f.zero = false
+ f.pad(buf[i:])
+ f.zero = oldZero
+}
+
+// fmt_integer formats signed and unsigned integers.
+func (f *fmt) fmt_integer(u uint64, base int, isSigned bool, digits string) {
+ negative := isSigned && int64(u) < 0
if negative {
- a = -a
+ u = -u
}
- var buf []byte = f.intbuf[0:]
- if f.widPresent || f.precPresent || f.plus || f.space {
- width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
- if base == 16 && f.sharp {
- // Also adds "0x".
- width += 2
- }
- if f.unicode {
- // Also adds "U+".
- width += 2
- if f.uniQuote {
- // Also adds " 'x'".
- width += 1 + 1 + utf8.UTFMax + 1
- }
- }
- if negative || f.plus || f.space {
- width++
- }
- if width > nByte {
+ buf := f.intbuf[0:]
+ // The already allocated f.intbuf with a capacity of 68 bytes
+ // is large enough for integer formatting when no precision or width is set.
+ if f.widPresent || f.precPresent {
+ // Account 3 extra bytes for possible addition of a sign and "0x".
+ width := 3 + f.wid + f.prec // wid and prec are always positive.
+ if width > len(buf) {
// We're going to need a bigger boat.
buf = make([]byte, width)
}
}
- // two ways to ask for extra leading zero digits: %.3d or %03d.
- // apparently the first cancels the second.
+ // Two ways to ask for extra leading zero digits: %.3d or %03d.
+ // If both are specified the f.zero flag is ignored and
+ // padding with spaces is used instead.
prec := 0
if f.precPresent {
prec = f.prec
- f.zero = false
- } else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+ // Precision of 0 and value of 0 means "print nothing" but padding.
+ if prec == 0 && u == 0 {
+ oldZero := f.zero
+ f.zero = false
+ f.writePadding(f.wid)
+ f.zero = oldZero
+ return
+ }
+ } else if f.zero && f.widPresent {
prec = f.wid
if negative || f.plus || f.space {
prec-- // leave room for sign
}
}
- // format a into buf, ending at buf[i]. (printing is easier right-to-left.)
- // a is made into unsigned ua. we could make things
- // marginally faster by splitting the 32-bit case out into a separate
- // block but it's not worth the duplication, so ua has 64 bits.
+ // Because printing is easier right-to-left: format u into buf, ending at buf[i].
+ // We could make things marginally faster by splitting the 32-bit case out
+ // into a separate block but it's not worth the duplication, so u has 64 bits.
i := len(buf)
- ua := uint64(a)
- // use constants for the division and modulo for more efficient code.
- // switch cases ordered by popularity.
+ // Use constants for the division and modulo for more efficient code.
+ // Switch cases ordered by popularity.
switch base {
case 10:
- for ua >= 10 {
+ for u >= 10 {
i--
- next := ua / 10
- buf[i] = byte('0' + ua - next*10)
- ua = next
+ next := u / 10
+ buf[i] = byte('0' + u - next*10)
+ u = next
}
case 16:
- for ua >= 16 {
+ for u >= 16 {
i--
- buf[i] = digits[ua&0xF]
- ua >>= 4
+ buf[i] = digits[u&0xF]
+ u >>= 4
}
case 8:
- for ua >= 8 {
+ for u >= 8 {
i--
- buf[i] = byte('0' + ua&7)
- ua >>= 3
+ buf[i] = byte('0' + u&7)
+ u >>= 3
}
case 2:
- for ua >= 2 {
+ for u >= 2 {
i--
- buf[i] = byte('0' + ua&1)
- ua >>= 1
+ buf[i] = byte('0' + u&1)
+ u >>= 1
}
default:
panic("fmt: unknown base; can't happen")
}
i--
- buf[i] = digits[ua]
+ buf[i] = digits[u]
for i > 0 && prec > len(buf)-i {
i--
buf[i] = '0'
@@ -257,18 +281,13 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = '0'
}
case 16:
+ // Add a leading 0x or 0X.
i--
- buf[i] = 'x' + digits[10] - 'a'
+ buf[i] = digits[16]
i--
buf[i] = '0'
}
}
- if f.unicode {
- i--
- buf[i] = '+'
- i--
- buf[i] = 'U'
- }
if negative {
i--
@@ -281,36 +300,23 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = ' '
}
- // If we want a quoted char for %#U, move the data up to make room.
- if f.unicode && f.uniQuote && a >= 0 && a <= utf8.MaxRune && strconv.IsPrint(rune(a)) {
- runeWidth := utf8.RuneLen(rune(a))
- width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
- copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
- i -= width
- // Now put " 'x'" at the end.
- j := len(buf) - width
- buf[j] = ' '
- j++
- buf[j] = '\''
- j++
- utf8.EncodeRune(buf[j:], rune(a))
- j += runeWidth
- buf[j] = '\''
- }
-
+ // Left padding with zeros has already been handled like precision earlier
+ // or the f.zero flag is ignored due to an explicitly set precision.
+ oldZero := f.zero
+ f.zero = false
f.pad(buf[i:])
+ f.zero = oldZero
}
// truncate truncates the string to the specified precision, if present.
func (f *fmt) truncate(s string) string {
- if f.precPresent && f.prec < utf8.RuneCountInString(s) {
+ if f.precPresent {
n := f.prec
for i := range s {
- if n == 0 {
- s = s[:i]
- break
- }
n--
+ if n < 0 {
+ return s[:i]
+ }
}
}
return s
@@ -324,212 +330,169 @@ func (f *fmt) fmt_s(s string) {
// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
- n := len(b)
+ length := len(b)
if b == nil {
- n = len(s)
+ // No byte slice present. Assume string s should be encoded.
+ length = len(s)
+ }
+ // Set length to not process more bytes than the precision demands.
+ if f.precPresent && f.prec < length {
+ length = f.prec
+ }
+ // Compute width of the encoding taking into account the f.sharp and f.space flag.
+ width := 2 * length
+ if width > 0 {
+ if f.space {
+ // Each element encoded by two hexadecimals will get a leading 0x or 0X.
+ if f.sharp {
+ width *= 2
+ }
+ // Elements will be separated by a space.
+ width += length - 1
+ } else if f.sharp {
+ // Only a leading 0x or 0X will be added for the whole string.
+ width += 2
+ }
+ } else { // The byte slice or string that should be encoded is empty.
+ if f.widPresent {
+ f.writePadding(f.wid)
+ }
+ return
+ }
+ // Handle padding to the left.
+ if f.widPresent && f.wid > width && !f.minus {
+ f.writePadding(f.wid - width)
}
- x := digits[10] - 'a' + 'x'
- // TODO: Avoid buffer by pre-padding.
- var buf []byte
- for i := 0; i < n; i++ {
- if i > 0 && f.space {
+ // Write the encoding directly into the output buffer.
+ buf := *f.buf
+ if f.sharp {
+ // Add leading 0x or 0X.
+ buf = append(buf, '0', digits[16])
+ }
+ var c byte
+ for i := 0; i < length; i++ {
+ if f.space && i > 0 {
+ // Separate elements with a space.
buf = append(buf, ' ')
+ if f.sharp {
+ // Add leading 0x or 0X for each element.
+ buf = append(buf, '0', digits[16])
+ }
}
- if f.sharp && (f.space || i == 0) {
- buf = append(buf, '0', x)
- }
- var c byte
- if b == nil {
- c = s[i]
+ if b != nil {
+ c = b[i] // Take a byte from the input byte slice.
} else {
- c = b[i]
+ c = s[i] // Take a byte from the input string.
}
+ // Encode each byte as two hexadecimal digits.
buf = append(buf, digits[c>>4], digits[c&0xF])
}
- f.pad(buf)
+ *f.buf = buf
+ // Handle padding to the right.
+ if f.widPresent && f.wid > width && f.minus {
+ f.writePadding(f.wid - width)
+ }
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s, digits string) {
- if f.precPresent && f.prec < len(s) {
- s = s[:f.prec]
- }
f.fmt_sbx(s, nil, digits)
}
// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_bx(b []byte, digits string) {
- if f.precPresent && f.prec < len(b) {
- b = b[:f.prec]
- }
f.fmt_sbx("", b, digits)
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
+// If f.sharp is set a raw (backquoted) string may be returned instead
+// if the string does not contain any control characters other than tab.
func (f *fmt) fmt_q(s string) {
s = f.truncate(s)
- var quoted string
if f.sharp && strconv.CanBackquote(s) {
- quoted = "`" + s + "`"
+ f.padString("`" + s + "`")
+ return
+ }
+ buf := f.intbuf[:0]
+ if f.plus {
+ f.pad(strconv.AppendQuoteToASCII(buf, s))
} else {
- if f.plus {
- quoted = strconv.QuoteToASCII(s)
- } else {
- quoted = strconv.Quote(s)
- }
+ f.pad(strconv.AppendQuote(buf, s))
}
- f.padString(quoted)
}
-// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
+// fmt_c formats an integer as a Unicode character.
// If the character is not valid Unicode, it will print '\ufffd'.
-func (f *fmt) fmt_qc(c int64) {
- var quoted []byte
+func (f *fmt) fmt_c(c uint64) {
+ r := rune(c)
+ if c > utf8.MaxRune {
+ r = utf8.RuneError
+ }
+ buf := f.intbuf[:0]
+ w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
+ f.pad(buf[:w])
+}
+
+// fmt_qc formats an integer as a single-quoted, escaped Go character constant.
+// If the character is not valid Unicode, it will print '\ufffd'.
+func (f *fmt) fmt_qc(c uint64) {
+ r := rune(c)
+ if c > utf8.MaxRune {
+ r = utf8.RuneError
+ }
+ buf := f.intbuf[:0]
if f.plus {
- quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
+ f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
} else {
- quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
+ f.pad(strconv.AppendQuoteRune(buf, r))
}
- f.pad(quoted)
}
-// floating-point
-
-func doPrec(f *fmt, def int) int {
+// fmt_float formats a float64. It assumes that verb is a valid format specifier
+// for strconv.AppendFloat and therefore fits into a byte.
+func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
+ // Explicit precision in format specifier overrules default precision.
if f.precPresent {
- return f.prec
+ prec = f.prec
}
- return def
-}
-
-// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
-func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// Format number, reserving space for leading + sign if needed.
- num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
num[0] = '+'
}
- // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
- if math.IsInf(v, 0) {
- if f.zero {
- defer func() { f.zero = true }()
- f.zero = false
- }
+ // f.space means to add a leading space instead of a "+" sign unless
+ // the sign is explicitly asked for by f.plus.
+ if f.space && num[0] == '+' && !f.plus {
+ num[0] = ' '
}
- // num is now a signed version of the number.
- // If we're zero padding, want the sign before the leading zeros.
- // Achieve this by writing the sign out and then padding the unsigned number.
- if f.zero && f.widPresent && f.wid > len(num) {
- if f.space && v >= 0 {
- f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
- f.wid--
- } else if f.plus || v < 0 {
- f.buf.WriteByte(num[0])
- f.wid--
+ // Special handling for infinities and NaN,
+ // which don't look like a number so shouldn't be padded with zeros.
+ if num[1] == 'I' || num[1] == 'N' {
+ oldZero := f.zero
+ f.zero = false
+ // Remove sign before NaN if not asked for.
+ if num[1] == 'N' && !f.space && !f.plus {
+ num = num[1:]
}
- f.pad(num[1:])
- return
- }
- // f.space says to replace a leading + with a space.
- if f.space && num[0] == '+' {
- num[0] = ' '
f.pad(num)
+ f.zero = oldZero
return
}
- // Now we know the sign is attached directly to the number, if present at all.
- // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
- if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+ // We want a sign if asked for and if the sign is not positive.
+ if f.plus || num[0] != '+' {
+ // If we're zero padding to the left we want the sign before the leading zeros.
+ // Achieve this by writing the sign out and then padding the unsigned number.
+ if f.zero && f.widPresent && f.wid > len(num) {
+ f.buf.WriteByte(num[0])
+ f.writePadding(f.wid - len(num))
+ f.buf.Write(num[1:])
+ return
+ }
f.pad(num)
return
}
// No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:])
}
-
-// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
-
-// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
-
-// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
-
-// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
-
-// fmt_G64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
-
-// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
-
-// float32
-// cannot defer to float64 versions
-// because it will get rounding wrong in corner cases.
-
-// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
-
-// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
-
-// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
-
-// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
-
-// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
-
-// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
-
-// fmt_c64 formats a complex64 according to the verb.
-func (f *fmt) fmt_c64(v complex64, verb rune) {
- f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
-}
-
-// fmt_c128 formats a complex128 according to the verb.
-func (f *fmt) fmt_c128(v complex128, verb rune) {
- f.fmt_complex(real(v), imag(v), 64, verb)
-}
-
-// fmt_complex formats a complex number as (r+ji).
-func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
- f.buf.WriteByte('(')
- oldPlus := f.plus
- oldSpace := f.space
- oldWid := f.wid
- for i := 0; ; i++ {
- switch verb {
- case 'b':
- f.formatFloat(r, 'b', 0, size)
- case 'e':
- f.formatFloat(r, 'e', doPrec(f, 6), size)
- case 'E':
- f.formatFloat(r, 'E', doPrec(f, 6), size)
- case 'f', 'F':
- f.formatFloat(r, 'f', doPrec(f, 6), size)
- case 'g':
- f.formatFloat(r, 'g', doPrec(f, -1), size)
- case 'G':
- f.formatFloat(r, 'G', doPrec(f, -1), size)
- }
- if i != 0 {
- break
- }
- // Imaginary part always has a sign.
- f.plus = true
- f.space = false
- f.wid = oldWid
- r = j
- }
- f.space = oldSpace
- f.plus = oldPlus
- f.wid = oldWid
- f.buf.Write(irparenBytes)
-}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index ebfa13e4d3..a7ef2e5ac2 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -13,24 +13,23 @@ import (
"unicode/utf8"
)
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
- commaSpaceBytes = []byte(", ")
- nilAngleBytes = []byte("<nil>")
- nilParenBytes = []byte("(nil)")
- nilBytes = []byte("nil")
- mapBytes = []byte("map[")
- percentBangBytes = []byte("%!")
- missingBytes = []byte("(MISSING)")
- badIndexBytes = []byte("(BADINDEX)")
- panicBytes = []byte("(PANIC=")
- extraBytes = []byte("%!(EXTRA ")
- irparenBytes = []byte("i)")
- bytesBytes = []byte("[]byte{")
- badWidthBytes = []byte("%!(BADWIDTH)")
- badPrecBytes = []byte("%!(BADPREC)")
- noVerbBytes = []byte("%!(NOVERB)")
+// Strings for use with buffer.WriteString.
+// This is less overhead than using buffer.Write with byte arrays.
+const (
+ commaSpaceString = ", "
+ nilAngleString = "<nil>"
+ nilParenString = "(nil)"
+ nilString = "nil"
+ mapString = "map["
+ percentBangString = "%!"
+ missingString = "(MISSING)"
+ badIndexString = "(BADINDEX)"
+ panicString = "(PANIC="
+ extraString = "%!(EXTRA "
+ badWidthString = "%!(BADWIDTH)"
+ badPrecString = "%!(BADPREC)"
+ noVerbString = "%!(NOVERB)"
+ invReflectString = "<invalid reflect.Value>"
)
// State represents the printer state passed to custom formatters.
@@ -38,7 +37,7 @@ var (
// the flags and options for the operand's format specifier.
type State interface {
// Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err error)
+ Write(b []byte) (n int, err error)
// Width returns the value of the width option and whether it has been set.
Width() (wid int, ok bool)
// Precision returns the value of the precision option and whether it has been set.
@@ -75,25 +74,22 @@ type GoStringer interface {
// Use simple []byte instead of bytes.Buffer to avoid large dependency.
type buffer []byte
-func (b *buffer) Write(p []byte) (n int, err error) {
+func (b *buffer) Write(p []byte) {
*b = append(*b, p...)
- return len(p), nil
}
-func (b *buffer) WriteString(s string) (n int, err error) {
+func (b *buffer) WriteString(s string) {
*b = append(*b, s...)
- return len(s), nil
}
-func (b *buffer) WriteByte(c byte) error {
+func (b *buffer) WriteByte(c byte) {
*b = append(*b, c)
- return nil
}
-func (bp *buffer) WriteRune(r rune) error {
+func (bp *buffer) WriteRune(r rune) {
if r < utf8.RuneSelf {
*bp = append(*bp, byte(r))
- return nil
+ return
}
b := *bp
@@ -103,25 +99,29 @@ func (bp *buffer) WriteRune(r rune) error {
}
w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
*bp = b[:n+w]
- return nil
}
+// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.
type pp struct {
- n int
- panicking bool
- erroring bool // printing an error condition
- buf buffer
+ buf buffer
+
// arg holds the current item, as an interface{}.
arg interface{}
- // value holds the current item, as a reflect.Value, and will be
- // the zero Value if the item has not been reflected.
+
+ // value is used instead of arg for reflect values.
value reflect.Value
+
+ // fmt is used to format basic items such as integers or strings.
+ fmt fmt
+
// reordered records whether the format string used argument reordering.
reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ // panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
+ panicking bool
+ // erroring is set when printing an error string to guard against calling handleMethods.
+ erroring bool
}
var ppFree = sync.Pool{
@@ -139,10 +139,6 @@ func newPrinter() *pp {
// free saves used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
- // Don't hold on to pp structs with large buffers.
- if cap(p.buf) > 1024 {
- return
- }
p.buf = p.buf[:0]
p.arg = nil
p.value = reflect.Value{}
@@ -158,9 +154,9 @@ func (p *pp) Flag(b int) bool {
case '-':
return p.fmt.minus
case '+':
- return p.fmt.plus
+ return p.fmt.plus || p.fmt.plusV
case '#':
- return p.fmt.sharp
+ return p.fmt.sharp || p.fmt.sharpV
case ' ':
return p.fmt.space
case '0':
@@ -169,14 +165,11 @@ func (p *pp) Flag(b int) bool {
return false
}
-func (p *pp) add(c rune) {
- p.buf.WriteRune(c)
-}
-
// Implement Write so we can call Fprintf on a pp (through State), for
// recursive use in custom verbs.
func (p *pp) Write(b []byte) (ret int, err error) {
- return p.buf.Write(b)
+ p.buf.Write(b)
+ return len(b), nil
}
// These routines end in 'f' and take a format string.
@@ -219,7 +212,7 @@ func Errorf(format string, a ...interface{}) error {
// It returns the number of bytes written and any write error encountered.
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
- p.doPrint(a, false, false)
+ p.doPrint(a)
n, err = w.Write(p.buf)
p.free()
return
@@ -236,7 +229,7 @@ func Print(a ...interface{}) (n int, err error) {
// Spaces are added between operands when neither is a string.
func Sprint(a ...interface{}) string {
p := newPrinter()
- p.doPrint(a, false, false)
+ p.doPrint(a)
s := string(p.buf)
p.free()
return s
@@ -251,7 +244,7 @@ func Sprint(a ...interface{}) string {
// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
- p.doPrint(a, true, true)
+ p.doPrintln(a)
n, err = w.Write(p.buf)
p.free()
return
@@ -268,7 +261,7 @@ func Println(a ...interface{}) (n int, err error) {
// Spaces are always added between operands and a newline is appended.
func Sprintln(a ...interface{}) string {
p := newPrinter()
- p.doPrint(a, true, true)
+ p.doPrintln(a)
s := string(p.buf)
p.free()
return s
@@ -309,7 +302,7 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
func (p *pp) unknownType(v reflect.Value) {
if !v.IsValid() {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
return
}
p.buf.WriteByte('?')
@@ -319,23 +312,22 @@ func (p *pp) unknownType(v reflect.Value) {
func (p *pp) badVerb(verb rune) {
p.erroring = true
- p.add('%')
- p.add('!')
- p.add(verb)
- p.add('(')
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteByte('(')
switch {
case p.arg != nil:
p.buf.WriteString(reflect.TypeOf(p.arg).String())
- p.add('=')
- p.printArg(p.arg, 'v', 0)
+ p.buf.WriteByte('=')
+ p.printArg(p.arg, 'v')
case p.value.IsValid():
p.buf.WriteString(p.value.Type().String())
- p.add('=')
+ p.buf.WriteByte('=')
p.printValue(p.value, 'v', 0)
default:
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
}
- p.add(')')
+ p.buf.WriteByte(')')
p.erroring = false
}
@@ -348,162 +340,82 @@ func (p *pp) fmtBool(v bool, verb rune) {
}
}
-// fmtC formats a rune for the 'c' format.
-func (p *pp) fmtC(c int64) {
- r := rune(c) // Check for overflow.
- if int64(r) != c {
- r = utf8.RuneError
- }
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
- p.fmt.pad(p.runeBuf[0:w])
-}
-
-func (p *pp) fmtInt64(v int64, verb rune) {
- switch verb {
- case 'b':
- p.fmt.integer(v, 2, signed, ldigits)
- case 'c':
- p.fmtC(v)
- case 'd', 'v':
- p.fmt.integer(v, 10, signed, ldigits)
- case 'o':
- p.fmt.integer(v, 8, signed, ldigits)
- case 'q':
- if 0 <= v && v <= utf8.MaxRune {
- p.fmt.fmt_qc(v)
- } else {
- p.badVerb(verb)
- }
- case 'x':
- p.fmt.integer(v, 16, signed, ldigits)
- case 'U':
- p.fmtUnicode(v)
- case 'X':
- p.fmt.integer(v, 16, signed, udigits)
- default:
- p.badVerb(verb)
- }
-}
-
// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
// not, as requested, by temporarily setting the sharp flag.
func (p *pp) fmt0x64(v uint64, leading0x bool) {
sharp := p.fmt.sharp
p.fmt.sharp = leading0x
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.fmt_integer(v, 16, unsigned, ldigits)
p.fmt.sharp = sharp
}
-// fmtUnicode formats a uint64 in U+1234 form by
-// temporarily turning on the unicode flag and tweaking the precision.
-func (p *pp) fmtUnicode(v int64) {
- precPresent := p.fmt.precPresent
- sharp := p.fmt.sharp
- p.fmt.sharp = false
- prec := p.fmt.prec
- if !precPresent {
- // If prec is already set, leave it alone; otherwise 4 is minimum.
- p.fmt.prec = 4
- p.fmt.precPresent = true
- }
- p.fmt.unicode = true // turn on U+
- p.fmt.uniQuote = sharp
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- p.fmt.unicode = false
- p.fmt.uniQuote = false
- p.fmt.prec = prec
- p.fmt.precPresent = precPresent
- p.fmt.sharp = sharp
-}
-
-func (p *pp) fmtUint64(v uint64, verb rune) {
+// fmtInteger formats a signed or unsigned integer.
+func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) {
switch verb {
- case 'b':
- p.fmt.integer(int64(v), 2, unsigned, ldigits)
- case 'c':
- p.fmtC(int64(v))
- case 'd':
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
case 'v':
- if p.fmt.sharpV {
+ if p.fmt.sharpV && !isSigned {
p.fmt0x64(v, true)
} else {
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ p.fmt.fmt_integer(v, 10, isSigned, ldigits)
}
+ case 'd':
+ p.fmt.fmt_integer(v, 10, isSigned, ldigits)
+ case 'b':
+ p.fmt.fmt_integer(v, 2, isSigned, ldigits)
case 'o':
- p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ p.fmt.fmt_integer(v, 8, isSigned, ldigits)
+ case 'x':
+ p.fmt.fmt_integer(v, 16, isSigned, ldigits)
+ case 'X':
+ p.fmt.fmt_integer(v, 16, isSigned, udigits)
+ case 'c':
+ p.fmt.fmt_c(v)
case 'q':
- if 0 <= v && v <= utf8.MaxRune {
- p.fmt.fmt_qc(int64(v))
+ if v <= utf8.MaxRune {
+ p.fmt.fmt_qc(v)
} else {
p.badVerb(verb)
}
- case 'x':
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
- case 'X':
- p.fmt.integer(int64(v), 16, unsigned, udigits)
case 'U':
- p.fmtUnicode(int64(v))
+ p.fmt.fmt_unicode(v)
default:
p.badVerb(verb)
}
}
-func (p *pp) fmtFloat32(v float32, verb rune) {
+// fmtFloat formats a float. The default precision for each verb
+// is specified as last argument in the call to fmt_float.
+func (p *pp) fmtFloat(v float64, size int, verb rune) {
switch verb {
- case 'b':
- p.fmt.fmt_fb32(v)
- case 'e':
- p.fmt.fmt_e32(v)
- case 'E':
- p.fmt.fmt_E32(v)
- case 'f', 'F':
- p.fmt.fmt_f32(v)
- case 'g', 'v':
- p.fmt.fmt_g32(v)
- case 'G':
- p.fmt.fmt_G32(v)
- default:
- p.badVerb(verb)
- }
-}
-
-func (p *pp) fmtFloat64(v float64, verb rune) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb64(v)
- case 'e':
- p.fmt.fmt_e64(v)
- case 'E':
- p.fmt.fmt_E64(v)
- case 'f', 'F':
- p.fmt.fmt_f64(v)
- case 'g', 'v':
- p.fmt.fmt_g64(v)
- case 'G':
- p.fmt.fmt_G64(v)
- default:
- p.badVerb(verb)
- }
-}
-
-func (p *pp) fmtComplex64(v complex64, verb rune) {
- switch verb {
- case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c64(v, verb)
case 'v':
- p.fmt.fmt_c64(v, 'g')
+ p.fmt.fmt_float(v, size, 'g', -1)
+ case 'b', 'g', 'G':
+ p.fmt.fmt_float(v, size, verb, -1)
+ case 'f', 'e', 'E':
+ p.fmt.fmt_float(v, size, verb, 6)
+ case 'F':
+ p.fmt.fmt_float(v, size, 'f', 6)
default:
p.badVerb(verb)
}
}
-func (p *pp) fmtComplex128(v complex128, verb rune) {
+// fmtComplex formats a complex number v with
+// r = real(v) and j = imag(v) as (r+ji) using
+// fmtFloat for r and j formatting.
+func (p *pp) fmtComplex(v complex128, size int, verb rune) {
+ // Make sure any unsupported verbs are found before the
+ // calls to fmtFloat to not generate an incorrect error string.
switch verb {
- case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c128(v, verb)
- case 'v':
- p.fmt.fmt_c128(v, 'g')
+ case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
+ oldPlus := p.fmt.plus
+ p.buf.WriteByte('(')
+ p.fmtFloat(real(v), size/2, verb)
+ // Imaginary part always has a sign.
+ p.fmt.plus = true
+ p.fmtFloat(imag(v), size/2, verb)
+ p.buf.WriteString("i)")
+ p.fmt.plus = oldPlus
default:
p.badVerb(verb)
}
@@ -530,45 +442,33 @@ func (p *pp) fmtString(v string, verb rune) {
}
}
-func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
- if verb == 'v' || verb == 'd' {
+func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
+ switch verb {
+ case 'v', 'd':
if p.fmt.sharpV {
+ p.buf.WriteString(typeString)
if v == nil {
- if typ == nil {
- p.buf.WriteString("[]byte(nil)")
- } else {
- p.buf.WriteString(typ.String())
- p.buf.Write(nilParenBytes)
- }
+ p.buf.WriteString(nilParenString)
return
}
- if typ == nil {
- p.buf.Write(bytesBytes)
- } else {
- p.buf.WriteString(typ.String())
- p.buf.WriteByte('{')
+ p.buf.WriteByte('{')
+ for i, c := range v {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ p.fmt0x64(uint64(c), true)
}
+ p.buf.WriteByte('}')
} else {
p.buf.WriteByte('[')
- }
- for i, c := range v {
- if i > 0 {
- if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
- } else {
+ for i, c := range v {
+ if i > 0 {
p.buf.WriteByte(' ')
}
+ p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
}
- p.printArg(c, 'v', depth+1)
- }
- if p.fmt.sharpV {
- p.buf.WriteByte('}')
- } else {
p.buf.WriteByte(']')
}
- return
- }
- switch verb {
case 's':
p.fmt.fmt_s(string(v))
case 'x':
@@ -578,23 +478,11 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
case 'q':
p.fmt.fmt_q(string(v))
default:
- p.badVerb(verb)
+ p.printValue(reflect.ValueOf(v), verb, 0)
}
}
func (p *pp) fmtPointer(value reflect.Value, verb rune) {
- use0x64 := true
- switch verb {
- case 'p', 'v':
- // ok
- case 'b', 'd', 'o', 'x', 'X':
- use0x64 = false
- // ok
- default:
- p.badVerb(verb)
- return
- }
-
var u uintptr
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
@@ -604,40 +492,41 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) {
return
}
- if p.fmt.sharpV {
- p.add('(')
- p.buf.WriteString(value.Type().String())
- p.add(')')
- p.add('(')
- if u == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(u), true)
- }
- p.add(')')
- } else if verb == 'v' && u == 0 {
- p.buf.Write(nilAngleBytes)
- } else {
- if use0x64 {
- p.fmt0x64(uint64(u), !p.fmt.sharp)
+ switch verb {
+ case 'v':
+ if p.fmt.sharpV {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(")(")
+ if u == 0 {
+ p.buf.WriteString(nilString)
+ } else {
+ p.fmt0x64(uint64(u), true)
+ }
+ p.buf.WriteByte(')')
} else {
- p.fmtUint64(uint64(u), verb)
+ if u == 0 {
+ p.fmt.padString(nilAngleString)
+ } else {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ }
}
+ case 'p':
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ case 'b', 'o', 'd', 'x', 'X':
+ p.fmtInteger(uint64(u), unsigned, verb)
+ default:
+ p.badVerb(verb)
}
}
-var (
- intBits = reflect.TypeOf(0).Bits()
- uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
-)
-
func (p *pp) catchPanic(arg interface{}, verb rune) {
if err := recover(); err != nil {
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
// Stringer that fails to guard against nil or a nil pointer for a
// value receiver, and in either case, "<nil>" is a nice result.
if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
return
}
// Otherwise print a concise panic message. Most of the time the panic
@@ -646,53 +535,30 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
// Nested panics; the recursion in printArg cannot succeed.
panic(err)
}
- p.fmt.clearflags() // We are done, and for this output we want default behavior.
- p.buf.Write(percentBangBytes)
- p.add(verb)
- p.buf.Write(panicBytes)
+
+ oldFlags := p.fmt.fmtFlags
+ // For this output we want default behavior.
+ p.fmt.clearflags()
+
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(panicString)
p.panicking = true
- p.printArg(err, 'v', 0)
+ p.printArg(err, 'v')
p.panicking = false
p.buf.WriteByte(')')
- }
-}
-// clearSpecialFlags pushes %#v back into the regular flags and returns their old state.
-func (p *pp) clearSpecialFlags() (plusV, sharpV bool) {
- plusV = p.fmt.plusV
- if plusV {
- p.fmt.plus = true
- p.fmt.plusV = false
- }
- sharpV = p.fmt.sharpV
- if sharpV {
- p.fmt.sharp = true
- p.fmt.sharpV = false
- }
- return
-}
-
-// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags,
-// restores the setting of the plusV and sharpV flags.
-func (p *pp) restoreSpecialFlags(plusV, sharpV bool) {
- if plusV {
- p.fmt.plus = false
- p.fmt.plusV = true
- }
- if sharpV {
- p.fmt.sharp = false
- p.fmt.sharpV = true
+ p.fmt.fmtFlags = oldFlags
}
}
-func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
+func (p *pp) handleMethods(verb rune) (handled bool) {
if p.erroring {
return
}
// Is it a Formatter?
if formatter, ok := p.arg.(Formatter); ok {
handled = true
- defer p.restoreSpecialFlags(p.clearSpecialFlags())
defer p.catchPanic(p.arg, verb)
formatter.Format(p, verb)
return
@@ -721,13 +587,13 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
case error:
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.Error(), verb, depth)
+ p.fmtString(v.Error(), verb)
return
case Stringer:
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.String(), verb, depth)
+ p.fmtString(v.String(), verb)
return
}
}
@@ -735,28 +601,29 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
return false
}
-func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
+func (p *pp) printArg(arg interface{}, verb rune) {
p.arg = arg
p.value = reflect.Value{}
if arg == nil {
- if verb == 'T' || verb == 'v' {
- p.fmt.pad(nilAngleBytes)
- } else {
+ switch verb {
+ case 'T', 'v':
+ p.fmt.padString(nilAngleString)
+ default:
p.badVerb(verb)
}
- return false
+ return
}
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
- p.printArg(reflect.TypeOf(arg).String(), 's', 0)
- return false
+ p.fmt.fmt_s(reflect.TypeOf(arg).String())
+ return
case 'p':
- p.fmtPointer(reflect.ValueOf(arg), verb)
- return false
+ p.fmtPointer(reflect.ValueOf(arg), 'p')
+ return
}
// Some types can be done without reflection.
@@ -764,137 +631,118 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
case bool:
p.fmtBool(f, verb)
case float32:
- p.fmtFloat32(f, verb)
+ p.fmtFloat(float64(f), 32, verb)
case float64:
- p.fmtFloat64(f, verb)
+ p.fmtFloat(f, 64, verb)
case complex64:
- p.fmtComplex64(f, verb)
+ p.fmtComplex(complex128(f), 64, verb)
case complex128:
- p.fmtComplex128(f, verb)
+ p.fmtComplex(f, 128, verb)
case int:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int8:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int16:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int32:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int64:
- p.fmtInt64(f, verb)
+ p.fmtInteger(uint64(f), signed, verb)
case uint:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint8:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint16:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint32:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint64:
- p.fmtUint64(f, verb)
+ p.fmtInteger(f, unsigned, verb)
case uintptr:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case string:
p.fmtString(f, verb)
- wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, nil, depth)
- wasString = verb == 's'
+ p.fmtBytes(f, verb, "[]byte")
case reflect.Value:
- return p.printReflectValue(f, verb, depth)
+ // Handle extractable values with special methods
+ // since printValue does not handle them at depth 0.
+ if f.IsValid() && f.CanInterface() {
+ p.arg = f.Interface()
+ if p.handleMethods(verb) {
+ return
+ }
+ }
+ p.printValue(f, verb, 0)
default:
// If the type is not simple, it might have methods.
- if handled := p.handleMethods(verb, depth); handled {
- return false
+ if !p.handleMethods(verb) {
+ // Need to use reflection, since the type had no
+ // interface methods that could be used for formatting.
+ p.printValue(reflect.ValueOf(f), verb, 0)
}
- // Need to use reflection
- return p.printReflectValue(reflect.ValueOf(arg), verb, depth)
}
- p.arg = nil
- return
}
-// printValue is like printArg but starts with a reflect value, not an interface{} value.
-func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) {
- if !value.IsValid() {
- if verb == 'T' || verb == 'v' {
- p.buf.Write(nilAngleBytes)
- } else {
- p.badVerb(verb)
- }
- return false
- }
-
- // Special processing considerations.
- // %T (the value's type) and %p (its address) are special; we always do them first.
- switch verb {
- case 'T':
- p.printArg(value.Type().String(), 's', 0)
- return false
- case 'p':
- p.fmtPointer(value, verb)
- return false
- }
+var byteType = reflect.TypeOf(byte(0))
- // Handle values with special methods.
- // Call always, even when arg == nil, because handleMethods clears p.fmt.plus for us.
- p.arg = nil // Make sure it's cleared, for safety.
- if value.CanInterface() {
+// printValue is similar to printArg but starts with a reflect value, not an interface{} value.
+// It does not handle 'p' and 'T' verbs because these should have been already handled by printArg.
+func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
+ // Handle values with special methods if not already handled by printArg (depth == 0).
+ if depth > 0 && value.IsValid() && value.CanInterface() {
p.arg = value.Interface()
+ if p.handleMethods(verb) {
+ return
+ }
}
- if handled := p.handleMethods(verb, depth); handled {
- return false
- }
-
- return p.printReflectValue(value, verb, depth)
-}
-
-var byteType = reflect.TypeOf(byte(0))
-
-// printReflectValue is the fallback for both printArg and printValue.
-// It uses reflect to print the value.
-func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) {
- oldValue := p.value
+ p.arg = nil
p.value = value
-BigSwitch:
- switch f := value; f.Kind() {
+
+ switch f := value; value.Kind() {
case reflect.Invalid:
- p.buf.WriteString("<invalid reflect.Value>")
+ if depth == 0 {
+ p.buf.WriteString(invReflectString)
+ } else {
+ switch verb {
+ case 'v':
+ p.buf.WriteString(nilAngleString)
+ default:
+ p.badVerb(verb)
+ }
+ }
case reflect.Bool:
p.fmtBool(f.Bool(), verb)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb)
+ p.fmtInteger(uint64(f.Int()), signed, verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(f.Uint(), verb)
- case reflect.Float32, reflect.Float64:
- if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb)
- } else {
- p.fmtFloat64(f.Float(), verb)
- }
- case reflect.Complex64, reflect.Complex128:
- if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb)
- } else {
- p.fmtComplex128(f.Complex(), verb)
- }
+ p.fmtInteger(f.Uint(), unsigned, verb)
+ case reflect.Float32:
+ p.fmtFloat(f.Float(), 32, verb)
+ case reflect.Float64:
+ p.fmtFloat(f.Float(), 64, verb)
+ case reflect.Complex64:
+ p.fmtComplex(f.Complex(), 64, verb)
+ case reflect.Complex128:
+ p.fmtComplex(f.Complex(), 128, verb)
case reflect.String:
p.fmtString(f.String(), verb)
case reflect.Map:
if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
if f.IsNil() {
- p.buf.WriteString("(nil)")
- break
+ p.buf.WriteString(nilParenString)
+ return
}
p.buf.WriteByte('{')
} else {
- p.buf.Write(mapBytes)
+ p.buf.WriteString(mapString)
}
keys := f.MapKeys()
for i, key := range keys {
if i > 0 {
if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
+ p.buf.WriteString(commaSpaceString)
} else {
p.buf.WriteByte(' ')
}
@@ -910,26 +758,24 @@ BigSwitch:
}
case reflect.Struct:
if p.fmt.sharpV {
- p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(f.Type().String())
}
- p.add('{')
- v := f
- t := v.Type()
- for i := 0; i < v.NumField(); i++ {
+ p.buf.WriteByte('{')
+ for i := 0; i < f.NumField(); i++ {
if i > 0 {
if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
+ p.buf.WriteString(commaSpaceString)
} else {
p.buf.WriteByte(' ')
}
}
if p.fmt.plusV || p.fmt.sharpV {
- if f := t.Field(i); f.Name != "" {
- p.buf.WriteString(f.Name)
+ if name := f.Type().Field(i).Name; name != "" {
+ p.buf.WriteString(name)
p.buf.WriteByte(':')
}
}
- p.printValue(getField(v, i), verb, depth+1)
+ p.printValue(getField(f, i), verb, depth+1)
}
p.buf.WriteByte('}')
case reflect.Interface:
@@ -937,91 +783,78 @@ BigSwitch:
if !value.IsValid() {
if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
- p.buf.Write(nilParenBytes)
+ p.buf.WriteString(nilParenString)
} else {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
}
} else {
- wasString = p.printValue(value, verb, depth+1)
+ p.printValue(value, verb, depth+1)
}
case reflect.Array, reflect.Slice:
- // Byte slices are special:
- // - Handle []byte (== []uint8) with fmtBytes.
- // - Handle []T, where T is a named byte type, with fmtBytes only
- // for the s, q, an x verbs. For other verbs, T might be a
- // Stringer, so we use printValue to print each element.
- if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 && (typ.Elem() == byteType || verb == 's' || verb == 'q' || verb == 'x') {
- var bytes []byte
- if f.Kind() == reflect.Slice {
- bytes = f.Bytes()
- } else if f.CanAddr() {
- bytes = f.Slice(0, f.Len()).Bytes()
- } else {
- // We have an array, but we cannot Slice() a non-addressable array,
- // so we build a slice by hand. This is a rare case but it would be nice
- // if reflection could help a little more.
- bytes = make([]byte, f.Len())
- for i := range bytes {
- bytes[i] = byte(f.Index(i).Uint())
+ switch verb {
+ case 's', 'q', 'x', 'X':
+ // Handle byte and uint8 slices and arrays special for the above verbs.
+ t := f.Type()
+ if t.Elem().Kind() == reflect.Uint8 {
+ var bytes []byte
+ if f.Kind() == reflect.Slice {
+ bytes = f.Bytes()
+ } else if f.CanAddr() {
+ bytes = f.Slice(0, f.Len()).Bytes()
+ } else {
+ // We have an array, but we cannot Slice() a non-addressable array,
+ // so we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes = make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Index(i).Uint())
+ }
}
+ p.fmtBytes(bytes, verb, t.String())
+ return
}
- p.fmtBytes(bytes, verb, typ, depth)
- wasString = verb == 's'
- break
}
if p.fmt.sharpV {
- p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(f.Type().String())
if f.Kind() == reflect.Slice && f.IsNil() {
- p.buf.WriteString("(nil)")
- break
+ p.buf.WriteString(nilParenString)
+ return
}
p.buf.WriteByte('{')
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ p.printValue(f.Index(i), verb, depth+1)
+ }
+ p.buf.WriteByte('}')
} else {
p.buf.WriteByte('[')
- }
- for i := 0; i < f.Len(); i++ {
- if i > 0 {
- if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
- } else {
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
p.buf.WriteByte(' ')
}
+ p.printValue(f.Index(i), verb, depth+1)
}
- p.printValue(f.Index(i), verb, depth+1)
- }
- if p.fmt.sharpV {
- p.buf.WriteByte('}')
- } else {
p.buf.WriteByte(']')
}
case reflect.Ptr:
- v := f.Pointer()
// pointer to array or slice or struct? ok at top level
// but not embedded (avoid loops)
- if v != 0 && depth == 0 {
+ if depth == 0 && f.Pointer() != 0 {
switch a := f.Elem(); a.Kind() {
- case reflect.Array, reflect.Slice:
- p.buf.WriteByte('&')
- p.printValue(a, verb, depth+1)
- break BigSwitch
- case reflect.Struct:
- p.buf.WriteByte('&')
- p.printValue(a, verb, depth+1)
- break BigSwitch
- case reflect.Map:
+ case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
p.buf.WriteByte('&')
p.printValue(a, verb, depth+1)
- break BigSwitch
+ return
}
}
fallthrough
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(value, verb)
+ p.fmtPointer(f, verb)
default:
p.unknownType(f)
}
- p.value = oldValue
- return wasString
}
// intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type.
@@ -1098,11 +931,24 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
return argNum, i + wid, ok
}
+func (p *pp) badArgNum(verb rune) {
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(badIndexString)
+}
+
+func (p *pp) missingArg(verb rune) {
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(missingString)
+}
+
func (p *pp) doPrintf(format string, a []interface{}) {
end := len(format)
argNum := 0 // we process one argument per non-trivial format
afterIndex := false // previous item in format was an index like [3].
p.reordered = false
+formatLoop:
for i := 0; i < end; {
p.goodArgNum = true
lasti := i
@@ -1122,21 +968,40 @@ func (p *pp) doPrintf(format string, a []interface{}) {
// Do we have flags?
p.fmt.clearflags()
- F:
+ simpleFormat:
for ; i < end; i++ {
- switch format[i] {
+ c := format[i]
+ switch c {
case '#':
p.fmt.sharp = true
case '0':
- p.fmt.zero = true
+ p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left.
case '+':
p.fmt.plus = true
case '-':
p.fmt.minus = true
+ p.fmt.zero = false // Do not pad with zeros to the right.
case ' ':
p.fmt.space = true
default:
- break F
+ // Fast path for common case of ascii lower case simple verbs
+ // without precision or width or argument indices.
+ if 'a' <= c && c <= 'z' && argNum < len(a) {
+ if c == 'v' {
+ // Go syntax
+ p.fmt.sharpV = p.fmt.sharp
+ p.fmt.sharp = false
+ // Struct-field syntax
+ p.fmt.plusV = p.fmt.plus
+ p.fmt.plus = false
+ }
+ p.printArg(a[argNum], rune(c))
+ argNum++
+ i++
+ continue formatLoop
+ }
+ // Format is more complex than simple flags and a verb or is malformed.
+ break simpleFormat
}
}
@@ -1149,7 +1014,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
if !p.fmt.widPresent {
- p.buf.Write(badWidthBytes)
+ p.buf.WriteString(badWidthString)
}
// We have a negative width, so take its value and ensure
@@ -1157,6 +1022,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
if p.fmt.wid < 0 {
p.fmt.wid = -p.fmt.wid
p.fmt.minus = true
+ p.fmt.zero = false // Do not pad with zeros to the right.
}
afterIndex = false
} else {
@@ -1182,7 +1048,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.precPresent = false
}
if !p.fmt.precPresent {
- p.buf.Write(badPrecBytes)
+ p.buf.WriteString(badPrecString)
}
afterIndex = false
} else {
@@ -1199,80 +1065,77 @@ func (p *pp) doPrintf(format string, a []interface{}) {
}
if i >= end {
- p.buf.Write(noVerbBytes)
- continue
+ p.buf.WriteString(noVerbString)
+ break
}
- c, w := utf8.DecodeRuneInString(format[i:])
+
+ verb, w := utf8.DecodeRuneInString(format[i:])
i += w
- // percent is special - absorbs no operand
- if c == '%' {
- p.buf.WriteByte('%') // We ignore width and prec.
- continue
- }
- if !p.goodArgNum {
- p.buf.Write(percentBangBytes)
- p.add(c)
- p.buf.Write(badIndexBytes)
- continue
- } else if argNum >= len(a) { // out of operands
- p.buf.Write(percentBangBytes)
- p.add(c)
- p.buf.Write(missingBytes)
- continue
- }
- arg := a[argNum]
- argNum++
-
- if c == 'v' {
- if p.fmt.sharp {
- // Go syntax. Set the flag in the fmt and clear the sharp flag.
- p.fmt.sharp = false
- p.fmt.sharpV = true
- }
- if p.fmt.plus {
- // Struct-field syntax. Set the flag in the fmt and clear the plus flag.
- p.fmt.plus = false
- p.fmt.plusV = true
- }
+
+ switch {
+ case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
+ p.buf.WriteByte('%')
+ case !p.goodArgNum:
+ p.badArgNum(verb)
+ case argNum >= len(a): // No argument left over to print for the current verb.
+ p.missingArg(verb)
+ case verb == 'v':
+ // Go syntax
+ p.fmt.sharpV = p.fmt.sharp
+ p.fmt.sharp = false
+ // Struct-field syntax
+ p.fmt.plusV = p.fmt.plus
+ p.fmt.plus = false
+ fallthrough
+ default:
+ p.printArg(a[argNum], verb)
+ argNum++
}
- p.printArg(arg, c, 0)
}
// Check for extra arguments unless the call accessed the arguments
// out of order, in which case it's too expensive to detect if they've all
// been used and arguably OK if they're not.
if !p.reordered && argNum < len(a) {
- p.buf.Write(extraBytes)
- for ; argNum < len(a); argNum++ {
- arg := a[argNum]
- if arg != nil {
+ p.fmt.clearflags()
+ p.buf.WriteString(extraString)
+ for i, arg := range a[argNum:] {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ if arg == nil {
+ p.buf.WriteString(nilAngleString)
+ } else {
p.buf.WriteString(reflect.TypeOf(arg).String())
p.buf.WriteByte('=')
- }
- p.printArg(arg, 'v', 0)
- if argNum+1 < len(a) {
- p.buf.Write(commaSpaceBytes)
+ p.printArg(arg, 'v')
}
}
p.buf.WriteByte(')')
}
}
-func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+func (p *pp) doPrint(a []interface{}) {
prevString := false
- for argNum := 0; argNum < len(a); argNum++ {
- p.fmt.clearflags()
- // always add spaces if we're doing Println
- arg := a[argNum]
- if argNum > 0 {
- isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
- if addspace || !isString && !prevString {
- p.buf.WriteByte(' ')
- }
+ for argNum, arg := range a {
+ isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
+ // Add a space between two non-string arguments.
+ if argNum > 0 && !isString && !prevString {
+ p.buf.WriteByte(' ')
}
- prevString = p.printArg(arg, 'v', 0)
+ p.printArg(arg, 'v')
+ prevString = isString
}
- if addnewline {
- p.buf.WriteByte('\n')
+}
+
+// doPrintln is like doPrint but always adds a space between arguments
+// and a newline after the last argument.
+func (p *pp) doPrintln(a []interface{}) {
+ for argNum, arg := range a {
+ if argNum > 0 {
+ p.buf.WriteByte(' ')
+ }
+ p.printArg(arg, 'v')
}
+ p.buf.WriteByte('\n')
}
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index 4618ed4a82..cd7232c33c 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -15,14 +15,6 @@ import (
"unicode/utf8"
)
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
- UnreadRune() error
-}
-
// ScanState represents the scanner state passed to custom scanners.
// Scanners may do rune-at-a-time scanning or ask the ScanState
// to discover the next space-delimited token.
@@ -41,7 +33,7 @@ type ScanState interface {
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated appropriately for the operation being
+ // characters. Newlines are treated appropriately for the operation being
// performed; see the package documentation for more information.
// The returned slice points to shared data that may be overwritten
// by the next call to Token, a call to a Scan function using the ScanState
@@ -58,15 +50,15 @@ type ScanState interface {
// Scanner is implemented by any value that has a Scan method, which scans
// the input for the representation of a value and stores the result in the
-// receiver, which must be a pointer to be useful. The Scan method is called
+// receiver, which must be a pointer to be useful. The Scan method is called
// for any argument to Scan, Scanf, or Scanln that implements it.
type Scanner interface {
Scan(state ScanState, verb rune) error
}
// Scan scans text read from standard input, storing successive
-// space-separated values into successive arguments. Newlines count
-// as space. It returns the number of items successfully scanned.
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
@@ -80,7 +72,7 @@ func Scanln(a ...interface{}) (n int, err error) {
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
-// the format. It returns the number of items successfully scanned.
+// the format. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
// Newlines in the input must match newlines in the format.
// The one exception: the verb %c always scans the next rune in the
@@ -101,8 +93,8 @@ func (r *stringReader) Read(b []byte) (n int, err error) {
}
// Sscan scans the argument string, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
func Sscan(str string, a ...interface{}) (n int, err error) {
return Fscan((*stringReader)(&str), a...)
@@ -115,7 +107,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
}
// Sscanf scans the argument string, storing successive space-separated
-// values into successive arguments as determined by the format. It
+// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
// Newlines in the input must match newlines in the format.
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
@@ -123,8 +115,8 @@ func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
}
// Fscan scans text read from r, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, true, false)
@@ -143,7 +135,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
}
// Fscanf scans text read from r, storing successive space-separated
-// values into successive arguments as determined by the format. It
+// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
// Newlines in the input must match newlines in the format.
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
@@ -163,12 +155,10 @@ const eof = -1
// ss is the internal implementation of ScanState.
type ss struct {
- rr io.RuneReader // where to read input
- buf buffer // token accumulator
- peekRune rune // one-rune lookahead
- prevRune rune // last rune returned by ReadRune
- count int // runes consumed so far.
- atEOF bool // already read EOF
+ rs io.RuneScanner // where to read input
+ buf buffer // token accumulator
+ count int // runes consumed so far.
+ atEOF bool // already read EOF
ssave
}
@@ -191,23 +181,17 @@ func (s *ss) Read(buf []byte) (n int, err error) {
}
func (s *ss) ReadRune() (r rune, size int, err error) {
- if s.peekRune >= 0 {
- s.count++
- r = s.peekRune
- size = utf8.RuneLen(r)
- s.prevRune = r
- s.peekRune = -1
- return
- }
- if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.argLimit {
+ if s.atEOF || s.count >= s.argLimit {
err = io.EOF
return
}
- r, size, err = s.rr.ReadRune()
+ r, size, err = s.rs.ReadRune()
if err == nil {
s.count++
- s.prevRune = r
+ if s.nlIsEnd && r == '\n' {
+ s.atEOF = true
+ }
} else if err == io.EOF {
s.atEOF = true
}
@@ -246,12 +230,8 @@ func (s *ss) mustReadRune() (r rune) {
}
func (s *ss) UnreadRune() error {
- if u, ok := s.rr.(runeUnreader); ok {
- u.UnreadRune()
- } else {
- s.peekRune = s.prevRune
- }
- s.prevRune = -1
+ s.rs.UnreadRune()
+ s.atEOF = false
s.count--
return nil
}
@@ -326,13 +306,14 @@ func (s *ss) SkipSpace() {
}
// readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader. It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneScanner.
type readRune struct {
- reader io.Reader
- buf [utf8.UTFMax]byte // used only inside ReadRune
- pending int // number of bytes in pendBuf; only >0 for bad UTF-8
- pendBuf [utf8.UTFMax]byte // bytes left over
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+ peekRune rune // if >=0 next rune; when <0 is ^(previous Rune)
}
// readByte returns the next byte from the input, which may be
@@ -344,33 +325,35 @@ func (r *readRune) readByte() (b byte, err error) {
r.pending--
return
}
- n, err := io.ReadFull(r.reader, r.pendBuf[0:1])
+ n, err := io.ReadFull(r.reader, r.pendBuf[:1])
if n != 1 {
return 0, err
}
return r.pendBuf[0], err
}
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
- copy(r.pendBuf[r.pending:], buf)
- r.pending += len(buf)
-}
-
// ReadRune returns the next UTF-8 encoded code point from the
// io.Reader inside r.
func (r *readRune) ReadRune() (rr rune, size int, err error) {
+ if r.peekRune >= 0 {
+ rr = r.peekRune
+ r.peekRune = ^r.peekRune
+ size = utf8.RuneLen(rr)
+ return
+ }
r.buf[0], err = r.readByte()
if err != nil {
- return 0, 0, err
+ return
}
if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
rr = rune(r.buf[0])
size = 1 // Known to be 1.
+ // Flip the bits of the rune so it's available to UnreadRune.
+ r.peekRune = ^rr
return
}
var n int
- for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ for n = 1; !utf8.FullRune(r.buf[:n]); n++ {
r.buf[n], err = r.readByte()
if err != nil {
if err == io.EOF {
@@ -380,13 +363,25 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
return
}
}
- rr, size = utf8.DecodeRune(r.buf[0:n])
- if size < n { // an error
- r.unread(r.buf[size:n])
+ rr, size = utf8.DecodeRune(r.buf[:n])
+ if size < n { // an error, save the bytes for the next read
+ copy(r.pendBuf[r.pending:], r.buf[size:n])
+ r.pending += n - size
}
+ // Flip the bits of the rune so it's available to UnreadRune.
+ r.peekRune = ^rr
return
}
+func (r *readRune) UnreadRune() error {
+ if r.peekRune >= 0 {
+ return errors.New("fmt: scanning called UnreadRune with no rune available")
+ }
+ // Reverse bit flip of previously read rune to obtain valid >=0 state.
+ r.peekRune = ^r.peekRune
+ return nil
+}
+
var ssFree = sync.Pool{
New: func() interface{} { return new(ss) },
}
@@ -394,15 +389,13 @@ var ssFree = sync.Pool{
// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
s = ssFree.Get().(*ss)
- if rr, ok := r.(io.RuneReader); ok {
- s.rr = rr
+ if rs, ok := r.(io.RuneScanner); ok {
+ s.rs = rs
} else {
- s.rr = &readRune{reader: r}
+ s.rs = &readRune{reader: r, peekRune: -1}
}
s.nlIsSpace = nlIsSpace
s.nlIsEnd = nlIsEnd
- s.prevRune = -1
- s.peekRune = -1
s.atEOF = false
s.limit = hugeWid
s.argLimit = hugeWid
@@ -424,7 +417,7 @@ func (s *ss) free(old ssave) {
return
}
s.buf = s.buf[:0]
- s.rr = nil
+ s.rs = nil
ssFree.Put(s)
}
@@ -455,8 +448,8 @@ func (s *ss) skipSpace(stopAtNewline bool) {
}
}
-// token returns the next space-delimited string from the input. It
-// skips white space. For Scanln, it stops at newlines. For Scan,
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
// newlines are treated as spaces.
func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
if skipSpace {
@@ -525,7 +518,7 @@ func (s *ss) notEOF() {
s.UnreadRune()
}
-// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
// buffer and returns true. Otherwise it return false.
func (s *ss) accept(ok string) bool {
return s.consume(ok, true)
@@ -549,7 +542,7 @@ func (s *ss) scanBool(verb rune) bool {
if !s.okVerb(verb, "tv", "boolean") {
return false
}
- // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
switch s.getRune() {
case '0':
return false
@@ -643,7 +636,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
}
// scanInt returns the value of the integer represented by the next
-// token, checking for overflow. Any error is stored in s.err.
+// token, checking for overflow. Any error is stored in s.err.
func (s *ss) scanInt(verb rune, bitSize int) int64 {
if verb == 'c' {
return s.scanRune(bitSize)
@@ -676,7 +669,7 @@ func (s *ss) scanInt(verb rune, bitSize int) int64 {
}
// scanUint returns the value of the unsigned integer represented
-// by the next token, checking for overflow. Any error is stored in s.err.
+// by the next token, checking for overflow. Any error is stored in s.err.
func (s *ss) scanUint(verb rune, bitSize int) uint64 {
if verb == 'c' {
return uint64(s.scanRune(bitSize))
@@ -846,7 +839,7 @@ func (s *ss) quotedString() string {
return string(s.buf)
case '"':
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
- s.buf.WriteRune(quote)
+ s.buf.WriteByte('"')
for {
r := s.mustReadRune()
s.buf.WriteRune(r)
@@ -922,9 +915,14 @@ func (s *ss) hexString() string {
return string(s.buf)
}
-const floatVerbs = "beEfFgGv"
+const (
+ floatVerbs = "beEfFgGv"
-const hugeWid = 1 << 30
+ hugeWid = 1 << 30
+
+ intBits = 32 << (^uint(0) >> 63)
+ uintptrBits = 32 << (^uintptr(0) >> 63)
+)
// scanOne scans a single value, deriving the scanner from the type of the argument.
func (s *ss) scanOne(verb rune, arg interface{}) {
@@ -1077,6 +1075,58 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
func (s *ss) advance(format string) (i int) {
for i < len(format) {
fmtc, w := utf8.DecodeRuneInString(format[i:])
+
+ // Space processing.
+ // In the rest of this comment "space" means spaces other than newline.
+ // Newline in the format matches input of zero or more spaces and then newline or end-of-input.
+ // Spaces in the format before the newline are collapsed into the newline.
+ // Spaces in the format after the newline match zero or more spaces after the corresponding input newline.
+ // Other spaces in the format match input of one or more spaces or end-of-input.
+ if isSpace(fmtc) {
+ newlines := 0
+ trailingSpace := false
+ for isSpace(fmtc) && i < len(format) {
+ if fmtc == '\n' {
+ newlines++
+ trailingSpace = false
+ } else {
+ trailingSpace = true
+ }
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ for j := 0; j < newlines; j++ {
+ inputc := s.getRune()
+ for isSpace(inputc) && inputc != '\n' {
+ inputc = s.getRune()
+ }
+ if inputc != '\n' && inputc != eof {
+ s.errorString("newline in format does not match input")
+ }
+ }
+ if trailingSpace {
+ inputc := s.getRune()
+ if newlines == 0 {
+ // If the trailing space stood alone (did not follow a newline),
+ // it must find at least one space to consume.
+ if !isSpace(inputc) && inputc != eof {
+ s.errorString("expected space in input to match format")
+ }
+ if inputc == '\n' {
+ s.errorString("newline in input does not match format")
+ }
+ }
+ for isSpace(inputc) && inputc != '\n' {
+ inputc = s.getRune()
+ }
+ if inputc != eof {
+ s.UnreadRune()
+ }
+ }
+ continue
+ }
+
+ // Verbs.
if fmtc == '%' {
// % at end of string is an error.
if i+w == len(format) {
@@ -1089,48 +1139,8 @@ func (s *ss) advance(format string) (i int) {
}
i += w // skip the first %
}
- sawSpace := false
- wasNewline := false
- // Skip spaces in format but absorb at most one newline.
- for isSpace(fmtc) && i < len(format) {
- if fmtc == '\n' {
- if wasNewline { // Already saw one; stop here.
- break
- }
- wasNewline = true
- }
- sawSpace = true
- i += w
- fmtc, w = utf8.DecodeRuneInString(format[i:])
- }
- if sawSpace {
- // There was space in the format, so there should be space
- // in the input.
- inputc := s.getRune()
- if inputc == eof {
- return
- }
- if !isSpace(inputc) {
- // Space in format but not in input.
- s.errorString("expected space in input to match format")
- }
- // Skip spaces but stop at newline.
- for inputc != '\n' && isSpace(inputc) {
- inputc = s.getRune()
- }
- if inputc == '\n' {
- if !wasNewline {
- s.errorString("newline in input does not match format")
- }
- // We've reached a newline, stop now; don't read further.
- return
- }
- s.UnreadRune()
- if wasNewline {
- s.errorString("newline in format does not match input")
- }
- continue
- }
+
+ // Literals.
inputc := s.mustReadRune()
if fmtc != inputc {
s.UnreadRune()
@@ -1142,7 +1152,7 @@ func (s *ss) advance(format string) (i int) {
}
// doScanf does the real work when scanning with a format string.
-// At the moment, it handles only pointers to basic types.
+// At the moment, it handles only pointers to basic types.
func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
end := len(format) - 1
@@ -1155,7 +1165,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
}
// Either we failed to advance, we have a percent character, or we ran out of input.
if format[i] != '%' {
- // Can't advance format. Why not?
+ // Can't advance format. Why not?
if w < 0 {
s.errorString("input does not match format")
}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index 7ac74dcb4b..d7019d9439 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -15,6 +15,7 @@ import (
"regexp"
"strings"
"testing"
+ "testing/iotest"
"unicode/utf8"
)
@@ -78,12 +79,6 @@ var (
renamedComplex128Val renamedComplex128
)
-type FloatTest struct {
- text string
- in float64
- out float64
-}
-
// Xs accepts any non-empty run of the verb character
type Xs string
@@ -124,20 +119,6 @@ func (s *IntString) Scan(state ScanState, verb rune) error {
var intStringVal IntString
-// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
-// type that creates something that can read runes given only Read().
-type myStringReader struct {
- r *strings.Reader
-}
-
-func (s *myStringReader) Read(p []byte) (n int, err error) {
- return s.r.Read(p)
-}
-
-func newReader(s string) *myStringReader {
- return &myStringReader{strings.NewReader(s)}
-}
-
var scanTests = []ScanTest{
// Basic types
{"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
@@ -310,6 +291,97 @@ var scanfTests = []ScanfTest{
{"%c", " ", &uintVal, uint(' ')}, // %c must accept a blank.
{"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space.
{"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space.
+
+ // space handling
+ {"%d", "27", &intVal, 27},
+ {"%d", "27 ", &intVal, 27},
+ {"%d", " 27", &intVal, 27},
+ {"%d", " 27 ", &intVal, 27},
+
+ {"X%d", "X27", &intVal, 27},
+ {"X%d", "X27 ", &intVal, 27},
+ {"X%d", "X 27", &intVal, 27},
+ {"X%d", "X 27 ", &intVal, 27},
+
+ {"X %d", "X27", &intVal, nil}, // expected space in input to match format
+ {"X %d", "X27 ", &intVal, nil}, // expected space in input to match format
+ {"X %d", "X 27", &intVal, 27},
+ {"X %d", "X 27 ", &intVal, 27},
+
+ {"%dX", "27X", &intVal, 27},
+ {"%dX", "27 X", &intVal, nil}, // input does not match format
+ {"%dX", " 27X", &intVal, 27},
+ {"%dX", " 27 X", &intVal, nil}, // input does not match format
+
+ {"%d X", "27X", &intVal, nil}, // expected space in input to match format
+ {"%d X", "27 X", &intVal, 27},
+ {"%d X", " 27X", &intVal, nil}, // expected space in input to match format
+ {"%d X", " 27 X", &intVal, 27},
+
+ {"X %d X", "X27X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X27 X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X 27X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X 27 X", &intVal, 27},
+
+ {"X %s X", "X27X", &stringVal, nil}, // expected space in input to match format
+ {"X %s X", "X27 X", &stringVal, nil}, // expected space in input to match format
+ {"X %s X", "X 27X", &stringVal, nil}, // unexpected EOF
+ {"X %s X", "X 27 X", &stringVal, "27"},
+
+ {"X%sX", "X27X", &stringVal, nil}, // unexpected EOF
+ {"X%sX", "X27 X", &stringVal, nil}, // input does not match format
+ {"X%sX", "X 27X", &stringVal, nil}, // unexpected EOF
+ {"X%sX", "X 27 X", &stringVal, nil}, // input does not match format
+
+ {"X%s", "X27", &stringVal, "27"},
+ {"X%s", "X27 ", &stringVal, "27"},
+ {"X%s", "X 27", &stringVal, "27"},
+ {"X%s", "X 27 ", &stringVal, "27"},
+
+ {"X%dX", "X27X", &intVal, 27},
+ {"X%dX", "X27 X", &intVal, nil}, // input does not match format
+ {"X%dX", "X 27X", &intVal, 27},
+ {"X%dX", "X 27 X", &intVal, nil}, // input does not match format
+
+ {"X%dX", "X27X", &intVal, 27},
+ {"X%dX", "X27X ", &intVal, 27},
+ {"X%dX", " X27X", &intVal, nil}, // input does not match format
+ {"X%dX", " X27X ", &intVal, nil}, // input does not match format
+
+ {"X%dX\n", "X27X", &intVal, 27},
+ {"X%dX \n", "X27X ", &intVal, 27},
+ {"X%dX\n", "X27X\n", &intVal, 27},
+ {"X%dX\n", "X27X \n", &intVal, 27},
+
+ {"X%dX \n", "X27X", &intVal, 27},
+ {"X%dX \n", "X27X ", &intVal, 27},
+ {"X%dX \n", "X27X\n", &intVal, 27},
+ {"X%dX \n", "X27X \n", &intVal, 27},
+
+ {"X%c", "X\n", &runeVal, '\n'},
+ {"X%c", "X \n", &runeVal, ' '},
+ {"X %c", "X!", &runeVal, nil}, // expected space in input to match format
+ {"X %c", "X\n", &runeVal, nil}, // newline in input does not match format
+ {"X %c", "X !", &runeVal, '!'},
+ {"X %c", "X \n", &runeVal, '\n'},
+
+ {" X%dX", "X27X", &intVal, nil}, // expected space in input to match format
+ {" X%dX", "X27X ", &intVal, nil}, // expected space in input to match format
+ {" X%dX", " X27X", &intVal, 27},
+ {" X%dX", " X27X ", &intVal, 27},
+
+ {"X%dX ", "X27X", &intVal, 27},
+ {"X%dX ", "X27X ", &intVal, 27},
+ {"X%dX ", " X27X", &intVal, nil}, // input does not match format
+ {"X%dX ", " X27X ", &intVal, nil}, // input does not match format
+
+ {" X%dX ", "X27X", &intVal, nil}, // expected space in input to match format
+ {" X%dX ", "X27X ", &intVal, nil}, // expected space in input to match format
+ {" X%dX ", " X27X", &intVal, 27},
+ {" X%dX ", " X27X ", &intVal, 27},
+
+ {"%d\nX", "27\nX", &intVal, 27},
+ {"%dX\n X", "27X\n X", &intVal, 27},
}
var overflowTests = []ScanTest{
@@ -369,25 +441,38 @@ var multiTests = []ScanfMultiTest{
{"%v%v", "FALSE23", args(&truth, &i), args(false, 23), ""},
}
-func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
+var readers = []struct {
+ name string
+ f func(string) io.Reader
+}{
+ {"StringReader", func(s string) io.Reader {
+ return strings.NewReader(s)
+ }},
+ {"ReaderOnly", func(s string) io.Reader {
+ return struct{ io.Reader }{strings.NewReader(s)}
+ }},
+ {"OneByteReader", func(s string) io.Reader {
+ return iotest.OneByteReader(strings.NewReader(s))
+ }},
+ {"DataErrReader", func(s string) io.Reader {
+ return iotest.DataErrReader(strings.NewReader(s))
+ }},
+}
+
+func testScan(t *testing.T, f func(string) io.Reader, scan func(r io.Reader, a ...interface{}) (int, error)) {
for _, test := range scanTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := scan(r, test.in)
if err != nil {
m := ""
if n > 0 {
m = Sprintf(" (%d fields ok)", n)
}
- t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
+ t.Errorf("got error scanning %q: %s%s", test.text, err, m)
continue
}
if n != 1 {
- t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+ t.Errorf("count error on entry %q: got %d", test.text, n)
continue
}
// The incoming value may be a pointer
@@ -397,36 +482,42 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("scanning %q: expected %#v got %#v, type %T", test.text, test.out, val, val)
}
}
}
func TestScan(t *testing.T) {
- testScan("StringReader", t, Fscan)
-}
-
-func TestMyReaderScan(t *testing.T) {
- testScan("myStringReader", t, Fscan)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscan)
+ })
+ }
}
func TestScanln(t *testing.T) {
- testScan("StringReader", t, Fscanln)
-}
-
-func TestMyReaderScanln(t *testing.T) {
- testScan("myStringReader", t, Fscanln)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscanln)
+ })
+ }
}
func TestScanf(t *testing.T) {
for _, test := range scanfTests {
n, err := Sscanf(test.text, test.format, test.in)
if err != nil {
- t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+ if test.out != nil {
+ t.Errorf("Sscanf(%q, %q): unexpected error: %v", test.text, test.format, err)
+ }
+ continue
+ }
+ if test.out == nil {
+ t.Errorf("Sscanf(%q, %q): unexpected success", test.text, test.format)
continue
}
if n != 1 {
- t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+ t.Errorf("Sscanf(%q, %q): parsed %d field, want 1", test.text, test.format, n)
continue
}
// The incoming value may be a pointer
@@ -436,7 +527,7 @@ func TestScanf(t *testing.T) {
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
+ t.Errorf("Sscanf(%q, %q): parsed value %T(%#v), want %T(%#v)", test.text, test.format, val, val, test.out, test.out)
}
}
}
@@ -506,20 +597,15 @@ func TestInf(t *testing.T) {
}
}
-func testScanfMulti(name string, t *testing.T) {
+func testScanfMulti(t *testing.T, f func(string) io.Reader) {
sliceType := reflect.TypeOf(make([]interface{}, 1))
for _, test := range multiTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := Fscanf(r, test.format, test.in...)
if err != nil {
if test.err == "" {
t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
- } else if strings.Index(err.Error(), test.err) < 0 {
+ } else if !strings.Contains(err.Error(), test.err) {
t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
}
continue
@@ -545,11 +631,11 @@ func testScanfMulti(name string, t *testing.T) {
}
func TestScanfMulti(t *testing.T) {
- testScanfMulti("StringReader", t)
-}
-
-func TestMyReaderScanfMulti(t *testing.T) {
- testScanfMulti("myStringReader", t)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScanfMulti(t, r.f)
+ })
+ }
}
func TestScanMultiple(t *testing.T) {
@@ -613,7 +699,7 @@ func TestScanNotPointer(t *testing.T) {
_, err := Fscan(r, a)
if err == nil {
t.Error("expected error scanning non-pointer")
- } else if strings.Index(err.Error(), "pointer") < 0 {
+ } else if !strings.Contains(err.Error(), "pointer") {
t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
}
}
@@ -623,7 +709,7 @@ func TestScanlnNoNewline(t *testing.T) {
_, err := Sscanln("1 x\n", &a)
if err == nil {
t.Error("expected error scanning string missing newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string missing newline, got: %s", err)
}
}
@@ -634,7 +720,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
_, err := Fscanln(r, &a, &b)
if err == nil {
t.Error("expected error scanning string with extra newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
@@ -767,7 +853,7 @@ func TestUnreadRuneWithBufio(t *testing.T) {
type TwoLines string
-// Scan attempts to read two lines into the object. Scanln should prevent this
+// Scan attempts to read two lines into the object. Scanln should prevent this
// because it stops at newline; Scan and Scanf should be fine.
func (t *TwoLines) Scan(state ScanState, verb rune) error {
chars := make([]rune, 0, 100)
@@ -824,20 +910,10 @@ func TestMultiLine(t *testing.T) {
}
}
-// simpleReader is a strings.Reader that implements only Read, not ReadRune.
-// Good for testing readahead.
-type simpleReader struct {
- sr *strings.Reader
-}
-
-func (s *simpleReader) Read(b []byte) (n int, err error) {
- return s.sr.Read(b)
-}
-
// TestLineByLineFscanf tests that Fscanf does not read past newline. Issue
// 3481.
func TestLineByLineFscanf(t *testing.T) {
- r := &simpleReader{strings.NewReader("1\n2\n")}
+ r := struct{ io.Reader }{strings.NewReader("1\n2\n")}
var i, j int
n, err := Fscanf(r, "%v\n", &i)
if n != 1 || err != nil {
@@ -1001,6 +1077,18 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
}
}
+func BenchmarkScanRecursiveIntReaderWrapper(b *testing.B) {
+ b.ResetTimer()
+ ints := makeInts(intCount)
+ var r RecursiveInt
+ for i := b.N - 1; i >= 0; i-- {
+ buf := struct{ io.Reader }{strings.NewReader(string(ints))}
+ b.StartTimer()
+ Fscan(buf, &r)
+ b.StopTimer()
+ }
+}
+
// Issue 9124.
// %x on bytes couldn't handle non-space bytes terminating the scan.
func TestHexBytes(t *testing.T) {
@@ -1122,9 +1210,47 @@ func TestScanfNewlineMatchFormat(t *testing.T) {
{"space-newline in both", "1 \n2", "%d \n%d", 2, true},
{"extra space in format", "1\n2", "%d\n %d", 2, true},
{"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
+ {"space vs newline 0000", "1\n2", "%d\n%d", 2, true},
+ {"space vs newline 0001", "1\n2", "%d\n %d", 2, true},
+ {"space vs newline 0010", "1\n2", "%d \n%d", 2, true},
+ {"space vs newline 0011", "1\n2", "%d \n %d", 2, true},
+ {"space vs newline 0100", "1\n 2", "%d\n%d", 2, true},
+ {"space vs newline 0101", "1\n 2", "%d\n%d ", 2, true},
+ {"space vs newline 0110", "1\n 2", "%d \n%d", 2, true},
+ {"space vs newline 0111", "1\n 2", "%d \n %d", 2, true},
+ {"space vs newline 1000", "1 \n2", "%d\n%d", 2, true},
+ {"space vs newline 1001", "1 \n2", "%d\n %d", 2, true},
+ {"space vs newline 1010", "1 \n2", "%d \n%d", 2, true},
+ {"space vs newline 1011", "1 \n2", "%d \n %d", 2, true},
+ {"space vs newline 1100", "1 \n 2", "%d\n%d", 2, true},
+ {"space vs newline 1101", "1 \n 2", "%d\n %d", 2, true},
+ {"space vs newline 1110", "1 \n 2", "%d \n%d", 2, true},
+ {"space vs newline 1111", "1 \n 2", "%d \n %d", 2, true},
+ {"space vs newline no-percent 0000", "1\n2", "1\n2", 0, true},
+ {"space vs newline no-percent 0001", "1\n2", "1\n 2", 0, true},
+ {"space vs newline no-percent 0010", "1\n2", "1 \n2", 0, true},
+ {"space vs newline no-percent 0011", "1\n2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 0100", "1\n 2", "1\n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0101", "1\n 2", "1\n2 ", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0110", "1\n 2", "1 \n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0111", "1\n 2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 1000", "1 \n2", "1\n2", 0, true},
+ {"space vs newline no-percent 1001", "1 \n2", "1\n 2", 0, true},
+ {"space vs newline no-percent 1010", "1 \n2", "1 \n2", 0, true},
+ {"space vs newline no-percent 1011", "1 \n2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 1100", "1 \n 2", "1\n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 1101", "1 \n 2", "1\n 2", 0, true},
+ {"space vs newline no-percent 1110", "1 \n 2", "1 \n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 1111", "1 \n 2", "1 \n 2", 0, true},
}
for _, test := range tests {
- n, err := Sscanf(test.text, test.format, &a, &b)
+ var n int
+ var err error
+ if strings.Contains(test.format, "%") {
+ n, err = Sscanf(test.text, test.format, &a, &b)
+ } else {
+ n, err = Sscanf(test.text, test.format)
+ }
if n != test.count {
t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
}
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
index 5ab4283826..a197b5a5bf 100644
--- a/libgo/go/go/ast/ast.go
+++ b/libgo/go/go/ast/ast.go
@@ -99,7 +99,7 @@ func (g *CommentGroup) Text() string {
}
comments := make([]string, len(g.List))
for i, c := range g.List {
- comments[i] = string(c.Text)
+ comments[i] = c.Text
}
lines := make([]string, 0, 10) // most comments are less than 10 lines
@@ -317,7 +317,7 @@ type (
Fun Expr // function expression
Lparen token.Pos // position of "("
Args []Expr // function arguments; or nil
- Ellipsis token.Pos // position of "...", if any
+ Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
Rparen token.Pos // position of ")"
}
@@ -418,7 +418,7 @@ type (
)
// Pos and End implementations for expression/type nodes.
-//
+
func (x *BadExpr) Pos() token.Pos { return x.From }
func (x *Ident) Pos() token.Pos { return x.NamePos }
func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
@@ -709,7 +709,7 @@ type (
)
// Pos and End implementations for statement nodes.
-//
+
func (s *BadStmt) Pos() token.Pos { return s.From }
func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
@@ -854,7 +854,7 @@ type (
)
// Pos and End implementations for spec nodes.
-//
+
func (s *ImportSpec) Pos() token.Pos {
if s.Name != nil {
return s.Name.Pos()
@@ -902,7 +902,7 @@ type (
// A GenDecl node (generic declaration node) represents an import,
// constant, type or variable declaration. A valid Lparen position
- // (Lparen.Line > 0) indicates a parenthesized declaration.
+ // (Lparen.IsValid()) indicates a parenthesized declaration.
//
// Relationship between Tok value and Specs element type:
//
@@ -931,7 +931,7 @@ type (
)
// Pos and End implementations for declaration nodes.
-//
+
func (d *BadDecl) Pos() token.Pos { return d.From }
func (d *GenDecl) Pos() token.Pos { return d.TokPos }
func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
diff --git a/libgo/go/go/ast/commentmap.go b/libgo/go/go/ast/commentmap.go
index ac999d627c..2a653a60ac 100644
--- a/libgo/go/go/ast/commentmap.go
+++ b/libgo/go/go/ast/commentmap.go
@@ -267,7 +267,7 @@ func (cmap CommentMap) Filter(node Node) CommentMap {
}
// Comments returns the list of comment groups in the comment map.
-// The result is sorted is source order.
+// The result is sorted in source order.
//
func (cmap CommentMap) Comments() []*CommentGroup {
list := make([]*CommentGroup, 0, len(cmap))
diff --git a/libgo/go/go/ast/import.go b/libgo/go/go/ast/import.go
index 5c794c3e79..6b27fe822e 100644
--- a/libgo/go/go/ast/import.go
+++ b/libgo/go/go/ast/import.go
@@ -31,7 +31,7 @@ func SortImports(fset *token.FileSet, f *File) {
specs := d.Specs[:0]
for j, s := range d.Specs {
if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
- // j begins a new run. End this one.
+ // j begins a new run. End this one.
specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
i = j
}
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
index f15dc11dc0..d86d9ba64b 100644
--- a/libgo/go/go/ast/print.go
+++ b/libgo/go/go/ast/print.go
@@ -36,8 +36,11 @@ func NotNilFilter(_ string, v reflect.Value) bool {
// struct fields for which f(fieldname, fieldvalue) is true are
// printed; all others are filtered from the output. Unexported
// struct fields are never printed.
-//
-func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) error {
+ return fprint(w, fset, x, f)
+}
+
+func fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
// setup printer
p := printer{
output: w,
diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go
index 0406bfc584..c1830b5e4d 100644
--- a/libgo/go/go/ast/resolve.go
+++ b/libgo/go/go/ast/resolve.go
@@ -56,7 +56,7 @@ func resolve(scope *Scope, ident *Ident) bool {
// indexed by package id (canonical import path).
// An Importer must determine the canonical import path and
// check the map to see if it is already present in the imports map.
-// If so, the Importer can return the map entry. Otherwise, the
+// If so, the Importer can return the map entry. Otherwise, the
// Importer should load the package data for the given path into
// a new *Object (pkg), record pkg in the imports map, and then
// return pkg.
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
index 1ce5e2e84b..a400c7152a 100644
--- a/libgo/go/go/ast/scope.go
+++ b/libgo/go/go/ast/scope.go
@@ -70,10 +70,8 @@ func (s *Scope) String() string {
// The Data fields contains object-specific data:
//
// Kind Data type Data value
-// Pkg *types.Package package scope
+// Pkg *Scope package scope
// Con int iota for the respective declaration
-// Con != nil constant value
-// Typ *Scope (used as method scope during type checking - transient)
//
type Object struct {
Kind ObjKind
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
index 2f570c334d..4e1b29fecd 100644
--- a/libgo/go/go/build/build.go
+++ b/libgo/go/go/build/build.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -55,8 +55,8 @@ type Context struct {
InstallSuffix string
// By default, Import uses the operating system's file system calls
- // to read directories and files. To read from other sources,
- // callers can set the following functions. They all have default
+ // to read directories and files. To read from other sources,
+ // callers can set the following functions. They all have default
// behaviors that use the local file system, so clients need only set
// the functions whose behaviors they wish to change.
@@ -76,8 +76,9 @@ type Context struct {
// If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
IsDir func(path string) bool
- // HasSubdir reports whether dir is a subdirectory of
- // (perhaps multiple levels below) root.
+ // HasSubdir reports whether dir is lexically a subdirectory of
+ // root, perhaps multiple levels below. It does not try to check
+ // whether dir exists.
// If so, HasSubdir sets rel to a slash-separated path that
// can be joined to root to produce a path equivalent to dir.
// If HasSubdir is nil, Import uses an implementation built on
@@ -87,11 +88,11 @@ type Context struct {
// ReadDir returns a slice of os.FileInfo, sorted by Name,
// describing the content of the named directory.
// If ReadDir is nil, Import uses ioutil.ReadDir.
- ReadDir func(dir string) (fi []os.FileInfo, err error)
+ ReadDir func(dir string) ([]os.FileInfo, error)
// OpenFile opens a file (not a directory) for reading.
// If OpenFile is nil, Import uses os.Open.
- OpenFile func(path string) (r io.ReadCloser, err error)
+ OpenFile func(path string) (io.ReadCloser, error)
}
// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
@@ -256,37 +257,23 @@ func (ctxt *Context) SrcDirs() []string {
// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
var Default Context = defaultContext()
-// Also known to cmd/dist/build.go.
-var cgoEnabled = map[string]bool{
- "darwin/386": true,
- "darwin/amd64": true,
- "darwin/arm": true,
- "darwin/arm64": true,
- "dragonfly/amd64": true,
- "freebsd/386": true,
- "freebsd/amd64": true,
- "freebsd/arm": true,
- "linux/386": true,
- "linux/alpha": true,
- "linux/amd64": true,
- "linux/arm": true,
- "linux/arm64": true,
- "linux/ppc": true,
- "linux/ppc64": true,
- "linux/ppc64le": true,
- "linux/s390": true,
- "linux/s390x": true,
- "android/386": true,
- "android/amd64": true,
- "android/arm": true,
- "netbsd/386": true,
- "netbsd/amd64": true,
- "netbsd/arm": true,
- "openbsd/386": true,
- "openbsd/amd64": true,
- "solaris/amd64": true,
- "windows/386": true,
- "windows/amd64": true,
+func defaultGOPATH() string {
+ env := "HOME"
+ if runtime.GOOS == "windows" {
+ env = "USERPROFILE"
+ } else if runtime.GOOS == "plan9" {
+ env = "home"
+ }
+ if home := os.Getenv(env); home != "" {
+ def := filepath.Join(home, "go")
+ if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
+ // Don't set the default GOPATH to GOROOT,
+ // as that will trigger warnings from the go tool.
+ return ""
+ }
+ return def
+ }
+ return ""
}
func defaultContext() Context {
@@ -295,7 +282,7 @@ func defaultContext() Context {
c.GOARCH = envOr("GOARCH", runtime.GOARCH)
c.GOOS = envOr("GOOS", runtime.GOOS)
c.GOROOT = pathpkg.Clean(runtime.GOROOT())
- c.GOPATH = envOr("GOPATH", "")
+ c.GOPATH = envOr("GOPATH", defaultGOPATH())
c.Compiler = runtime.Compiler
// Each major Go release in the Go 1.x series should add a tag here.
@@ -303,9 +290,14 @@ func defaultContext() Context {
// in all releases >= Go 1.x. Code that requires Go 1.x or later should
// say "+build go1.x", and code that should only be built before Go 1.x
// (perhaps it is the stub to use in that case) should say "+build !go1.x".
- c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"}
-
- switch os.Getenv("CGO_ENABLED") {
+ c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"}
+
+ env := os.Getenv("CGO_ENABLED")
+ // No defaultCGO_ENABLED in gccgo.
+ // if env == "" {
+ // env = defaultCGO_ENABLED
+ // }
+ switch env {
case "1":
c.CgoEnabled = true
case "0":
@@ -313,7 +305,8 @@ func defaultContext() Context {
default:
// cgo must be explicitly enabled for cross compilation builds
if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
- c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+ // Always enabled for gccgo.
+ c.CgoEnabled = true
break
}
c.CgoEnabled = false
@@ -335,12 +328,19 @@ type ImportMode uint
const (
// If FindOnly is set, Import stops after locating the directory
- // that should contain the sources for a package. It does not
+ // that should contain the sources for a package. It does not
// read any files in the directory.
FindOnly ImportMode = 1 << iota
// If AllowBinary is set, Import can be satisfied by a compiled
// package object without corresponding sources.
+ //
+ // Deprecated:
+ // The supported way to create a compiled-only package is to
+ // write source code containing a //go:binary-only-package comment at
+ // the top of the file. Such a package will be recognized
+ // regardless of this flag setting (because it has source code)
+ // and will have BinaryOnly set to true in the returned Package.
AllowBinary
// If ImportComment is set, parse import comments on package statements.
@@ -362,6 +362,11 @@ const (
// See golang.org/s/go15vendor for more information.
//
// Setting IgnoreVendor ignores vendor directories.
+ //
+ // In contrast to the package's ImportPath,
+ // the returned package's Imports, TestImports, and XTestImports
+ // are always the exact import paths from the source files:
+ // Import makes no attempt to resolve or check those paths.
IgnoreVendor
)
@@ -381,6 +386,7 @@ type Package struct {
PkgObj string // installed .a file
AllTags []string // tags that can influence file selection in this directory
ConflictDir string // this directory shadows Dir in $GOPATH
+ BinaryOnly bool // cannot be rebuilt from source (has //go:binary-only-package comment)
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -391,6 +397,7 @@ type Package struct {
CXXFiles []string // .cc, .cpp and .cxx source files
MFiles []string // .m (Objective-C) source files
HFiles []string // .h, .hh, .hpp and .hxx source files
+ FFiles []string // .f, .F, .for and .f90 Fortran source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
@@ -400,19 +407,20 @@ type Package struct {
CgoCFLAGS []string // Cgo CFLAGS directives
CgoCPPFLAGS []string // Cgo CPPFLAGS directives
CgoCXXFLAGS []string // Cgo CXXFLAGS directives
+ CgoFFLAGS []string // Cgo FFLAGS directives
CgoLDFLAGS []string // Cgo LDFLAGS directives
CgoPkgConfig []string // Cgo pkg-config directives
// Dependency information
- Imports []string // imports from GoFiles, CgoFiles
+ Imports []string // import paths from GoFiles, CgoFiles
ImportPos map[string][]token.Position // line information for Imports
// Test information
TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
+ TestImports []string // import paths from TestGoFiles
TestImportPos map[string][]token.Position // line information for TestImports
XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
+ XTestImports []string // import paths from XTestGoFiles
XTestImportPos map[string][]token.Position // line information for XTestImports
}
@@ -659,7 +667,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
format = "\t%s"
}
if len(tried.gopath) == 0 {
- paths = append(paths, "\t($GOPATH not set)")
+ paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
}
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
}
@@ -710,7 +718,7 @@ Found:
p.InvalidGoFiles = append(p.InvalidGoFiles, name)
}
- match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
+ match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags, &p.BinaryOnly)
if err != nil {
badFile(err)
continue
@@ -722,7 +730,7 @@ Found:
continue
}
- // Going to save the file. For non-Go files, can stop here.
+ // Going to save the file. For non-Go files, can stop here.
switch ext {
case ".c":
p.CFiles = append(p.CFiles, name)
@@ -736,6 +744,9 @@ Found:
case ".h", ".hh", ".hpp", ".hxx":
p.HFiles = append(p.HFiles, name)
continue
+ case ".f", ".F", ".for", ".f90":
+ p.FFiles = append(p.FFiles, name)
+ continue
case ".s":
p.SFiles = append(p.SFiles, name)
continue
@@ -1021,7 +1032,7 @@ func parseWord(data []byte) (word, rest []byte) {
// MatchFile considers the name of the file and may use ctxt.OpenFile to
// read some or all of the file's content.
func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
- match, _, _, err = ctxt.matchFile(dir, name, false, nil)
+ match, _, _, err = ctxt.matchFile(dir, name, false, nil, nil)
return
}
@@ -1033,7 +1044,7 @@ func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
// considers text until the first non-comment.
// If allTags is non-nil, matchFile records any encountered build tag
// by setting allTags[tag] = true.
-func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) {
+func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) {
if strings.HasPrefix(name, "_") ||
strings.HasPrefix(name, ".") {
return
@@ -1050,7 +1061,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
}
switch ext {
- case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+ case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
case ".syso":
// binary, no reading
@@ -1069,7 +1080,11 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
if strings.HasSuffix(filename, ".go") {
data, err = readImports(f, false, nil)
+ if strings.HasSuffix(filename, "_test.go") {
+ binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
+ }
} else {
+ binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
data, err = readComments(f)
}
f.Close()
@@ -1079,10 +1094,14 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
}
// Look for +build comments to accept or reject the file.
- if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
+ var sawBinaryOnly bool
+ if !ctxt.shouldBuild(data, allTags, &sawBinaryOnly) && !ctxt.UseAllFiles {
return
}
+ if binaryOnly != nil && sawBinaryOnly {
+ *binaryOnly = true
+ }
match = true
return
}
@@ -1108,6 +1127,11 @@ func ImportDir(dir string, mode ImportMode) (*Package, error) {
var slashslash = []byte("//")
+// Special comment denoting a binary-only package.
+// See https://golang.org/design/2775-binary-only-packages
+// for more about the design of binary-only packages.
+var binaryOnlyComment = []byte("//go:binary-only-package")
+
// shouldBuild reports whether it is okay to use this file,
// The rule is that in the file's leading run of // comments
// and blank lines, which must be followed by a blank line
@@ -1115,13 +1139,18 @@ var slashslash = []byte("//")
// lines beginning with '// +build' are taken as build directives.
//
// The file is accepted only if each such line lists something
-// matching the file. For example:
+// matching the file. For example:
//
// // +build windows linux
//
// marks the file as applicable only on Windows and Linux.
//
-func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
+// If shouldBuild finds a //go:binary-only-package comment in the file,
+// it sets *binaryOnly to true. Otherwise it does not change *binaryOnly.
+//
+func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool {
+ sawBinaryOnly := false
+
// Pass 1. Identify leading run of // comments and blank lines,
// which must be followed by a blank line.
end := 0
@@ -1156,6 +1185,9 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
}
line = bytes.TrimSpace(line)
if bytes.HasPrefix(line, slashslash) {
+ if bytes.Equal(line, binaryOnlyComment) {
+ sawBinaryOnly = true
+ }
line = bytes.TrimSpace(line[len(slashslash):])
if len(line) > 0 && line[0] == '+' {
// Looks like a comment +line.
@@ -1175,6 +1207,10 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
}
}
+ if binaryOnly != nil && sawBinaryOnly {
+ *binaryOnly = true
+ }
+
return allok
}
@@ -1241,6 +1277,8 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
case "CXXFLAGS":
di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
+ case "FFLAGS":
+ di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
case "LDFLAGS":
di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
case "pkg-config":
@@ -1256,7 +1294,7 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
// the result is safe for the shell.
func expandSrcDir(str string, srcdir string) (string, bool) {
// "\" delimited paths cause safeCgoName to fail
- // so convert native paths with a different delimeter
+ // so convert native paths with a different delimiter
// to "/" before starting (eg: on windows).
srcdir = filepath.ToSlash(srcdir)
@@ -1278,7 +1316,8 @@ func expandSrcDir(str string, srcdir string) (string, bool) {
// We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
// See golang.org/issue/6038.
// The @ is for OS X. See golang.org/issue/13720.
-const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@"
+// The % is for Jenkins. See golang.org/issue/16959.
+const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%"
const safeSpaces = " "
var safeBytes = []byte(safeSpaces + safeString)
@@ -1292,7 +1331,7 @@ func safeCgoName(s string, spaces bool) bool {
safe = safe[len(safeSpaces):]
}
for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safe, c) < 0 {
+ if c := s[i]; c < utf8.RuneSelf && bytes.IndexByte(safe, c) < 0 {
return false
}
}
@@ -1305,7 +1344,7 @@ func safeCgoName(s string, spaces bool) bool {
// Single quotes and double quotes are recognized to prevent splitting within the
// quoted region, and are removed from the resulting substrings. If a quote in s
// isn't closed err will be set and r will have the unclosed argument as the
-// last element. The backslash is used for escaping.
+// last element. The backslash is used for escaping.
//
// For example, the following string:
//
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
index 4d705b6fb2..2e2ff84fb1 100644
--- a/libgo/go/go/build/build_test.go
+++ b/libgo/go/go/build/build_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -152,28 +152,28 @@ func TestShouldBuild(t *testing.T) {
ctx := &Context{BuildTags: []string{"tag1"}}
m := map[string]bool{}
- if !ctx.shouldBuild([]byte(file1), m) {
+ if !ctx.shouldBuild([]byte(file1), m, nil) {
t.Errorf("shouldBuild(file1) = false, want true")
}
if !reflect.DeepEqual(m, want1) {
- t.Errorf("shoudBuild(file1) tags = %v, want %v", m, want1)
+ t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
}
m = map[string]bool{}
- if ctx.shouldBuild([]byte(file2), m) {
- t.Errorf("shouldBuild(file2) = true, want fakse")
+ if ctx.shouldBuild([]byte(file2), m, nil) {
+ t.Errorf("shouldBuild(file2) = true, want false")
}
if !reflect.DeepEqual(m, want2) {
- t.Errorf("shoudBuild(file2) tags = %v, want %v", m, want2)
+ t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
}
m = map[string]bool{}
ctx = &Context{BuildTags: nil}
- if !ctx.shouldBuild([]byte(file3), m) {
+ if !ctx.shouldBuild([]byte(file3), m, nil) {
t.Errorf("shouldBuild(file3) = false, want true")
}
if !reflect.DeepEqual(m, want3) {
- t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3)
+ t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
}
}
@@ -285,6 +285,7 @@ func TestShellSafety(t *testing.T) {
result bool
}{
{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
+ {"-I${SRCDIR}", "wtf$@%", "-Iwtf$@%", true},
{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
@@ -302,15 +303,14 @@ func TestShellSafety(t *testing.T) {
}
func TestImportVendor(t *testing.T) {
- t.Skip("skipping; hpack has moved to internal for now; golang.org/issue/14047")
testenv.MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
- p, err := ctxt.Import("golang.org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+ p, err := ctxt.Import("golang_org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err != nil {
- t.Fatalf("cannot find vendored golang.org/x/net/http2/hpack from net/http directory: %v", err)
+ t.Fatalf("cannot find vendored golang_org/x/net/http2/hpack from net/http directory: %v", err)
}
- want := "vendor/golang.org/x/net/http2/hpack"
+ want := "vendor/golang_org/x/net/http2/hpack"
if p.ImportPath != want {
t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
}
@@ -336,7 +336,7 @@ func TestImportVendorParentFailure(t *testing.T) {
ctxt := Default
ctxt.GOPATH = ""
// This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
- p, err := ctxt.Import("golang.org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+ p, err := ctxt.Import("golang_org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err == nil {
t.Fatalf("found empty parent in %s", p.Dir)
}
diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go
index c7cd8804da..147eaf6aba 100644
--- a/libgo/go/go/build/deps_test.go
+++ b/libgo/go/go/build/deps_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -21,7 +21,7 @@ import (
)
// pkgDeps defines the expected dependencies between packages in
-// the Go source tree. It is a statement of policy.
+// the Go source tree. It is a statement of policy.
// Changes should not be made to this map without prior discussion.
//
// The map contains two kinds of entries:
@@ -59,7 +59,6 @@ var pkgDeps = map[string][]string{
"math": {"unsafe"},
"math/cmplx": {"math"},
"math/rand": {"L0", "math"},
- "sort": {},
"strconv": {"L0", "unicode/utf8", "math"},
"unicode/utf16": {},
"unicode/utf8": {},
@@ -94,8 +93,8 @@ var pkgDeps = map[string][]string{
// L3 adds reflection and some basic utility packages
// and interface definitions, but nothing that makes
// system calls.
- "crypto": {"L2", "hash"}, // interfaces
- "crypto/cipher": {"L2", "crypto/subtle"}, // interfaces
+ "crypto": {"L2", "hash"}, // interfaces
+ "crypto/cipher": {"L2", "crypto/subtle"},
"crypto/subtle": {},
"encoding/base32": {"L2"},
"encoding/base64": {"L2"},
@@ -109,11 +108,13 @@ var pkgDeps = map[string][]string{
"image/color": {"L2"}, // interfaces
"image/color/palette": {"L2", "image/color"},
"reflect": {"L2"},
+ "sort": {"reflect"},
"L3": {
"L2",
"crypto",
"crypto/cipher",
+ "crypto/internal/cipherhw",
"crypto/subtle",
"encoding/base32",
"encoding/base64",
@@ -136,11 +137,23 @@ 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"},
- "os/exec": {"L2", "os", "path/filepath", "syscall"},
+ "os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,
@@ -158,17 +171,18 @@ var pkgDeps = map[string][]string{
"log": {"L1", "os", "fmt", "time"},
// Packages used by testing must be low-level (L2+fmt).
- "regexp": {"L2", "regexp/syntax"},
- "regexp/syntax": {"L2"},
- "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
- "runtime/pprof": {"L2", "fmt", "text/tabwriter"},
- "runtime/trace": {"L0"},
- "text/tabwriter": {"L2"},
-
- "testing": {"L2", "flag", "fmt", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
+ "regexp": {"L2", "regexp/syntax"},
+ "regexp/syntax": {"L2"},
+ "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
+ "runtime/pprof/internal/protopprof": {"L2", "fmt", "internal/pprof/profile", "os", "time"},
+ "runtime/pprof": {"L2", "fmt", "internal/pprof/profile", "os", "runtime/pprof/internal/protopprof", "text/tabwriter", "time"},
+ "runtime/trace": {"L0"},
+ "text/tabwriter": {"L2"},
+
+ "testing": {"L2", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
"testing/iotest": {"L2", "log"},
"testing/quick": {"L2", "flag", "fmt", "reflect"},
- "internal/testenv": {"L2", "os", "testing"},
+ "internal/testenv": {"L2", "OS", "flag", "testing", "syscall"},
// L4 is defined as L3+fmt+log+time, because in general once
// you're using L3 packages, use of fmt, log, or time is not a big deal.
@@ -207,49 +221,53 @@ var pkgDeps = map[string][]string{
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
// One of a kind.
- "archive/tar": {"L4", "OS", "syscall"},
- "archive/zip": {"L4", "OS", "compress/flate"},
- "container/heap": {"sort"},
- "compress/bzip2": {"L4"},
- "compress/flate": {"L4"},
- "compress/gzip": {"L4", "compress/flate"},
- "compress/lzw": {"L4"},
- "compress/zlib": {"L4", "compress/flate"},
- "database/sql": {"L4", "container/list", "database/sql/driver"},
- "database/sql/driver": {"L4", "time"},
- "debug/dwarf": {"L4"},
- "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"},
- "debug/gosym": {"L4"},
- "debug/macho": {"L4", "OS", "debug/dwarf"},
- "debug/pe": {"L4", "OS", "debug/dwarf"},
- "debug/plan9obj": {"L4", "OS"},
- "encoding": {"L4"},
- "encoding/ascii85": {"L4"},
- "encoding/asn1": {"L4", "math/big"},
- "encoding/csv": {"L4"},
- "encoding/gob": {"L4", "OS", "encoding"},
- "encoding/hex": {"L4"},
- "encoding/json": {"L4", "encoding"},
- "encoding/pem": {"L4"},
- "encoding/xml": {"L4", "encoding"},
- "flag": {"L4", "OS"},
- "go/build": {"L4", "OS", "GOPARSER"},
- "html": {"L4"},
- "image/draw": {"L4", "image/internal/imageutil"},
- "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
- "image/internal/imageutil": {"L4"},
- "image/jpeg": {"L4", "image/internal/imageutil"},
- "image/png": {"L4", "compress/zlib"},
- "index/suffixarray": {"L4", "regexp"},
- "internal/singleflight": {"sync"},
- "internal/trace": {"L4", "OS"},
- "math/big": {"L4"},
- "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
- "mime/quotedprintable": {"L4"},
- "net/internal/socktest": {"L4", "OS", "syscall"},
- "net/url": {"L4"},
- "text/scanner": {"L4", "OS"},
- "text/template/parse": {"L4"},
+ "archive/tar": {"L4", "OS", "syscall"},
+ "archive/zip": {"L4", "OS", "compress/flate"},
+ "container/heap": {"sort"},
+ "compress/bzip2": {"L4"},
+ "compress/flate": {"L4"},
+ "compress/gzip": {"L4", "compress/flate"},
+ "compress/lzw": {"L4"},
+ "compress/zlib": {"L4", "compress/flate"},
+ "context": {"errors", "fmt", "reflect", "sync", "time"},
+ "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
+ "database/sql/driver": {"L4", "context", "time", "database/sql/internal"},
+ "debug/dwarf": {"L4"},
+ "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"},
+ "debug/gosym": {"L4"},
+ "debug/macho": {"L4", "OS", "debug/dwarf"},
+ "debug/pe": {"L4", "OS", "debug/dwarf"},
+ "debug/plan9obj": {"L4", "OS"},
+ "encoding": {"L4"},
+ "encoding/ascii85": {"L4"},
+ "encoding/asn1": {"L4", "math/big"},
+ "encoding/csv": {"L4"},
+ "encoding/gob": {"L4", "OS", "encoding"},
+ "encoding/hex": {"L4"},
+ "encoding/json": {"L4", "encoding"},
+ "encoding/pem": {"L4"},
+ "encoding/xml": {"L4", "encoding"},
+ "flag": {"L4", "OS"},
+ "go/build": {"L4", "OS", "GOPARSER"},
+ "html": {"L4"},
+ "image/draw": {"L4", "image/internal/imageutil"},
+ "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+ "image/internal/imageutil": {"L4"},
+ "image/jpeg": {"L4", "image/internal/imageutil"},
+ "image/png": {"L4", "compress/zlib"},
+ "index/suffixarray": {"L4", "regexp"},
+ "internal/singleflight": {"sync"},
+ "internal/trace": {"L4", "OS"},
+ "internal/pprof/profile": {"L4", "OS", "compress/gzip", "regexp"},
+ "math/big": {"L4"},
+ "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
+ "mime/quotedprintable": {"L4"},
+ "net/internal/socktest": {"L4", "OS", "syscall"},
+ "net/url": {"L4"},
+ "plugin": {"L0", "OS", "CGO"},
+ "testing/internal/testdeps": {"L4", "runtime/pprof", "regexp"},
+ "text/scanner": {"L4", "OS"},
+ "text/template/parse": {"L4"},
"html/template": {
"L4", "OS", "encoding/json", "html", "text/template",
@@ -279,7 +297,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", "math/rand", "os", "sort", "syscall", "time", "internal/syscall/windows", "internal/singleflight", "internal/race"},
+ "net": {
+ "L0", "CGO",
+ "context", "math/rand", "os", "sort", "syscall", "time",
+ "internal/nettrace",
+ "internal/syscall/windows", "internal/singleflight", "internal/race",
+ "golang_org/x/net/lif", "golang_org/x/net/route",
+ },
// NET enables use of basic network-related packages.
"NET": {
@@ -313,6 +337,9 @@ var pkgDeps = map[string][]string{
"crypto/sha1",
"crypto/sha256",
"crypto/sha512",
+ "golang_org/x/crypto/chacha20poly1305",
+ "golang_org/x/crypto/curve25519",
+ "golang_org/x/crypto/poly1305",
},
// Random byte, number generation.
@@ -356,11 +383,24 @@ var pkgDeps = map[string][]string{
// HTTP, kingpin of dependencies.
"net/http": {
"L4", "NET", "OS",
- "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+ "compress/gzip",
+ "container/list",
+ "context",
+ "crypto/rand",
+ "crypto/tls",
+ "golang_org/x/net/http2/hpack",
+ "golang_org/x/net/idna",
+ "golang_org/x/net/lex/httplex",
+ "golang_org/x/text/unicode/norm",
+ "golang_org/x/text/width",
+ "internal/nettrace",
+ "mime/multipart",
+ "net/http/httptrace",
"net/http/internal",
- "internal/golang.org/x/net/http2/hpack",
+ "runtime/debug",
},
- "net/http/internal": {"L4"},
+ "net/http/internal": {"L4"},
+ "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"},
// HTTP-using packages.
"expvar": {"L4", "OS", "encoding/json", "net/http"},
@@ -368,7 +408,7 @@ var pkgDeps = map[string][]string{
"net/http/cookiejar": {"L4", "NET", "net/http"},
"net/http/fcgi": {"L4", "NET", "OS", "net/http", "net/http/cgi"},
"net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal"},
- "net/http/httputil": {"L4", "NET", "OS", "net/http", "net/http/internal"},
+ "net/http/httputil": {"L4", "NET", "OS", "context", "net/http", "net/http/internal"},
"net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
"net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"},
"net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
@@ -402,21 +442,6 @@ func allowed(pkg string) map[string]bool {
return m
}
-var bools = []bool{false, true}
-var geese = []string{"android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
-var goarches = []string{"386", "amd64", "arm", "arm64"}
-
-type osPkg struct {
- goos, pkg string
-}
-
-// allowedErrors are the operating systems and packages known to contain errors
-// (currently just "no Go source files")
-var allowedErrors = map[osPkg]bool{
- osPkg{"windows", "log/syslog"}: true,
- osPkg{"plan9", "log/syslog"}: true,
-}
-
// listStdPkgs returns the same list of packages as "go list std".
func listStdPkgs(goroot string) ([]string, error) {
// Based on cmd/go's matchPackages function.
@@ -434,7 +459,7 @@ func listStdPkgs(goroot string) ([]string, error) {
}
name := filepath.ToSlash(path[len(src):])
- if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
+ if name == "builtin" || name == "cmd" || strings.Contains(name, "golang_org") {
return filepath.SkipDir
}
diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go
index d436d28b31..979d0477df 100644
--- a/libgo/go/go/build/doc.go
+++ b/libgo/go/go/build/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -8,7 +8,7 @@
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
-// Go tree. The default path is the value of the GOPATH environment
+// Go tree. The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
@@ -16,7 +16,7 @@
//
// Each directory listed in the Go path must have a prescribed structure:
//
-// The src/ directory holds source code. The path below 'src' determines
+// The src/ directory holds source code. The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
@@ -31,9 +31,9 @@
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
-// using the final element, not the entire path. That is, the
+// using the final element, not the entire path. That is, the
// command with source in DIR/src/foo/quux is installed into
-// DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+// DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
@@ -103,6 +103,8 @@
// - "go1.4", from Go version 1.4 onward
// - "go1.5", from Go version 1.5 onward
// - "go1.6", from Go version 1.6 onward
+// - "go1.7", from Go version 1.7 onward
+// - "go1.8", from Go version 1.8 onward
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
@@ -138,4 +140,26 @@
// Using GOOS=android matches build tags and files as for GOOS=linux
// in addition to android tags and files.
//
+// Binary-Only Packages
+//
+// It is possible to distribute packages in binary form without including the
+// source code used for compiling the package. To do this, the package must
+// be distributed with a source file not excluded by build constraints and
+// containing a "//go:binary-only-package" comment.
+// Like a build constraint, this comment must appear near the top of the file,
+// preceded only by blank lines and other line comments and with a blank line
+// following the comment, to separate it from the package documentation.
+// Unlike build constraints, this comment is only recognized in non-test
+// Go source files.
+//
+// The minimal source code for a binary-only package is therefore:
+//
+// //go:binary-only-package
+//
+// package mypkg
+//
+// The source code may include additional Go code. That code is never compiled
+// but will be processed by tools like godoc and might be useful as end-user
+// documentation.
+//
package build
diff --git a/libgo/go/go/build/read.go b/libgo/go/go/build/read.go
index 1049ac50d9..29b8cdc786 100644
--- a/libgo/go/go/build/read.go
+++ b/libgo/go/go/build/read.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,6 +8,7 @@ import (
"bufio"
"errors"
"io"
+ "unicode/utf8"
)
type importReader struct {
@@ -20,7 +21,7 @@ type importReader struct {
}
func isIdent(c byte) bool {
- return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= 0x80
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
}
var (
diff --git a/libgo/go/go/build/read_test.go b/libgo/go/go/build/read_test.go
index 326960bdc9..9cef657e13 100644
--- a/libgo/go/go/build/read_test.go
+++ b/libgo/go/go/build/read_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go
index d800a78f0a..ea316ea61a 100644
--- a/libgo/go/go/build/syslist.go
+++ b/libgo/go/go/build/syslist.go
@@ -1,8 +1,8 @@
-// Copyright 2011 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 build
-const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be alpha m68k ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le mipso32 mipsn32 mipsn64 mipso64 ppc s390 s390x sparc sparc64 "
diff --git a/libgo/go/go/build/syslist_test.go b/libgo/go/go/build/syslist_test.go
index 3be2928f52..7973ff4ee5 100644
--- a/libgo/go/go/build/syslist_test.go
+++ b/libgo/go/go/build/syslist_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/go/constant/value.go b/libgo/go/go/constant/value.go
index 310814df71..7c32473c61 100644
--- a/libgo/go/go/constant/value.go
+++ b/libgo/go/go/constant/value.go
@@ -43,13 +43,14 @@ type Value interface {
// Kind returns the value kind.
Kind() Kind
- // String returns a short, human-readable form of the value.
+ // String returns a short, quoted (human-readable) form of the value.
// For numeric values, the result may be an approximation;
// for String values the result may be a shortened string.
// Use ExactString for a string representing a value exactly.
String() string
- // ExactString returns an exact, printable form of the value.
+ // ExactString returns an exact, quoted (human-readable) form of the value.
+ // If the Value is of Kind String, use StringVal to obtain the unquoted string.
ExactString() string
// Prevent external implementations.
@@ -276,10 +277,10 @@ func smallRat(x *big.Float) bool {
// MakeUnknown returns the Unknown value.
func MakeUnknown() Value { return unknownVal{} }
-// MakeBool returns the Bool value for x.
+// MakeBool returns the Bool value for b.
func MakeBool(b bool) Value { return boolVal(b) }
-// MakeString returns the String value for x.
+// MakeString returns the String value for s.
func MakeString(s string) Value { return stringVal(s) }
// MakeInt64 returns the Int value for x.
@@ -308,8 +309,8 @@ func MakeFloat64(x float64) Value {
// MakeFromLiteral returns the corresponding integer, floating-point,
// imaginary, character, or string value for a Go literal string. The
-// tok value must be one of token.INT, token.FLOAT, toke.IMAG, token.
-// CHAR, or token.STRING. The final argument must be zero.
+// tok value must be one of token.INT, token.FLOAT, token.IMAG,
+// token.CHAR, or token.STRING. The final argument must be zero.
// If the literal string syntax is invalid, the result is an Unknown.
func MakeFromLiteral(lit string, tok token.Token, zero uint) Value {
if zero != 0 {
@@ -847,6 +848,10 @@ Error:
func ord(x Value) int {
switch x.(type) {
+ default:
+ // force invalid value into "x position" in match
+ // (don't panic here so that callers can provide a better error message)
+ return -1
case unknownVal:
return 0
case boolVal, stringVal:
@@ -861,15 +866,13 @@ func ord(x Value) int {
return 5
case complexVal:
return 6
- default:
- panic("unreachable")
}
}
// match returns the matching representation (same type) with the
// smallest complexity for two values x and y. If one of them is
-// numeric, both of them must be numeric. If one of them is Unknown,
-// both results are Unknown.
+// numeric, both of them must be numeric. If one of them is Unknown
+// or invalid (say, nil) both results are that value.
//
func match(x, y Value) (_, _ Value) {
if ord(x) > ord(y) {
@@ -879,9 +882,6 @@ func match(x, y Value) (_, _ Value) {
// ord(x) <= ord(y)
switch x := x.(type) {
- case unknownVal:
- return x, x
-
case boolVal, stringVal, complexVal:
return x, y
@@ -920,6 +920,7 @@ func match(x, y Value) (_, _ Value) {
case complexVal:
return vtoc(x), y
}
+
case floatVal:
switch y := y.(type) {
case floatVal:
@@ -929,18 +930,23 @@ func match(x, y Value) (_, _ Value) {
}
}
- panic("unreachable")
+ // force unknown and invalid values into "x position" in callers of match
+ // (don't panic here so that callers can provide a better error message)
+ return x, x
}
// BinaryOp returns the result of the binary expression x op y.
// The operation must be defined for the operands. If one of the
// operands is Unknown, the result is Unknown.
+// BinaryOp doesn't handle comparisons or shifts; use Compare
+// or Shift instead.
+//
// To force integer division of Int operands, use op == token.QUO_ASSIGN
// instead of token.QUO; the result is guaranteed to be Int in this case.
// Division by zero leads to a run-time panic.
//
-func BinaryOp(x Value, op token.Token, y Value) Value {
- x, y = match(x, y)
+func BinaryOp(x_ Value, op token.Token, y_ Value) Value {
+ x, y := match(x_, y_)
switch x := x.(type) {
case unknownVal:
@@ -1107,7 +1113,7 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
}
Error:
- panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+ panic(fmt.Sprintf("invalid binary operation %v %s %v", x_, op, y_))
}
func add(x, y Value) Value { return BinaryOp(x, token.ADD, y) }
@@ -1167,7 +1173,7 @@ func cmpZero(x int, op token.Token) bool {
case token.GEQ:
return x >= 0
}
- panic("unreachable")
+ panic(fmt.Sprintf("invalid comparison %v %s 0", x, op))
}
// Compare returns the result of the comparison x op y.
@@ -1175,8 +1181,8 @@ func cmpZero(x int, op token.Token) bool {
// If one of the operands is Unknown, the result is
// false.
//
-func Compare(x Value, op token.Token, y Value) bool {
- x, y = match(x, y)
+func Compare(x_ Value, op token.Token, y_ Value) bool {
+ x, y := match(x_, y_)
switch x := x.(type) {
case unknownVal:
@@ -1246,5 +1252,5 @@ func Compare(x Value, op token.Token, y Value) bool {
}
}
- panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+ panic(fmt.Sprintf("invalid comparison %v %s %v", x_, op, y_))
}
diff --git a/libgo/go/go/constant/value_test.go b/libgo/go/go/constant/value_test.go
index dbd96c07a3..8a8a08eaaa 100644
--- a/libgo/go/go/constant/value_test.go
+++ b/libgo/go/go/constant/value_test.go
@@ -244,6 +244,7 @@ var stringTests = []struct {
{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
{"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
+ {"0e9999999999", "0", "0"}, // issue #16176
// Complex
{"0i", "(0 + 0i)", "(0 + 0i)"},
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
index f414ca4090..15e034b6df 100644
--- a/libgo/go/go/doc/comment.go
+++ b/libgo/go/go/doc/comment.go
@@ -53,7 +53,7 @@ const (
filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
urlRx = `(` + protocol + `)://` + // http://
hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
- filePart + `([:.,]` + filePart + `)*`
+ filePart + `([:.,;]` + filePart + `)*`
)
var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
@@ -225,7 +225,7 @@ func heading(line string) string {
}
// exclude lines with illegal characters
- if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
+ if strings.ContainsAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") {
return ""
}
@@ -398,7 +398,7 @@ func blocks(text string) []block {
// ToText prepares comment text for presentation in textual output.
// It wraps paragraphs of text to width or fewer Unicode code points
-// and then prefixes each line with the indent. In preformatted sections
+// and then prefixes each line with the indent. In preformatted sections
// (such as program text), it prefixes each non-blank line with preIndent.
func ToText(w io.Writer, text string, indent, preIndent string, width int) {
l := lineWrapper{
diff --git a/libgo/go/go/doc/comment_test.go b/libgo/go/go/doc/comment_test.go
index ad65c2a27f..76dfbeac79 100644
--- a/libgo/go/go/doc/comment_test.go
+++ b/libgo/go/go/doc/comment_test.go
@@ -162,6 +162,7 @@ var emphasizeTests = []struct {
{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
{"javascript://is/not/linked", "javascript://is/not/linked"},
+ {"http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD", `<a href="http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD">http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD</a>`},
}
func TestEmphasize(t *testing.T) {
diff --git a/libgo/go/go/doc/doc_test.go b/libgo/go/go/doc/doc_test.go
index ad8ba5378f..82e63100d4 100644
--- a/libgo/go/go/doc/doc_test.go
+++ b/libgo/go/go/doc/doc_test.go
@@ -25,7 +25,7 @@ var files = flag.String("files", "", "consider only Go test files matching this
const dataDir = "testdata"
-var templateTxt = readTemplate("template.txt")
+var templateTxt *template.Template
func readTemplate(filename string) *template.Template {
t := template.New(filename)
@@ -96,6 +96,9 @@ func test(t *testing.T, mode Mode) {
if err != nil {
t.Fatal(err)
}
+ if templateTxt == nil {
+ templateTxt = readTemplate("template.txt")
+ }
// test packages
for _, pkg := range pkgs {
diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go
index c414e548cc..bbf8096ce2 100644
--- a/libgo/go/go/doc/example.go
+++ b/libgo/go/go/doc/example.go
@@ -26,8 +26,9 @@ type Example struct {
Play *ast.File // a whole program version of the example
Comments []*ast.CommentGroup
Output string // expected output
- EmptyOutput bool // expect empty output
- Order int // original source code order
+ Unordered bool
+ EmptyOutput bool // expect empty output
+ Order int // original source code order
}
// Examples returns the examples found in the files, sorted by Name field.
@@ -71,7 +72,7 @@ func Examples(files ...*ast.File) []*Example {
if f.Doc != nil {
doc = f.Doc.Text()
}
- output, hasOutput := exampleOutput(f.Body, file.Comments)
+ output, unordered, hasOutput := exampleOutput(f.Body, file.Comments)
flist = append(flist, &Example{
Name: name[len("Example"):],
Doc: doc,
@@ -79,6 +80,7 @@ func Examples(files ...*ast.File) []*Example {
Play: playExample(file, f.Body),
Comments: file.Comments,
Output: output,
+ Unordered: unordered,
EmptyOutput: output == "" && hasOutput,
Order: len(flist),
})
@@ -96,24 +98,27 @@ func Examples(files ...*ast.File) []*Example {
return list
}
-var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
+var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*(unordered )?output:`)
// Extracts the expected output and whether there was a valid output comment
-func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, ok bool) {
+func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, unordered, ok bool) {
if _, last := lastComment(b, comments); last != nil {
// test that it begins with the correct prefix
text := last.Text()
- if loc := outputPrefix.FindStringIndex(text); loc != nil {
+ if loc := outputPrefix.FindStringSubmatchIndex(text); loc != nil {
+ if loc[2] != -1 {
+ unordered = true
+ }
text = text[loc[1]:]
// Strip zero or more spaces followed by \n or a single space.
text = strings.TrimLeft(text, " ")
if len(text) > 0 && text[0] == '\n' {
text = text[1:]
}
- return text, true
+ return text, unordered, true
}
}
- return "", false // no suitable comment found
+ return "", false, false // no suitable comment found
}
// isTest tells whether name looks like a test, example, or benchmark.
@@ -255,7 +260,8 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
}
}
- // Strip "Output:" comment and adjust body end position.
+ // Strip the "Output:" or "Unordered output:" comment and adjust body
+ // end position.
body, comments = stripOutputComment(body, comments)
// Synthesize import declaration.
@@ -318,10 +324,10 @@ func playExampleFile(file *ast.File) *ast.File {
return &f
}
-// stripOutputComment finds and removes an "Output:" comment from body
-// and comments, and adjusts the body block's end position.
+// stripOutputComment finds and removes the "Output:" or "Unordered output:"
+// comment from body and comments, and adjusts the body block's end position.
func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) {
- // Do nothing if no "Output:" comment found.
+ // Do nothing if there is no "Output:" or "Unordered output:" comment.
i, last := lastComment(body, comments)
if last == nil || !outputPrefix.MatchString(last.Text()) {
return body, comments
diff --git a/libgo/go/go/doc/reader.go b/libgo/go/go/doc/reader.go
index e4e7b7c1c7..8e82353868 100644
--- a/libgo/go/go/doc/reader.go
+++ b/libgo/go/go/doc/reader.go
@@ -362,6 +362,11 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
// associate methods with the receiver type, if any
if fun.Recv != nil {
// method
+ if len(fun.Recv.List) == 0 {
+ // should not happen (incorrect AST); (See issue 17788)
+ // don't show this method
+ return
+ }
recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
if imp {
// should not happen (incorrect AST);
@@ -645,7 +650,9 @@ func (r *reader) computeMethodSets() {
func (r *reader) cleanupTypes() {
for _, t := range r.types {
visible := r.isVisible(t.name)
- if t.decl == nil && (predeclaredTypes[t.name] || visible && (t.isEmbedded || r.hasDotImp)) {
+ predeclared := predeclaredTypes[t.name]
+
+ if t.decl == nil && (predeclared || visible && (t.isEmbedded || r.hasDotImp)) {
// t.name is a predeclared type (and was not redeclared in this package),
// or it was embedded somewhere but its declaration is missing (because
// the AST is incomplete), or we have a dot-import (and all bets are off):
@@ -660,10 +667,12 @@ func (r *reader) cleanupTypes() {
r.funcs[name] = f
}
// 3) move methods
- for name, m := range t.methods {
- // don't overwrite functions with the same name - drop them
- if _, found := r.funcs[name]; !found {
- r.funcs[name] = m
+ if !predeclared {
+ for name, m := range t.methods {
+ // don't overwrite functions with the same name - drop them
+ if _, found := r.funcs[name]; !found {
+ r.funcs[name] = m
+ }
}
}
}
@@ -809,6 +818,11 @@ func noteBodies(notes []*Note) []string {
// ----------------------------------------------------------------------------
// Predeclared identifiers
+// IsPredeclared reports whether s is a predeclared identifier.
+func IsPredeclared(s string) bool {
+ return predeclaredTypes[s] || predeclaredFuncs[s] || predeclaredConstants[s]
+}
+
var predeclaredTypes = map[string]bool{
"bool": true,
"byte": true,
diff --git a/libgo/go/go/doc/testdata/benchmark.go b/libgo/go/go/doc/testdata/benchmark.go
index 905e49644a..1d581f057e 100644
--- a/libgo/go/go/doc/testdata/benchmark.go
+++ b/libgo/go/go/doc/testdata/benchmark.go
@@ -33,7 +33,7 @@ type B struct {
result BenchmarkResult
}
-// StartTimer starts timing a test. This function is called automatically
+// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (b *B) StartTimer() {
@@ -43,7 +43,7 @@ func (b *B) StartTimer() {
}
}
-// StopTimer stops timing a test. This can be used to pause the timer
+// StopTimer stops timing a test. This can be used to pause the timer
// while performing complex initialization that you don't
// want to measure.
func (b *B) StopTimer() {
@@ -134,9 +134,9 @@ func (b *B) run() BenchmarkResult {
return b.result
}
-// launch launches the benchmark function. It gradually increases the number
+// launch launches the benchmark function. It gradually increases the number
// of benchmark iterations until the benchmark runs for a second in order
-// to get a reasonable measurement. It prints timing information in this form
+// to get a reasonable measurement. It prints timing information in this form
// testing.BenchmarkHello 100000 19 ns/op
// launch is run by the fun function as a separate goroutine.
func (b *B) launch() {
diff --git a/libgo/go/go/doc/testdata/issue17788.0.golden b/libgo/go/go/doc/testdata/issue17788.0.golden
new file mode 100644
index 0000000000..42c00da504
--- /dev/null
+++ b/libgo/go/go/doc/testdata/issue17788.0.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/libgo/go/go/doc/testdata/issue17788.1.golden b/libgo/go/go/doc/testdata/issue17788.1.golden
new file mode 100644
index 0000000000..42c00da504
--- /dev/null
+++ b/libgo/go/go/doc/testdata/issue17788.1.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/libgo/go/go/doc/testdata/issue17788.2.golden b/libgo/go/go/doc/testdata/issue17788.2.golden
new file mode 100644
index 0000000000..42c00da504
--- /dev/null
+++ b/libgo/go/go/doc/testdata/issue17788.2.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/libgo/go/go/doc/testdata/issue17788.go b/libgo/go/go/doc/testdata/issue17788.go
new file mode 100644
index 0000000000..883ad5f769
--- /dev/null
+++ b/libgo/go/go/doc/testdata/issue17788.go
@@ -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.
+
+package issue17788
+
+func ( /* receiver type */ ) f0() {
+}
diff --git a/libgo/go/go/doc/testdata/predeclared.0.golden b/libgo/go/go/doc/testdata/predeclared.0.golden
new file mode 100644
index 0000000000..9f37b069f0
--- /dev/null
+++ b/libgo/go/go/doc/testdata/predeclared.0.golden
@@ -0,0 +1,8 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
diff --git a/libgo/go/go/doc/testdata/predeclared.1.golden b/libgo/go/go/doc/testdata/predeclared.1.golden
new file mode 100644
index 0000000000..2ff8ee666b
--- /dev/null
+++ b/libgo/go/go/doc/testdata/predeclared.1.golden
@@ -0,0 +1,22 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
+
+TYPES
+ //
+ type bool int
+
+ // Must not be visible.
+ func (b bool) String() string
+
+ //
+ type error struct{}
+
+ // Must not be visible.
+ func (e error) Error() string
+
diff --git a/libgo/go/go/doc/testdata/predeclared.2.golden b/libgo/go/go/doc/testdata/predeclared.2.golden
new file mode 100644
index 0000000000..9f37b069f0
--- /dev/null
+++ b/libgo/go/go/doc/testdata/predeclared.2.golden
@@ -0,0 +1,8 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
diff --git a/libgo/go/go/doc/testdata/predeclared.go b/libgo/go/go/doc/testdata/predeclared.go
new file mode 100644
index 0000000000..c6dd806cba
--- /dev/null
+++ b/libgo/go/go/doc/testdata/predeclared.go
@@ -0,0 +1,22 @@
+// 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 predeclared is a go/doc test for handling of
+// exported methods on locally-defined predeclared types.
+// See issue 9860.
+package predeclared
+
+type error struct{}
+
+// Must not be visible.
+func (e error) Error() string {
+ return ""
+}
+
+type bool int
+
+// Must not be visible.
+func (b bool) String() string {
+ return ""
+}
diff --git a/libgo/go/go/doc/testdata/testing.0.golden b/libgo/go/go/doc/testdata/testing.0.golden
index f8348f1ac3..83cf37cd3a 100644
--- a/libgo/go/go/doc/testdata/testing.0.golden
+++ b/libgo/go/go/doc/testdata/testing.0.golden
@@ -78,10 +78,10 @@ TYPES
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
- // StartTimer starts timing a test. This function is called ...
+ // StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
- // StopTimer stops timing a test. This can be used to pause the ...
+ // StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
// The results of a benchmark run.
diff --git a/libgo/go/go/doc/testdata/testing.1.golden b/libgo/go/go/doc/testdata/testing.1.golden
index 282bb1015a..b9d14517a9 100644
--- a/libgo/go/go/doc/testdata/testing.1.golden
+++ b/libgo/go/go/doc/testdata/testing.1.golden
@@ -25,8 +25,8 @@ VARIABLES
//
var (
// The short flag requests that tests run more quickly, but its functionality
- // is provided by test writers themselves. The testing package is just its
- // home. The all.bash installation script sets it to make installation more
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
// efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -151,13 +151,13 @@ TYPES
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
- // StartTimer starts timing a test. This function is called ...
+ // StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
- // StopTimer stops timing a test. This can be used to pause the ...
+ // StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
- // launch launches the benchmark function. It gradually increases ...
+ // launch launches the benchmark function. It gradually increases ...
func (b *B) launch()
// log generates the output. It's always at the same stack depth.
diff --git a/libgo/go/go/doc/testdata/testing.2.golden b/libgo/go/go/doc/testdata/testing.2.golden
index f8348f1ac3..83cf37cd3a 100644
--- a/libgo/go/go/doc/testdata/testing.2.golden
+++ b/libgo/go/go/doc/testdata/testing.2.golden
@@ -78,10 +78,10 @@ TYPES
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
- // StartTimer starts timing a test. This function is called ...
+ // StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
- // StopTimer stops timing a test. This can be used to pause the ...
+ // StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
// The results of a benchmark run.
diff --git a/libgo/go/go/doc/testdata/testing.go b/libgo/go/go/doc/testdata/testing.go
index 93ed494c32..52810f7a56 100644
--- a/libgo/go/go/doc/testdata/testing.go
+++ b/libgo/go/go/doc/testdata/testing.go
@@ -22,7 +22,7 @@
// }
// }
// The benchmark package will vary b.N until the benchmark function lasts
-// long enough to be timed reliably. The output
+// long enough to be timed reliably. The output
// testing.BenchmarkHello 10000000 282 ns/op
// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
@@ -51,8 +51,8 @@ import (
var (
// The short flag requests that tests run more quickly, but its functionality
- // is provided by test writers themselves. The testing package is just its
- // home. The all.bash installation script sets it to make installation more
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
// efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -152,9 +152,9 @@ func (c *common) FailNow() {
// This previous version duplicated code (those lines are in
// tRunner no matter what), but worse the goroutine teardown
// implicit in runtime.Goexit was not guaranteed to complete
- // before the test exited. If a test deferred an important cleanup
+ // before the test exited. If a test deferred an important cleanup
// function (like removing temporary files), there was no guarantee
- // it would run on a test failure. Because we send on c.signal during
+ // it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
runtime.Goexit()
diff --git a/libgo/go/go/format/format_test.go b/libgo/go/go/format/format_test.go
index b5817a5dd1..72b8d5aeeb 100644
--- a/libgo/go/go/format/format_test.go
+++ b/libgo/go/go/format/format_test.go
@@ -6,9 +6,11 @@ package format
import (
"bytes"
+ "fmt"
"go/parser"
"go/token"
"io/ioutil"
+ "log"
"strings"
"testing"
)
@@ -143,3 +145,28 @@ func TestPartial(t *testing.T) {
}
}
}
+
+func ExampleNode() {
+ const expr = "(6+2*3)/4"
+
+ // parser.ParseExpr parses the argument and returns the
+ // corresponding ast.Node.
+ node, err := parser.ParseExpr(expr)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Create a FileSet for node. Since the node does not come
+ // from a real source file, fset will be empty.
+ fset := token.NewFileSet()
+
+ var buf bytes.Buffer
+ err = Node(&buf, fset, node)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(buf.String())
+
+ // Output: (6 + 2*3) / 4
+}
diff --git a/libgo/go/go/format/internal.go b/libgo/go/go/format/internal.go
index 9d04878f86..b8b470da8b 100644
--- a/libgo/go/go/format/internal.go
+++ b/libgo/go/go/format/internal.go
@@ -28,9 +28,9 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
) {
// Try as whole source file.
file, err = parser.ParseFile(fset, filename, src, parserMode)
- // If there's no error, return. If the error is that the source file didn't begin with a
+ // If there's no error, return. If the error is that the source file didn't begin with a
// package line and source fragments are ok, fall through to
- // try as a source fragment. Stop and return on any other error.
+ // try as a source fragment. Stop and return on any other error.
if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
return
}
@@ -59,7 +59,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
// If this is a statement list, make it a source file
// by inserting a package clause and turning the list
- // into a function body. This handles expressions too.
+ // into a function body. This handles expressions too.
// Insert using a ;, not a newline, so that the line numbers
// in fsrc match the ones in src. Add an extra '\n' before the '}'
// to make sure comments are flushed before the '}'.
diff --git a/libgo/go/go/importer/importer.go b/libgo/go/go/importer/importer.go
index 560b853c39..f655bc1e92 100644
--- a/libgo/go/go/importer/importer.go
+++ b/libgo/go/go/importer/importer.go
@@ -31,7 +31,7 @@ func For(compiler string, lookup Lookup) types.Importer {
return make(gcimports)
case "gccgo":
- if lookup == nil {
+ if lookup != nil {
panic("gccgo importer for custom import path lookup not yet implemented")
}
diff --git a/libgo/go/go/internal/gccgoimporter/importer.go b/libgo/go/go/internal/gccgoimporter/importer.go
index aa0d01afdf..a22d8fed90 100644
--- a/libgo/go/go/internal/gccgoimporter/importer.go
+++ b/libgo/go/go/internal/gccgoimporter/importer.go
@@ -63,6 +63,7 @@ func findExportFile(searchpaths []string, pkgpath string) (string, error) {
const (
gccgov1Magic = "v1;\n"
+ gccgov2Magic = "v2;\n"
goimporterMagic = "\n$$ "
archiveMagic = "!<ar"
)
@@ -88,16 +89,10 @@ 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[:]) {
- case gccgov1Magic, goimporterMagic:
+ case gccgov1Magic, gccgov2Magic, goimporterMagic:
// Raw export data.
reader = f
return
@@ -168,13 +163,13 @@ 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
}
switch string(magic[:]) {
- case gccgov1Magic:
+ case gccgov1Magic, gccgov2Magic:
var p parser
p.init(fpath, reader, imports)
pkg = p.parsePackage()
diff --git a/libgo/go/go/internal/gccgoimporter/importer_test.go b/libgo/go/go/internal/gccgoimporter/importer_test.go
index c10fa484e3..2b454701be 100644
--- a/libgo/go/go/internal/gccgoimporter/importer_test.go
+++ b/libgo/go/go/internal/gccgoimporter/importer_test.go
@@ -95,8 +95,12 @@ var importerTests = [...]importerTest{
{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1 + 1i)"},
{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
- // TODO: enable this entry once bug has been tracked down
- //{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+ {pkgpath: "conversions", name: "Bits", want: "const Bits Units", wantval: `"bits"`},
+ {pkgpath: "time", name: "Duration", want: "type Duration int64"},
+ {pkgpath: "time", name: "Nanosecond", want: "const Nanosecond Duration", wantval: "1"},
+ {pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
+ {pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
+ {pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
}
func TestGoxImporter(t *testing.T) {
diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go
index c06cce435b..3b97c96d43 100644
--- a/libgo/go/go/internal/gccgoimporter/parser.go
+++ b/libgo/go/go/internal/gccgoimporter/parser.go
@@ -19,6 +19,7 @@ import (
type parser struct {
scanner scanner.Scanner
+ version string // format version
tok rune // current token
lit string // literal string; only valid for Ident, Int, String tokens
pkgpath string // package path of imported package
@@ -245,9 +246,20 @@ func (p *parser) parseVar(pkg *types.Package) *types.Var {
return types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
}
-// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) .
+// Conversion = "convert" "(" Type "," ConstValue ")" .
+func (p *parser) parseConversion(pkg *types.Package) (val constant.Value, typ types.Type) {
+ p.expectKeyword("convert")
+ p.expect('(')
+ typ = p.parseType(pkg)
+ p.expect(',')
+ val, _ = p.parseConstValue(pkg)
+ p.expect(')')
+ return
+}
+
+// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) | Conversion .
// FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
-func (p *parser) parseConstValue() (val constant.Value, typ types.Type) {
+func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ types.Type) {
switch p.tok {
case scanner.String:
str := p.parseString()
@@ -262,6 +274,9 @@ func (p *parser) parseConstValue() (val constant.Value, typ types.Type) {
case "true":
b = true
+ case "convert":
+ return p.parseConversion(pkg)
+
default:
p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
}
@@ -348,7 +363,7 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
typ = p.parseType(pkg)
}
p.expect('=')
- val, vtyp := p.parseConstValue()
+ val, vtyp := p.parseConstValue(pkg)
if typ == nil {
typ = vtyp
}
@@ -696,7 +711,10 @@ func (p *parser) parseType(pkg *types.Package) (t types.Type) {
func (p *parser) parsePackageInit() PackageInit {
name := p.parseUnquotedString()
initfunc := p.parseUnquotedString()
- priority := int(p.parseInt())
+ priority := -1
+ if p.version == "v1" {
+ priority = int(p.parseInt())
+ }
return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
}
@@ -723,7 +741,7 @@ func (p *parser) maybeCreatePackage() {
}
}
-// InitDataDirective = "v1" ";" |
+// InitDataDirective = ( "v1" | "v2" ) ";" |
// "priority" int ";" |
// "init" { PackageInit } ";" |
// "checksum" unquotedString ";" .
@@ -734,7 +752,8 @@ func (p *parser) parseInitDataDirective() {
}
switch p.lit {
- case "v1":
+ case "v1", "v2":
+ p.version = p.lit
p.next()
p.expect(';')
@@ -750,6 +769,15 @@ func (p *parser) parseInitDataDirective() {
}
p.expect(';')
+ case "init_graph":
+ p.next()
+ // The graph data is thrown away for now.
+ for p.tok != ';' && p.tok != scanner.EOF {
+ p.parseInt()
+ p.parseInt()
+ }
+ p.expect(';')
+
case "checksum":
// Don't let the scanner try to parse the checksum as a number.
defer func(mode uint) {
@@ -766,8 +794,9 @@ func (p *parser) parseInitDataDirective() {
}
// Directive = InitDataDirective |
-// "package" unquotedString ";" |
+// "package" unquotedString [ unquotedString ] [ unquotedString ] ";" |
// "pkgpath" unquotedString ";" |
+// "prefix" unquotedString ";" |
// "import" unquotedString unquotedString string ";" |
// "func" Func ";" |
// "type" Type ";" |
@@ -780,13 +809,17 @@ func (p *parser) parseDirective() {
}
switch p.lit {
- case "v1", "priority", "init", "checksum":
+ case "v1", "v2", "priority", "init", "init_graph", "checksum":
p.parseInitDataDirective()
case "package":
p.next()
p.pkgname = p.parseUnquotedString()
p.maybeCreatePackage()
+ if p.version == "v2" && p.tok != ';' {
+ p.parseUnquotedString()
+ p.parseUnquotedString()
+ }
p.expect(';')
case "pkgpath":
@@ -795,6 +828,11 @@ func (p *parser) parseDirective() {
p.maybeCreatePackage()
p.expect(';')
+ case "prefix":
+ p.next()
+ p.pkgpath = p.parseUnquotedString()
+ p.expect(';')
+
case "import":
p.next()
pkgname := p.parseUnquotedString()
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/complexnums.gox b/libgo/go/go/internal/gccgoimporter/testdata/complexnums.gox
new file mode 100644
index 0000000000..b66524f80e
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/complexnums.gox
@@ -0,0 +1,8 @@
+v1;
+package complexnums;
+pkgpath complexnums;
+priority 1;
+const NN = -0.1E1-0.1E1i ;
+const NP = -0.1E1+0.1E1i ;
+const PN = 0.1E1-0.1E1i ;
+const PP = 0.1E1+0.1E1i ;
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/conversions.go b/libgo/go/go/internal/gccgoimporter/testdata/conversions.go
new file mode 100644
index 0000000000..653927ad67
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/conversions.go
@@ -0,0 +1,5 @@
+package conversions
+
+type Units string
+
+const Bits = Units("bits")
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/conversions.gox b/libgo/go/go/internal/gccgoimporter/testdata/conversions.gox
new file mode 100644
index 0000000000..7de6cdad2c
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/conversions.gox
@@ -0,0 +1,6 @@
+v2;
+package conversions;
+prefix go;
+package conversions go.conversions go.conversions;
+const Bits <type 1 "Units" <type -16>> = convert(<type 1>, "bits");
+type <type 1>;
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/imports.gox b/libgo/go/go/internal/gccgoimporter/testdata/imports.gox
new file mode 100644
index 0000000000..958a4f5b82
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/imports.gox
@@ -0,0 +1,7 @@
+v1;
+package imports;
+pkgpath imports;
+priority 7;
+import fmt fmt "fmt";
+init imports imports..import 7 math math..import 1 runtime runtime..import 1 strconv strconv..import 2 io io..import 3 reflect reflect..import 3 syscall syscall..import 3 time time..import 4 os os..import 5 fmt fmt..import 6;
+var Hello <type -16>;
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/pointer.gox b/libgo/go/go/internal/gccgoimporter/testdata/pointer.gox
new file mode 100644
index 0000000000..d96ebbdd14
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/pointer.gox
@@ -0,0 +1,4 @@
+v1;
+package pointer;
+pkgpath pointer;
+type <type 1 "Int8Ptr" <type 2 *<type -1>>>;
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/time.gox b/libgo/go/go/internal/gccgoimporter/testdata/time.gox
new file mode 100644
index 0000000000..80c2dbcb47
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/time.gox
Binary files differ
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/unicode.gox b/libgo/go/go/internal/gccgoimporter/testdata/unicode.gox
new file mode 100644
index 0000000000..e70e539655
--- /dev/null
+++ b/libgo/go/go/internal/gccgoimporter/testdata/unicode.gox
Binary files differ
diff --git a/libgo/go/go/internal/gcimporter/bimport.go b/libgo/go/go/internal/gcimporter/bimport.go
index 68690424a1..a8f349052a 100644
--- a/libgo/go/go/internal/gcimporter/bimport.go
+++ b/libgo/go/go/internal/gcimporter/bimport.go
@@ -11,100 +11,140 @@ import (
"go/token"
"go/types"
"sort"
+ "strconv"
+ "strings"
+ "sync"
"unicode"
"unicode/utf8"
)
+type importer struct {
+ imports map[string]*types.Package
+ data []byte
+ path string
+ buf []byte // for reading strings
+ version int // export format version
+
+ // object lists
+ 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
+ prevFile string
+ prevLine int
+ fset *token.FileSet
+ files map[string]*token.File
+
+ // debugging support
+ debugFormat bool
+ read int // bytes read
+}
+
// BImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
-// If data is obviously malformed, an error is returned but in
-// general it is not recommended to call BImportData on untrusted data.
-func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
+// If the export data version is not recognized or the format is otherwise
+// compromised, an error is returned.
+func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, _ *types.Package, err error) {
+ // catch panics and return them as errors
+ defer func() {
+ if e := recover(); e != nil {
+ // The package (filename) causing the problem is added to this
+ // error by a wrapper in the caller (Import in gcimporter.go).
+ err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e)
+ }
+ }()
+
p := importer{
imports: imports,
data: data,
+ path: path,
+ version: -1, // unknown version
+ strList: []string{""}, // empty string is mapped to 0
+ fset: fset,
+ files: make(map[string]*token.File),
+ }
+
+ // read version info
+ var versionstr string
+ if b := p.rawByte(); b == 'c' || b == 'd' {
+ // Go1.7 encoding; first byte encodes low-level
+ // encoding format (compact vs debug).
+ // For backward-compatibility only (avoid problems with
+ // old installed packages). Newly compiled packages use
+ // the extensible format string.
+ // TODO(gri) Remove this support eventually; after Go1.8.
+ if b == 'd' {
+ p.debugFormat = true
+ }
+ p.trackAllTypes = p.rawByte() == 'a'
+ p.posInfoFormat = p.int() != 0
+ versionstr = p.string()
+ if versionstr == "v1" {
+ p.version = 0
+ }
+ } else {
+ // Go1.8 extensible encoding
+ // read version string and extract version number (ignore anything after the version number)
+ versionstr = p.rawStringln(b)
+ if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
+ if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
+ p.version = v
+ }
+ }
}
- p.buf = p.bufarray[:]
- // read low-level encoding format
- switch format := p.byte(); format {
- case 'c':
- // compact format - nothing to do
- case 'd':
- p.debugFormat = true
+ // read version specific flags - extend as necessary
+ switch p.version {
+ // case 4:
+ // ...
+ // fallthrough
+ case 3, 2, 1:
+ p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
+ p.trackAllTypes = p.int() != 0
+ p.posInfoFormat = p.int() != 0
+ case 0:
+ // Go1.7 encoding format - nothing to do here
default:
- return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ errorf("unknown export format version %d (%q)", p.version, versionstr)
}
// --- generic export data ---
- if v := p.string(); v != "v0" {
- return p.read, nil, fmt.Errorf("unknown version: %s", v)
- }
-
// populate typList with predeclared "known" types
p.typList = append(p.typList, predeclared...)
// read package data
- // TODO(gri) clean this up
- i := p.tagOrIndex()
- if i != packageTag {
- panic(fmt.Sprintf("package tag expected, got %d", i))
- }
- name := p.string()
- if s := p.string(); s != "" {
- panic(fmt.Sprintf("empty path expected, got %s", s))
- }
- pkg := p.imports[path]
- if pkg == nil {
- pkg = types.NewPackage(path, name)
- p.imports[path] = pkg
- }
- p.pkgList = append(p.pkgList, pkg)
-
- if debug && p.pkgList[0] != pkg {
- panic("imported packaged not found in pkgList[0]")
- }
-
- // read compiler-specific flags
- p.string() // discard
-
- // read consts
- for i := p.int(); i > 0; i-- {
- name := p.string()
- typ := p.typ(nil)
- val := p.value()
- p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
- }
-
- // read vars
- for i := p.int(); i > 0; i-- {
- name := p.string()
- typ := p.typ(nil)
- p.declare(types.NewVar(token.NoPos, pkg, name, typ))
- }
-
- // read funcs
- for i := p.int(); i > 0; i-- {
- name := p.string()
- sig := p.typ(nil).(*types.Signature)
- p.int() // read and discard index of inlined function body
- p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+ pkg := p.pkg()
+
+ // read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
+ objcount := 0
+ for {
+ tag := p.tagOrIndex()
+ if tag == endTag {
+ break
+ }
+ p.obj(tag)
+ objcount++
}
- // read types
- for i := p.int(); i > 0; i-- {
- // name is parsed as part of named type and the
- // type object is added to scope via respective
- // named type
- _ = p.typ(nil).(*types.Named)
+ // self-verification
+ if count := p.int(); count != objcount {
+ errorf("got %d objects; want %d", objcount, count)
}
// ignore compiler-specific import data
// 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()
}
}
@@ -120,23 +160,8 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
return p.read, pkg, nil
}
-type importer struct {
- imports map[string]*types.Package
- data []byte
- buf []byte // for reading strings
- bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
- pkgList []*types.Package
- typList []types.Type
-
- debugFormat bool
- read int // bytes read
-}
-
-func (p *importer) declare(obj types.Object) {
- if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
- // This can only happen if we import a package a second time.
- panic(fmt.Sprintf("%s already declared", alt.Name()))
- }
+func errorf(format string, args ...interface{}) {
+ panic(fmt.Sprintf(format, args...))
}
func (p *importer) pkg() *types.Package {
@@ -148,7 +173,7 @@ func (p *importer) pkg() *types.Package {
// otherwise, i is the package tag (< 0)
if i != packageTag {
- panic(fmt.Sprintf("unexpected package tag %d", i))
+ errorf("unexpected package tag %d", i)
}
// read package data
@@ -157,25 +182,179 @@ func (p *importer) pkg() *types.Package {
// we should never see an empty package name
if name == "" {
- panic("empty package name in import")
+ errorf("empty package name in import")
}
- // we should never see an empty import path
- if path == "" {
- panic("empty import path")
+ // an empty path denotes the package we are currently importing;
+ // it must be the first package we see
+ if (path == "") != (len(p.pkgList) == 0) {
+ errorf("package path %q for pkg index %d", path, len(p.pkgList))
}
// if the package was imported before, use that one; otherwise create a new one
+ if path == "" {
+ path = p.path
+ }
pkg := p.imports[path]
if pkg == nil {
pkg = types.NewPackage(path, name)
p.imports[path] = pkg
+ } else if pkg.Name() != name {
+ errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path)
}
p.pkgList = append(p.pkgList, pkg)
return pkg
}
+// objTag returns the tag value for each object kind.
+// obj must not be a *types.Alias.
+func objTag(obj types.Object) int {
+ switch obj.(type) {
+ case *types.Const:
+ return constTag
+ case *types.TypeName:
+ return typeTag
+ case *types.Var:
+ return varTag
+ case *types.Func:
+ return funcTag
+ // Aliases are not exported multiple times, thus we should not see them here.
+ default:
+ errorf("unexpected object: %v (%T)", obj, obj) // panics
+ panic("unreachable")
+ }
+}
+
+func sameObj(a, b types.Object) bool {
+ // Because unnamed types are not canonicalized, we cannot simply compare types for
+ // (pointer) identity.
+ // Ideally we'd check equality of constant values as well, but this is good enough.
+ return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
+}
+
+func (p *importer) declare(obj types.Object) {
+ pkg := obj.Pkg()
+ if alt := pkg.Scope().Insert(obj); alt != nil {
+ // This can only trigger if we import a (non-type) object a second time.
+ // Excluding aliases, this cannot happen because 1) we only import a package
+ // once; and b) we ignore compiler-specific export data which may contain
+ // functions whose inlined function bodies refer to other functions that
+ // were already imported.
+ // However, aliases require reexporting the original object, so we need
+ // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
+ // method importer.obj, switch case importing functions).
+ // Note that the original itself cannot be an alias.
+ if !sameObj(obj, alt) {
+ errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
+ }
+ }
+}
+
+func (p *importer) obj(tag int) {
+ switch tag {
+ case constTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ typ := p.typ(nil)
+ val := p.value()
+ p.declare(types.NewConst(pos, pkg, name, typ, val))
+
+ case typeTag:
+ p.typ(nil)
+
+ case varTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ typ := p.typ(nil)
+ p.declare(types.NewVar(pos, pkg, name, typ))
+
+ case funcTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ sig := types.NewSignature(nil, params, result, isddd)
+ p.declare(types.NewFunc(pos, pkg, name, sig))
+
+ case aliasTag:
+ pos := p.pos()
+ name := p.string()
+ var orig types.Object
+ if pkg, name := p.qualifiedName(); pkg != nil {
+ orig = pkg.Scope().Lookup(name)
+ }
+ // Alias-related code. Keep for now.
+ _ = pos
+ _ = name
+ _ = orig
+ // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
+
+ default:
+ errorf("unexpected object tag %d", tag)
+ }
+}
+
+func (p *importer) pos() token.Pos {
+ if !p.posInfoFormat {
+ return token.NoPos
+ }
+
+ file := p.prevFile
+ line := p.prevLine
+ if delta := p.int(); delta != 0 {
+ // line changed
+ line += delta
+ } else if n := p.int(); n >= 0 {
+ // file changed
+ file = p.prevFile[:n] + p.string()
+ p.prevFile = file
+ line = p.int()
+ }
+ p.prevLine = line
+
+ // Synthesize a token.Pos
+
+ // Since we don't know the set of needed file positions, we
+ // reserve maxlines positions per file.
+ const maxlines = 64 * 1024
+ f := p.files[file]
+ if f == nil {
+ f = p.fset.AddFile(file, -1, maxlines)
+ p.files[file] = f
+ // Allocate the fake linebreak indices on first use.
+ // TODO(adonovan): opt: save ~512KB using a more complex scheme?
+ fakeLinesOnce.Do(func() {
+ fakeLines = make([]int, maxlines)
+ for i := range fakeLines {
+ fakeLines[i] = i
+ }
+ })
+ f.SetLines(fakeLines)
+ }
+
+ if line > maxlines {
+ line = 1
+ }
+
+ // Treat the file as if it contained only newlines
+ // and column=1: use the line number as the offset.
+ return f.Pos(line - 1)
+}
+
+var (
+ fakeLines []int
+ fakeLinesOnce sync.Once
+)
+
+func (p *importer) qualifiedName() (pkg *types.Package, name string) {
+ name = p.string()
+ if name != "" {
+ pkg = p.pkg()
+ }
+ return
+}
+
func (p *importer) record(t types.Type) {
p.typList = append(p.typList, t)
}
@@ -205,19 +384,19 @@ func (p *importer) typ(parent *types.Package) types.Type {
switch i {
case namedTag:
// read type object
- name := p.string()
- parent = p.pkg()
+ pos := p.pos()
+ parent, name := p.qualifiedName()
scope := parent.Scope()
obj := scope.Lookup(name)
// if the object doesn't exist yet, create and insert it
if obj == nil {
- obj = types.NewTypeName(token.NoPos, parent, name, nil)
+ obj = types.NewTypeName(pos, parent, name, nil)
scope.Insert(obj)
}
if _, ok := obj.(*types.TypeName); !ok {
- panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj))
+ errorf("pkg = %s, name = %s => %s", parent, name, obj)
}
// associate new named type with obj if it doesn't exist yet
@@ -231,26 +410,35 @@ func (p *importer) typ(parent *types.Package) types.Type {
t0.SetUnderlying(p.typ(parent))
// interfaces don't have associated methods
- if _, ok := t0.Underlying().(*types.Interface); ok {
+ if types.IsInterface(t0) {
return t
}
// read associated methods
for i := p.int(); i > 0; i-- {
+ // TODO(gri) replace this with something closer to fieldName
+ pos := p.pos()
name := p.string()
+ if !exported(name) {
+ p.pkg()
+ }
+
recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params, isddd := p.paramList()
result, _ := p.paramList()
- p.int() // read and discard index of inlined function body
+ p.int() // go:nointerface pragma - discarded
+
sig := types.NewSignature(recv.At(0), params, result, isddd)
- t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
+ t0.AddMethod(types.NewFunc(pos, parent, name, sig))
}
return t
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)
@@ -258,42 +446,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)
-
- n := p.int()
- fields := make([]*types.Var, n)
- tags := make([]string, n)
- for i := range fields {
- fields[i] = p.field(parent)
- tags[i] = p.string()
+ if p.trackAllTypes {
+ p.record(t)
}
- *t = *types.NewStruct(fields, tags)
+
+ *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()
@@ -306,30 +497,26 @@ 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 {
- panic("unexpected embedded interface")
+ errorf("unexpected embedded interface")
}
- // read methods
- methods := make([]*types.Func, p.int())
- for i := range methods {
- pkg, name := p.fieldName(parent)
- params, isddd := p.paramList()
- result, _ := p.paramList()
- sig := types.NewSignature(nil, params, result, isddd)
- methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
+ t := types.NewInterface(p.methodList(parent), nil)
+ if p.trackAllTypes {
+ p.typList[n] = t
}
-
- t := types.NewInterface(methods, nil)
- 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)
@@ -338,7 +525,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
@@ -350,18 +539,32 @@ func (p *importer) typ(parent *types.Package) types.Type {
case 3 /* Cboth */ :
dir = types.SendRecv
default:
- panic(fmt.Sprintf("unexpected channel dir %d", d))
+ errorf("unexpected channel dir %d", d)
}
val := p.typ(parent)
*t = *types.NewChan(dir, val)
return t
default:
- panic(fmt.Sprintf("unexpected type tag %d", i))
+ errorf("unexpected type tag %d", i) // panics
+ panic("unreachable")
}
}
+func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) {
+ if n := p.int(); n > 0 {
+ fields = make([]*types.Var, n)
+ tags = make([]string, n)
+ for i := range fields {
+ fields[i] = p.field(parent)
+ tags[i] = p.string()
+ }
+ }
+ return
+}
+
func (p *importer) field(parent *types.Package) *types.Var {
+ pos := p.pos()
pkg, name := p.fieldName(parent)
typ := p.typ(parent)
@@ -375,28 +578,47 @@ func (p *importer) field(parent *types.Package) *types.Var {
case *types.Named:
name = typ.Obj().Name()
default:
- panic("anonymous field expected")
+ errorf("anonymous field expected")
}
anonymous = true
}
- return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+ return types.NewField(pos, pkg, name, typ, anonymous)
+}
+
+func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
+ if n := p.int(); n > 0 {
+ methods = make([]*types.Func, n)
+ for i := range methods {
+ methods[i] = p.method(parent)
+ }
+ }
+ return
+}
+
+func (p *importer) method(parent *types.Package) *types.Func {
+ pos := p.pos()
+ pkg, name := p.fieldName(parent)
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ sig := types.NewSignature(nil, params, result, isddd)
+ return types.NewFunc(pos, pkg, name, sig)
}
func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
+ name := p.string()
pkg := parent
if pkg == nil {
// use the imported package instead
pkg = p.pkgList[0]
}
- name := p.string()
- if name == "" {
- return pkg, "" // anonymous
+ if p.version == 0 && name == "_" {
+ // version 0 didn't export a package for _ fields
+ return pkg, name
}
- if name == "?" || name != "_" && !exported(name) {
- // explicitly qualified field
+ if name != "" && !exported(name) {
if name == "?" {
- name = "" // anonymous
+ name = ""
}
pkg = p.pkg()
}
@@ -430,18 +652,25 @@ func (p *importer) param(named bool) (*types.Var, bool) {
t = types.NewSlice(td.elem)
}
+ var pkg *types.Package
var name string
if named {
name = p.string()
if name == "" {
- panic("expected named parameter")
+ errorf("expected named parameter")
+ }
+ if name != "_" {
+ pkg = p.pkg()
+ }
+ if i := strings.Index(name, "·"); i > 0 {
+ name = name[:i] // cut off gc-specific parameter numbering
}
}
// read and discard compiler-specific info
p.string()
- return types.NewVar(token.NoPos, nil, name, t), isddd
+ return types.NewVar(token.NoPos, pkg, name, t), isddd
}
func exported(name string) bool {
@@ -465,8 +694,11 @@ func (p *importer) value() constant.Value {
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
case stringTag:
return constant.MakeString(p.string())
+ case unknownTag:
+ return constant.MakeUnknown()
default:
- panic(fmt.Sprintf("unexpected value tag %d", tag))
+ errorf("unexpected value tag %d", tag) // panics
+ panic("unreachable")
}
}
@@ -529,7 +761,7 @@ func (p *importer) tagOrIndex() int {
func (p *importer) int() int {
x := p.int64()
if int64(int(x)) != x {
- panic("exported integer too large")
+ errorf("exported integer too large")
}
return int(x)
}
@@ -546,50 +778,65 @@ func (p *importer) string() string {
if p.debugFormat {
p.marker('s')
}
-
- if n := int(p.rawInt64()); n > 0 {
- if cap(p.buf) < n {
- p.buf = make([]byte, n)
- } else {
- p.buf = p.buf[:n]
- }
- for i := 0; i < n; i++ {
- p.buf[i] = p.byte()
- }
- return string(p.buf)
+ // if the string was seen before, i is its index (>= 0)
+ // (the empty string is at index 0)
+ i := p.rawInt64()
+ if i >= 0 {
+ return p.strList[i]
}
-
- return ""
+ // otherwise, i is the negative string length (< 0)
+ if n := int(-i); n <= cap(p.buf) {
+ p.buf = p.buf[:n]
+ } else {
+ p.buf = make([]byte, n)
+ }
+ for i := range p.buf {
+ p.buf[i] = p.rawByte()
+ }
+ s := string(p.buf)
+ p.strList = append(p.strList, s)
+ return s
}
func (p *importer) marker(want byte) {
- if got := p.byte(); got != want {
- panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
+ if got := p.rawByte(); got != want {
+ errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
pos := p.read
if n := int(p.rawInt64()); n != pos {
- panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+ errorf("incorrect position: got %d; want %d", n, pos)
}
}
-// rawInt64 should only be used by low-level decoders
+// rawInt64 should only be used by low-level decoders.
func (p *importer) rawInt64() int64 {
i, err := binary.ReadVarint(p)
if err != nil {
- panic(fmt.Sprintf("read error: %v", err))
+ errorf("read error: %v", err)
}
return i
}
+// rawStringln should only be used to read the initial version string.
+func (p *importer) rawStringln(b byte) string {
+ p.buf = p.buf[:0]
+ for b != '\n' {
+ p.buf = append(p.buf, b)
+ b = p.rawByte()
+ }
+ return string(p.buf)
+}
+
// needed for binary.ReadVarint in rawInt64
func (p *importer) ReadByte() (byte, error) {
- return p.byte(), nil
+ return p.rawByte(), nil
}
// byte is the bottleneck interface for reading p.data.
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
-func (p *importer) byte() byte {
+// rawByte should only be used by low-level decoders.
+func (p *importer) rawByte() byte {
b := p.data[0]
r := 1
if b == '|' {
@@ -601,7 +848,7 @@ func (p *importer) byte() byte {
case '|':
// nothing to do
default:
- panic("unexpected escape sequence in export data")
+ errorf("unexpected escape sequence in export data")
}
}
p.data = p.data[r:]
@@ -615,8 +862,13 @@ func (p *importer) byte() byte {
// Tags. Must be < 0.
const (
- // Packages
+ // Objects
packageTag = -(iota + 1)
+ constTag
+ typeTag
+ varTag
+ funcTag
+ endTag
// Types
namedTag
@@ -638,6 +890,11 @@ const (
fractionTag // not used by gc
complexTag
stringTag
+ nilTag // only used by gc (appears in exported inlined function bodies)
+ unknownTag // not used by gc (only appears in packages with errors)
+
+ // Aliases
+ aliasTag
)
var predeclared = []types.Type{
@@ -678,4 +935,15 @@ var predeclared = []types.Type{
// package unsafe
types.Typ[types.UnsafePointer],
+
+ // invalid type
+ types.Typ[types.Invalid], // only appears in packages with errors
+
+ // used internally by gc; never used by this package or in .a files
+ anyType{},
}
+
+type anyType struct{}
+
+func (t anyType) Underlying() types.Type { return t }
+func (t anyType) String() string { return "any" }
diff --git a/libgo/go/go/internal/gcimporter/exportdata.go b/libgo/go/go/internal/gcimporter/exportdata.go
index 18bea415ae..c12e459c3d 100644
--- a/libgo/go/go/internal/gcimporter/exportdata.go
+++ b/libgo/go/go/internal/gcimporter/exportdata.go
@@ -8,7 +8,6 @@ package gcimporter
import (
"bufio"
- "errors"
"fmt"
"io"
"strconv"
@@ -29,7 +28,7 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
- err = errors.New("invalid archive header")
+ err = fmt.Errorf("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:16]))
@@ -46,47 +45,27 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Read first line to make sure this is an object file.
line, err := r.ReadSlice('\n')
if err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
if string(line) == "!<arch>\n" {
// Archive file. Scan to __.PKGDEF.
var name string
- var size int
- if name, size, err = readGopackHeader(r); err != nil {
+ if name, _, err = readGopackHeader(r); err != nil {
return
}
- // Optional leading __.GOSYMDEF or __.SYMDEF.
- // Read and discard.
- if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
- const block = 4096
- tmp := make([]byte, block)
- for size > 0 {
- n := size
- if n > block {
- n = block
- }
- if _, err = io.ReadFull(r, tmp[:n]); err != nil {
- return
- }
- size -= n
- }
-
- if name, _, err = readGopackHeader(r); err != nil {
- return
- }
- }
-
- // First real entry should be __.PKGDEF.
+ // First entry should be __.PKGDEF.
if name != "__.PKGDEF" {
- err = errors.New("go archive is missing __.PKGDEF")
+ err = fmt.Errorf("go archive is missing __.PKGDEF")
return
}
// Read first line of __.PKGDEF data, so that line
// is once again the first line of the input.
if line, err = r.ReadSlice('\n'); err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
@@ -94,7 +73,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
- err = errors.New("not a go object file")
+ err = fmt.Errorf("not a Go object file")
return
}
@@ -102,6 +81,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Begins after first line starting with $$.
for line[0] != '$' {
if line, err = r.ReadSlice('\n'); err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
diff --git a/libgo/go/go/internal/gcimporter/gcimporter.go b/libgo/go/go/internal/gcimporter/gcimporter.go
index d70ec083c3..f99f0f8bef 100644
--- a/libgo/go/go/internal/gcimporter/gcimporter.go
+++ b/libgo/go/go/internal/gcimporter/gcimporter.go
@@ -7,21 +7,14 @@ package gcimporter // import "go/internal/gcimporter"
import (
"bufio"
- "errors"
"fmt"
"go/build"
"go/token"
- "io"
+ "go/types"
"io/ioutil"
"os"
"path/filepath"
- "sort"
- "strconv"
"strings"
- "text/scanner"
-
- exact "go/constant"
- "go/types"
)
// debugging/development support
@@ -86,38 +79,6 @@ func FindPkg(path, srcDir string) (filename, id string) {
return
}
-// ImportData imports a package by reading the gc-generated export data,
-// adds the corresponding package object to the packages map indexed by id,
-// and returns the object.
-//
-// The packages map must contains all packages already imported. The data
-// reader position must be the beginning of the export data section. The
-// filename is only used in error messages.
-//
-// If packages[id] contains the completely imported package, that package
-// can be used directly, and there is no need to call this function (but
-// there is also no harm but for extra time used).
-//
-func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
- // support for parser error handling
- defer func() {
- switch r := recover().(type) {
- case nil:
- // nothing to do
- case importError:
- err = r
- default:
- panic(r) // internal error
- }
- }()
-
- var p parser
- p.init(filename, id, data, packages)
- pkg = p.parseExport()
-
- return
-}
-
// Import imports a gc-generated package given its import path and srcDir, adds
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
@@ -146,7 +107,7 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
f.Close()
if err != nil {
// add file name to error
- err = fmt.Errorf("reading export data: %s: %v", filename, err)
+ err = fmt.Errorf("%s: %v", filename, err)
}
}()
@@ -158,12 +119,15 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
switch hdr {
case "$$\n":
- return ImportData(packages, filename, id, buf)
+ err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
case "$$B\n":
var data []byte
data, err = ioutil.ReadAll(buf)
if err == nil {
- _, pkg, err = BImportData(packages, data, path)
+ // TODO(gri): allow clients of go/importer to provide a FileSet.
+ // Or, define a new standard go/types/gcexportdata package.
+ fset := token.NewFileSet()
+ _, pkg, err = BImportData(fset, packages, data, id)
return
}
default:
@@ -173,312 +137,6 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
return
}
-// ----------------------------------------------------------------------------
-// Parser
-
-// TODO(gri) Imported objects don't have position information.
-// Ideally use the debug table line info; alternatively
-// create some fake position (or the position of the
-// import). That way error messages referring to imported
-// objects can print meaningful information.
-
-// parser parses the exports inside a gc compiler-produced
-// object/archive file and populates its scope with the results.
-type parser struct {
- scanner scanner.Scanner
- tok rune // current token
- lit string // literal string; only valid for Ident, Int, String tokens
- id string // package id of imported package
- sharedPkgs map[string]*types.Package // package id -> package object (across importer)
- localPkgs map[string]*types.Package // package id -> package object (just this package)
-}
-
-func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) {
- p.scanner.Init(src)
- p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
- p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
- p.scanner.Whitespace = 1<<'\t' | 1<<' '
- p.scanner.Filename = filename // for good error messages
- p.next()
- p.id = id
- p.sharedPkgs = packages
- if debug {
- // check consistency of packages map
- for _, pkg := range packages {
- if pkg.Name() == "" {
- fmt.Printf("no package name for %s\n", pkg.Path())
- }
- }
- }
-}
-
-func (p *parser) next() {
- p.tok = p.scanner.Scan()
- switch p.tok {
- case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
- p.lit = p.scanner.TokenText()
- default:
- p.lit = ""
- }
- if debug {
- fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
- }
-}
-
-func declTypeName(pkg *types.Package, name string) *types.TypeName {
- scope := pkg.Scope()
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*types.TypeName)
- }
- obj := types.NewTypeName(token.NoPos, pkg, name, nil)
- // a named type may be referred to before the underlying type
- // is known - set it up
- types.NewNamed(obj, nil, nil)
- scope.Insert(obj)
- return obj
-}
-
-// ----------------------------------------------------------------------------
-// Error handling
-
-// Internal errors are boxed as importErrors.
-type importError struct {
- pos scanner.Position
- err error
-}
-
-func (e importError) Error() string {
- return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
-}
-
-func (p *parser) error(err interface{}) {
- if s, ok := err.(string); ok {
- err = errors.New(s)
- }
- // panic with a runtime.Error if err is not an error
- panic(importError{p.scanner.Pos(), err.(error)})
-}
-
-func (p *parser) errorf(format string, args ...interface{}) {
- p.error(fmt.Sprintf(format, args...))
-}
-
-func (p *parser) expect(tok rune) string {
- lit := p.lit
- if p.tok != tok {
- p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
- }
- p.next()
- return lit
-}
-
-func (p *parser) expectSpecial(tok string) {
- sep := 'x' // not white space
- i := 0
- for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- i++
- }
- if i < len(tok) {
- p.errorf("expected %q, got %q", tok, tok[0:i])
- }
-}
-
-func (p *parser) expectKeyword(keyword string) {
- lit := p.expect(scanner.Ident)
- if lit != keyword {
- p.errorf("expected keyword %s, got %q", keyword, lit)
- }
-}
-
-// ----------------------------------------------------------------------------
-// Qualified and unqualified names
-
-// PackageId = string_lit .
-//
-func (p *parser) parsePackageId() string {
- id, err := strconv.Unquote(p.expect(scanner.String))
- if err != nil {
- p.error(err)
- }
- // id == "" stands for the imported package id
- // (only known at time of package installation)
- if id == "" {
- id = p.id
- }
- return id
-}
-
-// PackageName = ident .
-//
-func (p *parser) parsePackageName() string {
- return p.expect(scanner.Ident)
-}
-
-// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
-func (p *parser) parseDotIdent() string {
- ident := ""
- if p.tok != scanner.Int {
- sep := 'x' // not white space
- for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
- ident += p.lit
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- }
- }
- if ident == "" {
- p.expect(scanner.Ident) // use expect() for error handling
- }
- return ident
-}
-
-// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
-//
-func (p *parser) parseQualifiedName() (id, name string) {
- p.expect('@')
- id = p.parsePackageId()
- p.expect('.')
- // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
- if p.tok == '?' {
- p.next()
- } else {
- name = p.parseDotIdent()
- }
- return
-}
-
-// getPkg returns the package for a given id. If the package is
-// not found, create the package and add it to the p.localPkgs
-// and p.sharedPkgs maps. name is the (expected) name of the
-// package. If name == "", the package name is expected to be
-// set later via an import clause in the export data.
-//
-// id identifies a package, usually by a canonical package path like
-// "encoding/json" but possibly by a non-canonical import path like
-// "./json".
-//
-func (p *parser) getPkg(id, name string) *types.Package {
- // package unsafe is not in the packages maps - handle explicitly
- if id == "unsafe" {
- return types.Unsafe
- }
-
- pkg := p.localPkgs[id]
- if pkg == nil {
- // first import of id from this package
- pkg = p.sharedPkgs[id]
- if pkg == nil {
- // first import of id by this importer;
- // add (possibly unnamed) pkg to shared packages
- pkg = types.NewPackage(id, name)
- p.sharedPkgs[id] = pkg
- }
- // add (possibly unnamed) pkg to local packages
- if p.localPkgs == nil {
- p.localPkgs = make(map[string]*types.Package)
- }
- p.localPkgs[id] = pkg
- } else if name != "" {
- // package exists already and we have an expected package name;
- // make sure names match or set package name if necessary
- if pname := pkg.Name(); pname == "" {
- pkg.SetName(name)
- } else if pname != name {
- p.errorf("%s package name mismatch: %s (given) vs %s (expected)", pname, name)
- }
- }
- return pkg
-}
-
-// parseExportedName is like parseQualifiedName, but
-// the package id is resolved to an imported *types.Package.
-//
-func (p *parser) parseExportedName() (pkg *types.Package, name string) {
- id, name := p.parseQualifiedName()
- pkg = p.getPkg(id, "")
- return
-}
-
-// ----------------------------------------------------------------------------
-// Types
-
-// BasicType = identifier .
-//
-func (p *parser) parseBasicType() types.Type {
- id := p.expect(scanner.Ident)
- obj := types.Universe.Lookup(id)
- if obj, ok := obj.(*types.TypeName); ok {
- return obj.Type()
- }
- p.errorf("not a basic type: %s", id)
- return nil
-}
-
-// ArrayType = "[" int_lit "]" Type .
-//
-func (p *parser) parseArrayType(parent *types.Package) types.Type {
- // "[" already consumed and lookahead known not to be "]"
- lit := p.expect(scanner.Int)
- p.expect(']')
- elem := p.parseType(parent)
- n, err := strconv.ParseInt(lit, 10, 64)
- if err != nil {
- p.error(err)
- }
- return types.NewArray(elem, n)
-}
-
-// MapType = "map" "[" Type "]" Type .
-//
-func (p *parser) parseMapType(parent *types.Package) types.Type {
- p.expectKeyword("map")
- p.expect('[')
- key := p.parseType(parent)
- p.expect(']')
- elem := p.parseType(parent)
- return types.NewMap(key, elem)
-}
-
-// Name = identifier | "?" | QualifiedName .
-//
-// For unqualified and anonymous names, the returned package is the parent
-// package unless parent == nil, in which case the returned package is the
-// package being imported. (The parent package is not nil if the the name
-// is an unqualified struct field or interface method name belonging to a
-// type declared in another package.)
-//
-// For qualified names, the returned package is nil (and not created if
-// it doesn't exist yet) unless materializePkg is set (which creates an
-// unnamed package with valid package path). In the latter case, a
-// subequent import clause is expected to provide a name for the package.
-//
-func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
- pkg = parent
- if pkg == nil {
- pkg = p.sharedPkgs[p.id]
- }
- switch p.tok {
- case scanner.Ident:
- name = p.lit
- p.next()
- case '?':
- // anonymous
- p.next()
- case '@':
- // exported name prefixed with package path
- pkg = nil
- var id string
- id, name = p.parseQualifiedName()
- if materializePkg {
- pkg = p.getPkg(id, "")
- }
- default:
- p.error("name expected")
- }
- return
-}
-
func deref(typ types.Type) types.Type {
if p, _ := typ.(*types.Pointer); p != nil {
return p.Elem()
@@ -486,531 +144,6 @@ func deref(typ types.Type) types.Type {
return typ
}
-// Field = Name Type [ string_lit ] .
-//
-func (p *parser) parseField(parent *types.Package) (*types.Var, string) {
- pkg, name := p.parseName(parent, true)
- typ := p.parseType(parent)
- anonymous := false
- if name == "" {
- // anonymous field - typ must be T or *T and T must be a type name
- switch typ := deref(typ).(type) {
- case *types.Basic: // basic types are named types
- pkg = nil // objects defined in Universe scope have no package
- name = typ.Name()
- case *types.Named:
- name = typ.Obj().Name()
- default:
- p.errorf("anonymous field expected")
- }
- anonymous = true
- }
- tag := ""
- if p.tok == scanner.String {
- s := p.expect(scanner.String)
- var err error
- tag, err = strconv.Unquote(s)
- if err != nil {
- p.errorf("invalid struct tag %s: %s", s, err)
- }
- }
- return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
-}
-
-// StructType = "struct" "{" [ FieldList ] "}" .
-// FieldList = Field { ";" Field } .
-//
-func (p *parser) parseStructType(parent *types.Package) types.Type {
- var fields []*types.Var
- var tags []string
-
- p.expectKeyword("struct")
- p.expect('{')
- for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
- if i > 0 {
- p.expect(';')
- }
- fld, tag := p.parseField(parent)
- if tag != "" && tags == nil {
- tags = make([]string, i)
- }
- if tags != nil {
- tags = append(tags, tag)
- }
- fields = append(fields, fld)
- }
- p.expect('}')
-
- return types.NewStruct(fields, tags)
-}
-
-// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
-//
-func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
- _, name := p.parseName(nil, false)
- // remove gc-specific parameter numbering
- if i := strings.Index(name, "·"); i >= 0 {
- name = name[:i]
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- isVariadic = true
- }
- typ := p.parseType(nil)
- if isVariadic {
- typ = types.NewSlice(typ)
- }
- // ignore argument tag (e.g. "noescape")
- if p.tok == scanner.String {
- p.next()
- }
- // TODO(gri) should we provide a package?
- par = types.NewVar(token.NoPos, nil, name, typ)
- return
-}
-
-// Parameters = "(" [ ParameterList ] ")" .
-// ParameterList = { Parameter "," } Parameter .
-//
-func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
- p.expect('(')
- for p.tok != ')' && p.tok != scanner.EOF {
- if len(list) > 0 {
- p.expect(',')
- }
- par, variadic := p.parseParameter()
- list = append(list, par)
- if variadic {
- if isVariadic {
- p.error("... not on final argument")
- }
- isVariadic = true
- }
- }
- p.expect(')')
-
- return
-}
-
-// Signature = Parameters [ Result ] .
-// Result = Type | Parameters .
-//
-func (p *parser) parseSignature(recv *types.Var) *types.Signature {
- params, isVariadic := p.parseParameters()
-
- // optional result type
- var results []*types.Var
- if p.tok == '(' {
- var variadic bool
- results, variadic = p.parseParameters()
- if variadic {
- p.error("... not permitted on result type")
- }
- }
-
- return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
-}
-
-// InterfaceType = "interface" "{" [ MethodList ] "}" .
-// MethodList = Method { ";" Method } .
-// Method = Name Signature .
-//
-// The methods of embedded interfaces are always "inlined"
-// by the compiler and thus embedded interfaces are never
-// visible in the export data.
-//
-func (p *parser) parseInterfaceType(parent *types.Package) types.Type {
- var methods []*types.Func
-
- p.expectKeyword("interface")
- p.expect('{')
- for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
- if i > 0 {
- p.expect(';')
- }
- pkg, name := p.parseName(parent, true)
- sig := p.parseSignature(nil)
- methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
- }
- p.expect('}')
-
- // Complete requires the type's embedded interfaces to be fully defined,
- // but we do not define any
- return types.NewInterface(methods, nil).Complete()
-}
-
-// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
-//
-func (p *parser) parseChanType(parent *types.Package) types.Type {
- dir := types.SendRecv
- if p.tok == scanner.Ident {
- p.expectKeyword("chan")
- if p.tok == '<' {
- p.expectSpecial("<-")
- dir = types.SendOnly
- }
- } else {
- p.expectSpecial("<-")
- p.expectKeyword("chan")
- dir = types.RecvOnly
- }
- elem := p.parseType(parent)
- return types.NewChan(dir, elem)
-}
-
-// Type =
-// BasicType | TypeName | ArrayType | SliceType | StructType |
-// PointerType | FuncType | InterfaceType | MapType | ChanType |
-// "(" Type ")" .
-//
-// BasicType = ident .
-// TypeName = ExportedName .
-// SliceType = "[" "]" Type .
-// PointerType = "*" Type .
-// FuncType = "func" Signature .
-//
-func (p *parser) parseType(parent *types.Package) types.Type {
- switch p.tok {
- case scanner.Ident:
- switch p.lit {
- default:
- return p.parseBasicType()
- case "struct":
- return p.parseStructType(parent)
- case "func":
- // FuncType
- p.next()
- return p.parseSignature(nil)
- case "interface":
- return p.parseInterfaceType(parent)
- case "map":
- return p.parseMapType(parent)
- case "chan":
- return p.parseChanType(parent)
- }
- case '@':
- // TypeName
- pkg, name := p.parseExportedName()
- return declTypeName(pkg, name).Type()
- case '[':
- p.next() // look ahead
- if p.tok == ']' {
- // SliceType
- p.next()
- return types.NewSlice(p.parseType(parent))
- }
- return p.parseArrayType(parent)
- case '*':
- // PointerType
- p.next()
- return types.NewPointer(p.parseType(parent))
- case '<':
- return p.parseChanType(parent)
- case '(':
- // "(" Type ")"
- p.next()
- typ := p.parseType(parent)
- p.expect(')')
- return typ
- }
- p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
- return nil
-}
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-// ImportDecl = "import" PackageName PackageId .
-//
-func (p *parser) parseImportDecl() {
- p.expectKeyword("import")
- name := p.parsePackageName()
- p.getPkg(p.parsePackageId(), name)
-}
-
-// int_lit = [ "+" | "-" ] { "0" ... "9" } .
-//
-func (p *parser) parseInt() string {
- s := ""
- switch p.tok {
- case '-':
- s = "-"
- p.next()
- case '+':
- p.next()
- }
- return s + p.expect(scanner.Int)
-}
-
-// number = int_lit [ "p" int_lit ] .
-//
-func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
- // mantissa
- mant := exact.MakeFromLiteral(p.parseInt(), token.INT, 0)
- if mant == nil {
- panic("invalid mantissa")
- }
-
- if p.lit == "p" {
- // exponent (base 2)
- p.next()
- exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
- if err != nil {
- p.error(err)
- }
- if exp < 0 {
- denom := exact.MakeInt64(1)
- denom = exact.Shift(denom, token.SHL, uint(-exp))
- typ = types.Typ[types.UntypedFloat]
- val = exact.BinaryOp(mant, token.QUO, denom)
- return
- }
- if exp > 0 {
- mant = exact.Shift(mant, token.SHL, uint(exp))
- }
- typ = types.Typ[types.UntypedFloat]
- val = mant
- return
- }
-
- typ = types.Typ[types.UntypedInt]
- val = mant
- return
-}
-
-// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
-// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
-// bool_lit = "true" | "false" .
-// complex_lit = "(" float_lit "+" float_lit "i" ")" .
-// rune_lit = "(" int_lit "+" int_lit ")" .
-// string_lit = `"` { unicode_char } `"` .
-//
-func (p *parser) parseConstDecl() {
- p.expectKeyword("const")
- pkg, name := p.parseExportedName()
-
- var typ0 types.Type
- if p.tok != '=' {
- // constant types are never structured - no need for parent type
- typ0 = p.parseType(nil)
- }
-
- p.expect('=')
- var typ types.Type
- var val exact.Value
- switch p.tok {
- case scanner.Ident:
- // bool_lit
- if p.lit != "true" && p.lit != "false" {
- p.error("expected true or false")
- }
- typ = types.Typ[types.UntypedBool]
- val = exact.MakeBool(p.lit == "true")
- p.next()
-
- case '-', scanner.Int:
- // int_lit
- typ, val = p.parseNumber()
-
- case '(':
- // complex_lit or rune_lit
- p.next()
- if p.tok == scanner.Char {
- p.next()
- p.expect('+')
- typ = types.Typ[types.UntypedRune]
- _, val = p.parseNumber()
- p.expect(')')
- break
- }
- _, re := p.parseNumber()
- p.expect('+')
- _, im := p.parseNumber()
- p.expectKeyword("i")
- p.expect(')')
- typ = types.Typ[types.UntypedComplex]
- val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
-
- case scanner.Char:
- // rune_lit
- typ = types.Typ[types.UntypedRune]
- val = exact.MakeFromLiteral(p.lit, token.CHAR, 0)
- p.next()
-
- case scanner.String:
- // string_lit
- typ = types.Typ[types.UntypedString]
- val = exact.MakeFromLiteral(p.lit, token.STRING, 0)
- p.next()
-
- default:
- p.errorf("expected literal got %s", scanner.TokenString(p.tok))
- }
-
- if typ0 == nil {
- typ0 = typ
- }
-
- pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
-}
-
-// TypeDecl = "type" ExportedName Type .
-//
-func (p *parser) parseTypeDecl() {
- p.expectKeyword("type")
- pkg, name := p.parseExportedName()
- obj := declTypeName(pkg, name)
-
- // The type object may have been imported before and thus already
- // have a type associated with it. We still need to parse the type
- // structure, but throw it away if the object already has a type.
- // This ensures that all imports refer to the same type object for
- // a given type declaration.
- typ := p.parseType(pkg)
-
- if name := obj.Type().(*types.Named); name.Underlying() == nil {
- name.SetUnderlying(typ)
- }
-}
-
-// VarDecl = "var" ExportedName Type .
-//
-func (p *parser) parseVarDecl() {
- p.expectKeyword("var")
- pkg, name := p.parseExportedName()
- typ := p.parseType(pkg)
- pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
-}
-
-// Func = Signature [ Body ] .
-// Body = "{" ... "}" .
-//
-func (p *parser) parseFunc(recv *types.Var) *types.Signature {
- sig := p.parseSignature(recv)
- if p.tok == '{' {
- p.next()
- for i := 1; i > 0; p.next() {
- switch p.tok {
- case '{':
- i++
- case '}':
- i--
- }
- }
- }
- return sig
-}
-
-// MethodDecl = "func" Receiver Name Func .
-// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
-//
-func (p *parser) parseMethodDecl() {
- // "func" already consumed
- p.expect('(')
- recv, _ := p.parseParameter() // receiver
- p.expect(')')
-
- // determine receiver base type object
- base := deref(recv.Type()).(*types.Named)
-
- // parse method name, signature, and possibly inlined body
- _, name := p.parseName(nil, false)
- sig := p.parseFunc(recv)
-
- // methods always belong to the same package as the base type object
- pkg := base.Obj().Pkg()
-
- // add method to type unless type was imported before
- // and method exists already
- // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
- base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
-}
-
-// FuncDecl = "func" ExportedName Func .
-//
-func (p *parser) parseFuncDecl() {
- // "func" already consumed
- pkg, name := p.parseExportedName()
- typ := p.parseFunc(nil)
- pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
-}
-
-// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
-//
-func (p *parser) parseDecl() {
- if p.tok == scanner.Ident {
- switch p.lit {
- case "import":
- p.parseImportDecl()
- case "const":
- p.parseConstDecl()
- case "type":
- p.parseTypeDecl()
- case "var":
- p.parseVarDecl()
- case "func":
- p.next() // look ahead
- if p.tok == '(' {
- p.parseMethodDecl()
- } else {
- p.parseFuncDecl()
- }
- }
- }
- p.expect('\n')
-}
-
-// ----------------------------------------------------------------------------
-// Export
-
-// Export = "PackageClause { Decl } "$$" .
-// PackageClause = "package" PackageName [ "safe" ] "\n" .
-//
-func (p *parser) parseExport() *types.Package {
- p.expectKeyword("package")
- name := p.parsePackageName()
- if p.tok == scanner.Ident && p.lit == "safe" {
- // package was compiled with -u option - ignore
- p.next()
- }
- p.expect('\n')
-
- pkg := p.getPkg(p.id, name)
-
- for p.tok != '$' && p.tok != scanner.EOF {
- p.parseDecl()
- }
-
- if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
- // don't call next()/expect() since reading past the
- // export data may cause scanner errors (e.g. NUL chars)
- p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
- }
-
- if n := p.scanner.ErrorCount; n != 0 {
- p.errorf("expected no scanner errors, got %d", n)
- }
-
- // Record all locally referenced packages as imports.
- var imports []*types.Package
- for id, pkg2 := range p.localPkgs {
- if pkg2.Name() == "" {
- p.errorf("%s package has no name", id)
- }
- if id == p.id {
- continue // avoid self-edge
- }
- imports = append(imports, pkg2)
- }
- sort.Sort(byPath(imports))
- pkg.SetImports(imports)
-
- // package was imported completely and without errors
- pkg.MarkComplete()
-
- return pkg
-}
-
type byPath []*types.Package
func (a byPath) Len() int { return len(a) }
diff --git a/libgo/go/go/internal/gcimporter/gcimporter_test.go b/libgo/go/go/internal/gcimporter/gcimporter_test.go
index e56720b0d5..a0697faeb6 100644
--- a/libgo/go/go/internal/gcimporter/gcimporter_test.go
+++ b/libgo/go/go/internal/gcimporter/gcimporter_test.go
@@ -5,6 +5,7 @@
package gcimporter
import (
+ "bytes"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -34,22 +35,7 @@ func skipSpecialPlatforms(t *testing.T) {
}
func compile(t *testing.T, dirname, filename string) string {
- testenv.MustHaveGoBuild(t)
- cmd := exec.Command("go", "tool", "compile", filename)
- cmd.Dir = dirname
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Logf("%s", out)
- t.Fatalf("go tool compile %s failed: %s", filename, err)
- }
- // filename should end with ".go"
- return filepath.Join(dirname, filename[:len(filename)-2]+"o")
-}
-
-// TODO(gri) Remove this function once we switched to new export format by default.
-func compileNewExport(t *testing.T, dirname, filename string) string {
- testenv.MustHaveGoBuild(t)
- cmd := exec.Command("go", "tool", "compile", "-newexport", filename)
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
if err != nil {
@@ -121,6 +107,8 @@ func TestImportTestdata(t *testing.T) {
// additional packages that are not strictly required for
// import processing alone (they are exported to err "on
// the safe side").
+ // TODO(gri) update the want list to be precise, now that
+ // the textual export data is gone.
got := fmt.Sprint(pkg.Imports())
for _, want := range []string{"go/ast", "go/token"} {
if !strings.Contains(got, want) {
@@ -130,27 +118,66 @@ func TestImportTestdata(t *testing.T) {
}
}
-// TODO(gri) Remove this function once we switched to new export format by default
-// (and update the comment and want list in TestImportTestdata).
-func TestImportTestdataNewExport(t *testing.T) {
+func TestVersionHandling(t *testing.T) {
+ skipSpecialPlatforms(t) // we really only need to exclude nacl platforms, but this is fine
+
// This package only handles gc export data.
if runtime.Compiler != "gc" {
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
return
}
- if outFn := compileNewExport(t, "testdata", "exports.go"); outFn != "" {
- defer os.Remove(outFn)
+ const dir = "./testdata/versions"
+ list, err := ioutil.ReadDir(dir)
+ if err != nil {
+ t.Fatal(err)
}
- if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
- // The package's Imports list must include all packages
- // explicitly imported by exports.go, plus all packages
- // referenced indirectly via exported objects in exports.go.
- want := `[package ast ("go/ast") package token ("go/token")]`
- got := fmt.Sprint(pkg.Imports())
- if got != want {
- t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
+ for _, f := range list {
+ name := f.Name()
+ if !strings.HasSuffix(name, ".a") {
+ continue // not a package file
+ }
+ if strings.Contains(name, "corrupted") {
+ continue // don't process a leftover corrupted file
+ }
+ pkgpath := "./" + name[:len(name)-2]
+
+ // test that export data can be imported
+ _, err := Import(make(map[string]*types.Package), pkgpath, dir)
+ if err != nil {
+ t.Errorf("import %q failed: %v", pkgpath, err)
+ continue
+ }
+
+ // create file with corrupted export data
+ // 1) read file
+ data, err := ioutil.ReadFile(filepath.Join(dir, name))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // 2) find export data
+ i := bytes.Index(data, []byte("\n$$B\n")) + 5
+ j := bytes.Index(data[i:], []byte("\n$$\n")) + i
+ if i < 0 || j < 0 || i > j {
+ t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
+ }
+ // 3) corrupt the data (increment every 7th byte)
+ for k := j - 13; k >= i; k -= 7 {
+ data[k]++
+ }
+ // 4) write the file
+ pkgpath += "_corrupted"
+ filename := filepath.Join(dir, pkgpath) + ".a"
+ ioutil.WriteFile(filename, data, 0666)
+ defer os.Remove(filename)
+
+ // test that importing the corrupted file results in an error
+ _, err = Import(make(map[string]*types.Package), pkgpath, dir)
+ if err == nil {
+ t.Errorf("import corrupted %q succeeded", pkgpath)
+ } else if msg := err.Error(); !strings.Contains(msg, "version skew") {
+ t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
}
}
}
@@ -351,9 +378,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 +388,67 @@ 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)
+ }
+ }
+}
+
+func TestIssue15920(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", "issue15920.go"); f != "" {
+ defer os.Remove(f)
+ }
+
+ imports := make(map[string]*types.Package)
+ if _, err := Import(imports, "./testdata/issue15920", "."); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/libgo/go/go/internal/gcimporter/testdata/exports.go b/libgo/go/go/internal/gcimporter/testdata/exports.go
index 8ee28b0942..9a0273ba20 100644
--- a/libgo/go/go/internal/gcimporter/testdata/exports.go
+++ b/libgo/go/go/internal/gcimporter/testdata/exports.go
@@ -7,9 +7,7 @@
package exports
-import (
- "go/ast"
-)
+import "go/ast"
// Issue 3682: Correctly read dotted identifiers from export data.
const init1 = 0
@@ -77,7 +75,8 @@ type (
var (
V0 int
- V1 = -991.0
+ V1 = -991.0
+ V2 float32 = 1.2
)
func F1() {}
diff --git a/libgo/go/go/internal/gcimporter/testdata/issue15920.go b/libgo/go/go/internal/gcimporter/testdata/issue15920.go
new file mode 100644
index 0000000000..c70f7d8267
--- /dev/null
+++ b/libgo/go/go/internal/gcimporter/testdata/issue15920.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// The underlying type of Error is the underlying type of error.
+// Make sure we can import this again without problems.
+type Error error
+
+func F() Error { return nil }
diff --git a/libgo/go/go/internal/gcimporter/testdata/p.go b/libgo/go/go/internal/gcimporter/testdata/p.go
new file mode 100644
index 0000000000..9e2e705765
--- /dev/null
+++ b/libgo/go/go/internal/gcimporter/testdata/p.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Input for TestIssue15517
+
+package p
+
+const C = 0
+
+var V int
+
+func F() {}
diff --git a/libgo/go/go/internal/gcimporter/testdata/versions/test.go b/libgo/go/go/internal/gcimporter/testdata/versions/test.go
new file mode 100644
index 0000000000..ac9c968c2d
--- /dev/null
+++ b/libgo/go/go/internal/gcimporter/testdata/versions/test.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// To create a test case for a new export format version,
+// build this package with the latest compiler and store
+// the resulting .a file appropriately named in the versions
+// directory. The VersionHandling test will pick it up.
+//
+// In the testdata/versions:
+//
+// go build -o test_go1.$X_$Y.a test.go
+//
+// with $X = Go version and $Y = export format version.
+//
+// Make sure this source is extended such that it exercises
+// whatever export format change has taken place.
+
+package test
+
+// Any release before and including Go 1.7 didn't encode
+// the package for a blank struct field.
+type BlankField struct {
+ _ int
+}
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
index c6fd93240a..724d8658a7 100644
--- a/libgo/go/go/parser/interface.go
+++ b/libgo/go/go/parser/interface.go
@@ -73,7 +73,7 @@ const (
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality. Position information is recorded in the
-// file set fset.
+// file set fset, which must not be nil.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
@@ -82,6 +82,10 @@ const (
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
+ if fset == nil {
+ panic("parser.ParseFile: no token.FileSet provided (fset == nil)")
+ }
+
// get source
text, err := readSource(filename, src)
if err != nil {
@@ -125,7 +129,8 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
//
// If filter != nil, only the files with os.FileInfo entries passing through
// the filter (and ending in ".go") are considered. The mode bits are passed
-// to ParseFile unchanged. Position information is recorded in fset.
+// to ParseFile unchanged. Position information is recorded in fset, which
+// must not be nil.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occurred, a non-nil but incomplete map and the
@@ -168,10 +173,15 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
}
// ParseExprFrom is a convenience function for parsing an expression.
-// The arguments have the same meaning as for Parse, but the source must
-// be a valid Go (type or value) expression.
+// The arguments have the same meaning as for ParseFile, but the source must
+// be a valid Go (type or value) expression. Specifically, fset must not
+// be nil.
//
func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
+ if fset == nil {
+ panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)")
+ }
+
// get source
text, err := readSource(filename, src)
if err != nil {
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index f3a26032ee..d3ef7db31e 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -1597,23 +1597,19 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
}
x := p.parseUnaryExpr(lhs)
- for _, prec := p.tokPrec(); prec >= prec1; prec-- {
- for {
- op, oprec := p.tokPrec()
- if oprec != prec {
- break
- }
- pos := p.expect(op)
- if lhs {
- p.resolve(x)
- lhs = false
- }
- y := p.parseBinaryExpr(false, prec+1)
- x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
+ for {
+ op, oprec := p.tokPrec()
+ if oprec < prec1 {
+ return x
+ }
+ pos := p.expect(op)
+ if lhs {
+ p.resolve(x)
+ lhs = false
}
+ y := p.parseBinaryExpr(false, oprec+1)
+ x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
}
-
- return x
}
// If lhs is set and the result is an identifier, it is not resolved.
diff --git a/libgo/go/go/parser/performance_test.go b/libgo/go/go/parser/performance_test.go
index f2732c0e2b..b2e1c11e9d 100644
--- a/libgo/go/go/parser/performance_test.go
+++ b/libgo/go/go/parser/performance_test.go
@@ -10,17 +10,12 @@ import (
"testing"
)
-var src = readFile("parser.go")
-
-func readFile(filename string) []byte {
- data, err := ioutil.ReadFile(filename)
+func BenchmarkParse(b *testing.B) {
+ src, err := ioutil.ReadFile("parser.go")
if err != nil {
- panic(err)
+ b.Fatal(err)
}
- return data
-}
-
-func BenchmarkParse(b *testing.B) {
+ b.ResetTimer()
b.SetBytes(int64(len(src)))
for i := 0; i < b.N; i++ {
if _, err := ParseFile(token.NewFileSet(), "", src, ParseComments); err != nil {
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 11f26d45ea..ea432860a8 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -733,7 +733,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
case *ast.FuncLit:
p.expr(x.Type)
- p.adjBlock(p.distanceFrom(x.Type.Pos()), blank, x.Body)
+ p.funcBody(p.distanceFrom(x.Type.Pos()), blank, x.Body)
case *ast.ParenExpr:
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
@@ -825,6 +825,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
if x.Type != nil {
p.expr1(x.Type, token.HighestPrec, depth)
}
+ p.level++
p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
// do not insert extra line break following a /*-style comment
@@ -837,6 +838,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
mode |= noExtraBlank
}
p.print(mode, x.Rbrace, token.RBRACE, mode)
+ p.level--
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
@@ -1557,18 +1559,23 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
return bodySize
}
-// adjBlock prints an "adjacent" block (e.g., a for-loop or function body) following
-// a header (e.g., a for-loop control clause or function signature) of given headerSize.
+// funcBody prints a function body following a function header of given headerSize.
// If the header's and block's size are "small enough" and the block is "simple enough",
// the block is printed on the current line, without line breaks, spaced from the header
// by sep. Otherwise the block's opening "{" is printed on the current line, followed by
// lines for the block's statements and its closing "}".
//
-func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
+func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
if b == nil {
return
}
+ // save/restore composite literal nesting level
+ defer func(level int) {
+ p.level = level
+ }(p.level)
+ p.level = 0
+
const maxSize = 100
if headerSize+p.bodySize(b, maxSize) <= maxSize {
p.print(sep, b.Lbrace, token.LBRACE)
@@ -1613,7 +1620,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
}
p.expr(d.Name)
p.signature(d.Type.Params, d.Type.Results)
- p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body)
+ p.funcBody(p.distanceFrom(d.Pos()), vtab, d.Body)
}
func (p *printer) decl(decl ast.Decl) {
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index a3eaa6638e..be61dad590 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -58,6 +58,7 @@ type printer struct {
// Current state
output []byte // raw printer result
indent int // current indentation
+ level int // level == 0: outside composite literal; level > 0: inside composite literal
mode pmode // current printer mode
impliedSemi bool // if set, a linebreak implies a semicolon
lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
@@ -712,6 +713,16 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, dropped
return
}
+// containsLinebreak reports whether the whitespace buffer contains any line breaks.
+func (p *printer) containsLinebreak() bool {
+ for _, ch := range p.wsbuf {
+ if ch == newline || ch == formfeed {
+ return true
+ }
+ }
+ return false
+}
+
// intersperseComments consumes all comments that appear before the next token
// tok and prints it together with the buffered whitespace (i.e., the whitespace
// that needs to be written before the next token). A heuristic is used to mix
@@ -730,23 +741,35 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
}
if last != nil {
- // if the last comment is a /*-style comment and the next item
+ // If the last comment is a /*-style comment and the next item
// follows on the same line but is not a comma, and not a "closing"
// token immediately following its corresponding "opening" token,
- // add an extra blank for separation unless explicitly disabled
+ // add an extra separator unless explicitly disabled. Use a blank
+ // as separator unless we have pending linebreaks, they are not
+ // disabled, and we are outside a composite literal, in which case
+ // we want a linebreak (issue 15137).
+ // TODO(gri) This has become overly complicated. We should be able
+ // to track whether we're inside an expression or statement and
+ // use that information to decide more directly.
+ needsLinebreak := false
if p.mode&noExtraBlank == 0 &&
last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
tok != token.COMMA &&
(tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
(tok != token.RBRACK || p.prevOpen == token.LBRACK) {
- p.writeByte(' ', 1)
+ if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 && p.level == 0 {
+ needsLinebreak = true
+ } else {
+ p.writeByte(' ', 1)
+ }
+ }
+ // Ensure that there is a line break after a //-style comment,
+ // before EOF, and before a closing '}' unless explicitly disabled.
+ if last.Text[1] == '/' ||
+ tok == token.EOF ||
+ tok == token.RBRACE && p.mode&noExtraLinebreak == 0 {
+ needsLinebreak = true
}
- // ensure that there is a line break after a //-style comment,
- // before a closing '}' unless explicitly disabled, or at eof
- needsLinebreak :=
- last.Text[1] == '/' ||
- tok == token.RBRACE && p.mode&noExtraLinebreak == 0 ||
- tok == token.EOF
return p.writeCommentSuffix(needsLinebreak)
}
@@ -1292,6 +1315,8 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
// Fprint "pretty-prints" an AST node to output.
// It calls Config.Fprint with default settings.
+// Note that gofmt uses tabs for indentation but spaces for alignent;
+// use format.Node (package go/format) for output that matches gofmt.
//
func Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
return (&Config{Tabwidth: 8}).Fprint(output, fset, node)
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 73f9ead5a3..0badbfba69 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -197,12 +197,17 @@ var data = []entry{
}
func TestFiles(t *testing.T) {
+ t.Parallel()
for _, e := range data {
source := filepath.Join(dataDir, e.source)
golden := filepath.Join(dataDir, e.golden)
- check(t, source, golden, e.mode)
- // TODO(gri) check that golden is idempotent
- //check(t, golden, golden, e.mode)
+ mode := e.mode
+ t.Run(e.source, func(t *testing.T) {
+ t.Parallel()
+ check(t, source, golden, mode)
+ // TODO(gri) check that golden is idempotent
+ //check(t, golden, golden, e.mode)
+ })
}
}
@@ -295,6 +300,7 @@ func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) {
// even if the position information of comments introducing newlines
// is incorrect.
func TestBadComments(t *testing.T) {
+ t.Parallel()
const src = `
// first comment - text and position changed by test
package p
@@ -481,6 +487,7 @@ func TestStmtLists(t *testing.T) {
}
func TestBaseIndent(t *testing.T) {
+ t.Parallel()
// The testfile must not contain multi-line raw strings since those
// are not indented (because their values must not change) and make
// this test fail.
@@ -495,28 +502,31 @@ func TestBaseIndent(t *testing.T) {
panic(err) // error in test
}
- var buf bytes.Buffer
for indent := 0; indent < 4; indent++ {
- buf.Reset()
- (&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
- // all code must be indented by at least 'indent' tabs
- lines := bytes.Split(buf.Bytes(), []byte{'\n'})
- for i, line := range lines {
- if len(line) == 0 {
- continue // empty lines don't have indentation
- }
- n := 0
- for j, b := range line {
- if b != '\t' {
- // end of indentation
- n = j
- break
+ indent := indent
+ t.Run(fmt.Sprint(indent), func(t *testing.T) {
+ t.Parallel()
+ var buf bytes.Buffer
+ (&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
+ // all code must be indented by at least 'indent' tabs
+ lines := bytes.Split(buf.Bytes(), []byte{'\n'})
+ for i, line := range lines {
+ if len(line) == 0 {
+ continue // empty lines don't have indentation
+ }
+ n := 0
+ for j, b := range line {
+ if b != '\t' {
+ // end of indentation
+ n = j
+ break
+ }
+ }
+ if n < indent {
+ t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
}
}
- if n < indent {
- t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
- }
- }
+ })
}
}
@@ -567,6 +577,7 @@ func (l *limitWriter) Write(buf []byte) (n int, err error) {
// Test whether the printer stops writing after the first error
func TestWriteErrors(t *testing.T) {
+ t.Parallel()
const filename = "printer.go"
src, err := ioutil.ReadFile(filename)
if err != nil {
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index 849fa62448..4d92e65327 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -601,6 +601,32 @@ func _() {
_ = a
}
+// Test cases from issues 11274, 15137:
+// Semicolon must not be lost when multiple statements are on the same line with a comment.
+func _() {
+ x := 0 /**/
+ y := 1
+}
+
+func _() {
+ f()
+ f()
+ f() /* comment */
+ f()
+ f() /* comment */
+ f()
+ f() /* a */ /* b */
+ f()
+ f() /* a */ /* b */
+ f()
+ f() /* a */ /* b */
+ f()
+}
+
+func _() {
+ f() /* a */ /* b */
+}
+
// Comments immediately adjacent to punctuation followed by a newline
// remain after the punctuation (looks better and permits alignment of
// comments).
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index 30cd23c6dd..40351eeef6 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -607,6 +607,24 @@ func _() {
_ = a
}
+// Test cases from issues 11274, 15137:
+// Semicolon must not be lost when multiple statements are on the same line with a comment.
+func _() {
+ x := 0 /**/; y := 1
+}
+
+func _() {
+ f(); f()
+ f(); /* comment */ f()
+ f() /* comment */; f()
+ f(); /* a */ /* b */ f()
+ f() /* a */ /* b */; f()
+ f() /* a */; /* b */ f()
+}
+
+func _() {
+ f() /* a */ /* b */ }
+
// Comments immediately adjacent to punctuation followed by a newline
// remain after the punctuation (looks better and permits alignment of
// comments).
diff --git a/libgo/go/go/printer/testdata/comments2.golden b/libgo/go/go/printer/testdata/comments2.golden
index 7676a26c12..8b3a94ddcd 100644
--- a/libgo/go/go/printer/testdata/comments2.golden
+++ b/libgo/go/go/printer/testdata/comments2.golden
@@ -103,3 +103,62 @@ label:
mask := uint64(1)<<c - 1 // Allocation mask
used := atomic.LoadUint64(&h.used) // Current allocations
}
+
+// Test cases for issue 18782
+var _ = [][]int{
+ /* a, b, c, d, e */
+ /* a */ {0, 0, 0, 0, 0},
+ /* b */ {0, 5, 4, 4, 4},
+ /* c */ {0, 4, 5, 4, 4},
+ /* d */ {0, 4, 4, 5, 4},
+ /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0}
+
+var _ = T{ /* a */ /* b */ 0}
+
+var _ = T{ /* a */ /* b */
+ /* c */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */
+ /* d */ 0,
+}
+
+var _ = T{
+ /* a */
+ /* b */ 0,
+}
+
+var _ = T{ /* a */ {}}
+
+var _ = T{ /* a */ /* b */ {}}
+
+var _ = T{ /* a */ /* b */
+ /* c */ {},
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */
+ /* d */ {},
+}
+
+var _ = T{
+ /* a */
+ /* b */ {},
+}
+
+var _ = []T{
+ func() {
+ var _ = [][]int{
+ /* a, b, c, d, e */
+ /* a */ {0, 0, 0, 0, 0},
+ /* b */ {0, 5, 4, 4, 4},
+ /* c */ {0, 4, 5, 4, 4},
+ /* d */ {0, 4, 4, 5, 4},
+ /* e */ {0, 4, 4, 4, 5},
+ }
+ },
+}
diff --git a/libgo/go/go/printer/testdata/comments2.input b/libgo/go/go/printer/testdata/comments2.input
index 4a055c8277..8d38c4194b 100644
--- a/libgo/go/go/printer/testdata/comments2.input
+++ b/libgo/go/go/printer/testdata/comments2.input
@@ -103,3 +103,66 @@ label:
mask := uint64(1)<<c - 1 // Allocation mask
used := atomic.LoadUint64(&h.used) // Current allocations
}
+
+// Test cases for issue 18782
+var _ = [][]int{
+ /* a, b, c, d, e */
+ /* a */ {0, 0, 0, 0, 0},
+ /* b */ {0, 5, 4, 4, 4},
+ /* c */ {0, 4, 5, 4, 4},
+ /* d */ {0, 4, 4, 5, 4},
+ /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0,
+}
+
+var _ = T{ /* a */ /* b */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */
+ /* d */ 0,
+}
+
+var _ = T{
+ /* a */
+ /* b */ 0,
+}
+
+var _ = T{ /* a */ {},
+}
+
+var _ = T{ /* a */ /* b */ {},
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */ {},
+}
+
+var _ = T{ /* a */ /* b */
+ /* c */
+ /* d */ {},
+}
+
+var _ = T{
+ /* a */
+ /* b */ {},
+}
+
+var _ = []T{
+ func() {
+ var _ = [][]int{
+ /* a, b, c, d, e */
+ /* a */ {0, 0, 0, 0, 0},
+ /* b */ {0, 5, 4, 4, 4},
+ /* c */ {0, 4, 5, 4, 4},
+ /* d */ {0, 4, 4, 5, 4},
+ /* e */ {0, 4, 4, 4, 5},
+ }
+ },
+}
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index e9476c4dee..a86e4eb668 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -26,7 +26,7 @@ import (
type ErrorHandler func(pos token.Position, msg string)
// A Scanner holds the scanner's internal state while processing
-// a given text. It can be allocated as part of another data
+// a given text. It can be allocated as part of another data
// structure but must be initialized via Init before use.
//
type Scanner struct {
@@ -64,7 +64,7 @@ func (s *Scanner) next() {
switch {
case r == 0:
s.error(s.offset, "illegal character NUL")
- case r >= 0x80:
+ case r >= utf8.RuneSelf:
// not ASCII
r, w = utf8.DecodeRune(s.src[s.rdOffset:])
if r == utf8.RuneError && w == 1 {
@@ -255,11 +255,11 @@ func (s *Scanner) findLineEnd() bool {
}
func isLetter(ch rune) bool {
- return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+ return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
}
func isDigit(ch rune) bool {
- return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+ return '0' <= ch && ch <= '9' || ch >= utf8.RuneSelf && unicode.IsDigit(ch)
}
func (s *Scanner) scanIdentifier() string {
@@ -349,7 +349,11 @@ exponent:
if s.ch == '-' || s.ch == '+' {
s.next()
}
- s.scanMantissa(10)
+ if digitVal(s.ch) < 10 {
+ s.scanMantissa(10)
+ } else {
+ s.error(offs, "illegal floating-point exponent")
+ }
}
if s.ch == 'i' {
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 0d21905166..ff41c036f0 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -716,6 +716,7 @@ var errors = []struct {
{"078.", token.FLOAT, 0, "078.", ""},
{"07801234567.", token.FLOAT, 0, "07801234567.", ""},
{"078e0", token.FLOAT, 0, "078e0", ""},
+ {"0E", token.FLOAT, 0, "0E", "illegal floating-point exponent"}, // issue 17621
{"078", token.INT, 0, "078", "illegal octal number"},
{"07800000009", token.INT, 0, "07800000009", "illegal octal number"},
{"0x", token.INT, 0, "0x", "illegal hexadecimal number"},
diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go
index 33751779a3..d4171d80e0 100644
--- a/libgo/go/go/token/position.go
+++ b/libgo/go/go/token/position.go
@@ -164,6 +164,7 @@ func (f *File) MergeLine(line int) {
// Each line offset must be larger than the offset for the previous line
// and smaller than the file size; otherwise SetLines fails and returns
// false.
+// Callers must not mutate the provided slice after SetLines returns.
//
func (f *File) SetLines(lines []int) bool {
// verify validity of lines table
@@ -445,7 +446,9 @@ func (s *FileSet) File(p Pos) (f *File) {
func (s *FileSet) PositionFor(p Pos, adjusted bool) (pos Position) {
if p != NoPos {
if f := s.file(p); f != nil {
+ s.mutex.RLock()
pos = f.position(p, adjusted)
+ s.mutex.RUnlock()
}
}
return
diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go
index d26939ce27..63984bc872 100644
--- a/libgo/go/go/token/position_test.go
+++ b/libgo/go/go/token/position_test.go
@@ -214,7 +214,7 @@ func TestFileSetCacheUnlikely(t *testing.T) {
}
}
-// issue 4345. Test concurrent use of FileSet.Pos does not trigger a
+// issue 4345. Test that concurrent use of FileSet.Pos does not trigger a
// race in the FileSet position cache.
func TestFileSetRace(t *testing.T) {
fset := NewFileSet()
@@ -237,6 +237,35 @@ func TestFileSetRace(t *testing.T) {
stop.Wait()
}
+// issue 16548. Test that concurrent use of File.AddLine and FileSet.PositionFor
+// does not trigger a race in the FileSet position cache.
+func TestFileSetRace2(t *testing.T) {
+ const N = 1e3
+ var (
+ fset = NewFileSet()
+ file = fset.AddFile("", -1, N)
+ ch = make(chan int, 2)
+ )
+
+ go func() {
+ for i := 0; i < N; i++ {
+ file.AddLine(i)
+ }
+ ch <- 1
+ }()
+
+ go func() {
+ pos := file.Pos(0)
+ for i := 0; i < N; i++ {
+ fset.PositionFor(pos, false)
+ }
+ ch <- 1
+ }()
+
+ <-ch
+ <-ch
+}
+
func TestPositionFor(t *testing.T) {
src := []byte(`
foo
diff --git a/libgo/go/go/types/api.go b/libgo/go/go/types/api.go
index ca109f0a80..5b911cb96c 100644
--- a/libgo/go/go/types/api.go
+++ b/libgo/go/go/types/api.go
@@ -5,7 +5,7 @@
// Package types declares the data types and implements
// the algorithms for type-checking of Go packages. Use
// Config.Check to invoke the type checker for a package.
-// Alternatively, create a new type checked with NewChecker
+// Alternatively, create a new type checker with NewChecker
// and invoke it incrementally by calling Checker.Files.
//
// Type-checking consists of several interdependent phases:
@@ -135,7 +135,8 @@ type Config struct {
// be incomplete.
type Info struct {
// Types maps expressions to their types, and for constant
- // expressions, their values. Invalid expressions are omitted.
+ // expressions, also their values. Invalid expressions are
+ // omitted.
//
// For (possibly parenthesized) identifiers denoting built-in
// functions, the recorded signatures are call-site specific:
@@ -143,9 +144,13 @@ type Info struct {
// an argument-specific signature. Otherwise, the recorded type
// is invalid.
//
- // Identifiers on the lhs of declarations (i.e., the identifiers
- // which are being declared) are collected in the Defs map.
- // Identifiers denoting packages are collected in the Uses maps.
+ // The Types map does not record the type of every identifier,
+ // only those that appear where an arbitrary expression is
+ // permitted. For instance, the identifier f in a selector
+ // expression x.f is found only in the Selections map, the
+ // identifier z in a variable declaration 'var z int' is found
+ // only in the Defs map, and identifiers denoting packages in
+ // qualified identifiers are collected in the Uses map.
Types map[ast.Expr]TypeAndValue
// Defs maps identifiers to the objects they define (including
diff --git a/libgo/go/go/types/api_test.go b/libgo/go/go/types/api_test.go
index 97af965c9f..818a51993e 100644
--- a/libgo/go/go/types/api_test.go
+++ b/libgo/go/go/types/api_test.go
@@ -172,13 +172,11 @@ func TestTypesInfo(t *testing.T) {
`x.(int)`,
`(int, bool)`,
},
- // TODO(gri): uncomment if we accept issue 8189.
- // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
- // `m["foo"]`,
- // `(complex128, p2.mybool)`,
- // },
- // TODO(gri): remove if we accept issue 8189.
- {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+ {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+ `m["foo"]`,
+ `(complex128, p2a.mybool)`,
+ },
+ {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
`m["foo"]`,
`(complex128, bool)`,
},
@@ -573,6 +571,64 @@ func TestInitOrderInfo(t *testing.T) {
`, []string{
"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
}},
+ // test case for issue 10709
+ {`package p13
+
+ var (
+ v = t.m()
+ t = makeT(0)
+ )
+
+ type T struct{}
+
+ func (T) m() int { return 0 }
+
+ func makeT(n int) T {
+ if n > 0 {
+ return makeT(n-1)
+ }
+ return T{}
+ }`, []string{
+ "t = makeT(0)", "v = t.m()",
+ }},
+ // test case for issue 10709: same as test before, but variable decls swapped
+ {`package p14
+
+ var (
+ t = makeT(0)
+ v = t.m()
+ )
+
+ type T struct{}
+
+ func (T) m() int { return 0 }
+
+ func makeT(n int) T {
+ if n > 0 {
+ return makeT(n-1)
+ }
+ return T{}
+ }`, []string{
+ "t = makeT(0)", "v = t.m()",
+ }},
+ // another candidate possibly causing problems with issue 10709
+ {`package p15
+
+ var y1 = f1()
+
+ func f1() int { return g1() }
+ func g1() int { f1(); return x1 }
+
+ var x1 = 0
+
+ var y2 = f2()
+
+ func f2() int { return g2() }
+ func g2() int { return x2 }
+
+ var x2 = 0`, []string{
+ "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()",
+ }},
}
for _, test := range tests {
@@ -962,7 +1018,11 @@ func TestScopeLookupParent(t *testing.T) {
}
var info Info
makePkg := func(path string, files ...*ast.File) {
- imports[path], _ = conf.Check(path, fset, files, &info)
+ var err error
+ imports[path], err = conf.Check(path, fset, files, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
}
makePkg("lib", mustParse("package lib; var X int"))
@@ -970,17 +1030,44 @@ func TestScopeLookupParent(t *testing.T) {
// name at that point and checks that it resolves to a decl of
// the specified kind and line number. "undef" means undefined.
mainSrc := `
+/*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
package main
+
import "lib"
-var Y = lib.X
-func f() {
- print(Y) /*Y=var:4*/
- z /*z=undef*/ := /*z=undef*/ 1 /*z=var:7*/
- print(z)
- /*f=func:5*/ /*lib=pkgname:3*/
- type /*T=undef*/ T /*T=typename:10*/ *T
+import . "lib"
+
+const Pi = 3.1415
+type T struct{}
+var Y, _ = lib.X, X
+
+func F(){
+ const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
+ type /*t=undef*/ t /*t=typename:14*/ *t
+ print(Y) /*Y=var:10*/
+ x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
+ var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
+
+ var a []int
+ for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+
+ var i interface{}
+ switch y := i.(type) { /*y=undef*/
+ case /*y=undef*/ int /*y=var:23*/ :
+ case float32, /*y=undef*/ float64 /*y=var:23*/ :
+ default /*y=var:23*/:
+ println(y)
+ }
+ /*y=undef*/
+
+ switch int := i.(type) {
+ case /*int=typename:0*/ int /*int=var:31*/ :
+ println(int)
+ default /*int=var:31*/ :
+ }
}
+/*main=undef*/
`
+
info.Uses = make(map[*ast.Ident]Object)
f := mustParse(mainSrc)
makePkg("main", f)
@@ -1044,3 +1131,321 @@ func f() {
}
}
}
+
+func TestIdentical_issue15173(t *testing.T) {
+ // Identical should allow nil arguments and be symmetric.
+ for _, test := range []struct {
+ x, y Type
+ want bool
+ }{
+ {Typ[Int], Typ[Int], true},
+ {Typ[Int], nil, false},
+ {nil, Typ[Int], false},
+ {nil, nil, true},
+ } {
+ if got := Identical(test.x, test.y); got != test.want {
+ t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
+ }
+ }
+}
+
+func TestIssue15305(t *testing.T) {
+ const src = "package p; func f() int16; var _ = f(undef)"
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "issue15305.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ conf := Config{
+ Error: func(err error) {}, // allow errors
+ }
+ info := &Info{
+ Types: make(map[ast.Expr]TypeAndValue),
+ }
+ conf.Check("p", fset, []*ast.File{f}, info) // ignore result
+ for e, tv := range info.Types {
+ if _, ok := e.(*ast.CallExpr); ok {
+ if tv.Type != Typ[Int16] {
+ t.Errorf("CallExpr has type %v, want int16", tv.Type)
+ }
+ return
+ }
+ }
+ t.Errorf("CallExpr has no type")
+}
+
+// TestCompositeLitTypes verifies that Info.Types registers the correct
+// types for composite literal expressions and composite literal type
+// expressions.
+func TestCompositeLitTypes(t *testing.T) {
+ for _, test := range []struct {
+ lit, typ string
+ }{
+ {`[16]byte{}`, `[16]byte`},
+ {`[...]byte{}`, `[0]byte`}, // test for issue #14092
+ {`[...]int{1, 2, 3}`, `[3]int`}, // test for issue #14092
+ {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092
+ {`[]int{}`, `[]int`},
+ {`map[string]bool{"foo": true}`, `map[string]bool`},
+ {`struct{}{}`, `struct{}`},
+ {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
+ } {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0)
+ if err != nil {
+ t.Fatalf("%s: %v", test.lit, err)
+ }
+
+ info := &Info{
+ Types: make(map[ast.Expr]TypeAndValue),
+ }
+ if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+ t.Fatalf("%s: %v", test.lit, err)
+ }
+
+ cmptype := func(x ast.Expr, want string) {
+ tv, ok := info.Types[x]
+ if !ok {
+ t.Errorf("%s: no Types entry found", test.lit)
+ return
+ }
+ if tv.Type == nil {
+ t.Errorf("%s: type is nil", test.lit)
+ return
+ }
+ if got := tv.Type.String(); got != want {
+ t.Errorf("%s: got %v, want %s", test.lit, got, want)
+ }
+ }
+
+ // test type of composite literal expression
+ rhs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0]
+ cmptype(rhs, test.typ)
+
+ // test type of composite literal type expression
+ cmptype(rhs.(*ast.CompositeLit).Type, test.typ)
+ }
+}
+
+// TestObjectParents verifies that objects have parent scopes or not
+// as specified by the Object interface.
+func TestObjectParents(t *testing.T) {
+ const src = `
+package p
+
+const C = 0
+
+type T1 struct {
+ a, b int
+ T2
+}
+
+type T2 interface {
+ im1()
+ im2()
+}
+
+func (T1) m1() {}
+func (*T1) m2() {}
+
+func f(x int) { y := x; print(y) }
+`
+
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "src", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ info := &Info{
+ Defs: make(map[*ast.Ident]Object),
+ }
+ if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+ t.Fatal(err)
+ }
+
+ for ident, obj := range info.Defs {
+ if obj == nil {
+ // only package names and implicit vars have a nil object
+ // (in this test we only need to handle the package name)
+ if ident.Name != "p" {
+ t.Errorf("%v has nil object", ident)
+ }
+ continue
+ }
+
+ // struct fields, type-associated and interface methods
+ // have no parent scope
+ wantParent := true
+ switch obj := obj.(type) {
+ case *Var:
+ if obj.IsField() {
+ wantParent = false
+ }
+ case *Func:
+ if obj.Type().(*Signature).Recv() != nil { // method
+ wantParent = false
+ }
+ }
+
+ gotParent := obj.Parent() != nil
+ switch {
+ case gotParent && !wantParent:
+ t.Errorf("%v: want no parent, got %s", ident, obj.Parent())
+ case !gotParent && wantParent:
+ t.Errorf("%v: no parent found", ident)
+ }
+ }
+}
+
+// Alias-related code. Keep for now.
+/*
+func TestAliases(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ const src = `
+package b
+
+import (
+ "./testdata/alias"
+ a "./testdata/alias"
+ "math"
+)
+
+const (
+ c1 = alias.Pi1
+ c2 => a.Pi1
+ c3 => a.Pi2
+ c4 => math.Pi
+)
+
+var (
+ v1 => alias.Default
+ v2 => a.Default
+ v3 = f1
+)
+
+type (
+ t1 => alias.Context
+ t2 => a.Context
+)
+
+func f1 => alias.Sin
+func f2 => a.Sin
+
+func _() {
+ assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
+ assert(c2 == c2 && c2 == c3 && c3 == c4)
+ v1 = v2 // must be assignable
+ var _ *t1 = new(t2) // must be assignable
+ var _ t2 = alias.Default
+ f1(1) // must be callable
+ f2(1)
+ _ = alias.Sin(1)
+ _ = a.Sin(1)
+}
+`
+
+ if out := compile(t, "testdata", "alias.go"); out != "" {
+ defer os.Remove(out)
+ }
+
+ DefPredeclaredTestFuncs() // declare assert built-in for testing
+ mustTypecheck(t, "Aliases", src, nil)
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("go tool compile %s failed: %s", filename, err)
+ }
+ // filename should end with ".go"
+ return filepath.Join(dirname, filename[:len(filename)-2]+"o")
+}
+
+func TestAliasDefUses(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ const src = `
+package p
+
+import(
+ "go/build"
+ "go/types"
+)
+
+// Defs
+const Invalid => types.Invalid
+type Struct => types.Struct
+var Default => build.Default
+func Implements => types.Implements
+
+// Uses
+const _ = Invalid
+var _ types.Struct = Struct{} // types must be identical
+var _ build.Context = Default
+var _ = Implements(nil, nil)
+`
+
+ info := Info{
+ Defs: make(map[*ast.Ident]Object),
+ Uses: make(map[*ast.Ident]Object),
+ }
+ mustTypecheck(t, "TestAliasDefUses", src, &info)
+
+ // verify Defs
+ defs := map[string]string{
+ "Invalid": "types.Invalid",
+ "Struct": "types.Struct",
+ "Default": "build.Default",
+ "Implements": "types.Implements",
+ }
+
+ for ident, obj := range info.Defs {
+ if alias, ok := obj.(*Alias); ok {
+ if want := defs[ident.Name]; want != "" {
+ orig := alias.Orig()
+ if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
+ t.Errorf("%v: got %v, want %v", ident, got, want)
+ }
+ delete(defs, ident.Name) // mark as found
+ } else {
+ t.Errorf("unexpected alias def of %v", ident)
+ }
+ }
+ }
+
+ if len(defs) != 0 {
+ t.Errorf("missing aliases: %v", defs)
+ }
+
+ // verify Uses
+ uses := map[string]string{
+ "Invalid": "types.Invalid",
+ "Struct": "types.Struct",
+ "Default": "build.Default",
+ "Implements": "types.Implements",
+ }
+
+ for ident, obj := range info.Uses {
+ if alias, ok := obj.(*Alias); ok {
+ if want := uses[ident.Name]; want != "" {
+ orig := alias.Orig()
+ if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
+ t.Errorf("%v: got %v, want %v", ident, got, want)
+ }
+ delete(uses, ident.Name) // mark as found
+ } else {
+ t.Errorf("unexpected alias use of %v", ident)
+ }
+ }
+ }
+
+ if len(uses) != 0 {
+ t.Errorf("missing aliases: %v", defs)
+ }
+}
+*/
diff --git a/libgo/go/go/types/assignments.go b/libgo/go/go/types/assignments.go
index 10ab17b9cf..18f893d478 100644
--- a/libgo/go/go/types/assignments.go
+++ b/libgo/go/go/types/assignments.go
@@ -41,7 +41,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
x.mode = invalid
return
}
- target = defaultType(x.typ)
+ target = Default(x.typ)
}
check.convertUntyped(x, target)
if x.mode == invalid {
@@ -116,7 +116,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
lhs.typ = Typ[Invalid]
return nil
}
- typ = defaultType(typ)
+ typ = Default(typ)
}
lhs.typ = typ
}
@@ -179,6 +179,14 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
case variable, mapindex:
// ok
default:
+ if sel, ok := z.expr.(*ast.SelectorExpr); ok {
+ var op operand
+ check.expr(&op, sel.X)
+ if op.mode == mapindex {
+ check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
+ return nil
+ }
+ }
check.errorf(z.pos(), "cannot assign to %s", &z)
return nil
}
diff --git a/libgo/go/go/types/builtins.go b/libgo/go/go/types/builtins.go
index 803264fb58..596a989a2d 100644
--- a/libgo/go/go/types/builtins.go
+++ b/libgo/go/go/types/builtins.go
@@ -366,7 +366,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
} else {
// an untyped non-constant argument may appear if
// it contains a (yet untyped non-constant) shift
- // epression: convert it to complex128 which will
+ // expression: convert it to complex128 which will
// result in an error (shift of complex value)
check.convertUntyped(x, Typ[Complex128])
// x should be invalid now, but be conservative and check
@@ -434,7 +434,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
if nargs < min || min+1 < nargs {
- check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+ check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
return
}
var sizes []int64 // constant integer arguments, if any
@@ -595,7 +595,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
if !constant.BoolVal(x.val) {
- check.errorf(call.Pos(), "%s failed", call)
+ check.errorf(call.Pos(), "%v failed", call)
// compile-time assertion failure - safe to continue
}
// result is constant - no need to record signature
@@ -632,7 +632,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
func makeSig(res Type, args ...Type) *Signature {
list := make([]*Var, len(args))
for i, param := range args {
- list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+ list[i] = NewVar(token.NoPos, nil, "", Default(param))
}
params := NewTuple(list...)
var result *Tuple
diff --git a/libgo/go/go/types/call.go b/libgo/go/go/types/call.go
index 8aeb862993..8e5c5371f2 100644
--- a/libgo/go/go/types/call.go
+++ b/libgo/go/go/types/call.go
@@ -62,14 +62,12 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
}
arg, n, _ := unpack(func(x *operand, i int) { check.multiExpr(x, e.Args[i]) }, len(e.Args), false)
- if arg == nil {
+ if arg != nil {
+ check.arguments(x, e, sig, arg, n)
+ } else {
x.mode = invalid
- x.expr = e
- return statement
}
- check.arguments(x, e, sig, arg, n)
-
// determine result
switch sig.results.Len() {
case 0:
@@ -81,6 +79,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
x.mode = value
x.typ = sig.results
}
+
x.expr = e
check.hasCallOrRecv = true
@@ -276,24 +275,34 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// so we don't need a "package" mode for operands: package names
// can only appear in qualified identifiers which are mapped to
// selector expressions.
+ // (see also decl.go: checker.aliasDecl)
+ // TODO(gri) factor this code out and share with checker.aliasDecl
if ident, ok := e.X.(*ast.Ident); ok {
_, obj := check.scope.LookupParent(ident.Name, check.pos)
- if pkg, _ := obj.(*PkgName); pkg != nil {
- assert(pkg.pkg == check.pkg)
- check.recordUse(ident, pkg)
- pkg.used = true
- exp := pkg.imported.scope.Lookup(sel)
+ if pname, _ := obj.(*PkgName); pname != nil {
+ assert(pname.pkg == check.pkg)
+ check.recordUse(ident, pname)
+ pname.used = true
+ pkg := pname.imported
+ exp := pkg.scope.Lookup(sel)
if exp == nil {
- if !pkg.imported.fake {
- check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+ if !pkg.fake {
+ check.errorf(e.Pos(), "%s not declared by package %s", sel, pkg.name)
}
goto Error
}
if !exp.Exported() {
- check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+ check.errorf(e.Pos(), "%s not exported by package %s", sel, pkg.name)
// ok to continue
}
check.recordUse(e.Sel, exp)
+ exp = original(exp)
+
+ // avoid further errors if the imported object is an alias that's broken
+ if exp == nil {
+ goto Error
+ }
+
// Simplified version of the code for *ast.Idents:
// - imported objects are always fully initialized
switch exp := exp.(type) {
@@ -316,6 +325,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
x.typ = exp.typ
x.id = exp.id
default:
+ check.dump("unexpected object %v", exp)
unreachable()
}
x.expr = e
diff --git a/libgo/go/go/types/check.go b/libgo/go/go/types/check.go
index bb0b07415e..28e94f1940 100644
--- a/libgo/go/go/types/check.go
+++ b/libgo/go/go/types/check.go
@@ -215,7 +215,9 @@ func (check *Checker) handleBailout(err *error) {
}
// Files checks the provided files as part of the checker's package.
-func (check *Checker) Files(files []*ast.File) (err error) {
+func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
+
+func (check *Checker) checkFiles(files []*ast.File) (err error) {
defer check.handleBailout(&err)
check.initFiles(files)
@@ -343,7 +345,6 @@ func (check *Checker) recordImplicit(node ast.Node, obj Object) {
func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
assert(obj != nil && (recv == nil || len(index) > 0))
check.recordUse(x.Sel, obj)
- // TODO(gri) Should we also call recordTypeAndValue?
if m := check.Selections; m != nil {
m[x] = &Selection{kind, recv, obj, index, indirect}
}
diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go
index 5e2043be84..f844575269 100644
--- a/libgo/go/go/types/check_test.go
+++ b/libgo/go/go/types/check_test.go
@@ -72,6 +72,7 @@ var tests = [][]string{
{"testdata/const1.src"},
{"testdata/constdecl.src"},
{"testdata/vardecl.src"},
+ //{"testdata/aliasdecl.src"},
{"testdata/expr0.src"},
{"testdata/expr1.src"},
{"testdata/expr2.src"},
@@ -80,6 +81,7 @@ var tests = [][]string{
{"testdata/shifts.src"},
{"testdata/builtins.src"},
{"testdata/conversions.src"},
+ {"testdata/conversions2.src"},
{"testdata/stmt0.src"},
{"testdata/stmt1.src"},
{"testdata/gotos.src"},
diff --git a/libgo/go/go/types/conversions.go b/libgo/go/go/types/conversions.go
index f98cc8d81a..2bf1e2d5e3 100644
--- a/libgo/go/go/types/conversions.go
+++ b/libgo/go/go/types/conversions.go
@@ -55,7 +55,7 @@ func (check *Checker) conversion(x *operand, T Type) {
// not []byte as type for the constant "foo").
// - Keep untyped nil for untyped nil arguments.
if IsInterface(T) || constArg && !isConstType(T) {
- final = defaultType(x.typ)
+ final = Default(x.typ)
}
check.updateExprType(x.expr, final, true)
}
@@ -69,18 +69,19 @@ func (x *operand) convertibleTo(conf *Config, T Type) bool {
return true
}
- // "x's type and T have identical underlying types"
+ // "x's type and T have identical underlying types if tags are ignored"
V := x.typ
Vu := V.Underlying()
Tu := T.Underlying()
- if Identical(Vu, Tu) {
+ if IdenticalIgnoreTags(Vu, Tu) {
return true
}
- // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+ // "x's type and T are unnamed pointer types and their pointer base types
+ // have identical underlying types if tags are ignored"
if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok {
- if Identical(V.base.Underlying(), T.base.Underlying()) {
+ if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) {
return true
}
}
diff --git a/libgo/go/go/types/decl.go b/libgo/go/go/types/decl.go
index f064f6856f..dced7a6d6d 100644
--- a/libgo/go/go/types/decl.go
+++ b/libgo/go/go/types/decl.go
@@ -85,6 +85,10 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
case *Func:
// functions may be recursive - no need to track dependencies
check.funcDecl(obj, d)
+ // Alias-related code. Keep for now.
+ // case *Alias:
+ // // aliases cannot be recursive - no need to track dependencies
+ // check.aliasDecl(obj, d)
default:
unreachable()
}
@@ -141,6 +145,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 +185,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)
}
@@ -310,6 +333,106 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
}
}
+// original returns the original Object if obj is an Alias;
+// otherwise it returns obj. The result is never an Alias,
+// but it may be nil.
+func original(obj Object) Object {
+ // an alias stands for the original object; use that one instead
+ if alias, _ := obj.(*disabledAlias); alias != nil {
+ obj = alias.orig
+ // aliases always refer to non-alias originals
+ if _, ok := obj.(*disabledAlias); ok {
+ panic("original is an alias")
+ }
+ }
+ return obj
+}
+
+func (check *Checker) aliasDecl(obj *disabledAlias, decl *declInfo) {
+ assert(obj.typ == nil)
+
+ // alias declarations cannot use iota
+ assert(check.iota == nil)
+
+ // assume alias is invalid to start with
+ obj.typ = Typ[Invalid]
+
+ // rhs must be package-qualified identifer pkg.sel (see also call.go: checker.selector)
+ // TODO(gri) factor this code out and share with checker.selector
+ rhs := decl.init
+ var pkg *Package
+ var sel *ast.Ident
+ if sexpr, ok := rhs.(*ast.SelectorExpr); ok {
+ if ident, ok := sexpr.X.(*ast.Ident); ok {
+ _, obj := check.scope.LookupParent(ident.Name, check.pos)
+ if pname, _ := obj.(*PkgName); pname != nil {
+ assert(pname.pkg == check.pkg)
+ check.recordUse(ident, pname)
+ pname.used = true
+ pkg = pname.imported
+ sel = sexpr.Sel
+ }
+ }
+ }
+ if pkg == nil {
+ check.errorf(rhs.Pos(), "invalid alias: %v is not a package-qualified identifier", rhs)
+ return
+ }
+
+ // qualified identifier must denote an exported object
+ orig := pkg.scope.Lookup(sel.Name)
+ if orig == nil || !orig.Exported() {
+ if !pkg.fake {
+ check.errorf(rhs.Pos(), "%s is not exported by package %s", sel.Name, pkg.name)
+ }
+ return
+ }
+ check.recordUse(sel, orig)
+ orig = original(orig)
+
+ // avoid further errors if the imported object is an alias that's broken
+ if orig == nil {
+ return
+ }
+
+ // An alias declaration must not refer to package unsafe.
+ if orig.Pkg() == Unsafe {
+ check.errorf(rhs.Pos(), "invalid alias: %s refers to package unsafe (%v)", obj.Name(), orig)
+ return
+ }
+
+ // The original must be of the same kind as the alias declaration.
+ var why string
+ switch obj.kind {
+ case token.CONST:
+ if _, ok := orig.(*Const); !ok {
+ why = "constant"
+ }
+ case token.TYPE:
+ if _, ok := orig.(*TypeName); !ok {
+ why = "type"
+ }
+ case token.VAR:
+ if _, ok := orig.(*Var); !ok {
+ why = "variable"
+ }
+ case token.FUNC:
+ if _, ok := orig.(*Func); !ok {
+ why = "function"
+ }
+ default:
+ unreachable()
+ }
+ if why != "" {
+ check.errorf(rhs.Pos(), "invalid alias: %v is not a %s", orig, why)
+ return
+ }
+
+ // alias is valid
+ obj.typ = orig.Type()
+ obj.orig = orig
+}
+
func (check *Checker) declStmt(decl ast.Decl) {
pkg := check.pkg
diff --git a/libgo/go/go/types/eval.go b/libgo/go/go/types/eval.go
index 7b42ff1a9d..831d771d80 100644
--- a/libgo/go/go/types/eval.go
+++ b/libgo/go/go/types/eval.go
@@ -34,7 +34,7 @@ import (
// level untyped constants will return an untyped type rather then the
// respective context-specific type.
//
-func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv TypeAndValue, err error) {
+func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (TypeAndValue, error) {
// determine scope
var scope *Scope
if pkg == nil {
@@ -44,7 +44,7 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv Typ
scope = pkg.scope
} else {
// The package scope extent (position information) may be
- // incorrect (files spread accross a wide range of fset
+ // incorrect (files spread across a wide range of fset
// positions) - ignore it and just consider its children
// (file scopes).
for _, fscope := range pkg.scope.children {
diff --git a/libgo/go/go/types/expr.go b/libgo/go/go/types/expr.go
index f7c4a17378..f76da17fe5 100644
--- a/libgo/go/go/types/expr.go
+++ b/libgo/go/go/types/expr.go
@@ -541,7 +541,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
if !t.Empty() {
goto Error
}
- target = defaultType(x.typ)
+ target = Default(x.typ)
}
case *Pointer, *Signature, *Slice, *Map, *Chan:
if !x.isNil() {
@@ -605,8 +605,8 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
// time will be materialized. Update the expression trees.
// If the current types are untyped, the materialized type
// is the respective default type.
- check.updateExprType(x.expr, defaultType(x.typ), true)
- check.updateExprType(y.expr, defaultType(y.typ), true)
+ check.updateExprType(x.expr, Default(x.typ), true)
+ check.updateExprType(y.expr, Default(y.typ), true)
}
// spec: "Comparison operators compare two operands and yield
@@ -660,10 +660,10 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
return
}
// rhs must be within reasonable bounds
- const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+ const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
s, ok := constant.Uint64Val(yval)
- if !ok || s > stupidShift {
- check.invalidOp(y.pos(), "stupid shift count %s", y)
+ if !ok || s > shiftBound {
+ check.invalidOp(y.pos(), "invalid shift count %s", y)
x.mode = invalid
return
}
@@ -1015,32 +1015,38 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
case *ast.CompositeLit:
- typ := hint
- openArray := false
- if e.Type != nil {
+ var typ, base Type
+
+ switch {
+ case e.Type != nil:
+ // composite literal type present - use it
// [...]T array types may only appear with composite literals.
// Check for them here so we don't have to handle ... in general.
- typ = nil
if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
// We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
- openArray = true
+ base = typ
+ break
}
}
- if typ == nil {
- typ = check.typ(e.Type)
- }
- }
- if typ == nil {
+ typ = check.typ(e.Type)
+ base = typ
+
+ case hint != nil:
+ // no composite literal type present - use hint (element type of enclosing type)
+ typ = hint
+ base, _ = deref(typ.Underlying()) // *T implies &T{}
+
+ default:
// TODO(gri) provide better error messages depending on context
check.error(e.Pos(), "missing type in composite literal")
goto Error
}
- switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+ switch utyp := base.Underlying().(type) {
case *Struct:
if len(e.Elts) == 0 {
break
@@ -1106,9 +1112,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *Array:
n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
- // if we have an "open" [...]T array, set the length now that we know it
- if openArray {
+ // If we have an "open" [...]T array, set the length now that we know it
+ // and record the type for [...] (usually done by check.typExpr which is
+ // not called for [...]).
+ if utyp.len < 0 {
utyp.len = n
+ check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
}
case *Slice:
diff --git a/libgo/go/go/types/hilbert_test.go b/libgo/go/go/types/hilbert_test.go
index bf2a15b26a..07d5a635e0 100644
--- a/libgo/go/go/types/hilbert_test.go
+++ b/libgo/go/go/types/hilbert_test.go
@@ -195,19 +195,6 @@ func (g *gen) printProduct(n int) {
g.p("}\n\n")
}
-func (g *gen) mulRange(a, b int) {
- if a > b {
- g.p("1")
- return
- }
- for i := a; i <= b; i++ {
- if i > a {
- g.p("*")
- }
- g.p("%d", i)
- }
-}
-
func (g *gen) binomials(n int) {
g.p(`// Binomials
const (
diff --git a/libgo/go/go/types/initorder.go b/libgo/go/go/types/initorder.go
index 0fd567b269..966dccb828 100644
--- a/libgo/go/go/types/initorder.go
+++ b/libgo/go/go/types/initorder.go
@@ -12,56 +12,85 @@ import (
// initOrder computes the Info.InitOrder for package variables.
func (check *Checker) initOrder() {
// An InitOrder may already have been computed if a package is
- // built from several calls to (*Checker).Files. Clear it.
+ // built from several calls to (*Checker).Files. Clear it.
check.Info.InitOrder = check.Info.InitOrder[:0]
- // compute the object dependency graph and
- // initialize a priority queue with the list
- // of graph nodes
+ // Compute the object dependency graph and initialize
+ // a priority queue with the list of graph nodes.
pq := nodeQueue(dependencyGraph(check.objMap))
heap.Init(&pq)
const debug = false
if debug {
- fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+ fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
+ fmt.Println("Object dependency graph:")
+ for obj, d := range check.objMap {
+ // only print objects that may appear in the dependency graph
+ if obj, _ := obj.(dependency); obj != nil {
+ if len(d.deps) > 0 {
+ fmt.Printf("\t%s depends on\n", obj.Name())
+ for dep := range d.deps {
+ fmt.Printf("\t\t%s\n", dep.Name())
+ }
+ } else {
+ fmt.Printf("\t%s has no dependencies\n", obj.Name())
+ }
+ }
+ }
+ fmt.Println()
+
+ fmt.Println("Transposed object dependency graph (functions eliminated):")
for _, n := range pq {
- for _, o := range n.out {
- fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+ fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
+ for p := range n.pred {
+ fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
}
}
fmt.Println()
- fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+
+ fmt.Println("Processing nodes:")
}
- // determine initialization order by removing the highest priority node
+ // Determine initialization order by removing the highest priority node
// (the one with the fewest dependencies) and its edges from the graph,
// repeatedly, until there are no nodes left.
// In a valid Go program, those nodes always have zero dependencies (after
// removing all incoming dependencies), otherwise there are initialization
// cycles.
- mark := 0
emitted := make(map[*declInfo]bool)
for len(pq) > 0 {
// get the next node
- n := heap.Pop(&pq).(*objNode)
+ n := heap.Pop(&pq).(*graphNode)
+
+ if debug {
+ fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
+ n.obj.Name(), n.obj.order(), n.ndeps)
+ }
// if n still depends on other nodes, we have a cycle
- if n.in > 0 {
- mark++ // mark nodes using a different value each time
- cycle := findPath(n, n, mark)
- if i := valIndex(cycle); i >= 0 {
- check.reportCycle(cycle, i)
+ if n.ndeps > 0 {
+ cycle := findPath(check.objMap, n.obj, n.obj, make(objSet))
+ // If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),
+ // cycle will be nil. Don't report anything in that case since
+ // the cycle is reported when the algorithm gets to an object
+ // in the cycle.
+ // Furthermore, once an object in the cycle is encountered,
+ // the cycle will be broken (dependency count will be reduced
+ // below), and so the remaining nodes in the cycle don't trigger
+ // another error (unless they are part of multiple cycles).
+ if cycle != nil {
+ check.reportCycle(cycle)
}
- // ok to continue, but the variable initialization order
+ // Ok to continue, but the variable initialization order
// will be incorrect at this point since it assumes no
- // cycle errors
+ // cycle errors.
}
// reduce dependency count of all dependent nodes
// and update priority queue
- for _, out := range n.out {
- out.in--
- heap.Fix(&pq, out.index)
+ for p := range n.pred {
+ p.ndeps--
+ heap.Fix(&pq, p.index)
}
// record the init order for variables with initializers only
@@ -86,113 +115,159 @@ func (check *Checker) initOrder() {
}
init := &Initializer{infoLhs, info.init}
check.Info.InitOrder = append(check.Info.InitOrder, init)
-
- if debug {
- fmt.Printf("\t%s\n", init)
- }
}
if debug {
fmt.Println()
+ fmt.Println("Initialization order:")
+ for _, init := range check.Info.InitOrder {
+ fmt.Printf("\t%s\n", init)
+ }
+ fmt.Println()
}
}
-// findPath returns the (reversed) list of nodes z, ... c, b, a,
-// such that there is a path (list of edges) from a to z.
+// findPath returns the (reversed) list of objects []Object{to, ... from}
+// such that there is a path of object dependencies from 'from' to 'to'.
// If there is no such path, the result is nil.
-// Nodes marked with the value mark are considered "visited";
-// unvisited nodes are marked during the graph search.
-func findPath(a, z *objNode, mark int) []*objNode {
- if a.mark == mark {
+func findPath(objMap map[Object]*declInfo, from, to Object, visited objSet) []Object {
+ if visited[from] {
return nil // node already seen
}
- a.mark = mark
+ visited[from] = true
- for _, n := range a.out {
- if n == z {
- return []*objNode{z}
+ for d := range objMap[from].deps {
+ if d == to {
+ return []Object{d}
}
- if P := findPath(n, z, mark); P != nil {
- return append(P, n)
+ if P := findPath(objMap, d, to, visited); P != nil {
+ return append(P, d)
}
}
return nil
}
-// valIndex returns the index of the first constant or variable in a,
-// if any; or a value < 0.
-func valIndex(a []*objNode) int {
- for i, n := range a {
- switch n.obj.(type) {
- case *Const, *Var:
- return i
- }
- }
- return -1
-}
-
-// reportCycle reports an error for the cycle starting at i.
-func (check *Checker) reportCycle(cycle []*objNode, i int) {
- obj := cycle[i].obj
+// reportCycle reports an error for the given cycle.
+func (check *Checker) reportCycle(cycle []Object) {
+ obj := cycle[0]
check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
- // print cycle
- for _ = range cycle {
+ // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
+ for i := len(cycle) - 1; i >= 0; i-- {
check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
- i++
- if i >= len(cycle) {
- i = 0
- }
- obj = cycle[i].obj
+ obj = cycle[i]
}
+ // print cycle[0] again to close the cycle
check.errorf(obj.Pos(), "\t%s", obj.Name())
}
-// An objNode represents a node in the object dependency graph.
-// Each node b in a.out represents an edge a->b indicating that
-// b depends on a.
-// Nodes may be marked for cycle detection. A node n is marked
-// if n.mark corresponds to the current mark value.
-type objNode struct {
- obj Object // object represented by this node
- in int // number of nodes this node depends on
- out []*objNode // list of nodes that depend on this node
- index int // node index in list of nodes
- mark int // for cycle detection
+// ----------------------------------------------------------------------------
+// Object dependency graph
+
+// A dependency is an object that may be a dependency in an initialization
+// expression. Only constants, variables, and functions can be dependencies.
+// Constants are here because constant expression cycles are reported during
+// initialization order computation.
+type dependency interface {
+ Object
+ isDependency()
+}
+
+// A graphNode represents a node in the object dependency graph.
+// Each node p in n.pred represents an edge p->n, and each node
+// s in n.succ represents an edge n->s; with a->b indicating that
+// a depends on b.
+type graphNode struct {
+ obj dependency // object represented by this node
+ pred, succ nodeSet // consumers and dependencies of this node (lazily initialized)
+ index int // node index in graph slice/priority queue
+ ndeps int // number of outstanding dependencies before this object can be initialized
+}
+
+type nodeSet map[*graphNode]bool
+
+func (s *nodeSet) add(p *graphNode) {
+ if *s == nil {
+ *s = make(nodeSet)
+ }
+ (*s)[p] = true
}
-// dependencyGraph computes the transposed object dependency graph
-// from the given objMap. The transposed graph is returned as a list
-// of nodes; an edge d->n indicates that node n depends on node d.
-func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
- // M maps each object to its corresponding node
- M := make(map[Object]*objNode, len(objMap))
+// dependencyGraph computes the object dependency graph from the given objMap,
+// with any function nodes removed. The resulting graph contains only constants
+// and variables.
+func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
+ // M is the dependency (Object) -> graphNode mapping
+ M := make(map[dependency]*graphNode)
for obj := range objMap {
- M[obj] = &objNode{obj: obj}
+ // only consider nodes that may be an initialization dependency
+ if obj, _ := obj.(dependency); obj != nil {
+ M[obj] = &graphNode{obj: obj}
+ }
}
- // G is the graph of nodes n
- G := make([]*objNode, len(M))
- i := 0
+ // compute edges for graph M
+ // (We need to include all nodes, even isolated ones, because they still need
+ // to be scheduled for initialization in correct order relative to other nodes.)
for obj, n := range M {
- deps := objMap[obj].deps
- n.in = len(deps)
- for d := range deps {
- d := M[d] // node n depends on node d
- d.out = append(d.out, n) // add edge d->n
+ // for each dependency obj -> d (= deps[i]), create graph edges n->s and s->n
+ for d := range objMap[obj].deps {
+ // only consider nodes that may be an initialization dependency
+ if d, _ := d.(dependency); d != nil {
+ d := M[d]
+ n.succ.add(d)
+ d.pred.add(n)
+ }
}
+ }
- G[i] = n
+ // remove function nodes and collect remaining graph nodes in G
+ // (Mutually recursive functions may introduce cycles among themselves
+ // which are permitted. Yet such cycles may incorrectly inflate the dependency
+ // count for variables which in turn may not get scheduled for initialization
+ // in correct order.)
+ var G []*graphNode
+ for obj, n := range M {
+ if _, ok := obj.(*Func); ok {
+ // connect each predecessor p of n with each successor s
+ // and drop the function node (don't collect it in G)
+ for p := range n.pred {
+ // ignore self-cycles
+ if p != n {
+ // Each successor s of n becomes a successor of p, and
+ // each predecessor p of n becomes a predecessor of s.
+ for s := range n.succ {
+ // ignore self-cycles
+ if s != n {
+ p.succ.add(s)
+ s.pred.add(p)
+ delete(s.pred, n) // remove edge to n
+ }
+ }
+ delete(p.succ, n) // remove edge to n
+ }
+ }
+ } else {
+ // collect non-function nodes
+ G = append(G, n)
+ }
+ }
+
+ // fill in index and ndeps fields
+ for i, n := range G {
n.index = i
- i++
+ n.ndeps = len(n.succ)
}
return G
}
+// ----------------------------------------------------------------------------
+// Priority queue
+
// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
-type nodeQueue []*objNode
+type nodeQueue []*graphNode
func (a nodeQueue) Len() int { return len(a) }
@@ -206,7 +281,7 @@ func (a nodeQueue) Less(i, j int) bool {
x, y := a[i], a[j]
// nodes are prioritized by number of incoming dependencies (1st key)
// and source order (2nd key)
- return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+ return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
}
func (a *nodeQueue) Push(x interface{}) {
diff --git a/libgo/go/go/types/labels.go b/libgo/go/go/types/labels.go
index 7364d4dbe6..3b43b4ba05 100644
--- a/libgo/go/go/types/labels.go
+++ b/libgo/go/go/types/labels.go
@@ -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.
diff --git a/libgo/go/go/types/object.go b/libgo/go/go/types/object.go
index b835c6e53e..6c0c5c4a24 100644
--- a/libgo/go/go/types/object.go
+++ b/libgo/go/go/types/object.go
@@ -19,7 +19,7 @@ import (
// All objects implement the Object interface.
//
type Object interface {
- Parent() *Scope // scope in which this object is declared
+ Parent() *Scope // scope in which this object is declared; nil for methods and struct fields
Pos() token.Pos // position of object identifier in declaration
Pkg() *Package // nil for objects in the Universe scope and labels
Name() string // package local object name
@@ -152,6 +152,7 @@ func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.V
}
func (obj *Const) Val() constant.Value { return obj.val }
+func (*Const) isDependency() {} // a constant may be a dependency of an initialization expression
// A TypeName represents a declared type.
type TypeName struct {
@@ -184,11 +185,11 @@ func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool
}
func (obj *Var) Anonymous() bool { return obj.anonymous }
-
-func (obj *Var) IsField() bool { return obj.isField }
+func (obj *Var) IsField() bool { return obj.isField }
+func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression
// A Func represents a declared function, concrete method, or abstract
-// (interface) method. Its Type() is always a *Signature.
+// (interface) method. Its Type() is always a *Signature.
// An abstract method may belong to many interfaces due to embedding.
type Func struct {
object
@@ -211,10 +212,31 @@ func (obj *Func) FullName() string {
return buf.String()
}
-func (obj *Func) Scope() *Scope {
- return obj.typ.(*Signature).scope
+func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
+func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
+
+// An Alias represents a declared alias.
+type disabledAlias struct {
+ object
+ orig Object // aliased constant, type, variable, or function; never an alias
+ kind token.Token // token.CONST, token.TYPE, token.VAR, or token.FUNC (only needed during resolve phase)
+}
+
+func disabledNewAlias(pos token.Pos, pkg *Package, name string, orig Object) *disabledAlias {
+ var typ Type = Typ[Invalid]
+ if orig != nil {
+ typ = orig.Type()
+ }
+ // No need to set a valid Alias.kind - that field is only used during identifier
+ // resolution (1st type-checker pass). We could store the field outside but it's
+ // easier to keep it here.
+ return &disabledAlias{object{nil, pos, pkg, name, typ, 0, token.NoPos}, orig, token.ILLEGAL}
}
+// Orig returns the aliased object, or nil if there was an error.
+// The returned object is never an Alias.
+func (obj *disabledAlias) disabledOrig() Object { return obj.orig }
+
// A Label represents a declared label.
type Label struct {
object
@@ -273,6 +295,10 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
}
return
+ // Alias-related code. Keep for now.
+ // case *Alias:
+ // buf.WriteString("alias")
+
case *Label:
buf.WriteString("label")
typ = nil
@@ -327,14 +353,15 @@ func ObjectString(obj Object, qf Qualifier) string {
return buf.String()
}
-func (obj *PkgName) String() string { return ObjectString(obj, nil) }
-func (obj *Const) String() string { return ObjectString(obj, nil) }
-func (obj *TypeName) String() string { return ObjectString(obj, nil) }
-func (obj *Var) String() string { return ObjectString(obj, nil) }
-func (obj *Func) String() string { return ObjectString(obj, nil) }
-func (obj *Label) String() string { return ObjectString(obj, nil) }
-func (obj *Builtin) String() string { return ObjectString(obj, nil) }
-func (obj *Nil) String() string { return ObjectString(obj, nil) }
+func (obj *PkgName) String() string { return ObjectString(obj, nil) }
+func (obj *Const) String() string { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string { return ObjectString(obj, nil) }
+func (obj *Func) String() string { return ObjectString(obj, nil) }
+func (obj *disabledAlias) String() string { return ObjectString(obj, nil) }
+func (obj *Label) String() string { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string { return ObjectString(obj, nil) }
+func (obj *Nil) String() string { return ObjectString(obj, nil) }
func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
if f.typ != nil {
diff --git a/libgo/go/go/types/ordering.go b/libgo/go/go/types/ordering.go
index 6bb98f2dc1..3579abf7d7 100644
--- a/libgo/go/go/types/ordering.go
+++ b/libgo/go/go/types/ordering.go
@@ -56,13 +56,9 @@ func (check *Checker) resolveOrder() []Object {
// sort interface types topologically by dependencies,
// and in source order if there are no dependencies
sort.Sort(inSourceOrder(ifaces))
- if debug {
- for _, obj := range ifaces {
- assert(check.objMap[obj].mark == 0)
- }
- }
+ visited := make(objSet)
for _, obj := range ifaces {
- check.appendInPostOrder(&order, obj)
+ check.appendInPostOrder(&order, obj, visited)
}
// sort everything else in source order
@@ -89,25 +85,25 @@ func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
return ityp
}
-func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
- d := check.objMap[obj]
- if d.mark != 0 {
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object, visited objSet) {
+ if visited[obj] {
// We've already seen this object; either because it's
// already added to order, or because we have a cycle.
// In both cases we stop. Cycle errors are reported
// when type-checking types.
return
}
- d.mark = 1
+ visited[obj] = true
+ d := check.objMap[obj]
for _, obj := range orderedSetObjects(d.deps) {
- check.appendInPostOrder(order, obj)
+ check.appendInPostOrder(order, obj, visited)
}
*order = append(*order, obj)
}
-func orderedSetObjects(set map[Object]bool) []Object {
+func orderedSetObjects(set objSet) []Object {
list := make([]Object, len(set))
i := 0
for obj := range set {
diff --git a/libgo/go/go/types/package.go b/libgo/go/go/types/package.go
index 4a432b5496..a588ee73dc 100644
--- a/libgo/go/go/types/package.go
+++ b/libgo/go/go/types/package.go
@@ -55,7 +55,7 @@ func (pkg *Package) MarkComplete() { pkg.complete = true }
// pkg; the list is in source order. Package unsafe is excluded.
//
// If pkg was loaded from export data, Imports includes packages that
-// provide package-level objects referenced by pkg. This may be more or
+// provide package-level objects referenced by pkg. This may be more or
// less than the set of packages directly imported by pkg's source code.
func (pkg *Package) Imports() []*Package { return pkg.imports }
diff --git a/libgo/go/go/types/predicates.go b/libgo/go/go/types/predicates.go
index 993c6d290b..21fd81e3c2 100644
--- a/libgo/go/go/types/predicates.go
+++ b/libgo/go/go/types/predicates.go
@@ -112,7 +112,12 @@ func hasNil(typ Type) bool {
// Identical reports whether x and y are identical.
func Identical(x, y Type) bool {
- return identical(x, y, nil)
+ return identical(x, y, true, nil)
+}
+
+// IdenticalIgnoreTags reports whether x and y are identical if tags are ignored.
+func IdenticalIgnoreTags(x, y Type) bool {
+ return identical(x, y, false, nil)
}
// An ifacePair is a node in a stack of interface type pairs compared for identity.
@@ -125,7 +130,7 @@ func (p *ifacePair) identical(q *ifacePair) bool {
return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
}
-func identical(x, y Type, p *ifacePair) bool {
+func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
if x == y {
return true
}
@@ -143,13 +148,13 @@ func identical(x, y Type, p *ifacePair) bool {
// Two array types are identical if they have identical element types
// and the same array length.
if y, ok := y.(*Array); ok {
- return x.len == y.len && identical(x.elem, y.elem, p)
+ return x.len == y.len && identical(x.elem, y.elem, cmpTags, p)
}
case *Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok {
- return identical(x.elem, y.elem, p)
+ return identical(x.elem, y.elem, cmpTags, p)
}
case *Struct:
@@ -162,9 +167,9 @@ func identical(x, y Type, p *ifacePair) bool {
for i, f := range x.fields {
g := y.fields[i]
if f.anonymous != g.anonymous ||
- x.Tag(i) != y.Tag(i) ||
+ cmpTags && x.Tag(i) != y.Tag(i) ||
!f.sameId(g.pkg, g.name) ||
- !identical(f.typ, g.typ, p) {
+ !identical(f.typ, g.typ, cmpTags, p) {
return false
}
}
@@ -175,7 +180,7 @@ func identical(x, y Type, p *ifacePair) bool {
case *Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok {
- return identical(x.base, y.base, p)
+ return identical(x.base, y.base, cmpTags, p)
}
case *Tuple:
@@ -186,7 +191,7 @@ func identical(x, y Type, p *ifacePair) bool {
if x != nil {
for i, v := range x.vars {
w := y.vars[i]
- if !identical(v.typ, w.typ, p) {
+ if !identical(v.typ, w.typ, cmpTags, p) {
return false
}
}
@@ -202,8 +207,8 @@ func identical(x, y Type, p *ifacePair) bool {
// names are not required to match.
if y, ok := y.(*Signature); ok {
return x.variadic == y.variadic &&
- identical(x.params, y.params, p) &&
- identical(x.results, y.results, p)
+ identical(x.params, y.params, cmpTags, p) &&
+ identical(x.results, y.results, cmpTags, p)
}
case *Interface:
@@ -249,7 +254,7 @@ func identical(x, y Type, p *ifacePair) bool {
}
for i, f := range a {
g := b[i]
- if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+ if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) {
return false
}
}
@@ -260,14 +265,14 @@ func identical(x, y Type, p *ifacePair) bool {
case *Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok {
- return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+ return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p)
}
case *Chan:
// Two channel types are identical if they have identical value types
// and the same direction.
if y, ok := y.(*Chan); ok {
- return x.dir == y.dir && identical(x.elem, y.elem, p)
+ return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p)
}
case *Named:
@@ -277,6 +282,8 @@ func identical(x, y Type, p *ifacePair) bool {
return x.obj == y.obj
}
+ case nil:
+
default:
unreachable()
}
@@ -284,11 +291,11 @@ func identical(x, y Type, p *ifacePair) bool {
return false
}
-// defaultType returns the default "typed" type for an "untyped" type;
+// Default returns the default "typed" type for an "untyped" type;
// it returns the incoming type for all other types. The default type
// for untyped nil is untyped nil.
//
-func defaultType(typ Type) Type {
+func Default(typ Type) Type {
if t, ok := typ.(*Basic); ok {
switch t.kind {
case UntypedBool:
diff --git a/libgo/go/go/types/resolver.go b/libgo/go/go/types/resolver.go
index 1536df5bf1..046e147456 100644
--- a/libgo/go/go/types/resolver.go
+++ b/libgo/go/go/types/resolver.go
@@ -14,29 +14,34 @@ import (
"unicode"
)
-// A declInfo describes a package-level const, type, var, or func declaration.
+// A declInfo describes a package-level const, type, var, func, or alias declaration.
type declInfo struct {
file *Scope // scope of file containing this declaration
lhs []*Var // lhs of n:1 variable declarations, or nil
typ ast.Expr // type, or nil
- init ast.Expr // init expression, or nil
+ init ast.Expr // init/orig expression, or nil
fdecl *ast.FuncDecl // func declaration, or nil
- deps map[Object]bool // type and init dependencies; lazily allocated
- mark int // for dependency analysis
+ // The deps field tracks initialization expression dependencies.
+ // As a special (overloaded) case, it also tracks dependencies of
+ // interface types on embedded interfaces (see ordering.go).
+ deps objSet // lazily initialized
}
+// An objSet is simply a set of objects.
+type objSet map[Object]bool
+
// hasInitializer reports whether the declared object has an initialization
// expression or function body.
func (d *declInfo) hasInitializer() bool {
return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
}
-// addDep adds obj as a dependency to d.
+// addDep adds obj to the set of objects d's init expression depends on.
func (d *declInfo) addDep(obj Object) {
m := d.deps
if m == nil {
- m = make(map[Object]bool)
+ m = make(objSet)
d.deps = m
}
m[obj] = true
@@ -67,7 +72,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):
@@ -269,6 +274,13 @@ func (check *Checker) collectObjects() {
check.declare(fileScope, nil, obj, token.NoPos)
}
+ // Alias-related code. Keep for now.
+ // case *ast.AliasSpec:
+ // obj := NewAlias(s.Name.Pos(), pkg, s.Name.Name, nil)
+ // obj.typ = nil // unresolved
+ // obj.kind = d.Tok
+ // check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, init: s.Orig})
+
case *ast.ValueSpec:
switch d.Tok {
case token.CONST:
diff --git a/libgo/go/go/types/return.go b/libgo/go/go/types/return.go
index 6628985214..0c1447f89b 100644
--- a/libgo/go/go/types/return.go
+++ b/libgo/go/go/types/return.go
@@ -83,8 +83,13 @@ func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
}
func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
- n := len(list)
- return n > 0 && check.isTerminating(list[n-1], label)
+ // trailing empty statements are permitted - skip them
+ for i := len(list) - 1; i >= 0; i-- {
+ if _, ok := list[i].(*ast.EmptyStmt); !ok {
+ return check.isTerminating(list[i], label)
+ }
+ }
+ return false // all statements are empty
}
func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
diff --git a/libgo/go/go/types/scope.go b/libgo/go/go/types/scope.go
index 3502840225..b5d34d6e65 100644
--- a/libgo/go/go/types/scope.go
+++ b/libgo/go/go/types/scope.go
@@ -31,7 +31,7 @@ type Scope struct {
}
// NewScope returns a new, empty scope contained in the given parent
-// scope, if any. The comment is for debugging only.
+// scope, if any. The comment is for debugging only.
func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
s := &Scope{parent, nil, nil, pos, end, comment}
// don't add children to Universe scope!
diff --git a/libgo/go/go/types/sizes.go b/libgo/go/go/types/sizes.go
index 87c3ce4159..3bbe5aee40 100644
--- a/libgo/go/go/types/sizes.go
+++ b/libgo/go/go/types/sizes.go
@@ -64,12 +64,25 @@ func (s *StdSizes) Alignof(T Type) int64 {
}
}
return max
+ case *Slice, *Interface:
+ // Multiword data structures are effectively structs
+ // in which each element has size WordSize.
+ return s.WordSize
+ case *Basic:
+ // Strings are like slices and interfaces.
+ if t.Info()&IsString != 0 {
+ return s.WordSize
+ }
}
a := s.Sizeof(T) // may be 0
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
if a < 1 {
return 1
}
+ // complex{64,128} are aligned like [2]float{32,64}.
+ if isComplex(T) {
+ a /= 2
+ }
if a > s.MaxAlign {
return s.MaxAlign
}
@@ -132,8 +145,8 @@ func (s *StdSizes) Sizeof(T Type) int64 {
if n == 0 {
return 0
}
- setOffsets(t, s)
- return t.offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+ offsets := s.Offsetsof(t.fields)
+ return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
case *Interface:
return s.WordSize * 2
}
@@ -158,22 +171,18 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
if T.NumFields() > 0 {
// compute offsets on demand
if s := conf.Sizes; s != nil {
- calculated := setOffsets(T, s)
- offsets = T.offsets
- if calculated {
- // sanity checks
- if len(offsets) != T.NumFields() {
- panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
- }
- for _, o := range offsets {
- if o < 0 {
- panic("Config.Sizes.Offsetsof returned an offset < 0")
- }
+ offsets = s.Offsetsof(T.fields)
+ // sanity checks
+ if len(offsets) != T.NumFields() {
+ panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+ }
+ for _, o := range offsets {
+ if o < 0 {
+ panic("Config.Sizes.Offsetsof returned an offset < 0")
}
}
} else {
- setOffsets(T, &stdSizes)
- offsets = T.offsets
+ offsets = stdSizes.Offsetsof(T.fields)
}
}
return offsets
@@ -207,15 +216,3 @@ func align(x, a int64) int64 {
y := x + a - 1
return y - y%a
}
-
-// setOffsets sets the offsets of s for the given sizes if necessary.
-// The result is true if the offsets were not set before; otherwise it
-// is false.
-func setOffsets(s *Struct, sizes Sizes) bool {
- var calculated bool
- s.offsetsOnce.Do(func() {
- calculated = true
- s.offsets = sizes.Offsetsof(s.fields)
- })
- return calculated
-}
diff --git a/libgo/go/go/types/sizes_test.go b/libgo/go/go/types/sizes_test.go
new file mode 100644
index 0000000000..dea18e7db4
--- /dev/null
+++ b/libgo/go/go/types/sizes_test.go
@@ -0,0 +1,119 @@
+// 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 contains tests for sizes.
+
+package types_test
+
+import (
+ "go/ast"
+ // "go/importer"
+ "go/parser"
+ "go/token"
+ "go/types"
+ "testing"
+)
+
+// findStructType typechecks src and returns the first struct type encountered.
+func findStructType(t *testing.T, src string) *types.Struct {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "x.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
+ var conf types.Config
+ _, err = conf.Check("x", fset, []*ast.File{f}, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, tv := range info.Types {
+ if ts, ok := tv.Type.(*types.Struct); ok {
+ return ts
+ }
+ }
+ t.Fatalf("failed to find a struct type in src:\n%s\n", src)
+ return nil
+}
+
+// Issue 16316
+func TestMultipleSizeUse(t *testing.T) {
+ const src = `
+package main
+
+type S struct {
+ i int
+ b bool
+ s string
+ n int
+}
+`
+ ts := findStructType(t, src)
+ sizes := types.StdSizes{WordSize: 4, MaxAlign: 4}
+ if got := sizes.Sizeof(ts); got != 20 {
+ t.Errorf("Sizeof(%v) with WordSize 4 = %d want 20", ts, got)
+ }
+ sizes = types.StdSizes{WordSize: 8, MaxAlign: 8}
+ if got := sizes.Sizeof(ts); got != 40 {
+ t.Errorf("Sizeof(%v) with WordSize 8 = %d want 40", ts, got)
+ }
+}
+
+// Issue 16464
+func TestAlignofNaclSlice(t *testing.T) {
+ const src = `
+package main
+
+var s struct {
+ x *int
+ y []byte
+}
+`
+ ts := findStructType(t, src)
+ sizes := &types.StdSizes{WordSize: 4, MaxAlign: 8}
+ var fields []*types.Var
+ // Make a copy manually :(
+ for i := 0; i < ts.NumFields(); i++ {
+ fields = append(fields, ts.Field(i))
+ }
+ offsets := sizes.Offsetsof(fields)
+ if offsets[0] != 0 || offsets[1] != 4 {
+ t.Errorf("OffsetsOf(%v) = %v want %v", ts, offsets, []int{0, 4})
+ }
+}
+
+/*
+Doesn't compile with current gccgo.
+
+sizes_test.go:101:3: error: use of undefined type 'Importer'
+
+func TestIssue16902(t *testing.T) {
+ const src = `
+package a
+
+import "unsafe"
+
+const _ = unsafe.Offsetof(struct{ x int64 }{}.x)
+`
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "x.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
+ conf := types.Config{
+ Importer: importer.Default(),
+ Sizes: &types.StdSizes{WordSize: 8, MaxAlign: 8},
+ }
+ _, err = conf.Check("x", fset, []*ast.File{f}, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, tv := range info.Types {
+ _ = conf.Sizes.Sizeof(tv.Type)
+ _ = conf.Sizes.Alignof(tv.Type)
+ }
+}
+
+*/
diff --git a/libgo/go/go/types/stdlib_test.go b/libgo/go/go/types/stdlib_test.go
index c63bfbb9a4..8fc51d4b17 100644
--- a/libgo/go/go/types/stdlib_test.go
+++ b/libgo/go/go/types/stdlib_test.go
@@ -160,6 +160,9 @@ func TestStdFixed(t *testing.T) {
"issue6889.go", // gc-specific test
"issue7746.go", // large constants - consumes too much memory
"issue11362.go", // canonical import path check
+ "issue15002.go", // uses Mmap; testTestDir should consult build tags
+ "issue16369.go", // go/types handles this correctly - not an issue
+ "issue18459.go", // go/types doesn't check validity of //go:xxx directives
)
}
@@ -273,13 +276,16 @@ func walkDirs(t *testing.T, dir string) {
}
// typecheck package in directory
- files, err := pkgFilenames(dir)
- if err != nil {
- t.Error(err)
- return
- }
- if files != nil {
- typecheck(t, dir, files)
+ // but ignore files directly under $GOROOT/src (might be temporary test files).
+ if dir != filepath.Join(runtime.GOROOT(), "src") {
+ files, err := pkgFilenames(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if files != nil {
+ typecheck(t, dir, files)
+ }
}
// traverse subdirectories, but don't walk into testdata
diff --git a/libgo/go/go/types/stmt.go b/libgo/go/go/types/stmt.go
index e0129cf0e0..4e423bd686 100644
--- a/libgo/go/go/types/stmt.go
+++ b/libgo/go/go/types/stmt.go
@@ -68,13 +68,19 @@ func (check *Checker) usage(scope *Scope) {
}
// stmtContext is a bitset describing which
-// control-flow statements are permissible.
+// control-flow statements are permissible,
+// and provides additional context information
+// for better error messages.
type stmtContext uint
const (
+ // permissible control-flow statements
breakOk stmtContext = 1 << iota
continueOk
fallthroughOk
+
+ // additional context information
+ finalSwitchCase
)
func (check *Checker) simpleStmt(s ast.Stmt) {
@@ -83,9 +89,19 @@ func (check *Checker) simpleStmt(s ast.Stmt) {
}
}
+func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
+ for i := len(list); i > 0; i-- {
+ if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
+ return list[:i]
+ }
+ }
+ return nil
+}
+
func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
ok := ctxt&fallthroughOk != 0
inner := ctxt &^ fallthroughOk
+ list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
for i, s := range list {
inner := inner
if ok && i+1 == len(list) {
@@ -113,7 +129,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
}
@@ -282,7 +298,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}(check.scope)
}
- inner := ctxt &^ fallthroughOk
+ inner := ctxt &^ (fallthroughOk | finalSwitchCase)
switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt:
// ignore
@@ -346,7 +362,17 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
return
}
+
var x operand
+ check.expr(&x, s.X)
+ if x.mode == invalid {
+ return
+ }
+ if !isNumeric(x.typ) {
+ check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
+ return
+ }
+
Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
check.binary(&x, nil, s.X, Y, op)
if x.mode == invalid {
@@ -434,7 +460,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
case token.FALLTHROUGH:
if ctxt&fallthroughOk == 0 {
- check.error(s.Pos(), "fallthrough statement out of place")
+ msg := "fallthrough statement out of place"
+ if ctxt&finalSwitchCase != 0 {
+ msg = "cannot fallthrough final case in switch"
+ }
+ check.error(s.Pos(), msg)
}
default:
check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
@@ -503,6 +533,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
inner := inner
if i+1 < len(s.Body.List) {
inner |= fallthroughOk
+ } else {
+ inner |= finalSwitchCase
}
check.stmtList(inner, clause.Body)
check.closeScope()
@@ -596,9 +628,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
T = x.typ
}
obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
- scopePos := clause.End()
- if len(clause.Body) > 0 {
- scopePos = clause.Body[0].Pos()
+ scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
+ if n := len(clause.List); n > 0 {
+ scopePos = clause.List[n-1].End()
}
check.declare(check.scope, nil, obj, scopePos)
check.recordImplicit(clause, obj)
@@ -790,12 +822,12 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// declare variables
if len(vars) > 0 {
+ scopePos := s.X.End()
for _, obj := range vars {
// spec: "The scope of a constant or variable identifier declared inside
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
// for short variable declarations) and ends at the end of the innermost
// containing block."
- scopePos := s.End()
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
}
} else {
diff --git a/libgo/go/go/types/testdata/blank.src b/libgo/go/go/types/testdata/blank.src
new file mode 100644
index 0000000000..6a2507f482
--- /dev/null
+++ b/libgo/go/go/types/testdata/blank.src
@@ -0,0 +1,5 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package _ /* ERROR invalid package name */
diff --git a/libgo/go/go/types/testdata/builtins.src b/libgo/go/go/types/testdata/builtins.src
new file mode 100644
index 0000000000..7fb7b58a48
--- /dev/null
+++ b/libgo/go/go/types/testdata/builtins.src
@@ -0,0 +1,901 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+ var b byte
+ var x int
+ var s []byte
+ _ = append() // ERROR not enough arguments
+ _ = append("foo" /* ERROR not a slice */ )
+ _ = append(nil /* ERROR not a slice */ , s)
+ _ = append(x /* ERROR not a slice */ , s)
+ _ = append(s)
+ append /* ERROR not used */ (s)
+
+ _ = append(s, b)
+ _ = append(s, x /* ERROR cannot use x */ )
+ _ = append(s, s /* ERROR cannot use s */ )
+ _ = append(s... /* ERROR can only use ... with matching parameter */ )
+ _ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
+ _ = append(s, 1, 2, 3)
+ _ = append(s, 1, 2, 3, x /* ERROR cannot use x */ , 5, 6, 6)
+ _ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
+ _ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+ type S []byte
+ type T string
+ var t T
+ _ = append(s, "foo" /* ERROR cannot convert */ )
+ _ = append(s, "foo"...)
+ _ = append(S(s), "foo" /* ERROR cannot convert */ )
+ _ = append(S(s), "foo"...)
+ _ = append(s, t /* ERROR cannot use t */ )
+ _ = append(s, t...)
+ _ = append(s, T("foo")...)
+ _ = append(S(s), t /* ERROR cannot use t */ )
+ _ = append(S(s), t...)
+ _ = append(S(s), T("foo")...)
+ _ = append([]string{}, t /* ERROR cannot use t */ , "foo")
+ _ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+ s0 := []int{0, 0}
+ s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2}
+ s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7}
+ s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+ s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+ var t []interface{}
+ t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
+
+ var b []byte
+ b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
+
+ _ = s4
+}
+
+func append3() {
+ f1 := func() (s []int) { return }
+ f2 := func() (s []int, x int) { return }
+ f3 := func() (s []int, x, y int) { return }
+ f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+ ff := func() (int, float32) { return 0, 0 }
+ _ = append(f0 /* ERROR used as value */ ())
+ _ = append(f1())
+ _ = append(f2())
+ _ = append(f3())
+ _ = append(f5())
+ _ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+ var a [10]bool
+ var p *[20]int
+ var c chan string
+ _ = cap() // ERROR not enough arguments
+ _ = cap(1, 2) // ERROR too many arguments
+ _ = cap(42 /* ERROR invalid */)
+ const _3 = cap(a)
+ assert(_3 == 10)
+ const _4 = cap(p)
+ assert(_4 == 20)
+ _ = cap(c)
+ cap /* ERROR not used */ (c)
+
+ // issue 4744
+ type T struct{ a [10]int }
+ const _ = cap(((*T)(nil)).a)
+
+ var s [][]byte
+ _ = cap(s)
+ _ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+ f1a := func() (a [10]int) { return }
+ f1s := func() (s []int) { return }
+ f2 := func() (s []int, x int) { return }
+ _ = cap(f0 /* ERROR used as value */ ())
+ _ = cap(f1a())
+ _ = cap(f1s())
+ _ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+ var f = func() int { return 0 }
+ var x = f()
+ const (
+ _ = cap([4]int{})
+ _ = cap([4]int{x})
+ _ = cap /* ERROR not constant */ ([4]int{f()})
+ _ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+ _ = cap([4]int{cap([4]int{})})
+ )
+ var y float64
+ var z complex128
+ const (
+ _ = cap([4]float64{})
+ _ = cap([4]float64{y})
+ _ = cap([4]float64{real(2i)})
+ _ = cap /* ERROR not constant */ ([4]float64{real(z)})
+ )
+ var ch chan [10]int
+ const (
+ _ = cap /* ERROR not constant */ (<-ch)
+ _ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+ )
+}
+
+func close1() {
+ var c chan int
+ var r <-chan int
+ close() // ERROR not enough arguments
+ close(1, 2) // ERROR too many arguments
+ close(42 /* ERROR not a channel */)
+ close(r /* ERROR receive-only channel */)
+ close(c)
+ _ = close /* ERROR used as value */ (c)
+
+ var s []chan int
+ close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+ f1 := func() (ch chan int) { return }
+ f2 := func() (ch chan int, x int) { return }
+ close(f0 /* ERROR used as value */ ())
+ close(f1())
+ close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+ var i32 int32
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = complex() // ERROR not enough arguments
+ _ = complex(1) // ERROR not enough arguments
+ _ = complex(true /* ERROR mismatched types */ , 0)
+ _ = complex(i32 /* ERROR expected floating-point */ , 0)
+ _ = complex("foo" /* ERROR mismatched types */ , 0)
+ _ = complex(c64 /* ERROR expected floating-point */ , 0)
+ _ = complex(0 /* ERROR mismatched types */ , true)
+ _ = complex(0 /* ERROR expected floating-point */ , i32)
+ _ = complex(0 /* ERROR mismatched types */ , "foo")
+ _ = complex(0 /* ERROR expected floating-point */ , c64)
+ _ = complex(f32, f32)
+ _ = complex(f32, 1)
+ _ = complex(f32, 1.0)
+ _ = complex(f32, 'a')
+ _ = complex(f64, f64)
+ _ = complex(f64, 1)
+ _ = complex(f64, 1.0)
+ _ = complex(f64, 'a')
+ _ = complex(f32 /* ERROR mismatched types */ , f64)
+ _ = complex(f64 /* ERROR mismatched types */ , f32)
+ _ = complex(1, 1)
+ _ = complex(1, 1.1)
+ _ = complex(1, 'a')
+ complex /* ERROR not used */ (1, 2)
+
+ var _ complex64 = complex(f32, f32)
+ var _ complex64 = complex /* ERROR cannot use .* in variable declaration */ (f64, f64)
+
+ var _ complex128 = complex /* ERROR cannot use .* in variable declaration */ (f32, f32)
+ var _ complex128 = complex(f64, f64)
+
+ // untyped constants
+ const _ int = complex(1, 0)
+ const _ float32 = complex(1, 0)
+ const _ complex64 = complex(1, 0)
+ const _ complex128 = complex(1, 0)
+ const _ = complex(0i, 0i)
+ const _ = complex(0i, 0)
+ const _ int = 1.0 + complex(1, 0i)
+
+ const _ int = complex /* ERROR int */ (1.1, 0)
+ const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+ // untyped values
+ var s uint
+ _ = complex(1 /* ERROR integer */ <<s, 0)
+ const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+ var _ int = complex /* ERROR cannot use .* in variable declaration */ (1 /* ERROR integer */ <<s, 0)
+
+ // floating-point argument types must be identical
+ type F32 float32
+ type F64 float64
+ var x32 F32
+ var x64 F64
+ c64 = complex(x32, x32)
+ _ = complex(x32 /* ERROR mismatched types */ , f32)
+ _ = complex(f32 /* ERROR mismatched types */ , x32)
+ c128 = complex(x64, x64)
+ _ = c128
+ _ = complex(x64 /* ERROR mismatched types */ , f64)
+ _ = complex(f64 /* ERROR mismatched types */ , x64)
+
+ var t []float32
+ _ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+ f1 := func() (x float32) { return }
+ f2 := func() (x, y float32) { return }
+ f3 := func() (x, y, z float32) { return }
+ _ = complex(f0 /* ERROR used as value */ ())
+ _ = complex(f1()) // ERROR not enough arguments
+ _ = complex(f2())
+ _ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+ copy() // ERROR not enough arguments
+ copy("foo") // ERROR not enough arguments
+ copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+ copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+ copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+ // spec examples
+ var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+ var s = make([]int, 6)
+ var b = make([]byte, 5)
+ n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+ n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+ n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
+ _, _, _ = n1, n2, n3
+
+ var t [][]int
+ copy(t, t)
+ copy(t /* ERROR copy expects slice arguments */ , nil)
+ copy(nil /* ERROR copy expects slice arguments */ , t)
+ copy(nil /* ERROR copy expects slice arguments */ , nil)
+ copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+ f1 := func() (a []int) { return }
+ f2 := func() (a, b []int) { return }
+ f3 := func() (a, b, c []int) { return }
+ copy(f0 /* ERROR used as value */ ())
+ copy(f1()) // ERROR not enough arguments
+ copy(f2())
+ copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+ var m map[string]int
+ var s string
+ delete() // ERROR not enough arguments
+ delete(1) // ERROR not enough arguments
+ delete(1, 2, 3) // ERROR too many arguments
+ delete(m, 0 /* ERROR not assignable */)
+ delete(m, s)
+ _ = delete /* ERROR used as value */ (m, s)
+
+ var t []map[string]string
+ delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+ f1 := func() (m map[string]int) { return }
+ f2 := func() (m map[string]int, k string) { return }
+ f3 := func() (m map[string]int, k string, x float32) { return }
+ delete(f0 /* ERROR used as value */ ())
+ delete(f1()) // ERROR not enough arguments
+ delete(f2())
+ delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = imag() // ERROR not enough arguments
+ _ = imag(1, 2) // ERROR too many arguments
+ _ = imag(10)
+ _ = imag(2.7182818)
+ _ = imag("foo" /* ERROR expected complex */)
+ _ = imag('a')
+ const _5 = imag(1 + 2i)
+ assert(_5 == 2)
+ f32 = _5
+ f64 = _5
+ const _6 = imag(0i)
+ assert(_6 == 0)
+ f32 = imag(c64)
+ f64 = imag(c128)
+ f32 = imag /* ERROR cannot use .* in assignment */ (c128)
+ f64 = imag /* ERROR cannot use .* in assignment */ (c64)
+ imag /* ERROR not used */ (c64)
+ _, _ = f32, f64
+
+ // complex type may not be predeclared
+ type C64 complex64
+ type C128 complex128
+ var x64 C64
+ var x128 C128
+ f32 = imag(x64)
+ f64 = imag(x128)
+
+ var a []complex64
+ _ = imag(a... /* ERROR invalid use of \.\.\. */ )
+
+ // if argument is untyped, result is untyped
+ const _ byte = imag(1.2 + 3i)
+ const _ complex128 = imag(1.2 + 3i)
+
+ // lhs constant shift operands are typed as complex128
+ var s uint
+ _ = imag(1 /* ERROR must be integer */ << s)
+}
+
+func imag2() {
+ f1 := func() (x complex128) { return }
+ f2 := func() (x, y complex128) { return }
+ _ = imag(f0 /* ERROR used as value */ ())
+ _ = imag(f1())
+ _ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+ const c = "foobar"
+ var a [10]bool
+ var p *[20]int
+ var m map[string]complex128
+ _ = len() // ERROR not enough arguments
+ _ = len(1, 2) // ERROR too many arguments
+ _ = len(42 /* ERROR invalid */)
+ const _3 = len(c)
+ assert(_3 == 6)
+ const _4 = len(a)
+ assert(_4 == 10)
+ const _5 = len(p)
+ assert(_5 == 20)
+ _ = len(m)
+ len /* ERROR not used */ (c)
+
+ // esoteric case
+ var t string
+ var hash map[interface{}][]*[10]int
+ const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+ assert(n == 10) // ok because n has unknown value and no error is reported
+ var ch <-chan int
+ const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+ // issue 4744
+ type T struct{ a [10]int }
+ const _ = len(((*T)(nil)).a)
+
+ var s [][]byte
+ _ = len(s)
+ _ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+ f1 := func() (x []int) { return }
+ f2 := func() (x, y []int) { return }
+ _ = len(f0 /* ERROR used as value */ ())
+ _ = len(f1())
+ _ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+ var f = func() int { return 0 }
+ var x = f()
+ const (
+ _ = len([4]int{})
+ _ = len([4]int{x})
+ _ = len /* ERROR not constant */ ([4]int{f()})
+ _ = len /* ERROR not constant */ ([4]int{len([]int{})})
+ _ = len([4]int{len([4]int{})})
+ )
+ var y float64
+ var z complex128
+ const (
+ _ = len([4]float64{})
+ _ = len([4]float64{y})
+ _ = len([4]float64{real(2i)})
+ _ = len /* ERROR not constant */ ([4]float64{real(z)})
+ )
+ var ch chan [10]int
+ const (
+ _ = len /* ERROR not constant */ (<-ch)
+ _ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+ )
+}
+
+func make1() {
+ var n int
+ var m float32
+ var s uint
+
+ _ = make() // ERROR not enough arguments
+ _ = make(1 /* ERROR not a type */)
+ _ = make(int /* ERROR cannot make */)
+
+ // slices
+ _ = make/* ERROR arguments */ ([]int)
+ _ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+ _ = make([]int, int /* ERROR not an expression */)
+ _ = make([]int, 10, float32 /* ERROR not an expression */)
+ _ = make([]int, "foo" /* ERROR cannot convert */)
+ _ = make([]int, 10, 2.3 /* ERROR truncated */)
+ _ = make([]int, 5, 10.0)
+ _ = make([]int, 0i)
+ _ = make([]int, 1.0)
+ _ = make([]int, 1.0<<s)
+ _ = make([]int, 1.1 /* ERROR int */ <<s)
+ _ = make([]int, - /* ERROR must not be negative */ 1, 10)
+ _ = make([]int, 0, - /* ERROR must not be negative */ 1)
+ _ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+ _ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+ _ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+ _ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+ _ = make([]int, m /* ERROR must be integer */ )
+ _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+ // maps
+ _ = make /* ERROR arguments */ (map[int]string, 10, 20)
+ _ = make(map[int]float32, int /* ERROR not an expression */)
+ _ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+ _ = make(map[int]float32, 10)
+ _ = make(map[int]float32, n)
+ _ = make(map[int]float32, int64(n))
+ _ = make(map[string]bool, 10.0)
+ _ = make(map[string]bool, 10.0<<s)
+ _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+ // channels
+ _ = make /* ERROR arguments */ (chan int, 10, 20)
+ _ = make(chan int, int /* ERROR not an expression */)
+ _ = make(chan<- int, "foo" /* ERROR cannot convert */)
+ _ = make(chan int, - /* ERROR must not be negative */ 10)
+ _ = make(<-chan float64, 10)
+ _ = make(chan chan int, n)
+ _ = make(chan string, int64(n))
+ _ = make(chan bool, 10.0)
+ _ = make(chan bool, 10.0<<s)
+ _ = &make /* ERROR cannot take address */ (chan bool)
+
+ make /* ERROR not used */ ([]int, 10)
+
+ var t []int
+ _ = make([]int, t[0], t[1])
+ _ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+ f1 /* ERROR not used */ := func() (x []int) { return }
+ _ = make(f0 /* ERROR not a type */ ())
+ _ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+ _ = new() // ERROR not enough arguments
+ _ = new(1, 2) // ERROR too many arguments
+ _ = new("foo" /* ERROR not a type */)
+ p := new(float64)
+ _ = new(struct{ x, y int })
+ q := new(*float64)
+ _ = *p == **q
+ new /* ERROR not used */ (int)
+ _ = &new /* ERROR cannot take address */ (int)
+
+ _ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+ f1 /* ERROR not used */ := func() (x []int) { return }
+ _ = new(f0 /* ERROR not a type */ ())
+ _ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+ panic() // ERROR not enough arguments
+ panic(1, 2) // ERROR too many arguments
+ panic(0)
+ panic("foo")
+ panic(false)
+ panic(1<<10)
+ panic(1 /* ERROR overflows */ <<1000)
+ _ = panic /* ERROR used as value */ (0)
+
+ var s []byte
+ panic(s)
+ panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ panic(f0 /* ERROR used as value */ ())
+ panic(f1())
+ panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+ print()
+ print(1)
+ print(1, 2)
+ print("foo")
+ print(2.718281828)
+ print(false)
+ print(1<<10)
+ print(1 /* ERROR overflows */ <<1000)
+ println(nil /* ERROR untyped nil */ )
+
+ var s []int
+ print(s... /* ERROR invalid use of \.\.\. */ )
+ _ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ f3 := func() (x int, y float32, z string) { return }
+ print(f0 /* ERROR used as value */ ())
+ print(f1())
+ print(f2())
+ print(f3())
+}
+
+func println1() {
+ println()
+ println(1)
+ println(1, 2)
+ println("foo")
+ println(2.718281828)
+ println(false)
+ println(1<<10)
+ println(1 /* ERROR overflows */ <<1000)
+ println(nil /* ERROR untyped nil */ )
+
+ var s []int
+ println(s... /* ERROR invalid use of \.\.\. */ )
+ _ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ f3 := func() (x int, y float32, z string) { return }
+ println(f0 /* ERROR used as value */ ())
+ println(f1())
+ println(f2())
+ println(f3())
+}
+
+func real1() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = real() // ERROR not enough arguments
+ _ = real(1, 2) // ERROR too many arguments
+ _ = real(10)
+ _ = real(2.7182818)
+ _ = real("foo" /* ERROR expected complex */)
+ const _5 = real(1 + 2i)
+ assert(_5 == 1)
+ f32 = _5
+ f64 = _5
+ const _6 = real(0i)
+ assert(_6 == 0)
+ f32 = real(c64)
+ f64 = real(c128)
+ f32 = real /* ERROR cannot use .* in assignment */ (c128)
+ f64 = real /* ERROR cannot use .* in assignment */ (c64)
+ real /* ERROR not used */ (c64)
+
+ // complex type may not be predeclared
+ type C64 complex64
+ type C128 complex128
+ var x64 C64
+ var x128 C128
+ f32 = imag(x64)
+ f64 = imag(x128)
+ _, _ = f32, f64
+
+ var a []complex64
+ _ = real(a... /* ERROR invalid use of \.\.\. */ )
+
+ // if argument is untyped, result is untyped
+ const _ byte = real(1 + 2.3i)
+ const _ complex128 = real(1 + 2.3i)
+
+ // lhs constant shift operands are typed as complex128
+ var s uint
+ _ = real(1 /* ERROR must be integer */ << s)
+}
+
+func real2() {
+ f1 := func() (x complex128) { return }
+ f2 := func() (x, y complex128) { return }
+ _ = real(f0 /* ERROR used as value */ ())
+ _ = real(f1())
+ _ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+ _ = recover()
+ _ = recover(10) // ERROR too many arguments
+ recover()
+
+ var s []int
+ recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ _ = recover(f0 /* ERROR used as value */ ())
+ _ = recover(f1()) // ERROR too many arguments
+ _ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{ // offset
+ a bool // 0
+ b rune // 4
+ c *int // 8
+ d bool // 16
+ e complex128 // 24
+} // 40
+
+type S1 struct{ // offset
+ x float32 // 0
+ y string // 8
+ z *S1 // 24
+ S0 // 32
+} // 72
+
+type S2 struct{ // offset
+ *S1 // 0
+} // 8
+
+type S3 struct { // offset
+ a int64 // 0
+ b int32 // 8
+} // 12
+
+type S4 struct { // offset
+ S3 // 0
+ int32 // 12
+} // 16
+
+type S5 struct { // offset
+ a [3]int32 // 0
+ b int32 // 12
+} // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+ var x int
+ _ = unsafe.Alignof() // ERROR not enough arguments
+ _ = unsafe.Alignof(1, 2) // ERROR too many arguments
+ _ = unsafe.Alignof(int /* ERROR not an expression */)
+ _ = unsafe.Alignof(42)
+ _ = unsafe.Alignof(new(struct{}))
+ _ = unsafe.Alignof(1<<10)
+ _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+ _ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+ unsafe /* ERROR not used */ .Alignof(x)
+
+ var y S0
+ assert(unsafe.Alignof(y.a) == 1)
+ assert(unsafe.Alignof(y.b) == 4)
+ assert(unsafe.Alignof(y.c) == 8)
+ assert(unsafe.Alignof(y.d) == 1)
+ assert(unsafe.Alignof(y.e) == 8)
+
+ var s []byte
+ _ = unsafe.Alignof(s)
+ _ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+ f1 := func() (x int32) { return }
+ f2 := func() (x, y int32) { return }
+ _ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+ assert(unsafe.Alignof(f1()) == 4)
+ _ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+ var x struct{ f int }
+ _ = unsafe.Offsetof() // ERROR not enough arguments
+ _ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+ _ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(x.f)
+ _ = unsafe.Offsetof((x.f))
+ _ = unsafe.Offsetof((((((((x))).f)))))
+ unsafe /* ERROR not used */ .Offsetof(x.f)
+
+ var y0 S0
+ assert(unsafe.Offsetof(y0.a) == 0)
+ assert(unsafe.Offsetof(y0.b) == 4)
+ assert(unsafe.Offsetof(y0.c) == 8)
+ assert(unsafe.Offsetof(y0.d) == 16)
+ assert(unsafe.Offsetof(y0.e) == 24)
+
+ var y1 S1
+ assert(unsafe.Offsetof(y1.x) == 0)
+ assert(unsafe.Offsetof(y1.y) == 8)
+ assert(unsafe.Offsetof(y1.z) == 24)
+ assert(unsafe.Offsetof(y1.S0) == 32)
+
+ assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+ assert(unsafe.Offsetof(y1.a) == 32) // relative to S1
+ assert(unsafe.Offsetof(y1.b) == 36) // relative to S1
+ assert(unsafe.Offsetof(y1.c) == 40) // relative to S1
+ assert(unsafe.Offsetof(y1.d) == 48) // relative to S1
+ assert(unsafe.Offsetof(y1.e) == 56) // relative to S1
+
+ var y1p *S1
+ assert(unsafe.Offsetof(y1p.S0) == 32)
+
+ type P *S1
+ var p P = y1p
+ assert(unsafe.Offsetof(p.S0) == 32)
+
+ var y2 S2
+ assert(unsafe.Offsetof(y2.S1) == 0)
+ _ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+ _ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+ var s []byte
+ _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+ f1 := func() (x int32) { return }
+ f2 := func() (x, y int32) { return }
+ _ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+ _ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+ _ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+ var x int
+ _ = unsafe.Sizeof() // ERROR not enough arguments
+ _ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+ _ = unsafe.Sizeof(int /* ERROR not an expression */)
+ _ = unsafe.Sizeof(42)
+ _ = unsafe.Sizeof(new(complex128))
+ _ = unsafe.Sizeof(1<<10)
+ _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+ _ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+ unsafe /* ERROR not used */ .Sizeof(x)
+
+ // basic types have size guarantees
+ assert(unsafe.Sizeof(byte(0)) == 1)
+ assert(unsafe.Sizeof(uint8(0)) == 1)
+ assert(unsafe.Sizeof(int8(0)) == 1)
+ assert(unsafe.Sizeof(uint16(0)) == 2)
+ assert(unsafe.Sizeof(int16(0)) == 2)
+ assert(unsafe.Sizeof(uint32(0)) == 4)
+ assert(unsafe.Sizeof(int32(0)) == 4)
+ assert(unsafe.Sizeof(float32(0)) == 4)
+ assert(unsafe.Sizeof(uint64(0)) == 8)
+ assert(unsafe.Sizeof(int64(0)) == 8)
+ assert(unsafe.Sizeof(float64(0)) == 8)
+ assert(unsafe.Sizeof(complex64(0)) == 8)
+ assert(unsafe.Sizeof(complex128(0)) == 16)
+
+ var y0 S0
+ assert(unsafe.Sizeof(y0.a) == 1)
+ assert(unsafe.Sizeof(y0.b) == 4)
+ assert(unsafe.Sizeof(y0.c) == 8)
+ assert(unsafe.Sizeof(y0.d) == 1)
+ assert(unsafe.Sizeof(y0.e) == 16)
+ assert(unsafe.Sizeof(y0) == 40)
+
+ var y1 S1
+ assert(unsafe.Sizeof(y1) == 72)
+
+ var y2 S2
+ assert(unsafe.Sizeof(y2) == 8)
+
+ var y3 S3
+ assert(unsafe.Sizeof(y3) == 12)
+
+ var y4 S4
+ assert(unsafe.Sizeof(y4) == 16)
+
+ var y5 S5
+ assert(unsafe.Sizeof(y5) == 16)
+
+ var a3 [10]S3
+ assert(unsafe.Sizeof(a3) == 156)
+
+ // test case for issue 5670
+ type T struct {
+ a int32
+ _ int32
+ c int32
+ }
+ assert(unsafe.Sizeof(T{}) == 12)
+
+ var s []byte
+ _ = unsafe.Sizeof(s)
+ _ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+ f1 := func() (x int64) { return }
+ f2 := func() (x, y int64) { return }
+ _ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+ assert(unsafe.Sizeof(f1()) == 8)
+ _ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+ var x int
+ assert() /* ERROR not enough arguments */
+ assert(1, 2) /* ERROR too many arguments */
+ assert("foo" /* ERROR boolean constant */ )
+ assert(x /* ERROR boolean constant */)
+ assert(true)
+ assert /* ERROR failed */ (false)
+ _ = assert(true)
+
+ var s []byte
+ assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+ f1 := func() (x bool) { return }
+ f2 := func() (x bool) { return }
+ assert(f0 /* ERROR used as value */ ())
+ assert(f1 /* ERROR boolean constant */ ())
+ assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+ // Uncomment the code below to test trace - will produce console output
+ // _ = trace /* ERROR no value */ ()
+ // _ = trace(1)
+ // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+ var s []byte
+ trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x int, y string) { return }
+ f3 := func() (x int, y string, z []int) { return }
+ _ = f1
+ _ = f2
+ _ = f3
+ // Uncomment the code below to test trace - will produce console output
+ // trace(f0())
+ // trace(f1())
+ // trace(f2())
+ // trace(f3())
+ // trace(f0(), 1)
+ // trace(f1(), 1, 2)
+ // trace(f2(), 1, 2, 3)
+ // trace(f3(), 1, 2, 3, 4)
+}
diff --git a/libgo/go/go/types/testdata/const0.src b/libgo/go/go/types/testdata/const0.src
new file mode 100644
index 0000000000..a61717887e
--- /dev/null
+++ b/libgo/go/go/types/testdata/const0.src
@@ -0,0 +1,295 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// constant declarations
+
+package const0
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+ const _ interface /* ERROR invalid constant type */ {} = 0
+ for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+ // boolean values
+ ub0 = false
+ ub1 = true
+ ub2 = 2 < 1
+ ub3 = ui1 == uf1
+ ub4 = true /* ERROR "cannot convert" */ == 0
+
+ // integer values
+ ui0 = 0
+ ui1 = 1
+ ui2 = 42
+ ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+ ui4 = -10
+
+ ui5 = ui0 + ui1
+ ui6 = ui1 - ui1
+ ui7 = ui2 * ui1
+ ui8 = ui3 / ui3
+ ui9 = ui3 % ui3
+
+ ui10 = 1 / 0 /* ERROR "division by zero" */
+ ui11 = ui1 / 0 /* ERROR "division by zero" */
+ ui12 = ui3 / ui0 /* ERROR "division by zero" */
+ ui13 = 1 % 0 /* ERROR "division by zero" */
+ ui14 = ui1 % 0 /* ERROR "division by zero" */
+ ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+ ui16 = ui2 & ui3
+ ui17 = ui2 | ui3
+ ui18 = ui2 ^ ui3
+ ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+ // floating point values
+ uf0 = 0.
+ uf1 = 1.
+ uf2 = 4.2e1
+ uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+ uf4 = 1e-1
+
+ uf5 = uf0 + uf1
+ uf6 = uf1 - uf1
+ uf7 = uf2 * uf1
+ uf8 = uf3 / uf3
+ uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+ uf10 = 1 / 0 /* ERROR "division by zero" */
+ uf11 = uf1 / 0 /* ERROR "division by zero" */
+ uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+ uf16 = uf2 /* ERROR "not defined" */ & uf3
+ uf17 = uf2 /* ERROR "not defined" */ | uf3
+ uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+ // complex values
+ uc0 = 0.i
+ uc1 = 1.i
+ uc2 = 4.2e1i
+ uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+ uc4 = 1e-1i
+
+ uc5 = uc0 + uc1
+ uc6 = uc1 - uc1
+ uc7 = uc2 * uc1
+ uc8 = uc3 / uc3
+ uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+ uc10 = 1 / 0 /* ERROR "division by zero" */
+ uc11 = uc1 / 0 /* ERROR "division by zero" */
+ uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+ uc16 = uc2 /* ERROR "not defined" */ & uc3
+ uc17 = uc2 /* ERROR "not defined" */ | uc3
+ uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+ mybool bool
+ myint int
+ myfloat float64
+ mycomplex complex128
+)
+
+// typed constants
+const (
+ // boolean values
+ tb0 bool = false
+ tb1 bool = true
+ tb2 mybool = 2 < 1
+ tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+ // integer values
+ ti0 int8 = ui0
+ ti1 int32 = ui1
+ ti2 int64 = ui2
+ ti3 myint = ui3 /* ERROR "overflows" */
+ ti4 myint = ui4
+
+ ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+ ti6 = ti1 - ti1
+ ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+ ti8 = ti3 / ti3
+ ti9 = ti3 % ti3
+
+ ti10 = 1 / 0 /* ERROR "division by zero" */
+ ti11 = ti1 / 0 /* ERROR "division by zero" */
+ ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+ ti13 = 1 % 0 /* ERROR "division by zero" */
+ ti14 = ti1 % 0 /* ERROR "division by zero" */
+ ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+ ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+ ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+ ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+ // floating point values
+ tf0 float32 = 0.
+ tf1 float32 = 1.
+ tf2 float64 = 4.2e1
+ tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+ tf4 myfloat = 1e-1
+
+ tf5 = tf0 + tf1
+ tf6 = tf1 - tf1
+ tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+ tf8 = tf3 / tf3
+ tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+ tf10 = 1 / 0 /* ERROR "division by zero" */
+ tf11 = tf1 / 0 /* ERROR "division by zero" */
+ tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+ tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+ tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+ tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+ // complex values
+ tc0 = 0.i
+ tc1 = 1.i
+ tc2 = 4.2e1i
+ tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+ tc4 = 1e-1i
+
+ tc5 = tc0 + tc1
+ tc6 = tc1 - tc1
+ tc7 = tc2 * tc1
+ tc8 = tc3 / tc3
+ tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+ tc10 = 1 / 0 /* ERROR "division by zero" */
+ tc11 = tc1 / 0 /* ERROR "division by zero" */
+ tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+ tc16 = tc2 /* ERROR "not defined" */ & tc3
+ tc17 = tc2 /* ERROR "not defined" */ | tc3
+ tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+ a /* ERROR "initialization cycle" */ = a
+ b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+ f float64 = d
+)
+
+// multiple initialization
+const (
+ a1, a2, a3 = 7, 3.1415926, "foo"
+ b1, b2, b3 = b3, b1, 42
+ c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2
+ d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+ _p0 = assert(a1 == 7)
+ _p1 = assert(a2 == 3.1415926)
+ _p2 = assert(a3 == "foo")
+ _p3 = assert(b1 == 42)
+ _p4 = assert(b2 == 42)
+ _p5 = assert(b3 == 42)
+)
+
+func _() {
+ const (
+ a1, a2, a3 = 7, 3.1415926, "foo"
+ b1, b2, b3 = b3, b1, 42
+ c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2
+ d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+ _p0 = assert(a1 == 7)
+ _p1 = assert(a2 == 3.1415926)
+ _p2 = assert(a3 == "foo")
+ _p3 = assert(b1 == 42)
+ _p4 = assert(b2 == 42)
+ _p5 = assert(b3 == 42)
+ )
+}
+
+// iota
+const (
+ iota0 = iota
+ iota1 = iota
+ iota2 = iota*2
+ _a0 = assert(iota0 == 0)
+ _a1 = assert(iota1 == 1)
+ _a2 = assert(iota2 == 4)
+ iota6 = iota*3
+
+ iota7
+ iota8
+ _a3 = assert(iota7 == 21)
+ _a4 = assert(iota8 == 24)
+)
+
+const (
+ _b0 = iota
+ _b1 = assert(iota + iota2 == 5)
+ _b2 = len([iota]int{}) // iota may appear in a type!
+ _b3 = assert(_b2 == 2)
+ _b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands across different
+// constant declarations must use the right iota values
+const (
+ _c0 = iota
+ _c1
+ _c2
+ _x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+ _d0 = iota
+ _d1
+)
+
+const (
+ _e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+ _n0 = nil /* ERROR "not constant" */
+ _n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+ _ = iota /* ERROR "iota outside constant decl" */
+ const _ = iota
+ _ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+ iota := 123
+ const x = iota /* ERROR "is not constant" */
+ var y = iota
+ _ = y
+}
+
+// constant arithmetic precision and rounding must lead to expected (integer) results
+var _ = []int64{
+ 0.0005 * 1e9,
+ 0.001 * 1e9,
+ 0.005 * 1e9,
+ 0.01 * 1e9,
+ 0.05 * 1e9,
+ 0.1 * 1e9,
+ 0.5 * 1e9,
+ 1 * 1e9,
+ 5 * 1e9,
+}
diff --git a/libgo/go/go/types/testdata/const1.src b/libgo/go/go/types/testdata/const1.src
new file mode 100644
index 0000000000..d82770464f
--- /dev/null
+++ b/libgo/go/go/types/testdata/const1.src
@@ -0,0 +1,322 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// constant conversions
+
+package const1
+
+const(
+ mi = ^int(0)
+ mu = ^uint(0)
+ mp = ^uintptr(0)
+
+ logSizeofInt = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+ logSizeofUint = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+ logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+ minInt8 = -1<<(8<<iota - 1)
+ minInt16
+ minInt32
+ minInt64
+ minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+ maxInt8 = 1<<(8<<iota - 1) - 1
+ maxInt16
+ maxInt32
+ maxInt64
+ maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+ maxUint8 = 1<<(8<<iota) - 1
+ maxUint16
+ maxUint32
+ maxUint64
+ maxUint = 1<<(8<<logSizeofUint) - 1
+ maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+ smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+ smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+ _ = assert(smallestFloat32 > 0)
+ _ = assert(smallestFloat64 > 0)
+)
+
+const (
+ maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+ maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+ _ int8 = minInt8 /* ERROR "overflows" */ - 1
+ _ int8 = minInt8
+ _ int8 = maxInt8
+ _ int8 = maxInt8 /* ERROR "overflows" */ + 1
+ _ int8 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+ _ = int8(minInt8)
+ _ = int8(maxInt8)
+ _ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+ _ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int16 = minInt16 /* ERROR "overflows" */ - 1
+ _ int16 = minInt16
+ _ int16 = maxInt16
+ _ int16 = maxInt16 /* ERROR "overflows" */ + 1
+ _ int16 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+ _ = int16(minInt16)
+ _ = int16(maxInt16)
+ _ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+ _ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int32 = minInt32 /* ERROR "overflows" */ - 1
+ _ int32 = minInt32
+ _ int32 = maxInt32
+ _ int32 = maxInt32 /* ERROR "overflows" */ + 1
+ _ int32 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+ _ = int32(minInt32)
+ _ = int32(maxInt32)
+ _ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+ _ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int64 = minInt64 /* ERROR "overflows" */ - 1
+ _ int64 = minInt64
+ _ int64 = maxInt64
+ _ int64 = maxInt64 /* ERROR "overflows" */ + 1
+ _ int64 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+ _ = int64(minInt64)
+ _ = int64(maxInt64)
+ _ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+ _ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int = minInt /* ERROR "overflows" */ - 1
+ _ int = minInt
+ _ int = maxInt
+ _ int = maxInt /* ERROR "overflows" */ + 1
+ _ int = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int(minInt /* ERROR "cannot convert" */ - 1)
+ _ = int(minInt)
+ _ = int(maxInt)
+ _ = int(maxInt /* ERROR "cannot convert" */ + 1)
+ _ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint8 = 0 /* ERROR "overflows" */ - 1
+ _ uint8 = 0
+ _ uint8 = maxUint8
+ _ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+ _ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint8(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint8(0)
+ _ = uint8(maxUint8)
+ _ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+ _ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint16 = 0 /* ERROR "overflows" */ - 1
+ _ uint16 = 0
+ _ uint16 = maxUint16
+ _ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+ _ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint16(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint16(0)
+ _ = uint16(maxUint16)
+ _ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+ _ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint32 = 0 /* ERROR "overflows" */ - 1
+ _ uint32 = 0
+ _ uint32 = maxUint32
+ _ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+ _ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint32(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint32(0)
+ _ = uint32(maxUint32)
+ _ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+ _ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint64 = 0 /* ERROR "overflows" */ - 1
+ _ uint64 = 0
+ _ uint64 = maxUint64
+ _ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+ _ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint64(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint64(0)
+ _ = uint64(maxUint64)
+ _ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+ _ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint = 0 /* ERROR "overflows" */ - 1
+ _ uint = 0
+ _ uint = maxUint
+ _ uint = maxUint /* ERROR "overflows" */ + 1
+ _ uint = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint(0)
+ _ = uint(maxUint)
+ _ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+ _ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uintptr = 0 /* ERROR "overflows" */ - 1
+ _ uintptr = 0
+ _ uintptr = maxUintptr
+ _ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+ _ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+ _ = uintptr(0)
+ _ = uintptr(maxUintptr)
+ _ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+ _ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ float32 = minInt64
+ _ float64 = minInt64
+ _ complex64 = minInt64
+ _ complex128 = minInt64
+
+ _ = float32(minInt64)
+ _ = float64(minInt64)
+ _ = complex64(minInt64)
+ _ = complex128(minInt64)
+)
+
+const (
+ _ float32 = maxUint64
+ _ float64 = maxUint64
+ _ complex64 = maxUint64
+ _ complex128 = maxUint64
+
+ _ = float32(maxUint64)
+ _ = float64(maxUint64)
+ _ = complex64(maxUint64)
+ _ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+ _ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+ _ float32 = -maxFloat32
+ _ float32 = maxFloat32
+ _ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+ _ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+ _ = float32(-maxFloat32)
+ _ = float32(maxFloat32)
+ _ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+ _ = assert(float32(smallestFloat32) == smallestFloat32)
+ _ = assert(float32(smallestFloat32/2) == 0)
+ _ = assert(float32(smallestFloat64) == 0)
+ _ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+ _ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+ _ float64 = -maxFloat64
+ _ float64 = maxFloat64
+ _ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+ _ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+ _ = float64(-maxFloat64)
+ _ = float64(maxFloat64)
+ _ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+ _ = assert(float64(smallestFloat32) == smallestFloat32)
+ _ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+ _ = assert(float64(smallestFloat64) == smallestFloat64)
+ _ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+ _ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+ _ complex64 = -maxFloat32
+ _ complex64 = maxFloat32
+ _ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+ _ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+ _ = complex64(-maxFloat32)
+ _ = complex64(maxFloat32)
+ _ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+ _ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+ _ complex128 = -maxFloat64
+ _ complex128 = maxFloat64
+ _ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+ _ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+ _ = complex128(-maxFloat64)
+ _ = complex128(maxFloat64)
+ _ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+ f32 = 1 + smallestFloat32
+ x32 float32 = f32
+ y32 = float32(f32)
+ _ = assert(x32 - y32 == 0)
+)
+
+const (
+ f64 = 1 + smallestFloat64
+ x64 float64 = f64
+ y64 = float64(f64)
+ _ = assert(x64 - y64 == 0)
+)
+
+const (
+ _ = int8(-1) << 7
+ _ = int8 /* ERROR "overflows" */ (-1) << 8
+
+ _ = uint32(1) << 31
+ _ = uint32 /* ERROR "overflows" */ (1) << 32
+)
diff --git a/libgo/go/go/types/testdata/constdecl.src b/libgo/go/go/types/testdata/constdecl.src
new file mode 100644
index 0000000000..6de9b13d6e
--- /dev/null
+++ b/libgo/go/go/types/testdata/constdecl.src
@@ -0,0 +1,97 @@
+// 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.
+
+package constdecl
+
+import "math"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+ const _ = v /* ERROR "not constant" */
+ const _ = math /* ERROR "not constant" */ .Sin(0)
+ const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+ _ = 1
+ _
+ _, _ /* ERROR "missing init expr for _" */
+ _
+)
+
+const (
+ _, _ = 1, 2
+ _, _
+ _ /* ERROR "extra init expr at" */
+ _, _
+ _, _, _ /* ERROR "missing init expr for _" */
+ _, _
+)
+
+func _() {
+ const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+ const (
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+ )
+
+ const (
+ _ = 1
+ _
+ _, _ /* ERROR "missing init expr for _" */
+ _
+ )
+
+ const (
+ _, _ = 1, 2
+ _, _
+ _ /* ERROR "extra init expr at" */
+ _, _
+ _, _, _ /* ERROR "missing init expr for _" */
+ _, _
+ )
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+ const (
+ x string = missing /* ERROR "undeclared name" */
+ y = x + ""
+ )
+}
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/libgo/go/go/types/testdata/conversions.src b/libgo/go/go/types/testdata/conversions.src
new file mode 100644
index 0000000000..e1336c0456
--- /dev/null
+++ b/libgo/go/go/types/testdata/conversions.src
@@ -0,0 +1,93 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+ _ = int() /* ERROR "missing argument" */
+ _ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+ const A = string(65)
+ assert(A == "A")
+ const E = string(-1)
+ assert(E == "\uFFFD")
+ assert(E == string(1234567890))
+
+ type myint int
+ assert(A == string(myint(65)))
+
+ type mystring string
+ const _ mystring = mystring("foo")
+
+ const _ = string(true /* ERROR "cannot convert" */ )
+ const _ = string(1.2 /* ERROR "cannot convert" */ )
+ const _ = string(nil /* ERROR "cannot convert" */ )
+
+ // issues 11357, 11353: argument must be of integer type
+ _ = string(0.0 /* ERROR "cannot convert" */ )
+ _ = string(0i /* ERROR "cannot convert" */ )
+ _ = string(1 /* ERROR "cannot convert" */ + 2i)
+}
+
+func interface_conversions() {
+ type E interface{}
+
+ type I1 interface{
+ m1()
+ }
+
+ type I2 interface{
+ m1()
+ m2(x int)
+ }
+
+ type I3 interface{
+ m1()
+ m2() int
+ }
+
+ var e E
+ var i1 I1
+ var i2 I2
+ var i3 I3
+
+ _ = E(0)
+ _ = E(nil)
+ _ = E(e)
+ _ = E(i1)
+ _ = E(i2)
+
+ _ = I1(0 /* ERROR "cannot convert" */ )
+ _ = I1(nil)
+ _ = I1(i1)
+ _ = I1(e /* ERROR "cannot convert" */ )
+ _ = I1(i2)
+
+ _ = I2(nil)
+ _ = I2(i1 /* ERROR "cannot convert" */ )
+ _ = I2(i2)
+ _ = I2(i3 /* ERROR "cannot convert" */ )
+
+ _ = I3(nil)
+ _ = I3(i1 /* ERROR "cannot convert" */ )
+ _ = I3(i2 /* ERROR "cannot convert" */ )
+ _ = I3(i3)
+
+ // TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+ type T unsafe.Pointer
+ var x T
+ _ = uintptr(x) // see issue 6326
+}
diff --git a/libgo/go/go/types/testdata/conversions2.src b/libgo/go/go/types/testdata/conversions2.src
new file mode 100644
index 0000000000..93a5f182fb
--- /dev/null
+++ b/libgo/go/go/types/testdata/conversions2.src
@@ -0,0 +1,313 @@
+// 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 various valid and invalid struct assignments and conversions.
+// Does not compile.
+
+package conversions2
+
+type I interface {
+ m()
+}
+
+// conversions between structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s S
+ var t T
+ var u struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u
+ t = T(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t /* ERROR "cannot convert" */ )
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s S
+ var t T
+ var u struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u /* ERROR "cannot convert" */ )
+}
+
+// conversions between pointers to structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s *S
+ var t *T
+ var u *struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t /* ERROR "cannot convert" */ )
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(*struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(*struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}
diff --git a/libgo/go/go/types/testdata/cycles.src b/libgo/go/go/types/testdata/cycles.src
new file mode 100644
index 0000000000..621d83c945
--- /dev/null
+++ b/libgo/go/go/types/testdata/cycles.src
@@ -0,0 +1,143 @@
+// 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.
+
+package cycles
+
+type (
+ T0 int
+ T1 /* ERROR cycle */ T1
+ T2 *T2
+
+ T3 /* ERROR cycle */ T4
+ T4 T5
+ T5 T3
+
+ T6 T7
+ T7 *T8
+ T8 T6
+
+ // arrays
+ A0 /* ERROR cycle */ [10]A0
+ A1 [10]*A1
+
+ A2 /* ERROR cycle */ [10]A3
+ A3 [10]A4
+ A4 A2
+
+ A5 [10]A6
+ A6 *A5
+
+ // slices
+ L0 []L0
+
+ // structs
+ S0 /* ERROR cycle */ struct{ _ S0 }
+ S1 /* ERROR cycle */ struct{ S1 }
+ S2 struct{ _ *S2 }
+ S3 struct{ *S3 }
+
+ S4 /* ERROR cycle */ struct{ S5 }
+ S5 struct{ S6 }
+ S6 S4
+
+ // pointers
+ P0 *P0
+
+ // functions
+ F0 func(F0)
+ F1 func() F1
+ F2 func(F2) F2
+
+ // interfaces
+ I0 /* ERROR cycle */ interface{ I0 }
+
+ I1 interface{ I2 }
+ I2 interface{ I3 }
+ I3 /* ERROR cycle */ interface{ I1 }
+
+ I4 interface{ f(I4) }
+
+ // testcase for issue 5090
+ I5 interface{ f(I6) }
+ I6 interface{ I5 }
+
+ // maps
+ M0 map[M0 /* ERROR invalid map key */ ]M0
+
+ // channels
+ C0 chan C0
+)
+
+func _() {
+ type (
+ t1 /* ERROR cycle */ t1
+ t2 *t2
+
+ t3 t4 /* ERROR undeclared */
+ t4 t5 /* ERROR undeclared */
+ t5 t3
+
+ // arrays
+ a0 /* ERROR cycle */ [10]a0
+ a1 [10]*a1
+
+ // slices
+ l0 []l0
+
+ // structs
+ s0 /* ERROR cycle */ struct{ _ s0 }
+ s1 /* ERROR cycle */ struct{ s1 }
+ s2 struct{ _ *s2 }
+ s3 struct{ *s3 }
+
+ // pointers
+ p0 *p0
+
+ // functions
+ f0 func(f0)
+ f1 func() f1
+ f2 func(f2) f2
+
+ // interfaces
+ i0 /* ERROR cycle */ interface{ i0 }
+
+ // maps
+ m0 map[m0 /* ERROR invalid map key */ ]m0
+
+ // channels
+ c0 chan c0
+ )
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+ m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+ P1 *T9
+ T9 /* ERROR cycle */ T9
+
+ T10 /* ERROR cycle */ T10
+ P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+ P3 *T13
+ T13 /* ERROR cycle */ T13
+) \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/cycles1.src b/libgo/go/go/types/testdata/cycles1.src
new file mode 100644
index 0000000000..ae2b38ebec
--- /dev/null
+++ b/libgo/go/go/types/testdata/cycles1.src
@@ -0,0 +1,77 @@
+// 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.
+
+package p
+
+type (
+ A interface {
+ a() interface {
+ ABC1
+ }
+ }
+ B interface {
+ b() interface {
+ ABC2
+ }
+ }
+ C interface {
+ c() interface {
+ ABC3
+ }
+ }
+
+ AB interface {
+ A
+ B
+ }
+ BC interface {
+ B
+ C
+ }
+
+ ABC1 interface {
+ A
+ B
+ C
+ }
+ ABC2 interface {
+ AB
+ C
+ }
+ ABC3 interface {
+ A
+ BC
+ }
+)
+
+var (
+ x1 ABC1
+ x2 ABC2
+ x3 ABC3
+)
+
+func _() {
+ // all types have the same method set
+ x1 = x2
+ x2 = x1
+
+ x1 = x3
+ x3 = x1
+
+ x2 = x3
+ x3 = x2
+
+ // all methods return the same type again
+ x1 = x1.a()
+ x1 = x1.b()
+ x1 = x1.c()
+
+ x2 = x2.a()
+ x2 = x2.b()
+ x2 = x2.c()
+
+ x3 = x3.a()
+ x3 = x3.b()
+ x3 = x3.c()
+}
diff --git a/libgo/go/go/types/testdata/cycles2.src b/libgo/go/go/types/testdata/cycles2.src
new file mode 100644
index 0000000000..345ab56ea6
--- /dev/null
+++ b/libgo/go/go/types/testdata/cycles2.src
@@ -0,0 +1,118 @@
+// 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.
+
+package p
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+ f(u)
+}
+
+type u interface {
+ t
+}
+
+func _() {
+ var t t
+ var u u
+
+ t.f(t)
+ t.f(u)
+
+ u.f(t)
+ u.f(u)
+}
+
+
+// Test case for issue 6589.
+
+type A interface {
+ a() interface {
+ AB
+ }
+}
+
+type B interface {
+ a() interface {
+ AB
+ }
+}
+
+type AB interface {
+ a() interface {
+ A
+ B /* ERROR a redeclared */
+ }
+ b() interface {
+ A
+ B /* ERROR a redeclared */
+ }
+}
+
+var x AB
+var y interface {
+ A
+ B /* ERROR a redeclared */
+}
+var _ = x /* ERROR cannot compare */ == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+ m() [T /* ERROR no value */ (nil).m()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 interface {
+ m() [x1 /* ERROR no value */ .m()[0]]int
+}
+
+var x1 T1
+
+type T2 interface {
+ m() [len(x2 /* ERROR no value */ .m())]int
+}
+
+var x2 T2
+
+type T3 interface {
+ m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+// The test case below should also report an error for
+// the cast inside the T4 interface (like it does for the
+// variable initialization). The reason why it does not is
+// that inside T4, the method x4.m depends on T4 which is not
+// fully set up yet. The x4.m method happens to have an empty
+// signature which is why the cast is permitted.
+// TODO(gri) Consider marking methods as incomplete and provide
+// a better error message in that case.
+
+type T4 interface {
+ m() [unsafe.Sizeof(cast4(x4.m))]int
+}
+
+var x4 T4
+var _ = cast4(x4 /* ERROR cannot convert */.m)
+
+type cast4 func()
+
+// This test is symmetric to the T4 case: Here the cast is
+// "correct", but it doesn't work inside the T5 interface.
+
+type T5 interface {
+ m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
+}
+
+var x5 T5
+var _ = cast5(x5.m)
+
+type cast5 func() [0]int
diff --git a/libgo/go/go/types/testdata/cycles3.src b/libgo/go/go/types/testdata/cycles3.src
new file mode 100644
index 0000000000..3da4fb5761
--- /dev/null
+++ b/libgo/go/go/types/testdata/cycles3.src
@@ -0,0 +1,60 @@
+// 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.
+
+package p
+
+import "unsafe"
+
+var (
+ _ A = A(nil).a().b().c().d().e().f()
+ _ A = A(nil).b().c().d().e().f()
+ _ A = A(nil).c().d().e().f()
+ _ A = A(nil).d().e().f()
+ _ A = A(nil).e().f()
+ _ A = A(nil).f()
+ _ A = A(nil)
+)
+
+type (
+ A interface {
+ a() B
+ B
+ }
+
+ B interface {
+ b() C
+ C
+ }
+
+ C interface {
+ c() D
+ D
+ }
+
+ D interface {
+ d() E
+ E
+ }
+
+ E interface {
+ e() F
+ F
+ }
+
+ F interface {
+ f() A
+ }
+)
+
+type (
+ U interface {
+ V
+ }
+
+ V interface {
+ v() [unsafe.Sizeof(u)]int
+ }
+)
+
+var u U
diff --git a/libgo/go/go/types/testdata/cycles4.src b/libgo/go/go/types/testdata/cycles4.src
new file mode 100644
index 0000000000..445babca68
--- /dev/null
+++ b/libgo/go/go/types/testdata/cycles4.src
@@ -0,0 +1,110 @@
+// 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.
+
+package p
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+ m() interface {T}
+ E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+ e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+ m() interface{C}
+ E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+ m() interface{T1}
+}
+
+type T2 interface {
+ m() interface{T2}
+}
+
+func _(x T1, y T2) {
+ // Checking for assignability of interfaces must check
+ // if all methods of x are present in y, and that they
+ // have identical signatures. The signatures recur via
+ // the result type, which is an interface that embeds
+ // a single method m that refers to the very interface
+ // that contains it. This requires cycle detection in
+ // identity checks for interface types.
+ x = y
+}
+
+type T3 interface {
+ m() interface{T4}
+}
+
+type T4 interface {
+ m() interface{T3}
+}
+
+func _(x T1, y T3) {
+ x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+ T6
+}
+
+type T6 interface {
+ m() T7
+}
+type T7 interface {
+ T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+ return wrapElement()
+}
+
+func wrapElement() Element {
+ return nil
+}
+
+type EventTarget interface {
+ AddEventListener(Event)
+}
+
+type Node interface {
+ EventTarget
+}
+
+type Element interface {
+ Node
+}
+
+type Event interface {
+ Target() Element
+}
diff --git a/libgo/go/go/types/testdata/decls0.src b/libgo/go/go/types/testdata/decls0.src
new file mode 100644
index 0000000000..d4df386b13
--- /dev/null
+++ b/libgo/go/go/types/testdata/decls0.src
@@ -0,0 +1,210 @@
+// 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.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+ N undeclared /* ERROR "undeclared" */
+ B bool
+ I int32
+ A [10]P
+ T struct {
+ x, y P
+ }
+ P *T
+ R (*R)
+ F func(A) I
+ Y interface {
+ f(A) I
+ }
+ S [](((P)))
+ M map[I]F
+ C chan<- I
+
+ // blank types must be typechecked
+ _ pi /* ERROR "not a type" */
+ _ struct{}
+ _ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+ iA0 [... /* ERROR "invalid use of '...'" */ ]byte
+ // The error message below could be better. At the moment
+ // we believe an integer that is too large is not an integer.
+ // But at least we get an error.
+ iA1 [1 /* ERROR "must be integer" */ <<100]int
+ iA2 [- /* ERROR "invalid array length" */ 1]complex128
+ iA3 ["foo" /* ERROR "must be integer" */ ]string
+ iA4 [float64 /* ERROR "must be integer" */ (0)]int
+)
+
+
+type (
+ p1 pi /* ERROR "no field or method foo" */ .foo
+ p2 unsafe.Pointer
+)
+
+
+type (
+ Pi pi /* ERROR "not a type" */
+
+ a /* ERROR "illegal cycle" */ a
+ a /* ERROR "redeclared" */ int
+
+ // where the cycle error appears depends on the
+ // order in which declarations are processed
+ // (which depends on the order in which a map
+ // is iterated through)
+ b /* ERROR "illegal cycle" */ c
+ c d
+ d e
+ e b
+
+ t *t
+
+ U V
+ V *W
+ W U
+
+ P1 *S2
+ P2 P1
+
+ S0 struct {
+ }
+ S1 struct {
+ a, b, c int
+ u, v, a /* ERROR "redeclared" */ float32
+ }
+ S2 struct {
+ S0 // anonymous field
+ S0 /* ERROR "redeclared" */ int
+ }
+ S3 struct {
+ x S2
+ }
+ S4/* ERROR "illegal cycle" */ struct {
+ S4
+ }
+ S5 /* ERROR "illegal cycle" */ struct {
+ S6
+ }
+ S6 struct {
+ field S7
+ }
+ S7 struct {
+ S5
+ }
+
+ L1 []L1
+ L2 []int
+
+ A1 [10.0]int
+ A2 /* ERROR "illegal cycle" */ [10]A2
+ A3 /* ERROR "illegal cycle" */ [10]struct {
+ x A4
+ }
+ A4 [10]A3
+
+ F1 func()
+ F2 func(x, y, z float32)
+ F3 func(x, y, x /* ERROR "redeclared" */ float32)
+ F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+ F5 func(x int) (x /* ERROR "redeclared" */ float32)
+ F6 func(x ...int)
+
+ I1 interface{}
+ I2 interface {
+ m1()
+ }
+ I3 interface {
+ m1()
+ m1 /* ERROR "redeclared" */ ()
+ }
+ I4 interface {
+ m1(x, y, x /* ERROR "redeclared" */ float32)
+ m2() (x, y, x /* ERROR "redeclared" */ float32)
+ m3(x int) (x /* ERROR "redeclared" */ float32)
+ }
+ I5 interface {
+ m1(I5)
+ }
+ I6 interface {
+ S0 /* ERROR "not an interface" */
+ }
+ I7 interface {
+ I1
+ I1
+ }
+ I8 /* ERROR "illegal cycle" */ interface {
+ I8
+ }
+ I9 interface {
+ I10
+ }
+ I10 interface {
+ I11
+ }
+ I11 /* ERROR "illegal cycle" */ interface {
+ I9
+ }
+
+ C1 chan int
+ C2 <-chan int
+ C3 chan<- C3
+ C4 chan C5
+ C5 chan C6
+ C6 chan C4
+
+ M1 map[Last]string
+ M2 map[string]M2
+
+ Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issue 5217 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {}
+func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {}
+func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+ _ /* ERROR "invalid method name" */ ()
+ _ /* ERROR "invalid method name" */ (float32) int
+ m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/libgo/go/go/types/testdata/decls1.src b/libgo/go/go/types/testdata/decls1.src
new file mode 100644
index 0000000000..cb162f7aa7
--- /dev/null
+++ b/libgo/go/go/types/testdata/decls1.src
@@ -0,0 +1,144 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// variable declarations
+
+package decls1
+
+import (
+ "math"
+)
+
+// Global variables without initialization
+var (
+ a, b bool
+ c byte
+ d uint8
+ r rune
+ i int
+ j, k, l int
+ x, y float32
+ xx, yy float64
+ u, v complex64
+ uu, vv complex128
+ s, t string
+ array []byte
+ iface interface{}
+
+ blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+ s1 = i + j
+ s2 = i /* ERROR "mismatched types" */ + x
+ s3 = c + d
+ s4 = s + t
+ s5 = s /* ERROR "invalid operation" */ / t
+ s6 = array[t1]
+ s7 = array[x /* ERROR "integer" */]
+ s8 = &a
+ s10 = &42 /* ERROR "cannot take address" */
+ s11 = &v
+ s12 = -(u + *t11) / *&v
+ s13 = a /* ERROR "shifted operand" */ << d
+ s14 = i << j /* ERROR "must be unsigned" */
+ s18 = math.Pi * 10.0
+ s19 = s1 /* ERROR "cannot call" */ ()
+ s20 = f0 /* ERROR "no value" */ ()
+ s21 = f6(1, s1, i)
+ s22 = f6(1, s1, uu /* ERROR "cannot use .* in argument" */ )
+
+ t1 int = i + j
+ t2 int = i /* ERROR "mismatched types" */ + x
+ t3 int = c /* ERROR "cannot use .* variable declaration" */ + d
+ t4 string = s + t
+ t5 string = s /* ERROR "invalid operation" */ / t
+ t6 byte = array[t1]
+ t7 byte = array[x /* ERROR "must be integer" */]
+ t8 *int = & /* ERROR "cannot use .* variable declaration" */ a
+ t10 *int = &42 /* ERROR "cannot take address" */
+ t11 *complex64 = &v
+ t12 complex64 = -(u + *t11) / *&v
+ t13 int = a /* ERROR "shifted operand" */ << d
+ t14 int = i << j /* ERROR "must be unsigned" */
+ t15 math /* ERROR "not in selector" */
+ t16 math /* ERROR "not declared" */ .xxx
+ t17 math /* ERROR "not a type" */ .Pi
+ t18 float64 = math.Pi * 10.0
+ t19 int = t1 /* ERROR "cannot call" */ ()
+ t20 int = f0 /* ERROR "no value" */ ()
+ t21 int = a /* ERROR "cannot use .* variable declaration" */
+)
+
+// Various more complex expressions
+var (
+ u1 = x /* ERROR "not an interface" */ .(int)
+ u2 = iface.([]int)
+ u3 = iface.(a /* ERROR "not a type" */ )
+ u4, ok = iface.(int)
+ u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+)
+
+// Constant expression initializations
+var (
+ v1 = 1 /* ERROR "cannot convert" */ + "foo"
+ v2 = c + 255
+ v3 = c + 256 /* ERROR "overflows" */
+ v4 = r + 2147483647
+ v5 = r + 2147483648 /* ERROR "overflows" */
+ v6 = 42
+ v7 = v6 + 9223372036854775807
+ v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+ v9 = i + 1 << 10
+ v10 byte = 1024 /* ERROR "overflows" */
+ v11 = xx/yy*yy - xx
+ v12 = true && false
+ v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+ m1a, m1b = 1, 2
+ m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+ m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+ var (
+ m1a, m1b = 1, 2
+ m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+ m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+ )
+
+ _, _ = m1a, m1b
+ _, _, _ = m2a, m2b, m2c
+ _, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/libgo/go/go/types/testdata/decls2a.src b/libgo/go/go/types/testdata/decls2a.src
new file mode 100644
index 0000000000..bdbecd9dbb
--- /dev/null
+++ b/libgo/go/go/types/testdata/decls2a.src
@@ -0,0 +1,111 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+ f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+ int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+ time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+ f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+ m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "missing receiver" */ ) _() {}
+func (T3, * /* ERROR "exactly one receiver" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {}
+func (a, b /* ERROR "exactly one receiver" */ T3) _() {}
+func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/libgo/go/go/types/testdata/decls2b.src b/libgo/go/go/types/testdata/decls2b.src
new file mode 100644
index 0000000000..e7bc394762
--- /dev/null
+++ b/libgo/go/go/types/testdata/decls2b.src
@@ -0,0 +1,65 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+ f *T3
+}
+
+type T6 struct {
+ x int
+}
+
+func (t *T6) m1() int {
+ return t.x
+}
+
+func f() {
+ var t *T6
+ t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
diff --git a/libgo/go/go/types/testdata/decls3.src b/libgo/go/go/types/testdata/decls3.src
new file mode 100644
index 0000000000..80d2bc8ff8
--- /dev/null
+++ b/libgo/go/go/types/testdata/decls3.src
@@ -0,0 +1,309 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+ type (
+ T1 struct { X int }
+ T2 struct { X int }
+ T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+ )
+
+ var t T3
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+ type (
+ T1 struct { X int }
+ T2 struct { T1 }
+ T3 struct { T1 }
+ T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+ )
+
+ var t T4
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func issue4355() {
+ type (
+ T1 struct {X int}
+ T2 struct {T1}
+ T3 struct {T2}
+ T4 struct {T2}
+ T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+ )
+
+ var t T5
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+ type State int
+ type A struct{ State }
+ type B struct{ fmt.State }
+ type T struct{ A; B }
+
+ var t T
+ _ = t /* ERROR "ambiguous selector" */ .State
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+ type T0 struct{
+ int
+ float32
+ f int
+ }
+ var x T0
+ _ = x.int
+ _ = x.float32
+ _ = x.f
+
+ type T1 struct{
+ T0
+ }
+ var y T1
+ _ = y.int
+ _ = y.float32
+ _ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+ type I1 interface{}
+ type I2 interface{}
+ type P1 *int
+ type P2 *int
+ type UP unsafe.Pointer
+
+ type T1 struct {
+ I1
+ * /* ERROR "cannot be a pointer to an interface" */ I2
+ * /* ERROR "cannot be a pointer to an interface" */ error
+ P1 /* ERROR "cannot be a pointer" */
+ * /* ERROR "cannot be a pointer" */ P2
+ }
+
+ // unsafe.Pointers are treated like regular pointers when embedded
+ type T2 struct {
+ unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+ */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
+ UP /* ERROR "cannot be unsafe.Pointer" */
+ * /* ERROR "cannot be unsafe.Pointer" */ UP
+ }
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+ var s *S
+ _ = s.x
+ _ = s.m
+
+ var p P
+ _ = p.x
+ _ = p /* ERROR "no field or method" */ .m
+ _ = P /* ERROR "no field or method" */ .m
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+ d int
+}
+type D2 struct {
+ d int
+}
+
+type S0 struct {
+ A, B, C int
+ D1
+ D2
+}
+
+type S1 struct {
+ B int
+ S0
+}
+
+type S2 struct {
+ A int
+ *S1
+}
+
+type S1x struct {
+ S1
+}
+
+type S1y struct {
+ S1
+}
+
+type S3 struct {
+ S1x
+ S2
+ D, E int
+ *S1y
+}
+
+type S4 struct {
+ *S4
+ A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+ S6
+ S7
+ S8
+}
+
+type S6 struct {
+ X int
+}
+
+type S7 S6
+
+type S8 struct {
+ S9
+}
+
+type S9 struct {
+ X int
+ Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+ S11
+ S12
+ S13
+}
+
+type S11 struct {
+ S6
+}
+
+type S12 struct {
+ S6
+}
+
+type S13 struct {
+ S8
+}
+
+func _() {
+ _ = struct /* ERROR "no field or method" */ {}{}.Foo
+ _ = S0{}.A
+ _ = S0 /* ERROR "no field or method" */ {}.D
+ _ = S1{}.A
+ _ = S1{}.B
+ _ = S1{}.S0
+ _ = S1{}.C
+ _ = S2{}.A
+ _ = S2{}.S1
+ _ = S2{}.B
+ _ = S2{}.C
+ _ = S2 /* ERROR "no field or method" */ {}.D
+ _ = S3 /* ERROR "ambiguous selector" */ {}.S1
+ _ = S3{}.A
+ _ = S3 /* ERROR "ambiguous selector" */ {}.B
+ _ = S3{}.D
+ _ = S3{}.E
+ _ = S4{}.A
+ _ = S4 /* ERROR "no field or method" */ {}.B
+ _ = S5 /* ERROR "ambiguous selector" */ {}.X
+ _ = S5{}.Y
+ _ = S10 /* ERROR "ambiguous selector" */ {}.X
+ _ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+ *R1
+ *R2
+ *R3
+ *R4
+}
+
+type R1 struct {
+ *R5
+ *R6
+ *R7
+ *R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+ *R9
+ *R10
+ *R11
+ *R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+ *R13
+ *R14
+ *R15
+ *R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+ *R17
+ *R18
+ *R19
+ *R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+ *R21
+ *R22
+ *R23
+ *R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+ X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0 /* ERROR "ambiguous selector" */ {}.X \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/errors.src b/libgo/go/go/types/testdata/errors.src
new file mode 100644
index 0000000000..29fcd8fe1d
--- /dev/null
+++ b/libgo/go/go/types/testdata/errors.src
@@ -0,0 +1,55 @@
+// 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.
+
+package errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+ // no values
+ _ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+ // built-ins
+ _ = println /* ERROR "println \(built-in\) must be called" */
+
+ // types
+ _ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+ // constants
+ const c1 = 991
+ const c2 float32 = 0.5
+ 0 /* ERROR "0 \(untyped int constant\) is not used" */
+ c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+ c2 /* ERROR "c2 \(constant 0.5 of type float32\) is not used" */
+ c1 /* ERROR "c1 \+ c2 \(constant 991.5 of type float32\) is not used" */ + c2
+
+ // variables
+ x /* ERROR "x \(variable of type int\) is not used" */
+
+ // values
+ x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+ x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+ // value, ok's
+ const s = "foo"
+ m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+ 0 /* ERROR "0 .* is not used" */
+ 0 /* ERROR 0 .* is not used */
+ 0 // ERROR "0 .* is not used"
+ 0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+ if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
diff --git a/libgo/go/go/types/testdata/expr0.src b/libgo/go/go/types/testdata/expr0.src
new file mode 100644
index 0000000000..1aac726327
--- /dev/null
+++ b/libgo/go/go/types/testdata/expr0.src
@@ -0,0 +1,180 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// unary expressions
+
+package expr0
+
+type mybool bool
+
+var (
+ // bool
+ b0 = true
+ b1 bool = b0
+ b2 = !true
+ b3 = !b1
+ b4 bool = !true
+ b5 bool = !b4
+ b6 = +b0 /* ERROR "not defined" */
+ b7 = -b0 /* ERROR "not defined" */
+ b8 = ^b0 /* ERROR "not defined" */
+ b9 = *b0 /* ERROR "cannot indirect" */
+ b10 = &true /* ERROR "cannot take address" */
+ b11 = &b0
+ b12 = <-b0 /* ERROR "cannot receive" */
+ b13 = & & /* ERROR "cannot take address" */ b0
+
+ // byte
+ _ = byte(0)
+ _ = byte(- /* ERROR "cannot convert" */ 1)
+ _ = - /* ERROR "-byte\(1\) \(constant -1 of type byte\) overflows byte" */ byte(1) // test for issue 11367
+ _ = byte /* ERROR "overflows byte" */ (0) - byte(1)
+
+ // int
+ i0 = 1
+ i1 int = i0
+ i2 = +1
+ i3 = +i0
+ i4 int = +1
+ i5 int = +i4
+ i6 = -1
+ i7 = -i0
+ i8 int = -1
+ i9 int = -i4
+ i10 = !i0 /* ERROR "not defined" */
+ i11 = ^1
+ i12 = ^i0
+ i13 int = ^1
+ i14 int = ^i4
+ i15 = *i0 /* ERROR "cannot indirect" */
+ i16 = &i0
+ i17 = *i16
+ i18 = <-i16 /* ERROR "cannot receive" */
+
+ // uint
+ u0 = uint(1)
+ u1 uint = u0
+ u2 = +1
+ u3 = +u0
+ u4 uint = +1
+ u5 uint = +u4
+ u6 = -1
+ u7 = -u0
+ u8 uint = - /* ERROR "overflows" */ 1
+ u9 uint = -u4
+ u10 = !u0 /* ERROR "not defined" */
+ u11 = ^1
+ u12 = ^i0
+ u13 uint = ^ /* ERROR "overflows" */ 1
+ u14 uint = ^u4
+ u15 = *u0 /* ERROR "cannot indirect" */
+ u16 = &u0
+ u17 = *u16
+ u18 = <-u16 /* ERROR "cannot receive" */
+ u19 = ^uint(0)
+
+ // float64
+ f0 = float64(1)
+ f1 float64 = f0
+ f2 = +1
+ f3 = +f0
+ f4 float64 = +1
+ f5 float64 = +f4
+ f6 = -1
+ f7 = -f0
+ f8 float64 = -1
+ f9 float64 = -f4
+ f10 = !f0 /* ERROR "not defined" */
+ f11 = ^1
+ f12 = ^i0
+ f13 float64 = ^1
+ f14 float64 = ^f4 /* ERROR "not defined" */
+ f15 = *f0 /* ERROR "cannot indirect" */
+ f16 = &f0
+ f17 = *u16
+ f18 = <-u16 /* ERROR "cannot receive" */
+
+ // complex128
+ c0 = complex128(1)
+ c1 complex128 = c0
+ c2 = +1
+ c3 = +c0
+ c4 complex128 = +1
+ c5 complex128 = +c4
+ c6 = -1
+ c7 = -c0
+ c8 complex128 = -1
+ c9 complex128 = -c4
+ c10 = !c0 /* ERROR "not defined" */
+ c11 = ^1
+ c12 = ^i0
+ c13 complex128 = ^1
+ c14 complex128 = ^c4 /* ERROR "not defined" */
+ c15 = *c0 /* ERROR "cannot indirect" */
+ c16 = &c0
+ c17 = *u16
+ c18 = <-u16 /* ERROR "cannot receive" */
+
+ // string
+ s0 = "foo"
+ s1 = +"foo" /* ERROR "not defined" */
+ s2 = -s0 /* ERROR "not defined" */
+ s3 = !s0 /* ERROR "not defined" */
+ s4 = ^s0 /* ERROR "not defined" */
+ s5 = *s4
+ s6 = &s4
+ s7 = *s6
+ s8 = <-s7
+
+ // channel
+ ch chan int
+ rc <-chan float64
+ sc chan <- string
+ ch0 = +ch /* ERROR "not defined" */
+ ch1 = -ch /* ERROR "not defined" */
+ ch2 = !ch /* ERROR "not defined" */
+ ch3 = ^ch /* ERROR "not defined" */
+ ch4 = *ch /* ERROR "cannot indirect" */
+ ch5 = &ch
+ ch6 = *ch5
+ ch7 = <-ch
+ ch8 = <-rc
+ ch9 = <-sc /* ERROR "cannot receive" */
+ ch10, ok = <-ch
+ // ok is of type bool
+ ch11, myok = <-ch
+ _ mybool = myok /* ERROR "cannot use .* in variable declaration" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+ _ = &T{1, 2}
+ _ = &[...]int{}
+ _ = &[]int{}
+ _ = &[]int{}
+ _ = &map[string]T{}
+ _ = &(T{1, 2})
+ _ = &((((T{1, 2}))))
+ _ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+ p1 P = new(P)
+ p2 P = *p1
+ p3 P = &p2
+)
+
+func g() (a, b int) { return }
+
+func _() {
+ _ = -g /* ERROR 2-valued g */ ()
+ _ = <-g /* ERROR 2-valued g */ ()
+}
diff --git a/libgo/go/go/types/testdata/expr1.src b/libgo/go/go/types/testdata/expr1.src
new file mode 100644
index 0000000000..eaaf610b03
--- /dev/null
+++ b/libgo/go/go/types/testdata/expr1.src
@@ -0,0 +1,127 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// binary expressions
+
+package expr1
+
+type mybool bool
+
+func _(x, y bool, z mybool) {
+ x = x || y
+ x = x || true
+ x = x || false
+ x = x && y
+ x = x && true
+ x = x && false
+
+ z = z /* ERROR mismatched types */ || y
+ z = z || true
+ z = z || false
+ z = z /* ERROR mismatched types */ && y
+ z = z && true
+ z = z && false
+}
+
+type myint int
+
+func _(x, y int, z myint) {
+ x = x + 1
+ x = x + 1.0
+ x = x + 1.1 // ERROR truncated to int
+ x = x + y
+ x = x - y
+ x = x * y
+ x = x / y
+ x = x % y
+ x = x << y // ERROR must be unsigned integer
+ x = x >> y // ERROR must be unsigned integer
+
+ z = z + 1
+ z = z + 1.0
+ z = z + 1.1 // ERROR truncated to int
+ z = z /* ERROR mismatched types */ + y
+ z = z /* ERROR mismatched types */ - y
+ z = z /* ERROR mismatched types */ * y
+ z = z /* ERROR mismatched types */ / y
+ z = z /* ERROR mismatched types */ % y
+ z = z << y // ERROR must be unsigned integer
+ z = z >> y // ERROR must be unsigned integer
+}
+
+type myuint uint
+
+func _(x, y uint, z myuint) {
+ x = x + 1
+ x = x + - /* ERROR overflows uint */ 1
+ x = x + 1.0
+ x = x + 1.1 // ERROR truncated to uint
+ x = x + y
+ x = x - y
+ x = x * y
+ x = x / y
+ x = x % y
+ x = x << y
+ x = x >> y
+
+ z = z + 1
+ z = x + - /* ERROR overflows uint */ 1
+ z = z + 1.0
+ z = z + 1.1 // ERROR truncated to uint
+ z = z /* ERROR mismatched types */ + y
+ z = z /* ERROR mismatched types */ - y
+ z = z /* ERROR mismatched types */ * y
+ z = z /* ERROR mismatched types */ / y
+ z = z /* ERROR mismatched types */ % y
+ z = z << y
+ z = z >> y
+}
+
+type myfloat64 float64
+
+func _(x, y float64, z myfloat64) {
+ x = x + 1
+ x = x + -1
+ x = x + 1.0
+ x = x + 1.1
+ x = x + y
+ x = x - y
+ x = x * y
+ x = x / y
+ x = x /* ERROR not defined */ % y
+ x = x /* ERROR operand x .* must be integer */ << y
+ x = x /* ERROR operand x .* must be integer */ >> y
+
+ z = z + 1
+ z = z + -1
+ z = z + 1.0
+ z = z + 1.1
+ z = z /* ERROR mismatched types */ + y
+ z = z /* ERROR mismatched types */ - y
+ z = z /* ERROR mismatched types */ * y
+ z = z /* ERROR mismatched types */ / y
+ z = z /* ERROR mismatched types */ % y
+ z = z /* ERROR operand z .* must be integer */ << y
+ z = z /* ERROR operand z .* must be integer */ >> y
+}
+
+type mystring string
+
+func _(x, y string, z mystring) {
+ x = x + "foo"
+ x = x /* ERROR not defined */ - "foo"
+ x = x + 1 // ERROR cannot convert
+ x = x + y
+ x = x /* ERROR not defined */ - y
+ x = x * 10 // ERROR cannot convert
+}
+
+func f() (a, b int) { return }
+
+func _(x int) {
+ _ = f /* ERROR 2-valued f */ () + 1
+ _ = x + f /* ERROR 2-valued f */ ()
+ _ = f /* ERROR 2-valued f */ () + f
+ _ = f /* ERROR 2-valued f */ () + f /* ERROR 2-valued f */ ()
+}
diff --git a/libgo/go/go/types/testdata/expr2.src b/libgo/go/go/types/testdata/expr2.src
new file mode 100644
index 0000000000..31dc5f021c
--- /dev/null
+++ b/libgo/go/go/types/testdata/expr2.src
@@ -0,0 +1,247 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+ const t = true == true
+ const f = true == false
+ _ = t /* ERROR "cannot compare" */ < f
+ _ = 0 /* ERROR "cannot convert" */ == t
+ var b bool
+ var x, y float32
+ b = x < y
+ _ = b
+ _ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+ v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+ // basics
+ var a, b [10]int
+ _ = a == b
+ _ = a != b
+ _ = a /* ERROR < not defined */ < b
+ _ = a == nil /* ERROR cannot convert */
+
+ type C [10]int
+ var c C
+ _ = a == c
+
+ type D [10]int
+ var d D
+ _ = c /* ERROR mismatched types */ == d
+
+ var e [10]func() int
+ _ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+ // basics
+ var s, t struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ _ = s == t
+ _ = s != t
+ _ = s /* ERROR < not defined */ < t
+ _ = s == nil /* ERROR cannot convert */
+
+ type S struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ type T struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ var ss S
+ var tt T
+ _ = s == ss
+ _ = ss /* ERROR mismatched types */ == tt
+
+ var u struct {
+ x int
+ a [10]map[string]int
+ }
+ _ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+ // nil
+ _ = nil /* ERROR == not defined */ == nil
+ _ = nil /* ERROR != not defined */ != nil
+ _ = nil /* ERROR < not defined */ < nil
+ _ = nil /* ERROR <= not defined */ <= nil
+ _ = nil /* ERROR > not defined */ > nil
+ _ = nil /* ERROR >= not defined */ >= nil
+
+ // basics
+ var p, q *int
+ _ = p == q
+ _ = p != q
+
+ _ = p == nil
+ _ = p != nil
+ _ = nil == q
+ _ = nil != q
+
+ _ = p /* ERROR < not defined */ < q
+ _ = p /* ERROR <= not defined */ <= q
+ _ = p /* ERROR > not defined */ > q
+ _ = p /* ERROR >= not defined */ >= q
+
+ // various element types
+ type (
+ S1 struct{}
+ S2 struct{}
+ P1 *S1
+ P2 *S2
+ )
+ var (
+ ps1 *S1
+ ps2 *S2
+ p1 P1
+ p2 P2
+ )
+ _ = ps1 == ps1
+ _ = ps1 /* ERROR mismatched types */ == ps2
+ _ = ps2 /* ERROR mismatched types */ == ps1
+
+ _ = p1 == p1
+ _ = p1 /* ERROR mismatched types */ == p2
+
+ _ = p1 == ps1
+}
+
+func channels() {
+ // basics
+ var c, d chan int
+ _ = c == d
+ _ = c != d
+ _ = c == nil
+ _ = c /* ERROR < not defined */ < d
+
+ // various element types (named types)
+ type (
+ C1 chan int
+ C1r <-chan int
+ C1s chan<- int
+ C2 chan float32
+ )
+ var (
+ c1 C1
+ c1r C1r
+ c1s C1s
+ c1a chan int
+ c2 C2
+ )
+ _ = c1 == c1
+ _ = c1 /* ERROR mismatched types */ == c1r
+ _ = c1 /* ERROR mismatched types */ == c1s
+ _ = c1r /* ERROR mismatched types */ == c1s
+ _ = c1 == c1a
+ _ = c1a == c1
+ _ = c1 /* ERROR mismatched types */ == c2
+ _ = c1a /* ERROR mismatched types */ == c2
+
+ // various element types (unnamed types)
+ var (
+ d1 chan int
+ d1r <-chan int
+ d1s chan<- int
+ d1a chan<- int
+ d2 chan float32
+ )
+ _ = d1 == d1
+ _ = d1 == d1r
+ _ = d1 == d1s
+ _ = d1r /* ERROR mismatched types */ == d1s
+ _ = d1 == d1a
+ _ = d1a == d1
+ _ = d1 /* ERROR mismatched types */ == d2
+ _ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+ // basics
+ var i, j interface{ m() int }
+ _ = i == j
+ _ = i != j
+ _ = i == nil
+ _ = i /* ERROR < not defined */ < j
+
+ // various interfaces
+ var ii interface { m() int; n() }
+ var k interface { m() float32 }
+ _ = i == ii
+ _ = i /* ERROR mismatched types */ == k
+
+ // interfaces vs values
+ var s1 S1
+ var s11 S11
+ var s2 S2
+
+ _ = i == 0 /* ERROR cannot convert */
+ _ = i /* ERROR mismatched types */ == s1
+ _ = i == &s1
+ _ = i == &s11
+
+ _ = i /* ERROR mismatched types */ == s2
+ _ = i /* ERROR mismatched types */ == &s2
+}
+
+func slices() {
+ // basics
+ var s []int
+ _ = s == nil
+ _ = s != nil
+ _ = s /* ERROR < not defined */ < nil
+
+ // slices are not otherwise comparable
+ _ = s /* ERROR == not defined */ == s
+ _ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+ // basics
+ var m map[string]int
+ _ = m == nil
+ _ = m != nil
+ _ = m /* ERROR < not defined */ < nil
+
+ // maps are not otherwise comparable
+ _ = m /* ERROR == not defined */ == m
+ _ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+ // basics
+ var f func(int) float32
+ _ = f == nil
+ _ = f != nil
+ _ = f /* ERROR < not defined */ < nil
+
+ // funcs are not otherwise comparable
+ _ = f /* ERROR == not defined */ == f
+ _ = f /* ERROR < not defined */ < f
+}
diff --git a/libgo/go/go/types/testdata/expr3.src b/libgo/go/go/types/testdata/expr3.src
new file mode 100644
index 0000000000..ab1a9f684b
--- /dev/null
+++ b/libgo/go/go/types/testdata/expr3.src
@@ -0,0 +1,558 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expr3
+
+import "time"
+
+func indexes() {
+ _ = 1 /* ERROR "cannot index" */ [0]
+ _ = indexes /* ERROR "cannot index" */ [0]
+ _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+ var a [10]int
+ _ = a[true /* ERROR "cannot convert" */ ]
+ _ = a["foo" /* ERROR "cannot convert" */ ]
+ _ = a[1.1 /* ERROR "truncated" */ ]
+ _ = a[1.0]
+ _ = a[- /* ERROR "negative" */ 1]
+ _ = a[- /* ERROR "negative" */ 1 :]
+ _ = a[: - /* ERROR "negative" */ 1]
+ _ = a[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = a[0: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = a[0: /* ERROR "2nd index required" */ :10]
+ _ = a[:10:10]
+
+ var a0 int
+ a0 = a[0]
+ _ = a0
+ var a1 int32
+ a1 = a /* ERROR "cannot use .* in assignment" */ [1]
+ _ = a1
+
+ _ = a[9]
+ _ = a[10 /* ERROR "index .* out of bounds" */ ]
+ _ = a[1 /* ERROR "overflows" */ <<100]
+ _ = a[10:]
+ _ = a[:10]
+ _ = a[10:10]
+ _ = a[11 /* ERROR "index .* out of bounds" */ :]
+ _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+ _ = a[: 1 /* ERROR "overflows" */ <<100]
+ _ = a[:10:10]
+ _ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+ _ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+ _ = a[10:0:10] /* ERROR "invalid slice indices" */
+ _ = a[0:10:0] /* ERROR "invalid slice indices" */
+ _ = a[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &a /* ERROR "cannot take address" */ [:10]
+
+ pa := &a
+ _ = pa[9]
+ _ = pa[10 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[1 /* ERROR "overflows" */ <<100]
+ _ = pa[10:]
+ _ = pa[:10]
+ _ = pa[10:10]
+ _ = pa[11 /* ERROR "index .* out of bounds" */ :]
+ _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[: 1 /* ERROR "overflows" */ <<100]
+ _ = pa[:10:10]
+ _ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+ _ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[10:0:10] /* ERROR "invalid slice indices" */
+ _ = pa[0:10:0] /* ERROR "invalid slice indices" */
+ _ = pa[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &pa /* ERROR "cannot take address" */ [:10]
+
+ var b [0]int
+ _ = b[0 /* ERROR "index .* out of bounds" */ ]
+ _ = b[:]
+ _ = b[0:]
+ _ = b[:0]
+ _ = b[0:0]
+ _ = b[0:0:0]
+ _ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+ var s []int
+ _ = s[- /* ERROR "negative" */ 1]
+ _ = s[- /* ERROR "negative" */ 1 :]
+ _ = s[: - /* ERROR "negative" */ 1]
+ _ = s[0]
+ _ = s[1:2]
+ _ = s[2:1] /* ERROR "invalid slice indices" */
+ _ = s[2:]
+ _ = s[: 1 /* ERROR "overflows" */ <<100]
+ _ = s[1 /* ERROR "overflows" */ <<100 :]
+ _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+ _ = s[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = s[:10:10]
+ _ = s[10:0:10] /* ERROR "invalid slice indices" */
+ _ = s[0:10:0] /* ERROR "invalid slice indices" */
+ _ = s[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &s /* ERROR "cannot take address" */ [:10]
+
+ var m map[string]int
+ _ = m[0 /* ERROR "cannot convert" */ ]
+ _ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+ _ = m["foo"]
+ // ok is of type bool
+ type mybool bool
+ var ok mybool
+ _, ok = m["bar"]
+ _ = ok
+
+ var t string
+ _ = t[- /* ERROR "negative" */ 1]
+ _ = t[- /* ERROR "negative" */ 1 :]
+ _ = t[: - /* ERROR "negative" */ 1]
+ _ = t /* ERROR "3-index slice of string" */ [1:2:3]
+ _ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+ var t0 byte
+ t0 = t[0]
+ _ = t0
+ var t1 rune
+ t1 = t /* ERROR "cannot use .* in assignment" */ [2]
+ _ = t1
+ _ = ("foo" + "bar")[5]
+ _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+ const c = "foo"
+ _ = c[- /* ERROR "negative" */ 1]
+ _ = c[- /* ERROR "negative" */ 1 :]
+ _ = c[: - /* ERROR "negative" */ 1]
+ var c0 byte
+ c0 = c[0]
+ _ = c0
+ var c2 float32
+ c2 = c /* ERROR "cannot use .* in assignment" */ [2]
+ _ = c[3 /* ERROR "index .* out of bounds" */ ]
+ _ = ""[0 /* ERROR "index .* out of bounds" */ ]
+ _ = c2
+
+ _ = s[1<<30] // no compile-time error here
+
+ // issue 4913
+ type mystring string
+ var ss string
+ var ms mystring
+ var i, j int
+ ss = "foo"[1:2]
+ ss = "foo"[i:j]
+ ms = "foo" /* ERROR "cannot use .* in assignment" */ [1:2]
+ ms = "foo" /* ERROR "cannot use .* in assignment" */ [i:j]
+ _, _ = ss, ms
+}
+
+type T struct {
+ x int
+ y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+ _ = T /* ERROR "no field or method" */ .a
+ _ = T /* ERROR "has no method" */ .x
+ _ = T /* ERROR "not in method set" */ .m
+ _ = (*T).m
+
+ var f func(*T) = T /* ERROR "not in method set" */ .m
+ var g func(*T) = (*T).m
+ _, _ = f, g
+
+ _ = T /* ERROR "has no method" */ .y
+ _ = ( /* ERROR "has no method" */ *T).y
+}
+
+func struct_literals() {
+ type T0 struct {
+ a, b, c int
+ }
+
+ type T1 struct {
+ T0
+ a, b int
+ u float64
+ s string
+ }
+
+ // keyed elements
+ _ = T1{}
+ _ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+ _ = T1{aa /* ERROR "unknown field" */ : 0}
+ _ = T1{1 /* ERROR "invalid field name" */ : 0}
+ _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+ _ = T1{a: "foo" /* ERROR "cannot convert" */ }
+ _ = T1{c /* ERROR "unknown field" */ : 0}
+ _ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+ _ = T1{T0: T0{}}
+ _ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+ // unkeyed elements
+ _ = T0{1, 2, 3}
+ _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+ _ = T0{1, 2} /* ERROR "too few values" */
+ _ = T0{1, 2, 3, 4 /* ERROR "too many values" */ }
+ _ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4 /* ERROR "truncated" */}
+
+ // invalid type
+ type P *struct{
+ x int
+ }
+ _ = P /* ERROR "invalid composite literal type" */ {}
+
+ // unexported fields
+ _ = time.Time{}
+ _ = time.Time{sec /* ERROR "unknown field" */ : 0}
+ _ = time.Time{
+ 0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+ 0 /* ERROR implicit assignment */ ,
+ nil /* ERROR implicit assignment */ ,
+ }
+}
+
+func array_literals() {
+ type A0 [0]int
+ _ = A0{}
+ _ = A0{0 /* ERROR "index .* out of bounds" */}
+ _ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+ type A1 [10]int
+ _ = A1{}
+ _ = A1{0, 1, 2}
+ _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+ _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+ _ = A1{- /* ERROR "negative" */ 1: 0}
+ _ = A1{8: 8, 9}
+ _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+ _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ _ = A1{5: 5, 6, 7, 3: 3, 4}
+ _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+ _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+ _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+ _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+ _ = A1{2.0}
+ _ = A1{2.1 /* ERROR "truncated" */ }
+ _ = A1{"foo" /* ERROR "cannot convert" */ }
+
+ // indices must be integer constants
+ i := 1
+ const f = 2.1
+ const s = "foo"
+ _ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+ _ = A1{f /* ERROR "truncated" */ : 0}
+ _ = A1{s /* ERROR "cannot convert" */ : 0}
+
+ a0 := [...]int{}
+ assert(len(a0) == 0)
+
+ a1 := [...]int{0, 1, 2}
+ assert(len(a1) == 3)
+ var a13 [3]int
+ var a14 [4]int
+ a13 = a1
+ a14 = a1 /* ERROR "cannot use .* in assignment" */
+ _, _ = a13, a14
+
+ a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+ _ = a2
+
+ a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ assert(len(a3) == 5) // somewhat arbitrary
+
+ a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+ assert(len(a4) == 1024)
+
+ // composite literal element types may be elided
+ type T []int
+ _ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ assert(len(a6) == 8)
+
+ // recursively so
+ _ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+ // from the spec
+ type Point struct { x, y float32 }
+ _ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+ _ = [...]Point{{1.5, -3.5}, {0, 0}}
+ _ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+ _ = [][]int{{1, 2, 3}, {4, 5}}
+ _ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+ _ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+ type S0 []int
+ _ = S0{}
+ _ = S0{0, 1, 2}
+ _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+ _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ _ = S0{- /* ERROR "negative" */ 1: 0}
+ _ = S0{8: 8, 9}
+ _ = S0{8: 8, 9, 10}
+ _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ _ = S0{5: 5, 6, 7, 3: 3, 4}
+ _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+ _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+ _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+ _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+ _ = S0{2.0}
+ _ = S0{2.1 /* ERROR "truncated" */ }
+ _ = S0{"foo" /* ERROR "cannot convert" */ }
+
+ // indices must be resolved correctly
+ const index1 = 1
+ _ = S0{index1: 1}
+ _ = S0{index2: 2}
+ _ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+ // indices must be integer constants
+ i := 1
+ const f = 2.1
+ const s = "foo"
+ _ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+ _ = S0{f /* ERROR "truncated" */ : 0}
+ _ = S0{s /* ERROR "cannot convert" */ : 0}
+
+ // composite literal element types may be elided
+ type T []int
+ _ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ _ = [][]int{{1, 2, 3}, {4, 5}}
+
+ // recursively so
+ _ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+
+ // issue 17954
+ type T0 *struct { s string }
+ _ = []T0{{}}
+ _ = []T0{{"foo"}}
+
+ type T1 *struct{ int }
+ _ = []T1{}
+ _ = []T1{{0}, {1}, {2}}
+
+ type T2 T1
+ _ = []T2{}
+ _ = []T2{{0}, {1}, {2}}
+
+ _ = map[T0]T2{}
+ _ = map[T0]T2{{}: {}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+ type M0 map[string]int
+ type M1 map[bool]int
+ type M2 map[*int]int
+
+ _ = M0{}
+ _ = M0{1 /* ERROR "missing key" */ }
+ _ = M0{1 /* ERROR "cannot convert" */ : 2}
+ _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+ _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+ _ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+ _ = map[interface{}]int{int(2): 1, int16(2): 1}
+ _ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+ type S string
+
+ _ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+ _ = map[interface{}]int{"a": 1, S("a"): 1}
+ _ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+
+ type I interface {
+ f()
+ }
+
+ _ = map[I]int{N(0): 1, N(2): 1}
+ _ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+ // map keys must be resolved correctly
+ key1 := "foo"
+ _ = M0{key1: 1}
+ _ = M0{key2: 2}
+ _ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+ var value int
+ _ = M1{true: 1, false: 0}
+ _ = M2{nil: 0, &value: 1}
+
+ // composite literal element types may be elided
+ type T [2]int
+ _ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+ // recursively so
+ _ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+ // composite literal key types may be elided
+ _ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+ // recursively so
+ _ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+ // composite literal element and key types may be elided
+ _ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+ _ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+ // recursively so
+ _ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+ // from the spec
+ type Point struct { x, y float32 }
+ _ = map[string]Point{"orig": {0, 0}}
+ _ = map[*Point]string{{0, 0}: "orig"}
+
+ // issue 17954
+ type T0 *struct{ s string }
+ type T1 *struct{ int }
+ type T2 T1
+
+ _ = map[T0]T2{}
+ _ = map[T0]T2{{}: {}}
+}
+
+var key2 string = "bar"
+
+type I interface {
+ m()
+}
+
+type I2 interface {
+ m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+ var x int
+ _ = x /* ERROR "not an interface" */ .(int)
+
+ var e interface{}
+ var ok bool
+ x, ok = e.(int)
+ _ = ok
+
+ // ok value is of type bool
+ var myok mybool
+ _, myok = e.(int)
+ _ = myok
+
+ var t I
+ _ = t /* ERROR "use of .* outside type switch" */ .(type)
+ _ = t /* ERROR "missing method m" */ .(T)
+ _ = t.(*T)
+ _ = t /* ERROR "missing method m" */ .(T1)
+ _ = t /* ERROR "wrong type for method m" */ .(T2)
+ _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+ // e doesn't statically have an m, but may have one dynamically.
+ _ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+ var x int
+ var y float32
+ var s []int
+
+ f0()
+ _ = f0 /* ERROR "used as value" */ ()
+ f0(g0 /* ERROR "too many arguments" */ )
+
+ f1(0)
+ f1(x)
+ f1(10.0)
+ f1() /* ERROR "too few arguments" */
+ f1(x, y /* ERROR "too many arguments" */ )
+ f1(s /* ERROR "cannot use .* in argument" */ )
+ f1(x ... /* ERROR "cannot use ..." */ )
+ f1(g0 /* ERROR "used as value" */ ())
+ f1(g1())
+ // f1(g2()) // TODO(gri) missing position in error message
+
+ f2() /* ERROR "too few arguments" */
+ f2(3.14) /* ERROR "too few arguments" */
+ f2(3.14, "foo")
+ f2(x /* ERROR "cannot use .* in argument" */ , "foo")
+ f2(g0 /* ERROR "used as value" */ ())
+ f2(g1 /* ERROR "cannot use .* in argument" */ ()) /* ERROR "too few arguments" */
+ f2(g2())
+
+ fs() /* ERROR "too few arguments" */
+ fs(g0 /* ERROR "used as value" */ ())
+ fs(g1 /* ERROR "cannot use .* in argument" */ ())
+ fs(g2 /* ERROR "cannot use .* in argument" */ /* ERROR "too many arguments" */ ())
+ fs(gs())
+
+ fv()
+ fv(1, 2.0, x)
+ fv(s /* ERROR "cannot use .* in argument" */ )
+ fv(s...)
+ fv(x /* ERROR "cannot use" */ ...)
+ fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ fv(gs /* ERROR "cannot use .* in argument" */ ())
+ fv(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+ var t T
+ t.fm()
+ t.fm(1, 2.0, x)
+ t.fm(s /* ERROR "cannot use .* in argument" */ )
+ t.fm(g1())
+ t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ t.fm(gs /* ERROR "cannot use .* in argument" */ ())
+ t.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+ T.fm(t, )
+ T.fm(t, 1, 2.0, x)
+ T.fm(t, s /* ERROR "cannot use .* in argument" */ )
+ T.fm(t, g1())
+ T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
+ T.fm(t, gs /* ERROR "cannot use .* in argument" */ ())
+ T.fm(t, gs /* ERROR "cannot use .* in argument" */ ()...)
+
+ var i interface{ fm(x ...int) } = t
+ i.fm()
+ i.fm(1, 2.0, x)
+ i.fm(s /* ERROR "cannot use .* in argument" */ )
+ i.fm(g1())
+ i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ i.fm(gs /* ERROR "cannot use .* in argument" */ ())
+ i.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+ fi()
+ fi(1, 2.0, x, 3.14, "foo")
+ fi(g2())
+ fi(0, g2)
+ fi(0, g2 /* ERROR "2-valued g2" */ ())
+}
+
+func issue6344() {
+ type T []interface{}
+ var x T
+ fi(x...) // ... applies also to named slices
+}
diff --git a/libgo/go/go/types/testdata/gotos.src b/libgo/go/go/types/testdata/gotos.src
new file mode 100644
index 0000000000..069a94bbbf
--- /dev/null
+++ b/libgo/go/go/types/testdata/gotos.src
@@ -0,0 +1,560 @@
+// 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.
+
+// This file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+ i, n int
+ x []int
+ c chan int
+ m map[int]int
+ s string
+)
+
+// goto after declaration okay
+func _() {
+ x := 1
+ goto L
+L:
+ _ = x
+}
+
+// goto before declaration okay
+func _() {
+ goto L
+L:
+ x := 1
+ _ = x
+}
+
+// goto across declaration not okay
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+ goto L
+ {
+ x := 1
+ _ = x
+ }
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+ {
+ x := 1
+ _ = x
+ }
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+ x := 1
+ _ = x
+ goto L
+}
+
+func _() {
+L: L1:
+ x := 1
+ _ = x
+ goto L
+ goto L1
+}
+
+// error shows first offending variable
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration" */
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+ return
+L:
+}
+
+// goto into outer block okay
+func _() {
+ {
+ goto L
+ }
+L:
+}
+
+func _() {
+ {
+ goto L
+ goto L1
+ }
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+ {
+ goto L
+ }
+}
+
+func _() {
+L: L1:
+ {
+ goto L
+ goto L1
+ }
+}
+
+// goto into inner block not okay
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ {
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ goto L1 /* ERROR "goto L1 jumps into block" */
+ {
+ L: L1:
+ }
+}
+
+// goto backward into inner block still not okay
+func _() {
+ {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ {
+ L: L1:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+ goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ {
+ {
+ {
+ L:
+ }
+ }
+ }
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ x := 1
+ _ = x
+ {
+ L:
+ }
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+ if true {
+ goto L
+ }
+}
+
+func _() {
+L:
+ if true {
+ goto L
+ } else {
+ }
+}
+
+func _() {
+L:
+ if false {
+ } else {
+ goto L
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if false {
+ L:
+ } else {
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ L:
+ } else {
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+// for
+
+func _() {
+ for {
+ goto L
+ }
+L:
+}
+
+func _() {
+ for {
+ goto L
+ L:
+ }
+}
+
+func _() {
+ for {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for {
+ goto L
+ L1:
+ }
+L:
+ goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+ for i < n {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = 0; i < n; i++ {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range x {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range c {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range m {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range s {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+ switch i {
+ case 0:
+ goto L
+ }
+}
+
+func _() {
+L:
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ default:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+// select
+// different from switch. the statement has no implicit block around it.
+
+func _() {
+L:
+ select {
+ case <-c:
+ goto L
+ }
+}
+
+func _() {
+L:
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case c <- 1:
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case c <- 1:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case <-c:
+ default:
+ L:
+ }
+}
+
+func _() {
+ select {
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ case <-c:
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ L:
+ ;
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
diff --git a/libgo/go/go/types/testdata/importC.src b/libgo/go/go/types/testdata/importC.src
new file mode 100644
index 0000000000..31436be6ad
--- /dev/null
+++ b/libgo/go/go/types/testdata/importC.src
@@ -0,0 +1,10 @@
+// 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 importC
+
+import "C"
+import _ /* ERROR cannot rename import "C" */ "C"
+import foo /* ERROR cannot rename import "C" */ "C"
+import . /* ERROR cannot rename import "C" */ "C"
diff --git a/libgo/go/go/types/testdata/importdecl0a.src b/libgo/go/go/types/testdata/importdecl0a.src
new file mode 100644
index 0000000000..463dcd083d
--- /dev/null
+++ b/libgo/go/go/types/testdata/importdecl0a.src
@@ -0,0 +1,53 @@
+// 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.
+
+package importdecl0
+
+import ()
+
+import (
+ // we can have multiple blank imports (was bug)
+ _ "math"
+ _ "net/rpc"
+ init /* ERROR "cannot declare init" */ "fmt"
+ // reflect defines a type "flag" which shows up in the gc export data
+ "reflect"
+ . /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+ "math/big" /* ERROR "imported but not used" */
+ b /* ERROR "imported but not used" */ "math/big"
+ _ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect /* ERROR "not exported" */ .flag
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+ f1.Println() // use "fmt"
+}
+
+func _() {
+ _ = func() {
+ f2.Println() // use "fmt"
+ }
+}
diff --git a/libgo/go/go/types/testdata/importdecl0b.src b/libgo/go/go/types/testdata/importdecl0b.src
new file mode 100644
index 0000000000..6844e70982
--- /dev/null
+++ b/libgo/go/go/types/testdata/importdecl0b.src
@@ -0,0 +1,33 @@
+// 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.
+
+package importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt" // declares Println in file scope
+
+import (
+ // TODO(gri) At the moment, 2 errors are reported because both go/parser
+ // and the type checker report it. Eventually, this test should not be
+ // done by the parser anymore.
+ "" /* ERROR invalid import path */ /* ERROR invalid import path */
+ "a!b" /* ERROR invalid import path */ /* ERROR invalid import path */
+ "abc\xffdef" /* ERROR invalid import path */ /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+ return func() interface{} {
+ return Println // use "fmt"
+ }
+}
diff --git a/libgo/go/go/types/testdata/importdecl1a.src b/libgo/go/go/types/testdata/importdecl1a.src
new file mode 100644
index 0000000000..8301820dda
--- /dev/null
+++ b/libgo/go/go/types/testdata/importdecl1a.src
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
diff --git a/libgo/go/go/types/testdata/importdecl1b.src b/libgo/go/go/types/testdata/importdecl1b.src
new file mode 100644
index 0000000000..f24bb9ade9
--- /dev/null
+++ b/libgo/go/go/types/testdata/importdecl1b.src
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
diff --git a/libgo/go/go/types/testdata/init0.src b/libgo/go/go/types/testdata/init0.src
new file mode 100644
index 0000000000..ef0349c70f
--- /dev/null
+++ b/libgo/go/go/types/testdata/init0.src
@@ -0,0 +1,106 @@
+// 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.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+ s0 /* ERROR initialization cycle */ = s0
+
+ x0 /* ERROR initialization cycle */ = y0
+ y0 = x0
+
+ a0 = b0
+ b0 /* ERROR initialization cycle */ = c0
+ c0 = d0
+ d0 = b0
+)
+
+var (
+ s1 /* ERROR initialization cycle */ = s1
+
+ x1 /* ERROR initialization cycle */ = y1
+ y1 = x1
+
+ a1 = b1
+ b1 /* ERROR initialization cycle */ = c1
+ c1 = d1
+ d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+ s2 /* ERROR initialization cycle */ int = s2
+
+ x2 /* ERROR initialization cycle */ int = y2
+ y2 = x2
+
+ a2 = b2
+ b2 /* ERROR initialization cycle */ int = c2
+ c2 = d2
+ d2 = b2
+)
+
+var (
+ s3 /* ERROR initialization cycle */ int = s3
+
+ x3 /* ERROR initialization cycle */ int = y3
+ y3 = x3
+
+ a3 = b3
+ b3 /* ERROR initialization cycle */ int = c3
+ c3 = d3
+ d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+ f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via closures
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+ _ = func() {
+ _ = x10
+ }
+ return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/libgo/go/go/types/testdata/init1.src b/libgo/go/go/types/testdata/init1.src
new file mode 100644
index 0000000000..39ca31466b
--- /dev/null
+++ b/libgo/go/go/types/testdata/init1.src
@@ -0,0 +1,97 @@
+// 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.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+ m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+ _ = y2
+ return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+ _ = y3
+ return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+ _ = y4
+ return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+ _ = y5
+ return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+ E int
+ S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) } \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/init2.src b/libgo/go/go/types/testdata/init2.src
new file mode 100644
index 0000000000..614db6c949
--- /dev/null
+++ b/libgo/go/go/types/testdata/init2.src
@@ -0,0 +1,139 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/libgo/go/go/types/testdata/issues.src b/libgo/go/go/types/testdata/issues.src
new file mode 100644
index 0000000000..6579aa3b11
--- /dev/null
+++ b/libgo/go/go/types/testdata/issues.src
@@ -0,0 +1,188 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issues
+
+import "fmt"
+
+func issue7035() {
+ type T struct{ X int }
+ _ = func() {
+ fmt.Println() // must refer to imported fmt rather than the fmt below
+ }
+ fmt := new(T)
+ _ = fmt.X
+}
+
+func issue8066() {
+ const (
+ _ = float32(340282356779733661637539395458142568447)
+ _ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+ )
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+ x, ok := missing /* ERROR undeclared */ ()
+ _ = !ok
+ _ = x
+}
+
+func issue8799b(x int, ok bool) {
+ x, ok = missing /* ERROR undeclared */ ()
+ _ = !ok
+ _ = x
+}
+
+func issue9182() {
+ type Point C /* ERROR undeclared */ .Point
+ // no error for composite literal based on unknown type
+ _ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int) { return }
+func f1() (a []int, b int) { return }
+func f2() (a, b []int) { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+ // variadic builtin function
+ _ = append(f0())
+ _ = append(f0(), f0()...)
+ _ = append(f1())
+ _ = append(f2 /* ERROR cannot use .* in argument */ ())
+ _ = append(f2()... /* ERROR cannot use ... */ )
+ _ = append(f0(), f1 /* ERROR 2-valued f1 */ ())
+ _ = append(f0(), f2 /* ERROR 2-valued f2 */ ())
+ _ = append(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+ _ = append(f0(), f2 /* ERROR 2-valued f2 */ ()...)
+
+ // variadic user-defined function
+ append_(f0())
+ append_(f0(), f0()...)
+ append_(f1())
+ append_(f2 /* ERROR cannot use .* in argument */ ())
+ append_(f2()... /* ERROR cannot use ... */ )
+ append_(f0(), f1 /* ERROR 2-valued f1 */ ())
+ append_(f0(), f2 /* ERROR 2-valued f2 */ ())
+ append_(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+ append_(f0(), f2 /* ERROR 2-valued f2 */ ()...)
+}
+
+// Check that embedding a non-interface type in an interface results in a good error message.
+func issue10979() {
+ type _ interface {
+ int /* ERROR int is not an interface */
+ }
+ type T struct{}
+ type _ interface {
+ T /* ERROR T is not an interface */
+ }
+ type _ interface {
+ nosuchtype /* ERROR undeclared name: nosuchtype */
+ }
+ type _ interface {
+ fmt /* ERROR Nosuchtype not declared by package fmt */ .Nosuchtype
+ }
+ type _ interface {
+ nosuchpkg /* ERROR undeclared name: nosuchpkg */ .Nosuchtype
+ }
+ type I interface {
+ I /* ERROR I\.m \(value of type func\(I\)\) is not a type */ .m
+ m()
+ }
+}
+
+// issue11347
+// These should not crash.
+var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1
+var a2, b2 /* ERROR cycle */ = 0 /* ERROR mismatch */ /* ERROR mismatch */ > 0<<""[b2]
+var a3, b3 /* ERROR cycle */ = int /* ERROR mismatch */ /* ERROR mismatch */ (1<<""[b3])
+
+// issue10260
+// Check that error messages explain reason for interface assignment failures.
+type (
+ I0 interface{}
+ I1 interface{ foo() }
+ I2 interface{ foo(x int) }
+ T0 struct{}
+ T1 struct{}
+ T2 struct{}
+)
+
+func (*T1) foo() {}
+func (*T2) foo(x int) {}
+
+func issue10260() {
+ var (
+ i0 I0
+ i1 I1
+ i2 I2
+ t0 *T0
+ t1 *T1
+ t2 *T2
+ )
+ i1 = i0 /* ERROR cannot use .* missing method foo */
+ i1 = t0 /* ERROR cannot use .* missing method foo */
+ i1 = i2 /* ERROR cannot use .* wrong type for method foo */
+ i1 = t2 /* ERROR cannot use .* wrong type for method foo */
+ i2 = i1 /* ERROR cannot use .* wrong type for method foo */
+ i2 = t1 /* ERROR cannot use .* wrong type for method foo */
+
+ _ = func() I1 { return i0 /* ERROR cannot use .* missing method foo */ }
+ _ = func() I1 { return t0 /* ERROR cannot use .* missing method foo */ }
+ _ = func() I1 { return i2 /* ERROR cannot use .* wrong type for method foo */ }
+ _ = func() I1 { return t2 /* ERROR cannot use .* wrong type for method foo */ }
+ _ = func() I2 { return i1 /* ERROR cannot use .* wrong type for method foo */ }
+ _ = func() I2 { return t1 /* ERROR cannot use .* wrong type for method foo */ }
+
+ // a few more - less exhaustive now
+
+ f := func(I1, I2){}
+ f(i0 /* ERROR cannot use .* missing method foo */ , i1 /* ERROR cannot use .* wrong type for method foo */)
+
+ _ = [...]I1{i0 /* ERROR cannot use .* missing method foo */ }
+ _ = [...]I1{i2 /* ERROR cannot use .* wrong type for method foo */ }
+ _ = []I1{i0 /* ERROR cannot use .* missing method foo */ }
+ _ = []I1{i2 /* ERROR cannot use .* wrong type for method foo */ }
+ _ = map[int]I1{0: i0 /* ERROR cannot use .* missing method foo */ }
+ _ = map[int]I1{0: i2 /* ERROR cannot use .* wrong type for method foo */ }
+
+ make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */
+ make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */
+}
+
+// Check that constants representable as integers are in integer form
+// before being used in operations that are only defined on integers.
+func issue14229() {
+ // from the issue
+ const _ = int64(-1<<63) % 1e6
+
+ // related
+ const (
+ a int = 3
+ b = 4.0
+ _ = a / b
+ _ = a % b
+ _ = b / a
+ _ = 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
+}
diff --git a/libgo/go/go/types/testdata/labels.src b/libgo/go/go/types/testdata/labels.src
new file mode 100644
index 0000000000..9f42406965
--- /dev/null
+++ b/libgo/go/go/types/testdata/labels.src
@@ -0,0 +1,207 @@
+// 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.
+
+// This file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+ for {
+ }
+L2 /* ERROR "label L2 declared but not used" */ :
+ select {
+ }
+L3 /* ERROR "label L3 declared but not used" */ :
+ switch {
+ }
+L4 /* ERROR "label L4 declared but not used" */ :
+ if true {
+ }
+L5 /* ERROR "label L5 declared but not used" */ :
+ f0()
+L6:
+ f0()
+L6 /* ERROR "label L6 already declared" */ :
+ f0()
+ if x == 20 {
+ goto L6
+ }
+
+L7:
+ for {
+ break L7
+ break L8 /* ERROR "invalid break label L8" */
+ }
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+ for {
+ break L7a /* ERROR "invalid break label L7a" */
+ continue L7a /* ERROR "invalid continue label L7a" */
+ continue L7b
+ }
+
+L8:
+ for {
+ if x == 21 {
+ continue L8
+ continue L7 /* ERROR "invalid continue label L7" */
+ }
+ }
+
+L9:
+ switch {
+ case true:
+ break L9
+ defalt /* ERROR "label defalt declared but not used" */ :
+ }
+
+L10:
+ select {
+ default:
+ break L10
+ break L9 /* ERROR "invalid break label L9" */
+ }
+
+ goto L10a
+L10a: L10b:
+ select {
+ default:
+ break L10a /* ERROR "invalid break label L10a" */
+ break L10b
+ continue L10b /* ERROR "invalid continue label L10b" */
+ }
+}
+
+func f1() {
+L1:
+ for {
+ if x == 0 {
+ break L1
+ }
+ if x == 1 {
+ continue L1
+ }
+ goto L1
+ }
+
+L2:
+ select {
+ default:
+ if x == 0 {
+ break L2
+ }
+ if x == 1 {
+ continue L2 /* ERROR "invalid continue label L2" */
+ }
+ goto L2
+ }
+
+L3:
+ switch {
+ case x > 10:
+ if x == 11 {
+ break L3
+ }
+ if x == 12 {
+ continue L3 /* ERROR "invalid continue label L3" */
+ }
+ goto L3
+ }
+
+L4:
+ if true {
+ if x == 13 {
+ break L4 /* ERROR "invalid break label L4" */
+ }
+ if x == 14 {
+ continue L4 /* ERROR "invalid continue label L4" */
+ }
+ if x == 15 {
+ goto L4
+ }
+ }
+
+L5:
+ f1()
+ if x == 16 {
+ break L5 /* ERROR "invalid break label L5" */
+ }
+ if x == 17 {
+ continue L5 /* ERROR "invalid continue label L5" */
+ }
+ if x == 18 {
+ goto L5
+ }
+
+ for {
+ if x == 19 {
+ break L1 /* ERROR "invalid break label L1" */
+ }
+ if x == 20 {
+ continue L1 /* ERROR "invalid continue label L1" */
+ }
+ if x == 21 {
+ goto L1
+ }
+ }
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+ if x == 0 {
+ for {
+ continue L1 /* ERROR "invalid continue label L1" */
+ }
+ }
+}
+
+func f3() {
+L1:
+L2:
+L3:
+ for {
+ break L1 /* ERROR "invalid break label L1" */
+ break L2 /* ERROR "invalid break label L2" */
+ break L3
+ continue L1 /* ERROR "invalid continue label L1" */
+ continue L2 /* ERROR "invalid continue label L2" */
+ continue L3
+ goto L1
+ goto L2
+ goto L3
+ }
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+ goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+ for {
+ break _ /* ERROR "invalid break label _" */
+ continue _ /* ERROR "invalid continue label _" */
+ }
+}
+
+func f6() {
+_:
+ switch {
+ default:
+ break _ /* ERROR "invalid break label _" */
+ }
+}
diff --git a/libgo/go/go/types/testdata/methodsets.src b/libgo/go/go/types/testdata/methodsets.src
new file mode 100644
index 0000000000..89211468ea
--- /dev/null
+++ b/libgo/go/go/types/testdata/methodsets.src
@@ -0,0 +1,214 @@
+// 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.
+
+package methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+ v2()
+ p2()
+}
+
+type T3 struct {
+ T0
+ *T1
+ T2
+}
+
+// Method expressions
+func _() {
+ var (
+ _ func(T0) = T0.v0
+ _ = T0 /* ERROR "not in method set" */ .p0
+
+ _ func (*T0) = (*T0).v0
+ _ func (*T0) = (*T0).p0
+
+ // T1 is like T0
+
+ _ func(T2) = T2.v2
+ _ func(T2) = T2.p2
+
+ _ func(T3) = T3.v0
+ _ func(T3) = T3 /* ERROR "not in method set" */ .p0
+ _ func(T3) = T3.v1
+ _ func(T3) = T3.p1
+ _ func(T3) = T3.v2
+ _ func(T3) = T3.p2
+
+ _ func(*T3) = (*T3).v0
+ _ func(*T3) = (*T3).p0
+ _ func(*T3) = (*T3).v1
+ _ func(*T3) = (*T3).p1
+ _ func(*T3) = (*T3).v2
+ _ func(*T3) = (*T3).p2
+ )
+}
+
+// Method values with addressable receivers
+func _() {
+ var (
+ v0 T0
+ _ func() = v0.v0
+ _ func() = v0.p0
+ )
+
+ var (
+ p0 *T0
+ _ func() = p0.v0
+ _ func() = p0.p0
+ )
+
+ // T1 is like T0
+
+ var (
+ v2 T2
+ _ func() = v2.v2
+ _ func() = v2.p2
+ )
+
+ var (
+ v4 T3
+ _ func() = v4.v0
+ _ func() = v4.p0
+ _ func() = v4.v1
+ _ func() = v4.p1
+ _ func() = v4.v2
+ _ func() = v4.p2
+ )
+
+ var (
+ p4 *T3
+ _ func() = p4.v0
+ _ func() = p4.p0
+ _ func() = p4.v1
+ _ func() = p4.p1
+ _ func() = p4.v2
+ _ func() = p4.p2
+ )
+}
+
+// Method calls with addressable receivers
+func _() {
+ var v0 T0
+ v0.v0()
+ v0.p0()
+
+ var p0 *T0
+ p0.v0()
+ p0.p0()
+
+ // T1 is like T0
+
+ var v2 T2
+ v2.v2()
+ v2.p2()
+
+ var v4 T3
+ v4.v0()
+ v4.p0()
+ v4.v1()
+ v4.p1()
+ v4.v2()
+ v4.p2()
+
+ var p4 *T3
+ p4.v0()
+ p4.p0()
+ p4.v1()
+ p4.p1()
+ p4.v2()
+ p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+ var (
+ _ func() = T0{}.v0
+ _ func() = T0 /* ERROR "not in method set" */ {}.p0
+
+ _ func() = (&T0{}).v0
+ _ func() = (&T0{}).p0
+
+ // T1 is like T0
+
+ // no values for T2
+
+ _ func() = T3{}.v0
+ _ func() = T3 /* ERROR "not in method set" */ {}.p0
+ _ func() = T3{}.v1
+ _ func() = T3{}.p1
+ _ func() = T3{}.v2
+ _ func() = T3{}.p2
+
+ _ func() = (&T3{}).v0
+ _ func() = (&T3{}).p0
+ _ func() = (&T3{}).v1
+ _ func() = (&T3{}).p1
+ _ func() = (&T3{}).v2
+ _ func() = (&T3{}).p2
+ )
+}
+
+// Method calls with value receivers
+func _() {
+ T0{}.v0()
+ T0 /* ERROR "not in method set" */ {}.p0()
+
+ (&T0{}).v0()
+ (&T0{}).p0()
+
+ // T1 is like T0
+
+ // no values for T2
+
+ T3{}.v0()
+ T3 /* ERROR "not in method set" */ {}.p0()
+ T3{}.v1()
+ T3{}.p1()
+ T3{}.v2()
+ T3{}.p2()
+
+ (&T3{}).v0()
+ (&T3{}).p0()
+ (&T3{}).v1()
+ (&T3{}).p1()
+ (&T3{}).v2()
+ (&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+ var (
+ err error
+ _ = err.Error()
+ _ func() string = err.Error
+ _ func(error) string = error.Error
+
+ perr = &err
+ _ = perr /* ERROR "no field or method" */ .Error()
+ _ func() string = perr /* ERROR "no field or method" */ .Error
+ _ func(*error) string = ( /* ERROR "no field or method" */ *error).Error
+ )
+
+ type T *interface{ m() int }
+ var (
+ x T
+ _ = (*x).m()
+ _ = (*x).m
+
+ _ = x /* ERROR "no field or method" */ .m()
+ _ = x /* ERROR "no field or method" */ .m
+ _ = T /* ERROR "no field or method" */ .m
+ )
+}
diff --git a/libgo/go/go/types/testdata/shifts.src b/libgo/go/go/types/testdata/shifts.src
new file mode 100644
index 0000000000..099c9ecc7c
--- /dev/null
+++ b/libgo/go/go/types/testdata/shifts.src
@@ -0,0 +1,341 @@
+// 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.
+
+package shifts
+
+func shifts0() {
+ // basic constant shifts
+ const (
+ s = 10
+ _ = 0<<0
+ _ = 1<<s
+ _ = 1<<- /* ERROR "invalid shift" */ 1
+ _ = 1<<1075 /* ERROR "invalid shift" */
+ _ = 2.0<<1
+
+ _ int = 2<<s
+ _ float32 = 2<<s
+ _ complex64 = 2<<s
+
+ _ int = 2.0<<s
+ _ float32 = 2.0<<s
+ _ complex64 = 2.0<<s
+
+ _ int = 'a'<<s
+ _ float32 = 'a'<<s
+ _ complex64 = 'a'<<s
+ )
+}
+
+func shifts1() {
+ // basic non-constant shifts
+ var (
+ i int
+ u uint
+
+ _ = 1<<0
+ _ = 1<<i /* ERROR "must be unsigned" */
+ _ = 1<<u
+ _ = 1<<"foo" /* ERROR "cannot convert" */
+ _ = i<<0
+ _ = i<<- /* ERROR "must not be negative" */ 1
+ _ = 1 /* ERROR "overflows" */ <<100
+
+ _ uint = 1 << 0
+ _ uint = 1 << u
+ _ float32 = 1 /* ERROR "must be integer" */ << u
+ )
+}
+
+func shifts2() {
+ // from the spec
+ var (
+ s uint = 33
+ i = 1<<s // 1 has type int
+ j int32 = 1<<s // 1 has type int32; j == 0
+ k = uint64(1<<s) // 1 has type uint64; k == 1<<33
+ m int = 1.0<<s // 1.0 has type int
+ n = 1.0<<s != i // 1.0 has type int; n == false if ints are 32bits in size
+ o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
+ p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+ u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
+ u1 = 1.0 /* ERROR "must be integer" */ <<s != 0 // illegal: 1.0 has type float64, cannot shift
+ u2 = 1 /* ERROR "must be integer" */ <<s != 1.0 // illegal: 1 has type float64, cannot shift
+ v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
+ w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
+ )
+ _, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+ // random tests
+ var (
+ s uint = 11
+ u = 1 /* ERROR "must be integer" */ <<s + 1.0
+ v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+ )
+ x := 1.0 /* ERROR "must be integer" */ <<s + 1
+ shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+ _, _, _ = u, v, x
+}
+
+func shifts4() {
+ // shifts in comparisons w/ untyped operands
+ var s uint
+
+ _ = 1<<s == 1
+ _ = 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s == 1.
+
+ _ = 1<<s + 1 == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+ _ = 1 /* ERROR "integer" */ <<s + 1. == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1 == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1. == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+ _ = 1<<s == 1<<s
+ _ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+ _ = 1<<s + 1<<s == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+ _ = 1<<s + 1<<s == 1<<s + 1<<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+ // shifts in comparisons w/ typed operands
+ var s uint
+ var x int
+
+ _ = 1<<s == x
+ _ = 1.<<s == x
+ _ = 1.1 /* ERROR "int" */ <<s == x
+
+ _ = 1<<s + x == 1
+ _ = 1<<s + x == 1.
+ _ = 1<<s + x == 1.1 /* ERROR "int" */
+ _ = 1.<<s + x == 1
+ _ = 1.<<s + x == 1.
+ _ = 1.<<s + x == 1.1 /* ERROR "int" */
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1.
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+ _ = 1<<s == x<<s
+ _ = 1.<<s == x<<s
+ _ = 1.1 /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+ // shifts as operands in non-arithmetic operations and as arguments
+ var a [10]int
+ var s uint
+
+ _ = a[1<<s]
+ _ = a[1.0]
+ _ = a[1.0<<s]
+
+ _ = make([]int, 1.0)
+ _ = make([]int, 1.0<<s)
+ _ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = float32(1)
+ _ = float32(1 /* ERROR "must be integer" */ <<s)
+ _ = float32(1.0)
+ _ = float32(1.0 /* ERROR "must be integer" */ <<s)
+ _ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+ var b []int
+ _ = append(b, 1<<s)
+ _ = append(b, 1.0<<s)
+ _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = append(b, 1<<s)
+ _ = append(b, 1.0<<s) // should fail - see TODO in append code
+ _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+ _ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+ _ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+ _ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+ // TODO(gri) The delete below is not type-checked correctly yet.
+ // var m1 map[int]string
+ // delete(m1, 1<<s)
+}
+
+func shifts7() {
+ // shifts of shifts
+ var s uint
+ var x int
+ _ = x
+
+ _ = 1<<(1<<s)
+ _ = 1<<(1.<<s)
+ _ = 1. /* ERROR "integer" */ <<(1<<s)
+ _ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+ x = 1<<(1<<s)
+ x = 1<<(1.<<s)
+ x = 1.<<(1<<s)
+ x = 1.<<(1.<<s)
+
+ _ = (1<<s)<<(1<<s)
+ _ = (1<<s)<<(1.<<s)
+ _ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+ _ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+ x = (1<<s)<<(1<<s)
+ x = (1<<s)<<(1.<<s)
+ x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+ x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+ // shift examples from shift discussion: better error messages
+ var s uint
+ _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+ _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+ // additional cases
+ _ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+ _ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+ _ = int(1.<<s)
+ _ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ // TODO(gri) the error messages for these two are incorrect - disabled for now
+ // _ = complex64(1<<s)
+ // _ = complex64(1.<<s)
+ _ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+ // various originally failing snippets of code from the std library
+ // from src/compress/lzw/reader.go:90
+ {
+ var d struct {
+ bits uint32
+ width uint
+ }
+ _ = uint16(d.bits & (1<<d.width - 1))
+ }
+
+ // from src/debug/dwarf/buf.go:116
+ {
+ var ux uint64
+ var bits uint
+ x := int64(ux)
+ if x&(1<<(bits-1)) != 0 {}
+ }
+
+ // from src/encoding/asn1/asn1.go:160
+ {
+ var bytes []byte
+ if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+ }
+
+ // from src/math/big/rat.go:140
+ {
+ var exp int
+ var mantissa uint64
+ shift := uint64(-1022 - (exp - 1)) // [1..53)
+ _ = mantissa & (1<<shift - 1)
+ }
+
+ // from src/net/interface.go:51
+ {
+ type Flags uint
+ var f Flags
+ var i int
+ if f&(1<<uint(i)) != 0 {}
+ }
+
+ // from src/runtime/softfloat64.go:234
+ {
+ var gm uint64
+ var shift uint
+ _ = gm & (1<<shift - 1)
+ }
+
+ // from src/strconv/atof.go:326
+ {
+ var mant uint64
+ var mantbits uint
+ if mant == 2<<mantbits {}
+ }
+
+ // from src/route_bsd.go:82
+ {
+ var Addrs int32
+ const rtaRtMask = 1
+ var i uint
+ if Addrs&rtaRtMask&(1<<i) == 0 {}
+ }
+
+ // from src/text/scanner/scanner.go:540
+ {
+ var s struct { Whitespace uint64 }
+ var ch rune
+ for s.Whitespace&(1<<uint(ch)) != 0 {}
+ }
+}
+
+func issue5895() {
+ var x = 'a' << 1 // type of x must be rune
+ var _ rune = x
+}
+
+func issue11325() {
+ var _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */ // example from issue 11325
+ _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */
+ _ = 0 << 1.1 /* ERROR "must be unsigned integer" */
+ _ = 0 >> 1.
+ _ = 1 >> 1.1 /* ERROR "must be unsigned integer" */
+ _ = 1 >> 1.
+ _ = 1. >> 1
+ _ = 1. >> 1.
+ _ = 1.1 /* ERROR "must be integer" */ >> 1
+}
+
+func issue11594() {
+ var _ = complex64 /* ERROR "must be integer" */ (1) << 2 // example from issue 11594
+ _ = float32 /* ERROR "must be integer" */ (0) << 1
+ _ = float64 /* ERROR "must be integer" */ (0) >> 2
+ _ = complex64 /* ERROR "must be integer" */ (0) << 3
+ _ = complex64 /* ERROR "must be integer" */ (0) >> 4
+}
diff --git a/libgo/go/go/types/testdata/stmt0.src b/libgo/go/go/types/testdata/stmt0.src
new file mode 100644
index 0000000000..87f08e4314
--- /dev/null
+++ b/libgo/go/go/types/testdata/stmt0.src
@@ -0,0 +1,980 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+ var a, b, c int
+ var ch chan int
+ f0 := func() {}
+ f1 := func() int { return 1 }
+ f2 := func() (int, int) { return 1, 2 }
+ f3 := func() (int, int, int) { return 1, 2, 3 }
+
+ a, b, c = 1, 2, 3
+ a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
+ a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+ _, _, _ = a, b, c
+
+ a = f0 /* ERROR "used as value" */ ()
+ a = f1()
+ a = f2 /* ERROR "assignment count mismatch" */ ()
+ a, b = f2()
+ a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+ a, b, c = f3()
+ a, b = f3 /* ERROR "assignment count mismatch" */ ()
+
+ a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+
+ return /* ERROR "wrong number of return values" */
+ return /* ERROR "wrong number of return values" */ 1
+ return 1, 2
+ return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+ b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+ b = i /* ERROR "cannot use .* in assignment" */
+ i = f /* ERROR "cannot use .* in assignment" */
+ f = c /* ERROR "cannot use .* in assignment" */
+ c = s /* ERROR "cannot use .* in assignment" */
+ s = b /* ERROR "cannot use .* in assignment" */
+
+ v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+ _, _, _ = v0, v1, v2
+
+ b = true
+
+ i += 1
+ i += "foo" /* ERROR "cannot convert.*int" */
+
+ f -= 1
+ f /= 0
+ f = float32(0)/0 /* ERROR "division by zero" */
+ f -= "foo" /* ERROR "cannot convert.*float64" */
+
+ c *= 1
+ c /= 0
+
+ s += "bar"
+ s += 1 /* ERROR "cannot convert.*string" */
+
+ var u64 uint64
+ u64 += 1<<u64
+
+ undeclared /* ERROR "undeclared" */ = 991
+
+ // test cases for issue 5800
+ var (
+ _ int = nil /* ERROR "untyped nil value" */
+ _ [10]int = nil /* ERROR "untyped nil value" */
+ _ []byte = nil
+ _ struct{} = nil /* ERROR "untyped nil value" */
+ _ func() = nil
+ _ map[int]string = nil
+ _ chan int = nil
+ )
+
+ // test cases for issue 5500
+ _ = func() (int, bool) {
+ var m map[int]int
+ return /* ERROR "wrong number of return values" */ m[0]
+ }
+
+ g := func(int, bool){}
+ var m map[int]int
+ g(m[0]) /* ERROR "too few arguments" */
+
+ // assignments to _
+ _ = nil /* ERROR "use of untyped nil" */
+ _ = 1 /* ERROR overflow */ <<1000
+ (_) = 0
+}
+
+func assignments2() {
+ type mybool bool
+ var m map[string][]bool
+ var s []bool
+ var b bool
+ var d mybool
+ _ = s
+ _ = b
+ _ = d
+
+ // assignments to map index expressions are ok
+ s, b = m["foo"]
+ _, d = m["bar"]
+ m["foo"] = nil
+ m["foo"] = nil /* ERROR assignment count mismatch */ , false
+ _ = append(m["foo"])
+ _ = append(m["foo"], true)
+
+ var c chan int
+ _, b = <-c
+ _, d = <-c
+ <- /* ERROR cannot assign */ c = 0
+ <-c = 0 /* ERROR assignment count mismatch */ , false
+
+ var x interface{}
+ _, b = x.(int)
+ x /* ERROR cannot assign */ .(int) = 0
+ x.(int) = 0 /* ERROR assignment count mismatch */ , false
+
+ assignments2 /* ERROR used as value */ () = nil
+ int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+ type S struct{x int}
+ _ = &S /* ERROR "cannot take address" */ {}.x
+ _ = &( /* ERROR "cannot take address" */ S{}.x)
+ _ = (&S{}).x
+ S /* ERROR "cannot assign" */ {}.x = 0
+ (&S{}).x = 0
+
+ type M map[string]S
+ var m M
+ m /* ERROR "cannot assign to struct field" */ ["foo"].x = 0
+ _ = &( /* ERROR "cannot take address" */ m["foo"].x)
+ _ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+ a, a /* ERROR redeclared */ := 1, 2
+ _ = a
+ a, b, b /* ERROR redeclared */ := 1, 2, 3
+ _ = b
+ c, c /* ERROR redeclared */, b := 1, 2, 3
+ _ = c
+ a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+ const c = 0
+ type d int
+ a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */ := 1, "zwei", 3.0, 4
+ var _ int = a // a is of type int
+ var _ string = b // b is of type string
+}
+
+func incdecs() {
+ const c = 3.14
+ c /* ERROR "cannot assign" */ ++
+ s := "foo"
+ s /* ERROR "invalid operation" */ --
+ 3.14 /* ERROR "cannot assign" */ ++
+ var (
+ x int
+ y float32
+ z complex128
+ )
+ x++
+ y--
+ z++
+}
+
+func sends() {
+ var ch chan int
+ var rch <-chan int
+ var x int
+ x <- /* ERROR "cannot send" */ x
+ rch <- /* ERROR "cannot send" */ x
+ ch <- "foo" /* ERROR "cannot convert" */
+ ch <- x
+}
+
+func selects() {
+ select {}
+ var (
+ ch chan int
+ sc chan <- bool
+ )
+ select {
+ case <-ch:
+ case (<-ch):
+ case t := <-ch:
+ _ = t
+ case t := (<-ch):
+ _ = t
+ case t, ok := <-ch:
+ _, _ = t, ok
+ case t, ok := (<-ch):
+ _, _ = t, ok
+ case <-sc /* ERROR "cannot receive from send-only channel" */ :
+ }
+ select {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+ select {
+ case a, b := <-ch:
+ _, b = a, b
+ case x /* ERROR send or receive */ :
+ case a /* ERROR send or receive */ := ch:
+ }
+
+ // test for issue 9570: ch2 in second case falsely resolved to
+ // ch2 declared in body of first case
+ ch1 := make(chan int)
+ ch2 := make(chan int)
+ select {
+ case <-ch1:
+ var ch2 /* ERROR ch2 declared but not used */ chan bool
+ case i := <-ch2:
+ print(i + 1)
+ }
+}
+
+func gos() {
+ go 1 /* ERROR HERE "function must be invoked" */
+ go int /* ERROR "go requires function call, not conversion" */ (0)
+ go gos()
+ var c chan int
+ go close(c)
+ go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+ defer 1 /* ERROR HERE "function must be invoked" */
+ defer int /* ERROR "defer requires function call, not conversion" */ (0)
+ defer defers()
+ var c chan int
+ defer close(c)
+ defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+ var x, y int
+
+ break /* ERROR "break" */
+ {
+ break /* ERROR "break" */
+ }
+ if x < y {
+ break /* ERROR "break" */
+ }
+
+ switch x {
+ case 0:
+ break
+ case 1:
+ if x == y {
+ break
+ }
+ default:
+ break
+ break
+ }
+
+ var z interface{}
+ switch z.(type) {
+ case int:
+ break
+ }
+
+ for {
+ break
+ }
+
+ var a []int
+ for _ = range a {
+ break
+ }
+
+ for {
+ if x == y {
+ break
+ }
+ }
+
+ var ch chan int
+ select {
+ case <-ch:
+ break
+ }
+
+ select {
+ case <-ch:
+ if x == y {
+ break
+ }
+ default:
+ break
+ }
+}
+
+func continues() {
+ var x, y int
+
+ continue /* ERROR "continue" */
+ {
+ continue /* ERROR "continue" */
+ }
+
+ if x < y {
+ continue /* ERROR "continue" */
+ }
+
+ switch x {
+ case 0:
+ continue /* ERROR "continue" */
+ }
+
+ var z interface{}
+ switch z.(type) {
+ case int:
+ continue /* ERROR "continue" */
+ }
+
+ var ch chan int
+ select {
+ case <-ch:
+ continue /* ERROR "continue" */
+ }
+
+ for i := 0; i < 10; i++ {
+ continue
+ if x < y {
+ continue
+ break
+ }
+ switch x {
+ case y:
+ continue
+ default:
+ break
+ }
+ select {
+ case <-ch:
+ continue
+ }
+ }
+
+ var a []int
+ for _ = range a {
+ continue
+ if x < y {
+ continue
+ break
+ }
+ switch x {
+ case y:
+ continue
+ default:
+ break
+ }
+ select {
+ case <-ch:
+ continue
+ }
+ }
+}
+
+func returns0() {
+ return
+ return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+ return 0, &x
+ return /* ERROR wrong number of return values */
+ return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot use .* in return statement" */
+ return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+ return
+ return 1, "foo" /* ERROR cannot convert */
+ return /* ERROR wrong number of return values */ 1, 2, 3
+ {
+ type a int
+ return 1, 2
+ return /* ERROR a not in scope at return */
+ }
+}
+
+func returns3() (_ int) {
+ return
+ {
+ var _ int // blank (_) identifiers never shadow since they are in no scope
+ return
+ }
+}
+
+func switches0() {
+ var x int
+
+ switch x {
+ }
+
+ switch x {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+
+ switch {
+ case 1 /* ERROR "cannot convert" */ :
+ }
+
+ true := "false"
+ _ = true
+ // A tagless switch is equivalent to the bool
+ // constant true, not the identifier 'true'.
+ switch {
+ case "false" /* ERROR "cannot convert" */:
+ }
+
+ switch int32(x) {
+ case 1, 2:
+ case x /* ERROR "cannot compare" */ :
+ }
+
+ switch x {
+ case 1 /* ERROR "overflows" */ << 100:
+ }
+
+ switch x {
+ case 1:
+ case 1 /* ERROR "duplicate case" */ :
+ case ( /* ERROR "duplicate case" */ 1):
+ case 2, 3, 4:
+ case 5, 1 /* ERROR "duplicate case" */ :
+ }
+
+ switch uint64(x) {
+ case 1<<64 - 1:
+ case 1 /* ERROR duplicate case */ <<64 - 1:
+ case 2, 3, 4:
+ case 5, 1 /* ERROR duplicate case */ <<64 - 1:
+ }
+
+ var y32 float32
+ switch y32 {
+ case 1.1:
+ case 11/10: // integer division!
+ case 11. /* ERROR duplicate case */ /10:
+ case 2, 3.0, 4.1:
+ case 5.2, 1.10 /* ERROR duplicate case */ :
+ }
+
+ var y64 float64
+ switch y64 {
+ case 1.1:
+ case 11/10: // integer division!
+ case 11. /* ERROR duplicate case */ /10:
+ case 2, 3.0, 4.1:
+ case 5.2, 1.10 /* ERROR duplicate case */ :
+ }
+
+ var s string
+ switch s {
+ case "foo":
+ case "foo" /* ERROR duplicate case */ :
+ case "f" /* ERROR duplicate case */ + "oo":
+ case "abc", "def", "ghi":
+ case "jkl", "foo" /* ERROR duplicate case */ :
+ }
+
+ type T int
+ type F float64
+ type S string
+ type B bool
+ var i interface{}
+ switch i {
+ case nil:
+ case nil: // no duplicate detection
+ case (*int)(nil):
+ case (*int)(nil): // do duplicate detection
+ case 1:
+ case byte(1):
+ case int /* ERROR duplicate case */ (1):
+ case T(1):
+ case 1.0:
+ case F(1.0):
+ case F /* ERROR duplicate case */ (1.0):
+ case "hello":
+ case S("hello"):
+ case S /* ERROR duplicate case */ ("hello"):
+ case 1==1, B(false):
+ case false, B(2==2):
+ }
+
+ // switch on array
+ var a [3]int
+ switch a {
+ case [3]int{1, 2, 3}:
+ case [3]int{1, 2, 3}: // no duplicate detection
+ case [ /* ERROR "mismatched types */ 4]int{4, 5, 6}:
+ }
+
+ // switch on channel
+ var c1, c2 chan int
+ switch c1 {
+ case nil:
+ case c1:
+ case c2:
+ case c1, c2: // no duplicate detection
+ }
+}
+
+func switches1() {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+
+ var x int
+ switch x {
+ case 0:
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ break
+ case 1:
+ fallthrough
+ case 2:
+ fallthrough; ; ; // trailing empty statements are ok
+ case 3:
+ default:
+ fallthrough; ;
+ case 4:
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
+ }
+
+ var y interface{}
+ switch y.(type) {
+ case int:
+ fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ;
+ default:
+ }
+
+ switch x {
+ case 0:
+ if x == 0 {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+ }
+
+ switch x {
+ case 0:
+ goto L1
+ L1: fallthrough; ;
+ case 1:
+ goto L2
+ goto L3
+ goto L4
+ L2: L3: L4: fallthrough
+ default:
+ }
+
+ switch x {
+ case 0:
+ goto L5
+ L5: fallthrough
+ default:
+ goto L6
+ goto L7
+ goto L8
+ L6: L7: L8: fallthrough /* ERROR "cannot fallthrough final case in switch" */
+ }
+
+ switch x {
+ case 0:
+ fallthrough; ;
+ case 1:
+ {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+ case 2:
+ fallthrough
+ case 3:
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ { /* empty block is not an empty statement */ }; ;
+ default:
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
+ }
+
+ switch x {
+ case 0:
+ {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+ }
+}
+
+func switches2() {
+ // untyped nil is not permitted as switch expression
+ switch nil /* ERROR "use of untyped nil" */ {
+ case 1, 2, "foo": // don't report additional errors here
+ }
+
+ // untyped constants are converted to default types
+ switch 1<<63-1 {
+ }
+ switch 1 /* ERROR "overflows int" */ << 63 {
+ }
+ var x int
+ switch 1.0 {
+ case 1.0, 2.0, x /* ERROR "mismatched types int and float64" */ :
+ }
+ switch x {
+ case 1.0:
+ }
+
+ // untyped bools become of type bool
+ type B bool
+ var b B = true
+ switch x == x {
+ case b /* ERROR "mismatched types B and bool" */ :
+ }
+ switch {
+ case b /* ERROR "mismatched types B and bool" */ :
+ }
+}
+
+func issue11667() {
+ switch 9223372036854775808 /* ERROR "overflows int" */ {
+ }
+ switch 9223372036854775808 /* ERROR "overflows int" */ {
+ case 9223372036854775808:
+ }
+ var x int
+ switch x {
+ case 9223372036854775808 /* ERROR "overflows int" */ :
+ }
+ var y float64
+ switch y {
+ case 9223372036854775808:
+ }
+}
+
+func issue11687() {
+ f := func() (_, _ int) { return }
+ switch f /* ERROR "2-valued f" */ () {
+ }
+ var x int
+ switch f /* ERROR "2-valued f" */ () {
+ case x:
+ }
+ switch x {
+ case f /* ERROR "2-valued f" */ ():
+ }
+}
+
+type I interface {
+ m()
+}
+
+type I2 interface {
+ m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+ var i int
+ var x interface{}
+
+ switch x.(type) {}
+ switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+ switch x.(type) {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+
+ switch x /* ERROR "declared but not used" */ := x.(type) {}
+ switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+ switch x := x.(type) {
+ case int:
+ var y int = x
+ _ = y
+ }
+
+ switch x := i /* ERROR "not an interface" */ .(type) {}
+
+ switch t := x.(type) {
+ case nil:
+ var v bool = t /* ERROR "cannot use .* in variable declaration" */
+ _ = v
+ case int:
+ var v int = t
+ _ = v
+ case float32, complex64:
+ var v float32 = t /* ERROR "cannot use .* in variable declaration" */
+ _ = v
+ default:
+ var v float32 = t /* ERROR "cannot use .* in variable declaration" */
+ _ = v
+ }
+
+ var t I
+ switch t.(type) {
+ case T:
+ case T1 /* ERROR "missing method m" */ :
+ case T2 /* ERROR "wrong type for method m" */ :
+ case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+ }
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+ switch y := interface{}(nil).(type) {
+ case int:
+ func() int { return y + 0 }()
+ case float32:
+ func() float32 { return y }()
+ }
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+ var t I
+ switch t := t; t := t.(type) {
+ case nil:
+ var _ I = t
+ case T:
+ var _ T = t
+ default:
+ var _ I = t
+ }
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+ switch A(nil).(type) {
+ case A:
+ case B:
+ case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+ }
+}
+
+func typeswitch3(x interface{}) {
+ switch x.(type) {
+ case int:
+ case float64:
+ case int /* ERROR duplicate case */ :
+ }
+
+ switch x.(type) {
+ case nil:
+ case int:
+ case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+ }
+
+ type F func(int)
+ switch x.(type) {
+ case nil:
+ case int, func(int):
+ case float32, func /* ERROR duplicate case */ (x int):
+ case F:
+ }
+}
+
+func fors1() {
+ for {}
+ var i string
+ _ = i
+ for i := 0; i < 10; i++ {}
+ for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+ var (
+ x int
+ a [10]float32
+ b []string
+ p *[10]complex128
+ pp **[10]complex128
+ s string
+ m map[int]bool
+ c chan int
+ sc chan<- int
+ rc <-chan int
+ )
+
+ for range x /* ERROR "cannot range over" */ {}
+ for _ = range x /* ERROR "cannot range over" */ {}
+ for i := range x /* ERROR "cannot range over" */ {}
+
+ for range a {}
+ for i := range a {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range a {
+ var ii int
+ ii = i
+ _ = ii
+ var xx float64
+ xx = x /* ERROR "cannot use .* in assignment" */
+ _ = xx
+ }
+ var ii int
+ var xx float32
+ for ii, xx = range a {}
+ _, _ = ii, xx
+
+ for range b {}
+ for i := range b {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range b {
+ var ii int
+ ii = i
+ _ = ii
+ var xx string
+ xx = x
+ _ = xx
+ }
+
+ for range s {}
+ for i := range s {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range s {
+ var ii int
+ ii = i
+ _ = ii
+ var xx rune
+ xx = x
+ _ = xx
+ }
+
+ for range p {}
+ for _, x := range p {
+ var xx complex128
+ xx = x
+ _ = xx
+ }
+
+ for range pp /* ERROR "cannot range over" */ {}
+ for _, x := range pp /* ERROR "cannot range over" */ {}
+
+ for range m {}
+ for k := range m {
+ var kk int32
+ kk = k /* ERROR "cannot use .* in assignment" */
+ _ = kk
+ }
+ for k, v := range m {
+ var kk int
+ kk = k
+ _ = kk
+ if v {}
+ }
+
+ for range c {}
+ for _, _ /* ERROR "only one iteration variable" */ = range c {}
+ for e := range c {
+ var ee int
+ ee = e
+ _ = ee
+ }
+ for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
+ for _ = range rc {}
+
+ // constant strings
+ const cs = "foo"
+ for range cs {}
+ for range "" {}
+ for i, x := range cs { _, _ = i, x }
+ for i, x := range "" {
+ var ii int
+ ii = i
+ _ = ii
+ var xx rune
+ xx = x
+ _ = xx
+ }
+}
+
+func rangeloops2() {
+ type I int
+ type R rune
+
+ var a [10]int
+ var i I
+ _ = i
+ for i /* ERROR cannot use .* in assignment */ = range a {}
+ for i /* ERROR cannot use .* in assignment */ = range &a {}
+ for i /* ERROR cannot use .* in assignment */ = range a[:] {}
+
+ var s string
+ var r R
+ _ = r
+ for i /* ERROR cannot use .* in assignment */ = range s {}
+ for i /* ERROR cannot use .* in assignment */ = range "foo" {}
+ for _, r /* ERROR cannot use .* in assignment */ = range s {}
+ for _, r /* ERROR cannot use .* in assignment */ = range "foo" {}
+}
+
+func issue6766b() {
+ for _ := /* ERROR no new variables */ range "" {}
+ for a, a /* ERROR redeclared */ := range "" { _ = a }
+ var a int
+ _ = a
+ for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+ for y /* ERROR declared but not used */ := range "" {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+ for range 1 /* ERROR cannot range over 1 */ {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+ for y := range 1 /* ERROR cannot range over 1 */ {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+}
+
+func labels0() {
+ goto L0
+ goto L1
+ L0:
+ L1:
+ L1 /* ERROR "already declared" */ :
+ if true {
+ goto L2
+ L2:
+ L0 /* ERROR "already declared" */ :
+ }
+ _ = func() {
+ goto L0
+ goto L1
+ goto L2
+ L0:
+ L1:
+ L2:
+ }
+}
+
+func expression_statements(ch chan int) {
+ expression_statements(ch)
+ <-ch
+ println()
+
+ 0 /* ERROR "not used" */
+ 1 /* ERROR "not used" */ +2
+ cap /* ERROR "not used" */ (ch)
+ println /* ERROR "must be called" */
+}
diff --git a/libgo/go/go/types/testdata/stmt1.src b/libgo/go/go/types/testdata/stmt1.src
new file mode 100644
index 0000000000..24ad6ebdf1
--- /dev/null
+++ b/libgo/go/go/types/testdata/stmt1.src
@@ -0,0 +1,241 @@
+// 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.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+ {
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+ {
+ return; ; ; // trailing empty statements are ok
+ }
+ ; ; ;
+}
+
+func _(x, y int) (z int) {
+ {
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ {
+ ; ; ;
+ }
+ ; ; ;
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+ if x < y { return }
+ return 1
+}
+
+func _(x, y int) (z int) {
+ if x < y { return; ; ; ; }
+ return 1
+}
+
+func _(x, y int) (z int) {
+ if x < y { return }
+ return 1; ;
+}
+
+func _(x, y int) (z int) {
+ if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ if x < y {
+ } else { return 1
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ if x < y { return
+ } else { return
+ }
+}
+
+// for statements
+func _(x, y int) (z int) {
+ for x < y {
+ return
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ for {
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+ for {
+ return; ; ; ;
+ }
+}
+
+func _(x, y int) (z int) {
+ for {
+ return
+ break
+ }
+ ; ; ;
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ for {
+ for { break }
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+ for {
+ for { break }
+ return ; ;
+ }
+ ;
+}
+
+func _(x, y int) (z int) {
+L: for {
+ for { break L }
+ return
+ }
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ default: return
+ }
+}
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return;
+ default: return; ; ;
+ }
+}
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ case 1: break
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ default:
+ switch y {
+ case 0: break
+ }
+ panic(0)
+ }
+}
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ default:
+ switch y {
+ case 0: break
+ }
+ panic(0); ; ;
+ }
+ ;
+}
+
+func _(x, y int) (z int) {
+L: switch x {
+ case 0: return
+ default:
+ switch y {
+ case 0: break L
+ }
+ panic(0)
+ }
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+ select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+ select {}
+ ; ;
+}
+
+func _(ch chan int) (z int) {
+ select {
+ default: break
+ }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+ select {
+ case <-ch: return
+ default: break
+ }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+ select {
+ case <-ch: return
+ default:
+ for i := 0; i < 10; i++ {
+ break
+ }
+ return
+ }
+}
+
+func _(ch chan int) (z int) {
+ select {
+ case <-ch: return; ; ;
+ default:
+ for i := 0; i < 10; i++ {
+ break
+ }
+ return; ; ;
+ }
+ ; ; ;
+}
+
+func _(ch chan int) (z int) {
+L: select {
+ case <-ch: return
+ default:
+ for i := 0; i < 10; i++ {
+ break L
+ }
+ return
+ }
+ ; ; ;
+} /* ERROR "missing return" */
diff --git a/libgo/go/go/types/testdata/vardecl.src b/libgo/go/go/types/testdata/vardecl.src
new file mode 100644
index 0000000000..00825371f2
--- /dev/null
+++ b/libgo/go/go/types/testdata/vardecl.src
@@ -0,0 +1,186 @@
+// 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.
+
+package vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued g" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+ _, _ = 1, 2
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+ _, _ = 1 /* ERROR "assignment count mismatch" */
+ _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+ _ = g /* ERROR "2-valued g" */ ()
+ _, _ = g()
+ _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+ _ = m["foo"]
+ _, _ = m["foo"]
+ _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+ _, _ int = 1, 2
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+ _, _ int = 1 /* ERROR "assignment count mismatch" */
+ _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+ var x1 /* ERROR "declared but not used" */ int
+ var x2 /* ERROR "declared but not used" */ int
+ x1 = 1
+ (x2) = 2
+
+ y1 /* ERROR "declared but not used" */ := 1
+ y2 /* ERROR "declared but not used" */ := 2
+ y1 = 1
+ (y1) = 2
+
+ {
+ var x1 /* ERROR "declared but not used" */ int
+ var x2 /* ERROR "declared but not used" */ int
+ x1 = 1
+ (x2) = 2
+
+ y1 /* ERROR "declared but not used" */ := 1
+ y2 /* ERROR "declared but not used" */ := 2
+ y1 = 1
+ (y1) = 2
+ }
+
+ if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+ switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+ case 0:
+ _ = y
+ case 1:
+ x /* ERROR "declared but not used" */ := 0
+ }
+
+ var t interface{}
+ switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+ switch t /* ERROR "declared but not used" */ := t.(type) {
+ case int:
+ }
+
+ switch t /* ERROR "declared but not used" */ := t.(type) {
+ case int:
+ case float32, complex64:
+ t = nil
+ }
+
+ switch t := t.(type) {
+ case int:
+ case float32, complex64:
+ _ = t
+ }
+
+ switch t := t.(type) {
+ case int:
+ case float32:
+ case string:
+ _ = func() string {
+ return t
+ }
+ }
+
+ switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+ var z1 /* ERROR "declared but not used" */ int
+ var z2 int
+ _ = func(a, b, c int) (u, v, w int) {
+ z1 = a
+ (z1) = b
+ a = z2
+ return
+ }
+
+ var s []int
+ var i /* ERROR "declared but not used" */ , j int
+ for i, j = range s {
+ _ = j
+ }
+
+ for i, j /* ERROR "declared but not used" */ := range s {
+ _ = func() int {
+ return i
+ }
+ }
+ return
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
+func _() {
+ var a, b, c int
+ var x, y int
+ x, y = a /* ERROR assignment count mismatch */ , b, c
+ _ = x
+ _ = y
+}
+
+func _() {
+ var x int
+ return x /* ERROR no result values expected */
+ return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+ var x, y int
+ return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+ _ := /* ERROR no new variables */ 0
+ _, a := 0, 1
+ _, a := /* ERROR no new variables */ 0, 1
+ _, a, b := 0, 1, 2
+ _, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+ _ = a
+ _ = b
+}
+
+// TODO(gri) consolidate other var decl checks in this file \ No newline at end of file
diff --git a/libgo/go/go/types/type.go b/libgo/go/go/types/type.go
index d8415f1fdf..01adee8a3e 100644
--- a/libgo/go/go/types/type.go
+++ b/libgo/go/go/types/type.go
@@ -4,10 +4,7 @@
package types
-import (
- "sort"
- "sync"
-)
+import "sort"
// A Type represents a type of Go.
// All types implement the Type interface.
@@ -121,10 +118,8 @@ func (s *Slice) Elem() Type { return s.elem }
// A Struct represents a struct type.
type Struct struct {
- fields []*Var
- tags []string // field tags; nil if there are no tags
- offsets []int64 // field offsets in bytes, lazily initialized
- offsetsOnce sync.Once // for threadsafe lazy initialization of offsets
+ fields []*Var
+ tags []string // field tags; nil if there are no tags
}
// NewStruct returns a new struct with the given fields and corresponding field tags.
@@ -229,7 +224,7 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
// function.
//
// For an abstract method, Recv returns the enclosing interface either
-// as a *Named or an *Interface. Due to embedding, an interface may
+// as a *Named or an *Interface. Due to embedding, an interface may
// contain methods whose receiver type is a different interface.
func (s *Signature) Recv() *Var { return s.recv }
diff --git a/libgo/go/go/types/typexpr.go b/libgo/go/go/types/typexpr.go
index 931b924712..ecc0a7da02 100644
--- a/libgo/go/go/types/typexpr.go
+++ b/libgo/go/go/types/typexpr.go
@@ -45,6 +45,17 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
delete(check.unusedDotImports[scope], pkg)
}
+ // Alias-related code. Keep for now.
+ // An alias stands for the original object; use that one instead.
+ // TODO(gri) We should be able to factor out the Typ[Invalid] test.
+ // if alias, _ := obj.(*Alias); alias != nil {
+ // obj = original(obj)
+ // if obj == nil || typ == Typ[Invalid] {
+ // return
+ // }
+ // assert(typ == obj.Type())
+ // }
+
switch obj := obj.(type) {
case *PkgName:
check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
@@ -623,8 +634,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
// current field typ and tag
var typ Type
var tag string
- // anonymous != nil indicates an anonymous field.
- add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+ add := func(field *ast.Field, ident *ast.Ident, anonymous bool, pos token.Pos) {
if tag != "" && tags == nil {
tags = make([]string, len(fields))
}
@@ -633,15 +643,12 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
}
name := ident.Name
- fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+ fld := NewField(pos, check.pkg, name, typ, anonymous)
// spec: "Within a struct, non-blank field names must be unique."
if name == "_" || check.declareInSet(&fset, pos, fld) {
fields = append(fields, fld)
check.recordDef(ident, fld)
}
- if anonymous != nil {
- check.recordUse(ident, anonymous)
- }
}
for _, f := range list.List {
@@ -650,7 +657,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
if len(f.Names) > 0 {
// named fields
for _, name := range f.Names {
- add(f, name, nil, name.Pos())
+ add(f, name, false, name.Pos())
}
} else {
// anonymous field
@@ -668,7 +675,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
continue
}
- add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+ add(f, name, true, pos)
case *Named:
// spec: "An embedded type must be specified as a type name
@@ -690,7 +697,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
continue
}
}
- add(f, name, t.obj, pos)
+ add(f, name, true, pos)
default:
check.invalidAST(pos, "anonymous field type %s must be named", typ)
diff --git a/libgo/go/go/types/universe.go b/libgo/go/go/types/universe.go
index 40185c1ad4..cc3bd5a370 100644
--- a/libgo/go/go/types/universe.go
+++ b/libgo/go/go/types/universe.go
@@ -196,7 +196,7 @@ func init() {
//
func def(obj Object) {
name := obj.Name()
- if strings.Index(name, " ") >= 0 {
+ if strings.Contains(name, " ") {
return // nothing to do
}
// fix Obj link for named types
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
new file mode 100644
index 0000000000..eb6739a109
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539.
+package chacha20poly1305
+
+import (
+ "crypto/cipher"
+ "errors"
+)
+
+const (
+ // KeySize is the size of the key used by this AEAD, in bytes.
+ KeySize = 32
+ // NonceSize is the size of the nonce used with this AEAD, in bytes.
+ NonceSize = 12
+)
+
+type chacha20poly1305 struct {
+ key [32]byte
+}
+
+// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key.
+func New(key []byte) (cipher.AEAD, error) {
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20poly1305: bad key length")
+ }
+ ret := new(chacha20poly1305)
+ copy(ret.key[:], key)
+ return ret, nil
+}
+
+func (c *chacha20poly1305) NonceSize() int {
+ return NonceSize
+}
+
+func (c *chacha20poly1305) Overhead() int {
+ return 16
+}
+
+func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Seal")
+ }
+
+ if uint64(len(plaintext)) > (1<<38)-64 {
+ panic("chacha20poly1305: plaintext too large")
+ }
+
+ return c.seal(dst, nonce, plaintext, additionalData)
+}
+
+var errOpen = errors.New("chacha20poly1305: message authentication failed")
+
+func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Open")
+ }
+ if len(ciphertext) < 16 {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > (1<<38)-48 {
+ panic("chacha20poly1305: ciphertext too large")
+ }
+
+ return c.open(dst, nonce, ciphertext, additionalData)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
new file mode 100644
index 0000000000..4755033212
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
@@ -0,0 +1,80 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+package chacha20poly1305
+
+import "encoding/binary"
+
+//go:noescape
+func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
+
+//go:noescape
+func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
+
+//go:noescape
+func haveSSSE3() bool
+
+var canUseASM bool
+
+func init() {
+ canUseASM = haveSSSE3()
+}
+
+// setupState writes a ChaCha20 input matrix to state. See
+// https://tools.ietf.org/html/rfc7539#section-2.3.
+func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
+ state[0] = 0x61707865
+ state[1] = 0x3320646e
+ state[2] = 0x79622d32
+ state[3] = 0x6b206574
+
+ state[4] = binary.LittleEndian.Uint32(key[:4])
+ state[5] = binary.LittleEndian.Uint32(key[4:8])
+ state[6] = binary.LittleEndian.Uint32(key[8:12])
+ state[7] = binary.LittleEndian.Uint32(key[12:16])
+ state[8] = binary.LittleEndian.Uint32(key[16:20])
+ state[9] = binary.LittleEndian.Uint32(key[20:24])
+ state[10] = binary.LittleEndian.Uint32(key[24:28])
+ state[11] = binary.LittleEndian.Uint32(key[28:32])
+
+ state[12] = 0
+ state[13] = binary.LittleEndian.Uint32(nonce[:4])
+ state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+ state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+}
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if !canUseASM {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+16)
+ chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
+ return ret
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if !canUseASM {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ciphertext = ciphertext[:len(ciphertext)-16]
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ return ret, nil
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
new file mode 100644
index 0000000000..b9a55ea046
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
@@ -0,0 +1,70 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+ "encoding/binary"
+
+ "golang_org/x/crypto/chacha20poly1305/internal/chacha20"
+ "golang_org/x/crypto/poly1305"
+)
+
+func roundTo16(n int) int {
+ return 16 * ((n + 15) / 16)
+}
+
+func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
+ var counter [16]byte
+ copy(counter[4:], nonce)
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
+ counter[0] = 1
+ chacha20.XORKeyStream(out, plaintext, &counter, &c.key)
+
+ polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
+ copy(polyInput, additionalData)
+ copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
+
+ var tag [poly1305.TagSize]byte
+ poly1305.Sum(&tag, polyInput, &polyKey)
+ copy(out[len(plaintext):], tag[:])
+
+ return ret
+}
+
+func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ var tag [poly1305.TagSize]byte
+ copy(tag[:], ciphertext[len(ciphertext)-16:])
+ ciphertext = ciphertext[:len(ciphertext)-16]
+
+ var counter [16]byte
+ copy(counter[4:], nonce)
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
+
+ polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
+ copy(polyInput, additionalData)
+ copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if !poly1305.Verify(&tag, polyInput, &polyKey) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ counter[0] = 1
+ chacha20.XORKeyStream(out, ciphertext, &counter, &c.key)
+ return ret, nil
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
new file mode 100644
index 0000000000..4c2eb703c3
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 !go1.7 gccgo appengine
+
+package chacha20poly1305
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
new file mode 100644
index 0000000000..78f981a74f
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
@@ -0,0 +1,182 @@
+// 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 chacha20poly1305
+
+import (
+ "bytes"
+ cr "crypto/rand"
+ "encoding/hex"
+ mr "math/rand"
+ "testing"
+)
+
+func TestVectors(t *testing.T) {
+ for i, test := range chacha20Poly1305Tests {
+ key, _ := hex.DecodeString(test.key)
+ nonce, _ := hex.DecodeString(test.nonce)
+ ad, _ := hex.DecodeString(test.aad)
+ plaintext, _ := hex.DecodeString(test.plaintext)
+
+ aead, err := New(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ct := aead.Seal(nil, nonce, plaintext, ad)
+ if ctHex := hex.EncodeToString(ct); ctHex != test.out {
+ t.Errorf("#%d: got %s, want %s", i, ctHex, test.out)
+ continue
+ }
+
+ plaintext2, err := aead.Open(nil, nonce, ct, ad)
+ if err != nil {
+ t.Errorf("#%d: Open failed", i)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, plaintext2) {
+ t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+ continue
+ }
+
+ if len(ad) > 0 {
+ alterAdIdx := mr.Intn(len(ad))
+ ad[alterAdIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering additional data", i)
+ }
+ ad[alterAdIdx] ^= 0x80
+ }
+
+ alterNonceIdx := mr.Intn(aead.NonceSize())
+ nonce[alterNonceIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering nonce", i)
+ }
+ nonce[alterNonceIdx] ^= 0x80
+
+ alterCtIdx := mr.Intn(len(ct))
+ ct[alterCtIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering ciphertext", i)
+ }
+ ct[alterCtIdx] ^= 0x80
+ }
+}
+
+func TestRandom(t *testing.T) {
+ // Some random tests to verify Open(Seal) == Plaintext
+ for i := 0; i < 256; i++ {
+ var nonce [12]byte
+ var key [32]byte
+
+ al := mr.Intn(128)
+ pl := mr.Intn(16384)
+ ad := make([]byte, al)
+ plaintext := make([]byte, pl)
+ cr.Read(key[:])
+ cr.Read(nonce[:])
+ cr.Read(ad)
+ cr.Read(plaintext)
+
+ aead, err := New(key[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ct := aead.Seal(nil, nonce[:], plaintext, ad)
+
+ plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
+ if err != nil {
+ t.Errorf("Random #%d: Open failed", i)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, plaintext2) {
+ t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+ continue
+ }
+
+ if len(ad) > 0 {
+ alterAdIdx := mr.Intn(len(ad))
+ ad[alterAdIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering additional data", i)
+ }
+ ad[alterAdIdx] ^= 0x80
+ }
+
+ alterNonceIdx := mr.Intn(aead.NonceSize())
+ nonce[alterNonceIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering nonce", i)
+ }
+ nonce[alterNonceIdx] ^= 0x80
+
+ alterCtIdx := mr.Intn(len(ct))
+ ct[alterCtIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
+ }
+ ct[alterCtIdx] ^= 0x80
+ }
+}
+
+func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) {
+ b.SetBytes(int64(len(buf)))
+
+ var key [32]byte
+ var nonce [12]byte
+ var ad [13]byte
+ var out []byte
+
+ aead, _ := New(key[:])
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
+ }
+}
+
+func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) {
+ b.SetBytes(int64(len(buf)))
+
+ var key [32]byte
+ var nonce [12]byte
+ var ad [13]byte
+ var ct []byte
+ var out []byte
+
+ aead, _ := New(key[:])
+ ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:])
+ }
+}
+
+func BenchmarkChacha20Poly1305Open_64(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 64))
+}
+
+func BenchmarkChacha20Poly1305Seal_64(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 64))
+}
+
+func BenchmarkChacha20Poly1305Open_1350(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 1350))
+}
+
+func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350))
+}
+
+func BenchmarkChacha20Poly1305Open_8K(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024))
+}
+
+func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024))
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go
new file mode 100644
index 0000000000..49f0da6b73
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go
@@ -0,0 +1,332 @@
+// 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 chacha20poly1305
+
+var chacha20Poly1305Tests = []struct {
+ plaintext, aad, key, nonce, out string
+}{
+ {
+ "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
+ "50515253c0c1c2c3c4c5c6c7",
+ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
+ "070000004041424344454647",
+ "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691",
+ },
+ {
+ "1400000cebccee3bf561b292340fec60",
+ "00000000000000001603030010",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "2b487a2941bc07f3cc76d1a531662588ee7c2598e59778c24d5b27559a80d163",
+ },
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "3f487a25aa70e9c8391763370569c9e83b7650dd1921c8b78869f241f25d2096c910b180930c5b8747fd90959fe8ca2dcadb4fa50fa1439f916b2301e1cc0810d6725775d3ab86721700f96e22709b0a7a8bef32627dd929b2dd3ba15772b669062bb558bc92e6c241a1d60d9f0035e80c335f854815fe1138ab8af653eab3e122135feeec7dfaba1cc24af82a2b7acccdd824899a7e03cc29c25be8a4f56a66673845b93bae1556f09dafc89a0d22af207718e2a6bb022e9d917597295992ea3b750cc0e7a7c3d33b23c5a8aeab45f5bb542f6c9e6c1747ae5a344aff483ba38577ad534b33b3abc7d284776ea33ed488c2a2475648a4fcda561745ea7787ed60f2368deb27c75adce6ff9b6cc6de1f5e72a741e2d59f64751b3ae482d714e0c90e83c671ff98ed611823afb39e6e5019a6ba548a2a72e829c7b7b4a101ac9deb90a25d3e0c50d22e1fc26c7c02296fa13c6d9c14767f68aaf46450a8d0fd5feb60d9d73c6e68623425b4984a79d619dd6bf896459aa77a681ec9c1a97f645e121f47779b051f8948a817f84d1f55da170d5bbbaf2f64e18b97ed3fd822db2819f523314f1e5ac72e8f69bbe6c87c22daddb0e1ac6790f8534071de2f258064b99789bfb165b065b8fe96f9127cd7dca9f7cb0368420f1e802faa3ca23792f2a5b93773dd405e71c320b211b54f7a26626b03c060e1ab87f32ac588abfa056ce090bd7c69913a700c80f325bfe824fa",
+ },
+ {
+ "0967de57eefe1aaa999b9b746d88a1a248000d8734e0e938c6aa87",
+ "e4f0a3a4f90a8250f8806aa319053e8d73c62f150e2f239563037e9cc92823ad18c65111d0d462c954cc6c6ed2aafb45702a5a7e597d13bd8091594ab97cf7d1",
+ "f2db28620582e05f00f31c808475ca3df1c20e340bf14828352499466d79295f",
+ "4349e2131d44dc711148dfe3",
+ "bd06cc144fdc0d8b735fa4452eabbf78fd4ad2966ea41a84f68da40ca2da439777bc2ba6c4ec2de0d003eb",
+ },
+ {
+ "c4c920fb52a56fe66eaa8aa3fa187c543e3db8e5c8094c4313dc4ed35dfc5821c5791d171e8cfe8d37883031a0ad",
+ "85deea3dc4",
+ "05ff881d1e151bab4ca3db7d44880222733fe62686f71ce1e4610f2ea19599a7",
+ "b34710f65aed442e4a40866b",
+ "b154452fb7e85d175dd0b0db08591565c5587a725cf22386922f5d27a01015aba778975510b38754b2182e24352f019b7ad493e1ed255906715644aec6e0",
+ },
+ {
+ "c4b337df5e83823900c6c202e93541cf5bc8c677a9aad8b8d87a4d7221e294e595cbc4f34e462d4e0def50f62491c57f598cf60236cfba0f4908816aea154f80e013732e59a07c668fcc5cb35d2232b7ae29b9e4f874f3417c74ab6689fae6690d5a9766fa13cd8adf293d3d4b70f4f999adde9121d1d29d467d04cf77ea398444d0ea3fe4b7c9c3e106002c76f4260fa204a0c3d5",
+ "72611bef65eb664f24ea94f4d5d3d88c9c9c6da29c9a1991c02833c4c9f6993b57b5",
+ "dd0f2d4bb1c9e5ca5aa5f38d69bc8402f7dbb7229857b4a41b3044d481b7655e",
+ "2bbca0910cc47ca0b8517391",
+ "83aa28d6d98901e2981d21d3758ae4db8cce07fe08d82ca6f036a68daa88a7dda56eeb38040c942bdda0fd2d369eec44bd070e2c9314992f68dc16989a6ac0c3912c378cf3254f4bae74a66b075e828df6f855c0d8a827ffed3c03582c12a9112eeb7be43dfe8bd78beb2d1e56678b99a0372531727cb7f2b98d2f917ec10de93fe86267100c20356e80528c5066688c8b7acba76e591449952343f663993d5b642e59eb0f",
+ },
+ {
+ "a9775b8e42b63335439cf1c79fe8a3560b3baebfdfc9ef239d70da02cea0947817f00659a63a8ee9d67fb1756854cc738f7a326e432191e1916be35f0b78d72268de7c0e180af7ee8aa864f2fc30658baa97f9edb88ace49f5b2a8002a8023925e9fa076a997643340c8253cf88ac8a221c190d94c5e224110cb423a4b65cca9046c1fad0483e1444c0680449148e7b20a778c56d5ae97e679d920c43eed6d42598cf05d10d1a15cd722a0686a871b74fea7cad45562bacf3bda937ac701bc218dac7e9d7d20f955429abdac21d821207febf4d54daea4898837035038bf71c66cef63e90f5d3e51f7fcfe18d41f38540a2c2958dacde16304e4b33da324030f1366f923c337",
+ "74ba3372d308910b5c9c3885f41252d57556",
+ "9cf77bd06a4ed8fb59349791b98ba40b6019611942f5768e8be2ee88477149e3",
+ "b928935c4c966c60fd6583c0",
+ "ec7fd64fd75b254961a2b7fc942470d8620f439258b871d0d00f58028b5e0bee5e139e8108ac439391465d6658f559b1df57aa21cf826ede1a28bc11af885e13eebfc009870928fae8abfdd943a60c54fca93f0502dc23d29c2fd5340f9bc0e6ef2a18b66ef627af95f796d5bbca50de22c8ec802da9397089b25c6ba5262468e3977b45dc112e51896c70731b0a52d7efec7c93b41995823436bf4b0c477ae79684407c9831b487928b2b8303caca752b3edf1f0598e15831155462706f94ef3fa3a9e5f937f37085afa9b4bbf939d275796a61b78f70597acfd25cd87f967021cd99328fc371b5eb5739869520657b30e4a5b0db7c8715cbe275dee78e719b357d3a9731f9eaba95986479bb2004a77822fc115a3d",
+ },
+ {
+ "b3d3128bce6bbf66fd78f1a18352bae56bfcdae18b65c379ee0aeb37ee54fba1270d2df578ec5b75654d16e89fd1cd0acda7ec580dafd2fbbabd32a8112d49383a762db2638928c8d63eb0750f7e7fdd256b35321b072dd5c45f7dd58cc60dc63d3b79a0c4a1689adf180fef968eccbcfa01ee15091ceacd7b67a3082db0ce6aeb470aafe87249c88b58b721e783dde184ccf68de8e05b6347fe6b74ae3adf9a81e9496a5c9332e7ebe908d26ce6b3f0b2a97e9a89d9fdd0d7694585a3241f240d698e69fcc050e7a959ba153f6d06f117848ba05d887134f1b6b994dad9b9e74247513e08a125b1fadfc7394dcd2a6451b504ae3e75e22f2b9bc405747dedb6c43ef4ccdf1a7edaf9451346123eaa63f3af113124f361508e255503a242b96680ae3360c8b13ac1f64d08088bb26b7f617cb0866f11d6fd362b00d86eba3fee68724e302388f119d6f92161ac8ce00d08919377a26974d99575b1032ff0f1976240c785c8b89e9eb2bf005e4be06b5371ffca14683fedfdb49e00e38ff27af1324177faf91599abd5990920797574eb743effdc7decda318ada1419cc8e0bfecf82f9c99792746c2b",
+ "7e8da4f3018f673f8e43bd7a1dee05f8031ec49129c361abbc2a434e9eaf791c3c1d0f3dad767d3bba3ab6d728bbcf2bd994bd03571eae1348f161e6a1da03ddf7121ba4",
+ "7ee32dd501dce849cd492f6e23324c1a4567bfceff9f11d1352bcb8615f1b093",
+ "8998e043d2961afa51ea262a",
+ "ba85e72af18cb5ba85a4a0d6c28b4ac1e5509a3a2fdb0e3255cbc559df5e6a661fc560c756a0264dd99b72c61c51a4b7ad56ca4c8ccb7e8edfc48ff3cceac5d1e8ac5fc87096adc4d0e9a27492857b17604c3a694cfe0e70b22df106c8f3c61f840bcd634964cdb571840e125e381e7dd3a0d97972e965f16f775fa4ce555124318290bf508beb7bd77e633042deb0e863631478fc3dc9122862b3c31264471bcce54e0b74040c8bafd481cf798f332e8940f1134d3027d6f28e771d15e154fc89c6c25fe18a5d312807cc2e623bb1bbb4f0b6ec71d009407eb54bb0759f03682f65d0da8812f84d8e97483f6a8d76a8417efcd9526444abba24288647609791578887ef49780b0b89f51b072cae81c5b5014463da3633dda105b82add0f9c2f065dca46eedd2928be2570493c79a996fa78ea6aec0996497fe2dc444432ade4eaa662ee2255f0f4b92d593288a8e3ffe7a15a10e9d33b0203af23f4c9fd2cfcb6160db63b52810869ff1e65423dbe2c4415884b9f8dec3c968e14cd74f323c89053a96111bc9ce59ec483832c49c53a648e5f0f797f53642ac60170c94b473f1f2e7d8a38e46460b81219b52081263027f74cbf63a75af3a7",
+ },
+ {
+ "68d5ba501e87994ef6bc8042d7c5a99693a835a4796ad044f0e536a0790a7ee1e03832fec0cb4cb688cdf85f92a1f526492acac2949a0684803c24f947a3da27db0c259bd87251603f49bfd1eab4f733dec2f5725cfcf6dc381ad57fbdb0a699bccc34943e86f47dcfb34eba6746ed4508e3b764dfad4117c8169785c63d1e8309531747d90cc4a8bf13622759506c613324c512d10629991dc01fe3fe3d6607907e4f698a1312492674707fc4dde0f701a609d2ac336cc9f38badf1c813f9599148c21b5bd4658249d5010db2e205b3880e863441f2fe357dab2645be1f9e5067616bc335d0457ea6468c5828910cb09f92e5e184e316018e3c464c5ce59cc34608867bd8cbfa7e1286d73a17e3ebb675d097f9b3adfa41ea408d46252a096b3290e70a5be1896d6760a87e439334b863ccb11679ab5763ebe4a9110eb37c4043634b9e44d40cab34b42977475e2faa2ae0c0a38b170776fbb0870a63044aa6679545ac6951579d0581144cdf43f60923b6acaecdb325c864acd2c7b01d6e18b2b3c41c041bb9099cce557b114b84350131e3cee4089648b5691065867e7d38314154355d0e3ef9dc9375eddef922df2a06ad0f0e4357c3ac672932e5a66b16e8bf4b45cd893ea91cb397faadb9d9d7bf86e6ceca3e9176a5baa98b6114a149d3ed8ea176cc4a9380e18d2d9b67045aedeb28b729ba2ece74d759d5ebfb1ebee8ac5f5e79aaf1f98b7f2626e62a81d315a98b3e",
+ "63b90dd89066ad7b61cc39497899a8f14399eace1810f5fe3b76d2501f5d8f83169c5ba602082164d45aad4df3553e36ef29050739fa067470d8c58f3554124bf06df1f27612564a6c04976059d69648ff9b50389556ad052e729563c6a7",
+ "7d5c4314a542aff57a454b274a7999dfdc5f878a159c29be27dabdfcf7c06975",
+ "aeb6159fa88bb1ffd51d036d",
+ "7597f7f44191e815a409754db7fea688e0105c987fa065e621823ea6dea617aed613092ad566c487cfa1a93f556615d2a575fb30ac34b11e19cd908d74545906f929dc9e59f6f1e1e6eaaabe182748ef87057ef7820ffcf254c40237d3ea9ff004472db783ed54b5a294a46cf90519bf89367b04fc01ce544c5bcdd3197eb1237923ce2c0c99921ca959c53b54176d292e97f6d9696ded6054711721aebda543e3e077c90e6f216cdc275b86d45603521c5aab24f08fd06833b0743c388382f941e19e0283ac7c4ef22383e1b9b08572882769c1382bab9ad127e7f3e09b5330b82d3e0c7d6f0df46edc93265999eef8e7afa0cb1db77df7accf5bff8631a320d146a5c751a637a80f627b0c9a41b44f09212f38c154226de02f4906ef34139bbeacc3f06739c8540e37334392d38ba1cbf4bc7debe77c09b35d2200216db15ed4389f43bfd8ae9bf76fd8243c3d869546e16b8e44a6cd1edbd2c58ef890b5a84cda889131e5cd9402ca4d8271052c6b4fe3f2dff54fb77bcb575c315b9109f90b14bc8e109919808a581c1809e2a188d29fd34ce639088a6683f641925f5b4b3529baa34e080bb47fb7ad9b43d0d67c9e6ae7cacb50527fa74e56d0c8b20149f5d332d686d48ebbe634c2b5d35fc84c69a5bcc93b93dedcf9fdf19a1fb9b75f6df9692d16f6c3490377a06294499e4b8ebeaa0cfd840bfa05fde21c0b5e94d13063b3f5da7b537caefe89069cfa9de9eb8f06e4d30125de64716f821bcc8279c0c7ea2e",
+ },
+ {
+ "89c1ee38b6697d0190c87a2aa756892ee09fca095df1e31aeedbda5750f604d9b8f2116e5b8f70ec57ea16fe419f2d213ef72b9be90eb5d7e98f2e398632123e2524ac80b31c6c0a07820848223569602d94fc16a3b1ed8c411bc6c74ed80573fcb1f3afce60b9d5e2c21d04f78665241b613abe12274a5343101a91e91f04e5d1f7959f574e743a10913e0817a32c320467f0178e3b6ad14b856234a4661a755eaf14b5fd88ef0e192e1631d14263d6a954ed388f5709dadc6c0f81d229f630d80be6d593d5e3ad03f9ded53c41abe595981d24ef27ffcc930e4d653743960f4e7ce4e251c88f55c16d2afdaed5e3446d00685c276728ba757520acb9b6bb0732a0e9836878d829e5022794d70ad8440a40a132a8c9ec1d3f0ccaf8c285fff425e9788d6150b74753dedb2ae8b36ff2f310249bd911b9181d8310e00810d42ef94cbb5a9d72a1f0507c1a382f892b23994fbe7360778b7efa9c5e03ac3231a57fecff1c5fa10caf1d26e84db0137049622ebcc3a64841a0e49fa390d1d43550c1346c20d578cff39fb7404fcab0982dde55f0849d312581d0c811a19d46f25e7a5e7e50d74d43760583c5cf335dfc11b2ec964f1dbbd0ed83e18f2027817ea2dffcf2b64a352c4fb8f11eeb4f1bfc01079251254d2112d103a1f12a2270cc026cbeb8b6f3e505abd62496253f93274625786b73997e449c1f35c742a593441252fcc845e1cef1b8f287dd311a0477407ce3b31661f7b2802c79c2d20d06e45f03aca4e47a959c6c1d7a9d377e1577fbf82a115921c3d94e3d9c204aa204a9a5b04d8a2be3269700a035371f4aaf1a42d92b9bfbee74492b106975b36d1e581d6ce2484f09e04fa91586c85f35e2a10f0d3c0afcb05327c1bc9d7429bbcc4627af8f76b86fc561844c2ae3810c84901ac09a1670ed3d31a9daa5d296",
+ "7219bd21a834d917f93a9b45647ec77102578bc2f2a132dfde6489b9095b4f7b740c9c1c4075333ab0ce7f14",
+ "a7f849b054982cc8a4c8e5e53e181feee79e0233e58882839892134ad582da7c",
+ "4c46854e9e101090b1436f90",
+ "ab2e189baf60886bed88eb751bf3560a8bd3cdb6ee621d8c18b5fb3aa418f350048ecf359a7d542daf7090ec8688c3b0fe85914aa49d83be4ae3396f7bdc48051afae6a97fca7b42c0bf612a42d3c79ef6aadceb57f5cfe8d67f89d49add0ea1ffd423da058297239e72a85fa6cd1d82e243a503b1b0e12d7510a9ee98d7921dae2754d7581e52acb8ab9e7f9df3c73410789115cef6ce7c937a5441ad4edf2b7a8c0c6d152d5a5909c4ce839d59594a6163364038c4c71a1507389717f61e2bda1ea66a83ef477762e7834ebcfaa8f2ee61ced1605ba1380108236e1763bf40af5259da07dd3e3d0fb2801868c2e7c839e318678687cbe33384e2ef5750a0a0e2d2e19e869a4277e32a315ed4de79357f6a12a8a25d5b18291316d9bf40dad2d05d1b523ade76650669c700a1c2965f4e51337aa5d45ec7b4981072779401d6d30ed69034053334bccb18425ac68460becf2aeccc75aacd3d6709f07ee10366ed848c8a54904af4ea71fc2117de133f01e1cc031f2a4d0779b997b82682433ee615202d5dfffba6c916f11a00551d56ffde8c36b303263e14adaf45b6eab0bedf344e5214ce52f071d2f40154d788c6870020791a03d2fd4ec5879d9026241954ed45cfddef4937ea3d0d45647f252be31411237983a1be340fc65ebab9a5620abb0e8d475af4e89e842e895eda0cbd283bb5d0bf20236c62d956de733d60ebceb42fc0c9adbf9b69f8d66551b0aca0e260625ad41cad75d752a234af7caf7902c2c5b62f04b6a8e019a6179d44feeb2ad5859ef1c45371e66f1af1fe0de63997266c290e27f0dd62185c53f81e0a50c296a51ace7c90d9cf0dda8b2d7e72a347f64c44262e2a544d1acc7bb05734dc1783bbc1903279092fe7fe434610aa95fc2ce5fc5ee45858f5e8337d8fcb0a468464becb1cef6b7e5ea48ba383ad8a406df9c581f1cac057d8711fcb",
+ },
+ {
+ "2dcfbb59975f217c445f95634d7c0250afe7d8316a70c47dba99ff94167ab74349729ce1d2bd5d161df27a6a6e7cba1e63924fcd03134abdad4952c3c409060d7ca2ee4e5f4c647c3edee7ad5aa1cbbd341a8a372ed4f4db1e469ee250a4efcc46de1aa52a7e22685d0915b7aae075defbff1529d40a04f250a2d4a046c36c8ca18631cb055334625c4919072a8ee5258efb4e6205525455f428f63aeb62c68de9f758ee4b8c50a7d669ae00f89425868f73e894c53ce9b964dff34f42b9dc2bb03519fbc169a397d25197cae5bc50742f3808f474f2add8d1a0281359043e0a395705fbc0a89293fa2a5ddfe6ae5416e65c0a5b4eb83320585b33b26072bc99c9c1948a6a271d64517a433728974d0ff4586a42109d6268f9961a5908d6f2d198875b02ae7866fff3a9361b41842a35dc9477ec32da542b706f8478457649ddfda5dfab1d45aa10efe12c3065566541ebdc2d1db6814826f0cc9e3642e813408df3ebaa3896bb2777e757dc3dbc1d28994a454fcb8d76bc5914f29cfc05dc89f8c734315def58d4d6b0b0136ccd3c05178155e30fcb9f68df9104dc96e0658fa899c0058818da5ec88a723558ae3a6f2f8f523e5af1a73a82ab16198c7ba8341568399d8013fc499e6e7ef61cb8654b48b88aa2a931dc2cdcf245686eed9c8355d620d5e91c1e878a9c7da655e3f29d9b7c3f44ad1c70890eb5f27ca28efff76420cd4e3cebd5c788536ddd365f7ad1dbb91588d58612e43b0460de9260d5f780a245bc8e1a83166df1f3a3506d742c268ab4fc10c6e04bca40295da0ff5420a199dd2fb36045215138c4a2a539ceccc382c8d349a81e13e848708947c4a9e85d861811e75d323896f6da3b2fa807f22bcfc57477e487602cf8e973bc925b1a19732b00d15d38675313a283bbaa75e6793b5af11fe2514bda3abe96cc19b0e58ddbe55e381ec58c31670fec1184d38bbf2d7cde0fcd29e907e780d30130b98e0c9eec44bcb1d0ed18dfda2a64adb523da3102eafe2bd3051353d8148491a290308ed4ec3fa5da5784b481e861360c3b670e256539f96a4c4c4360d0d40260049035f1cfdacb275e7fa847e0df531b466141ac9a3a16e7865947572e4ab732daec23aac6eed1256d796c4d58bf699f20aa4bbae461a16abbe9c1e9",
+ "33791b0d653fb72c2d88519b02bde85a7c51f99cfb4456dfa6f84a61e10b4a14846521",
+ "a0a7b73ca2fc9282a28acc036bd74d7f5cb2a146577a5c29dbc3963fe7ebfd87",
+ "eaa4d916d261676d632455be",
+ "c9a631de470fd04dcbf8ea9f4d8ac37c3988878b6381707ac2c91d3720edbb31576ba90731f433a5e13582aca2b3c76ae75ca8881a463ecfa789910d3a776a9ad4800521c6baa120b2f1afd10f32ef8da63f5b69f5e5fd88ee84bf66b0666b15d05c4050f5358a050b9d5cf1503719f56cd48ceba78f29efe2ae8092e37f5134df526831532f86ccb9339637e2c9e9b9036f83cc058fda23e826a188456e7fd3f4ee20f4e4a3221883fe3232b49db607b90a8956133ab95051c9ec33a908ea7e81a1bfa7bd06c09f0143d07bb23a3feeac7f0d7720269c93e2df19d03605828c8713b84d183c9a50954c12fe3b047511ad15ef03a63355520cbd224d06a34de67a671368e6a8f9feeefe48fc273764a8c69c00314e5d693f159cb5270544f3c4e1760b0529e3303ab308e9a6d03835a3a42aef2df5f7643696f707a574d1dcc676aeecdd9947ebe8c13bcf15d30b2d10d2cd95445a307c1d22d39450615ad38f9302c6eb9dc05764b0503d6a7eaff9feb94834853b47bc25660207be3e7c0e27cb3127b5402cb016396e5ff07ddc3df29861dd68a17f53bf660b23352b739d6da72381b8d19a9fc95da7efb79330a2b360dce4309860af429e3fd10cab235c4acc1d80d9e20d67019375bd161ab65648400f308815afe63cfc717f7d0eea150e687caac25b6603287d44dca4a7cc2f67c3bdd54450bd3170340253b03ba054ec003070eddf9c14fb9dc595e228e4968524900cb5d85af6d1e658a42d744e0e7eb6995023823a8dc33528c6715b2e1aa607782c8e1ddddad72026d657bf122ece8685f6e92236e809139325e4a3c069facf94c10b7896995bba01eb22c7b3a87ea2114a7649d7ed3e83d223e5e785c66a75119beab0968d3eaf0cbcc2d7ede95d024041e6db39a880ce3e19efea32fb89a40a2aae22f407e5fd615e51e48dbd50a8b4ec27ce95e2ba1928bf699d0418705482ed0ed7acc858dfbd690403c74667a88dd5221bb79940c6c4a268379c10343aaefb635982c14f33ad83d47ced9682961540bd4f75804d3d48ba8aa67fb2e3a1db83fbcbe57fec9e4ffb1b575e947f8bd8263c680357960e3a39382974774b5a013f2f8514b3c63c21dbfd314fd5d927d82ba616d76629ac018879f54ff84b5808e94af4fcfe1cf8845b65208ca5510b5b593ce6c109611652cd",
+ },
+ {
+ "c335b055b752e083554b5aa2cbb6556cfcace658d5c11b6b000256fd89e9b24c1e62a2d5b582580acdb2ad9869020465aeeabe83acd9eeacdc44aa652d5cb24bbe542073d6787ea32b2b3c942d40f9db2bb75ed7914c836d902dd2be89840948d82abbaea23952cd648e6191ce5b6cf912cad0a3165410a781e3650b676e5340980eee3b484008acce6a3e9dc5aa96d775677b8bbb8b323c6e9747d6069a169ea904d9f145e29d134cdbb0118647e8fbae638669efb9a55d50ed33568749f5304ece2193b0bfa6fc9a570d209ef61b4c59a2b5485b5aa6ab47d902cf23f7ff71c5210476e0aa727a01809b9f76b6ebcf58a018b3fbbe5f42976111ba58112b1d322f9312da068cdb86277bfcde66cb3607e3ea02a1494439aa56f302671f1f994eb3ab28b937043f5f7f3b3de50673ecea5dee8ba633c45089b852f0d772892525344ede6b521dcad15807b65e7ba348d891d47fc498cf4d50223d2794c64db9fa9b9766edb430be0c38746ab317b38ba9870a6d1fdabb70fcf89790bfe449b97fe01f6c94502aa0889f0a3bb6bdc65f44d1cd64ab88d4a7806b373f5080f9cf60183cf4686694f0059e2bbc5cf21ba0c3e8046e70d815f1444c3094cc29632c429f20aa06b49b0b52c6c7aeb8e34f7bcb53e93c2cfe2d704a5d0416876742c90762730d160e1869d5e0178dc366098ebaf2cae6f1f7563b555a52dcc194a5c8f718d50d27ee76fcce8e8991f4921fae85ea9476e1eab1364403120698b7ce8fd0a49cf79213f360a17cf1950f104494fad80adcc3bb1207bf250d57dcdce6ac8082a312959672361363cc227310b66ee8c04aab7b5cb33a81c0915e9c770a1cfaae2e8f44a0c65703927977a22fe58aef2f366b8be9a50da9376b46ae7562a82391386831febf359039ac326891bc58c0f2c34bdb6858859fc3cb4e392df65cbe2ec4f02c8425bcbdd1ee2562ab7d229d406d79a9c6fe4889c996c2f68d1fb5bbe3a5e867caa4249b934afd3ec71fdb088c54b15252f9dc1b909e121dbdc7d8a16cc00836652dd1f877ce363eed11467966f7ccb8f1a8d48146e69e04ad76a51937ad4f9cda209451eeca90dbdbd65441ce20fabfc8ce400fb4de136154b87a8b65c92740e9bb91d78521b261f806a2c6279c85ef6ac5fe1ea3117ff7c9f9832fc2aa6fab660082eb22344c1a3befe0628b6551f62a5014cd6194c42b8d475a50f2c9fb58c97e43ebb29005ed7fe54f0a4aa10074f1154152a9067d364dd7863fa082976a00db55b26b5ba0ea40eff48b90",
+ "f5ff810a41d4b34751e9942970d4c9f26b33f24689a4b1e4449b243490afc485af468ff01a42376b2bcb949b9f5e8d0b917f511a",
+ "a74271c184a82cb074c14b131fd91eb05870cb7c73c9e511ec8140bfe2f34089",
+ "2403fe689e239c2ed261b381",
+ "af9be893d5fd23aab42e6a2e59a8e7cb13d4f543db02af87cb0802bc1af7c717cd0093cc8244994cf21189146922b69927ffd5745e57118bea07a6afe7c21d952c13ab636b3c2e461dc9ffb3ae701175360156338be94b1fa7115799831019455cfaf5114010fe45f8fb9c77ec50fe06f2c5a32423edccb3b2210ee1200a78e1a3130c567542377827586ca8cf0c14c19fa1449a2cce9c039bb441b04e9c0a3f9a743b31c828032174fcdb7c894349aa68f5adf97dfe9294d24e6b5fed95eb994397883f58487bf5c57b0aea5268be7cee9efeab370f89805ebe5373ab2e93658fc078955ccf68b554dd5605005751ee8531c35ca5336a5d0ce273370c0dc9307779b86e96d2d1daf2620d67d43e1fb7800ccf250ca3c02eb74047c1d2a2bc7f29fff8320301694b80d0fd975f834337d00d5f0e4215044d52aa4ca21e6a9d7e03f186d7cdd5c48e3765dc926fb0a46bb0f05c50d9f69c9c507527a60366b7dc251aae1d6bb0d9c73735dcfab959f6fd4382fe2a1f6ad07affb0601bb9040f81b55a48f6a6c5f8ac4a2acc2b0c9a6c439198f7926460695fa11e0b0b017e39de5cf0d5d5f84d972b5eee7b5d1e0343b5485cd84b92ad892e5b23f3e803f5b363f2398c11c15be9f13e59922b0d49902dc8483fb142850b4226da2fb84e9b434a34f6bb67f575a9e57fde3354bc3077a876e260311bb2481bb139aa9af55df5074749fe532d7b8a554218a90cc7e7ac69db280bae5d55a174dfc8d325b9909a8da1016d4e162fe5ba70cf8726cdf291f5e47083d9929cd5e32021cbfd982fd0975f6f9baf4322b553cb3174b11c007559879f308419ff9e4e18eee8d3640cec8aea082b90f69cf3c7676c28af0265c24c91cd58a06513198892ce6ce1ab3ee9ac0a2e937b973a9cac06a039a54f8d994c13d42c59187f677352e5feb32a417aebec4d852b2595e7e67450e06dbd183279e3b63022a3813b37257b085bf8454d6890875a2950d20210a8df4f9da746722f62687e92f0e9efc3e5d526d65ccfbcc042fcac7964dbe147932c73924bdcdf62f9eae58d29e8567ffed90048bcf0566b952e986efeae4c477944af18bd243c3eccf8d88c06d07279adad037450cb8547a8aa0a74223f4851747c803cb21a2dd027e7080aed75038cdcecbc4639d87763cdd41829a1b72cedf0d722b180d0d492a5740ea7607b95f3201df352fb1ab28149124d2df5d5ec106867897b537302c3431402348f94d28eebc701ae1b49d10adedea38f1654fbc48885e59e6e6dfd413c6b5a97d8c35dfb07a6cdefe317bf61cf91",
+ },
+ {
+ "4aba5a776ace38b6e2578f0007e770d264e39c49f588ca3547ad2888365e3a811994f8836330394587c8458eb0b6611499fd5d8e8527c3cdd4ec550b4a8f8c632384e786b420cb3be911c999c72aad60270aefad31b27a069ecf11e95e9d4c81213308d554d3103de4d9d6ab04830c2b8dfbd8bead52c44c21d5357f72810193b5096809dc7846c1521c6c569f78812c735aea21acaf6dce84a24df7234e8ad857f3e1346b27f5bd436113e2da950e4deff96e9ba8db692c7db723a105ae795da15b910c8286cac6e7dda8c172b70f61b07dfd58596684d61da8772356f180f74c1103ce97cd947eab3d401df44f7fa4cc7cfc25e280fc002873237e64a375b0b4797f4b4613c9f150090f44588ee8250ae44aec6546ec8dba0f0c1eb281cf66fa4eb141617b32b28441f6ddcfdf02d9c34cc62893b2b64dc2c26b74433adb3e888c7fea07b19c8cf39269c2716b9c35b7625d4a141397d6d5034b193d2657c6b2d6b0ba874c467adeaf3d501ad985d13be21c4ff6b326cbb671e4f4973bba49116a0399b6491394f850e4122969e4644c00b442b3da0d6a4bf25ee22d182b3f822fd83878ebcc713cb183651a67ca66677ea81b58b685a3a8e385d5fbb0147ddfecb558d881c914324c794db443b31bc15c361912bbbcba9e418f99f2a416d190cb29684df27c7f3ff6ccf339800efbdc4514ee00d1a89f12373804db4fd66c1affd467f251e73147b3248033327b0f7790fd7861a51773dd4f78b89e4e24b94df9203f4a077091bb9411eec78dfe3e1dfbb67ea1cdf17e1d6936bbb75b74055495449e9cb52f5749404610cd444fea3f0568e0d35a5ef0c395ab7bf0208044b5c4e2517911a9c351efd31f33220972287253fbccb1eb8f46960a36b68a7a6b4f5cbdc86d668bbf555fde8881e7faa9594da425ff8fb54526bf7cdc4af64899530561c06bed7fc04c5d48cd4542779e901bc48fab79d4d13850ad8247f51b9afa7d5a656ada25b6376d837cb0fa1b4016dfcfc158a39290f43f133b352ed52fab2f951509bacb41284fbdd849d8185fb7e7200f8ab2a07ef2b3b927e18e568dbeeba2c7a66e08cebdc6a6069ebe6656a586652f3905ae2bb867529af6a827b494c97b3a378408f44aaefbe86c613e11e7a44020a9ee4b62569dfc4c462300daec7b1424ff1c1849ca1332367470475c14877cbe76c820cc651c18ab3f18852b93994f93b568dc7f7b0eb5f07ffc4c9384c851fa9071c6f68ddea1ccf627f889c0471c76aff9f52b07ab1b86a7671a2b2f6b25c0ddebb66ac95737bf7e2f493f7665b5265eaa5166556cecfdd3062802724ec24f3978b903d0f0c24e1f0b8d967142bccfed0d354279223f4c28684e9ab611e9ef89a3f25993b5a8b3c0354931780501651236a78b58e7d7814f251b053605f4c0a8e7193b9cc1ee5cf7378e6f3c8fd44ec57bd91e62b09fb1d6bab60cbfabcc6792e6a32ea7918a9ec9180d05a7e1546d5d2d8bbfde2a71b4e427c0a4d28d0b6473ae",
+ "921a401db90935c60edda8624a0590d5c46eff3522e35de2872f6f9394e24126fd8143b68a797c995624fba0298b75eef974",
+ "6a4d35ae03bf277f587da4541dcddf92bbd906dff45d5ff23c0f60ae53b062be",
+ "231b5780fedfb06d724450b3",
+ "ba40968282d98849b19d867f8b564ea5a81d657516099362926bca4cb6e9ae02719d10c8061f53008c727a0eeea5e1e36c9e55c117e9434e213316c96840231a1e356b254a9981d4a6ca3c66cfc61018bcaade1a4486506559e6aa3a86bac980d391d835fd5ded98d10f1394d84bf1bbf2cd3397890d704154802f7864ecc753db782fd3d19213ae65ace4770e1bacf32d61c6730aa5adcab4d7e2e437888c11c29abba4890a17a00f67a53b660becd94092df0598df5ac57326f6860593a519e28bd4a39f6481e1a4748881fd5f0456a3cd9f28d1d1e78dc64030cbd8fdb2c5abdab3f13d6ccccd187e71e989f8c486929efcdbf2a763effa95af62db5cef95e9081b818275c69267022fda4b7fdb8c650b491a785b03d4d0186625962b6326ec3f4e176373da4dc1f83a14815adf82c6bffa7c6967d77528d0249754bb4d17656bc4a89449b16152a4a1aea7eb0054a8892f271138971507d2f3b237ba5b620f444544e4a8c2b1ab4f9168762c27478c9f776c47ee2e9ff05bfa35ed127f0cabe7cc053640bb8aa01f8359b74bf89ef43ca94c48fcd201eae39d1835957eeccd6b3a852f4e1bbfef9a469f42c764481ff8408fe5871afeeae7676b58f4202199aad50a596626dff97c8e60d750cc59da9f595ce12ce9afdce14481cb1e39994de8fe4cce07845110d6703dc59d34734e93e9e57e1c52d61f44143a2d290220a4bad5098d098ee65ea4b6757d8a9bf5485aa3d697a7826d4a285186f5da10eff707566c23c6a15033365bcb498c44487c72d96402d1834753fdbf86770239761f03e0dc8963766441da99c0813e4f1df5a1d018c8799861a396562eb24ce305ca15f4022d83ea3c56b68d9a7ceac4742ec0ce50f4d36273df26005ec2b051fa071b319be2d8a5ed26eb75bc1ea83761b8454db234d15d84d6706cd178981c1f156e6d28f774aee3e9a4fade022e71b52b50aa532b8bc7fe464f22d6eb169c69671875d614e987658820c2f584a4fea3008afdcbb646dba3d69020fbf503f121be3480344db23efdda0d255aa058c3ff66abd3a5fe35db977521608bba7eddae72ae801f4fbb12a1de4133039e046ceb8db87e465e5ede1d79a08c857d59076d7ff858942c31e15cbbdae6fc15c3f9545a0825d6ff8583c0aba8a7d143d27b93f6caefb98c0d83bd8715abcab2a49087f55a9daf9090eacdf45be08ad80b5df5070e1719f68c4cc8f8711083f0f7823a09ec092f22df95fe9e95114fdf82a3f6eed0bfc9c0aa65222609442776154a474dbc9e662cd5dce66846572e52417ee5d7eb59287d07ef60a9537fe1f85c7fa74fe84dea0da235ac7574335e6649b54a6bd33397df4bf4a7976c4ab868aa702766d2bc8d2c82c2d1c2653fc8428b8d1e61852ac185a3a0b416dbcf8eb54c44967ff43c44f2b32c6d4a9dbf2c2f3a587b430aef50f0375cdb4c1b319ac9aca486d9bb321141b065f52f7b6decaf1985531ca7bbc3772a561eb1efb8a6297075920bc432131a5b211bf25e35fa31e12833bc77a9de14c7",
+ },
+ {
+ "6c0056937faf1023032df1e2bfacbbc58bb022eba25ffa020d4eb26f0caf0678af5d0b2f0c1b520f4843f107f0adcc7b5dee66ff4d61025bafb4cabb64d133132e3e423a599549a1d83aa8c8e774444462aa44b00b460bbafad5755ea6a872d4e6b40e3f4957e0229288ea79fc2ebe5fd9020fe4481a9f42ef14a196bd136aa3c779e311d0c333624c1ddc484c9aa7259cb609e4d0a826c0bdc7567adac01da23900b30ac4e66c100348584fe200747eb67e6287268947e3509d5d2b5d7bcd977b80a13f660d4f6956a8b938a82db75eab19e5d2a22cb5f3c9131e278eebbe096b5f49d16c983ac240f3fbe821b247cccb2c9e6e59546122677f49f56a07fed56647a6d3e0e09520d49009f54250c10e7c607cd5b4ddf81b5c4110c6490e9baf56418236211856f5a85feaebafacf92c0c7501c052f9dbae3beb7484f90f334f50b68571cedc67763b5161ebfd5a1709cf18c92112a4cf4d8f43d1895204d8a2ba5e14883a7bff75cc6060cabb77d38a909daca2417befd1bfc05a11c432b47f90c807ca4306400f67a0d92218adaca84a584a8bd4395c93f9b6a4bde9583c79204444634a8473b1244cd33cf980e443d82ecfac672b3f60e2e41ecb3c5a445d9e88c0e90c339a31806e6d79ee52bdc6808c73e8b7b24899966664d3c1a9305f31f0483e24e36fa451dc1d3f2eda05af6678971e2bdfb7c1461c9407c5c466f6b5af34d992a37de3809a22ae75275ddba0f4f9cbd4b18c1acd212192e587889a36bd73c860f0abe08bcd8f00f5ecdb95e1d560b586eccf530df0e5f3776d8dae2a01768bf1226b7ceffa7ce4e75879c82dd97db3c64c06d33cebc6b35854618355d80e46fa79c3e9743fce5b974723c421a077e7ec7dba286881dbc1d53d442a1552700fcb33f83f73c69a0a0ebdcf2f5d461649c4d0712c514ded268a31509f83c1ae4ff4a68e676d29727be641aa4487c08d4b90ff78e24c6508d69759751a1a23690ec9f8763621e8b107295b4bb01bd9fcacd8748e24d996fa70ef6f8b0992f4185bec8e920d7643159f9f604fba394b6611bff435998b2f097a9e948430899c8c752a1e83a061983f00f88ebb32da214399167932a1a83c1b47d09f77593b03cf6521520583ea4483e2d33e14ad60584676d1791779b532c085d238df0d3bae735d0078e0eabd63cc90a2e13d023983780afc8f83b1c14437937c16a1b7c41414c48cf4ae49587ad9fa5b16fc949a749e96032248c4667f58e295f999590dae1d99a2cbe3fa45bcf4a1d3f0356d64d40367f64b2c5cca843e5f7dd7b88a85d52328a00622e6c317879607bc036c9006d38652ffe21c83207c00f8348a7d0aaea5aab4c89077df170de6d41052641726eb6925cd85a9ee01a9e636346340e209ea96d17b0eb0921b96662ce9cb430fb6ac348331dd7133875769bbbba99dc49333950e4145a15ddb0789c4d2ccd38878080ca9e57ddc6cd5452790eec45482f8e990392e319609391fce0beba19463a9a00d8f1de9fbf22f23821de7d69fdfbf3019ed61aff79acfc5a6ba663a1e10da2b9ff7149aea43bd6c61a543008402309df0924de72c1cacd2d6120cf422e61fc1de345cc8771934d8be77d9437a09e06a9b2d51c849fd9a200fa714328d34f36b684f33df6968b827df916a599a4bc3367814fec21198e2213ff653cd2a463892966c72ffd42a26b3bb91",
+ "0d55dcd08b54e58916f622f81761ef6a2e19b167ac47d3",
+ "e42e1d6d44138f3d2bf12c951f454686f18d590fd30057405b5a3dc2b317fa97",
+ "1e46a7486c5a03fd6758d938",
+ "fd3c1fac10cc82e49235fd57f5aea0ee7a7bd6d539b138d4b3fb623aee591615c1a61228ef9673113a3a90a3687a12d4c6367d5f7bc67d422fdc4106455084d79c2c42c5e86368dd164bcbce7925bfffe7d96c13a2f49aac8e9d1ada3554e3fdc21aab00455a0f33b0c1fdea91b3588e7ad301bfccf9940027332fbdf966463491f7a33c093e0a13831ea9d2183294f89f414cf7b5876af04fa68d594430194429df74fa5915394427259e832bc545c13400aef6cf16620d48280798a6e49773c9316d79fa1dc758e54cde2e2cdb856092d83f4e9b698385cb976fd6cc2538abe055273a5b34a784182ea5e7d3ac9019a05de5e5afe4308a7ed2d363cd50ed6a52df1c616e4a82f607ced768445d13ae4884f2ae1f9fd8313924e8a1a8a23905c92eb231f638dfa6f4cb27bbb9844e05afbbe2ca4d1a3b3a5b371bf33c9ab6f82a7387d61cf8bf662097624145a983839b0cb9f4bd07556800b4054fb3d0bac94f44bcc9b4ac49c39f5571fac4e02ff09f08b3ed5add4bf8bba934e9feb773c0590b45c45fa036382f3fe9782ad19107d4630321e414b7b442b64f18fdd5219039e5740f34b3ce8925d1afe8a39e35ce8db086060bab63b9720700499f82db19a62897c6d845389461260303f9cf2bc7235a898b4620c2191ef05604a5c8c783d58009533a86b27c12b0772635d34ac53993ccf174c9087073e5e69b26c0c3d9f768507ac4d4e2af847b65e3a6e1b7a6dafb0aefc190871cdae6c60f0b1d6137c351d4cb211870791cf4cb8af2ea446f6401eb9ec8a5bcebccce898d1dfb13454df6b35b81ed6d7637e6e261e004080c60944f3a08e8e5fc7e2e4939e7c2607c8cf07d1d10883ba3ad43e2611826f245df571857ae0a7a867df9659f2082c19f94ce400132e48c7f8de2b102c7f83ba5cd1e785597a0ba0d73bb81bba0c00300d4bcd6ec25fb73105a46122873bfa729c0979d8d314ab7ea52391aabab513dbfd1cf01c2990c0a3612f4511c2bcf0f5a07e659a881a7f99c3f1fc4a46e66904427fe26a4a80a904c047d090c861a075c0ae4e29bfbc18b9620aaa42237f4c6fa76ee7491ee638ab5f1cf0b440759828e1ec519679efc776eb1468999a00f667e87199ad6891e98b95fb682e02517b024a6bb803ed23c944010cb7bad0733eccc12d6ab6030c6e88d510ce92e2f98fdcfaa1e37e41fbfb4e99589c0e8efbefd40473db42b3a73b57b22a2f8c9bdaab16831f1b117dd83a77dd01ee8d0c2e92203adb670f4fd65e618823ad196220d70e014c1aafd8863797c61c16382c2600062683ed3a180c70891717c52da15191b02f25d1715ebf33a5e6037092421989c942082f4b836423cc3e976c9bcda185de36f06265dfc250a27d2de0bc48c73b3bff704f3b386f962522f572108458bdb283c6ab3fd33b3ac13a406268fd5d97e17db9c0f780b4b2a8f761d15a4d8b3a0cd73357ecf4d26a6492ee069f19325823ef50bcb2f73326719a57b67eeef506fe8915a1b1ba1a637592268257b91e9c7c5d33cdd947967efc1952005d82ccef9a3ad7ef8ffbb6b658983d64c51242ba53f8f8963245b87a25aa9324c527e53f8c11d55f30aab598401589acd13f090541b3b057b162190f27910718b02a6b8ddbb8ca6cf40bf0d2848f4b76341bd5e78f476862bcdbe2d1bac84c0566fb45b21388221ecd8483d99fe603646b1a9f38a49230cf4dbe5d7883d73eece01bf",
+ },
+ {
+ "04892b94c65685f2eba438322b29bf8439938590d3e0eb10a29e279d356cb439f6dfcdbc3552af21f7e753221012a649a52bda780bc589ae63b04b981dffd113df9fcf14f17e35e865880a769bb1bf40dc99b9e85e4296c1f2e1590fe02b22bfcaf2d4bb7009a4d692ae4c2d5f0b6d3ca526240368bac55b9b1e6a7b498d3b137f0fcfef1873c5aa2111d7811d45bdc26be1c5d49b8a2f36a999b1f226ec06a5fbd59514485abe696c96ea89dba74b4688101a239b495944e30b3609f73caff3114407599ec5c30a5bad933655de7dddef97018ae15acec46504cd5d417c5052c057ac5f1c6f69781cfdae71db2b4fcac35054a4aa22681027356d68b2bdba721466d130d53ba8f23857631382b2de450232e9ad5551bd7c872ae439e79eabfb057d2bdab8d4ccf02b3003ade2e1f3e514dc92692e4fe5b579c9ee6067995b6c168647ce5a13be8543c23326a3260bb7029d2030ec05e565ced3c5366d20a283a6e95201fd108640d2b96676df712de20e4e12fa53f85f22cb24583844fabcebe40eece11e7221f12c88670bf994ed08e2000236f86258c386b0fccbaab8b68ec6a26fe41491d540193c4c12d1391ab3391de9317f41f505f1f1d09ca9862a6f289a533d2b297d4465c956360371ea3c8ed36e0d1563120654e3a2fd69cd6c9267bfcf92e84cd64e162c84199d6e552b42c33857264b5d7a2e007797cde32934a3f8c68b459cd95bc85e7466ccc9910e8dca65b315c32e43c3a5da908904c42cfc8ab74126919ceeef1054bbdae6ca67b02f1ac5f24808b5eee24577e609a3e3935a24b9ebc1a8dad1fc96abe26012928f2d5782755f3763427dda28867d0b1ad830d3c3f17b9ec278346e5a9480ed23ad44a523a4dd86e65a610ee0de1afab64ace7a3b4918fdc14c6b1ce0ec0903994da9bcf18643d7e0a4e6c08200bb394a89b385d2cb829417eeb0f7dab9fa7306a330f82973cf0917b5ca99b585d2ff0e8584e050077467f5245ecfdd5942e4fc72dc26e5ab2ffc61f996167e68168cee9a6d3ea1e1a696060465e35da8c75a1aa380004faffcb0a992c627fbdcb4e97721271802cdaf08d214ec2fbcb389d75709d7a6b9d35662661c8961f93d4a705e7188613f3769114c55400809cadf60d3b6068c8a5ceef078785171b59be1140c6a754ba1de5ced349df63d67d59d3a8ca3c716ffb506772d57e9e3f2caf7fe346c4ad64aa6c37e43b9bbaa8f58e51bfbac31fa6137728f8e5b728025697e5ad5c8301f6ff39eb2ad595d3cb24257adee88a84fbf1ade4d7550cd9ab94bf48e1424ae83184c35c5a5920157d45805c2e0ad129fc7f0ec3c41b9d6fa04cb8918ef379b0783d1cc2863cd80382585fa05320ca4f9fd90353e490b384ed6c166c6f802cd7bd39aa43667246e8da96992db7537d472c709b01114e95febaac5b1a3c77e1e9a18c2d180e63f0d8fa89f6a1ed63e909e4741af5c2a0e47d4d3f8779b7696358f58060f3f461cceeebb390c92779d30bfdedf1b08ed62dcc05a545bd0ea915f42976e81dd8a50cc4689d8d8007508bf53e7da5bd43c3894968cf0677681c6b818353af6bf8ac205139add1310e5d363ccadbfa0eaf735808325e7f9a6aeb1bee3ebb4a27576a88811859c216b6f84371c43d8063a0d87bd326eb6d81c6896ff534ba2c9c14a51d2cfedf33a5c787279bb4a7ff65706b389756a6191d2f791254233ee047d40d64c2dca878a42f903fd4382f39a89a723fe11848fe37b2008be53f7c2d037981d6462a4eea49df1a2e074957afd3c9dfb4d218a309cab395afe301ccf",
+ "67b5eccb1790babc2dab5e0d1ff3871c3024177d45a2ae",
+ "259603e1c3af3fd0ce3257eb627b02e0c0a48ea2f175de3d8c36570a445e5369",
+ "e14de73c4b17581a7e0d0649",
+ "33522e67ef932da5fa8abe628b51f3abd5049951dbc982ea95b7769652d4830c588fa45e3fcff094c8602b9008d7b2f9bf6c1c4a8cfb515401c7c44a7ec42ccb967722a710199e121a41160b1ec581507e9bd2e2e506b10c4b5a8d6977435aa08e27504957cd49e756e1574c4ccbbdde937de35128b7ee3455d2e665c596c2e97c253c94e405f85eb5de84874c099b4a97eb8f492d28f2e4bc64b228dd5984e76ca08376d7f1355ba8e0fa60fca96635075417d8b436278e0fb91e3bfc7d61ca8c7407086933c061b2d318f46f352099e1d317d6c44098539d1d2c1b7894db668e7a82ff991864fae236570cc420a4229883f1e2242d05aa07e175bc6abe11cc643cf1786a4456a2de8c066fb1a70fe387f149ffbe8cca7b110e256fd0c09b1d3bd7381cfa82fa700c8db1e79809ccf75ea52d0b349264557046e8703a191ddaace00ccfc513db5e78810eaac0a99d7bb1a5725e722d4e595216a0e12f3a7aab2e623ea9e1dad06169914bcd51b643016fea7dc3f2743b1e65877f1fd5581bee5ef206d86494a587ec8462a170746fcedb2c9f99090674ee687382711b4610ddac599732453dc063518aa36f5b4129098fb9fddc02eb8f8cfc2fdf0d904ef4d6d06014f977b29d0e9aab4044ce9c662a18b1a8db1ceea97854e90704430fe9b1046b221b27ac79054fcc68c3abd6fab7da66e255ff0cbd0506c852e961e619615c944cd9a05c25abb63742f5da7bd9939feb0f2f2208c8ce82f551a9d4d70e935dad018e3e4e6998e39670221601c3e34716ba75eb4e2fdf53c4d471c444330514986de45cf44d77f793c17e36a271fc65e6bf08943aef4c66547dc310c7a430e3fe7a54898de48f69f282f52bbdc4daabdb325cec7ab66fce1aea4e2fd932dc1a316c821f5220ea437447feae2fa478adade7cd515a27d8c132d0299b3ca1bc8516c9d9e7c65c38c238c69f03e104eb42a29cacc8d79b808ea6fb233a5056201e3697f81a2d49ccd8b8efd1ab0fd407c16a210767d1d3ca798ee53a4bbf1ce5090d321b1a64fc2c5f013c23829f5b0d2737936ca71595a1d02711c8a7b0e74654e5d76376ae26977dd49c68e3c0a7b36e047d44be42d732c31f681bd7b1b4b339f004ecd847960377acd005debfab13d0fb88355025877630aff753a7cfddf6851e8bcc8ec37b8f9149830f47e6b601098b2ba19a4c0808e31e8927b2525cb82bfddc9b4bcba2b46bbe768ee278fb89010243d16f9679f5ba4f13cfe76b5beb16c7b28daf99b0873098115c2233ee3402ac0f6c899a2cfcc83b2ccc06676999ad48017c4ace507080a26501993327ebdcbd1e2eaaaa99f4998b716cd9e36eb26b4573a03fd1d18047198fdf675ef4f979864ac85d230a011c69d8b6c45e9efbdc2a03f195c9731b4cefa60208ba845c0978e73d082bf6d6a513b93dc805a4f5973f4158f60a200167ca88704a15ac5ab1f38ed455a426f7c6a96b6bfea2ebc1ae1247cfe5ff29ee81bdbcb53b03b89568bae9a6f311d2b20e31c2d91bd18fd93a37be266d0de8015d52e325f78356dea0b77cc76f28e0f06e4ec705d1328340013a77b0b6196f44b7712fff4ae0ac7f6afab9456a95012b7c6d387285487476d189977e28f6c9d1a3f736320d61302c2d627d5a7ac8cde4988056b55eeba27efe7e640f94c115762ad5849423ae138c76f15b47bd2a2bde2c492489b7980aaf1c4e32a155f858d7be4fcd0f8a18e7b5d97c5a08d7885d6d56222ef49542c7f80498a14a8eed1c092543aac3439966d5b5d0cb9e602f4fd795c09d652b64f9ab67e38f48c88d18e30a9774f37e9c77b7a94cc7310d",
+ },
+ {
+ "4ab8068988d4bbe0bf1e5bc2fe1c668cbe58019c958dd2ec97164aea7f3f41c9f747527f1c0e5fdb2cbb9d2ad704b6955cb731f14403dddb1a28c5996707635e4eb5dd6ac33d46eff8e319cfe7cf6443869534ca9812a5b23a6b4ca172afffc064dc2b28197117115431e03c00447f87d9b45172c6f724006270a1d41fa094847cbfac9630c3a785f488c1f5cc407ca6f4cd18bac43cba26ad5bfaccfb8f50784efc0e7fc0b504b43dc5a90a0525b0faf3c8b4b7046fdeb1cad87ec667ce3eb6cb4c358b01393f3ffee949030ef9fd01c1b2b9c5219777eb6ff5b1d7c3ef8d8e3bc2193dfb597cf942c5fc50befa527fac0b44cda2bbb811b06ae87459750295371cd232754e2bb7132807d1225950ce64949b0650531800bd0074177677acad937ee008cc0bbfdf33c6b0552000238494be8be412a3e5cfa359e619d092c76310a76bdcb22abbe6f16b3b116b5f95001d20e42fc3c9ff6723e580f378475788eec265a1ed2087de8cc2eff72184f73fa5dc6e68a56dcfc85350bccb97135386d5b827c2d9aea065708f5c921454d1b9303f21d5adf19e00415acbd86d1e5e42d78505b033a515a435713649c50702f54623cbf31469f355c3be2e30dd8c72b4127764451d79e952ea1f9bb0269da56dc07060d5d9542a9c1258ccefe53fa3f7b6073cd38026256b45c01b6c5dc0d91e3139f30a8d1da7a076738f5bb23352693a8e3cbbb46226fa22416680013f9e3278913d06aee4a62457357f0a68d173a360af5e1411840e34c574b4c6b352f92ce33632911ad8b6710d357b7607ee19679e777baffb8ae3c0fe9786b2e97fdeccb5105ecfe81441f549bc6b50ab84b749fb33f8f6bddcb6bb733d6d5dbc4b29725b8741439b8239e53fa435ea29ed3324202b1bdd07d1987b0e06d8cb51013dad897ef02401290940ce3f2af72c5d1b4c8836299008c10b16c7e3e119e41ec66d9db6929ee09bdeaeda08a50665c052edf77b7dff3d8815046bf71d5015e3bdb29a4f507aeb2e28c536cdcc9b8d1e89849a0683d78f99dbfa90f94aa5dc08587657a8f042d718080de5d4a973f232f78c387b63c7143fc2a4380c491414a18b6c4a7bae2194b62e798ad7ec7d09e409425f6d0973accb17e4d860f8ec0283584cff076d93bd9b0c4873f9c57cddcebe3c3bc8afe793c6cb6b26c4582847b07446b7e1d9757de6bdf0df826cbc502bf88cf3a773866d3ff293034abc4afa3091b2126a278f50e47f2f66ebebb616e342098ab690f7f5828bf8cc4742c677d378893e9f188e8397bee983a9a0998de2a31798330f8db59a8581e1c847589bc0e2d95ffa68e39226cc15cf6cae5c4f5174e7848375391dfabafec202565ec2383721339f04c5c5d1da953d88f18cda65745ee8e99805e35203a6545a0416923b38c5db3c8aa00d64354bed27d7c78c4b257534bd7a18107ebe64d8c27b6afdb330d8efba79fd1fae480cd51fd3626bf8d79fb651b7c6cf752aa737a5123558420d48fc86451b358d270aacfa6c17f343b7a9956e6f64e4990c1b3f1e5097605edf5ce4247819b19f245e9a90758dd42c36699ba5cd7f3ed99a7df7eb155749f4b42d192c47cacb6b2865fb9ef2cfca283865cd06e40cdf7f89d76a9e2eb393e2e0ac0e2776da929f3f8e3d325d075a966d289c51347bd0bd523a5c81edef63ce9b72f5114c88b08b16edbd73f518096240a5b37421843173be8df4ac7c587a17ca6f2916f7d9a10dc75f81bc778a1eb730d12b51555cc414eab9c066113a7edba9a7f1a18092ae47f12f0368ba211feaf34a3b48a7ff5c91b81cf7c95675a4001c95a19d284fe4197fe8823909a123fcec5e45935da12416be1bdf14918414ad19b54a41052f5b8417ddbd207ee01d6a3e62fd9b0321b1c13d91d6ce15ea7b2ea0c670a5f5cb290ca8e62c26c6499104ab8e9fafb05170ede246bbf7313625d1fc9576f1609ffd08852a2f4b73c04f1f4eeecefe3f3eeb2185a618b6dd3e87d9d3fdcb349cc83c21f26b6c662bbb857aa95378e991640a160a23cce76153c134508c68ec54a5",
+ "0d471079ad3c3432b6de852ec71692d12d9df4f984554d458a9dd1f28a2697976da8111ae4454c9a23d1c8eae75bbc14f8b00e7c065bc290f8938282b91a1a26c22b40a6708c40945d087e45633a595beb67d8f1c29a81",
+ "f3dac58738ce057d3140d68d2b3e651c00ff9dbb2ca0f913be50219dd36f23c6",
+ "bb2d033de71d570ddf824e85",
+ "238c4e6be84bfb151557327095c88f6dc2889bce2d6f0329e0c42a5cd7554ab16c8b5a4db26eab30f519c24766b1085e11d40823053ca77adfe2af387b4dcde12bc38502229510606ff086265f45b1087375dc4a022eb0b641101c74ad566ab6f230133b7aa61861aa8202b67beddc30dda506691a42032357010d45adc7ee633b536a2fefb3b2143837bb46db04f66a6e2bc628d6041b3d306ff78e96205ab66847036efa1fb6e6a387cf8d5a105738be7163df9da0db48e3d8fd6a786f0f887968e180ad6888e110fb3d7919c42a7f8c92491d795c813f30ea645fafcddf877f5035f133f864fd0ba1415b3d698f2349ebe03d9e76610355e7fc23221c5c72b1b2628a40b14badf93288fc4abeaff5306d274f21938650ab236a39496d3f8a6e9086eac058e365d4335b51eafac813f9175bb7bebb75605909ec3fde6515694e119f7b6e96aa1d6d6454c3a7dddeacc83bf0c1f5f6c2a9dd2f460f3e5b074a33b8d7904e6988ae43a22a87f0933f812e45c4c518bf83e606bad4c3c55422ab2207e9d3cfcbc5819049f55e35b9663273d9d3a6f8a897fa38b0dca77eb6c344290cc007b68d913187f2cd480a40262623a4e95d90d5701ac2b9d858d70a27f0672f919c2ded1fb89134ac9a8ba6ac62931c832372abb70e811dc50cce264ece65e87338231f18ac007c5f68f3b1c5904ffbb2e1dc361d53914917770d66afe28c547d8cd5896d892cbdadc34cd6af348c93bdb8b072f38b085361e62ded7a38b4368824c759ec7d2cf4caddb9191e5deedc8b8388bc4ba2c0672321bcda3a7343c9ea71ef03750912f35624d81da5fa8a6ee676c4efd99d0c7258b844ded7b35d8c8233a316b508d79c7c0b3edabad5db9543615179b1c111bfd78b79327ac5b4155336d670baa592d441c810cb1b7c07f3d35473a45b57e780b7d997782aeecfc0363976fb608d6967844ed00b63ba75996054d090aeb605c195b1ff86f9d9ab5892d27632cbb59c06b3ccd69d33ed5dea9398f00b7c6404fcfe2fcb5924e4cb75cbcae0a1b084ea8b15eaa5847431e9ab70e4afe15b4c82239f6165e243e3b76d6c91d23b16edecad8bcb16898641f8e323671452034a8ec9b42b29cec0db210bad0444f1c5bf3505cc41d514d5a270d556f0a34333bd06cd6509ba253a6ba7a6db8f1a60c99f0c3d566a038a72f1271a178cc3ff890b0df1e7438c0c1a12d9873643e2d7bfeb92379545de50834abe2a345faf7ca49beeab87ee516dd8598b71196b8cdb15e7200cb5bd814338babd74c565faaf33d9a8ed4209b417345a1ae611880ea22ab2e894d5d14a28fe3835d3b2718125f0e6daabd85327455646290ceab89e579ed5e1d72a0172e4a6d8da70290b5022c941f3866f96cc4218de5d2622d13af6dab15760a1ec5d10918267f9585284058aba611ba07b1d5711cef505869831699bedc2b190fe1d578814065c91d87a8c8dc9b0d4dae0c80cd241f0bda3a6d5e714c894b7a48b1e5eed4555f103eb03c9db30efcb855df422d7451a6d70f28174c7ebff536dd2cd2891f6c3f264d632ca924c4e0d84b37cf8e06e6f2e29efac6cf008cc27f062441278dbc9f09cf44987e0e9ca088a48437b0b89efb9cf00d3d0c5fb449fd4b64e21dc48cf300c2d80a502cb583219f1881e78e647783d91dd2f3b389a1594eefd8ea07d4786f983d13e33cf7a34e4c9a0ec4b791f1666a4eef4e63bde7a241f49b5cf615888bd8130743bc8a6d502bfc73ab64d1184ead9a611832b7e24483a1a0fc475d9ff6166b86a18a3dc96910ff182cf326456c4461ce8acb3467f801890eaf1ce0b24791da9c650876e718c0bf43c475174f9712dd4a228695e8f8b2b23fc4a06358b4a6a8e1afa87a0280c3e098f218f7a6d6bd716f8c105a7eb799ba0220837fa5a96c8a22a826a6f7ea9d7216a24acbc7b0133210cc17c8190507badb421bc54997ff9340cdc1ee415126ac46a4fec9fee12d40f06300f7e397b228250f36d6f0d2ddad5fe1898ea690e4c7cc3a116a70bfaf6d2dc996753fffae40ba5280b8356b7ab4ffbc914ec74eaa070581fdd1d9e5aa2",
+ },
+ {
+ "4d81b652fee892d575bd13dad913d976cf0517c819d5183a72eba995b1f27efe743451721ce34791a15a6b7a6e44f13d4a080563dd1d9d4f0946e5ba3863b9ac970a1fb4ed66458ec1b1092ff5fa6c3f0271a2df8e3f2e97851352be760b6a0e1589c202f00791b1b89ae0ae944ced96bd90754bcfa3e355b735132d407d3b5507fd57f705e8a8bd82886b16d459ac91e921dcb8c5bf0d7cf420a9349ee589a5e2e19ce7c944a54ccc1062a0690f3152300d0bf5cd1871c1391bf6d7007f7ce26018ca2a5c6f76287fd8c8e9e7f93b1806460dd35f7f95989a8b6f9a0aeb7c6b0346955fb50b8735e34f1ecb4859e34ea0f022ff6fb797094206a34cf120b7f4664c531c57da513b296f0671c8e9bf68d9e1674998fe52da04f627f516dee97c2b3c988216e9bd3f58c3b021ac70898651f1cfeaef21c4f417ebe92dcad3aaf50f4277262c356584f816a5a5862f2bd720fac10f1b86033371ed603bc00a30cf4da8f579dd5bfdd571a37af7d2a5cef29f9001bb1605ee87f24ec3b259f381a69b771f78d21c4e43bfc83a916e08830d9885c8ae8ab6367c05f92e5eecaf0488262300f83f4e3bff177590857e149216995bc52311fb9f16f4cd74e07c7868a39b699bdbb7d7dace4c6a53ca7ee6e11741a63a52a1d96995a6dd752356dec6f14761ccfe38a6cd8511204f8f0630a747d6e19a77bb030c61e0828436604a28a7acf4a5e49b7269ac93b93b99e9e2e1c0c47b377f7e44e05ec6659526afbdcd5bb172404ce5a9f8786234114c16f20cda6d4359eb873a4a4d9fdf734e9c40aa4db3ea9a98939210f6c62142dd144eb78191116d194bb766ea96da38321ae27fcdcc196560ac75567297984fabe6072c771899906350f74de6d18518eb6898b934b11e945d94ead02b821fd6682602e03e9c70a1ec67eed33874eb24dc83dd1035fba5928f8f62ba1282907aa8935ae72fcb881b3277ee6bebda8fc75d6cd792677c25f70c87b11e094298b2d5f39904be211ff0980e5b83e8ea4a455622d8be9efdb5aa8466c88ea861407d54d98112faa10293af5e16974861dc9f83b45d21b112cc367894c421f5049e49dd205bd7c15e6a70bc810704e2e3a3659800864912527f8be743acdc474a26246a81fc2bdf669b9be7a2a0c986432e1e44b5675607e7e1ee2a8dcb72d8f1964272926e52f909ede0ac8daa32d1d850158db76b959e4d83c9da4e3bb23fd1f5b26463045d6cf13d187fe74a50c09a654d52d0e2f01d66b9f8b4f4aaf4c69fa62a02aa876f9bc4871aacd26a6c6ccfb9bea09cafbd0268b5b65d60aa23ff504d02fad4719698f8b044ca1bb037ea6af58a06a448080dfdbe6a5d698d5db9da5fb4aed04a46c8fa8b93153bca00a5bf8aab64d2b371d072db2ddb688a9442e948f0b99236828dc115a2fddfa2a29e2d4e02ff0173cf734efd4eb687e3f8712be82abe1fac4be0c1eddda090803fbdce41bccfb58c43038991ba1074b281a09bac5eba58a99a1a9678ba26f8f9e3c63ba095f02cd8f3b56aadc5de60477efbf3dcb54b854f651cc72042bf19268554c61b44f2f338a75de56c3c45b3ba40a697f5f21c4557380c777bcc91a151e5676c2a59606200bd476cf98d20b4cdc64bc3b8670810a014871be018bc32fe239e287cfe8a7cbcd1e8b55e08692ccfb4ef871cf797bc0b1fd7ec37931e35b6bc5d32bbe7ae77b9962c179f96436e4a32f566298d2235acf921e38c3f1942fb7674b65e222d17b95a2e58f072c63aa4bba1ce48c303f4bd24d84963f18c5e670015c52342dcdc9c0b348c7dfac721b568effe2bf2f2e816ca3279bbbed823beede8e12fc5bdccd0f1584deb1f6ea1875e9fb350919b675ccde0178bb83a4aa5232bd5e8e9a1b8daf905c6197367a0d106532297ef89f3bc690b48224592c768bd9c50a63d0881370d475081aef052b444744b33fd3fef674a37898fc950f887ed482d2a51ae615ef5b1dfa3a23257e6a6a319a4e2080b2c4094bb09e4b390d1fcbefc4d6c5dab620f8b05b1bd5d976300b007e2b8120ef8a6c9028b7d925c795058c6bdb6711fc5fc2476b9810d1d81bd24637537716edd3b7068b802c531531df710d3682f9865530e1ed51b3b56d860ba4e972bbc74662cdd1e2ea24f81bf469193afc02b14143a32e9556e3f2ecef97c65",
+ "2538d98b64b6aa9258f9141840a5abef66d6037a10356366a3a294719c10d6c148b04cac66f63ebff052d730f8821f5e5822d869573bcffbdd636c7973433abbf38767597da5186df8ef9df071bc4ecade2633366102313e659db8d8e0f293d379fa2df79f456497",
+ "a5049b0aa153e282457555bf6f82b60fc81aa6fd1c2ea3db031478ffb74b5b5d",
+ "350287a6bed5709dfba3d35c",
+ "849670914f5fe318eb01e8849e536374ec11e813acdbbe6a5e82a506f6aef4f916a3a7fb2e41db3adf990175e21f2386d1805af9bbc32a6ac156b13b1a9505958f68599019c4b7297314229c467114754277b10e9f49a4d12837ef24184629c8902ebe2a23f740dc826b01f8963d47100bf617b314835e436104eb207fa9a1079b8feba06d9369b9aa8222d38d87096b73678bc5db9a1add59394530e678b6ec93a80efc6e8320f2909e3e891306d69b016ade0d30cde64c2c903b401f9d01a29b5cb8619dc68ad6c21900b365a6b657f7d9ca4c145fe598a94eeea741e20a9329996b17aba5d7115c93623f2f5d6927068d0f190b49eb885429d771bbbb3980e9293e4d664a71c3cb629d869dc97e58fc3d328331b11df19a38d61e1705ec4c3d779168abe049e9d675337ff658e00d2d610c8f227d1341d1c41f1c01d8b5d83c4b1b30ae4318da9822f46402ee8cd5cfe9f3f22d90a5ec2d0aaa0baa85e10f5295cc6005c5a0887287b0c867a23da1a4c2196f91fe0bd4f0db1ab324c26fe6088d7583f3cd052b7f6fca38e8b21f98fd07fe78b7657da1f586f1fbd3d2b4079e20f21dccc0d269d53a29deb7c7fb63cc291d1d2c50ff163e08ce612310d3bd622f2416e193078ce4e1463f8a3490578af96ca98e665468281f1af9117a2ed23367df19b570885de9d6594f09aaba4090bdd1079720b08d54311793c97bbe14433b031c865b059cb4f75db74779b82c4f83eb4bd829c62eab995027b548063d7cab7d1a6f9642da6cf7181c0ac71594b97fc2c84b1768f81eb287091f63c76623c61e7ba90c922c74d46b9ae5d8094d9752bc1e8020a82601c356a201e0473d540053c707a88f4baad37826152dd245c4cee6b0019583c61e4327fdf6bdcae53584cdba8a503b835bfb5df9d649705fcc1f09376eec96c3da1e105accc1cbc21d90f527041a9beb85f8cbb1ee8db798838bb45374b741618f83b5d0801a3af2f640abdbe74ec3dc15d6711b4c1480aa8d6084defba82ed221ba359c9744705c4feee0955c27ef468cbb816694516f73fb541e0ad4ccf99ec8b67ef090505d1f7c4c3a8ed7e291c820261f12d92bbc6609da6c275349819848c9112826674f243acb9a29ab73f17c8f8af12c7437c11972c824f00db7ad284e51b9b508a925f0664bb259b4443d56463bffc9e5d845c9b9f79b24c1f457088fadd281f48238866e0b92d6253638eb188bbaa8bf6a81d2b1087904974752697cffb00b4ba05e5b7b842a3d2c0a743e4bd691625788fbe9df14600643b1d161bb2916176b6ee40aee38dbb594ec2735d41369ed3a0c6dd9073f1eb51d1b77eb9a967b53670a8ed755f3b2b73a6cb50a9e1ea7549346646dbe4b801c8aa642779d8761b6c2d2e1a9995e758ab92f07c4eb4a23c042171a4b354f434ced5f6d9ccd26cd6c2506e5023dc076ced15566fdabc7364f4a8594cd6ec404e1a9470f52a83052390e4f7789ade9179b069d9f84ca2c7ac9eea51035db817845aded7405bee90cbe92364c8c7cf8a366cbebd7a972438f2a9881395a8610a2cd0c06c46b60cdae5b1f473f4fd6ec48479cf35101656f05485198a470cd36af22838e7ba3e28863cd8ba7bbba7e3c2625c1106a6be44c9e3d9b9938679b26f0713c62c3757a2dc8b2d9eed5e652220a7711cd220bc91a9afd7c940dd8be71616ebb8b2cb0686dfa161c6ef56994a3cafaec5e79bd0a2531fd1c1a42771acb101a38988bcba51ad85bffcd8c67aebec5b37d526b29f7b9d31388e1e7ad7154f8e65516f0d80a30b88c2b868be2541d19ea1d2bcbadd30e2fbb1b4678bfef7f200e0f8309ac0701000c52ebbcd6fa00cb85c8d3ea9c5aceeb3adcf3773cfb3bfc9ac764d031d7c63ab888e9b03eb9fa74554dab4719d426d0875a508c8c86b22cabfeeb70b0f1461db4e5f639d2a2d28a089dbcc48e3f34394ff1acb887b89f75d3236c8143bb9b06273c3878744340ea1858a9f383f8bbdc259250e23a3c3992bf8b7ca7e1a66913547710402bb538a8866772d11cf4214060ed091d403e1c9ca3af75859259f88656a1cfecfdb49d57c193e60a2223627c681a2fbc7390140aeddc19df035a5207adde4f5736bc542bfdc943ae8b094f4a8701618688fadc2284fb423f602c41ad8ee11e5d9fdfa67fb7dc7d4dce7847d4875b3af667168ebb6082f6911c95",
+ },
+ {
+ "67f0494a728fbfc84e2f4a043e121ee40f3b12b31616c78e157ed970db28674318b08d8b3f4c538d7b9d91b9b0b09ebfebb07201c6398fdbb8684c9390b3d6a8636333a3b086302b24c2e5d47283935d33065efa3fedd5f755218be5d4618d38c5c1db75470ba06bcd853f3f08d39c3cd9fa3618e70b103c2d9b2101fcaf39c1701436b720d723ed5c622d6535c9a10ec4d727abe237e80fd20911ceb84a90285fc6e07f9d036cfa65995f9b6300a927d7d0d2b907bac9d9c4daa87c2438a583fe85029c886f96ed08f5886bf53292cc0265850a1f4ee3e3288b604dc305d0c28ad35e1242f4ff4ae988b6deba48aabcad2fc6cd7eaab0a63510f3f915c4bb9f9719b1d90db123f639d9d4f3227eafcfad769c2b204dd2555dc54e738909122022c4f92f751d25aef6f9a1187750e825c68450e6d1223c2fe88aa27194b492b6788be6eda80b9b9f053cb77c8d9fa15324f23af5147624fc00c66e947b004bf38b31e1343c7cd341b98abe462a5f994e51d343664968624a2ed0dea9d0299d5c5a7e9097fa63d8b3ed96f917f693654766a9adb01110fa3fe0d8e9b102860d5c049df3fe00ccb2ed62ab05583e6aa0a5134d55245d4f643e274def29d3fc86d79979d599458786a8338b0071f6a01609ee6b2e4bba9289e2df780bb27491890d0b5ea650e62df819b8f98aae99a1b8870ce6d3c7785ca957d5b4094946925751f0fda1d62a9aefe3937a912c1b49b4272f87eea7e397feb84c0702929959e38a568460811e5064b1caf5dee53f920c6e19fb16fc9214b5de1cb770b510533f66d8a0e7f6f04ba8ba41869f8018abee31a6042d3919e217359988eaa9db2a10b3caf7aaba43527484d81304f0bef22165f74e9e1031b545ca3d2f74195984cc237b76ddbec85142a06446902339b1883000264031db85fb19b46f320ef3fe316f750f2d3d6070dec5b66ee8ef20701f20965f5171e44c8a99bcbca7afbbd81e30e74c6d48bc4b0d72baf562da6581fafbe14b6cc597f75e53b305036ede219ec56d0c0d29571a9c110ffeeb747fe56f6030dc26c8d3841b868a1ef56840932dad9f3bd7f75573086571f4d9f0d949510a2577d2f8fbed7e850c73ed4c071bf9a656d09dab43a610b49aeaa57333f67d586d4f50683dceee4942db9549f68eef4c5f8df8a2330857cdf2fc4025f2be7d5f0dcdc74a9cb593de91282787b716d416a3ccb8d6d40fa3c70be4ecfda26a5caf3724fad3d98db16ab6d8f26defc68392923b69664b0c2d56f01a549284b042bbd43c8faec940187f190aec08d06f9a62ab03c9f610f64c0010a0939451d5502511dfd3da1fec5a38f64640c7b6db2961def257eee9a3eff944828e9557deba68bd8e42dc7a9c1570e35537993061fa0f5351fd3cf4ec36386ec4cdc5a2882d5f16703b900c5000efa63888d69982e5ecd3e329c8cf5f003e23ce03c55631246ca15ffcadb0fc9d5634252ccda812ba7bf5e343c44244026512062a68374ed4d8add0855dcc22b30148e0cef0f2886be76bafabadf3ae1205b43c6deb8a41c338114895dd6b49deb329ada31b350e02a1bdad4eb05b61b50f9d22fa2863bd607406f552713e302467ddc78213d584b4933202438d63f99d011b97297f5589f35b7e45ccbd76f02453b7a7668c2b1a1f5d1d63eb805c8881771faaf67433eacfb22f9b6fa58b93f9423a5fcf667aeec39751ae17ad36992556431bca77059a29353598dac12bd3036633d2ccadc18f44123e5bc074f4e5ca380095af062fd83b647015259be929011cfbcdc9bc5d0dcf9b688f0f5d74da95746f447a9e1cb5028ccb2827b45129d04cf6990953a6d8ee0e67fe6bdbd8004f4744cae5607fe7ec4a0f14fe603dcead3367b6870d8e751cf57387d04b881f92cce9772d695f19b36e2db2cf6a807c9ee83225f5c09a11b50e99855921a4eced8e631af7c234aa31615c00ccdd7c6ac5ae8fba6e29cc233765a891864c7d73dae08ed1a3c27cd423d8d4efb550597afee8356c12018f496637daec83575f5e38ed2fdbafabafd38483c239d31cb4d104e93d16eacc6050033a3c86929be4ca8914a538bf540b43d7ce7daaea317bee1ab80504846554879f900d312bf2fbb406a0edc5f4f809cbc68675b0b7f09fd1a8a4d52c0929b3a8b9c1dae4b3d599b976867e6a7e8736450dabf5c49c949544386a71419324ea4ce5c4319899ca510f50d07ace57b013655b0929f79dbf3cd629ad17bdd10109b7c53a4f5f04a16e5471e823c898362df43f57ebdd1627b33fd4cafca6cc065d9140acf0454d5f99be47bc87e0f3b4d4320bbf0f21e7c261bb8d5d615963beeaa46bdbe9b83a8277813ffe6132b23564bef5",
+ "74dfdc364097c39ef91c01b707a522e28edb1c11529d5050ff820234e6c0295aa00591e09d547e9671804d7825705ab44b76c59d1315ed1297ef477db070d85076693013bdafa92e2ff6a654660008b176cd4e8ae23b9c792be3f7db54cf2bca385bddf50a8624397cca8ee3cb96944164e3cb461e68",
+ "b3b5ccd7ef49a27d2c6d13c0ae77a37abec2e27e0b2d3530cdbb7f36792a7d2c",
+ "c0494bb7249f864f69beab46",
+ "ed8d6e964bcde1df68e7f362243073941fd68ac77929c8e480c89f519f748b3dc337b1af6231632c975167a8425b174b42c2c60dfc0ec85a0a212bf5c9aada818a83f9664c8712d96de1036b5e5d8c8298786b753638de3a8da958549f16eb9c723355cdf7b999aac464ec39df7d6c1607e81b88b63043d1c847dab618f1b19336911b4b0145c2a694e61db71e021282006d48e37f10f3b6314dd012a07618228532c28ca84a936e0eff83723d117b2f2db857d14af5bbd5948a0e53018b31e57cc2a81f36aa013a844990753ccb347fe98fab294cbd252a8b8f7246276275d2780511fd3cb7baa2fd1548184f968c422230f7ad73ae9dde91295f79f6b799e7d234dfd6573fee6d6ae748b0a8cd7ed4862ebd957390826f276c2afb01fbb4b64b61a1bfc138508efd630e77580867bdc1e96a48a694cf0db6c2a11f05dd0bc8769e7200bb0749f5798b6f3559de55d0c281eb5df22b731fbbc109da9c68f209b888e61240c4c0ca006d105c0a7f43144021547d3316e5a99f6c429f9ea2f17d77dc68bc9d5125b6260f79bc8b3b8061972e6757d87b6544f21645c0b4debe5224f7c48142c09f35b8e144c0c1e6521f04c170519ff744d61abd59a56d25a26c5ed5972191b25e78e2140f3ce68fe17be9e59a79f6c69619a79b83614c670c7736d19c27fd22515fb5b896a6418cc0b4850e85c07b38b995cffafd9f69763cbbcfa9d1bbea6868244a66a5cc82e815fae09f5775d28437634926d571c2b0d200855e09cbdc67d10f85bd4cc334ded4c83aeea57f8e373a950f135997666b653e8de47a3bc0059525720045996bff500a47baeec97808fe971d7693dfde339e8beca3598fbc053121536c30d0af10f8f5d8e5eeaaaa9586d7abb563fd69e88351f93bcc46520f6d97c1a49ba9f8f6a25cdcfc11b2a722910aabe7435ac8f0dcda9f824fdde80850f21a2d4bcbfd2e9fcbd14dec05c117a9796db49e2f0dc55e74c7f0f615bd049fa7d0bfcf197dcda3ef3de90762e6f6f9f8a8936bd04fcf2a97cf18ecc8f2f118ffbf02b67f252097e4289d02f264161f6f90f79e1e1ef8414b01a9e1a77b88c039ad6eda6df1e28fcfe9370f0d574aa9e857dcebb19eb7ce8af9b19b4481c9fb3e1f0db3b02af483f737ce3ea824b2165e7c0fca8585383d4b0a16eab2c7e3ee5c038f939a97bc8e1c093cc5372ee45d81836c988f3ab3e6ee0e5f9549e4b7bc381a2afac2074cf75ed56b0e757e7966cb253d549fb0902da98294c6dd4de3c2e166b7e45098d2729b1393deb68471d4d3218dea3dfd0183b654ae4092a79357945eea4b28cfd06b40d30d1b4b8f19827895f6f908f0fe511f74ec84cbab2483ca4bdfc6ef50178eabad79b18b58529c9328c13c52c2869858cc20ec36ef7717e1c743d13f9607bbdb0b701d9df6aca7366814e883d23e51ee5b0f20ef70e2c4134ab037d213315fddc89009260981329a1872e541767adbd5ee9501e7df4ef0cdfae9769961f8716ee7dfbab0ec89b3f62e987387d5842e124a69b07245d359052ada50cfd67472d27ce2c4eacb5421b62dd7331da54ebf0989803797f4c8c781d0e2e6477b421c7d5cefc8146aacc0012af3f1f7cd71ce2b1045d86bf48c9a13fe469a1865294e160b4975023d0eb24ed26837afefc250a914f86f8b1f5d67d65e9737e841519148d4dd5dbf2b5a8b073861288ec9793d4b113d71c01727f67d791852fc3946dc912d60fc66bffccf4c45d859eed9f0bfc7f89086df5d5cd830ac919aa7cdb4504018052d67f6a3ca012ed69187cd5fbe91875cfade381bff1e804ba59cd59f0f75cb46dcfba234ab9832c3fb9aa8dde19fc1fb30677ac1793a38d94aefd9ffcd4e777e9e4f6d49e0cdac6c16a36bc2f3ed8e23b80350e3be6d866aaafbc8cbf7c69fe44c2aa80651164803150c23ebe262aa669c77ca94d215895d2ee9c3e325a0bf2c61e419a41e0f7b1ba8ee0508307d49301abccd5b74c054b6c7bd1aa67cffeafee033761d8226d9dbd7214b130a867764062cf4da685deefa23693b8549d5ef5e53df85c19bfb3c43c6bd073e7a836f849587a4747e1a9a3c7194f6d5472d2e3e4c81784a3061fc9bd3b94862c4784974d859134369486f2651f1db94f511c6f59f41da0d75307191602730b88e4e6101fc8d392c87687f3be454dd92fb8ec380715bcd88aadb63717cbce4db91a36821a572c363759d8d0a2ab007e5981b78731dfdea20d900b14f0c5ee6a4a9b532ed2134e6edb4dc267f001cb88dbe43aac4aad453b839d035697df7de98ca7a9ee7601228a79004b89796e9ab971aeb8e62c789bb21f38b77b492c57db402bf6a42ad0cee169e9251d865ea3e5f79b1801ef1e53797aa6c7060d6f9486081",
+ },
+ {
+ "04cf92a64cbe135f7fc1d7223b95e41d13f04b482018039f4e7ccacba8aa15ac79a752c5666524e527fb076290ec80a3dccbebfce3ee9b316a65fd130f12bf88b9124d1f7772049e6d0c01fef881a1d44c8dd02f7b6b60e6d15df9e06fb86929cab64842284de09659e19451623525aec2f5dd3e603e24319b1d120bd57b34a0317ce25ac9c2f022a4847306b998b57c8d92baeed0de1f6cfb3177d0acab70de275238f1152813b9ac87bf651f74e1ad079b9bd779ba4374ecba459865b5768d08ae7e1dd691d6821895e8380ac9e5116580e8de3a2c5326e698bf4c4d35d955e45772bae8483d01de2539e8ee1ef9539ee132d80d85fff41dbe406af319c0d7703292587bcf5959f49241e2b03a364e1b682729ed261d0ae45d74d77634afe667413ee210983b042a7ce6dbb61c29d18450fa7176177b5a74f032ea24e1d08b220f6d32a7a836d1241cacda39d6acbd26a62f9dbeaaf7329a291dbf0aed4a2cfcb85ea360947585b1215feaf70ba71eb2d6bb7081b2a21bdcbfdae6ad2513a9dd714d3d06c2c2b7e322a1db2d48f9df1fb44fa066f2bb42b196295ebb3c0898ad55d5b317986afaba0bd5e754cec773821613e908ce2bba6454181f9020b73e758df18c255c87df675cc6bb2b8d2eada44196ac10c26674167f94a79f4be515d8d6a1fd3228dc9a85a355b030845dd4c5f481d5b6e74acc66de730629581b022fbcff61e5dcfb6a7f511aafd577849a6b057021ecbaee53986159c1ba74c3e930c34a159f467f1e9799cd6c1151067c56769e43308c96c8edef8aa7634d909310dba9af2128cdb8c29b24d3ec2a4f43a1ed86d1791c9a670b240e6e719f01827aaa319bd3ff53959a776886a1b7c942a54f141e6bae8576d294e44333e6c5ad90f74863f69bf890126016b318e0f6bd2f0adb9bb861118af5f6cd28dc93d56c8a1dd080b8c810ca29267d410673fe367dd9d1353ae2bf2fd88d57b4202c21aa49f12a01b93acbe260492367bc219d3afb6e6f35502f6529bcbcdddce9fe8632efb034a9eaff8b4a48afb105d04e3fcbbcae010ddd6636992213750b12fb3e01ab72aa957136e0bae591bfb5e0fe819cac82a98ae8df230af399160594540640c6b1d537e7b5f1cc47b08127ae02c35b846de56c4c08773fa18d4436e14b76a7fc4bdee301d0af4880306f2f33328ab79f6f24ec779b2b1928704f09bbc5b0b7108e9a115e4959df79c80eacfb98649a0788867e23b2974b22e654ddab0494bc922ecdf17727d0f0efde9dea7601857d890bfbacbd93f7df794bbc254f50e1e17eaed2f5d5a2e6c58083aff68434730d406fb9fd02b0dd7bfb99a04aea812b6830fe5e05a044ca21c77a174bae8b58eefa11ecfcc1c977bc6218064c9931b5c92f13cfd05799f11e130869c293c1b08dd29c899365014fc8195514b286c97cb6dc4b8633e47751f87fbaba137b6aa04d072ae06c2b2f34448449f60b1272c1efbd4722a2be749a3d2e5450aabef1f7c51bd8324607668a8caf8097c2f358b1b09fd3525d47ec9a7640eb20ffdc17c4f7eff63df75dc7830c471ace3a727feb11533d6e9a2a08106af33069cf482ec63724032e81cab18e12cb5c4c3ddc374e2f75bcc99fc5da09b80a738852a14e8ac552b8471c6ad52e35317b730db2c13c277e06c643e0d0fbea43833de4d2c7a9247ff040e9c56f1ff7ea92049c5341c4d1478a14275a10119d934e8165152b89951bca7ee1399dd8232fdcbf831d8354640e698b68799d060ceb877201b2fb96cec514affeb28721e163e1648164b9e5722271db9b0ee1a7f96819fa1b1590e9daa598d9571ffa3882db9d034056e9b2785a8d13686eba61d7d45cf2e9ecdbc391739ce89297211472be18b21401658c5bf29fc3615924382d802a166d05dafe7876e70a0d081e80c63632da379766928a0555eb5e7a238cfa4da267527c66caf34dd40055f2801b29b3f5604a5bf3d46048bfbec2e24abd2fed2481698a4b5cd71f5d2c12dd473b903c9bdb978eaff7d76fb69951005681ed7b0257054eb3dd6d10097fee51ba7e8d565925e4091cbb78d255c9d3ab4ac0264d172c9bcb0908db1288c9634248f198a1167daa323822058decd83936985f83b08b1e7b942756a7af200af168fb8a091107b4443fd649cdc22106f9b9657c69f19be485c23b2c715b3762c332eccc44f380883357d10019f20612ab6b8f155c2af9e2ec340e5d8f45bf5278ac1fbc9f9f44d2f615d21007d822b244b1c7a0dbc182c7f5912485d6e4d74e90f60a2f964e028c63d49c6aadbf1df170e4914ca514139ba538207b1cf7caaceed4db8423dd1086b2adf15f6c0e50dcf2e12898f53c339a745316904ae03c38b417bcd7f5cd5ea77a4f06e65d56c24f37ebe72d271ac79b6ddd2bb8bd67f0727ead49737aa71af4f620da53769ca3ae878adbaea5a249128074ca3ddbbbaf5a68f9cde2a0e8d69708b0ea7f4c8d2dd4180882bdaacccf2a409a681c551776bd10439fb12b7548342532b371c0e045d8e8c895929464bdd4fe25f0533c66104daaaffed52446094978bcbb389c",
+ "001084c8a5175c0ad43108f9215c35886c82321c800740c6118a3fcd45776a4588ee0e2d056a37d99b40d2bd9c0845088a77240b7e65d18fef105d3488c77910b5873dbbf275948db5",
+ "d614d2e671066e387f7eee07bca9f9313d86e6a4d1371360900d670e11ecf1e7",
+ "674a516f8f59f9067e0485e3",
+ "1ee376e9e3c89b2147bcf75480ff0dec1d0e8cd45ba812f34c84124871d484b4ca87bfc8cf99f85ad452c482933801426e2737a97468809fa36caebebe8eed07a626b3bc3614ef1ceb54f9221ecb16f413f0bd9ed4b3010c40632f05223484af7bf5948c2fb8a3d2ce04c53e3f2682494f3969a0f8eb738cf93c0141799c9e6b68924433f0326991e19626bb19e6fbb5dd46baf39f92e830f9b1ff465a007f031891fb1f1799cc122d3ae7a55624356b5297bd5d948d9ff2e414cd8adf00a53524df43f398938d33c93b2c06bcde2679566c0a7b0177b4a873f35874739d550712d5cfe3d25c19292ba97c01d84224738bb25546e5c252fe5e5f260ca881aaf176a271a6fca2edbb2cf23ae6d4c56c20daadadb8205c2e33881867cd67ae6e59132edccc3601f014b744ff8eb6aef5e09b358607695d3af42ab8fa30e9fdf99ce54427ba9da3699de19f7a8f9be368df47ff0607601a91e7a5fa6e72be50bb32b825427cdeda3972a18a23af290986cde14f5fb9cbddad336f5efcd2d7a0cf3d5b23e54b702352fd5ee52d7e3479441497d56e17d5868574c56cfc421ee47bb00e9c75b84262a1b9e2cbfcccfed9c4c386ef0d2c1be9a7b7556909b5d72a38b7258acdd624de2396c75386e077c34f005f92a2203c82d1072c8998f03b1df22de832ac733977705453b1d72336b8d371cf1ed3923f462ecd22075de5df68c83ab1e6648ede7fd5ee5794a744abcb32af73bcb182cf97d36f37c15535c4107b7c8f2321f9fe0e2b6ccbe74204df3d748c05bc1e0e2c55ae1aee2d4aa4a52e98ca7229d6d06576196ac8e4b14a9ce807075cdc876aaf904c9962741efa8c6caf41e6b87b2ecd6636e2e58f3ecf576e5d8b895162545e618960ff6e336ff17eacd5a1eb335001633fa78c41ed05466d904ef9b81b643a043298c0e291a085e4e67da72e329adfccc407f800709865147db49cbdf4232073b7bc7ad89b3dd901d927ee08ae6497e0f2f9d052ca8d7444d2e2ae2197f930a7b1c8af38d8739ad298464169823684612cb628c484f710cf9c552551b6837b575a43275100bf800b7a3d777adc44d07f67cee5000422b9049dcfbedfccded0f2aa4d189621579b01e3fdaedc4d772dcc593316ca85e7aa248d219dac21c561d318a4936ac0d3bd5c75311486c174e0e2182affdf69bdd6a086534e4a602efba2b9363beeb5346539b45336cbaf479da6b15b226a9ac026482216dedb84ae3443b306820d9f05f78dca7090d727c7481d82c6e5df80e189e24e46f5758e453e542bd91a58eb51a89e07c50afb543c6b998704432e863dc4c0d0236e0672835a7b0b64e14f5ced2904e54da4287597f920bb4d542c35d3b0271cf0eec055656d523d7d2cbd667445d3e8634854f8616b7d7a7f3e14fd32651e9df40e1daedfdff1371f16d5549ed5646adf2d417e4b3a4d145bbe0974ab388c2716861a08296b862e4fd035163281457877eff89dadb160eb2b780414435784804bf4fd36602699d8c2f6a8cbcb509198c38e2df2edaae7bd7c93313ca98a9c2d24419a12ce35b0b3d68c18840e3ff8739d70969927c7db9a6569787bdedf5c99948a9e79b2302a83a71159f4c789b3b3f05f1e574f8a24c899ae3457f8e73f9bd86976fbddd83b1af337eb8da4c0dbac3792921597e18a2fd3a0ac89a270794529d370d36bb6dc7452e754e903781cbf57c8646b92d5d02842e7df229b3d721f9b981f9d61a48f00e53948a5dbc4f739849609d94aba3e3f5f8163d40321576cb8eb8e89953b608a01184d41aafc13f40c47b12240e3ad49413473c26b6843f4514be221c2af632d1a54cba230457f23f00b2608485c381ae03b389ad0a1671fb416de4659cc7f7a9c4b6d9807789c307d061fcf613b96a2d79e5e3e20b863c8b1b75f35c982b40ac8dcb7d2712ef7df94901facef783e8015a9a48574aa6f0cfb0bf6c1a3409028f8d62137c347f5a35ad6a3cd60d71aeb29bae56bb4590f69226fb4e08fab7a9f41e58f4d5784540a70e7a97720c549c8440b089eabd0eb3e4d37a2e54b1160572ce568f4256dd244decec31fec555017ebf488e878945383750eff26a8a1cca73e7d6f52d8cb229d5603360a3bffec23029ee34145c4aade82d486758e0aea9e1b7bf0b4bfbd4fcc96aab66a27fb463b48c6a6c5c5a60253e2fbc5716ef55629277a5f3b89c300e21bf1226241ce0d587fe3f5b11e47f35614169dcfaa375ee1aa589be33a4363765368f5666d155cf72e851d426fa67b982aac4dbbc29356d71deb0715b34e00b9fd8876bbb09ca0701b15615f05cc45e128b3864b26003e6ffe801c4e27402f37b8997e0c29ebc273dc03358cd22fdb68d9cd3b56ff8248a727c2d4ac65acda4d0e0f511bc07ab06cefcf444f1002c151b953d7f7b19695668a86683497c2a2d2e69f19a4997148d2e8d158da859c8f44437d9ce9db92f84a88e89cbffc74c0ef4295088e2543a4f7c6ae9c908bd987bcfd7a074f83ffaf3888bd7f430dc5a5bb70d223c21b1bcd8bff2103408460df864dcc168486f6a66d67ded366c6e10f50bcddada93627cda711764a57ec36035ebc",
+ },
+ {
+ "ce72c93caa49bb9850774149a87fcf8e23a0c53701554468645554553d54190bc6e247712b02097b794bc421ca94afed34742435ca689d2ebef183fb469c060c7f4d7daa508726c9d2eaeb9c7e9a89b30faee8d9168607d4778acfbd27d5caa623475073ce763ca061273cdfc2c692d1747baa8a01b15f783b2e36620400082747599a16cfd6b630fef310c0b9a2912d1d3bb71eec16972745cd8a49cd927014eb0a2abbe0e1ebded4fb9e8d9e2fbabb6a71da5688717ecd3e08160b9a861f86904a41702b2c4fff28ed8cc61d468187b75bde3fcc5c0c0a642215fea83584387fc5a9aaf2f8a91ae535e0027b618a32bd687289c47e9428a1a92649deab825d702b076223b07c08e55c0b60be95937bfd0504c18398e924420f6e20baf07e2b1b858d3e360a461b66517c24e60f9fe314a4a4973c8dbc7e9d2a9f571a1d8235a21073d81ab9f4800b70a5f17f44d593e8792a2507e6a3a41042fb2a5f7e5f028ed2daa88cce28973ecd88bd125d50fad77b1fde61c38272057d9c65fbfc6789ce41315a105af14e277a0c39d75c34aed7538c39160eab1c8c47818743e8111229426c399c5e88c4d894fdaff0315ec885ea019bf9acb785f3380c37201d494a60b583fc130bc0eb9fbe9b90eff95874e35910dc05c761f8006e2f208b786aeb2eeee841f9a82d9966c82956c181caa4dada81dfa2e2d7a25007c2dc7f2dc7ad1bafef14581cadbee4d614a557df4931b9ca105bade8fdfdefc0d96eeda11c08500b1ca827ca670ba07bb0f85af92914c43a6f71226d6e112d487f1ae99b2239a63ee2cd0849d8a9c488a11f82ca334604a2b7260f25373c6db75656527890f9b772c6bfbb9f687f27099ea9d4d1efd874a6ff83cc36c039ed1690408f20394692ff054d9e6eccc6776b6f4b3c5f24b0052334d159f40b470a9b8799bbc0df4dbfe59a5e536624cad193160ef23abef85df2c9b6e6d4fdf16f848a2a446a77044f1162a278866c491982570cbc16041908cdd0efa2cde011526a3c96d4b39a23c5fcc53d8232869cb4dea871f4ac8afc795aeb1b28cb2d7a3669100a1cab2ee1a7f31e2a25a5c6da836e4b771ad57393305faf582adcd26045e26b618d9943358c615fb206258c8993d700adac7440dcd3ef34fdcb065e10e9c9727662b5abee160aa01d2f2ca6c203a76fb01bb08cee9fc1eb6bc7497bb012ed2774a2d263b9dd03d60c307ccf33233ee33eee702c8e3118f9f86174a97462d0e804a24bbd7f4f938c7f105bb23399967288069e1637b60f2f1883d88ce5a874ea4bc0a7ca0f3b568e4bb1407e4bd6f0d3dc8fe91345f8435d7b1be961c45e4b0f1ef2d92d2d30bb78e1fbf72cd2e7ffae76e8c2bce005195c2003bde46108f37ffacdac28fd67a0de62970b347f0ae3f5f3a5b1d3aacb2fcaceecaf2ff4a2aeef6f5a176cc1b74b234f5658ce603bc353e075278a4056540e43033d37a6eb2615453d8206f5cd294423811283bcd5d79c4afe268a547b98977ed5cf24c0f53a0533bc0b2889356cacb67e2f7353060f9e04362859b1c1f02f96bf5457b58e5ce84a6810d39d7c7f53faaec64db5d6ebb90c1412bdd503ec6bc240c277ce1f5f18876feb24eb6a77e5193e33ce141e8720329add079dc9735f0a35d7d85436f1dba6dcff9147777760b5aa2ec9c8b5e9fb4fc602ec8f754c99ab2372ff5963dbff3fda91865108e606b214cf7acab875197e78060eed52a798751998ce7c73cebc4d5f429f6729a5193d7593072d0921ac8127ba6e796107ee7b9fbcf7128ab35fe9f6fe501fa4695c19fd64460685f287acacf5250efc13899bcf80ad5a340d432a0b9449affda5c8fa090f008e01873aae7d5fbc7972451542c5c29cf9cfdf23db736c8a7112536b1b626caa63f3e4117044cdeab612fff8d8c194d19174f56ce761f6587349c48fab30390f231d209461ee7e18007d10d83ea5aacf199f3b00003259747b1d03274d3c3670595604bb4482d345ffe31d3e88c70da16649a2677bfbdbf618de1d651a53d573aada2eee5c01335ce5519a6d18a70f7ff0b1e66bacc162c49f7f29b9d3fe2c7dd85b6b355c9f9141f02baf08d2be87c36f6d2e1b2e90dfcd100886e306b360df0ecb146a6aa5ac5ad05b63a219ea65885894a386248254348ada17908d776f9b438306ad28b208f80d6b9b265500aead945134b9d388ed5d6205edf07c5d8bbfe0916d0943750150e09c76359d24e3317517ea489fd8a501dd93f159f07d19d00e86d952fbdba2db771910143df346b30a30fba908a1abe5349c3f241958f428dece7ad9a91cb42035c43573b87b26c2ab216cb4c21799f6b3d81acd300ff50edd6fe7868b9ba6c160db3418565ada027b46b63e5d4f3411284fde585ed3673b424ec1cdea678e4a43c262991c3c9b988351d6e0a10af1c959cf21b7a288f2e4d7b3b2c11b400b5e036df71fa993b72ce48d0d8598fe4ef1ce70a970f89b55cf4f07906a479bc84a08bf6ab25221de37afebbc47ea0b38b87be128737d7d43cc84d336cc6ffe1677bd802910a2084751f30398dd0ed09589b2befd2f3b40fbc013318c822fa2faec2323fcc52b43161f47aefc557e92df3050dc5f8b1c5a4b2f8bd7b2ba7aaca79dcfa362fbe7781a2e261683a4a862d5f83e34845a8fcf8a1aa73cd521e87cbeb71f20b20698cc34bee3b8628b1a3784596c",
+ "08b3fbd73d157e79ea9f61665d19867dcb8c1598c1d37b793606936d8aecd992a0d46addeae857d488b83be5d1c1639d4d78350e4cb08782b61bef4107c9d3a79d3d85",
+ "a56f38b4bbe83b3d9e562cdf5ef5b30593f08a1a166676c4fb0d5861654e640b",
+ "8726dc5cae9497936658f603",
+ "88420357d1ad70e7c7bfd55b3cfd4bf06cd4e9b4ed5cba681045199a06985956d35fe86b28b9a4599964930d05d230a23c55a6a152f67082a453fc31f68489df05c553f9ae5cdb3f611445db384d79af865e52440a876fc4153d896b7a2318dbc2a4495ecdbb2e9dc68022326d35289e82aa55197aedc266dd91ba3018c7b474ba22b4e773773f3e9890ea84bc16a6b235e4bb69e785c40c1adc15b0e0ef03aa147b0d14e62341e27398b84a53f72c9199cc1c94cbcad2bd31aa69c96b06d01775b8c0f80278a43f526664bdd430164863c9c9140ad87798a5b8f38dfe90d37f54d1137709d5311136b728e6c799da244294daa4c8b44bfb0acc603a16c088a081129a0d2cff55ce1c4ccb486fa0ecc3098ef2196f47c49f9d253112bd5746fd99df5d2be577617dc2519c0ad04ee49ee1d7be3d50492017108fffc9a414ea227af39fe49fb2c895fcf00d927bf4a2d78c466fd44df4768e6775d39fa5c834b60979ca27ee9f00faf37a090838f56275a894ddadd265a8d2de74265e4d8d286639ce8f01eccd4f551cf6b4429eae3f08902b6ce6ef422cf91ce8946d9403fe8064784895b62a7f5df76ea294132c59da6b9f53d4195c1e9000bec499c14cf8bad460aebb024a76ac50616f0dcda71c0f56dd3239b11764f3ed6ed06c049b2ad673e4beea391dbb854fde1f01b1900858b9809259f3906b34f95a1c6ce8d24fdf0cf7c2ab7bde2202a7f1482baa6e51caaccef9f541c377da620bfbc63955cae0e6644ec8ed6878f704f1dea30d6b50d4291892bad19b0234582d50c6cc0b4165322cff24a9dc2ce1be35be0fdb3bb7abb777ff0b2f4cf16277388af5a89220d59f1f45ee9cc2a0fd7af9aa8e9e8d548fd65be4e47e7f8ef58f7701f93a42e7ff78f70e807fb63513157fcba96ad9731b2e8f80da85ef407d5c368ad16f0657620bfc122ba1b10d7ac2bf46d8133a9c6fec1fe04882f3d5765da8f825e1984a4313f72b67d806ed45c000dd3ddedd524d474b9b5788547d0712e8edb4c6c586d0cdf8f2384f1e093a7f6dffea6e79df9cb9398f5d0b9a7cbd63d489430fbfa397a0d03ef916b7702f33a54ebab84a7055b7ec6179b0ab7722f03e126ed343b1cdf2af3763df7e3a070162535514b01ad86c6cb051859aba1cc4766b12c8cd57b73fdd3c65af6961c45395aa7b885dd59e115db885f644e1c94bfa26b3804f767601c86e2c7dcecd4daa59955e6a40991a4b4701e63fc82b46dc0ccf59af40a8583171375551c868436ede535705f2e6380c5899cddfcaf9e94314794bab98846cd5ba9e9afbdbe1ea7fec5e22e7b2aae59fa598f4d6c0cc6f936a616e11bf01a2acc891cbfa2bc53c511a8a3a3da2e3aa5907d123ab2a4a3c0009fdb5235a3c33718fe4c504e1539abac6370e06150c402b5fc2f8c32608db4ce2eca9d1e4b96371ee195f6cd632f5b972385f9d5d357b87c78cb4e2c27aa9851534de14de923543f5fd9d55e34d6e8b7e1f3f2735df80046de01f79d0321066f9bbd76299c7386d285f7bf4ac15e033e89a040710c90f87aacc09fb8159f93c8b4860247eef079e32d05707e88aac734a2eadaa853f528d9986e0af3435b5c5f44ddfdab9b0c9ab3eea97676e920f80d1794740067f9b229fb018c804e595aa997533a5e967cb79ee58eea18995a90ac08333f1c69600b17ef4f454f540dbfa8b502457761bc4daa876d9053ae1f55001b6916ce559dc6268d01841255990e56614e6f4ee4ce04472dff0657360d75da4e83a71c852a2585110e53137e91bd89d64d99b5614ab2a5691c876f15d9931b092fc6729c0732db5cc40f966fe440ff99d7d05b24a872f552c27fb0cf2af443340b153214b407fb9ca3750d9c157aa75763b0b7600959663889d00f392d6ebc12835bd2f03ad802a21d0228f1d2e9731d0f0051eb2d5369ab790d1134c38e28d2bc2d5d57d6d897244742c176559961a1e40c84ee5c8225c8d72b92352a011e3785c262aac115cafccc2fe1b5e81a677a0220f207ebadd786b93f58e40eb6ade68ddda5b66c5f0f6b4b95cdb8241156110ba3303beb79acbd54423315768bb43b4fe8c4a465e50c4e63bce272c4d731ea4c797e14b2de31ce4264e2479179b906f67af4a23c56e817abafedc2c7a65aa45f0c89fcd0baba60561a8d013e2d5e0bdf9fbcc1346d3edb20e6e9f9c410982e1ac43039ad8fd0ebd453a6788376951fc20374b59946a6803498929d9fdf2e0f5e58c441329a79d1232e957b3a9ed17231c663b4819dcb6b4e33d205edaeb7d7ec466930bd84a064b40aa67fd76f6ca005408062b45b5aed6f8161836c7160a8c8313dc9aa1c6d42c2c16972a1065e41aea9c58db7916e1670cb42a8b54d85498561b4401761506860b19b446655f8988101fb4c45067e30edc3f00df8d88ee34111dd6626d605d993ff207be09704fd8dc242ce514bae77cecd20f10d4a38435a3f5e545882fdc224586a04ca6a162e118d23716240fa67892b78faf98a17916471f7f121fb9f85497a0b34bf5aaa4ee1ed8a4681bec55d1b4973d4368600115bea70f20a37c9e942b87f6cd1e2ab70fd401e703e3c8334c75fc338508e06d6370779578fbe737a75954b4701bfd92028ec32d3d7ae606caaf9f049d9774f70efa707c1c1174d9fcb5b0a0ae2a961c6f58e48ba82c2db14ebbbdc24288e42879f547b855c86dea9a3b9877e4b105515bd78cc43465",
+ },
+ {
+ "bf7884fab52251e202afd7b5b46aa53f85bca5fb80a009d8016e276579e401385d853312a884f4aa33cc5fe7360426bbc0ccb7416cc0196e2e40d3a825d5e0825a1394029789acca550bb28b10d847d0a4fe1111be2b7fec6b5294902775128288a784203031ea853c9c104c75571d19552e2a1359a900c5fc9455230968a5920f2ab23f5b9cc49739d4e4ae2c01c7812ff295899b954e9729a3bb330b60c51a8a7759e5131d7d4cf261fa1e62c29f91b4341a4fc968e7f30ca2261702eb328d628b7275a9efc29b50bcb9b27e5844328d5e8256c76949d30b6fea0d5a1c9abca80d3251fcf4ec4db0a5ff2ffd43618aa2e3e1694c2a3c579a2665f443ffb1eb0ce33c09d7285687cd55b6ca9918553bfb36a44860e09ffa0604ef4904a034108370195a986fe165c598305eb08599abbb3df31b1d93162397056d9ba5a1ac2812c582aa356310fafb4058abc5f157802e4a9b4bddb16e75b6db105b7dbc838f820539b76949b1648909104efa67ce28b16a738f1be104d2bd142d3ad1b1c953b6020a1f4cbb84d5c49424befbf2e6ac5c593b783a3f4af75477312528fa78dffd82fe493d821e011642bf1135a5be91fef909383953308dcb61b2f35c2ad259acd1a2e953c0ea6a03a97b384e39c94c33d3846c26b4f9f116abe572d5b7cb81886d6adc2d544630fdc1684bfb32972e051b9a2bd0931de63e025813b923944290fe1ebd5264ee4f25569a2088314e8d4ce8b91c7bd602b9d85acc917d60d30d5ef1cbb055b9ff7b0f999b98caea2517d2de334eb436078c90d41e0e34f11b93e3e643389f43b3afdc4f47a7396cbe0b4bf159ff27618cb835aac6699be1fc7ec840b767836a165fb95d06f2cac4fe15b65714ddb8a095ed4a5b57e63d536405931b6c168683763fe07c32aa4130bff787d4d440746a2dbfc584a502d809076b257482abf7f8ead7741c82b54c41acd41581148aeb4149b0c6eeb39ef7ba091c2e8bc72583b2fdf8ce7fad1bc05aefd6db0360c644a9760a9729a88ee4b2ab123d7238c12435b9f3b4660e74c0fd4a9b00aa614453d84fea01f779e5a924f8e79630a8bb6561ae19c7bc8d88b9d823b98285fdd65d4cc05e443944ed5d3cd4f46c7cafd1dd5deaa519772dd24f508bd2d588a832d5689119a2d506ff11dbf37d57a24e35ff38da18af07eaff5775d12dfe795fd3e1f0ec83c5f283d6cd76532519a15a18d93431893b1b88929159bf8fd21f62b30f4e37d540baab0e30ff3349a08d627ac19303fcae8b8e3fe44eceb66d30697c7ea051bf5afdcd8bfc00d49c8d36164ec9194a78a4d8b78826863e93b6a810354861f4a35ec12e5ac102f74e390d9c0227e67acbbe3254e5b892786e3a88a383ea9726485854a319569a678fa70392cee90c9aa83eee8df6800565bb8e083e78a064c0f8b863120efd799ea57d3073663c0d0e7bfb9b717ca1d6372fdf75a77fd9677791cb899fc8033d6d806de1e6aaeef525ea909666316d9d604c1207cbeb6f427c3acc1b02cf59704fc65135703f2a9529bb2c8fec992c4de53e54b029c3f2a5fdbec1008d1a70dce0c11251003ce62af712b9e4abe631902485404e4933f346f1b4467fceb65baf776d0078aae6a2a1f95b85a441b635663c75b485a8a7cb9a5c12192ac874d940e2d9b88cc05a2db9b5b35df769925da508112ab0b8f64a1408633fd0d81810baf2c846b222736bd826c8cf905b2c35633d6013f5565e0a5ec1492e99613f53530799052a0d70023339d1c394fdf9f73a590a2faf68390d2a823bc3e47a173782b03dacbdadaef1e67fb47a7cad71b6067ce5b5e41fc20ea1fed28578e9bdfa99faa657a754488ed3fc084faa7a05b0f6eb66da0a28e9ab26bb319fa4ee993de840948f94dc1d68d926b783a0bd3396a89970b2c2595de8148e87b87c21f664618af4f567115d403715c3d7d2f66d7a90de2c5237893a4c18c20494e3faf94485ed39ecfe972c36acef0d7ee57bf8755924c790ad02dcc5c4e15aa7db53eb6040244c3ebb7874676782e54dfdddc256018ae6af8cc37450a4cef77f21e2e061062ca0c2a514290c960f5993ec1ce9eea6d09d3293118237e079b6015b966361c3032368174d74ae5cce4148ea2b3690fbd3c28ee544c5c5bd7bc618122979d52c9d3d44eab1f2467f338e695ec5f95998bbe77dffac42bc2809d43a324e0f5feb4ca3d5fd951b7dc8a9e6276ee080079b68849b14c7573cd02c76027a856165d1043acf99554c62fe32896d120974ae71f84986bfa0c28fcc399246bef3ab90f8e55f913aabf339dd7ca6f0861a9ef712e77dd28740615479f39a37e746c7df2b267066d1649fafe0459f665f3d5e7124db43ab1ba5ff94989acc7fe0935e0bbacf718b33103a1355d97ab416d8263ab369e6cf0ee563a77f2f265fc3856b7d54dc0887ed439a421c14f733ec1d6da086536f9539d23cb8026218c5e783423b5f4ac24c8d5d8faa7186dd5ea34afe299e6dbed73ffa8f415da706442a48808a9342d6209f65ca11eba76f8ef26db890da76671971f65bce9e6112c8aa92523dd5295d748e28857acff408c161c0513b37b855a8afb0764d118815bb1b68f8f09156641f7eea994ddea20f4062607b9919d041c880b71592402a4d5b92464b239caf431a99dc67787e76b8e1d7337af004bcb88473cd16b3f7640e8aaa59ad4609f060a2cdc71a4b3ed22c1506a7050a63bd8ed68aa58a8109980bb3f2b9f9fba9599d7620b8c25e8aee739095789af83529cfbfce5941d7f14c8ae30583deafdc7c25fc34e75bbed6ce4f6b47e9647c12333ce08c7db77dc94161cfc43f7ea0bba39def8bf8ae61c6fdcc0de6308af963c6d9ef43916d0cd2cedb970d5937c9fdd4b888cc66e99363b5a04ae62a4349f01c3933ada64080741b1781754e4a722303faef69e382cd9823177e4d5ac83e76017124a7b1a41bcdbb9c4209e7b42c",
+ "eaae1c53919e2029c137a80f91704d0871be2c1870d0333d8bcf7f94",
+ "4c434cddb399e52457113cc7e16f046c3f8301f5b6c296979f8a091a9ea557ea",
+ "b633c1a0e1ddf4727b149b3d",
+ "f1de487001a580cee6edadb1ef6b700c861a70c6ef16274447b8c61bb10d2d1efbf104d5f7d7172c6a5cf9c06d886165a2919ee9418e2e8f803d47832dae5ef232ee300d1f973a6298c22d777a1b16264353cc731a7a683cfe31e0abc704460788c555c0c24f281b81d7761235a955c736f17f213a896b40a034609ca8456ec3cf5906d01121b7580ce19d89347b6a59c81add318df487b2442a7a8b5e30df78467abbf46bcd5ee5b994a39ca5bd8846caba6f02f4f1335b73d4e20be0b6ad85966f86d1bb857713ebf947ae936782f1f4929498bbd66bdd5ad6fa252364a5a6b46180e93b54cc321b3cf63cf23d55392475c6b8c8c9dc707924b55544151c7c55ae0bf391f793e52bed70829fcd32b2926600f65be0943d6a9a96547675426b0dca9cc7b0f5dbc9d5439d0281014c6c159d055d6bd89d67828ba7fd2a0570ba82996037f7dcce297fe6518331270f6fd5ee63d406cc5081472bc5f2298a9208dba9398ccf807ce9af982885897715b3c5742456f756d79c70434a9baf7b4b6664c9d9f5696c5256b74099e593f97a2d4a469cb3430d0c3eb06083398cabd58af598945a85c9235a3fdd9ba7686e54d0de9afb594b1bb030be8e6bb839f6b45699dbcd2f771db64b0c62bbf6c8672fb412d60c00b3d87f82ffff6512e8308877573323c5a2d6a216ce3e2ce07c9763835ae59d44d7958fd873e3995b62b1b347e489ce86e023ae27a6cb03ddec27a38fb233499a714acd89232a91d38abce30299f38f437f7a46df647f2be862c1e7bcc1e4263c2147b13ee5b345b7fcb973f3ac71db8bc12309f67ddb62659bd73fbd20664eadcd23a79233386aeec1a6fcc8c592053954ee53826cb9b6bba22400648887311cdfa5414c96d5956fe193a3729be1434d923a3f9849f6c419f77ea05fb72f3c4f75ccec03b7f7aef8c8e55c8c5480ee505ae1a7594e6a911dfbc39dbb0ae8656f5972eb644c64203a920fe0078f3d050cc5666ed9747c23df7853d6913005d0156e741a5ead3bb1b22e5bd802c303a73a961f0b60d0fa698041c22577b44eba5d6071de4b545d9f5de24944c151de6a189bfdc223e0507c74ff929f06a2e7497e8c63073294b4aba110a006a6e9510a9617405d9ee711831e085940006761822672549d1d1c70e50002c2227f6f304b9a7f11dc05751be2dfd297087044d2e20ecfa0c091478d62c1bf5f0aacd25bb0384853762a51144b77d30418b633c4c10a6eda7b2eac46905641da0b685f85349749a91cdbaa4027fc50eb97a7dea9e8cbb5b5f386ace0363803ba579cd16ef80dc40ba1044b4ecd0e81e382635d7855e2341b18e0ca705ff46990282fe25093a248ca04a1fff64ebee25065350ea4b9e5990da4dd2e28688ab08b6d6fcb54d70f6d74fd7e5e05d21c12f5b140839aa966aea9ee094a923ee5ec704b5b709ff009c20ed89a75468c48b505d07c7a5ba1ad54ed610886c9d84468eaa598c71b017578404c909dbca431703e0cb1cfb975a696a1677bc015a75db007eccdcb21b9e5e119c48f148c2cffcf29e245e52156ba5ba0a8b0031570e4cbe7b3ac4646353594f0c4a9424c9d97845c5e1a4b4016df9be8df3013e5269484cf32258849afbdd733189ea11783f0f64d3aba9b4f48818011e868cc03ecaa44ff0ab83ed12981a6df445294ff672f3a16d6e0d19b90007d4646e967e0fb1763b3c879f548e1103a75c94f3a7f72be78555eafc086c1c58d1761aac60b843704f234c55b951a1303a12705f2120f784c2bc1494432a94c835d908f0edd5cbb169afd2d38087ca5bc5e5df9c3bd970dd2da4fb2a00933538148ebf669a20b5beef0402e53dbfc3a0f289b33b41ca27eb2f036a22f0d02e0617bd01e8c74be264515c9b46b9ab6fc67403a35837844580794088a9d3c14ad9309435daa0396f48017be524856ab6c191350529962ead64bab33171a01bb3c144b23bed406cb05102c693ce5df36eb541c47e871acf56f2b47de687eb9b3511ae83d06b1f69fbcef3225c3469c304741437fcd0ff4ae3484c117f51d24b6ae1363beb7d85d9b61e01e3dee901b90f2d3272eedb384ddb4d3b9594b9c0926595e500f8ce2e5cd407bd7a4e2c8e6f4315bf693e8c961ba5b8a6c7f5030c68a6b995e9d3f9eaee9eebc9d679eaf72a5f1cb6b2fc66edc7dffa2370dd778ea7ff446121999afba7bb35ceabf626c6269bc466d65f7f812c663bcb2fd87d3e09ab7d71e727f66d20ec48a5d2bf0aaf0aca05d1546d6e974f90df85c1393e3d45731f71ec7b5cb6cfb4e5c29976ead6944a99df2045056e198b19905362d4e9b765adb65eb089233a8b3777352665489c9456cceed593c6590d9f3cc4024d0bb92e1a0dc619bf8ae65be77456c18f8171e4d2d846073cf5c57ba93adbc0db9799e3d98934aa6899372acfa4d7d2ea32e20164b79c71d7bd33c94f9a781a25cbcafe563462eeacaec0e8d9d6c0199de85558a3a05d1ee3483351915d8a4e65ca0ab129a2386a9e26aff9b912c588babbcf25f8c467145061b9b8fbbff19d8c6ded8527d457be7c926c8f490bbcd627b3002044b7729a52e94147f95772591616f6074047e758597f410b3100f9efafaa4137dedfd0edfa85b0927804f0b4fcea1a174622116222004d42b36c2c73d04781f2f49d080f351e57154a3980005bcfb0ea34288e2fafec5bfd01e1f7901b3efc71ae58bf8df4cd7c045856103b77bd78073f0174aaaef4a3c0e8b5b46dc92db55478f012dc1b7d513e215e735573257f105d2390b5366f49b61809033c13ed4e1ebe19ab89313c947f2585f0788a0c5de90b41ad0dbbfc604a0d414d0e5390a0f3c9616cfce4097e38e05888b8bc6e55e40368bacdba7e5b76f4bd8fe619746155c30b38807a1ad325b00ecc3dbcf23014e79f1c39af7cdd0dc7ea58ce733e6611b7eae069deb047aeadfc21960e614db19d2e7e0905a9873268b9a24f856c28059321a742cd6cb3d1527",
+ },
+ {
+ "c89c3cadc094bffd5ba06c600dabe30ea19ad037316fc13b895fe0e14ac8841264c1bf25557e22b01f8e102c3af43adb8e0a12bf79d3fa0232dae37ca3688e07294e2c7ecc4e2eebdd3f17173351f2c15b0480d4d77bd70955ba86f82214004b622cc92f7bf81a5837326f6a83612bdf65abb33c268a457c45cb7467e074b342a17c711c748c74abbee31541444020a9ecd4e5125e2a8ea3f6030bd677be18183a8a34af16a85ad48b7015cfb036789c0a5daf68883d0c7e401754b8d56cd00ff605be0cad19e03989f608392c81d636de859e66c2aae403c138bb96a58ba69b9064a83e7d8877067e7f40aa0016e0df9b7f455d292a60eb621b8107a727a3378c4b7509d3ec10526c50fc6c66dd4b015c915e85bbbf701ddaf2258119c8b9a5132eafe61bbf38870f35f375123f766ed0d4f38b9364a86e56cdef6f95a815a8d7c48ff283c77992fc6c070eab7d7c7b517006e5d4af532a7c429912ebaebac27249b4f5112d870d998e1c450b98c05d08c742dc769506f2d7a004c24ebf84c10838b619653e27ffcc4344d8db0435e4cb77c0410cc734e36738a6b5f72a7600632d19c86b40c737830b0f5f104443dbbb031dc7ca51ab318951e7817b5d81de8a9aa7f5db6e2d5e7a3cbd8a8100653c048204ced3af005d00e7de7b445f5acff901c4d46ff133e92ef073aff1d9ebf55befc32f9ec38c9eaa6a1aefc974bec2758297e474cacea2ba4151ab1a3ca0762c64a5ca273169d29b83c164f77f266c01bd5075871e17426068ed7aa58ef0d1f2959b19c604eb6187acc57e2becea2da93ba23159ba73b9226034c7ee2498e0ba34fa8038e5e2c092a73ebd9329ea3d648d6ebd47e1776941ab3130cfc91089fd0a0a36f0ecf68293343f275d2a64c1b7d27ffeb3f667f4a19824706235fa5f3f04952ff08bb183c0f1aa1d1b0edfd2e05ed093543788f5d0ac6532e15f912163275053b202d772f381900e906fe070cdb00421e78c16b7387be91adb7b3b3ea28b92548d69c780ea578e7ac66eeb931eefb4067bcabdb345a7cd2022085fc494f118215adfa2443630bffc9faa8fbd9943c3140d81c7532895734a9dd20e31c326531d06f5623c252139c4cbc882640c457819c63f6ceed4e03872b246a3766df69373ebf5af1116e8d5e1b15745bd9dbdd663fd4352d1238a43d5d1e74b3edddfb1c9d460daeb49afccfa0712b7a4cf8d07ccd0599ef3e4e1c9b5c814f3a6f3a46fc80449b34df87f47ff91fea3618cab2d5c04cb50e8ad199d752d901b21348ae939d39c86cc1bcecbadcc6f0e581a3bb51e070507b41ea4294b35456c69cf55a2a3f1296f0df73abac3a9c81cc303d1e20ad6e9bef48de83fc22dac2cfc01ce9ff3f70e00ee49bab2f282ceb6859f989075814e690e36a8d16354fd6056cbff49c30e49b1570363498531ff0ad0979a4518e9ae271f57f883abf5e301c0e24a83f09335479698911bca90269a28c0e040a98e67c9e55f4c91542f921511dd980270cd490766da22306b48ca9309aad3b2393b7b1e9ac7afeff64204081f9c0a8f6a5396d02eb9009901ca2c0a75ffbdae3a38ccd5007cc4f6bec8fedd64086cce5c039e8abc9e23bd694fc8de4e858c89bd585ebdd422b492eab26f4ebbdc1d17dfbba19b5ac458c31320a161a52dea638548205a6ad4ec54875ca34238c059177bfab2d5be0a98d12b3932d0661d33ec655446d0283224af8ec7f1c6874add03448fd8029a71d3c5aa06951123c9fd881d435845757df50444e6cacc31a8cf7537a778d1184b96c3512cd474f5d1fd1214555789d24c8d173358e36400b2d937595109729d9f35eecb0963c0da60d2eeb52a778876059fa95d820d5d34e7948d389dffd53d34c4083d27c917879b053cc57dc43c8263e5dfe5f33c19dad0a7126ea6e8abdbacb318d37c305a183596ddb25b1934beff13a4f24fbdcc2064de8e0bc639e672ecfe45692e9f8164365e1691784b4f775ef369aeb135ce15135c20da95064c810592ea33316b9767caaef842f948b9573b2205ec57d3026a2f2244c42991462e233061549cf9bc66a7b4a8a0fc61f73883fd24dad02644004989c4721a0aa03d3b0191d7fa4d3da102e541fe463936c9365ba30681e706ca70cb3c8ad5dcc710de59e7d8a6247aa809bba74ff4dd182a38bb31baa337841302c19ed89d65e87bbed05465f4ce0dfe89b44d7e9266a8ca21d984c41109d813ca76eb67dbd4e39aa437ff98050c968ec1e40c534ab51d6b8ea2309fab08b3757e9edc5972bff316f6f2affbff458ac0299613734b30dfdad20f797d172cf295cbcfee3d8ee25485d40380d3480a9372a1a6e5ecd7c4c6a9d34027ea6c197f37e86e757750c9fc24cc7cf814878b8628326c140930dbb2041bd9ee87f36ebfdbdc34522cfd4e50c9cb48dd52d4647a06d08e0f0069c104849bf30c8e61cb693dffbc69fc0ab9c5d502a227d606a1dcd630ebd799acdb1e47ce2ad52ff53f6cf4fbd5f0058fb5db915702675ea44334d42e0b6ddae78b22b5b5f7e5aa36519e31278e37b64312479b14aef9b8f12d8c1f39faf920851bd53b13bae5490c847b3312b2e956c430f1d8deea91cf171dee5017e7709d0346d81600bd5f0c41da3f548c28aa50589b293685ba059cd7f3edefdb5d8cdea364f4a42153b0632ef0b7ba18610b71fc34a781eead1dc5a00ab47b6840590ba44dafc6a16029cf50e089684194d93dc881beb62edb7ccee6304a4e71a35915f109db92690461b9e4ea21257ffb62477c20feaafc7a78e2aac2301b66893157920ce9fb114ab4f534d61bb3d17dfb4d9ef9f79a736f7c1d32ac3998356aefc876d8c38722787d564e980a1f15056cb3fe634d71d2c98e0475c79cab318b73a863362f85aeacdcfc44e61b5aeb870de9ea5b5abd24e8c19ab05e45e1e9b8894deeb9d29d65ae99aa94b5047f3c1168276cc2e491aba52b5b03703ced28c63a167f0cb3e4bb4d8e4f0292cf3ea4376510fa49a1a5efcc00f23c3cdf6402197b81262e66e17bf4307d87ffbc2b37213b316bddd65aa9d64ce6122c4a1545c5966bf4fc4c6ff17ded787ca9a3b3cadee435bbba8f6590dc4ba30895b84d5b4eb94f4b05be3c",
+ "82abb4ff5457b21f359754f151e456e2c0a185c8363d15918bcee0d6d49f12564ac655",
+ "b63b577e719494032062e3f63682098dcdcfe26cedea2a40893c847a331e4ce9",
+ "9f1d08be539f1244f0f69ad2",
+ "88dcdb0309f8c4a96ad5560f8210eda1f5afb31b85b7a8b15525777748967d4ed77c063f65d64ef19b31044f2adc690f5e457faa1abe2e127b38c626eaa94053c9ae1b6b4d0db1f02c8404b50f58210cc9fcc6fa4ecc615631da631031cd6253b4a13a3e88295ffdc775fd4bdf29655d9780dbe02b0a82aad4c4088e90b51f170909c0f98ff93ca3926067ec94be05841603db4f913b7025a9ee34b8d8bc629ed827a2a9857e0814d36b83cba21e670f8f94ceb4be5757e0b8782895b5d8605868e4f584b5bb6a5f3a94edd9b23fc2b6fa06914aec970c260fc370aa245ca68888c90c43eecb68474c9e45c53a7da055f5bfe39b56769fa56264dc8bf4c1616e30262bd501ff9fc5cd78f73ad89e093feba0393a11c6b2cbca765ba025c40dd0417dfa644fce96db5a0362235ad37a317145e7b5f3c7213c7fb3c393be57a1cb55035f06da1f0bf665653c5fe8a0f3ca67dbcbfc59852694d34819d0978cd09b508d103017168f6848258493be737cc24c2112f2afeabf41038bea1f74bc8656d9910b77d33cc691a0d9b12f7c518ecef93423cb4871949a518d2f06e5427823324275b97110f8f88b0d14788741e617f4b194e679a1627da50376a08d4f23b005c0446b46d4f534ed85e4692e7946ec818437089425ee30e47de995e8774b61003801de67939d9fed7bf0cdaf625798d0d0d04a61a2482217b890168e36f20cf1d6b81f9daf1a49a781567c4363ac2f3ebf0252d5adfbed17f98cc264ed2765aa279b7437410ee8b4cf42932e5055f4884deefd2a979ab1328f97cb750b3b7e4615b9c1c61659c90a5ff6d1c736e785587ec85040fb2c6decf789c2707974bfcbd0c7f699627b31e0762321d55bcc6acf1aabbd44abd7766d397bfbb68c424b311611d9eeb6598ca3126f569f688455da8d5ab86eb01f9c96186858c4b5e447aa2b9ca11aa5453f731beed4e09f95bb7376e200212e2f03551b8b09a19d6910f25898d692bc20bf6ed3ac9a0276db560de5c9e264f4db8fec6577042fbbd4510bb7070086508ac451a1fda26582c259412fbf1bd60cd5e921160c2604fde559b5ed4df52b805010b225f999450adadc6e108b70f169a3d8da6efbe1cce1c4908b004e928e3cdfdd0b4c5f742fd72a11c9585aa3517486201b6d9a98739b77970a88072750d29d005a291546f13b576b4249d71f04a9abf8f653ca206d98f738af2a1203bf0975f0a40138df054ee834ab73a3b1d7036567369a7ae15f808904e08adfc84b34a0e1356009d8a82e51c3e8f2170908179bfe47be8ad819cb12e85b6b76bba7c9b9398dfc00f550e32c171b4d5f2d9676063efee0b0b49660c10260ce052dd00addc3359e35c25dc33066d4b05bec7d93f71e0ad7d5ab83d844c7f33137894327f464260688ea4ce9847046e7dd0bfa48d4e15277a9586b4742daf0c5ecc59aceea6867068b03c20aad38d04a814472287d809a9285cd4dcdbf68f3f4ffb794701f4c265b2dff4aee55c9815938689162e08309df150538e60dccc03d495adcc560fb831444b922a6375845cef5dec56eff2910b5bde5f25f0e550ab5a13205de91d20896fe04a8ecc2c83d1371cf381424f8c43d2a5ced374878405f52bb92f4fa3c15d29ec151508488f9b4e42527921e245a8ee4b5d6ee95797f6ec4374d79acd7b467454a1d7eda05a8ae104534b23c46b27581abed6afc3ca555202dda94fc2b93501fe78867730a84f6f726dfd7364bc240b65d6c3022a04e09c89e36a809fbf244cc5522315110e9e33c8a4e1f1396e3e51fcdd53d9ae94fe7bf6c6ccef0ce02048a11441de3c25aa9787c577501977e486f8dfaa4c81e3183e648311148ce5cf3de56878847a9d14c0645777022c158670377dd9553eb63eb17e19ebb06202be8fd9bc2b24878cc86f9938e5996751ad9ca04b636497199f7f27dfa0f5ba2a01c3a491bec6dc5113d127f6aae38fa07ce7539a0c1817f7f0de0da538f4d85ffa394784a42eb50994e28530e3997e3345db28bafbb836fa463d34146d9f46d8d2b28b3954b9bc7f84046828e9b55e2fd663e562aa95caa97873f48f0a003d2251fb3ddbce0b6072fc17e0d3f99b655b8f41e8e6986ef7526544222e2d402489eabed4c219540605b9f5dd321ad902708601e85bc874c11efedd072aab7e10272c87b08b9457223de9fbc3abc2d1346656a524e9c67d79d4053c4257e886d6b430f5b7f57b2e5e92ae69273c1705a3074d5066def69fadea1af8fa9b3bf4890f9cda4b1833e5ed27f22bc4fe4cf452880c7b53320bc7cb748c0af6e7550ffa84e4714ec18d208131ae9e3edc6cd6fa2c60ab8ebc1ee56eafc01fbfba061e55014b9711eb58fdd01f8936d29dd081565de0b175b02989c5ff374e6f58c3383e9bc00d8a93903e6a221c7475e15aaef77594849af877f3807a76e03bdd54ff0b192bf34385d24d858d6f454810ee48141d73e3acf1aa3d19cd4c723a634cd8e25b4fb604c744e408dfd82961e46e8444f001d0991af24b3b6ec57ba41fb45122afc73ec6b25f501f1abd46181247945729337bf5083e5821968502a5a696043ee696c290095feac000957f968ac61ccb572ab2f37008830ab9a81d02456190af99873450b52df1888c3d8b6b13df65a9bb36a4b6d0538a0f179daebca2bed6f94b4670560fc5471c3770f2d004b6a138b8243068d754fd246e9881242638c6675f1611f237146f6e0f72ff2fba96f479fe0a662a81f40928f5400a0bbfb5ed07a87f457d5febdbdd6f323e2a59f749e6fc8a51d08b023734c762a91cc517401be57ffdf6a52b9174ea153abf2190ae2642955c3c02b4a15d72456c9d2f323de6fabbf56dfa3b566f1aa688c86b662bd34cf2511cc4a30621b6f1f1ac382bc1c4fa4c0d4d5a30ae90a5e54a9fb4afc1475e7c612eeb7f0e09e894c2004cd04126df9359d525d7f090e4b531916207c38c3512341c84218c86fc50061043ba1b89ddfb21cd756b391cb53e8c1cd55352be05efe562669e3986c022e30c79a97bdf087889a392e6da0d72cc7ea208aaf23408df23f3a9ea9bf9a935e49c9994a37a5dd0faf1267d5f7db47cf64ae1d3ec166466b2f882eb21698aa375cb50146c0e660e9bbb38d7bbc1c1c6d8333f7031d6a",
+ },
+ {
+ "68ca38fccd585eb14f953358220027046c14ef965478d3d8f206f63fef4fe3571a1b53e774b298c347cc1b69cc426d39575ccfabd5a284c7a87a0698cae9efe40543cb79f5643c3c3057a5fc991235f06f059c44a7200b509a12e864fbd748001a14790f78b54ba80cf0a4a603da9672df32b68652c1d6edd3be51cf969acfb0ae49c026fe0bce0bfc72b1ff4c47712b7a27b2cce888b9bc470b8bdda55a8d53a34d79a25947ad55b95e5406a5c5311fece3ecd46ca590b3b01b9055761da8196b21bbc468681922c66d286c32598b1e3d77f2a91d835ccd9eec231409cb2e74ede9385552517718be9f84f0f9100e368701dfa4843b7222279537306065a54d4edda3a02f1ab9edba3ddeb34dece9d5edc8797103eb942a80cb5ae130ff2e7eddd11f0cecd8f9a615d75963c44238b10ab1230d9db7371d8291feb2912d306efe4f7aea2773903d4be9a00f2bd8c03589e342269a79441c0b42ce9c6fff0a6e4e845876f7e9b342d25351fe2b1233b4f576db90ef1facfa617b96d17aa03fc824973e1c80f15e5344b0516fc28424b7faff47ea1ef4e47f6f7b50e91b8fb14027f05ca7e1bafa266a4b952cd0b9e4cab82bb4d61f99568e14a6772f36296f5d19cb04fa86ff20f04ab61d1a6f01e5282c99fe4c3254da46fb5276317be58e94b1928e3791af27dc6544f6d445dbfc7275fbbea74f98ee4aea647b654909f9fa9c88312d3759099c9d0070e3db6d55506813f8b7abe602964a7dfb9387f58e237dbf50b4185a50b65ac099352dee8695017e4dac644f42aecc3e415333cf76b08fc764a721b45d7b74f6b0a2e43637e5b4849218d3d4c6a01208f345d76af56631590e520d6bcd82627d2446b45b2c68e0be81b3924753a54f47ea27b1e08de2399b34470701c9697eedaf3248db9b28991cdc2c632fd1b376bbda279b6709d5033d1c0a3ee573bdd222ef1afe8a4397a61fc30a4e94bdc55097ecebfef6c00133dc0b72c17e2f93a11eae9fa9f1364f10fa595e8e1623dead10caac068aad3967b9ab2837dabcd8f96a77a25baef16ba84bc93661ed150ffddfbb0369683cd021e8f959c2b531bb1fa95d7a574fe5ff9aae35fb9b4a0a9829c59b932ed8634fc05ca88211da3e30839baadaea8fd9843e0e80d9598a7282500d157ee579cda5d57628e7506617d301c2adec5186708f94f069ed7bdb70cbe88549cefe1673d48c9bbbdc01d2af03945cefe6e25f757750de64cbb9d496a25adf7058f5e32c827fe75e80ba0e834e6a72344dd2aac4228828ed42fd83e4576254af5737dcd9b6c338377d46baccb02d00fdffaac12133ea0e75e791593ef3aded4ae4c9249b8d5cd20aa28cd652b9d750b88111d9b4fbe729e27882206b2f0eb614d7daaf6436816fd80d452ac71c7a7f9e8c595287407c6ab9fe8a242e98da4270b4f1d4ea7243c27f89ed46a567c643f31f967b5f12e518106f3d3e08178078cc714cb6e39079631966a9becd6f02c18e983ceeaa2106ba9043f9985b791027eb5dddceed563106bcdbc48a4ac64bd95e87c708a8cdc33811bcd16c35e193203e70ef2bc7203183fbf60d46bc581f1bdfe62387b3e6c0c4a29130d872c3f8b134e7dcfb080e7e03048c49c0e468dbc44eff4b02e50bc6889cf7600fba58c0ee409ce948aa684baef4956fd8fd4a9c4c49e84e2ff314b7900b179fc66f5fb4affb9ef7a6064354fad8c3d2d50e6f2157576f864a843dda8f547955c4d80a73d4a86b7aaeaecea886927a5ba0e97df740ec7e8b70bb650010df55d4b75f478b07b205b560d45de666d84206c1bffd02ab7b8d1c37f21c47d1711b89d16214d8151a8e75eeeb5c54c39e5a855d578708d314240a064051d8b26c6183ce755be38fe9597dd5b5d198532b1db083a4b856b8dd60bf1db197cf1df852eb6daecffd97287a6cdd4c05307722e0fac798507f75b03e9361d5627ecdb56a3b633938fa61b2673efe6c6e768e4e7055e6c1d55c7113efd3e95151b606bbf169f4296455dccb93da370150c54fc11b3682f092f30381c6ecd218a3d9d39442c8bea61d9a71b174a8b2c56e028689380879cafb7c4bc2691dda0cf6ada039755edf93f851446df9f63267f8b8f030c069fabbe6457d4f63575b5905fb927a5a720d52c351bfbc48f12440a91471697e6b2564b1a2b314fa0e6dff090079637287b635d875f120671561102ad27aa83d9f0cee41bf023bcd703ad670b43ae23bf01713650834cc1e95dd486757f0a4f6fc9337bb95738805ad5e756198579c886eb0ee77e4ba957997dde0eecd84e4c9171c84ad8f0cb23c6a289e037f3a8beeea7965ce34fa47cbd727baa4ac9e6dc3baf17049fd2386674b246aca5ef6b8496f1d17a3175f6fee86299232c7fff682f066cbed895155d475bf9fd4b5571d257534c88c93377b1a600d4c280d42aafda975eb32c740073cffa610b5fd2dda7262a2fff5da7a0f3a875c62949e0c9247827d7a49bd8185bc27967124c34b9725ee961bc8102a029786652c2571be6cf33be63cf867c2b48e5826b31b714a415fe05c27f0862a870d8fb33200719ef4ac8530a4ecf2597b4a7f2e66f078a7505803774889a1cf963083c831f46725a1ec5545d8489e53921d81f80ef99f5e51a2d5992c7769c2a7ec8bd8e0f2fd81de53c7b69b650a2d838b269185c5efd668c470943bd956e3c5e1bba5d3b927b10cee68a75372d4d6fdfa6782c05659281bc9bc56a2123967f4f50cc7ae3379ba21e1617553354b5030b3d3f0092c1824f5d47b97e6b4fedaa90aa2573e1b115ffc72d44fa8209fd8d372c8dc9ee00193b47c2a9a302875da331731713243d02eb5a57d5dc51c35988ffd742ddd75c191f1eb2c2214a1fc47b82db8ea708818262d9583f2b1b98a40b6ff6e94742f25661a51882ef28475aab12d9422b6ac48e341cbd6f38460333b5fa1cfd4d0f43aeb46c21938468fe3f7bc771972246156652d2c58b18c8cecec2dbbc0feb0fae9f6bc022e029111f94e8913c0ad741612a1426b53cff73fbb24fb7b22ab750ba1310ecf339fe12ced6a3fae17b4c429550794a8d68be891b0e30cd28e81de2fb2ecfee58bdf11794951276005eb8a5af21e03c8aaeb595ace652c5ce60a8b98f6897d82698ffbb2e02213e50d9d3f00bb42c8652d22bffb87ec576ef6e206ed6c846fd5136a87f38c9ad899371799f35a6258878418830b04da79fabd80e7290456fe17c0850a4c20e2e657f97f4a53e1a3db65bb5e71bf38eab9f56aa11e6ef71c85b8a28f04c271",
+ "ea196b6a64be4b0799b1c2f72281300c3a2577db44e5d3606b8b02fa8fc46c7aded7e442",
+ "7c86a2c06b7520d60023d18fe73d09c514ed07a91d50d8fd5bff00e7550faed1",
+ "952f492fe00b26028c560fc6",
+ "b3f3294815ce461c8843172efe93f73a8254e58a0e71953e35c15aa89a7bd9dfee967853dcbfba73d3b87fa60449cbcabf13b1206d0cb27d2c3fedcfa695b6d41efda37bb6db35449bd470a23787619ee48f981d3f0b1c8e121725b2289b6d67858a4f9ab41683bdaec8a913ca2cc292a9640efe50fb85a1d1f7b286f45d4448f85b3242f45ab44e3281d759db24dfabbae4259f127d6546ecb914d7e93e2c19230c67fba8a6cba6069023ff7ea3d8a170289c2b4391bb97a7b899228d032b36186dfbb29ae8f0e6c06d753f4c6b21982d49ee682bef50a5c2c8434510c5fa2b9c0349592f33f8d7ad6f7243d42b292aee6d210c61e3f898875b91a17a89148275031b74cb34e628d7b701775dbfcf87c79ab279a73dad14d8eed365eb9f29a007b7d2ccc07ceb8cdcdaece67fa0166e135c9a4b939426882eeca98ab887ed2e4888bbebd5afc9f2da3e9162527262b0fa85903246bc8b80df3060c890ebaa516781a2b2a138b98001287e12a9c68471912dd297bc0beadccdc31a27b7c726baf31510cd355a28e4ef786b30084af66ef135909795aa73814cbbc6552270d5e11d46e9497ba30d6d8cecf343d16e7e3357bc9bbfbc7c1dcaa5fafd8a9b07056129da02e6228886463474c5af1d670bc14cf2868b816cc71578ad807a37477341c8192bfc2e8b1f7bfd58827e041f70384f92bb4c6acc415dde5099a1c2b27b709f9e53d1dab07c87a042ca4af7a2a6ee57b37bf2bb42259d372ecfeaf1dc55ac3a9f211f16fef3b2d5f11dc19fd1f425c14779580b2501ec6e0a84220e7e12baf9e0fee3e8cf499a7fba6721a746f598f04ee8ab4df31fb8fa5ce2d2419d5551155c009f2780cdd225ec2c19f94fb9c8b785ad4574b4da766eabfa696a1994e64a2518d1bcade6390cc683a6e80cf8b163c3e58cfa1134ee743079347f08a89c81478668df32ce9cdd7b853db5cf7af13436f3bbb11bcfa8f6b6d727a1df84f99fb3a5c248b8fd5baf669b68fd9af45298030f3251bf0351fa9b58b0b9fba53ecfd838300790ebd689744c1b7b333fbed76c8fb96fc669ecc6695ff5bf8379dd2a3c270af858cc60894be8922d69fb9707bd2a7825f2eec4a5056e5e91714f4dcfa86974259fcbfd5f20d55923a0a9936fb20e5ae9670e2019336e15f530c0be449fe355a7a02c0938d60720d5b8f4f59d2e4213ad5251c6058312b43d47c44ffc8946a98797f5ace279d3e126da63633c0eff1c412febdd47817aaee466c639e43637c1e179f606780ab490d3f0b3c2d79709f1262305fc87c02f68da2dc32f8c544e7b358c3a5d2c27986a19d13fe736c60a3524e94caa55e853eedeece985d16bfa6c487bed6583436cf82077fcdcf90a05f49db50588f46550f7a0c3a1cfca902d66d25dba8d2c53bb5557cc1d87c8a407898b3c30c4f0852df92d839859c191228d0a47324ea9ec2e0ae84513cbe4ff4aff85e77b8587f1044bcb9775099ebc2f28fbcd1cad58a8ce1f072f2228f559fbfdd8405d86f8262c27c3d95e01016b343c6a4e59dec81b59bb6e3c6109a4cffffa85e9752ed2149b5624417c0dfd1a27bd2630bf59814f15820c43bfa317be59ef6f433c95e8be154a8ae94765bcedadebb717f0d8c24e01e1952bd104ba9620f067554ae0faeb78f13c622c45d97b2b5774a3e30cb07f2cf0e8b19d1266d8a8861f3772305e24ec5c9cb714806c7d705a3bed6385f8be4e12562e17ec3df01afb4ef6f7427c48a1bc0e64fc65eb1c3d3ff2d6687e4c275a019f5ab5c63bbe47e3680fb1802d5835c4d494f0f394de1ae47f81eef005127d0971c4589c456ae6a69855f35635c28b590c1b93f155fabcab59b6c7cd8ea1c4ed1f67093aa782c54329cdcf9bf84a40400de707b894587d6e08cf7fd72fa45b6709a26e97ff5ec1269b8042358f872a79e8c2db1c7ebffac014d6b6f71b0c1c1945ddedaf5b6911668059b61b55eea4737aa307c829309c9ea548fba2bede023849bd61b5a467cd1ab1c61205ce64301e2531e5d58d03c74ecdafe1f5b74627be8716cad0d0a0be60984c9f9dfeae24a6c4949170ce2f589326e0a76c447a578ea3a5e4bd9f18884f18843eb1a78aa2fae06a7569a97551b227c34d429c8e1c8c5417ced93c30dcc607cb32a365d87328aaecb4ce57ab8e74f0d9099e267cfb747a3bca9f76b5f6dfb543bc4b5c06c3646062ec14f511058eb2939601913f8a0f1785249cb72b0bb1c12a9508b23caf490537eec53f614f3e06592eb61f75c1cecfa514cf7b500b0375095d5db74556220131390b77d0db72711c0c7229a5769b1d2b3f5105f3a4370beb1cacbd93ce32f89f1fc833c7949211dd204616c013a3399a22f5325f1a00008f4c8ee7dc5bd7476848721fef843123a6213cb0c0b6ae84233ed01a77a115d06e08990b8e60cfa4f41dbc9505cfae76463278b6c6b5ac7c3b83284caaba4a6a1d739c392528ff5b06bc3b82e98060e3001279a44aabaacc661fb14e7581d1235940cbe067c6b386da09454e0467c785ed0b65d41ff4cf36ba5f63d3ff2b45c11c6c22d3ea8ebbf1d52d770e0ebf2ba0c67c7d3641c145cab474a88119335990137fa82a340c2cc8c453752a3aa801127a47aeefe66d1af1a26ee1cd0e6d935bd548f6ce33a9c204be02ba08f9fa03c685665375db7c0c656ddf3e441ddd96b0d2018beff5086cc63339f26bc8332a5e6a1422bfedb69187a3443c23b630a28b02f8075faf3ff2fbeef6cdf02ba4af47a765003de2254b69f487bb5d038759a33ce6885611198b81b0b6fc5d7a531a7a90dbc3556aa758db1657698cb3698b8207b1c1b589efe5d52790667ac483dde9543953c6392d5eb8afdafa205d325e314f810e9c7722cbf5bb76fd6502733149bf21c60717ff5bc366b85ee9f206bb1f330ea72f61a9766090eabde747b1eb9c046cc8713d5a4f8d4b7dcd7c61f2496c5b467608cd9260382b8f11b04c318a5ebb6411a4c7fa060e08c295c6062ac644bd3d10bcbfcfe2e3748eba66f65d904ff21147faa8475f508f21238d42f62b697249b9fceb905127f7684c8130cb8663f09cd25ea038078e1980237389337d1446c3a77bce41b37b50b9c3a020526e7b7b3bef370cd7af71b225700627060eb65693899d277ed130ec5ed9eee75d4886f31aa93bbf302e0c69c9c4499396b43dceb67c02fafaff8b56698308393a03f60babde883f00de2c66831f024fafaf98b2fcf37a9ce01d4f34e95c9408395716dcf83fe86c7a0f5e3e6741c3b63b6ebe9964f1d5005eeb732ce66402007beb3e6a087053",
+ },
+ {
+ "9100c5b2d7c5d5a854bce55e82f94b89a268da7b66357a661dcf75cba10a1b320ae0e4e1a5b989f9766e57f867a3810a0b5b857191ffd7aece4c796f5694a2617486421940cc12b63a6aaea20d2fac188b318a1c3061cafeae436e04d710654b96a864d674768caee03a50ed6afc06f52d90115df1db5c9f1ecaa4f5da094070b1a447251ad3d4fb0e24e87821ee6d4e7e7eac7059080f77d2b36cacbdac1c6e5063946a376865458c4ebdad3c2afcbba8a82b01b03a7882eee42eab904a19e0aead4ae515b02aa2fee74f3a114bf5b9f320baa35b3225491653f4a69e0d864cbbd031d0805b727e42c2b9530dae0c01cfc6a42af8ca730e1d67b4bb743a072f0a38008b937209d534c2284271344340fae76af2b1dd00cf44b48ab8ee92e8f9cae8845e5a8d338f505cd1c19014018bfb6b7dad487e7c8c32064421982c1a63149ec16f2bf4fe7b50cf3ce1e33d6cdea8e98bf067077c9a0ec1bba6edd5090273ca719ebf6f1a0f3e56f021945cff3c468b2dad92a947a06a024758d7505a4a1bcbe9da3a03e97859da99ed36982a7c23572ab60071566b749dc34bee1d9609e87fe32282cc9adba633c9ddcbf359ef4a83a54af5fbb5699978b487954a907dc9739f4b3f3927e66cf0c338e31c272da0cc7795c72dfe60a5b2e73bfd77b8c6ea58122a913910fe29d3360cef5d398f29b024f0dd225183d538bed2b076989aceaac460e3d45e0ca7941897f151261a024b0adf6d5b62429420144497adde6557a3c53b7723471fb760b6a8b1dcc2b327cd939528f5d7bc16ec00ad99df12f082d82bf9fb7318b3d3ce5b84ab1e38d2ebcb6713c03fd0d62bd083c4af96b4316ee02b6953431c261278aabd96e28f81adf7946e3664446135c825e45ed916ccb941350c84523296cadd5360bfe3e16dda75db10da1f710fe796f3456f0911294a4735cf9968656345b9c3049ca47176194c86f36cf702538df699fcffaa254af15b198ac37eed0837b00cd3547e496ecacf6136c6648a535a235059cd75a3bfd0bc49933b379b72e7a8463c268faaf05f0b27256fb179c9d4c923a13ec6600f83aaa2bee13e30c8e676040c06aefc65ba238a29d403f3a8cc164a0bdcaa1a5f54bc1d35fa4efee0c402eccab1e92f6b0cba94e1bd87898a9dd3957a7eafd9d26bf70866450646090833d4b91c032428bdb9097b409305de669a58e44931b7b428bf1a6dc56177cd944b87b04eabd80c64e287a5758c83db26dbc06f0c772335363ea2fb9f19c833644fe3b3fbbbbf5f9d460412d287eef862ae676f258aa45bc8465667601e9ac46e7d77693936c8d67ccde94e54d746b785ad26aa38ca0500105b6870790235e780ac50b9e3198f5fe678ae3a4ff4f1d4a2177edae183daf2de42625845973fc544907e27a90d868f8634c9d529bbaacbd228a5b4ac7fa68ac208e207a022cce4b24a0b5b5791eaddc6b3b3ef6e5dba41855ff531de9bbca0a39ea743c0732772bd32cd15c4b7f28a6ba579d902331a88920fb970aa75114e14b891d42cb947e9eb14feafccf1393796b21099e52b21773adae8e550f93364b1c438dd7d7fc76994c51860b652974d04a7e6ead207610de149f231422595f4e9ced1674d98d0e15ee841143ad8613f804729524e8a5f30d451611676f70a60c5dcc7127497f4d27f35e7ba0e48f98e9022e0deac400e809170970867a1682c7d2f3ef2c632c44568abff76f4f804841ae462c7247147b6e1debe48802674fd55b2ef1be5b4604d5f60c35358c7d773ab3a3ad0ab81868c6044d4e06a48ddbffacddadf813a2ce09aef34f3b60b666245a032f021b87c81fc506166983f25930cff728d399f6dd48ea1c745ad2da7f2cdd9e3ee915f708db0d1f3481018db1c174ea950ed17247bb8ebc065186758e5403bd4d19a445e4a15519326696e4280bcecd1a903f525bbe1e521f94d79df8db4b35f4ef7bd990c0f2c32789a75f95761ca0064bf251fa00b409a58b979e56d2c44bc2302552f118162891bd78272384c739c0c98bbaca3fc46fbb5bfe123eb25df0e27343e38b5a0c2d0774443af91b64b9d4e0649f20290edb84fcedb3bf4ba491bee8754a32716739e5ab64deb6c9888bb9fd2ada1629a59b16934ec5dee3678dcbdcc7fe5e2f3833da9d1281669b1d108837eaae5180396813883de26b957037623825b0675df431fb06b35191c06229f84cc849ccf1b1e079efc2e575331cd77b3297d2908c048b82b7dd14883f3e707bf6ca38f87c19625bec47c11f54988a97205d27ac51a32f19704391af72021b78cc4461386dc3844a1b45596fede3f70e311eba92b1d9ac221d3dc19f3fdd080c2169348f2cc8c9380e12a7ebf69efa37bda4ca6f7e66919b94532ac43022c0518c04d0a8cd99e0cbac88b7a317a1dac5469534b4fbc64080196b44498e149b0a196bb2d6f59392a21c4a4523ec1ff922a52de790e42810fd9355471169d22b734dde4a3361ecd57e271a92132a8b35cfa91d508d45618ad8c6c1ea209405a3d1d3ee1535caeaa3f20546052fc13aff7a584ff79db1726678344098d8563caa2a2abf6fe5aa03d7af49dccf1b17be85600e7cfdbfff54282394b0fbeafda615185574fdff78d59ec2a26dddba1c531a1ac007cabf5be2e2f0a3dedb9174e0a9da5597c9de6d68911fc66ec9d2b1e3fd71ebb83147ab14384ee303d067f47a324a01fc187f54a98f1b0848fdba2ceb3c18936d503e71887d548c4dbc70b7eecac9ead3393f8cb85a84f1484f2e237b36b6d886f54a0f629e8bb05b0c6839c722149a5b541703aeac04e6eb230a5659b12ed0a668d018f75bc94258218c1f5390b9aee4c0b2836cb76a47da649e2425bcf4cc15c4d51d109e5f78cfdb88137c31b2510264e46f1c4eb6e6b3450ad901ff9517b47a24d508844dc85fc5dbcc079e2d09f301691f401ff5f36500cc66f0617eb4dba389d427c7ac778d78438506608f0961f818a2080ea56d0f61c40fc342b49ee63e730df61f757387b9089e1987977b7fa02d87aec2e4be24b8bdf7fb6286d190f9df870944fa910df32f178ab692fa56b071f57366a3981f51800ab416dc4500abcc19e0c6aaeeb9ca063470993ec749a0bcbd07604516b1d51175ebedbaec8986f67a4d9158f75b5f3bcbe86a83220b4fdf12a0242951f94ac7d52882b1b209b82c4749753ea4d46a60bcc4f3eed033bde2d3d20c25cb46fd907f7052217a0a4db143b2efe8875a59441f4d22ef70d0c244b2de6a7e15581e84c860a6326ae3e3aea6d3972e2de0623d2d852c9e65eed318bd3d86d29595575df60d9050e1740f884796b6657718a294adcf2303adf61c6b23933db93885172e82a78f741b8efc6315a2c88ccb6b11692a346cd82a79334e0c610734e61e6378b5e2ecc161d924778bfcf4475805a0823a0d5a54768d9272ee99b7c4a81b3d5dfe1a2f5ff34",
+ "3c77f30bbb698b1571aeb54653fcae2c23dc16be58603f0c361eedd813ec0c4f63005a1e69e533da93e820e6e4ce1308aa29c60289060ebf24fc9738e8a4874ca4e26a0dc79ee75b8607416bd554737f",
+ "0223c0a6052bb3cdc99a284fa169ba76be2df53b677642a606090a9267a60769",
+ "7d3981073f90c6648c5e9c74",
+ "61ec5230306b70113f67b340575b77ef76d521ff75b754d551e4177591a02351ad382b2a4067f2b3af7e8e15431c7133e98be9d8293d17ef40161dbad9a4f1a4f30cdd557bb9a8b03b5f1b277c850e23ecfa0fc2ab1102e4b1d5e836a606883c3d43527fc3aa26955964b144a9a56cafa7b174d72a0635b80e7b4f871ead3838a955a14c4b8c5c3c66fd86a5e4ff10dfaa92105378bbc5f76ad29727e5bc4779ba3e6dc19bf45020f6ce4dfb3400df05cac51577d58eec21b22839b8f055226b204e641783bb3305b4461172f1c1d48eec56fe6f82aae564ac6688d7b0994747d9b23a24418e69f8a4fc548f854f86baacbdec78b7597b138c453349034c8cad2ff272781e0e6799ef2f8addaf18528736aef21ef8c2d213161e36b2c7815fcfc40747626e0165684e46a9a2275c533d548e52a9952a556168195d602ead86f6bd699e97ca59f4cb2050ff148f5bdfec358dc4542ff2f700db9861dfe5ba377ec7fdc0fcb2501e72fe6873c7cc76b95b4f300857f76e6e6e370119f403b556115b19fee7009f4f6675ad2d174f44002e35ddc360f309f20a3a1dbf39d90d7e5fa2106c53afb0bf445e4cede59cb50b8a7a2c0961d00b2c251f2d815309f74a46a424838ee87f1229273ff3b66dfb79e3b1ce11bd60e061e60e3f37bd7ac896b618cd78388590f44b1a276b965a4b95f2e3a7a175b30fb45dc7a71d4b3a1a33e98af30dbb46a217c50046ac21b8bbe9537c02f05a5780c8a5d796bd6424fd9e9f3ed5932069bc050bf4a1898a0ef0ca756aa2e2269b709cc92e0c5192ab49d692143388ede2bde4923c85eae8f59db5c7711dabeb33743c692be6dfebd815456958b5e1384a109f891f433e7b4a1031d4f30478b05766dd97eb964a28f2f7b55aa6c27c7f4ebf4d47ee8709bf99915426b3896412a855798e392e111789213af537cff7a976b4509e0eb6ffbb8e886a3596a242d16d95109b0ff562c624e06636a3611f804f9b2e252afe8a4e5e868b48e9e734f688f2da2012d7fdfe2d3aca75fd74730a85aae90353417fd52b92d28a5098b6af358a096b859859916bcd5a8f779676c6e04ea461fe62872050af92d08cdf1124bde1e889ace3c923457ecfe0a635ec757907a131ad7c2ca3f60e1317880f843c5e63f4ba59ab2882a492dd1e070b070af6f60e18cca29541206a7b267c3f75a5327fd9b8ffc9b36b57b73b36e586541d15c85253e17a2581e8f8a1518f275cc79afcf2b5c88a16e9bf553e757df089b5db90a9dcdc1867b788fe75abb5161dd7ee1cf37d3f0faa793ddb1bbf1eca13f4220ea63af8ef7c0e7144d999ba1c5a983e74d48cef708c1d28d3c0a168ab87d0ef70f381693f0d438ce013ffa2cba65a8cf6b498a7120209564535b7372690329cdbd74eaa76765962720f06aae58338a10064ad80f5a67395db2c31d36b1f5eb777306395f192599d2f737327afdcd9f14b3f24155a3f974915d3302427494fad756703b13afcd1764ef9735e7dbff920f1253cb668e9f40632aea1e0b4620db162138e4a97e6f0729b14be4a7c3256250d5e7423ba1238c704503c51cfc9cb68db7001b2f597a15e77138beea02e11e0bb98a72f2a77b7260e9172fe7e60483114ddd836addd966b69570db5eb26a0cfc4f8a8b80d26357ed51a70165bc0dd11ad7467688025bdb532e7222ea12f23c44d08d111b0ad4acb2f5b3d6b45c387d541ffc84466ed57acacefb1436ef00bcb5b6211dfd0650113ac369b9f3e4891acb2693c377467b1e9c949cc0ea6c4a72ef9292964275ed397cd2b1ed25fe1aa8f47e90cde362392da5e53893eef6e4f61decae1a75e3b726f0596f09c3cba62aa08bea89984b484d5768296a5afa8b0759dceba530a169d22b81979212b3343db35ce4e4766dd251ea6a47f5033cc090d6577efbed441bb4f8944937e812f12ef17ede76df621bd4cfa31567ade18b74583a2b783279150d584ca13c0d4784b70156afdf9be8ae96666b82def888465cd3df349de427d5f5b3572e4f963d33f968e6780e381ca196bc04a6664fe93fdc8558b21b84130dfa2a646950eb2e927885925af46d7a28d1507bcc3c02ba98318bfebe5b9eea1bd47935ad869eb701cbc35a9aef5efad88ff54eb350a34ccef2e159de8e16135b81105bf799fbd86aa11653b5ef93a1ab1c367231d61b42b8bdb4f04d8d05396d53247d51890be9b56c51cb19eec0fd1e6b8cdc98376b6c6b30963ac7ab02656ff94dec0e3a0eb3f3ffb8bebd99d5889df98e6c77093c370373dd5f17871fb334c7eb12c6ca22deb75bdac9eaf24281c965dffe03da9c940e13fb382fb6be332797813710a7cd2e7720f5b9e53fc0d98fcceeea4a8e9f787e670d60bfc4a849f34571e5d09b9e9c28cdf2b2d888eca9bb31ea8b9239bd19dca86880ad3e12b1583acc3a6d1f0a438ce3b5a337487279dc4ead1b214272d455e6a2c8cce4ae3bb29abfdbe77a67ababeaff5dd9c96b17f589cd4615c0209eba5e4b1c7167b4b739ca4b9957185961529d1082226f85068890c94aa1f1c244259ef7b120e40114926a49c4412b67b4caef1ff3ce6f3aea3c6107b830cd34df9f4d73d7d978b6b9d5c481e9d76e83d649e742b098334838fe50d80975fb567642d3b72c461ef3072ebb1d03c0099e97575bae6a12cd2352d9d296351df6965d736d7568c2911394a73d199743526ba54dd62c56c598f4e78495c0172739274c0b8c96755e489765723a24a8704093a94544f6c8764dcd1ce6b4bf2917cfad27d85e4442b4e5bd577ea1a88c2b79d61cc1be01ee9028235b36444483b4e45da1087bf6d45ca540620de5aacc644a0d5c4b807b582c7b058e140eebca539947502bf73c9abc81a0e3a618b39d3a38c4ff7f94767fd7e6b9eb61e629806bc3d183bdade7e369d180dd2f57fef677e22ce41be7224f11723a85a3f1d14d7b72dc98ccb2816b77e625ce3db3e2c5753af8b079e0d63939079a01910ee4699cb405d4d9c60e4ac86a7fda3a4c9c290662afbdb7678c3a84c87ff83470fa8a416511a06d3216a1445699d7ad7e6980491fd596d39762d576b08fcbf0825243c1fc01ec8300780857c429c607113160a8354f6699b368a87983464472a5754fd58943fca6f6779764fbe6cbb510d5280292df02c4a7ed9acec8c95ad67ebcda71d0f519ac18db9b43b28244cd34fe02c5d694df57410eb54c5e1ca0f8501e7776a811d7ee81eb9d8c80b2ca50a012b5eecd5428af965b217e7fdac80be88a01f76d473105b027eb557a523f13c55e1670ff34627667649573e0f19dda41c525a8c96c2866a88bd73e66c786767e1657960f6676d8a22be1c6024158a0f0e4ec761148b5a3d8ea481d8fed94855be82479ba23213190054f937838f0e35e00aa74c89b294c29ea25ad7e96b4b6fa952ea8f1cbe5397b7c86d0b74ccc25e22c88736b045fe86110bffa0679f28a1f27162b51410498cb7",
+ },
+ {
+ "0fcff2c29cbb5cc40bfd2ec573ecf368275ade6a00e5730b77dab17e437b46524b3814e7f470acff6ddac4e0c6b748ed112657120bca1d83a4ce01e74a473995804d7c74bd28732a02370ac8ef52b600790d1284d82f077cfe096448509dddd0eb5944a882b7d384efdd4dde3003dea910f12de82035651e3ec9668e66435f519da3fa1f5bcda34aaaf028daf3068304f7b1ec18e65136241a9db281e011d27db5cc9c1099405a4430821e2488a228805314983966ce5d806b0f014c21d4c9d6a066e63aa6407ed6c29cfa4a3e22ca913762ca9d31271d9c371fe858f3b22e931814cdbe544b9416e88f6026b12bb8e88d8285beaaa35be1c24339b5f567480d7b16cbcf6160e549ef4570a0702889feaa0ebc54b11735735b6e2850d5715e5087291fe8890432784aa219bacaa2b874b075c9628cfed5e76dfe38426f9693f6bfb2de49b710c101b2dabb7c7c74f12de9ba8f75b8645d25629568d12bfbc7eaada63364b6f56569cf21e54c95d6797e9008f3496c506ecfe5d6a010d168fb7f0e2ee3c423492df36a133fffe9b87d7ac070c32cc131fba6089cb7d904b25812e03cd6048504f7ef1736ee00ee6b7aaedb3dda9c6fd6437772fa5076aca9888ce55e906a62875979bd477aabb2f4598d32342aa10a6d187c6768f213117a9ff6d830603bb7b9b475002e20b2237a4055ae6af6b8d70e343e76265188a0f07e7820dfb3d898684d99966d4bb9e78b0e95f5044dcc12810a89a75b11474c8fc06c6e734407db91a072ffeb2be6773a7c6c3ec939514b43daf29feb3aeb7afa57e96d9cf0492d90bb2c7be613f2208f5f5f5898b0a3db8a967a75d065efcabdd83759c88086583bb3d422c6c6425525a1adbd515199dbe71350b77940813618b88fe139153974c80d968ed4d9e3f97a91b7cce250a7c963f880dc38011250b9a131f2b76b677f78fd0e4cd6f1465182fd1d644dc42db0bcad8df4ae9f456841765af8e1c1775abf85a69577ece6f9e9035e36c88be784397479e713be4f5434aa4c166bc4702a4916c0c003a6baecaa182372a30af6dc7e6fc4912d13e662bd327829f6e85340fe130001babaee64d211d6761bcc52993c162a692a10cbe7434310392b64792a777a2b31341995072a6b7d4538cfde74e609dd1019a9f75cec0896186c0f42e3896d15be87aac5b11642f74e11d5c2f7de9f07f848ff543507ea4d73fa8f5683fc6b41831606352c482c7a5a013c51e0db59d824582c595f17a6d2113528943194d6b5aadcead62516507f178cd0f76729cf8b81fce4e0138ab224bfdbb8f16f8ea6196b90ef90a63f0fbdcbdfb5320984be8a80a26b932d1db7ecf870dd67fe838069136ff9b9ae087779e82cacf1b06a7b310ce6c439047c26fcec0364ea87e4549a544d540256cb7c3ef7282fa792aad89e919dd89519fe910501f5ef88da43232e917730e742ac2539d454e066feb9058f56dd246fdbb674dcab636585a788b338ffe41f4190447a65985acb9613d02669ad4ad888004c65acb0ca315752e58f51c9ae9259f20cbe8a668a207a5a46e30891bc909108f53db8bf6f0f11549e621d4cf4763e0035c867bfe9e1192fc421c080b25289a78f4167fe517852efdb6f3ccfe67ad01b4337da2c18f35bdc151c5dc76ee66efd27d5fc784e4e6829bea4f8a41ec8bf61ff998d178ce9f4a10551687337d7705eac6cd7fabb3f2379e31c1d01e4dc63e475f0fb01d9efa3de400b5177e2c2d68f2ead89e9ecad62cfc97fd0ad5b3391d0248dd2fd7c75dcbd802d3463ef0af21eb77b07a3286a72f1e9439f457630159abde7983a5c74f7dda12b40913632afedadb691d62003c70a46664fbd976457544cef8ea863858505b1c596e7f745d4a5fb657b1c694226afa9756c40d9c49425b323ce17a8531c5919b24010f715b5f27a300ee37334931ca9ff5c83c3f0a87713768ebccaaa15e35c56f3536ba945e5d954c94c885c68325bc4b51fb55d96c8d424849ece9a812af0747d5b1dc240f71609439f65acd1c17086e025e376eeb79a7255680cd692fc4b0f5768d1985fe8a1a387074f58c8bfdea8e5c11ed379b845ce2052a5b24ef0c1a658923eb87adf5b01e6aa59ae6937564ef97421722c67404cb9e5fe07d5bfad2e52ebe6cccb41ceb1eb2760545fb6a3582bc4ca572b0aa4e4f0a2ecc56299f3b485d980501a4e010576615ad518fd2d43c1f79aed013ed1f1e1bdb74357aaf7dc84772c9ec62da43c8ffe11a7fb3eeabc3584a936c37b28a438dfe78f89de6b0d5597ac1bc55057544e68fb49a6e505db69af122c2a3ad06219b7f2a2955db0ebf55c06baac5e0efac609436dee484857f75a8421945484ad0c7650a1d3008cc85c938208f19002b7994524878d6ddf85c763a65cb72a09c3a059657459f13cb584bfbd754fbf2de904517092be4f1786b2bde26ae8eb2d884592fc9e84395408f8117e47d1ab30d5fca167bbf07e41a33c230d240e3aac53cda9f251e24659da57d721288252fe7ff3653ae3e47b86209e9344accef0009b99f2ec7b3845558f1d77b89fc9b61ebc1b589fffd3261f71b9631e87541e22ed100e694854bed771358f10fe452fba61875a605b8080cc39e3eac13708e32518f28e60464c38b782c7c7800df63b6e7e95ced9154ea54e32900f6998f38eb1e51c112b6949e2eb11a96b1ea0a68c1e3b5af750a99c9fdb2cae44c5a1d37686ef87b158d19343e23daf00dd558cfb91e6f2e18f8e806abb2faf80d082f657717d08ca4e9c0d30d9bc30b612bcb1a3a3a3843231059dec344c6c04ce625b3fe064092e00175fd9d38f8fe54c4088efe30d211412be01460a6d4ad8d0a618b00a21de0a383de30ccd72f119b27a08958729a999e8aadff21829cbe8cfe398d90476e33db4c64981383a9aeab4a27f3bcb29d4b3d3b3a6ebdd71d3ac546b8658e269959630de176819b153cd53d2091efbddd2cf9178ba6ee98e1a3df9a095db0a2b713a0988a22239f5f08cc8f9abc3d67d9267f54dd5dedbf01bd490b0b09adb21d4e5aa7707e36cf77034f01bf8c7988a2e8dd7046bb2f486878436371f1258f3f7026afee6d7f6560be67103ad098edc9665e00118d4879f58bdd677cf2e6bc631d5c517acbb6db8a1debb4fe7492b7daf0b7ec7df056637c23caf926a1a589bef1db29cd81f547afd0fc9e459f46108ffdfcfdee43515a771c439dbde9177ceaf296a8749be0146cdca2b26be8c2ebd6cfd9b5032b1f7a375307f54c2f622711f8cf8684afaaf17c4da3e83666c40d26adc239c8d1a40024bbf560db5787ed404763d4e70ec6635c6a4b82c10f8ff7ad42217613c57648716ba94cb33129f3789dc86f9c8ec2e8e90e6bba0dfba1bb3dc3215188979a09f33346a6647099ed0e624c9ae10f83da0def840bdb25b718e8d86a616ff46b5327b1f99c22937920f5b5bbd6b53fa0b32f24befa4a7603234e6d94be51f00189a20b15c49e8ee58434a15ae9d10b9cf0204bfa7ab1fd9e006b22bebd22b036c4bb4c9949cb7ecdf01028d9f12466e144b2dbbf64d95d65347013e192d428678f64f0d9306f97208fb00a70d4615229143dd8890725ee3ba6021d38d6359055aa812edaf",
+ "0c5fb7075f5e15a6733737b614bf46871e29417e4b140bae6e10081623f5c52f557c36b4da4b5a4e82920497514b1e6f745fedbf73f86ee10976f82c6cbd5bc13a917514ddd062",
+ "e70954c812cac03e367e99f7b82a6dcc073d2f679f965d524872756ee58654cc",
+ "5f6267f6b3b21423267310e6",
+ "c53868c0fdc14e891ae1bc257fbb13be210a5d9cdbd9d18fe1b474f9a1929dbba3f25222d8fe8c1be3eef22352100064b922fd9642ad128a202b6382ae0a67c8affb0c5bfa1a80e55c1084cc372485243df872d677a80a3ef1ca3589908bca621f6f50133eb762cb9c05775d13db7dd3eb65ffd3eef96e8dd42928facc68390f6bbc50b17e1ef5ea6310d8756dd177be2cceb63a97bcceaa046794915589ca022d90756b02c22e8634c0ed44192abc3b8b1e2814c855ab27aaae3bdd801a73e6209fdd559ceb59a94fd98a66d12a31a643ca2f4b07ed910bc390f77ab89395d5cd1d783d8940dad4447f0452991b209cfcd998b0c814cebd08f9ff15052818bab0bf51c3b72ac1020d3b0974fbdf4ff941b1ab9c01f284fe82f2fd89c0aeb4b9fbb0a74ece08b3debc7b65e7263e2922fd4aba15ae3cba7885d04127c8e06a67f244e7aa4556f8694a5db6653f6e48d6de54f9e4024d25d3236d4f933205b6a358aa1506f832ef7d556c6a1bfe4aabfce51f3b5ac64bf6ab1e665bddb12fe13db9f07a55db3da3886df36ddb89f3a4939b1e9e5b701301570e3d01c0b947f498dcc6af438cc15e6038cb78a78986da0316cab67bca3e28c95e6b7e6b36cae9202cf4a77a0e15d3c3291d267aeee172dd587a944719b9fbe077603b4d39d4302b9a6415aa07af309a5e1cf7a9379552becdb4bc6a0b5c85d2e63bb141c405afc58a8b2b4188b3883a24eedf98dd50fc54725c440ccdb03514a6f37cab49296b6826b6bc7d7ad8cac0a3425eeb6866d94119acdad468cefe162a29e8831c77aa83321e8ae3e20e968cfe51dbf2b63f4e26c61536e6be4f63d61bbd06af38023b15f4fccb8ae0356d924dbf646bff69d1ac0d6e1c7f40b12d6d16e52d1c15958add5708bd38c514e47fe623a67c9ec211cd625b398fa7fd67a23e6e9f65d42dda2bae94524372fbc1a7e0ab3f1c451c126135536e73c573749aa60177dfb68843752b010e2cb9c1afaf51c94a48cf8ac7aab3fb200aaebcedefc6cccb581848da0121af92d9f4be002f0c2beffdfa65c36bec80e7f62d7009b1eb719d24b96e97059e6b50a52662c2c833738849f342391514349305228b29bfa9c7cf2a931558ca8e704c600148a28bd871465b23af499c11784aa45acd051f276d82789c58b14f12619372be4bc3a285f6cee21d65648d18e61752d6e7957736d3385f8ad36702c451c61ed475997d6d9f11c8be5257d8febce329aa701028aa2b5644b8515a95b5e866780e32754ac2e6f2e31b2c04a4ad35cbcbc25b23e9bf49cb1a5d877ca30880741757c29303af8676546760016f1538991b37cf0cd24ad3b1d877e5e1bd083e4b990af6ff5c0b28e530db3f463d21e76c928c8e1ffaa6c045937ea171a9071827a173e231f50e95430ae4895932c88ce048058ce6d0a50ca5c1842506158e98bb2912a61c7991a2256c97cb9050a4bb3ca32594622756291340561e9e584dd2e096263b6ff8eb898ae86f5f24500320d2d0ebb30d84cb4ef876a877dad23a611b39bf0cba5e22f2850e11c298fa23fed40691b83acc87136f8fa540b1dc40d1b0d0bd489ee9dad785c121955a094a2c6bd3353e142c04f7b88b2eb3305fd00d5eddb391b73fa2b16a6357aaa2abf2059ec979bd3ce06d5fff1c325bbe5c833a101615750613047d8155ac0c3a0734cc6aaeae7cb65d7501cb95f9d6d1161d09c961c0681547faf7983ed2efaf4e0fbb87a06169ecff1d0ee540a9223a73f75584441d4669cac09c2dbdb8aa2aed74eb9a2870f2021eb16e5f5c3e79a24d7110af4bece22a1086d27642550cadfa4f0e03f2c032a2745e1c9277a4f67fa4dc74ba056110fed3a63f643567d079c9430b8d5b3bf57a9b3f02d486d870229fee5462043b6bda8d265c745ddc1b8952bf91828d6db2edcfca7051e74df9dd456dca5e04ba469b9ff6a8130aab3903c05659b8f31cf4ba4c22511493a36541ff9d88c708dfb714d52a3c0356543e6efad37530b598bb63c3724772907abe4cad39c896c62daf5b30cd7d37eb36a7be2494353028c76e8d148b018c7bb755c45d2a33f61944071bae8316881e9aa37e4ec2374aac4f8436ed3c7db2092326538f07fc6644e0239899e3335f73c1e3c4602b12d19d7b639d4968974b6b2703ec1add8cd930cbafff4158f68f06aaac83bb4a2e31466e2ddc247ad71c5f4c49af7defd1394e21819cc24c78380caefb2ce87c0d1050680313037def12ca21cf67bb6692d6e4a9e90a9c9a0b7118ac300c6c6f636337aa25bc59cf1d9749dc183803cc0ccd1ff53210352795c6edb49ff1e5e8ebaee7b3eda6e3c0c340fa60594115e37fab60133b8a3b39d2e63db0bc6a03973e236fca801553912f93feafd8b96766049dd2066f3c5ac9222121ee9d36cbcd8f713adc8779949941f8a8dcc92ade62e46e9f1b292d5f7eced14c3bff50a811cb762ced1f103652773ef946e18569eb5892626627e085d4ffb3102c1586ddf88acbaeed903b22d3e7ccd8b8ddcdfddb872403240bc8e0e46a068f55bbddaf90fffb9a914187aac2ceedf21fefa1fe32fc7bdbb9fd76dcda1fca7b39107d308d11a118e47499dc4092ef0cd28d0d9af84440f095b4feb7adcba198894cd89a324c60ed0b996c520d4b33391bbbef1997256af7ba7ec1069244359066af81543ca23105742fee3480f890373d3205236bed566cd22a62bf69f8c0f27b714f84a203bca1605865e2cc2f9211389e0df7a4b3aab9d10826639357efe1f5fe64a1bd6d06d0b5605658c4d2d12e1bec77e70ea393b0a09043dd7d6684bd53f4c883f2f6928d99ba91873d063d43600f9105d503b11d8dc2b05e34b4fcf18e78b2b6c97d3b2c9249a2f6566ddab2a8a67fed6c9f8af2f4ef98dd579f2d4fb572e178489c503df5d5f03bee9920db347a6e734ed72ec7233387f1579c13725599a33a90915ddf03725dce20fd3806abc1029a20732380596057830ed63b6edcaa4d4418871bbfd58de1d1f2800588ed207f2016e11abd1baf1895f6096e2c75cc5916836a9ddc09cab4c28e53fadbd7d3080088131cc270095315b61011b0cea5b4d64b647bbcea54d20be1eec0992c72fc9c9771cae19191cf6a6f1840acec1deff605626d0a0d79ea8fe0af63ea75e80f8141fa8d7ca6f4c99dc7e78aeacc67762ed0134f1a0b053debfb9ccb145800b9818c2deb46f7124e8655f37c3291af107ed75384afcedb44518ca14cdea341c9657ec638531011cb957ed6b3434b736ae8c8199684cc58862638c5f6c07e1cbe8ae68c5582b1697ca9dbdd01e97023138a9173d6b1294cd99514a28102e6912b1c87ef22cdc611133bcc111e95c355a26b20a3d6f0ead66e932c5e1229b0fc17a7d6f78134c69beb362ca75017b1bf1105ac8970fad48acb8313cb3ff10e9d72c4ff11f95c2dab59575525c98653a9c7d31585a3742267c062d6ffc7a4303a3e81a45bf39e1ce2097623bba70f216aa612c64ba06ed6d596ad6abbdde69d56ab45e25ebcd4e485824449550232be26f987c14008f67c9db9d0f709f567fa44502b9e0839457e5f0aadec0395bf5c38ed8de7529708e58c0a895198fc8b2570fb6e68547630ca7f313526d392ac4776be973205f971854c300454d5",
+ },
+ {
+ "95a17355dfa9d378a18ba20e58aa4b8711ea1d6e3c65e0b2d3c6382892c7d02768437d47ed50bf8edc619c340be7bb1cd1d88b0d3d6bbf1031f738c4be09eb264c686d39b92cc7958e63c9994a84b61b5c412999ace8a9dee0e2a29eeb8dc537f63271af5f3844ed9c0d86e6913c02ed7d2b862a132f08f311aa92fc3757342d89a5dce8dd20d5792d5c60be9862ab168d3140a061489472f2266f297da357064833ef2554c49f8120ff40b961ebcfee1d0f8e7e5722f049485f72c502c9cc4afdbb70517f0fd2a00e12596ffe285d1b37eb998e0e89d756e9491ceb13e83610a3a66122b533c2c3461b3244438f5f7a7af8088881dfdf6a29fb563ce38c4c8632ada8e7e06baa2686dc6aca6bc944e5c14d6e432c4dad554803912b8fddb1c18a59a86bc452914b2efc1599c5597f87a6edcad33a7728827bbaad0a975ecc22b7748d7cc71ec7f51adc8fe0350e67dcfb31af35a8d7b72391642e29c2fa4b796ed8f535f6bc2b1198baf1cec858aac38959f83130af55c21383ebd57d364eeb0e442104004c1599060667ce5e1191e76a89199a386e5c4bf147206e7d6e598bb27a90b3c6a54cccacb39a0ac42bf22eb40bc8ec7925376a6c57d8eac6317578ac052b72ab773f572ad961ee05531cb95ee5a6d70add4176351960fb4bd673f7db9f698616a8dd41823f2f87924c40f131e6c83bc40ab1f92312f46ee86765c306cf4a1d77275ef9668d80f9d9c1ea0aa7b2456bbcf764e009584ef1c0b4b4c683fee3fa2641f48ccf7485a8356fb3dd22f848deefadbef8050de9c5c19e8c449c6f3ec2b1324f80a7d428dc44dbb966d40244c3af03bcb410a57ad1430615e07553a22686f1a62dc6cf090aaac3707ec5b44274b7fe28c7a3a298e7a8adc71e016944875bebb421babd2b64809be3454f25b90723e2cec68467ad2d14744b15de8f9c397a505a340e85998e207cd46fa18d76c46f458af4ac3821c0ac6cd68afb72c376c31daad1a2435fc2bf333260c1a82430edaf2499e7455a93b1301eada2e12365ffcd36a1119664d0c996318a3e55bb2c04dfc5eb251f7fd64f9d83f27ea6577d748e1f85248355ed19867857dc3383e01249cc37684b0eb8e891aa663801e4ac8f0331b38686a19f0d19f6e94c7ac95ec395962be0a4e3c8358d2f6d8f13191e164ad29cd1733bde8c31c7d8ab90366e26cc9a06707dcfa60bfe139a112db827778ac348fdfe26892fed61db7e9849a464e3aad561797b6c778e0688bbbeaf3349727b4670a2d0a08f317b0dc9c4b12ea85c0309d57e754d0c7bd5c83985fb82f776c968189908a8ca83b5944767c2efc3c5f898436de54fe8bb17224012a437896d9fa106a749d12aff657266276129ec5ac12fc7a77eb06296d2a2a876d931e479d3ea201cbb4b1b20bd81471eaa33786c624013e1f07577c2171f38f0511c6924078a40c2d55ce392dd2ab0885e29f4c06907a1597c181b933853838970edad7777ed394c491cde27478eafa5b7a36520aa0779261f94b957e83ce058298dcfa07b08ecc425caeb6c599a11103d7631e77daa0d9d3fc6f42703d57f2c624ecddd56b9a27b848de7dd28f8ed656f1e4decc95a8908217e2f2453ae50b5fc1d9352d735ce5bc2b538eaae25501d449d090df793151811443c64f28d19eeaaac4081e10edca4c4148e723ade8f7e7b988b732ba08b3ce4c8a0d655bac4ff66048148135decd7727a49ac59d82ad470b5479c55d3d8399b790ff033d3ef99d770e1eacecdc140480aeca1e2167553cbbdef2090c7592b40681b733b0a0d127beefd49bcbe8904c975a5ab8b1afe56d7ed7667b5cf92f537ad6972b876843364817c20400524097ac9b405e4b35bbba0d12355a0b54bd763b4491b2acd4e8e4fcaaf8fcfd398499d4c4e81ffa93ca07a5ff51a1540f178f43a931e07e1ad56ab5ce57a2f7dc3ccca114dc9ba8a6934e95f4efe9f3f76947909b280ea5fd795bbbc0feb3ad2b704e305cd9d8f37d178961f77355eedc9d7f77c58e1db2f7797eb8682255939293c3ef7dacd2eab46c4cbbdf929aac301a13f59831a88fab173803399d96dc216abb9f079e79bbfab667ca590266891c8a7ea4bc1724573e5c5a67e9f1341b5bffaa538e240f78da7733237999ac86141b2ac0324f17609b71c885630c90befc3b027a5f01e33979165ce2a00968c414838446c2aba76e1d7fe3707c742f68af21d30e23b637accc848f6c8df820a27bb4e94e5090ac6e008fde7cf3fdd5931fa891335ec8d01b5d6f77db57a87dc35d6701adf7ae0bf82dda6511c83ab4d7d3460b221eeb3d6c4aa537924db5559b1c6739040534fc330f5144c78bf99f5f4faa715e85aebac043e2529197a82ca40f65a8149a9447a9e58c61618600b0c5ab221420c0cee114a133a648dbc2eceb2894ffc329376d1eb3ce7039cf30ff6a53038b23c26c38739fdebc7b919956ca2e468d577dea6621a8d66b78075ad26a6e6d8e20c9b694698540d516ea2bd108625e5fd038b5f1e19c5d5993b82bfe16897c375322dbbca81c81cef6ad900f0ffe5ed02714c208a12f5234d78e32ee07af155ad1e1077a0d8938f426d8f326c751f6ee66c8f707e8493cbfc76f9ddf1ea329e094315a91ba9385e16c890823db0f0231c7f939a042665009d5edd8e48102c515341fa6eea33cc00fb5d82380d735b29f2eec3f61428f7b186d43fcee46b2037ad1aa6974d729848cf1a80dc8ddb0580c9c876def06d8f7642cf45263a655ee77f047fcd76171546319622bf71283f3bf0b519e123a85765779c8bb201e99981ed184e642f63aa61f9cc206bf45fa6e514bfc637671d9cdfba2891bb112a3cff438a6372ee0dd3e7d9f352ce52f8b367b7799e1f963bfe50638f0c74b94873fcd3d66fc1e342a8bd36fb8b88f33eefabb78eca4dc9c89e2c57aaa010f2140dc5ea7c86cebe2f8bf42a167d1d546cc80bfa9258c35af6efb1a090c293a4cf588e4bdf5c090ee7fe38fd7b5551e71e5ce2b0b5a50bab95bc4c257edfc94d37579816b4a2249ba05c991bb2ea02d047e480fc8a8ba71f48f344c6d20d140a64ac20184e45b4eea14d0953370c237ef0a47a7a2f22997715dd3ee8ea52f24ffe12674d571b3bf968454ca051701e411499bc43bb55bbd033f9b81d4baa6c49bdd49614efd20d58175af868ca16a9deaf65216abbdc3beed5f30b209e786a5b4c006f3bd27d93e9d78b51a1a2fb7f5160a0bc1b7df70952ea1573888ddde3d9dd5314b0d0a899a733eb48d5e6c7274667e362e4da6b37c480aa4d0d8730e66483fb1453a3aefad69942ac7f09d3c571b6275590938c541336a121bdd20722550236a9a5e4a37c7de628fceffbc260b1e9b6417c4295907937b13609b8585ebb8f076073abdcf19104ed80ffafe1b09997f115d987a552be5689c70fe125ca702d2ae4d807d5690bc2e90b72cabb0b61ad203b34c68df21c16b92bf8def5680b204ce327214c32e4363d5600f96162a6819dda472acc6441858f396385a16fa5ee52cc0f9ffef3d53c49d535aa37db2cd4b573ff81d74006677969ec1ad891082b5d18ca5b0b9f975574ccffaca72b805c9f7fdd76bfe3dd384dc953255a5b50b7731a137fb9aad42e77d3da1eff5a7b9eda5814993cf2d289bb25ae1680ffcdf419e073d38b4701021adb2019359bb70ff4cca930be7bb979a0678f20665d14803d8753c8ce54cae92feb026486ba747a861daa449863bd38cb4d5831aa6db1e7f404b0c3587aac8765aeecec686066ee7d11321574f04d3f3da571e71222ce07277eca7ff97607",
+ "5e24f34a8d53b17bd0c2aee5369e3276dbd7e7c2ea0990f1300fbbb00831b76655aab1e2fd625ecd",
+ "c1d796f1e651a1ee825855d80206baff6818cc8c247ee6ce62b7531e6e9ac32f",
+ "240cb25aaae4d085bbb747a5",
+ "319e968ad291ea5d4a057c38f7afa4ddb9c9565962fa1a7b231e397a268ad8e0c5030a2df09dc4f99402ddf2e0d06e753bf55e1b318b3e5ff0108de2328d3b8d53e23e08bf7d84d59fededd60d47bbb52736b0491f82c616eb5f779c496abd6499555035e4513c8613e7204e6bff8d06dfecd9ce38c6b83efd8d0e41f84f7cfc9ae07113237987a4b2eaa87f7e0a310155e282e57858244e9071712fa026cb781e5a4bfe6fa1bc480e534096394459a3d1354e2d9a54aac6926a60b388410fd0b53f7a3a9116292f37406369c22ea674418c4deeead171e00f74f5cabae5d24a0686a4bcd8ba99aea613a23edd0a019a319daa3779c212fbdca9d772fc3fe612cf178c2aca2aeaf6bce2433494027a474eff699bba95fc7dcf79ca1d77b1e097439a9050a5cc78e0b78bf2e7f50f959ea2986a59be3880519cd84d0a673acb0432feb1945c603e70748445c74600ccfec60efcf9e4d02a7df5f967de4b473f63b0b0499ff4ba350ec1182f3a0ac17ef9ae28945fc9bc714c49909a7c1e2f311aa6ad7652e22e1f48bb51cf53814a2125152813752d86c7f9468a991d0ac84b1a2f3969b8081c228b7f5760718036e26a10e211ff04ea323acdaaddf9b06a08c92ed663d0fdf13fa601cda45c416c2d3803dd9b5ca29cba57e59cf4ad93176c65c64507b1995d638541c90b381ff758833a2ad67b0de44c280fdfd82b3c6d4353ae30b33768863cd3169a2032f26e37ddd57e7da1673cfc7375bf6e6792495a2b434155d684f2a6f2b919f944469d47be5aa7da74eed69d871e6f65c3ae08904a9ad042ba39905188f0b9158fd14094bd6a408fba6ef57566d69eccda86bb54cd3ca7381f51bffeaf8bcc1ae8df91d22c359888e21b70f640d6f3726a34e6100ee269124747f0ca05110f63deee07e3628bd6aacf926036ccec02c0b6bd7259db52ea8b7a686b36ba1d0296c85e43e25d72ce46c66a1e646301dafd2f4c502281e6f949011cea69459c026c65bd130d6ef06be17b23a9c9a84746e39d017b144135025ac527c1e653f233770cd68e9f232c3b623ceda836843b3e9ea313cc6a57d28ce71ccfb7265ce73b06bce1447220645e6f66caeb06b55129b97c8dd8db54c94d771504d24cedc86a8ec706a9f7dcbbcd7fc7cf38005b2913b1cfb77370bd23183ac7b5ca5135a2738cc91d05b2b22640469e3daeb6a7b0f14fc6652563663520f7754aba624a35e5d24529a6ee9f5ef0d019d83c04f5a93a38b68cbce0cecd42a11aae305475806326aebb4f673791f50c9f90894add51a0fd7c02807efd8c1bd21fa717a860e224bc9fa3f40975fd8d558e4844a09f8920256528450d77e546604e2ce2d38efadaf39a0ea3ea12156174aa8a20481e6c1190e448564675f9ca60bcef37cacec5aa218122e7bd25b571ff10f54979d62018b779a2a3d5d7d6cd56ae31efef2c844ba50ff9da88eba7a8e0d9fc5388a805ba4ad35eaa4798e395d2fe112083cce2f11cc850d25ca5c6e60a9996cee4789ca99d519daedb62f4fb1e535b742a35d71d7390117e93821ff18948a78c1fcdcb90a5f1211327d7ee0663ef16ff446e0e22d8cb7b2d3d05469b1c02864f4a87e2d9715f60c9e7be841e308d0a5f6c50161a4a0464aebafb88e0d2df8cefcead93c9623106d5518a9852f320235594be10c45bc0cf06c9daa007100ff97959357f9be8e49c870d0a11c884213e266c35e9131439fb3654fd5f1abd1e778ccb02b8c262753a22653a09272a0c33b6b2683c9045e8f967af756b98dc1797ff605c64ac5bda8252e9ebfe0e4d8d7ca754fcca5e3de3c4b63678da095281d76d60fa12ff4ca818825f346b9c4e426cee16db5818d78a527a901cd088bc2983f9b83430b50683018996996717a1738439680b68e3f61cbdcd0f0e1a6b436af8fa05d3ce2228054e319bad1dc6ac970c75313c552fc1136fabc302fcd1d09ef1b9138d18133a772cbd9cb197ff58c6e898f9e83e4e27206f3b15b6bf2778aaf9fb38e0d50152f8dbf5763816132a04b4b2e9639584b3dc8ea6d95ade024f9497944200ab0aeab206ef099859b9240aaa15f737c1e0fe6d015d04f47261ade4928e3c2ca21d1f5ab4a3f571f2ed92ebeeebf2493e6e39f0063ba931e165384ee1b5081f5f8d26ec24716757037f5158d35effbe67009080ad7b0381292a513f312eb28328cf5ff47a6599e36c14277c3eb5053c5aca530ff5954c21c03fb3fd5fc0facdac36dd819b0495fde421411e0440991da0cc4a20d294446115c0b79045037fbfacfeac574da3bf192fec4bf38c27cef71d03787430223b6069ba6d9273ec8679736a832277c657862ca791b559a5054ee8c7c07618083f75480c8aa01cb086c7317315911802e6cefb15bbe20494b14d97e3a885806db775c216dc15949e3b724f7cbb30bd2c46bd5a2fd6132352c2b21cc2b47891dd9794975f70a6fa7a0791ee761ccf4c263f27f64790826c1aa656c39483e029baef0855935e7e6c133a4035a3699925fbde131ca62948879373346af35bd7fa52b8d6c3338f213bbd9c79977c0d710028d1d386df614c5faf4a1f8fe5506a9af7059370893ff6d07d91383baba67a617b5d829e0e2eb20e541ed5c34be7ef0eaf6c6f6f52d7ca01933a2a4e8de46e422dc95161ba8ad354f6bc7c8e4cf8ab5e08607530147fcd7c9481afc621c5a3230a05e2c4db79db9e1e73f43556a8e8f0dff7ffe420282212f23d4c5f6f8d2febe129b9fe5ba7ddf27f72ae898a4eba270b5d2bb3b6b06e38c546ba80a9b2bc46097d0b47db5ae72485ef2c6419e856c33c2d66a861b9d474699e730eb8a8992e3ea9c1ed74316687d5d9fc611189eba2aa31af5ba8e81179866dc016bda977c59c595e40001c8ab3a4a44cec00ff84c6dbd9ad4be30bcc080e69b9398089d6ea464a70f536ace3b447693301c94850606d0de1299770b5f45e6d28f8ab83e3ffe52178522eb91fdaa9e4a696674ba0f52ee18e960b04415782f018d67479081b1bf9b4c9b90de026cbb66bf7d9d12cddccdd9b2c8ee2f010892571c6f0c0feac9555c71bf61f9cd69553cf7fc2be8d058e0c3430e134adb1ba28985fdc4f0cf71bd3cd09f5f82f303cded0de62f98404477bdd0a846c6c51e3e82ebf72f475afc8e6388aec57206018ba2528ede194345cc1ee95cb2023793f692f708aac3c9e8a682af36b078f5d6c7a3ed07475e9fe73b95d1eee048ab898edfee3fac4beda45f03eeb64b2128f6df9453ed77c6010e13c0270c068f704f49e62fb7410be90ffee47584ca2efc5287dae1f63bcc1819e7548eb9f0d8a3182f9ed00da3817255a2ff735876b75cd21cb25e86aa4b2893f9e5089dfac76194563f9a14335dd37ef06a501c89623caaf6feb4afb792092dfed515ba7518e278c341834a9dd17b50a0fc860b62ec621b69408cb3fbf7d4ab88a3e367fda84c82357376fa9b1161b739361c313b99dcbf4122f3870c8175093298cf432174217398928983ab6cea4759f18e7a21d71fe1b0f3cda05d241e12db0818b8763bd23d958d6e52981ce8d84cd6d82640d2000874a53c0bd14949ec99e48ce6c954ef0d08e6e319de5ebf7e142f25c0f50ff13f6acecde6a270c8d8de05ef4c310ce9e92f40f6f2b77d6e7aa3f056d4a20f7faa7cd0b93d82e3972343a50a26ff462caada10621bc953b73913944246d2a4da25fa52cc6ee1293c436ab9031ee2dc79cce39f139f44d473c236731257c6f65ca4d383e39cf8d33923afea3c80244021d36e0ed43230c44e7d1a1297d35464861f9149d869f26cc51879027169803e43c898d1b4a2a2480197500",
+ },
+ {
+ "2158abc2472e1b9c061da2c01d0ad9e996fd687cccca331fe8a2baacd12c06f284b1b5cbdfd067e5ed09a60a137ff4a97c5c26482659680ffb22bbcd4ec1bfd272749e52440537320fdd3c225c30ccd98cf221b34b89c247ab7d14f93ed3ccb0486a028c6f3abe7e17fba1742b6d4db85f6e6baaf82df1a3aa059de8d9699821d39bad42d56cc1ec67626092cfad4a2e1cb5d814e2cab78ccf5474a8bd0dc990a877d37de394694af6cadcc57727f393dccba7bf955f4b65b3c00d71cdd701754ed4f231685b7b5e2557239d7e16305be2d81a773765dcea25ea5bf2c15d670f3159409ab5bbf8da121c779132a8ec1480068cb76b68a19152fd83135aeb228b446225f91d1ed4303a4bc16cf3ad8173b30d2a1e75ccafc8c933db231efeae6260d45c7ef230ae2c7b6f986f1c19e2cf260ded9cd99d64a2d03fc5ee3d73509e47ac1c39dcca655839fec75517a9243eb611da8fae3e317e7df66cbb6abd59b16975eb463f509e784e65cd660ef1a4c5027e54b1bc862f397c9cf4e6594d98c2c2830801d3a679220b46881a372cdf3aaa33eb66b91a9f36b6941c0fe1b4d2a437daa50b811f2d8c65b5a69de185d78bb9c2f172dc90a89324c5a2067974aab14f4fbcd06ee95cd49e03717f88480a410afbb4e68b5c79b0211cb69b90604cdfaf08af1ef10cf28f0f630e97ab18d9b5138d9b9ee9154e0b3104a6c164f2a114fa5032eb5c247a6b87880332a0dce7b36982515297a05dc8a4038a09f52b1def7b4fdad8735443fadc462c7c22132f8b9581de2d213bf5c53f7fce34aaeb24263afefead5341a72f88d3acaae6db367c5c14a97d4f9e438e1e11c3c8fde7ee37e5ece5382e8c68b660146046ef96c24caa6bc9fa0a0c88281e4bf01b32df5218cb3750f9c4b8af24cc106abca62d085198d14ba2ded3cafc1fbb17519a696965a1ba5f65720e893f1ef3fbc5200316b9d4615bb23426ae53e1c5a57b2f0ee0d0c83f353b4ebe7a6cb17531d278478b4ca8e6ffdd0cad30ed73d568a2e44972ac88a7e7d665614316d674e84ebc739b645a9a4166477254ba47bc5c2b05ced88e75bf64da21a7f1f71cd946d84de13ca77b7e0dc2f0617d371ed96323a83bb11dfa16f81bbde913d9c259b10f3aeeb6b56cc4775c25f49343cef667763118932c2e8b47ec745ac537b37746ed65fda2d1c11a2de60ec02adcb79152e8a9e614d8715cc4e6b6891d6a0063576560fa3621146308222432ffdbc351c36c37d844a934088fea92ac54920facf870a62e91ba9299dcb6cbdb918e2d54fb642c3f0d60489c4bda489f6c584b64c8f19359ab25f388dbbe636c4d90c048f5ed87024dcf9f98a9e738163f837a07750d61203254a80d120c795f9c3aa791272f9474fe330da81a45be5ac838613d46c25e781606862912ff88af393040605fd4d55d07e2052227c37ceffcdd2d42a08bbab69140dfa4406853799893daf768af546f915a91b81d0da719ebd45b8b5f1641f15621959689e810217bea18e3996c532ac6e4e2e4f289fddd5e5968bd6fa9aec5ca435c532b6c74a7568c8aeff9dd19bfc2fba3b484a191e2faf9a069a24e2e6d928ac0bdf635644cc1ef3bbacc547a8e4f1d42d4bed3b6b8cc56216fa550dc37da9cf4d1d1591d9348594d14adc7a3fde5e5d1a3b9875c85de7df483cdd0baa86dae793e0796d14fef1f649de6079acbec6b6fa5f2cb2bd0481f5316f00dbe5dbc379bc3cd6d13bd8c775a727ef43e6a5fad1051783b22c05a75d64a8394a73fcb430299b015563c8cb0ae0aa4ec750399855411c076d21aeca8656f3d0cae084fb0a1ffc6f73b52a7ea5d4bd6d24e7057a3811719533105fc967439a32241f2d3e3f299da2deb821748cdee1a1c5e71bfdf88d833bade2f505268f375a9e6488cd8e16705cce91d15b60b2fd269a19148296a7be348aa349a12270fbc0d5748e538afeb0598081a4f1349217ceab3c4141d40f765ea2bfffd530fb9606601469fb131a44939be984c07bac8f26d8c068accfdefb729eeb47cfd6ddc646e22031f53a7698c6501d86cbba05e282d64b2f962a1b08b9064078dd1e3f14006f45f599bc8e600cabe6d855fcbae8c3060859202361d929a241f6c0711ac0d050b67a1d44da19e0b0e236adad1f60a327c9c34b2b9c64cdde5b8e4f664f2fc70599d44a63ee2b14d051c27d71231098ecd3d4086038d63e84547dfaa39db1a92785e38b640ea0345062a1c185b25a72862e7ae6574114eba592d6492087e2580dc5d361c473a614d647e66c0a30de806f4976b69a8b92301e68794ee05b96ee116a5fd5edf5eab43dc1103801eec861383f17c2bab9f2d9126c1802b7aee0c909309ee72679ab644abb9c4caa54add283b5954e6f881781e42f849bce6554c7a5e3becc5d5a209805ccd4a0117272a53807e3978ffb19641a9dffd9034490a9284f658599961daf52f24f6464c2099cc9ed3459d84dbde2ebbdbbeef25c882a9beda03573bdd4c6a0143b14d634a1a021d5f9fa23a7ed0f5598ee57e56672814412b6c7c08b8e709fb98575fe2716100d000a20a7e7200d800e556564c7e6a8da9d609b18ff0bb8a8812e96b834a6b534b0d5dc97f5da17f42f8d58e763f1b201625d1a5158c2f9e9e190921637474ae81d278002f197f7211540088931ca8a941794e56067ef4a497fdc6fa713aa9f20c21f23c3a71ae4cc5aed459ca7c020bf55162fbcf56a066546660c5a009b8ad2aaae9651c97b1e145853a10013d1bf68e7df25dd492c328f823ed982da54557502ebc6cc56d4d0bf2881bf3c536ea53b4dcb0886e73b066969dfec343441b9372d7ff38454c4337d45e2b999415ec48f19cd05f0f80c5a61ec369610784f47a5cf3b2a13ff5d8145303ade7189a300936006846812dec9ff15500f8daf47236e724d72619af3a6cb3e854cb8284d5b8843dfe056beaa45c40a4541a98c7507feb27a605d6e07189c8c5554a492a03ce6701d3d2ec782e2c1c8346b54a963435bdda3a93bbac1d837172cebb9cd18903d25cd6bed404eaf18730a6d1c6da0783b5411770ed34f35fa6c11a4292a34565ff1b23d4200ec5a73e6b7905458088fac19f6aafd35e0e791f28bbb2cb0117ca1c3a9e3c4863e487ce5d8c14dd140e9eb4794d87d75b01f683bca84ebdbf19dafab716421bfac9e95755fd346a0cd31e8520a55c7ca652ff63fb4e20ba67fab41e11f7390bc02363162097802c6a9eb18b430d07ea60064d5b546d15bb68cada79c113848136e797577f1783e9b53574f9427be3a28230fdd69d139205dd6c7e9e7f031fb6eab70d69ce905384c5c77d084360aac590a89b2dbb2d339899b13619b455cf9f0cdc08db6c5b5f3223dc3a663ce42bcc8cc6f947f42cdf8dde15a6926b753177513a52be95b1f0b88d2a1ec90e49959b108fe204bbc29199d7382c42ad5dbaff970cbd2dbeade54bd70415e54daa805d396361f525f38efc2bba3fd818f9d7af0594dcc341c20f18c624fe13ce7e7108e1d2fd06c58b03f04642c95e3ba00d4035ea0476ac138f72378d85050bf60dedc90af38e96f67fdc38483a73e847b41d31b894ddcb234f02b0d507bbcb15a8941f9c23b592a291cbeacb3ed213f2f044aa842275a7717757467f121294bba6b357c969e96bfab455c6f328d9e5181d909c3f0543b17d9af7fcac099067b043be79aca8e5a75c3a6d4f6246357a63c516a3ca595447f34b43a055d3070517c67ec36e636aca9ed71a001d4f7b81149124deeb7826dec3697e183d861d544c9c17baff82849d599e9e77ed19f801aa1ce095940674576ff270ac788d00c429187e299a03c6f3a1646a8f7d6290287e70bd1276316ae624da929c67936191abdfba45e2803884e5a3136205a38a841448968a7900709dda033a42969bd3417a8d865d0dbee1f261f4556797dfebab278136a182a63e5ca9789e3f1371808efe06eb0cc5ccfe26c0538d573378035afa39fb7cdf3ad889b277c8c6e84954e74f3ff3140bf13bcb45c822784125d23b5eceb73e",
+ "088fc7ba068f80efd8d4d62813c93c1eba77e9ff400c7781314abc901873ce200295da09245bf8fd2fce254397616151d94b511957c89a881256182ac9e64acb7b25d4a080cc9daf9ac2f231235483fc9fd415f69caf7eaf0597",
+ "78d5f86b071bbf8a185e5e2d54faddd2a9e26983b1e7a74be0f0b979b9f4af31",
+ "d9ce7d249af9496e99c93b36",
+ "ad542824b49fc520f0b7ff8ce2bff8b3d47baacb4a1c95ed56a306483aac551fffba48e8a8f5e4cc536e9266182f6811d070fb9282f5c542cefb4993ccc7044b42cfd6fc71793dc8dd2de23c630f9ceaeddba45efed9d7fca25fcb07d193c000822478b19c2ee9fb31760cfe01475ba8a003db469d1130318a79345a29d054a9f9412dca1edf6d8f1498af5bb6fdbbd3d5f9a244ff176f62742c53779291ef6294df6540d841f4ee8c7c58fc8497ba74d9cf7947add5373427d81ae928305b93dd26cfc65e63b0ed0812ce759511bfbb10aca98f2abdbc9055c4e5ab82637f6a965bb74f592bdf11118b8eb79d50331e76cb4d10c6b4428cd4ec2ef4cb727bdba2b5375f5184d77772d0f9fd3a3c579a4a548b9c2dadc22c805ae959617af49a514b43f47af834313ed2e4d1fcec2c4b9ea87f328fa3d23129a36e6c54bcd08f7e30645de86e98ebb11bcaf99543503eb1e024bc9fd51fe6bd5e6d749033f2452cdf28b3d0f8a304111bdd26dbde641c02fcb15dc21b1a9baac5e86d35b4126ed1cc8a2c3c2a5b94c99fb9b2008daf1a0c090633bf9e31326428c75a50e821b1e72a6504c9d7bcfcaabecd929163d365832e8971f5efebff99ee3f5b95f957e8904d05b410936d8a81c60b4947f8605c58e5b727d491995c76fbe06e556c8ab5cc661a0c09ebc98d61010050f68b31fbe1f9de8f6481b2704204b0164d8433ba4dc1076908c782826e9b555e8d608463581099a466f92bfd6ac9796eacc0ab771a3f11d03806b0f33ec04c69cef6b87d58c11acb5d1374450ce61ba159456b915043c5c17cb03f0ba66d027105bb6fff41e6422f13e2a466f073358bf68149a3b577cfba7ea08b42f83fbc5a2aff17c5ee7dbdac3ff97389f5b8d1f3750e5c9be651209eeb9574127ea81bd7619da16d1cfab85754883543f6474c8c0cc9d5b80e34bf8262d2b4798f9917bcab4b880339397907a5bafe7d149247fd735523df3cbb17ae5e298846ad3bfb7d4f902aa549b7667d3ea945b002e7b209bc83842a7b120d6d27ce80631404371f31d1f61efc5423e1822032a1cbf4fa1a6b6fe79934a202d5add8c6e3595e49be3dd9553a569521c50e9653bc684ef2b73c3526ff7a0843fcac9cc9ecf46e63df5b9328a54c576bd299a366bbdc0f83a9de67b03f1da16244bd6d52e7e4b52c4ed693827735554b05b3a260cd01a41d7c944d0b7b58ae4b0eb052da34bc22b779d7ad46f90f3d4049c097e0adeaf71bbb30ed24b32ff5c7a65177db77492c2571e9cd99f15e613797e319ea7377038d53b28a4cd66a697e5e8f84cf16bd0f0430b34826114b4e1d1ebaaf2939dff7f9f4ce7c0861e51701c42d9cc9e871018b447ccaf4e402e3d63be164dcdf6799314a389ada8bf5e51a35148acf627e51481b9b0e4bec09c9e6d59229721b151fa9adf8323001fcf33afbc9a949643172f39b0d10ef57b37973683fdd9b9eb46e63054fd05ffbef889ff8fc8f251b0ab41fb00757ec1964ef373fceb8f6d148a7f7c89944b3cfc240d091601b23046188ba70a7cdf7b6f96eb93dcd3d24d4aebdc4a29a749bfe3cf5f6e1a025b62982ce188e6b57245d829c9fc1dcaaa5309a8b9557b8824a78eceef6e977721de4065b474ae008642b974001a5565ef5fe4250194e8b861cc45a8691c461817f10b646fb526bf0fe7790bb0db29d1356e8c7a197ec78df8310431d632a032b5490c2a458eb8d4327a9679d7e8ef8739797b0e820e2c567ce3562592e862a1dfcecd50bf77fcfcd00518db65ee0effb9eb3655d5d401a4a47808faa596d17b316f828cbbc14a7e018a0593da9320140a752f3824b5fcb66aa4c3cb94366ee8b821b09e7bea2c04ece15e8a7be1f58463b525e8cfcfc3fdd395ec5b0575094313557e632d0a65e3099e3c653111a5fb4f0eb2aa710229fc055a2bfd8a7147cbecc10823f1244fbb6894af1408ff9047d6483ef83573b5421b9798ee387dc38f166b11de6c33e9785e9b3d9d28bc24c37890e4f8f8ff24cca298b44d6fb1c6aad28cc634a67dd427205285521a172c2a4884ac5b038e261e38faf0086a02aa29195713cea335c47d03d67fa0dec7a8cb21db741519f5f0ba0143f14d71e33d82c75d6a19b3f7a42e6c16d762354daa2670ffa55bd400637de9cddf9e7964a03b4c8956f36bf54d89cf16de23e8c52957b52eb4572a11d1398be72bdb129e2c1abb58c65cc291bb7b0d2dc326c6125a441863a6c92de0f47a355222d58bf10af0d297a86a98b4e933a8f844fc7f1bbc8ba77919dfc50c41219e3db309b92ba056349faa758daf360b8ac05e43fc2069cd46e63fec399cd7764b111467fc65407ac06f5f84a3179930f6215ac5ec906146c19e0d3e162e77a2bca3582128284282b251cdcac03ecc204266ac3a9cfe8d8854008baf89c0ea0096a400d6a0d2f7c681c99462cf0105f7a3dde690ece0438fbb820b9c73c6cdf6208c336831101b904526cf8ac331d879d71615d8b1f750ac7f0ec692d97a5e21e17e194a98c10172b5c4bc1049a8743188ae7c4d70384a7e68c1353aab7882bb91aa383821046ed0ebabb4b2dd126ccb935f48646b299095cdb71ecd5cc402e4635a3f7a3c8a6f54f4076ba028dedb402bcc92f5668dec3d91dda7319f58382017e306237e42480ee2c1f5930564cf16fdf37a3434585336b8e4535bba87311cd47722b9da727250560624a5dde48a2090ee44592d2fc06edda634b600fad9f843c6b2eaa0697b42858afee8191dd2a31e5685bd104188e2ccb057dd0a8d4d1205d7c846f5b8ec0f06bff61c7f47ac4da30e1bc80a4e95af79b14a83e9af2e0f195cb92d14f752a5f12ff90a05765be453075d799694848fcddb07859336ec101c8052bdc273d4abc313cfb351b543fa340dcd01bf32fea59881ddb8f33c6023ccea70532814ce4a2d0c66c846347b86c29dfc34f6fa4db298911d4367c59939020a3d078194e6a3a3c5126c24ed182398468e77fd61a5b1271f5cb2a97868876954c3f7179d6a045f4bd770f681cd82216cd2b1ceeb4e724b3fddeb74481e662fbd7f5dd45bed6d4f89d21b8dd9c1009ad2b0b16954e97993ab8f3fdd9d61f8db102a945591b4552f419971a9e46a792dd8392c8d9502767c82d9b4f69e66071eb579859e9ca070cad5fe3b7fcb77b8474926ea991ce7ad201421f8a79c051b762a066027ab2b9595a1c97ad57f3149f5872ed4d8e99195d47bd3c03bbee590a50a99d8048e912aaeed797977b52f0240a6cf2c865b108456881adbfda60cf701454da17bae879cf098df808f34e50bccaada2d3edeb1aa73cfe3c512d814eb33897b6ff9d67d3d682517cc333c3c2552adc99860b1f0d1076390de9f84fcc9e802581f77e14f5254da01831c70cb8581630dadb44209377d90447a1a21cc8a2d6d897db62d8420afbcc6ed85ce42f3281255bd43e0afd3e86b27d3b957104ef54959282b0e1b381a26f16057246704c7888126055af5a1f494540f01897e8781e1a5c0193b7bef4b5588d0e9b9c8de74dcdb63f03f7b15cf48fbb71c7c3bbe9329e3d326988bad7d0cb85537c1e0b3cd88f37a3c7765f548f99e495ddc29daed8c7f15dadf2e5b79def91dbbea277c51a5da250e66c305604bcce4789ca2df9a10614d72824ba8e4f179f35ccae7119fd962cce13b282f0f970ca6c4776374c4bc438f0de98aa04fb3cf23d2c6800a4a666c15bd20c486e88e688ff9e5fce906b4ae96ec7c3388d7567ce6c8bc61f6d2373b93f9ddbb02b384084b3f28f54c9ddda232d3084daa5fac5ca356ac0059f2fd3fde5d6a9516d0954653b699aa986f70733538e19721daa41329abb95058450e602eb5726ad5a8b81aa474650659c6f7f6f53f8a6e635bf35f4b1191e0dbefad3be756c6141c7d55f007f4fd131e5d5eaa120ba31cc32b8d4c69d4fa784fe0af7dc272898789c774e7995cb252eb6c8e8053c9e7adb59c27f675952d161dba78bdfb15859fdfe4fe4a44c01efd394bf51d43c600aa9a527d9c490971e188e28b980e77a9c6ea0a4ef6bd38d11b47f5745ecdb",
+ },
+ {
+ "9cd1c25b5bdab9b9080db3e5e05dc749e0783087c310777d89307138613bdffe0ca259677c13208420d4690031314a11a97a986d8b0fea143f5b4da0972c9ea3cef80b4b0b2bcf2bff392c306a764113f0d9807be86a9027c6ddc85d096600d85e0b236937f295362bc1679537a8a9278229a36a9433925a105ab719c0b7f11fc31488fa071d3032de97c81540713dc29ae02c2e13be8823183f3cd9f72ef8ba4280b4499ee47c7c7c4492bcb5cf7e4fafaa7ec26906e58146215a3d4f52f792d3abdb718f57ed0b9b7fc7504e45a0fdf01ebf5924a4da6ac635a715879ea75a4983cbd9dab9e47638acc687f16684e184443aa9e81513ae4abbc4d1596b2ca3eef77cc9b0603fe90c0570fe6cf4dff0381a99212fadcf7968934ac1ff7664ed6ee0b61e41f5074dfb774b676c2b57a445f1c5749e95ed062837c727ae2c151c0ccb3a4dc1429bbcb9e62325117aca566b8fca0924b70f4defd7749d0389b90f55f35d1635f8d2efdef514f06fde46db6e11e492c8f4dfb7cb5454cedd0ddd32013a4836321a25110f3a017f18475a86583e192132f8d8fd4c2dcb2a3aa95c3be3a57216bf9727cfd1284eea6fa870c8e689e91982c116ceeee2f8298b55646efad684b96eab883fd3d629437e9a0b6523f47ea5b59474a4766ccd01c13170bb08f47576a0fdb573d4dfb65279c1b79cb535426bcab60f4022dc42e40db29f15a6148b461241bae62070389932f035e7257752ef2d6130503d72344b24d360cae8ec11fa2dcbe04d3b18e66d081b552e93a71dc0094d1046bf4491e318f2ae00debffa0b8ada58c5f23e33fb598829ec2f46ad3894bd7f530210371a02e51ae0a414eb2eee43f3e08126dbdbae04c7de4b7416df32953234a6694ea84e6889f27c74206ab8144a393a2614e92adcc77550dd54827387b619f004c13f6c4a31e8bf525277669db0a0c3c589eda15063f12eb774a13e2aba2f2f7b6e9bc69f8485f1d6fc5773acf83671812412d28704003e78a17da25bacd1d61a6d9cb9f121abc71d023bcafa713b7c954e4e1c524e5bcaefd86c4a843e209eabbd579cde0263fc059ec6ff10017ba54fc9c2a1171d6b06f5d85079167117c12e6e5d0c71c008765fce756fd0f1141fbad6c1d2f32cd8e80429611a9a78dbc8e738d458f9ddce58ab43c77b34db9befb25cc1a588998e8dc2efa75c6883244fbbf9a7b4d6750c81b8d3fdedaf98dc61f49d067c369409f984b155ec347a3bef73e2a44957b0ca0f84c7fc335fd89453759ad0ac2fd9a5b38afa9fbe74daaee7bc52301302fb2286c21fb922f74d756de84519171fbecaa9b869682d431614ff6845126a4034f10253aa244bf89ab8e0dfd1f7fe8fc1a8472a10746d26896c8ece7ef80eb2e910069435518ccf096caeda63ad692455b04e6525bb8bae27197ca5118a57fb9a5d8fcfae1b9eb7874d91eafafa0e4fab5cb4d0173f7e3e58fae369843a641e98f3ee460e8cfe95d98f7fd38a8d2235e9d6050015833e6d7d21d7015c3b1ff42f0d3a3d9a38d373c8524752e06987c9408cca550f08c38c2a9a8d86d5ac7a04bab44254ed15c7b5670e0747788e11b81adb0d29e3d0b50d6a429340ee0d44a8c286fcaf9bc46403d26b4a4af95b021336103c1ae0f1274b33bb8b21c8cfca8a56c639f18a9df45d083fa7019aaa14d1ba50eb9a4112e574cd70969640602096265a87b1f77c0e00bbb501555f1626196611b4a824991cf10ab2874a12a8e0390267eaf9e3f8f99eadfbf40d111a26772cda1f50743c417eeec9c80171a83a730f246cf31c6691c96185d672a0fde9ccd7091c4b455dc93326913497396e0a4992773caeddcd783e534eb0f34b99bf23a2db6ee738381b5fc94ff603be014c507888ff55557793a8c5439b11dc5a347f35a2666eda81cda4d1c3a78fc4f3df3c7bde91d05524791b67142c446f60c3a4022912ddabdf817ca3280b671beaa496c935661e5adf39c1f4650563c5c807c8f21aa59df926199c4e2404690ea8ffd7dd65f637452ff93995fe9c5ac7a322b9bdc756b7ed6f533b9357a4a1ffa379dd096f144e9e0d87330c238ed3c6b08c8478e23b65518ea1e4e64585e5e9fec2f26dd7400ce4c73ff0eacdc3b07e4f34f6316f5b82fefc66e442ecc92bea8c1d58635d644724a3380e71fbbeef4bf3e57c6240ff603d65447f510eaa3c9ac794fd24f844489b7c560c7814fbc307e03f6a213eca5ea40fddf51d8731b74ec5b472bdf8ba59751065ed2461b02c41ef96622e60c0d26f9dc78c24f94372bef7e47cf09ed565ae3a52d39b02ffddf1953f1ff500f1659db9f1c2b23534702c19ec1cb7c18166fcd33997d53874c7cdb4e6c2b4d82751911913434e48b37a61a0971861187e5decb7f5c1ef6988bc1d6f7fd147a623d8bf361b0d7ece88df6e1ff8d037762d232e22e51d8c6ddaa9dc597b23ff9efbbfd416cc53e5543253732a23aba151cecf73b3ecff21c6a9fd1f24211fc21cde9633aae918ff1c6b72468f1de7e0ecb6539fa353c069fcbe8920dfa8e2fb86782e3062462f7eb2a2c441bfac21ab62744b05c70b6fc3c9f8e3a8a0c5a4263ed256a019861ecb28e20ce78e2d93f1a1def669e9652cb35d105bfdd5ff2313d27ab3eb00d1b628b4c20f42efa23390802af96a8f261ded3678ea0b780e1f4a88d23588a4ebb058adbf9a9c62ce2ce2f8264c874c697482e25f8d5a6daca4f57fd97d23c42d7b71ec150d4ee33931db5f7d63abe7d72dc936bb23a367c798e6a01509644284d52f9ae27d7d1bae597b2cbc26139354dcca0fff6d76c6065d661b66ca5eeb9f8d85810a029cb95b17e5173ef8ab92d475a1d3e21799e874ff04dbc962c668ef4be9f94d85b2a99d97c0db8f6b6d63e00e36c325cfab9aceaf7597113bff0086e8fad36eac7c0b443de6d3a8533789616d4c863df7200ba795a3b8d0a2b9568bb32af95fa604a3e3ea778c3dae159e1b612458584564ffda07b8aba9710134242b2d83d23127b51b9e41584c56f667b71bc01060240f3a2bc7e5d438e7095c1236e0e468079a83a5dbdcf132d258e9ed18f94d3c098867d06d3c09544565677b454be34ce567f1c143e2f3153bdc0353d65090dfd8f7af4633b89a781e01f4634dd7b0323ea1f38184e697bfc39a1299eaa278c39a2709cde0a346fea53a61f211112450b318d137fe68f6c102085aedabd2b045fab912da5c58d8019239f3a44b18f4fe30c5352e2e2bf030334a1dde1dcd23178636f1e38ec9e42102d8c54df0b94b207e804eacab3edddf89fabda6c8e1bd4e17ae31a57716c679ee8bc7de4412fec3934c6f3e8b4c1d1447dbba0fbc775dd3258f789ca53f1593cadc710fef6fd282bb41c0468ede5ad5b914e4758b4148b0d0c04c75ff6208ca3e79d92de8abafa4ec70ea7a4e454f0759337ce575c4954584e2bb8444c34e823d27b025d25fc9becfb4391df9882452bca0373164cd76e9af316df3f5bb7532e22557b485217254d5ab72ce349620f03758219b259784d4c9f1c7beac3cf08e624742e768b53b3d60ad0b94442c847b84a516a93d9b7d068c44c43980b4c7e2fb0ac964bf05a11fb2adb4f6d938715dde88061b238321afc7e5e84799b02a94baf3f879f89a98ab474ca12085137d639b837ebe069f6dcd8456141d063eb1c032aa392a44d1d58b1e77aba38a280625ab84e3b123507ea7a692c4acd1756c031fa52d637703ee957a993804c13e296cc20c1de55c9b8c032e50afffc51c02e5c12f48383237cdacd005b09243d9fe05e51cea42b77645e5c6f4e48c10e671d216b90a48f0d8f5c1dda553217f5126646d11a62587eb0a4ee0efdaf0d54bc2eb04cd34f5a529b682ce09a34d5acab2c8db58ed6244f7b024e68a14bcd5d7a7daa4dbcf490485cbd38e6f20e839d2b0142b9d766f9527937bb1a737877edf6122ba306bbfb5379243a6b22bdf85dcf3b079691f0e90b28a4259c1c9d8a02afa5b5a661a0f9dac52435e7d22e3591593d37eb2e10f646b51be2d1a96cd4490289ef642ad93eeffd64d7cf830d60dc4a98c768a9bdbf6ec9923062ff04abf19e8b65b95494a9420971018c7e6268b8fb2021a4ddd103976333fa52389643c711a980664e29a8479aa9c4091c2cc2074ce3ac1ab4afa217d39c6a1",
+ "c22add33457539a957d32dd07ec9110f8cdd2f00ab6ac256b4bc7732f63dd3b867b0ecac262555",
+ "e71f9a3dd457b4064df1d9055889f105af175a2d10dd7b8729da0d0116c2d9fd",
+ "7df9824e774c5f86d83cb5d8",
+ "689683c9e7aa9c48b9fda0cfffea0458ea0c3dedccd21efeb06126f1194780917c9f4f2f44b1daceec3f6b1f75506f4169bdacf12c1f65958784851056fe0b4b42a22aeb043ab35ca73747346ac58c550324c4b849a404c94b8860967b6fc58aff25dad0556f1952c045b91f56ec8eebf6f552c18b2a0641c037e6c6538b289601e1fd5a7bbe7b6e0b224124fec341bf77615183abafb52b3e30082a0abfc2cf224324338c132426011d9f800b382e6b834896ea48a8247f149d92ded7e69c7800096076cd2a729a1fe41c70dafb1f855ffa2ffc27b93e2f5f6827ade7118af60730033675d84de9cde6c260d3d615a945dfe0ed25f33b6cbd2c0e204ee919219d85c7536f4700f06fa61937f8dbbe9bda88db1f4ba8a8d195cd385eec62edd9ce673880800be9aa4430e5c10a5908f6dd349af70f32b32d8db38a7d73821af47b993b622bf168565082d07e88fc48231a440469adeca59263302438ece96d89de11cf8057454d1bfe8e4e36965a4d82618834a0847af39dd8776866d9558a5cff79a1cc9d1e3c22e050677e54ead68b3cf0094daa01330d41bb66708a8bbb8a196fae5c77dc6774629d38905e81d97c5b16d755182f687a8046e55d148419cf9c12139fee50c0533b0f04a805723ce1ea5595fca5b668e58f6b3b396f438308372489b640317cfa3a79392cf6d1afdd8c3359557a83790021a4eb418fa189ad15ba9be0f74182ac76076f102ec171117a3d16ca20b4d200e03e54f1f0ee6308e463a148c0c85aac3ccbe5781cf45b53a313f7c9975a45d1853ed9104a860c08634a8211b87500b5ffa3d8d9d56f22256d485b9b45b24d3873159adb8ae25966cc40f164f342519e88d1ead1e711e1b2bbd4be64c7e83f056f797c2d3a5cf7c5025f92be5637fa7738a1bbba55f761dcd1451ce4b1e85a6628b629a2f7917a86363b01516472c0f8614abe2ad1c9d5501b2a44a68e3eeeb34a64541125bf49138bcd15b7c82dfd40708414b85107d8b982c4f99783a03c707a37787a91a7198063f0e8a2d52dca61755105faaa09c063c7a0849570cba1aa7ddb3600eeba602c7e7c9b90ed00ec731d4d1d8e4bb42f9e9db21616c4aca48dc27b939428834404331288f03c2b5e887103c51748d0257519c3988f6492eb70cabbc2dd8a8a910d737a678d0970ec48bef3b81673bd10b687b37e11d49e7cf90c03c54826ecd833bfd9dbb8174274dd45b139d08371d5d248ee33298193194734c5863adf4bca92bc282bae2f47da5201fc240dd0710a22a8d922faf92c2071a7eede7ee17232d3b6ee5f3ebb1a8b230600b243c860968ab427a5f540912e5e7bfa0271201f288727f2bd5173539d5318e5c1c0a71cba4d9501b91c3bffa7bb61b3713f1751efe94a66e17d2b42da51d13c3df40f4db988dace42a6a1b9d138c4f590b7227990711afbf8f56fa63f2800cc019bbd4a7b3a0983c9b9e5f77562dcad6de96e3b2eb85cd99d28a021a10d6734400a91369236b48ed68528afc68f247d45c79318fc5d634ecb0f3ef8536d8ec2e877adc3308be906c5b96777d0e05970023e5c5dffed12310cc97249e4b95e32451c9acca8394fde699deda57e938bed7167e62e2cb62357f82fbe821ee73b4e09c6e2f512515412c2f27805762a8493e74a3d30bb409e499002a97354381318af28311ce484bdf7c39db53f08f73ca5793945e13fc8c66d503fa95506b37ce134ce2945d75b424ca6367ef4ed47b9cb8ba7de80e773279bf23ac888eb105385ea958b1b49b27c8db6b1e14a5c8ed5d28808a7d0b6bff1a58f24f9c57fd8b8f477a9d1365f89c698b8ba923896181299d474b93e05d3c915b10a69e61910761a6d8644933c593661b0828afeca590ca18e702322d9140d98fcf836c2f7a4f72b59eb529823a52ab05d919c3eee4db2cae1067213c5070450a160fd52fa44bc9bacc5c136701cd7adb1faf484da376477da08f6a4dcaa37af47c7b026c2da9d5fd0b30741357104cb2bc0d3cebd132b5fc7c873ebeceec5492aecab95ab393f35b93b923d2ca071e6bd8522c3ad8598a05e96646504f1620c045aa5734d665acbdda0ef73612be4ca4d95ba069041e042497f7b10445869989ce30f55206a1feb4e64890b7d1f7e9df2e88a352674a52ae4267c06592d425ed1d88101cf94588135892218ac11f3976ab2b47a27f02eb887696c94b13d48b4370eb11222274b5513a0fef905c66d0c1893832ffdb9b333178b65338fd8b81094d8f86f2e4e96a47e72032cd6fd47af87eec295c6e980f595b57f79abeb4654c4039fa03ade732b1e579551898b801ecd6e0fb1c5fd198335834b51673d074a8222640d2a969998f5b878bf897fdcf3426c4e24a7c599e5567643fa79ea5d20e7de581a873ee0181e3632a4e304f9dae09a81f882d4061ec17e588793b160c93a926874d5a8b78727f88de9bc125589a9562db5bb1c01012bbea1b2eeab68877871ce83455db43cc48455effbc71c436aebe362af22c6a319d134f65681c4d0d51f9aa42fb20f48ae3f7065664aeff5d8349624a5d79eb0bef3cbb2a1244ee445f560a6bf7a796b2c950a37dfb85ed5be11e8e305e835c9e077e676aa5ce23edb1f74806278548e3fa35059abc2f032289f9bd76043c8dd1352b6131cf34f66bcd0e7f1d13081f5b08ed0c69136f3b7ad8e05e9fe99a9b73624095f96740c1f40074e5d92ffeccdc0f15502082fdfcfc97a800be511c22b875f2832b2b891cb1aad2a17c7bd0be4427a4549404172f7c14d5e425e14498237c26a7813cd8612d048703cb180f1a6194f688b4644304950b078692faec7a2a5c5bbc482f3a7e8ef2825c4c19032a7a79a2908ca9774c6403e6b15625c485f2dd078902aff769dfee2dca9373704bf63ad981b51f61253910fd48c49ef10e3938f35ca8dd491a8e569baef675df30367b093f1088ebe8f876191dc32055481d074e5e47a4bd728efaea9fee3e83d8556255ffb2fa08194bdc66897d97d1557186d5f873169461494a83368ed8065b9a033fa4c2f07f7c60f945b60479e3c89233d58f674c0c6fa5918150bae0c6de2b65a09ccd490e2ad8571745bc37e70982411af667f3e8e9b9f7f75d863e5fef05c1f0d2acc7c86585a83ee32e0a64a9e67e75b80def5bfeb7cffe6e6822efa7a9cf049689b58336b081c039696e0fd3b2a2a6b0d177c9b3f8fe5cbb1c69ea93c1235b2c5b6934f603127eeafc4ed0728161612acdb2ba894a5ac376c4ef1fa8d49b4722379e5cb39752837395c413dd29a2a88c03849b6fb2221fd85ba6d5a50ba7ee9c09ecc5e6dc66afdaa1b021282cadc68f19529eadab809341187d57cfdfe01d0798ab8a94277b9b868612e575bd98f70de80ebe5f57637c511800373262eb5ac3836b03808ca5d5f732f286a5f18a7b7fb8cd8f60e4debe54731c9c524b84694c5469975443964ed28ccff2f4e8e0cf4c60c1c8a092e986cf12fa90a994e4f26ac89fabe8a0d1e27fdc00f1d3d3fdb73bb76809f93ea113e336cb0a5438147e454e262fbb7d656aa1be1288839bc342b48ba7d0e72c85a2e24be1a97dfb2db85b5d850481e62f3b11a28c6407686e73d550b9f1d0f010602e82af26813d2484a8db2da0814782c8404b2865abfbe3c98a07ffb37eea6de7992cad73a9b81ae96a9acb13ba213eb4111d868cc73b0432d2b6c2d7e0e0ca7ccbdce86d01576e1136871a07c76498eae53fb7ebf2e85fb8561d10dfba740400ef4495ece7eb33ce3bce26344eddd88cf1ed8028ec5fe8e71edda54dbdae08f50f8df6295f6d7ef1163f62262a200456a7777d0565d7f5832fcc7ac144b5c3e0ce3e5c9b7f880a54ed5e80662e96b356ff58f2e372b1dc0d73cb8b96c72caa9e5dd312841a8be23f838bc706d893e1a8a48b2c069874c293c41d00226f73f987aec8686046ac4c0c972c991c38b98cabce30e7255dbf16039b95dc7d103fde630b03441b15bd2c214763fece9d6778d1c6354d2c9478c226175c02cb006006715fffc879a6a2b4111f6234ee330d6c84d453c9ffac08efda1f380110a8ef8c2fe44e2ed644cc3e0146b4d02f76586fbb6d69b827be38b9add444e2bac4d7165007cdbf2ea8c4b967fc1bb70c68b229f19bc3f79cb13ee6265264885f04c09a96583f331ed46de3e5dcaf08313ba6053f3d0c1916a0f",
+ },
+ {
+ "3ab6cbeebc18df951d371e0f3cce2697fb367476bd9d50ca9e668c77636eeb9d24b68be0ce6a75eca194fbde6221755d57e9d3148623de24896a9becd98789fd3d14de0c7e53f81fe7f3fd491472a66b5b797fe19c5d0525c7a111a0289a9e65ae7c712ccf694cb75c490070bca7db17205af9bdb7fee27f9ff41fc78ebd2d3d399e690908b5c064ffc0d5bb67b0d2880bcb45c2ca2741691b6131aa1e5ee758fc50610406216905e13ec049ee92d1f95e16bc283dfd91595ec2037d20ead51d3a362140578a4538c80581b79852b0f6686c1ea66aafffc872024592ec1aaf2650d167a75bace024b261db4ab48b401cf85ec2620dc12a7fc37012af8ac1d6db923d82eee962129bc4ede578782594708357d29118fd10dc6d228bf7e461d2769e556488b776237b6309f3dc2e884cb2df1f43f71c53d389765f805ac053d05fa835e75fab0adb0f13ceeb425637f43556372d728a00fb005f7c5a20cf2b7f776066d60b70b11a848005c6d63dba0c93f139067b39017c997dd6b94c0138c3619e9a6d0e4b8792cb8d58a2ca12ae5d03e7637f2065fbb9e2d1722fd3aaf234488ca157d829e9a3b642458054f3dd58da41d7fba6d2b488a327b776d1aaab1a364c710e755ab22b9cf7abf1eb8949c5ca20c070f275f8959cb00c6d5ab7879003f89f795351a4ef4850e033d929f9a349b9133b2e0bd1cabbdd381594bfa697b845100b96b5fade05db12de040b814ec49489f39f5abd5b37f570cbb516636d5b7378f12872d02d4de20b52ed8ca0b12029a4c084621bbb578b870ca2ea79fd5df1ef8664bfb3b1a1bf038e4ba33f6ccde42c5146470c9dd293aa747d2372db1561617920142ac1d32e4f1fd18e8b9e72b7efb8fefc56d08f00450d23b7e8381849b1385ddcf9310a4850dbd6db7a4992690190655760f557a5027b5ceab3743365ac9041a5c14bed1126c4eca00d7e0a0e0e6f666f64bd1466387150ece5835192149237d5dd25e703e9d3a4f652ae04601d6acf8228e4e86055394c3abc9dccd02f04a60c298d101260b408b2620c137f77e2019fc6eaff1b234c56dfe922b0192656254fe3356143e969f64b7609cbedebcc8cb2b68bcdd9d723b9c14669da6cbfffbca2351de51e87db6afde435ead0017682b8014f91d9734a9ab9b374257273e114a8fffac786d53183ba666d8a67e30c1fe45bb1bdcefb5787afcbad213f8e36e78d30ae1305df96bf450349ade655cccbb17d887f79e00728abb449ea427fd2d0af80e3b5607a74a57dbe5264131f2fc49cb74415974b3d43ff872d4106ff11b680f56be06fdf85ec9dd850b1f77f759337b9a9ce04e611036d3f45743e562abe4b959eba7424a712fcf7c3f3773886aef22f7cf6168efa83cd3ff70b9521cae1b6689b2b8c423d883a007bb138025f2a31db2147691bcb365ac242efe40cd09a746cc501ae0289e80205993b07f86538d486803da14b74fb0db6ebf1c2bb8c36275137d654c1be56c65891cd50f705247d85621fd0d61ade8c05cf4ec15b84e8adbcbe017d7d5743d5e91025e0154a5d9bac7c6b8297490e9c195c5d74e046219c042219817a5c56636c7c4382c6a01d721d88f4b4d20250eb5eae5f3ef481dbf8a3f47a1d51d080bd4cc33f12645c8481e57835b77a85a2d83301172782f22026e69a43376ac4f5b78734c9eb914e6c76c6a12d4127cf195ad030825322a279093cbc40a680355d086a27f3fb7560713b019e7c286d96833dc60590e9a709f2e3c632894668e74ed20e42cd83a23ebea3dc3bcc49d14f8697541780fb2072dee6a5672d0d4e7bdf5cbdacdf5fea9e03c6d9cf0faa1e954172acc26dcd344bb3d9b2e0e6015cc55d19713d795bdb7c21b44b305e69c69fdb7261483f9693f36f45d356462f1ba4498de1c2e8bc3e0a70893acef2006dcd73cf15b265a8a5d4ed792a34a846d8f1d3b9b3bb75f1c5e57a00b36c00203973ef4e2654f6cb29e4445318ed99f0de6ca992281e83ed03feedb66aeed6a461c6f2871ae95343cd9797e58430d5639d7ef5c59c78b29f76a055e18e2b85eff177770c60ca4f2d61e612e617e749b4653e7901b62ba02dcbf50e59219349120ac01e6b8a6e98eb54abd16b921a1ff85898f90fc49a3c8f8f4ae9b0dd32c3e7f2e1527c4feb67a496390f28532f20acc71abb8bb4f71b434104f41e36b705289858a4e8430b8cd9449b0198ca2244923cff1df0f63833373c275572de5a9a77b23e5ff54aebce8e86d02651f26ae32e69001e5f3951967579ebe8574682cef8c12dee0b18bc999f8cc0f07e2ad3ac94d3caf30c1c8a8295756aecbbecbbb4ade8a2b8015e52a0eb1290693c6316d036e0c443fc4ec591c32f7e7f1b3933c921d5812233d3c21ee5528822b59ef2ec7eb62f7b04f40cc8238a473ec37a07e54f8907825ccaa1421c2964d2c756be450dedc011e1cdd9045720421b9a4a00e9d3076c2fd10d71ee36d5c0fd2c7e42396b034a4cd0245027449242dfdc42c8af4a34df1b4150097726c9745247b78bb2bad5fe8af94eb13ee1f41dbd36e56d801a4c9c5b9ca5d3c26f4714b6fe9f69b87567426eb6f4ac97e8c9541eafc19fc90d3b24aae0f76c4f3f81063d206ff695d638048c2cb023147a78332939d2f2470d16f1ed0e5d3d4dde438affb2809488b99815e54938fac3b02deceaffde310cf422f9027f364f5e79da5d2b5af1b4138ac9f9d301f396b220829c1f60cd2b54ef24576e5ba6ccd4802900db1bb4eea57de7787eda0e30fa90cc19f099444488699bf7c442c398c2ed989d084c8cadc97325484e337848c34562b3dea6f7670f935ed3d5216c970e04351651c1c31a34e862821bdbcbde202d91fed38965e31cc3b6f1e52288f327bd0a787ecd92b3b6f535d1d000b0f02d41ee01ca54e4e6179ad7fcbd60f0e41dfa5c9cc7ee4f7de3844fb385ffa3b24092b30be697f1fd32c9faef29ead346e42fe2ab1d312901b678b43b7758edb7eaa1c2d038b4cd6a7dc759a6b12cec955bcf4179006a7ab6e22ef15986df107080d340b8870e2304d57caa87a9961c04655d7d66c7f71ca9260e02aced131d6de65d256d6b487141c51bc86eb1e4721742f07d09e799b30da7b5ba94c8d701ae34271ba06f8ce134a7a9a2598d1570cf05edd9ec868cfa2e41b4c20a8bc4b8bfebd45f5a60408f08e931617746d1464bbe1f3844ab3272ede635f771f9af30e483903ee4d0cdecbaff4d31451e7791dc97c92042fb932fe1c82652c1d682a55912e33de3b1299db076cef594458670dc4f911f4a244e2bec757dad4b0052a41235e2f5e60b929682608c16a61287826218a1ac3cf0d8286555d5b0552754685c365d4342f0d9c45065daf6786179da791a86b50a5edd6fb4b21f09d9747136aacf79ecbf52b00fb88b0630ec7f0a6699901ba4eff913a3ab33ac85a71ebb51ed343eac86eebb3e79c16e664078ccda09e77ef8e0919b8cc447116b65ccbd5200fbfe86e9bac5637b33c9bcac9596b57c14ad5da548e96a8ffad5f5c69247c68d464c770011da7b45a337f138cda6b4e15311879bfaf12af4c61fba596780e6adcd5dadde372823da6014122dbac70f0dd896a8d387d3c74df282a659028d06cfeab3ae22dcd1fc3ce60f69a0d678aeae0e5681952949e31ccb8975cd167c9d012f4b230b1c1f47022eb1a3042951b338a734cdd17db0ed483a621650deb3510efe74191a94611dc212c0c73b117a73b8ae41892cf176742bd98a7cb73dcdc53b42df56d640739852335f8d44d901fc884286b433fc285fd5b3db8df0a8522cea3182c071f559c328b8516c9252681a94eecec7ebf626c0a9014d9aaaa0c694d14855433dae06656657d1f8a939123d28e00513d72bd3802d211ad7c1e06b9228c0d5656edccad5339bcdddd5e01afdc01f10974be3187804324fc513ba583b7b2da1e9096bbe3d078c1adc6c34d92c54e9c49fccdc17d10e66962120ee5d9b1cfe852569436270cf7c4c3bb12568050e2ca4db08bbac16214238413195dd4d936272fca5d56d7551b9b002df1807ed44abc84c66746387b79bc9e830a635c308a7bfad7c2c22cee6d3d0c5ebd8b230837b7ceaefdf71a67a3a8eaae0c36de86b2d96e759b8b53f8b8604775eb7a7e13223cb21033dc87d775628581a954085c2d66c1c8f225b1aa86091061738e7495cb36a5ff032dc678904bfa39a00285cd6947865b6d4805e3411644b4a4c94a6fffe05ef31e156bae6165d801685dcec195552d029d22e5de393a82ddf3cd3de3ad8cd6bba2325a03982204f07fc3c21518ef17a601fd743b27f7191bb446ff61d3c61d7608777990997e911932532e5b3235f13423756f5b6c786720cf6682932c90092",
+ "50772c5a0e156ba13a9d86edc0e600021d56f7d31e7e452a74ad53a6775339c7ca6521d87a8c79b42900a1e9e6a1ec03f7e3d615611c3fd5c9927c40e5b508af1a298794b60148df01e9c9e78ab5ea8198c097fadcd6cfa6694be64e00eefe1a1885aece86f6ad87df766e692b58ebc41982bef5",
+ "93a2561a9904a1787a10e2a668cd6a814f2877a7b512698e94796805875c8d1a",
+ "588d9bc1d98210d9700ef488",
+ "165d8c9eabcd5e93e6eff7be122c8c242e1a7f284790c93324f924efabcec4a4ce48262011b7360c2833143d645ff295453853c92f0c48c6dfc2af7ec58d9bec0d13239c7e5593cdb39d49376c6341263df80c0ed2ed79fe9899d0c07de93f6ea95a5dfd307e49bdb5672b158a4df623ee86d54cd1a0fa9a60ce39d1f5f4b6b0ce9daf2a61a907cff3bdd3f29156ac439638e0910d728843ae17ea7368814ad7734732e7c023d4954e1cd5fd19fc9b76e9bb84b61dd4371478917757b14b366b4bfab4eab0d9de746088ad43d8742e2b9e58faff15c2eff084df5f4316111d5dd7d23cc0b1ee1000253f26cd260aa636f03f64a8342e531ca1515b3beecc3ee07a29184988325322d5c09754c278231f92c0d980adc919d4fccf4a1da1d37f1ddb58ca997d6d700946199fa007c43853b6caf5f8049233584087fb23c3952414ac487e452f0c3898486d04e5b008b843122501f9c8a294da9159a04119ad5c8e9f5c211411e34559d3a7bcf2ac10e0174f94f3f2968c80ebdf4498de172884dbdad0acc3a887f9bfe896a6004d54cc424567d53f1198ba33c56aa460edc6af0e437b34322c1144854bafb2434f00703c1992dbad0ceaa0616aec60a380676ca11558cece57a936959d6c2ffe0647eeffd37524fbafa9691f31499701b202d9dc9980e79ea517089eced779aa45b522c9ad193e63ea8b64e8a942f630d44370f23b7e9acfedac51dd9f139f8806b09a8fbbabc76fec3c3721fad5087a6d41f93973af8d787d8bc74a3122d99ea14e2f30a3c90be4b695c8b269784eefafa52d6a79e785eb47a23d72f037ca572b7029d2f37baabce57658119fb02c5b659e3aadfe0052f1cc3c0afc6fe4624533d9700388713945c20c1d175da53738fc73f48fe57fef8305e796b474b6f8d3fc5040042373a13384237d95bb045ce0c20934a964a8372acedfd6e559aa84180a86311a3996cc17bf7f73e5d85d4db2529989e5836edad490aaa5f56d17326825aa20608fd209903335de4b36b79f68b6a52194f6ea8ce42570533df650e65b50c367f69b9f08c32b3ce3e75318106b8b2c6b6d09369c781fbf2aaa35053af215b621f833814ec4778ac683de0dc22c418b077a917a6e405ccbde9f72ed523aa696be1a6f247b096b9235217bcf19b88d43178cce5a7d82335fccb4c079e00280bfd272b9f16ffefa7fea38d09dfb2e4874553b135052595812aed3fa15096abf1eebf9abd598289e0d156974de4c2654c60825d42b662ca7439816d9d3a0255f40a4965504f643f029da535d4b109e8658ec570e99859382ca0ede0b0495d508c63c7f1eff3f648c60e9b773590cc663a751178ba7603a11985ff519056661b9460c1aabc30e83bb0073a927682a06d1b8050c345f7920c1a37546d79587fae2a92c803a986248f90547f0b6c0ad0552d8260d2a0dc3cc76d092ab76b8c12f05dcf141167a6ea300bc23227933396ef6fe9d51a1ba5a754485950f06cfa6964db2d0fd1d4393cc36f0592fca25ac1a6aacda2a32f548ed20287e3d291661848a62d41504e4fcb1cd1785617fa5786712b3005f1a1041733df6cf838ea3ea0b93685889bc6b2857d80a9bc0e7a66f7fb3d805770402f049889311fc112dccc72a25bd127777fd87bf5ab56d39bfe6be2b45a8301c2f324dcc50b27540200d522c24941701f7293b8877ac84cf35638507c7d912a3a94e4384b68c507412df65d0c4ca8ec2da704bd4483eb2e0d13b68c0c2b68c106a55b9710ad0a1436d655a3cf3c419d5e6f027ddf5dcfc896a5b316a7dae9290a7bf81aed539a647c8c98e24e7ed6a4f7f00a11134ca715e5826625c250500f8f16b40de048b095b5dd08268407f58a91c86c36ca5a2bf4f8fc682adf1bf601da24414c74956e1a8fd2888b5260e980c32f6678a4dc4ff73220c22593d23144b84c2ff56920342248876d15ea54fc100c09a81b802dd15f030bda9aa08727ea49e34f0ca8693e0a06d0af06ea7ceddbf0584adfdebeb20510bbac683451d9f84cf0f4e85c34d979e550e07e7f414d6f1011cb3dc28d0df6d4aac113f2d5b04e4486ee2cdcd4157dafcbbd55e8330a7176d1b231d9f47a63da9ee30fec6cc2c5aba3a8c6154f79997af89d972743255355647235ee939f4f305ec655271e0cd562ff6f401b86dd5826c769298445108ad0d9e13c504551f74c507436911331db60ef0ea99dc259b13cfcb0596fa9b3c95cd7fc3b1611e3b012b6719afbcee7548939676dffc372276aecd08e6a14251407cf995266545427d49ae5ab245cd5d534c52542fc71b3973f0b766f3d234c8baaec8b74eaa8ba90abe160b4504769d02e08d7af4e7ecc167780c619cefa58865169b674b2b1e10d82f6560ba0be41a781f4afa46bd722566d941a8e6f87e4a5c03d89685a22a3470354f2922e2915f9d46288a5e8896ed13617dce694a595e379f25fe621dde8ba73d865976950954e5bd07db147a0fb74f87cb06aba49b073942b82fab33a878651df73df2721ef800b658bdc6c359d396f684598e93f38e79639b8736b02dfcc124fb9fc199c35f2fa1d0dc39939c57286e58a7deed7b6c76e02b99a14d9bbf11f65d8eb7fa096fe4baf0f78cb34736499a0ca550f10d7edc8909dc34b039e3abdf1aa67a51d37a2eaf4c07022897d4d8355d3325bcf392d91d02d462488ead90b366e9645b956c3802e4249d34b5b2b2484a1dec15a9477821df6bef5e1626ec5ee9832fc3bd0b63a3c4100d32fac3e9085f0b5ba43123f54beaa7ccbe6ba68231649f35a28acfcbbf97dea2d6cfd96025032b3950ec8437108d0f07baf1bc89e3afbc2cdbb5031d3cd9e20b19018adda466382059229e4c8c54b455eda4280bde43b36afa96e146e408c7104523d5f565d22ef86d4c7cbf9c6e0d0b30e37b37feb9332939c642eacfe19d0dae1259d3267635051ea5f9b518dd74786e45fb8bdf72cbe3753bd50bea2a961b49cc0e2d589e77fd25ebd962463fc728b1d288c38a79a182b124d345872afbcfe792d259e7e5334311244edc75d05f9a12eadb61fd3ff79fe8c097eb01a4ac1f0c339d3be74be3d96b0b6a15e8868d043a0f2007ee8aa51756d78b7a78ad90fd9a26afbcb51fdc20ed7a3947f715c833e363bb87504d8efc9f8b93a993e2e26430f79f3cce203b09093c9b456b1967212eb0db4f7688d4dccd4a523866f75c9d9e7ce07825ae34399c5607a60b771866a647b6d5e1e20795ca906e451f367d8c40ffe79a2cecfe7aa47a402f8d49be9084661c96ebb11f1b48e7e8abd2978ee626f962e98f99db4eb3c6a52aa2bb2e62194120ce1e773b9db784e8c9b5adcfb70e3bd5717293eebf014e9872c5c1bdf3fb296cb88eab5e97a5ac320092033b49f37d840dac23021c19ab2a89190f3c8dde927f6e6b41874bf71ba7747a616682bd5b3f17a1dad40f4993a1b186ce4f44afb4e36af7715450bac62cb1527eb8db1d87bbc4d9c99415d16660e48efd911e02f5777a77e72733af3c3f5315dd0c785d5212b79c46c3bccd74582c57cfac0d50fc0c85370476913f9d8e8e10d0f6602f2271994972de49ab1a91728713c3cfcedb0e61c270b5fb331a980965bcfe10b41251a0f7915d5943f49fb139626f1c424524f2fba3a407e77dd7513669894fd09fff4185fbb997b4e4677f6ea0b52892f013f1691bdb38eee9307a565e396bab484d91cea9268f49aed29e319b0add900b6a75f7461db5486aaf5366f98df05674361308931de753c70777de73337a996f6d4b0e06d63a69849ba7533bb0e446f062edbd6250e61a49f4120f84efc1cf74c1bd30cc61a2d719fa76991dab119fc814a7c56f48bd584c7935679c53bb0ac78905b5d961fcd89a4b567d17a5182651cb07146aa9a94972ce613e8ff9c878a8433c0244052f09980a52d800e97ba65e8ac186862def58c72b9feec91266e26aa5075b3337c7bb8716b3acafe666ffe2df32b78f9995661d3ba28f8a8780436aae1da2a3e6a0a16dc562b8d5df6f68391aab73a10508e0f55208f974a0505f0fc0d8a55049a7b631fc94fab91459ae1f199527362695b41972e50faee34c5cca9e35e8682099f5e9652f88cfe9fa990ff2154c89c1c2a4ed6bb8a889fecfdf048ee0aae7798c55d6cdfd062cbca97ca289578c832d658ceaf26faba54c9c3ee9eb5bac80698c1441b9cba287f749a5e30d5cc715a01c89353ceab0974ae77fecc1d2dfb31a5101783cbc002c73cd155dfd14685c2f9acc170dc437c649b6b4720b676848a7f9b56cc4787eabe72f6e3f2aed776f9bb1432fba93a63bfa44fbcfcb6eaa9ef4b79b32bdbd68cddbb9897cf5a02c6f99fc765790092edf0d5bca7c55cf232a03fbb6f3eae09b12e09a9b49a538e0589394700d16ebd3",
+ },
+ {
+ "3497e8d61062e6f2084ebf72d00e9a47b550591edeee9746f31ea28039a1646d384c4348af293ab778f92a4807c48fbd14e8dbf3d67339c991dc4aca7dae38b5fb7bfeaaa538611d328b653950f4f664dcd257b345917cd66dc6a1ea75d99f70549d1af9d67b1608077b41576f38bb4c0a13ff4fa47b251142c6fbb79f9a27f43841ed0ebc0416c37f571aef8fd63b99e93ae88db50e9ef7d499ae7433d5686b165579d3598f96d9e7b1c876870310703df8fdf2069beadb34984f676eb7d3840c4c5766dcee3fc39f0739260a499647429339482e232362bc72c92a299cae36e9069cc5f4db8893e2c1b9ec0b4f334de26c951090b9724c2b3b7655d8248bc12a27861e020eb1e4cf6ad0dab903279b6fbdabff761d4ba159c1f631e681f210a8782faa86e08e554b5e30046157a0d1144bd08a691c2cc2dd22f3c3a4e5d44c5d03f7e3e385382ee4683345c0d316d41ee75f87038b49e0ad3ca45121789e7e7b95615e1a9a8dfe02c044c2935a97b141f639448182252ebfc980e0411e5fbcb3c01acd5aa7cc5d67101ffa6ab6acacace5f02d67155c26dedc071ffa66dbad26f67a819d46de0556fdffc1b4ab6d60905d8ef873ea1e51c62571c08b4c6db242e733e02e11e5840ee445c290b2232010b118839b37d4615c4521e8928e9ad475cdb4a3de9928ec7e6daf0e20d22e308347b31e7e877fdacda0c25f2e5c33a329e84707816ff4ffdca30dfc753c2cf883df16016795db34359e9363fac60624ae4d2b30bc1f2f99c23d953779c22ffca145fd08dad83c0f76cf727196799544c6c07483e0a41ca2e1b1da5a730956154f531d292b5a39a229ab13bf24a804eb68786e481c8aebfd3bc557afceadc41d00e1472c3b80ce652be1245089283bf1a1a93abd3325bb6eea121db8c0e1d6c0c31decfe9dba63c89b881824b0531651fc500f2f75ca9e5fdcbb179c9ded5d600a495ea704c2709f4a88c4fadcda4cd82a5b089f25a6fe0161159efe03fb5e0d44bdb5487f25e8c9adacc389860f62b06a6a4f8f104d9171622f70652ace736e8b28b70a4d9fd3fa4b9784d1a6e6811150d0a0601d31d17f6041e58a1058f99b80b0a6cd4f79c79a104b6bb731ecc881bc68e1d99ab358faf43d8504957ea0152e46e27dbfaa17d0f58287276e4fa82ab78a03513d5b4c3199d1362e4fd6447d1c26fadbd011abc69332ed0181952b391f2e8a5c89d68e22a7c451f69a9573b6bb6d918c7e3d52116f3f12f1d43d2af46bb450f58bde1732a268293cfd9cf2b90a844588c1979a30d6ac21aaea4b9e5500ef4a8bcd62bd70cae6acc8839f818d23c615e45daf14335c36dd46817c9b816be60c3848caa812b055da33f45bc01721d6fb7e850fb1e1458f27c70bc34876a955aef11f5703cfacde03a039c3b75b99b2d91fc18b00071a28ce25eb169b946b49858aa0885a4c665deca020a3fbba55d4d9175fd91e7901ec9eec0239806e8305f8238e5270f4af5c94d0008f8a5564636cc33c8a3d3e76db2a7915abe798b0dfbb3e322b33e188c7b188573bddbb9e4a7edbd4bb194b9743c4aceeab449f8affddbc2b109eb3d84f3b2f8b18ea2962680437241d82bb6146674ff1abee7baacc38d5dcd688b425c3e3b0dccdda3e36de755afcf7155d3d7cac2e279baad167e2a743b82ff8ddf3db8ecfa9680ddf468339427a4e9fb8ca4ce6f1e790c24e7269912a9989088c65965b0efe68ed44eb26876674261e3e72042f5995f1a7075b3932f4c23a8027d0db35ce4322122f489995bcc0b3fa32b7298c4c1b3354766c866a2fc0ea5690c58c5e08ae7037f70accb3ca7faefc37d78883f2bcd768285dd2571dbcaead813a0b8ae87cc1df868e93500d414c4418d5c80b919f73b9fd46111a02bfc884f9d30ee14fcfc1d55d54256b9572afad4777b8d8172c911472a22e7461f6f85aca063c19d6fdef3351149ee6864e93cdc54ca5dc7837f0ead91f5e3b155795df5dd1f933cee8671ffc05058353995019e5f6f55d2de6470605a5411afcd7fa5aa8f38d77dbf496d7fa9c5a4d35ab661aa15c77ce42bed44763166160ed5bba954e470c293ca301363f5b837406ea8ea746057588c34acf266030864d8c40e2da88ef04c49205fad1607d456767d30eadd884359bce04c12e35487bc1885d9b104c9fd4dea4ceaf054cf46cb3c77a619ffe963acc9bfcfad0447591ccd32cdd1fccb1fe7080ad75cca2e17f695ce0095a774327123f21e2839773506a9f2d896bde87dc5e35512ad733aa408f8a49e9018d1013cc32f550c968a03308cdbc73ab444f0a79a13450d4de906369da4c6a675d7e338f738358dc238be4f047579c8ba7a60448da541cb9e57f22bfcb8c26280a59b77edd0f5a009a3ef1e2958d6d3c3372840dc6a0c6ab1fe86aeb7590137feacbfdc7da57c77595b8572b45c4677836ec86fd8c4ca8ac351397aaa3aa298d752754507e1cc514d41c3f1ae0a692179218141f65bccb9acf6244730c6d00829455d21371972745b3665f930cf2aa9f0abebe6f7b89094aeb4dbdf7bbbe794f134b6284e289c995ef2929fc1bd39b259259950de29e57cdec15c4a7d33ef6e689596a6ce23301d25c2ace77fe699d90c2329da4d0f471bc093563dc735ac2fdb32c6995606a67bc953534939ed1236003c004d3b47590beabf39a1e4d5d1b00898496e9effda68433da17d1ab3a32aefa3681aeac116c5705077552649153ed15e9d704e67d8819579feb02d91db0d3533182ff43ee5648f5cc9a595ded4772d61e77bd9bffd6f29fc1f478dea44c32d5ce3118bc8860b254fb0bb1e85223bf709a7c0b9a52fd3914f1b1f295fd246bcb568388dee43a32df45e3c798068608a102143b5511746903255b98238003eed68776b46bb0e64af6c9118ecf9896709aaaabefbc1f58bf45b45768345b560ae2cdbe4d7da497736da8013c4098addb4258cafe7823bdbdd715250b707b155248d39fc6773639e4de3b201fd3cdfa1526c4149ee7d15bbee680c956fbdea844b1470a287d430c5c7e2d7b51fa756720397bbe214c19df3399a989958732d93979e361f7266e53a59bcef695435db67cd8749d258e7d582726e1bcad1395e68d7848849fb6d74451a53ae6e8989c64701102959f7fedc6a5cf8352e218396f9181f33037ca74886fae6e57460bbcb71cbe4cbb3d3a81e2090434eb1d6d5baeee4ede251952ad88001ce047279cfe435a4afe97847f798d84ad79a11bd44f09222d2f3b7fdcc47ff8a4c61f40c4629a0f603193e0aa2164579a05726e547c9081abcc0087907f8034469f740a020e19623fad42e9cea64068abb3d6ff2f6680da328061c200e1f646816a5083786ae5b71728a0e5cee14d7a942379c389fa9dbc7afe7e7ae075c061df11e4587bc90f92f1b077c091c43a25e7b3e870ad852c2883aba2632063c4ff74a857ef7267816317f823a8bc5dcda311b513be3a40e6bdeb89210bece50a608e624f00c9d063e0c8878884e45527f50a3ab4447a9a01652322700f087b6f96ddbe96a68ef98656800eda6563015a6d3c0eb1b6a9b21cccd58cdcdd074b73e40a098a980210ef831ec9e881cb42ee07519fbdfa52d9c62766a2046dee7752f880dc9082ed7f050b49ed8d14307b1b811bd87b6db2419418e49885d20fd7ca8fb45a11a1da17ac2304393734b552b5d02a303ddc72d1f456697a287851f207054c18a6262f5349348c806841d21e11fd4e4ed9c01fce1688483e009930079f7d2045a34f98ed83256dec66400a783d58c61619e6e42f6e2c6e6fc69e76651b96aabfe643ac69681955ce595f4696b80dadd1f3910061be6ed0840d47e928dd93e7c3d6932d3ead820d06e2539d9a604a6b53db6bb599da851de7cc060faa9af76d708a9aaf371dbc3eff0fdb99702504c3006f789a49feb730cabe40745837e2c8c17c77f999333798431231b337357637a5efd1eeed891fb7475f2c9f960e67578adf50241287bc5599ee08d0237f08c86ed9b75b62d612a9353e48cb4cb022d78f73fba1fab7f794a5ff64c97e6c91ec464847a81e5a5253989a1ee54a41bcd9b4b77bae6e72421471a7ddf0136edc59b72402d57e542916ee47fb3988b7123c6e8debddff2df171d4ce61e83c3d41f36143c9df97f2f68639f1bfc2a9d1fe175fe9f45e17e5cfebb330d3f06e15e3cf58acaff09ea576d896359a3f06985765824bc499319384e4c458d4326db801c564b0b503552bdbec60752b670d82cc8fce9028ff24ade3e805b81a72701b37d4ccedd72118b20d792739e035bbacc4893ded88619a6c499f246311947e48684a35406c4ef279c71ab2a74f6e5313f7900080f19aec3a39109d4aa41c930c66c84cd2163f4cdd59fe84a86cd8bb6468bce45a56d09490e032da844e6d90b436dd874c1cd32a75d1ae1d3e86d8a2ef948649eb56dd7b360f55ba5dc34a12f9279945436c6fb83d1ed57ba4ae1d9342a3dc2df9baa82fc9fee927c13439ba5bd2ff9f3e6f577b8d2df731db14c51db8a14bb15bf3e125f1ca4cb2fe856c5a576cf995db5010687d0799581c5e76d400c1855bb46680a631cc582f51c589a831",
+ "823d0cd34e7450550da9716c1f456ce0cbc79431483a6214939266581b0e899e4c95719a09c1ef166a618289a6ee6971b6fea3fe380512cb977823b387ac51d341c26d4a835c61eebde37764d2e1d588df7886177e98e3151106c898b3196bf4dbd83f5f",
+ "a4639c22fc7f370d8500a53819102df5e86c541c0ca10e8f6564e50b90c28f34",
+ "34a04df283c45655a52bdd84",
+ "cd8d1b2e5f65ddb3c0da8f12096134da22ad4d541444964077610aafc1f77f8da5ffc75bee807541cb6eb0526e78d57fd88fa9d9608914cf391ae7ccb8eedb0aa711889f9b6192601163b271c90df5d69fef487b6c05a24fc667469cf16cbd5afd58fc830119fc9f61b26dd50a96ed84c96825a615a3aee84ea4c950152323b20884346b25c9e2a6be3a93505ba059fbb114c224bed8f05f54eab76b2c9c23a0fd942eef9696ff67484b542c8347f1b1fd7df7242872b3528c9e45030447b2bc85eaf191963291e4223b75778335e5f1256618ff87bbd68b5a9e5cbd2ca1dc8aff4625c834edf8fb0d879b1f75ba9b85895a6bb4d7569a41bb3be6cdd020065bcc69b44a8fa335d9418ea2d090d8061e042e8e1a6ac03a6d5525079f14274079734ed42c5c9ab9986f0fee6bc9ee6c485e233e9b4d6de70664902529a135a5675ae129353eb2c00b73f226e84fe8c594272d6eceaca28b6da30492c92074250ec80beddb7208f9b5418944305b0864009b3bbb3dfbfb4cc2bba3313f8f7c6c19860f1dc0f5d7aa06e3b551adfc63dddac980a79d72bd2225d54a87a93717291c7b78bdfc5521f7f3239d5564fe9c9559dfefe76b77efc2e75991f31a0134529a6611ab9ef076491f2d2d81ffc5774ba8f8009dd7e5881e09ddf5116fcb5a44e576aef6cea91ebf52c56c742049639392cfb8b280dc2229252e04d8d394ffafa539290acdd8118656e7e1a4f7bfc0bb689448379e8cedff7590a09a3f5a29bf819fd87297b96ca07431a29a07ae126eb9d65e21824c16707db89868e127f17614a536de6ed268b1600a8b02aac2bca54a09b7cccf8e184448df334f95b9f0221187d56da7bd422f09b4d94228098b563df53414a5a86728962a2ea63023d8c3f03847b36db7cd189ccfef3e623b14842b8cccb18b4f80f01b32a4cec48f3009b98ffa25dbad76089c8700e90848da74aeca81d01f4dab2b7e844a3e48bef21f33c92734b821ab382bdf6d0b1048a9866e676b78ac9398678ff626d5c173a15a0a7514b2544405dd54eccaa2791605c87d7117bc9f8c0ad84623a9d3a2b1733304b492d4dec38f7981db9361b03a2837a95fe937976c7f4341a802dbf583366fbe368a3af3f92618046bb55696cf7af1f465a5a57ec5908621f431ffc762f35abe892f772a60a3f75ad8401321f67981e90083fdd1cce40903ce56a629120d6e13c8871523c4d848664331966298c8b31a5bc8174a8c14f61cbe98ae7ee3e90bc832b04318864d19a9b8b6d49a260f42bb120cef9afbe704faecf0f428d917ead9f020f5e9d772bc8f29600f8a7623d8971c1e3c5f1a3b094191e497bd70f85de124137cc4b9fe0617cb73cd44b89aada072625e25976e7aaa5a8fe9d9e3f32db47d1565aaef0e84d256bfce6aedfa1a2dce5a94976a2bb9a0da95941fb7ed444990b0e0e87627e35f3235a998019650a5e5cae804ecab8cf729a5c712f1e7d17486082dd50cbeb2ee1b0be6a7bf08a66ab3cf1fe9f49c7083f5b8ad183f32fb35fb8a41230e4041bcf0e5ef54bc3d21ecc1fceb08d95d745a997e8f2fc3c0f6b1b6c1c02e03ff02ae0d879d13eedd42d9f9949ca7ebb785764162ceb6c6f9944dcb3927b2f4eab23ab566b2b2bcc0c7d77b82579e88203602264064ce98b5b1ed992c1bb13edce579ae7f5e11697b493749f308b33e47512533350df5c07c3dadff656197884f359cdfcb736d29231aea1524b56e06c92f5a98ea663543f67e44003f5b41907a951dd792468c84c5e0e1b46149a5c9751295e153990b78c0cc712889a21b299b0315150dc50aa3b4f7fb0079ddd39d263a754b1dcc595c76ea9fea6c120384afb38d4bd40491c4689b1afc9dd096dd0327c84802bda6bb6b7a8830bc6c06b308ae9665a8666a5551ec954eb72adb827ef38f036c51698a28c92dc1c9e25c267532da2c04c1bf27f5b683ac750c3ef53a8460dc186331549bf82868f9327422c09afe1cd15e161bc41a70cab2f973efcfc8f01a380b86a432e1ae540e09d404d93d22a20dd5f685a52f0acb863dadea236288b1714700f23d1c19e40e219e8ed21f6a393e541abba850ffbbd4030e5f6567b7202fb66d86cc2a0beabd495814f6a50690e8d74cb8b093e4d43261fff80e7a67ca06dfe808899cbef84c09ece01414baac740cbe4c656b17991868e2a136f4785a0de311aeb18cc95ed33fbece22aaed8cc1e47f58cf6c09a6f92c96f37d2d2485b369093506f5e9f8534f8569655277d0399ddd3d33861bd40c71ac53a44d1981cd744d79202322d47a0228356c0e27efa2ff1009cf2a416fb6e8844eb76b8077a4a3961ff193e1c95b222e72688ba48be82ec5da498e58861ea613782ed1ab50a95b5cc236834af98e61528ab18453c20ff978551b81e1bcc0ff4b7092bdd9ab0b946b7324b7361ef05e1f7d7f6a336281b4bb2c671a95a6ab84be6bef1b9c8c3d2536edb8d79b40637e16d7281ec5243016232d7c9fc07ed9dfcf555055d8ae65f12ad150da81f62f2e1e82b3adacf6d623ee4759ad61a09038905bcf1dbbab671dd28fc1d10a0b7eaaef73a5862ab449bd84c8698d061e79fbe52a86739ba945a01353e0f3916667bd7b4356cc65451c7003927f2aa738d98245760550156dda529be741ce3ae1afdea0de35ada26ac241fcb5d518e6ee7f9930baf88bacf8bdaccbecfdb920f3b26285439912a8902ae029b07f28c1dbcfde780cd2bee6c6e5f4520c5c7ff3ab5448ec86cfb270c39586f80041f3764b5dc77dc5ced0695c89671cf90ed34c4067b4bd938b1493c7902dd94be824810a00bbde4915d138fcc7584790bb0b6682fc0799cd415441ac90c1caa008c7fde3ab4a3aae478c64991ebe07e6c4587d3046c9ebb8e125e795f0be9266bcee5a4e4355a2830c5b34e583b0355b34b89c08011db6f6b8371de003074704e8cdda37ce42c7e395b6a37bae3dfbe67bcfd1f125c9a262d56883ddc028773988270aa30c6dd326cbffee589f38286533e1d5c9486011170be591beab5e0ce98837cf91f0a58d69d872e364aa88daf9cfa71bad167129420282d99ed5884a1276dfffb2c4100c74a8b863b063c07937f2e9c12523deac4ea16178863d975e3a5be5efb5ffbea994d07f7ddc5326bed1f5c9415c1d4ee1667e3a581499bb573595158636ad94d84f7c6e4b8efc2b141f2bfab7932a050fd88a8c7b21877cddd488543db5b11138cc808e1248b6e2ef492faa8a32f9d93e3c060b5cec10f03794248f9662ed8c283a8e0eb493824e2750ec75b3b1292d80ce002083a3c64cc487afc31b20f84a778f386b012ef7bef46e638d0f1cd75487ea46e05621d608482637b3e642a9a2c5371bead4386eff968b3e007fc263086d8a930dc76a8431a4e6907ae35c7b3291075d1c723f02e4895714803c0e97d65b04c0f27d01d5d68001bdb3bbd44dfee1eff1754fe8c182cd9bc6ee273beb2a444ca1766f747d86f36cd8cef6eb1dafe0c38b9327a8cac6e83e076099188f02721cc4de3d940c3ef19d9b067be07b890c798a79ee8c44d96c5e05ee5d5202d941a674378386233a83bc85134dc8c46a7531b2b952fb277d8089cfb13e882bcf7545f0605271fe38bf4754f98dfa13fe6b635a62bcf962553882a8f28a9a5fc0b3f85509b702d4a7555d40c4f7d10fbe80d48b4826995fda7d15f14aa9b95fc6526101cf09c97fd74baca6bd26b4fce8a57b0726e0f68118969ec067e9ca39b2ba59fb0d78eb5cec5b872613b1b76763b3217d859bd6d991bbb5448bd4e49dd6597ddec9e46afb3f71d254aba828c91de51904139ab19138e36e6996a207da80323d96077c97a3e8994296376d4dcb602f1e77371efe8b020b7b6f6f7bd2bd733ad9c06c45b77a2893d73b4a8a57707969af74ba06b2fe7d4079bcad1cfeb3689ab95c8b1215fe0a855eb431f67df4ea589dadbf055086924e42cb142c9031e25b81e8e1167a54008ba1ad7fec6794f203b27f3092dd72bb766c9653a72b2e25c965f53487cf3baf74eb7742702380303af8c0a61cca3eec78d4b709e35e2cc5bd586263d9f56fc12454547bc6165e3f070ce7b2bcace5c8cbf52f987568dd90237cf190dabd4ee7a80494692a5379b013611f4eebeef8e1ab9a9c5ba61926095545e19c3dd61b7b404230729aff7d82b6bbbed6b4a926f6e49189e3bccb578fcb3537951fe9c78ac842350ddd80133275ac0bce3a669183776fee8288f874d29190b452d65bb7d8edfedc6fa0ae147102b92041af6dd8a566932e016763b60a5b9b1e3667f228cab075f966d1c525ac19d12046c6409345799adfd7154b6d8b51eeb1eab3a132ac6a2e08acd1a34bbbbdd019195af9f8a93c6ed5463765173e669cb0d42b6cffee1a4b45987853d43c02f920819f45a4fe0905d8c65aca182b4bf56fa0dc51cb53c642fef003d92c13ef4bc1bac571cbe2ba3673a49694f6311b7dfc17a4069759177930b179748d4403c7259e10a5d221cd0a6b745966e598f894e607b779dd5289fbdae0b4348141ad373a62c76aa454b35b39a7be875598bb30007fc300606ee2537cfcd7c22b6149880fb3cd8eb53054d698a0d20f26a5c3ce468255737a68706784",
+ },
+ {
+ "5622aa8d2f308dd468a7e4959ccc01f0e80d91f79df65b8201eb44911f6abc758c6703bb97908fff377395d33f96c328a4541f414b7ac34c6607dd85729afbfe01feba988e4997c6bd2c99fcc35d2467b143a8fcbe6b49247226a9e4c0a4e3c1a29d5931e6f1f7a31d90a0e0edc4479f08ef9bc65ae4eacd0b93b1cb38948dda31e60b18d702bbf5935bd580201d1f280cbbee679fd834aa6be576a37a037eabe989c3c18c7fb61fda8b9ffaa8bf22b57a101c19e850c454353af7af3d755b26ff1ee78b9d9daa78294972d108958682a5a29c8ef260e2289ad9d7d74f32fd4e51e5d9ee828366abccd97dd56e035713a6f3a1985383c0ed5d98c4accac2fa1ba7d30a295670d5224952f7b7554fcbfb426c9496f054834dec48f9b70af3d2b1c6dcda1c4daf3e9601364e57851952c785e65d753be1c22729bbde33aeb1e4748dbe90da6ecf716f05bfc68ad819515dffafd33a909562b95140ecfff1d0747f8e0459fcd3ca6cd8893262614bb4bf4b639285f327e7ac782898781968ec98f6f0f2f3c4bc5f9c4691ffa7ddb3662816f8ad092095b598bd4d10d6b5fc6fabed619eb11dfd4d638f4c0b6cff7194156a411e8ad6d3229320336ad52fd9811c3a1fcd571d1bbbac67c6186737ac7ca1ed9b2bc46e4e578f81c164b09ae5cdd4059a2c22b5e7ce1dade684e49200867f9bb1430aff9b99805cfd31f7e3fecbe898f70a4eded86b8bbeef7050eff6cf8ba71395a7ae2e270a2b58010e56cdf6efc4003da3d8a82e96979ee68694b6113cc9a6e377d40a810063830eb95005a81405e5b7de8de67424845bab1911bc55da6338513742d237a555465fa54b07ba50ed712e7a57a39fdcfe4af50f064ae969823aa1c40cd86a621ec90769d0c1babd33e8388a8bd76689215b9827a5819127bb32ecc80a562a291f3192eff34cad2635e5b0c0bc174add72e2041864953f1fc72be7d28111fba0438d9036da3d5c0f220ccfde2319bb96fcbfae6055ed7f1c1967ee9a78e93bbb77cbf151084d602a5a2f087d49c3134582c1a5d7af24f4c88be26204cc9dbf4368b19470fef49a5823a2d66c65e9b1e8ab56bf5a7bb3220696840a6222caa58a7b39fb792d95d25038a8bd9d916e853cc5459640f8b8468e3d51f05f1b95e996cee40ffb7ae14cb289094f1b77d5573c1aee7c12a6c3a1e31491422f272cc5f510d4f18ab63d3c3f468c5abd61b2fa7ba0768d46392e2a4dc06c7ce79841dca916cd33cc0a700b50fc660e5d1808d8b87e65feb89428055495823b2dc317d6d9e50aa5ef7ab14076174ed32f56abe7d410e58ca40e92f8a31433d0d74ba7b130b1561f2b075fa11ead744d031f34d82f1a64d428f6cccb0a009be24b42937bf3e99a1ef1fabf0fa7335dab52918382abe756d3de229ee8223aca6d7c5de87047838e387d4e472481a4cfd4365256e13aacb518ce5300f18dcb5e0a28477a6fca08a74756ef6bd8933bacc98d02abc7ae60df7cb3e06d41abcc4bd313c543ddcdea2424d98ffc6dcaa83658aae11f5841ffd4f5df42368a0e815d2146a0fe138b223764b133d17cdb08d485e9f3dd2bf2b220d1f4565b02d7b9231d592130e4436849f49b1a70772244fc0c38da372a8c57fc80ad57828410a5a16ac6d14e093997fdd5b26e4cd4b248e0ea221715ae6e112e1b68b09f795540e31b1231244bc922207b906c4f42b5302dd7474286b653b4d1bb657134bab117d6c349fa0f121c2f8dac9cdcef510c1c28545eae0ab163db6cc84ca182feb858c10153d0136f00a01c9c7d0bed892715dd85c4e73627c3a2ef0f43710dfccacffd1d9f118c9fb1a83b2eb328b8da3e955f027d95294038184f7b895d77532c7570cb86fd6b37a5a66659cf1e330db3930f302838706050c0dcd91d532d49c89d144e9a7f864026ec99f50acc02bd5f11ee88495ee8991ec4723b189f84e03d992fd718b5173ea1b033ab7d3568dc4656648fb54d28d3119b0f293a930a772c394f45ee66838f17b73a94eca27033f9d5c2ae22eb813386905dc024673850a087958eed191d04d05798bcf909eff2deb2a0009d223323b290e3d6f71b2797a2bc2590d54294a5992d629336518514032614a04847c3fad8a7d1cfc2f86765b48cf58acf892f68b691fbece38100e6a71487ef5c4ae934f1ba03b4b26a1967f70ef1c697202e4eb22a3a95ab3b7b524f0241ab4d2adf3ee5e3f2974d0bfe4419ef0ab11039ffc26339570e74d260c4d5a16f22cb4f60b03253487f5e46c47836ce29460728086a615f78d631d89a06790928455889f58adc3d0a3a84ceb2ba9cdb00a403080e6567873b985fd59fd9dec71e375013c12c51cb67d599198f36f58fdaf897e85dfe6f9896cf6d35a84cfdc6834dd9447a2a10e1ffa9fa8edfef1db9e8b4a245b211de49e04b7e88977b4e1ac9285f43526f2452181ee0f80efeb1f6b2533b656519ae45652ccefca81c17714476b497e5d8e9fdf6c9f504c7a7fa7afa36df5f4f8da5b4b973b1618fc8d2d43e866b235e5420551d1659e5bd545fb78a3e17d9cbbc8e842f3fe6be07b892453ffd689d5188f26f9e4c545ba0b3132af12a03bce6914015d026d3d7df661c1e6384bbb50dae24abfa78079a2b1ac41c44c7d82a59183f293f12011e781d3cdca2f791afa5b55a9f2d6139587bfd74bfc54ce91e642847a33b48c1b366fd8f08f520b79ad5113a0273735aee71ceae361a97547fc09b22fbe4e4ae4ae13e52d65e0971341aab368d1e917c8f5f2ac57ac119f981b51b7c99ff2be3e16935b7c73e28fb58d332e6f2c36281228c479c4d6095cf15b14baeb0769191dfc649a70471a25d45d4433797a5b8ba31ff567e60ec4d759d99244d0fb5dfef7c2896809938ddde0d2015a4c5ce5ef6cdb5752da1c2a33e5bc78b6b7c6a5af892f0792c28560a357720da3cee3833bbeda8e98e6a8cccc6535831cfc28bc8557b4181a3978bd90eabb34b99eb7e55d9263e6790ca34561d8c87ec4e12b4a38df524318db00a9b5bbde6f5a8644a818a88e91b521d716fa9f95bf70b109b9905bfca926fd42ecb9114c039790abb0392a41ee4c190536a89ae6194befc2dc4bcf7562bcb84f65c99b69612c0511552f53436b6c489204d3881e1f67e0fba3a061165d2955c2e2e12c440d31556250a8a5cc04ee5e09b1d627c14e08bce1a92df7f6475db92a3ee57e4c16c3ae677c44237122818ad457a29595ab528744707f3ab7ccf3d20bd94047e013e647802a7af14cfc7c11441ea6e9b9f960fe69d03911ad2cf3a8f633e0d647c71dc7e188c92e75353fc953d6a30dd0040c39d4355b71524f1a4872fb1ecab22c8293b54bb22a80e1e3d4c886d2988adec26f041dd0565cfa9edfe5ad9aa7da1d3b8f68fda9e9df9dbe98148120af6ff30e6400deca6dc9593dbf06c856d0d582503e7ffa185f87c6e7ac58184bb80b4a1c0c18d669e23f9791365fe807356a5763ea418c39d94311759b29b14324fb6f3104359ae66532779b825f92b7c9ea2ba43ba7de04eaef7a86192bc93e17286f1b6e0a01c33c796ebed8f17692eb9237173a051c14e4869afda2643bb98c9ac4ea94c6bdc1401c80190df6abe988d2f0b2d80cc7bc8362ba25c6e5df4370a43e156aebd6aaf856b3f64d5fefc622d078faed40b760a361966a4765adb809dbcd74b7a41faffad3a64823860e5656874133c7f8a46b5a3ac591906359aa4f171ef6bb2ea6b5f24cfe25c2fc7c1973bd5d3bb5f197002c5ca1bccffb570f0265f5cd949c7386d961ac9c5e18b5d1d6030d8bf4a48c10f12dcdb11924b02b8ab5e91f425ca62bbe42b80c6b6dde3160ebbd55803966716734327058e29bd39874f2eac199067fdbbe8c372c5a688d3615e2b65f4937b67d6a26c64cc2a9e5379cc00925c678f174f538915f912e85b7014c064a73bcc7ddd38e1a9627ffddb4bfd6da764fdbfb45048c9495ab1a4cac5642f6c9ffbe97d33cb26964a23719620df3d85dcfc392c4502759fb31a6a797e99e51e94cf9bc79ac15de4e5cf7a05aeb88a8ab4c3b6f9c52b99794503f2c49cd7e230a67df7403e552523249f29d257b35c0c7712053c3d9eb583a1a7473d7f296d25a66566e4ba8b08de2a31b082e40c8e5b1e93985b324dded3f52511744e7e99f4e3ffd99d8ae17bb5122b37f637c5525558eab18a378f5e2cb56fa003ed3af8d139d16ec4b2ea79c415b0ba4d750ca2cdf653582ee3b65a9825fb9b123593e36e645232163cabda515b959ed0a1419e9894f6c677ac200fd11babe3503ec7bfa319f1b9559d94a6f82945c9ca8667621a5d28920949a1da644cbdb58b84742e9d65e7f2027b99fba4dec46f642bd17e88fa109143b26ba7fe285c89add0b74a369f3d381ad633bfb4f72e1822ff96aaf9a73b3c59a6e457cf40e17c1198c64737037f52d9b3118daa3fa5cd3e3c7738e3b3743c595893289974a4aa0d6bf1446e70964823a7d5cee67b9b25b7125d9ac5d1d61f2a6947c3deec6deb575e2fc5cec60df26de3c0545e5b79156dd6af33a78552d1ee9994cc8501b7dc5fe7a22eadaf201a92e06ef03be705a8bdb4db65392d3628c7cbf44cccac292c93cb5a407a7a5a0d5ac9fd95b0033d6eb719d3f14609190dd40d5aa1b983cd4c4e278cc8a1e7d5fbb0d39060d6cdce8de6a17e2dab973a7fa594205e17edab6514372eb51e03b0ced6402fac0efd3af49fb8214a505cc9f5f0ea5308d7fe6dec369ba154",
+ "9f522375925222a04f5c95ee14b6386412025903ecad0bc3ab78afe1145136b3a3592835ab4ad6faa66be9",
+ "d1ba82b3ced3e9817642aaacedf482e79bedd0560ef2754215ee792514bbf8e6",
+ "bb21211f342379370f2642d3",
+ "1a6683805d3f478ca1c1512b9846468378f83be27393db63956e151ec408368b47334afe610249182f54c4d0a01b704db2aa90a9755b8feb67ef9301f0715d7d6bdfa5cc4497cef1142a43eeb42f7c413e8f489af30d742a706d05a40a0c4a5991f9e2cc5d9fbca6ad3767682e20c146ac35aef38dfb2a77388b738fa022158d5c802e5f0761096bb45b50815ebf09172759521b5c5d459703ebe9ff669ee4d14a86e5d0650b597f4a082ba0aef366a924ea378b91c3262d99f48189eea19c76c0f644079f8415c11033cf24d30d6c149ab13ca5c29deafdc816e457257361c1af4b915da312d2e6c7fc712faa27be3e67c893f9005a0e2c28369991c1dab22d38961d1abd6d94c4d549cf491aa1f8d522be3ffa6d214825a5fde3c94c4e35c29b8d05b2627eb12c9d94f450a85eec6bc963a279a37c2344ca36eb604c4bd11c2bf2ecc0dc16c2c365bbbcad3541bd54f8d0bdbb3ca4a087b62fc19fcc1c13984eab807d2a6a1386643d90d412d027bcd0a638765498cdbb1f4cc1b91b69bd241eab3645f225ece85a56e5008d6094041f8cca6b9a0ae3b15585de6fe0695d79d348f8619431ece40e736957a7627224fe92bbe30df5124f476d97e36b5b08b3787e8e00f0c10013068eb156f82f3494a35d6edd5f7048d1e91954f1013ede22eca8b4ba41699ee08decedde87139180a567c6d169b672af0f12aa09ce20e9cac4e78b8067d31ba4f63606c00d1d787b868cf7643fbb170f8074667c9f7584d36af80b4e6557724013618c28d0dd40bfe9d4b25761b3c99558af528c2d290d04b09821bd7f992c044dd61dde9395bd0c9ddec6d0bf6e044ddf0b4b2d6753f5acf2e9c904caa4e9f310578527b85e6738803758da646919989f735b09c9a5744e63fed2c3982e59fd29d2baeb9771316bf8d29213a4956b66c78d5654436ffdd82d0d572530fd09507b988d13fd743f35333237681f8abbb301a8ea870159f802a57760659094d0e4902036c5a62c563f1fc86c4238e1ce89f5176ecaea194ca112fbdeefbef4fa7c203678cafd34486fe58b2af04f84a1cb620c6e123bfd96301e0a5e5e5abcc95d28b852d0cee2f51faa73e42f22fc335f50de4c3812ee14038633a195083f3944284c1086c34995832c3cceb7d385b4ce86af10685c16005495121105272d1d739c584a07ec7801c3667bb280987a8aa41f9537e9d1812a5dba5b385a0b71d2e9573c6f3e9ebf0bf7267528946a6aa6f43efce908d32525cdc3b825bb11c7239f1de412704d24c17455b9382fd6a873180f0d5d44dc449320973d5cd0d4e67e83946b6ef47e5fc3dabadd80751f1421404e56b1bce748b7bde63c6975ca81f3eaf52586a55242c9745dee3f7c796d4508e818eaa4fa50490c1a79624561b98d2e1139a328806414c905372356a22393ea0da51c83957029edd8c2dfcf46d9564264d74c1c0497034ec018b1dd4c14acebc34b6d2c1a616937c37b8b4a0ee5dcdf787a0de1173798ab929b72e0fa83a6c9b9a99d8024328d9c236a8f57550a4f83e8071eac76adb55939f85f5b5f514174b670a3e8dc2b54656f6201940a81fe4953d2680ae4ec58635ba74d15efab3e06dca6ac269711ef2d4dd49f731e24a92a3b935ebbb3fe8d001cd4062669ae4baa62c2947033afcfaca227d88a11769f87456d5cd1bb6606891e71d63aff9cd5a7d23263a78768ac2ac54ece1441fd37d096cd27e916e68891137fc3cca427febd1947cfb4d7ccfad75b2ec5e809c132111eadf25a73043d68333139bd2435de9941bbc61c5c509897cfc19a21645019eaaccb6d06371e3d0570c09c7556e41a727e44d9bd672fccd1f89cc7d58761c16df8fb75fb8a1dde2caaf088f02dad91b6489114398740e6798f3ea8c7b0cfd974e160a0106d703d9589ab09aae79108e3212f19cb950ea9c0798a1532bc2a065d5900a12054395c0545b0878ac0b1d461f553dccfc2a22bf254ced88dcb538e3889549960b77ba6237ab1458e158f4f46606372e797ec9d9ecc6534acaa1218e7540eef11030bb9c3e5a7816f3b33a590d970619bdd2dc04d5c6f4ec38b7cb4d525234b836eab57f65dd045e02367eede9049e219b8712b8d6fe178080c5f77b821f1a475259ae571a5578eb3b48863162d45486f71a28ecbcedb35b320e5b6401f9e7870aa5418449bf47502626e1f42abf481b48d5a6819c640bfdb64f873d583fc4e40187940a6c3373ea7b47195270a8657898f55568985018abcea9bce1c155d95b426f91a734b2a14ec2c7ca2011a4d30019fd9b3ef63a804e9c30c3de2651c4213e90285a4ba100b31ee402e8a7f23cf9d4dba003bbf982526bc63be5af102dca34e7d362d6fbf6f56046160d7af33b364f2a86074d1c0fdd54aae89b19480efde2a9caef9de7c0f9491e1cf43a48752cef405a0ff16b0fc67bbe433a3c1b9661406c3726092efdc076febd60c436476f24dab1b0b8f8893986d951ed72282990e8b1526f4dcf539b22c01c6a7eb5577cd540a16a81296ebeeb7ddda72e60fcf2840c5b42c5cba30eaea5402f267d1d04bc80da5ef0dd2bf3c7a2be986507617c9bdbc96c6273a0c9e586a0c48c98b4552113149c6f79557fc8ace0b1a512fec3aa09ef191f95c2163113ac5cdd940f0c2120509bc53c3ea493c54703effb902ef752c830c61e85636ca95429bf16937bf6786b3eae1b277bf08dcd69f521a0078d633beb33c9aa0cb33b238e1021ca67df122a403a3698452740bdcac81d22ccfe4ab5f835d1961708d1faf6d40f115f16c6094ea37a7ff15e0534f62c19a6f4ded0967be337cdbdd2a7c58ba16ba2e4c3686e9d075c6fa7d29b2a0335ab4940d2a95c4500295f4db84ae65e46c54b7300909cc5411c725a31fd962d239aa0e2007c285586b4c778e2ac7afec42cd8409a63d7cd9c677031f43f4aaf04258dcf1270c02a4764177aa66db2d8f860eeb1fd06d0b27587537410bcb641f90aaa7bfc6f12bd143f66e7c933a0f3ce6b5048913e1b2d79eaa6c19e7255d5eabd24d5f12426339541a22d600cdfd1781a1a3894740887840aa82e5a461fc324285b0223ac9b95c3eb88160353f168b3d4ae8a2e87b7715b5fd2671f66e6eaaf9365b3d9e3acd9a749faefba6009783771177aa4dc91f72fed7a5bf6b1b7738b84ac0a07b4a5a3f0a9134a39e1e7e3e2f9a92d5644295f31c5a356092bf07c709b4c34305ebf50e857a4f593dd1cce0439d3fd125c1ede1a48f583bbbe0eec7058345129ef78868a96f8a76ba7fbfd1c5eebf75f3e0eeeb9db87474b96f321b87fffc02433513fb467fb74e2fc8feb498d51530c753e9a173e95e0edc5ba9802641a45db281b2e2d87d409057b4fb1925e834e90fa5619ae3a9237d5b104e7ac67c2bdc31001eedb4ec7064b2f72e0379bf8780f67ec4b195db014a2d130e77b1778efe3dc703f1310a566a6d3b5c9b12b1d4e25815493ed1510a516a31ced3b64ca49a783ad63ea71a57290727fa31386d2fbfe41f12d36a618c6c28d8f10405eb3e0a33e8ac2e4133ba75c688c8c9a2bb33c8fa032eaf3ea0d2c27bf89269c4aec55f8232b292e7fa9fc24527184f19187d9d8a3f52335e2feb5dc6d997b9b773a79a31db832b752e5738963ee5d61a1b426414975693f986e165e52d46cb059fdd4f48f008e96d4c1a48306b7c002fd0c861721656074cf11173ca65cbdb694c79f58a3f3365e872b24670b691682c10261eb1ffb2b65da031d070e31542f49704b77970a78bcfb4c4ca517b4c966a4e8e27664704f633e90cb7d7917dc1d3a8b8b7fcf59ea3a8a81305761923cb182cebdd59255803a14ca8a75fd007670d79a25eacda1138d67a0fd1da981529dbf182fc4d7a700ba498e4476a1d415381c9e2ffa3bd46201cf2e454c4aaedbbe3893bb4121a6de02cbecc1f319155eb8c99d1030103bb6194bee51e74fa01f28dbe16092955b9599d5c1f1c3f356e26d48fcad7c4cdf0eef25c25273dd62171785c9d2c5a01b1f3da9b4786b1b399d890e2049b73c12de2fb7177f2bc3d9c645398111ebcfd83b73119897bb994f998f4a6fae1b3d6361e171059dba0bf9de9af7a5a1b21641790baf82a36278945d649cf5d310f3792fdefe8c58986a48118fd94647b786e47733ae703701e18992bc1b143b1da6110a98030bb9895c14d7b8eae1a155a550e219a5b6301b6d26d7956ecfe4c7023eec1ff62538b3606ebc7906a1243bf8357f593b6cfff32e3fc6b51f6a0ffaecb658d526f7a5e9faa6294e4808b779f4832318cc184e49e8957b72bea0d67366e040cf76a85889fc6b04e84afab0d02947d0d83e0de19f12966fa8372f6e82ff402bd7a69195eb1a7864a3375aa9e23736fa4d4b0224647e416474c01f72b7d4af240d7f43395b5b04c8fdef1165ce1d56ee8ba0e350e6ada893e0594facbfb5f0d8829ae203929525951584c21371b86deb0f76ef5daad5e847135a6488b35ea33e3a165fea502975d6421d4567a229bf3ce94605885453610eb9c82f9ea743bee9e14776bc3076a29af268cc72d9092a492d9ff08c345dc2eb2f8003b561d9912ae1198c58107f8b37a08b35075af9863110e6770425e9d59c2dfff9d9942c8bc3bf7904c2a952bcd573706caf1ee14420564ffc433c0f5871c4bda916f2530ac75819ade49fa1de21edacbbf6b7075dba21a84989411c566b7c356b81803c7215ab0f326a6b8910dbc62c1bee3af51f105fcdebc0dbc56a50b22cf81eda563bf8c2eff98b476e8",
+ },
+ {
+ "99444e82c6c4c47070b164f298ffdf6955ee5bcb3070b9aa95ce658db4db084d2056cfe61a93568b44ba7ddcba5d450f4ba0da7b119425a6628b3416663c638692326cacc5c237097db5e537122b465dcb21d8dcb5fe831789b72deff3907685c2e23187a56990221e755930a09f8d6cc065487563cb8cec82b9dc754952fa0b342c92d99522fbb39854e338f470a4b4d5ed2a39b8b6253b7001b0b953abc588d757616c7a5d1f12b1024aa572ef5a47dc8480943aa6cfaaa78064fb2b29830280e46efa418d0cf38f57980146f2482276c9b6b16f865b1606bf1131e894336979a163ba2e70adbdc746be0d38062fafcfe5603e6bbb55717b66a263fbd5cc7476302ea4a0dc6167221f745a26a309f5886934f4258965a0ef0803eaddd05e54008df8a0695a078b797be59f1eef95a658c99a7d52001d4108212ce5f18a39f1173291808c980b0513f1a531e03ad7380372b65572d3967af4c25fe54d99d664cb67e557fff05c12e10143c13b1bfa3e8db093ff832a7978ecd85d3971349e3c9b83939b73f0ad55f1f1162d0c106b99c0ff98442911bc15e9194f5b4ded97e9702b84e31b31380c224f392e5fa5c720a45f64cd7020e25a3931b5871e4c708e77f4729225aa9f48f9d876597d3e79219dddee0efdd16836021dbd21692dafe121217347cc128fc5eb051e6843978ae17478ef714957a84c74656ddd931cbeb43e32fb0a448acf2f90ee98d38522b4fa9aa36be4fa13306e799d4c0cb90ac0f73cbc018146d1b0d6bf48aa446a5e3e0502aae9fcbd196b36b6b7426fc10367febf687f05392fdcf878863de2e47be7e625d0e3e3e94e199f055c0fc65f76c41ede43231873ff10eb854dcd6ac9b550ee8533d16f81eb0e86471d4da69311c47255e78ac8e79ab36ce880d6b135279fbb5a712adc5c3862a356af49e9c10d5b16f4e5dedb80914868111e194745b802a0292c7c8564de28ba8e71a44f7eff6573e5434e65d496cde5b5e62cfa9e2e9ac85a164dbff5767983e71dd2661d37d9027a27674ebe3433731a606db88e0880e91ecea8134421962b3f68915c9f6a5e1992c56750f99bc313fb30cb89384c72571a1a6a5e3c01897b691bd70985352217fa8a67f3252a06205bd1a9931d1cea3736559572561fedbf3ac4c8bff9ebd7f3753ee69a69ecbac4be6357db7f4213b697a828edc716ac01da75c1d46098c7d5d6ae6f3f9a2903588c5b340c9d47c234efea21b700cdb8db4279afa2117677e824e627bf0f2b179c864ba823926a57825478395545f130886bdf2a7c55a2647a888c3998b750343d9cdc602e46b7b09a2fe9ef74db1ffc46fe27c254c927ce51b307e96a571da7f3f907223fbed2daedbcc96197e95edde7859f3b4ec6099f791089e368a68a5ba0917ddf4f50b93c0c839ea36cfc8053811f8fcfe6986e5fa9f743119ecd6c3e5fea1dae3ad7eb465a89e9c68569190688a8d56e4143ceea3b11fbd9de67173d5134ec8b0bd7d16560ba2be52345ebacedc01a2e03e8183ef91317d87b2e15cc6301586ed829d438e4ff1d074408b332c8ce60ccb6790ab08c228807509dd4b39f2c227755f6b039f5cd413ad6f46c9ec2cc6a79457529d297b1d9e74ead9bedd9bd652fb31568a8e2a9e2b89e4e57601bc1d960360232cdb30cb502b950ef930d54c2c0692a684cd44b0472995bd2b41dac1553ae47216253d6640d2653a033a862f3118c5b5d60a662d240bda5f4da51092eff514f61a425c5b14b19517ec1b371d240cc30a0739273b34f18a72a69b1586802a7caa6cc8f5817a8a995695d063c9dd26c3d45feb0f84dc8a0773151cf9a537664f942f351599cfbee0558f441f5c7ad320cabe305f9aba570ddf6407749b6db42f9ce94526a8f4170e735b1dcfc5f0e090af10e039db3747aa9b4f1f26acc34639ac8b60557f7753e2c261a29852932901a4093b7f307319cbb228e26eec289898b3f8ee236032163293b8caf64be3f7ffed236f1da688d958a1bbb79dd45026884904bbb936c1ebca7aa6b0c68aa8b667dc1575729e4ecb4ffa82ddced2f4571bf902c52fc4a0ea3f47aaf5c243ac2a1fc19f825fde5d9fc8d06d97a351eebf4ae1846aa62554d57cffdb3f3377695338f8d598d723289ff3962796e8065632e7da9d8dffe2636cd23eac15a60568eefe3e77c561906555268cfc1e9342417b1cdf090cc16c79939b15a9311b0210094087dea22833f74eb0e35d44259ecf327dc84f3f24b8c2bfce7be0d97e00d2be88a150a0d557ff963b4cda60eb99935951d288768b4b2649b717133517f5e3909744417c9c3102c77ddd285976cba2c89e2b4f297665632d7c8652847c4625038a6670169772de0550066ec6c2018f503cce79a333ecc0a0632334df6959d2e3b052fa47c5c84d15ceabdc80bd6be0ea2a5a8d5e374e0e9a613369ca8d4cae3d9f98755560b27b2f6e47b01ba390f5ddeb732c22b12abd225e26ecdb639b08f3237e488430b3b39f0b63aaaef4907cd003a8f2b4c3bfd721d6c3fd3a5f062d72746606a529ba34251ddec4026f40d262e9d527ad84fecf5bb2cc8601c2a38437098aec2335104842ff1c455e5d17c136ece8d461d7a3bd9a60339c22d71059e09b3603c0565c0345684893b56054ec4d3db0bf15546cafb4a03bd7775c3157e7676bb7bdb7baf3100396c563eba1a12952503eb6ccde6b6d0a42d456743c4ddb97f5994fa08c5fa41315080eb6b928090956bfc6252b232f6e0785d233c3adcbb9370b59c35b0dd66005d516befd1fc843df8e68fab19858b91e2aecd1c8a88b0fa3d4c2fed2995ee87e65976b755fbf44ee183f9fa08848bea325807bce0b7b61e03e50b2c7af9b360532a17a8250cf6068fef0198738c82a5e58961c54017e343fcef7076e823d63b4deee472fada7989ca7a213d06a4e3eb2d44b16e5c94b1588321cf6c45a5a792938b058d667e1730f8386dfedc50ea0a959b78f12f2949b34b181f90bec622515227dfb8a5f6e89d2e559c0ba686153b218d2c50b67503018e22914ce9b49d3bdb7cf38172db1ea130baacd640c111614e3db204b3b50641d8978dc14b2afc27a7efa819cac6bafa8166d1c127e2237520d57ad38a80146217a12363cb1f8a720e328cd8f846d379ada43bd4865e4aa633c479bd448d205b2e43befa63486c717af84a733f1dececc127c047850aeeb8ce677612f5966e23d92c1d3c758aaeef82f862c1154fadd6766e1dfc780bb447732a5968c0c78b9af4a9d669338458b57cbb77910a24678092857c0b903152035bab6b1c73f7b667a08cd0d31128888de3ff1fed24866eb60beac19c1b139f77bf0b9332024999a2d56975e691fd7475fd93622119d0d725bb99c1d6ac604d6b6be09d6d29360fff9f84e5318259a67fec08a006d9772b9410ec6abd4cb828b898c625c2fc35c19cb9a6cd3b0073baec7b5af254d21de8e209539f560bc80ea38e33658a68262622cdf35dcd6618b9e272ac3644c91f27d372c6297d8e37201c6a86a7d3accdf579c15246276a0009ddac4021755f4848d10f714e9da86eba13f461e6a12edb1aef2d6117986120750d609682bfdfcb90ee3cde8be54d45f841a6dee2d5b9fdc4e65edb7ebffcf3cc5c8a4e1c6919ac57568be23bd8283319ce11fca3caf968b057432f163f22e29cac30b8154a646ca0ef4fdbc7770ee1451fdde9e9d651992d94c843d4eb2570975528ad9f8c193f7c681a43df28242547010e30d75fca04f39247c77d6c3715c25fc261ecdba16844bbab23e4d0482bd1565ca9b526ada9b8f5703661a84b23070d85f3e8265b2ce10750c5d798f1a8ef4d51a473ff4d2bf4be615566ac796db9fe61a224bcce05c31ecb9ab7bc43a609944a7c9398a7875609ddbcb556296f548a117847df7d0afe48a5b504e85b0d7ca589103d3197933a744fefca795e1e036f964a4f14554d5cfa0261e25d6e5e02f86e402906d3637a2352459cb1639f20faea6f0e3fbc6a39becb1b1b3a791e32e85e5bee31be685410adf0c11190e20b7a5119b90e83f2cc4f0de8898606bb6e64165c95d4c5eae472daa6836a888ee4d9a79de72b8fb47a9c9c0323a2be9106d4ee9ba8b3858c256032a9caba37af94df4c7b0adc2f8478cb879b6d452d73191b0fc1ce944df3f4809cbf3ad46eceb3ba4abd9679410f45c8aab20dd72626f235e7c0c934b4beb4507def24ebbdd7a507943c81d54bc69df578aacd9ed0bfd3b7809dec345ba084d88fa9c34d80685415a4d5eaef9b88e51432b2b2037186baf123a6257e47aa56d6531923d38178e8264dd315e95bfafd8dacaf901e354b0f58f135d638df2c0f32453205c7aaeeedf8c102e11cfddea9a98d3ac7c385d71b760cf2afeb1ebe1d64f0222b9b101893d11a74ed175297c1dfd188a2565fbecc6bb07b56ce3973322a965dc5a675587890cc65a71efc68fdcdf1a023505ef0bc0e6b12dca5860fcf1c6c94c2e2ec3a72b8a019d69c82d36a73738dc3d17d7fdfe992bc8e18cb5d3437f1f619dd318b95d1a56b6d273ed79ab2655d83e2dd63cb6f1f5987eab6bb21a7b13b84e2c619b36b842192c3f82c755d8af840675b0bd67a655d641b1886c3c9c147ac87615ff3e58085a879b21dd63c1616a3712279ec87d650a2eed665b797ad631f0ec312f343979cbc49b99385cfa92841cba12d52777df565545a1deb07800a15431c0987b4a543fd5ed6832e80ab6f4b4d9c9ec419932a6ded4759f5c7630a0b80139234b8d53117acb4452c60b477ad50157169a89bd796e2308baa9395b513a94747611c7978c82dbdf48d716c3ac181ac2b2a4702c02a324bd4c5e089d989d020ebec9963b5c721a95492158f54973b7fc1828181acb3cc8078ac095136d97221c60b847bd2a52427383ab68cd1f10b92738c13203fdfa0b78baa09c1837be2498667c459",
+ "0ce980442336d0f427db869a6799baa6785b5e030567c588e2a7d2680e96c11b7f415fa27730969e0b1c3973b5f3192d4e773153def6dcc09dae29ac44eac7c42c2666a356fd4262197bd5cf6eeefcbd662d104423ec05c19a2e6ddf1834a3445a09e8b1062a1320a5e8ef13d6ebd03c19e1813ccd86fd68b46a",
+ "1ac8a509db7bf4acb80d8d394a5abf47c273b2093f50f35049e749f3e16cb0fb",
+ "47cc9eea11f9f3f9aafa23bd",
+ "088888333340b3a057b05491fb2402301c8654948aa6d5ee1ec75eb045858c22056fef0873d6675f897126052923a47a30675b266ffb6181cbd29ce2da3720e36a227e4c6e53328d789913c0d9cd149a6e49293996b1be7d6c513b24d876445a950e723ade3efc36907c840b9b8cfdb1503811b4044d931a0009b381fd60a5bf1e73d16348cb57eea672709875fb9d56908dbc729d5d7d322a17a41d0f62c9af9a013ab1e19fb7b6c6e7fa0c0b18bec5e3d3e92546c77e3753193389e5fcdb6a6a1896cba461343e71ef7a156b136b27ae6f45be9368301cfade203e9b53824d70f07de9abfea1968b8ff8489b9804422ba05ac3c3adf23ba0848817fa51febab5e9b5500100310479e710b663f064c1ef101c9a5320367cd8bc6e52081a32f070e7d3fd6f4210cdffdb9fcab1de4af5b06a7c6d191dcc12b25b3053e58952bfd1f723afbf570796946c1df9579ad14ea9c8c30389c1de4d1e845c764fec5eb8faaf4c558c5eb5113018c6a21ef653ac7d7f5b6c7e1a8fd48c6f423e9913436202da176a86731287db7331db055508acc94168888040ee37b3c119c8a0d88360241d68745825fe480324a944d56e7cd0375d4d33a5fe7a3863c2aaa899b2d24f65b70bd804039116fe959c32442c9f0b5470463523eb4336985b71125fe5235cbca0c88a6f92416d038e144de5ff8ef6ca749a9e239f02db505bff8e16fad1cba8b1500445f067a674142b6413e9dc0f432242d8301879bfc11fa86d1ac9992ab12319fea8b703e10a13bfd4b017496222be26b56af3ef67610f904f0ca8a3e7cc249ca8122735a542b289f13922904ff23dd197f8883c7ac77150d7331316ef94e0cf13b6ad95070420513599100b0a6d117640b781c622ed7ef7ead29476b3c835bd9dbda2203930bcee7ac01c3b9c89da405ee436ee652ddcc3e96c7f1a94e200eec9a4a226f3cf7ae5725068916e73b61149497d11dd85157f895669f51978d1bea8fd2afabb18d082365daba2682ef623109988b7d0e27ae57bc14d86603f93b5ac040ae52d8db404ee27e6c34cd4246f40eccf9d3f8637a4615a4006918b01d34709bcbebd02ea72958d54db3e87d69e6d783de2f1841029d6975eb11f9b076c247108797d5368c656f888092b82aa81aa26e164e038b359bd68801c22fc107e4083a9d85fc254b002ece9d4545310b0cb22ec1af04a7ee31d210ede4b605dbdbcb70e4301989422ef46edf63f9c96de9cb3f70638b51df5c0abe79b7af8cd97148f2b7bf394bea0f7bbbf6925f83b901b87a6079f2c3b38a98fe1a86dc7f48bf97553701834f557451df4b41e7db984a34432823585380b45c1b84813d6aa21107cae252923fb4673cf660a541e65610ac0127d238285f53bf329b62169f3e42d5efe268dea62578e97da59a58a1314a1bd46cf7a7cae772814130b51411082e30062fdbda1c9e14d6b2bfff89d0379d32461f3b8e833b105f6a89532ae748b5fb43f283fc86450404e8befb8442b65e338aa0408303a70e9c27a1d923d9f2a06e7c6159c50bf2e3ba5b035420ecbd9d0b5fae478eb1ab72fa714f99d00188bb10e60380fa3a3a318c2d359ea3805c2fa0dde17ee52a504f70d6b466bd38d1dd4196be336a9ab4a9e573d1bc6404018a119f688c1dc2a8ed1433e8a8ebf455ce3808c245f0220f0c12d28c771757763bd111ab829294e2429a6f7a59858dfa1fe0b806e986d40aaff934589fefd75ab91097a979f26bc9352267efb2d82c4738e4e6c451b0d5adc398f546c646b9e6b8fc84e91651a1252d5b805a857c7798d102d1e6f90749252bc53588348ecec0897c79f514442fe3b27608c95d0cba999a7e0fbd7f601689b4dc63ecb9ff553ff12eca3e9b26e3eccbde28770bb6aff7c864ad6be77fc09f81f90df6efd0c4025d0916ab5197ab846dfe6121c462761d9cc87112ebbca197b0a222fd34a15b824b7eda06a56a6ffda760fae5f0b527e2798f01e205a3f47947a4bd190f6abfb1dab2e3a53131af95d593bb57e4f4af506440cf20636d9fccc449d9565bf43dec8b6877337ca5a43900c1dc600c877b290342914e909aad8c5f0755bc25652781535c057ed5ab2ff8ad4322a8edf3fc1b5311dae6361a7395919725f4cd87ce0ccba37c64eb3618f9c5a53644ada569b90cd07184fc048f1b589eb29852909e75e7116ef96a268ea85c2bd257cefdde9222d7eda875a2a3abcd3a02a1fb470ba967b20beb54914b8b0c6ed464ba978088d7f8b30d098966b0bde82a8f1210f5d0c3405c9bc73f703134d0b6ee13326f65fa0b8154f4e30808997d4afbd060285942ca1dededc3410a099881492b5730ab7bdc2a4cfd0068f67766d60b5d4945f121459d2083334ac878d067bef644b9ee427bbbd6c9351d7b019bfc051c05ac301ff3792a1c687546dbf6a07a0cf56717374bfa1191c22b7753f6ae02392f8aac9207d1ad0fcd57c5c8b35817574b7dd90a00cab75f508f8a234eabce6618305f94746cb6a8573389d336bb67e1b0d2b6e9bd3959ef344e1eb245b522c35222813b8c6e82df48987436b5592025e9786ca63b6d1a064223bfacf59ada713c2a3116611393aa8446ea79b3cb21e96d13b659ada2d6524686fd46ec66c1b4d8f5ae7831840c9e3db64d528f83a1cef1e0a586a783f8306cb261ed9c2905493e74d35883fcb39cfc5745c282104cc3ce804999231d13e1bc6f2c022f05999fb57575bbdaf00d7a990e17dd2f8b9dfe66a637b42f58ee49ba60f2dd9718d09d7025b6061b2087bc35f0a8c884f5b67a5e18c2b4e857d3b48b79dc7cab6b72f572d22987566238a7153ed6264578424f1ce091fd05b7f14563fe12c76104d3373367af3ed3aca694a21127b5912c0b7eb1ddf9d4a9f03f660d49f7a7f0fb42797fd112414c3eba2b75a04282dcb9645191fd3dbe376e7f60ab40bb7ca1e991053a1912854a68d7dcf854201d1f2c26c6cfaea32e29d80847e6288274713d2ca973b91dab97884326b280c6f06c65b8fd25d314be29139961051a1d8699467d02b67991baabc9b05629660c243ca3b0477362d5e6bf9eaa33beeb52cf399846c77fcae11a89cbfdb2058e443ddd44fe202a3ba5c2efce937d78b9639781b8b2b99077b433189cf3b0733ed73b59bb194c9a98c5aa0cba6e71d1c5522f193defb9e31fd2cd60f22bedaf7008c2fb0b55a8dd52731dfa2bc69b40f835ae95db040cda6a4a1588a5ba4769edfeb7369c1e9a3b1cda293255b4942881d94d771b7b82460004875e71be64c582f2830c5e80dd6de421a311c5852f4912bea1451b0328d01c7029867cf9af99284cdfc1e1f0aa0d8c19ba9bc035dc270b45724247137da5d3fc4daa09e7014fe1439889968eb23fe124f067825d5f7b304f17a983580e009e0e51630ea0006dbc74a30b512cd9eb4d0b315a0ffdbfb581609ea9661b0007cd234ce43c17c92269a7519bfe99c2ca94b5cd3e7654946e67b37d4270a369266db6804336a446022677a024d44cc02cb04108292dc12f790578a0d61cb6fada738902eed3afdf1850bafcb279f18b5798d7466752c6368a594533baff5dbd17974638ecc41753b184845206c79bbab84dfef148eb7f1390f8cb7346a14c88caf540c241cad11ce8869be3bec85d029ef490fc5edacf94fa962be39a33c8efefcbb6b43960d5bc35f8fb72038af3801466aed141b50e9ac7dcf1921f7a6abaf320ff02ac34bbfac265e05e27495e6e027e673a48a874e6f0c33827a050fa21c2efa789c1e3df2ecda95fc52ca7be35dbf17ff6c73f37cb236e5131542e002913d177ffb21ac450e2542e24b894650007c36c52d90f83731009a7c3239ccf11829cf0fb6510d9924e927f14d6a06f8dc772fc9b028a8bbd2d3388985f3e2609abbd08434c46642b97240c9380a831bbafdc5db77be63a1400cc9a4f7362a689b07a77162022c6ba7a1bb9f0446a0b6b460ebdd9111132694fa5f1b29da39be66c5179849ae9720b2da0a012d4bdfd1b18b8fbef0d5c32b92c351dcf2c599f069c3b53f622fc8e904f27584b2d97d43f779abcde6dc1413c0a677dd187b28cfbcf7fa6316f0967b53977432d45944ce8ebd2e265c0bf6b2870c75ae808fed52aa35421ef55667ecd6f9d279c9b91c9314bd9411bce267d6ad52b1d910b3e65147c3eb6021a0af98707408e66bb11ca5abf5e34b2bc85b144fd06ea56f5d7f8939fe0cfa4862e7f306de069cf85f4aa7aa97c6848594f5a6dbcc718d2af77497f4b9d5ffa217fc301127071e9bc9c2c9222ba90e286506e384f321e622f05d81c114953d0f7e9626b74f4a6bea8cfb86ceb4575e5cf4fb84e9efac8291d1f4153ad3cd9a34ce0ffcfbe30b6829c0f986a4f85d63b602ab99ff3934b1e0c46e55d56eb479b79ca0729beb59aed783e9a3ccd55db8d884733dbd93f9fd7a7209fb92fcc49826b2d4356ca676f01b0981637897b3d2f90f37bfd73b214a398a8e4e2f9e5abec01d8192ca690191255dd8304a2d95a69331288bce00385f462e942f4d694dc3560a263c8ac2b5cd1d2c63b90ec67c32eaf5bd947bd8ac730da9c09ebc6888b0b4f3bead157aa9d31c2802df8ff0e4d69b7abfed6f184bf35a16ffb5677ddfc4682322128932d57fe4c32f21e190e1147d8e673ae407b1dbbca31331310b299e9f3db08ebfd2dad3158562c2e47addcbcc831cef0194ac8ba9778d0103c2955c886d439967bf788eae688f2a7459b0ef3bd16808e8d768b8962a24588d918ceb2cd1cd611b504019f65216beca212f44600cb7fac77216b7645c49f18064a3acdc01399315084dc9ea151ee28534fb31628d190bc540ac6b6aba572ba51aee89544015e6fbca2b3c2330f2ac1f68849e99e1a1f7f523599eaee22720392ea52259e26f1101614d4edae481b3783af4e99082d75dcca549049290731bbadd1ec0a93789ad5c9afe8bae44e35b3e59e562362964",
+ },
+ {
+ "0410d1f8bc890649c250a3819766f4496f339a6384e34acdd72b3a87266edd2a7eae223a372883f978277a108d6e59fca1f35f25d7a9f3aed42d35fa9b12241ac04754f76fd8f0e8ff6af88cd851887a45e89f1c9192ca66bfff605b128575d2ccc9ca3ba1ba23a0251b2cfd6db577b29d17ce2ea998946997f5c4a97a397c46024681a400a54425c071232d269adfc3b1adf15b4586c4dd7b8886f5c1023bc348bc674961ac6e221d914f432c2f06dddcf738227dfcfff88485ed45882809d0e57019461c88683919b87c45e78223c37a5be5f758e4f0dc6add22f2062bc2eb9bdc31b8649af17d526ec339f0e6fc6a41e26299c65276302f982235c3e5205ec1521625ec08a23e766577664b73d18d5533261c859c4cb4346feaf7540a56155c6c3a4874dc86ea42fd518d71221ac65541e2dadd2f8e129e7809f2835f07dfcc4128401dae2b5fac7ced1d9e07e3f348c6cd26f55b3893d4418557a18c366dcd5eadea0dd84ab95437d6f23eb9e5877fb2ad740ee507e2268c39c7186f34e5cee2d0dbba1a940f516a018f23e716a399c317a7a81f89cfabc296c432cba900ad79db67936f76e4d97874fc5f8a9ff84eb7a0f6d629c581ec5c451e27ef1ed468f93bfc68b2e0412a543d89dfdd812d9421236a4be9eb374531556c207340886c7b84d42d651557b952e0982f62c5c383e92dced21905174a5a836acdc3f2393e770d6cdc22c39575a42ea406f36889dc9558aeae5dc5f8b84862850b55bf4accccb6a8ef793d641d6b08235f70ad3b0605eab462afad1af80fa003645f4d302b03d81a7d167e9a8187bee0f76b1cfd7006b2d2b55fedad6e8db1d3ecfe031702dc327ff2b0197337d7542f42702cb276de852b3d72d9acff8a7feb8882028a5e340950e523c41cfa184b3d8878effe56742994e60240e58cbfd01541d39fa007a9f0ecccb409c6cc540354ccf35223677cb74e7ef7330bb60420f7d7bf97de6888cb343cd4fb0928fe5df5f1b018592ccfa7aac6dab57cded573b5950b94fd935f32cf332dd85b2b36501de6687612371dbcfdf77279d647ed8bdcf81fda8b7e0c5ab139330d64695d814fc6f761fd141dfb0c8f74e2d7616db3598d8de40b993fbdd272ca37db27b82aedb08bebc4a8e6d0385ab20fbc20c215ad50fab8e93975bcab3ff38667abb0545b3b3f20e325f01b80a32a3cc3ed51703d4b2826849ee22fddd5b544816599dca0d8fc84feed9f7e90caba53b70bc3f457eb1adb89fd0b67d2c0ab53264430c61d2c4a1b19ea99a9b453fc6b5ebf5fb5ab799134769c9b495c479c828bcc49a8f993c3127d5cbc31afb89c0e78fbc323755457ebf0f3344d3ad1cfc59d186e96ac31a9298e655b3d1df74b95f30fb868631053540388a13d597002f689708d35a2365e309bb96db8b1b94ea4c8060c2b165f7f19e72056409159371ac9c44f6bfaad9b9567094d18c29bbc8aa2c8b5b82735d20f55284fe68186004b4a4fb644fd52d9645b277c1dc238a764005c1d2791ef36e71786cd990ccee4571d9a9b1aec757e479cfa645e320bc33268e05af9cf90e0e616ae7f237c637a99fe15b4ea8a3232262d96855fa248920a28ec03f77ce4dd93925db60ec030a7be455ba9d08edbf6bb717b1a13c3ac1deb9821e21505c0a8971d5ea5dd8e4c9cd3a845a336209af191150ba5d9b8c2c450e3a765e8670d7f846b2461f971fdcd1942704f620a40f4204b99f9035bbd543f64b927cbc7a74f32cbb12c3caef955f169a45374e4479430e08d333c4a877baf41a27a0849ca3a157b6651295fa71ac94b6e3d30b5d160965e93d2a81b4d575cefd264399c9e4e17059f4064465b2d92c96ac27e3b221499b5e642d033992c236b905c072faa1e34495f9890bac6228330e4016c061605bbfc478c30e1b8534c49af54785972aca2d144328b0a540e3b3810a73e26acfa22f48652d53ea521875475ffade8ab50b9f08245fad753350f63dc4e898948ac7dcefe520ca47394f8e993a6d13ff68a2f78cf294f235f5f863bad10c4f5bc41c3ba93cf5e076357f0f7fdc136f34b656b1b8ebb3eed1ac429c7d4edbc902f7f4bc24ea9c9b200b9a9fd7adff0c6445ce1d2171fc031e3e9f8b8d6b448053393c8813d91333d4bdc3bc5bb2b8bff876cd29e8b92cf6f7bc727517b6f57ae031f3040b0637dfb40b8c1fbe44cfb6bb9cd0a445fd9b3daa1da2b1c4a82cb4da1fb8d525e0a4d9ec30e9aa75b951214621c58c1f60c9b97e6c6b330497e7dea790a3cd8158a76d898107ff3a5910707ae60c8a46c633b522aee83736d005de60b9abe202435f8bc4577b0eb08b7f2b617bb5a831e95d6488459bbf15919d764b39684d7cb7c9310f343fbfcfbeeb212a90d96c7a26c1026c5cb171ee4ef839785076e5084026077455c73404a2653f333e9bad555cafc1a9613387a02bb1287c380d7478238bec8943208de585bd18b448b6099565cb3ec70ec6672a778fa6af9d1b17b0970439da24c7bfaa74c85ecd8e5852e42391ab2258024ccf91e37f2f0e86df958b197fafd12f4a45f7990375f1665a14f7f5374ff7740f89677ea8660587fb80916b30629a7aa88213bbf80512421a0a37414a2eb549b81cc85072cdd87e4e69d97ecc63f974e60d20de0233101c3d475d777602b12e2f797e9237570085b0e9f48d4dedf233eb1301ed4621f9736946eadf599bfd79157c0b4cc31bc273f5c6f133a4e3679ff6797d3c9b76aff4bd8ad40726c1703c3d8b78f0974b748d0265b0a75928374f91b48c2d2b2c11d8b6e5efddb75009e4db72e562be59efb0bfa06808c89f585a43d4776ef08947a77f277526777f0b52f1e0b5a03aa560fa45c8f30e584b58ac1fc00b104942b7b86a3cdee1abea349dcaea4e058faeffc567e2c3b03e1c5c4ddc675e25aa15de1442bcf5ee972a8c5204ca5794694759c13a2d716839dda61635043bdf1a09e35cb6d93b4df3b7a00871f79cdb4ee69c79041dd14deb7754107b8fef8589d2d240ac1d8eafc52ea847263512651bbede2fccaf6da816b1b892319817bb6af9fc17078ab6cca95f03cf8426249fd4f2bf91921d39b8cee24af07a52bbe54ca7fc4422a310dbf2149b763ac0060fb2c59154d2cb0da1ad4892279b4e0ce7f5f92c189c3ce48e518ff48c4ffa9bf2b02d4792f84534958dc6bd2914ba010aa32d133f6a07bdbb87a237c7acc3ba5cf101efe947147ed4eb3bfdffe5fefa991c0dc8760586218d286944c52d0f221e0101f74826761d01a20af187f9ec1115e9e98bff6fbd7c8816c15d33c07f51c171490997bf269951218ae92b66fa3150d3bd40336abccb717e18b53e8806fff94009910f202a5041b5396d1c339e6d075bad4ab66a0637d81eed1696e4068024001123204b8371f0bcdf0ce07d79f7c917327f7138a75947846fde68665e9c767fbf96bb3308abffe7a8d05512c81e39fa8dab2334f46ab9543921ca97be31076dc7b2a0d05e90b7f7610d1a391b442398ef56cde3b18737faa8f282572389b4fb3c55cb8ae6737257708c808bc0a414bffae293bc69cba702ce2959e1a30edcdf64985a4b0bcc927c5912f819c71cc9b1ff5d6e5929055be72ea5c8c1a4a591093deb5449b7e6b60109be1ac0cae472ba31e1035ae65f3214f50ad699a077a2de52f7180addde0bd78c2698470b1af13cfbf497d243c9e738c4cdc265356543885c5b933a299f01a5b5a9ecb0b4ddfda0c28573064f6a3f142801795d66bcd5c31868fd3207fee7bd98c47e4da26bee64e1617b20cbaa34e3abbe31126b06d5737fc2b577b19d255a519397f3ff8668d0e7d401a37e368729e4b83c5fbf01c32ec478967605cbc0675f685b5eeeb42fc688216a0667e1204c995c9c485e6f7712d80d88edc9594528b1907790549756dcc8b0d32091f36d2b4009639e68daa130e83a1ea18353ca34f431c548d91c1591ccf8b25eec1f7a3c18ddca71b87bb290a5c13229250c5e193e1352072f6798ec504b3b4c6aa578737332f52baea7bc4468fe6d8dfabb9728cee93fee50c8caa113f5ed7e9b55e21e98d73a377ef68be7e4e965dfa50cf863e6285236f11ce80512c573ae2b55bcb43cf6ebabed6783c250f991f5f68a59dcb2ac13a3c8fba8dbb11c79dc6236809f2d7c4b0ad3cecd24b85f1aaed9748b8c109f2fd98ac8a53bd52f18475598d67305117de8e03b0d988a2847539cc2efad520f86dcd82c08ad4b10e490b9cb03bedc7197bcaca55526cd9c8a5a5f69f7a1697e7e31aa76eee597c386418e89f06b0b9817a83d6cdefaf9594548b33cea1cbb585e55df3d3b66f0b1a88f4b98ea4720f1ef5e6ebe4958078ea0bacb8ad776e325ccb252f81943b9b1c2f54aad3c7baf1bca0dda1355d191f69c5d8163c464898116dc89201032d1e3281c8054882f60522d3a65831bf779a854fb0c195f85aa66522386625658457e74d5c2fcf5234f226da4a579ac1f11f11a1e0a6993a4dfe5c856481ebe9d8d2363401058736f7ad104104aa03f5c91496aaba2fe4072d418d91c2787a9b4ab0cf4bb65681ad0392ef073cf2fc060692b0c0c194c8eed5558098cdfa3317ab02626159e40e5c76fd64b2ef60b8f5f368b6b4fd7ea3d2d3236aa01d9db7c8a01929f9fd38557335b926251ade1a0d47d0c1444e6416218781c1a51e786dbe9297b78fcf0d0304c62929e00744ed4e14af926313a9849b2a464048bead075044bee013cbe318920c4172138560629a0ff4fd229d81bdc7c7fd1086ab17d6efd5b603a1991b33a55ca5b9e2051b7c140f7937adfaf474c2f284489d9b1e8c71d58f126eaa451407eacde9f0e86504f7de3ba4d830199a229de2bf39014baad6dbbc448501588ceb2575db0ddae005b81ba9914bc22b6d600e2c990f7843e553ff29d8008265eba7dac7b5b5a7ba6dc263fe0e262a7b8638a81f4720622c7361554b61d7b04c7f8b133440baeead7d51ac8b77d606fd0eae1c55ce7e8141dfd68d40ae3d8d2dc8a061085b4fb6d8a06263183869154618329be6b01c2890f2b5d0a0f25dcdbbfe2ec3597d79311edb943613fd4b59157df4fc2e1024be03d98ea3cbec7186ea9f4a431dc3743b9f0871b205bc0c1b3a001768",
+ "113b261414b4b7dfa028668ac8b0cde5734120124991c54f4dd16a87d181efe2bc15f6d0caaeaf6ad615f59ec5c2833904a34b4d34109c82e10609b387f995430e8c13d83ac34310d838af9efa32d7fed6224c0a33",
+ "cd762390b93369f1e207eb15deeaeb0036f5331e82480d180f84a76c3e44550b",
+ "e88c14ef96c7768f5dba9de9",
+ "8d6aaa27892a76fb05a2e96cef9a9b4b7ae0670a12cff95f7b076372456889fbd3b9b4fb5fd98b3bd85b247f15009be2f4e7a0329dd118b6872199b314e159618ede0381dd97db28743461ace1a694c0383d8458150a501d6c45f4b50d5b1bd47e61a51f9ed4929bf2e564f201ed0e6825170027d93e482c1ce268459d2f81cab41f0e7ff281430c16b34a29b5c76630dba72ab9e751bae41122b26121d91f2af271a23e818263f46e05fdd52f319d58330bcabf66637a368c0a8aeeb20cad1916d966e5e0b0de74cc67ebe57e3d1fe01e9743d42a931cb4b98bb762ea43ab937d1e5c42eb08fd56e70e911bdcc1ca4ca0604a329c5364b262ce2de282b4732ea657b89300cc7b7127ba4a2d08c13f581f024fd093ac09c2bc245be60c80e102405597fa8082f4d28cc954a93217edffaba3d2a397bb59ee89c8cc0f33eded78f21183bd1acdce64a923dd609a0620d2911f61e81fb2c8ccad8ad9d81157223253a121ea2bc60d6a3670c563fe06bd75688572b3be83cd31dfeac6b17cf8455267b481219c42034b2252977f32b8e6588fb05166498fa37d17c2b002a655b5711bbc21175348225fdcca041b1f97fae48fb1e222c5bb46b5202191c00666b7e1b2d84aca3edbee7a97dc0f6d1330e929226f8a76c155e973c1ab62c867e1f87be37788754e51825ba31af9f4722b5782ef782fbb70c391a664f252d14e49a805e94790135ff6bd881a687f98b42da96fd34bf240eae4914488af739ec15f13f048a7eb5fa94af14e8b6ac5fae714cbef6268b114813ca2a3920a7a9d5eb506a2ca211758de292047eefdb5a97e18530dcd8410495fc42abed91b1204d9b8ba9d6aed11d2d0fa0d931d46f93f2c1a560ef9f5f7cee1497be770d3cb07c534215cec12c1458bb57aab4d95cf4a15a5e3a3bf8e650206d5cac4af3193d169f1a57638d9a50f6b7c6985d42f7138b9226451670d7359351c2affbca65680557693d03458341198b8e13d0ea6abb7496edea3cd4dee2eb93695e668c7c0901c6809b8ef434e88b85a8b22cab6508b9560fae62900056b7c5c29a8c899bed45a2b5159a1d4929476ef350101317f77f02d48a039cf4cf01c56319cbba16fe908c49ed6f3face88867c0ad3703452baa7b86fe58a00ab8f740b4e8055164b0385dd3fa44502ffbb99cdd843bc3287ea468aafe4cc298a3fc180f284dbf78aa09e0a2f7d8593356eab016ad8dc505420edd376b66598a3d0aaa848fd68c4e07419b8b50e40febe2b6b17ad07726fae1f87e86abd01490a0ce24fb57b533c765504ee0a9ca154187bcf5e6828e3addc7597532643cfd992558d63b1acd00e7aa41b9765094217480c08c43f4f0b3f0127120699b7f2a5ac07c655b6143e467777cdad4bc21d4b57da4d8f9b9a7e4523d8c6fba3614b7f7281e80ff0f9004577adcff1b79fe443c80ca9655ecc102d5df6aab2ff6c3401f344b77666c59ac7d5b92bf4f1e2322f74b75e6ef2bf43ad9e018f164ae76a91451e5221bdf5b65a4fbbaa8dc31e6063b451edbbf4965307f8e65bfae87b15f2453083bea8484017228a9cdc6edab1a28834eed8ce07430f776b916b3bdd2340798955ce9ffcf114c3f6a88bcc4c7b6f2e3842426488c340d00f2c4d2d6fd3b6263dcf7a57f5cea6c77efba7013297bd3320accf033acc0833aaa8e8f95cecba469704214f54a1ed581349878a591f9993371f1daf92e55b2a4faf8f952cf785c687a59b3c258daef1b6d7bf9f904123c7384a859933c3ac31e33edf648a1be4d6264ffade860915bd118f0b9aaec2eb8e16b2015fc25e68caac77a3accea53b9b178f6cf48d15029fac12963b4277df037b7a494cb29b1d9e6d2148531a1f7360519cba5657c080254f130a1cc3ccaadb4298d7ea0223897e63d798b4f4909577cf9b491a82de0275a246bb1211bc4144574c8ef176b382262c0e087975cbef33cc616d32e0131a9efdbe8ad3d9cb5f935d3f4f409852acca22ae2a6e7450e9a426ec3b9183f93b4b7f89d850e1c7053c661936e0cde23e831a261b319b430da45772f0fc0113679d06f025983bbf37ecfba35eeca28de5ff4815a490570491266e92faaf8d0ad4ac8df106faff8fe3c8d050ae9dfc03a01ad177c21d7b653509a80369a668a97eaa532dc9867c32aebaf89ed36586e1ebbe1045347766a354a86ec1e8b2f30c8fdfbb6c5d549e7a84db81b73fb828499c5c4be0d4b2b7ffb197133a0ee18abb5a4e371be0ec0a6535507029316f8decde30833ca47493ffcab781d028edfb91c138609baf1054ad52a5d8ccb98b3ca5b138f253d99bd556afd80f71b39f36e0d96fba4e0cbdb18926894968aa825392f12d98b6497ff85a0e4a91c97f37ba1dcad30fe688b54008b925805104a61dc22b712685202ecdb073fad9b10b5b9ee2ff781f23fd41ecdec87f85b369a304b85bd2af126d08f79d8a9e2bff0b18607a95c4efe35941c5493c94e3f2f3902e79f4cfe84c138b83c7f32d7c5a125b28c6107921e8ac92f1af7da015b46a2f9169369cede770292eee8a5f40d080ea1c267c33cb7d4187093d486dc3911bb2d6cae036cb508e81ca783ab5e95cec751e39f3038003081a252eefa7cd913baf136d4e27076251da9cbf0c7d2586fe02b62ec786790ef08fb3ff3d79bd06868eb1abd9875920e14fccf6dc144e898f578b7295fb5f4e84cbf683722ce3597aafe3195e194736fc317ed03ebbb00d956ce89f7a41a334020e1a88da355d3b47d5bd3965a290f6fbf5dfdc8c8e6347b4eb85151e53a960311582235f3b546ca80a670dcb628fef572dfae0c101bc08c80f78d5630a793bdfe402592c316227f2333b386839a67e6ee8d9396fabc9648ea656a407670efaf80966034958f4a70fe7b920c79dea3d5a0ff05f3ed0516537d51a686efcb258520936fdd415345251c9ac1143a41be295cf12da5d4319e78e1c57ce20507490e5213ca7be92afca8ec8b6a07b33571afe6940daa2afb0dd4dcc1c329474ff8e13d740488e5ced552074fff695a04fc1b70755245895a1e9c387fd9514261dbb0f600ae03f4896e795d1e72f421d8572543243d662f6811eb9402b6a3b8dbb0f32de95bb1ac01b1287663d3b6a3f52339a4f6b27789e15519b2b59f2f4fc8fd33ad1a6e4d02cf0ddf8499f45746da424ee78e72847e3cd3833551b6e6fd6b1aa98c688252b57a1d97660ff006ea1b970a0b8fc7d2e313ffd0b0b85299ded47b60cd2fe9bdd7ebace4b0c1072cdf67231a475045990b35ec761e1dc1dfbd0c402296566eb4b9462979d33c9d652a9295ae70943f38adb212b48bd8ebe82722b1712ab6a3be6060297e2aa54e7d0158e4aba6975237e7c7a1e22b29560b8d262125ff2a6e5c1332acd0f6b5ba15b4a82d3631891a01530321830aa8f2e8ab6b41bc5b5356957a4d0c3bc3eab04df7700305a95d0f9cd18d486c675c963876b25b1a0f78e245deb40dedd14dafdaa9d614fb06eb2538c5411e13be116c76fbd3377ff212eb07c5c035612e4cd7a1de2ceafe95832eff88a9bdb3595cc19287fa40b8d244afe9bd24dca40db49893602a59640d7a1b8e7475825b09cb0cee111864deba9d3d1beac03664279910accb9fac534ef099e398d7f6e3235cef7685fd1ae46e47da093135741894273c0c3486197c26057044b10faa57244721328b47e611633d16d3e4776d90309d68ce4a60d3ecda26c9f39c1c6da67ff79fde4977efc5653d79ad86c3b53090003bb72e78aeedcf4c8107185d9aa65221df4e2104640a1a083845c01000370371fea2a6bc8ae43fbe290949da4e559d3867c16df16b143fdc807616f51ebce8d05bb03c2b0bd587b95e3f6a15d907aa9a5b11622ddf4c81ff9fda4bb49d3e9577551bae649cf64ac0cfd646b02f6f16cdefde09a55e77afd16c74e8a3d777d80b7cc42c51f618a3c467968631119f11ca4385f0f5713e37ab1133b692de475db1d44fbfe9d274b9a09e673dac88aea74ba88cde8db3c831e9b5a0f1e40261281e5aea9d4dfd48c5d9e173f4d9cd56fe7fd610909c838bcbe1d6c729e151ecb4caef511a36a14b03cca7ec5d0feacb4647ea5212a11d18cbcbedf78443127680ac0b1bb65120b4197570288226830e2a92b380e32387bbcd3be2c77d6c7722054d849be9de459cc1832ec3ac8e7f60fba9c81cf5fbad37d228eba137a23227d56cd24970340f2b7599aada9d2424cdba8b50c2b97244dc83f7391e2ceba5bc0a11ba547c142126c791265b33a3db6238321a5f3273ffb01e42adee17b898153e41818b91413ec4f6386ab3dd48db875afe659db9eac94d16f850ac179d087d93784d607349e8711f5f96fd514e8d096de8b4a74122ba914520e93a11fa4adf006700e122e2531e1f39340cccbab4862708d69c117d3efbebabc14a0231916ae1ee8285727c9fc980051360346d53dfc76aa5a11fb1fc8f36f95f741e913bd2cd1031e508b320abd2d3a62baa400dc439969eb44e6abf8223b29d4025c3d1ca08d2dbdbbf9927c625270543e8c0cb5ac5bb5d504d224e66a1895719e4f975d819a95e54cecfa59ec8e385aaacbb023772fdddbe093afaf5a75e63a62d51926254e5b47da1e9b05851196644b9180734d05810dcf3502747c4ece652b67674c02aae74f20d07de2ad5993b3a68d10207eab6be5be34e52ada655aa96c1d82df9b24c2acec35e8f0bec9131c20d0ad8936880af87215611b80d07d7a741a12d8145bd05066c6ac171afd8684b92f72237bb0e4ca4aec1ec280e39f36928852d5d8d02fe463acbad8ecefc103083fd4298f399bb254e7bfa166638460b760ccf2b0f5fec0e3875206bdc8ce096274643824acfad71ba06441c74788356caebdd2208f6f077b056fa9d85aa4357e93bf064a776f5f3b0f288d0afdc51558c8f25cbee17247364c2bb24637dd69017f92bbb43024d9c773439626a02bd0cd44136a642c9c5ae593f32eada790c31a6704030f2e07f1173cbc0dabc410bf9864214c298a6283b3631acbf94b8371681ba81eed1aa81ccf258252d7f90fe733ac770b9744d0170cb554b39e6c72e05919cc237f8f4d7f3545f4d2732f4c9473c77401dcba04c0fd33efc73219f31c08dfab26abee9a7cd4ad3584730768fae899fc",
+ },
+ {
+ "9c73ac05648e0c50a3ea3a8eea70841e8e06669c1e7520c5e25e093769c4b005375c0a9cea16ec8e00261ceb96a00924a66fc0c4e4e089c63e93fea857aead8e0ab82af4ce1682cf3c9fbad23fc3f7e632b7aa169834ddd6c7db7e1e892cac93e4d787b2ed0a812aa93bfce8fef3ce30ab794743ad241974ff989288c43e1ba815a25a03acdc2d5517293e161d0c46c8858d0b32b124a6b0bc3838807753288cf6838fa25fbcf876e6368c0342d3cbc860d6fa12faa1c2b7d9fb37504e60dd44e36ce74229dfb80f1545125718dd1f78b31a8aadbb4d6494489ce596fcc2dbdf2ec22157a1d966b61e780d36552daf084739b602861a96ceb67b65b23d40916c02b2c3a38c2a59aaa266e1f8939000dac9b6dc50d1731e87ee833a2cc3cb98c57e5b680a85c1b428289520bb252096efd7723fa8e55d2fd4e16900a435986ab3f3d2bd799471a1bc07c1772ce10d1bb8805a6065b8903999f9393d2ed1a7e1c57a9e3e0e10dfca17a04143814f5f3acfb99a34712a6e0a24a7485279ef343e69d27c77e25b41f9fb833d7cd29cb6a15551d5c77b43d19feb19f2640926a272f81eeadb792bd474ae11f080ada72103f8f7ca733a9b1325b50589be2b2b3023491afec246d336f4e4277592ce9695c68d5f39c8fa4cedaf51776d7ca29ea0ecb89eaefe71e5f3560c68e8dafe7da08cdcd954d626418677b8f3f45b9194474a32f548a4da3bfae6a3e2c0a25f602e3b3a821160c397d77c8bcbd71c5f1e669213af36eeea30d48e12953071f55eac2fe0bd8fa355671fe032f6fc9214632428125a16fc8aea8a9c7fba0d7518b9a4f876349ccb9bbbabcdb2a85fc60b83ee1ddd041967efa4036e5e10e377c9886f40bc0b0b57c7b724795f843f6a072e87e532a04c21445090a360731a2afb896ab795750e5c2c33d58bb714f5be427ca3751df09661402604a09a1eca95a8344d3daa5b99d68e6e6245825704c5d4a73af197d052d7f75778917542261d77735a21cff3f75d6159a3e4b1a7a9854ee376e6b3c8bdaa1f353b957862b2efd50d10a40007026261a546124cef979ad20d8085d53e30f5736b8aebcd3cdaa349ea474af249ac53eef2653ae1fcd5b3095538de9368d307d45df2a19acd44e3b78c2da9d5d9fcc4cb61feac5dd35f66299845bc0018c3d476b6761083baf33a4621e41cfae0e0c642de729fb2d206db6a4b976a635b3fd911b5e9946fddceb6feb2d2f893b2bed590317442037a1d6dc5b5d72910160221cbecb53bc983f1c736c3bfc9757e9e05af1248b28d651f521af67b2a0d7e4bd86a0013338404fabac7b9833c372142e6338a98c0efb7130aae8e34bb0c80937680a7a904aba3be735d41af9462f17b967b13566bcb697579f8a9340429c77baa6e24ae1ac86d8d25ae3cb9112e34a7a948fd141367898c5f33c0635c87de06f603b510cb229df0d0d9a9e107de88b12686c539ed4fc54c8285afde0c8ee502919a125cbcaf4c8c89f56e90d3f641f97c07326956f7b5d87c65b689f39b8b84359ee0f14d2c7ed621ec67f5e2a8ee5faf21c805187edd95e3941ed62fa95a65473a569566d46b87c0d27ca37b6b022a8cca30a4480d392ba15701d1015b3648958cddfb614983211bffc4966ac6c1f691f19bd9fed405a02c06712d62a775f73353f3949c76b6b7757a4ee0410fd6d20071abfe46b09e72b70f9f19b61410ea67037e037934bbefaf09cff018a5c218176d165d1eb5cfd5c46eee7b82fe65ea02e3ed7b18a86ac7b139b7c9df79e1f6e6f85304ad22d97190c7ec12c651fcc835ea434d92ae1444e7cb0dc644efbc2ae70f2f94310805c1d0f2d49643d05e78baa1c54d4fd99137a49efde88dba1374c94208fb4a0ebc1a0090b043610ebc1bb08168ff5bf936ff9834e825eefb9ab73da2b287b06fa2b0ff52f46061b07c1131e4108cde478c767b749b696f3520acd8d3338842d53941282da289dd1e9a0e02aa9be0f127566c9bf2d50a27f6b6ffc9e9880bbfc14ce7eeee70cb0c0ad90fb474efa69b46123638e8405fdef65fa7e0e7b29fa8fe8696edf661f9003a08b4aff85a4a3e6d817655c1d533b834da981b8c37c38abd5977b3ba71b3f57967a471c2eeaf2f6f258431fbb7e92f91814b1db80ea775681f282290db170942bb7b04aa2a331950b74a4b6e337affb4c51c6cd4c4e13ce3095e73e4767c2731f72bdb225ff572163fbd8573378427fda194d165750d487f6bbb63e1378a132fb6ee5115e3c32b2380b096b735bdb4d651853bc7928346fe3ea9df7534f2a4eae1f5ffc4b82ae738db7df0103ba4e68c2a2153bca499bae2439a57778cfc616df16032aa8a19e26597d275d2775b5ea17cb25d204b18028eb25a053e5666ac47c6def151f7d4b68ea62c601d87bfbe04711c24bc34274be6815024d7b7d01e7dae10cea6e485348ab195a83854663cc5826181b688cc9c091dc1e0d491fe51400e20e6f2a51a7d56af258e038bcbc80e2c4ac4b41661bd33229d07b39b59f3aa79d99c1ef41974a33e02a7cacd6fd8f9b99cadd0fd6a031f070bd3a364c64ddda0e9fb94036f374171de0b3f4ee3380780e6d77d50db9d58e670fb4a364827d631226a3491a27602808141ce657ad6e560ad62b088ff086e6f03b8a64bdf7c7d01e7b19289279509a9d6d80e50aef3b05b5561e4556952c46d0b6ab8eae735eccee77e570e1360b7ea38c53ae6b8eb420e4c2663b57827228392db6e79105a47f7d89e06ecfebdd63783101d3bfb5f494785acfdfed41f8166faefdf0b49260222c4080ec2c6e4f949f41784f076ce37fc7a34fa4e547bb44e6b9359b4b95cd67d64e4402ac83973bd50f8adc7c6e4c34019bd8f6d3843bba3d7155890712e0ed5134e00db877398d86b459f312a6272431f01b057446bfb1b8053acf181bac79408c7708f3a0867a64e06d7786849bb874a6bdf8fd6daaa572d5648ae100f4318d6b3a811bb0fb709168e817ed83c0622a7e5b17ebf5cd5ecb21d9ac32ddddb039083144c93cb55a95ad72732132d54bb120639d1620ebd142b58d75835b35cc6367012c93c6772963e9ac852c71c0dda2246ab845469997fc170d8f62334bc5aa4ce23e036967674303ec6f75bd3d17d197d026de69beda70bc59d2ff95a899d28ac7e5e42f4d37233996a8e6d3b0b86b80df49ea8e145b4a6e3e39f3d6c3c6518bac45baf97cde23037709d737b242b8918ca31f90fe59ff2c83e2f347a954d3559a8e4f075c620ad36be20b1e24b3afa156cf3255192171ad0474e4adc9b7f35436325b92945665f038611e5d14bdfe7b7d20c09642323346a717f460dfe7b5062a0098be66febe9f5fccfc747aeaeff81ba08e5dd2b1a489c998ea9970afaf9aa03859073707a686c492fb3f7ddb27897ba5e75e578bd82114b2ba85525a2002927909c970a04035334b64b1169c3a923211e0999db8baa26b6537cdcf57c051c0ca1b317a5b66ad96cb5ebd57994f99ab202348d8ddeb343312f1f26ab2442b8c5f5cf6bab394418ef2fed68c3e60275e836027515b6b946e5d86d91fdaf49c2a5182d5051726840a156a8653cabda25e1dd9af693533d782caa09295952ebfe6a194fbc8bb7fc2c0da5914a506c6f31490928dc5d6554890f5eb268b09d671bb6b6d7416dd36e7b78ffc5c86b34fab43d22909a87e5239643d5fef373650e291be56b89b9d90431d8c9fa44fdf4f83a1689d59d6ef833b1ce31a44197b36ab298d53b51ae3f8387087dcb0571c340874c1524ba0d576bdb88101c1fc387d25b5c0dad0b4d309255ad5d5b1e209ba56db0c927bd209399a8a3b5c8663c9ac199a76ea4f49e364a4b93a569b3400e20f0d748adf7db46a07efc68e43802a5d1a914759eb2abe8fe3e8d67f2cd7612bd4d5a6a4535b1e5b3ad4d97e54f3db7f8512c9603d87e01160b6908d8df1b952c750071abb1565e5ea3f643f233faeb84278187ff0089150bf21ee4d13979fdae796f592ac5b88869aecc5be1c64665edc8ececc87502d36720b73859313607aaa561d56a195dd3c7292fa8f0750ddd3df9ca056fccd9d6ec900f45c1454c6ceaad4154c69e288dc85735b8cc42950a3c5f0fab2be8811779905c3ad5a9a6bf56e7141d863caa4e93e0065f229b695efb790926618b3eda1b9a15f143bbb09aa3c4b72900617793417df364185cc213d5cc3a375778117212266356e214f085d8a7aed908256c4aa25faebabc70ce913c08c89380da06920069e8e27dd867567f152f883a9bd2dcfb8097b7f065482d6d11c0edebc67feb3068cead403503c04b324885ce1a62c99af9808a5ec8b7cbd978b8c43e37b06e9f7e1ce0b31fa0fe52e8842002e6e99cdf69263d31de080b56c0cf94f77f0397fd1f77b13e17af90ff33b00119999df802c33534a13d3ff7fd0e8cf58e8f8c8bae033cec1aec7d191f2d1a39c7b731c97a67fd1ca43c13a24b9f97d92e2364dc26a1c9408d4659ac7373e53a2a1704a47e01c0223ed4c489735b62a27ec67ea46747e4f48d3da101b0863bda9d3f7f1b413f3e7f130208875e6a29dc30a78198ef658c7ca32d7d53b4b92e51f8ad6d39ecabb800adc0870b2ab0e85b5769f346ce7fc371ad40c561f9f3b2f2a01f2b8ccae48c78a41383cfc36b2a1bd41d61a39c24144965d9aa5ecc5d506c7c7cf9476085bf049942d35caefd77821ad925b7fd3a006213abc1e008114c848d45cbedcb8af264cdc5c07bc338fddd1123940e5d95717040325048439dccd1e298bead22b011ef76d26a390a68161b8bab29e8409a5880cca9c8104694e1282c9fd64f50e73ec6b9a9ffc31115de9cc0088400a2dc806f85487fcbdd60f409ffca584fb197156b40142e512a0dedea1571ebb74d6b26d3b4a59e9105929a055cf3540e8a6a79ca7ea71ba8b40893c9797e81c6e9a7999d4d382e52cac95727bcac354616ae1094552b3d0a33d0d3ac4e547237fc0cd54944039b0eccf335889f6aceb518de496e0986783c564be8a4a05bdc9c67b1e5abb480b98173ef091259d8c772b611e0c09758fceea3e59243406edfa71fc452d4450b55b8fa5ecb543692c6eda3a6ad3bfea929a18ebbe5ce2ac4754989c71dced37286cdd1512107e4e7f4878da1c28b4beb2dd9a712a8d1d61d1a5fe5382db8aab4857b05a783e98e77711c1933a7641fd43dc6e6e597bd03b11ce8e94aa094fe250f03cc92ed5b0a5e7723911e87b0f3c476d9aa0d96adbfb395a8fd353cfb5a4cfe27deeb82e849f90bdb17928b0a5702e4010f7aaece2d43772a78b325d2ff24f9de0f7bc65974d2348c64",
+ "bf96bbc17abcd1f56a9f22ad164d25ca72f8c996f1a7a66d6effe140336da4f20460b47e1c8573872496343be35a055552ceec437692b0e4919224c4ffc8b603286a8245eff5cc148b004f6e5a54c4ac22b0f09842a07cd332a09732694d3591b8b7d6a7ada2bb38a30aa7fd5e6baa811b9a195d3a96306d",
+ "aa2f714d3a184a9883f4199e8e33fbc9c92b36fff2d59f07a9d0d335d7476e81",
+ "36c79f9f14d431cc8c077439",
+ "873d0617c986dc9d83e9cdfc50b1f916626a9d9e1c595dc7ccd99d1e993d25d89b04a893c89e205952eef8f1733054bbb55fa5e1b07135787d4fcfae226737b50cafa2c11276e8708451be9b4d7f662e98ef6b705c5c4fc64588728eab1dfee22a0a92bae61828a7394977b0ae8a3b6d0126a23583fec025becf0a72a28891391ac1495732a7a4a1d43a63ed8eb37b280b6d886096fbc4f77aadbc5e441e996334d0e10cd7f3dbba9bb7efb147297986509a07735385c681e0543186dc166291edc3b4664f5c8ffb0965c85bc30ff5e7769a69609c69ebb68f35d104bafe3dbd3e2a40e13865f19bca3612e48592aa930eaee29440b4ebc1c0a59f1c54519857c929709b086bfddd6d4a30940b592be48e0067976099efe71f45f956182dbb300e8076e1207baa32d59c1afef7f34171bd66099d2d7f07b39d16d0f8b085185bf2554c6ad66bcd656f07979e8f19575a116f5c4fb9700ec3b46a3254f28afa1ed51348c1af6dba26fd398098a76d7bfa2ff195eebab41330ef290bf75205a2ee570a2fa46bbaa74aa6ba68a0e63e2731dc1974eb44794f3c89ba58cf96f7a070fcca678185711d97cd9d7d8202351ed589e0b05a7a190e60ae4aa109254a7bcf7013f8addd07a64145e21226795ff7c7b1c225f40ed7c3552da8eb18b9bc9bc70c2e7ecb10c8b20c54f04b6e27b5044a7a67b558407eb330f2083444375c022565c45fe817dc00c7d24c23db320d15949b0b64fbbaedd310e73e423fcebe6e1e98a5cd232d97e6466642e5e3b23f06525ac1cdf8688650cd366b1b7ba2a9033e62d836b14bb73717757b76b9673671bd3d3b2a56628f5a309f3b86ad32abac0590c50f7c5a22e0a920d88dc9fbcb3add08b900a2a2fae4178aa100a0e645ab428e0e79bd90baf4af2755e48262b64838a6fbc21226e323c0a1ba5703e30738fc7b5a7df9eabec6199df5ff6ad58f9df5a734ccd6509e53ecb3de1c881732e26e52ab848a0335b04b25f2254aaf8c130c78b0c9a40b60d402673ac7ec7311d0b00c45bd176bc73ad81c2478611804f59e3c145110aacce922e473ef346f8acaabdbb9f313dd3f8d0a937d0c048e5af789e2e09a816146f9ea28170909caf2572a2f6e2d0d511242909de2815e9ec586b2d12183ddbeb7dd70f32424097e2ec28b4ba62cf78f547e2057a4c050cccdf6b582172343742ec8c85e2847efb1595bccf89ece3b3ebba824d2f097b1987ec26c6e5710544739d54a714060fa91b7995cff0161415eaf55758078772c0271d9d282354e47a25b673eb11497a6ed8db82267d65ad47412300ed525af96f943c5336b1de88676dc346e7339230032463d305b0442f934018bdf0242768511d20474c6ecc82fd752c0c0ca5cee1f3e06e679fa5835540f97870d47ccc6bab233290be7a3bbd4a73f1dc7682049bf7b3cbfb6687479c18d246e3c07161df5c889ee95d39cccd989625a8c9e80f951f8b1832f6378e05daa8566477d7fe547e49ae6e822a68de4df9fc4d6500d5219c3d3bd8887bd7f695151ba378da17c2e750399f7482973510a386721c59683a86003edb9f0ce1ea89bd7bb8a25c222df7ebedcc1b56c8ce18f367b2cae720e0591b477f6ffb498c3d7ce59cabb1b01d7cba84d7180b4b2a165d4b889a6ac361720e768f2913aa50b0b5c88e55c35bb4df4fbc4460338809605f1fd445a2bcd97ec1d2f269b5e779a18c8f215bbc5555c745424484ee5436119eb8754f5e9e91f51fe715353596baa1fbb0a690e99691636e6027cbd4b7be752bc278661e2677070ddc12dccc262d3dd47160345de51359ee8dcf2f61044f95dfdaf323881b2bbff68af6572348f786f6e52d1309cff871ad58148307d7eaedc93ef037922b6092ac62171433adc4934884efdee3052ebd60ee115f76f9dbd0eab7c4c0a77b4ce8078209d23d81d957335f331965b556ebd54732327b5aacc899f9ed0edacad9eb98cb845867f249efb0e1a5fa2483227f78decbf7f1f32d060ab0c01eb985d83920b2cc24b5f9a0d5d869e980129d3b78277fb87e5cda61e340a729d86b6617b8828dffc7c37d4c38080ef3515c2784935973dd184e0a8160f84bb78bcd8a5e691760be4a4d41ed6512ee436ce24650c0e17e7d74b5e01cc39b21e21514a84db262d673f24a82cfd5dfe2a162976171c538b24af16429bf8ed5fa8e37f89ec6e7d63ea1d83ac1087cf89e8f43161f225108889e922493d973e36b510074533cb1cb22174d21c4076959e4191a5df880a8b868b95a9cb5151a7ad47375fcd87725660cc0b59c88ceb86984941268493c49b8aa2baa8c531ecf497853ffc3d26b926a379e72188e246d42073041fbca453bd558f328881c8f8d9e099e898a912530c4be499f2b32229c359ea10e0befe6d94cba5ddafe51d164898166e890b22fd1eebd5724451511dce1f8f7431d712a3f1e50fa5f609da686253311af255b84b2106b09b803e94b51729cfa0826869945d46b9606547e7e33fd9961cf15b400d0f5e01d8fd4d92a83ae526934059d4514b9e0005317a70466aa0b6086d5fcfed201d958a0de55fd23f0919ea29b8aa02440031a9fc206b9feef362a73430a4204869354ec81b6fff92eca97e7f1bb12d25228eae466b8137b4806895ce34b57dc14bdcd107fe160776b0e5daab150ba06976eb884eaa574da393af4de355381c7caa4f611a2ee70a0c78df93a4276f55e6281997b4aeb36888a6d9638cc95444047e5202f41f8bdd787f1ff44a648cc7d39f05e49e5d6989fedb194c526780709763da81a780db0d1534a466cce57e11dd3a4c0e273d9873af1040d52a90e20101e1f80ef296d45769d204cd5417a84e022b6b336675d36d9cbdb16b0cbb08f5e240012967c8067c92f97f981cd19d449084400d76adfb7c610abb73bf21e161db04debe6665fca79d71c8cc50adc3ecf0e52d07773478ca97b8e9821a5704dc58acc647a5bc618d2b681f17942c46c266c73ec211ca403a7d47e42e12c775b370cd500d70a4aac7124f5f6d2d4ca78e1c17a96426c326bb60379ceb0c84a86200f3b450e5e9aaa11f45440f5260eee7675a8b9c47fbc58cf18a651a1dc7b39a911442504f12c103054bb50f15381e512dc6e3af7b414b3db26fe767d83a2a53d7181fec8f6b196c7874befd6628b31797ee3c9260c7b7853b137893e36696e2a47277add98462ea9a0edeb7d2d3c0f2805fd7db64c2c7eff353ff2b36f4de862a42779ffd4dbe77b6a79bc9f4ea3e909474ead915fa3fa990bc82b83a670b163e79300b627fb91c4502e96bb9dde00f716ae6ad14dac647c9f7c2e5b2e505708b5fee996b8e9113a8f4f2caaf414061ee72e76b8bf47ec4f781bd7c589adebc2c267448247e30d659998d8037783494a1fdadcc819d7ad7ea2674f75e10639c3d3055046a00814ddda0e463185454a4455d60b9780250183d591c3db6f27373cd2ce4f02f206ae10a8c32d71226e7cb8d5b05909445977164983c0073434d6c0f2bb62bda66a16792d6e53a49ccb5ac3e285a6baba935f30e9d1ddb812a018ce04f29e2009ad678ba72b6a7112d6e7cfcd3ee7b058ec954a6fd7fd01018a6eba6209687c3130de58147b07bcfa02ec1caf30b59daf87db4618b4a5fad34cbc8014a7529b9458e05eccb9a77ef1621aa95513c6fa4003b0877ffa6d48805e7867dcf53447caf348228ce926233f65d553146584d6ff3dc3ed3296db9bfe69dec6a07add13037b3aade118b2ac3c52350b9691a6cb32356ad93377059fb8ceab68de38d96876d6d383db01f3cf620e47cbfd471bf6dd1f601210482f7c3bdd4c3bd37dd0a7507e1f0fe515151634813dd4ecefe97b52eda28e7a7129993b0af311abd3a07bc463f3cbbcb4fb0eb265a5835663fdbab0d8b8b5a73837ac98ced6582348fdeb41ac8ea9e36f9818ab9c0a41bac1389a6b518ea17df043dd50550f32471645791bf59855ed695b84919aa5cb688e569122786660f06e3a919ef9cf18c355bb397b86710c367362cddb0239aa1d32d489328e4bf92b3abdc3d0dacd76ef1a1efa28fdb848e708aed6780e2d8efb19a2e26fea56b4440dc3eafd796896d73fd150bbd967871f5e6ee5db58995f2f85cc2a15077d7d472bec2e30430af6891193ef03dfc7761e2b3b3b54a72d4f1084a8fc541526fdeb0633dcba14e9485b43065aee8750397ea88d9ff13417149e0fa145be666e6f4afdabe7ad8e4864e777c20ee7a2842db44dedee22f3ce2f97d72919b9ff6059352083be816a7515c48c5140a99af8e81b9e18b10074dc73dab55fae66261421629c8e323d8134f08beefbda555660a51e4b55a9ba4573bdf0396cc413145a941c4175aa672586f7676027f9fe211db87fe07a23962f5b1ad8f566f0d5b13c5146457276f307a02e1e13d00c5032a06d225248215e4bc4be1b672f1eaff16ca95da42513fc4315c7a6663f9101aba80224acbf0c87fd3a2ee9dedd1808c1247c5bebf3cb8d77377a508ddb484ed91203a438ef5ed3ca14e087102bc5f3828d8c3437ecf5c92eeec0331ed93ae33520740abae9b7bfc45f097da70adbb9b9b879e46a7d655dbf75d89773f737b66fd8a8c13506cff7b44bd85dee279ea7053f3ed8447fe79c400cf23726fae800449d27af5e342ecf776378e2eb449a3af27a40fe4a9806487b81c942bfe1a4b0fc146c971a13f83669e0189e337cc9fa2024864436189a9165ade6b864698ecb797ea05fed0d60f0ab4b92cbae36c72ccb5aa45337cc02dd086afed9e5522ecdb75ccf389fcd63c5a4abbf60908e39cb3268c76a08687588be67a856a841eeaaee8ed016f6640ef0f5acce12ab8bb58dda380696e3fb22d0bae0788c4fb79d00cfa5ae3e479dcf7d08b45f4592c2d2a7f8081d5a9398659613ba4932ebfd7382d516b2648ec4ff4477648069b9b2e4decc89547c16ab82a0ad9cf293fee5adb17cea4c95ab7b8e386dcae6acac63ad0d1d13656dfd97d5623dbe45230de597751321bbe5a03c879c303fd7a0d837d48141decb6df4f0865717628c85dbfda29df9a8a69b2c956c75fc66e45c08960c23bbbc706e48395057f989dfe675305067b3ed8d046db339e504d5b2bc978ab4dc261d8afb325c5e794ec79d63d8db53f9dd24b623fbcc202679fae8f7d39f7f7e0667b142c714b6a723996e5254ad2ebafd63c3577f8909981ce6b3eb1a6ad67a4e93c45ac3b34587d153ec5ab67a2697a9741610d5a176cb9b5856bdccb98f69421061c84811dd6660495d9f30548efaa69e36ead246d997c95bad0ca3fdc1a08b4be31b12daf211d3e29d585cdac48af8f2268ec304bb35d",
+ },
+ {
+ "ceb1f819497c0d631a9c9616655f419b5e3470fd3b19cd0e4fa556bd26cd9df57e960ec7121b2a2cb7c0421c1f84b77eb8277bf341490190ee574d1424eb09a281176a933394bfea5502077486bef23ee66e3127b732b7a58a04b9aeefc35170dabb030d4fc3f8a4c5ff194bbd0b89a379baca30ec81d576868f25755276e62c31e93a80ac322571313ebcee494592c3ff5cf3ecdec962645887d9aafdbfd62ea910af5542d4c7731283625bc9f41ec85012b42edb1792339e6cdd9c2bb3cad4c4792a064df17a5f74dcbb3dd0d90620ebba4fc6d1e1f9704dd60c798ad64d4e5077549d68cefdddaab81a7a91209b7ddbea43accb3d1c191328929dffdfeb4f5740ecbf0ee99cb9a1b73333d7ceb0b2b8f35f84307b9d44a42fe1a30ecdf2650dde251bc8c1d46978089c50d64c028f40611370ddb0b481df9624ed63165370f4788bbc396026b268c2023e0f04cd4f66e0bf439074c46f0ae85d6dfeb0ddf22868af61c8d5133097156fa61a3cf5801db5c3ad29871d336f7aa06d2a7d5f52e50eb3aee3c7de7bdc4d21f68a1776a7cc3954f5c071282febc89c1545fc672a0a1bd8eee2b769be048ab58ea12b356d658a6225fb8a55e752f1fc97ed64c2f87f9ae661514f1f56d9d4e47b001ae865a44b8a9fd5df8628d183bfbee781b6661c9cc76debe6c3c5bba840bbc228206673aa05498a8c715b0f3019f6b2d05cce6c233b5809ff1dc4a75d7f69859fcff94ad442d460b32f6fe348659518c16385e49fddee9efab2455732aedcd17dd51b5117efb2ca1e21ae6787437f48a7042d46e11be4dbcd2932ffd70fd154e4eca5fcdc57c6fa79746100b8e1485fe575a5c79089a25eb2d55d89e42eddc81b82c4f7da8bf153ff5353b7349b161911bbe0a14483fff6585d7f3c8b5c04a6dfc99db9548f0c53e25f0b16fa212f0bdd10ad2193ac18eb09972795f42b3bd3f4d98c4868989c4af7a760f1c88ffda59faac73256df1d607644f56a70303d6409c9ad716149bb58f01b4ab8ab475e4af1257d47049aa77adf9ce54fcd22b3d6ec60484da903a6991ff052ca37b01428d5916fd92c17530bb3385a805b0d57476e9f9417a23ab1c12a038b61b3a0898831f9615d10b468c3edc24448d09b8f3e3a2355dc5e069e880929eabcc97344fb6ca5587c5ac1404783848f531f1e915941e7359fedd328f7fd12b3c685f8c1f29d1a6ef7dbae3e5e32cdb251eb43aa2d2ae0cc18b3f40fb006c2778cba387e5852ec4f2d9b8e8ccd5b3e1f4781c974aca940c45d35d30d3b9584c750bd45a80f32f73dcd85c99ae107b92888839c342cdcf88911cb974d611b14b1d85a59e88c502559d6eef3b7f5addf7d307bb25c57aae669767db6d798ca887124e159b0317e09076cfdbe61aa9ddeda189036703b1cd9b1998f88325910a37ef1fc2e227a382ae635e847df8625b99eb6ef0ef10ce7a2a5762ad7d03a7a4e2b767c4df0b477d6e9601dc8e6438184f97193ea7d7a8c22f1b6fac1f0740f1beb8b68db40e0b22940cff2261273aa0be43df561b88184a9377e6a27f27942dd04abb9448b6b6ecb3a60f14dd39b58b8d94e1991cf9d3a071ba42e0e1d71eb211ca466a70fd4724a34639707feefbfd73dd9680d76a214924642a063b38b85cf30eb763fbfe889f34b20fa4a10ba214d938a5a092c6e9b73b13bd664c75b34f746aa360593c0f8dee0f328f0ad4a3e40d498490007e573b8204a1ce7a550deecfb15f18ed5ea6cb5dd95a68adfe4cab37c13b383f8273b1971580016a8df02a3f4f431c9de9e7ebb33244512080fc5852278081b9f4434109c3427441329e8071d19d0fbb74fb6ea73fbfc7c0ac1012d3a0948d94d7ceae9b0112ec43a16cb582f9c53e7eb0ad15e05ceda108fdb3dc9e585a332018d1cb19e4a75d86041308fdd8476c88e4826931601a3a5dce06fc16512f4669f10183d5a8d15bace4649abcac07358089aeb1e9b8fc3776f3239d5442d3be33d532097e13651af7c9a5b465ace9e626889800318447b8876b45dbbe1989e1eecbfb5cdf5067c71a0d7b7fba6555d0edede12f7228d7f9841dc532274f24060b1f52da6fbaa179b81ce962723f43601d248f8f4d5778c1653e038c8d27828836d562968004003810e9aa9318edf3260272b54fca2e012f6c04abe92c2e6152f3c3e973c7e9abe8c3467bdc246f0226d1b7669bd577bb317c571aa8758bfb694fe4dd17ce78f091cf6c6de3cb601a9d177128fce8d42e652b490d90c4f8fa04ddc71cac300d3dff699be3250bfdb2136edb0057af3ebcca77ba5b3ca34531810c5e2d4c5b5b3bc4e71ee9e30cac067b7706c326357fe0ad2a4bd9cd811b4e9d696bd9b4b70579ae246381210f879c769e5f9cc3cf8d70e9c94ab74a55f5d7bf61a17418b6edb6db4147fc40cf98c75de85421b7d192919add48e5334ebce2a06e56b915447fe085b7dcd677659dd55de1f705c389975e56e0338a2ef07ccf5ec3786407e8449d9011641786f1ecd4d3d3da975d61f5a442293e6119ab20686ea8cc7681010421226838a95a157e2de948c536aabadafcd4095dfda48e5613272289a8238dc945e5f1ef30075d5de096131740cdf23da1fb8b9fa009e5b321083cd93bba9271909460c09bbe1e8c54319394ff85c291814e21215816d4791f01424abbe4cc4c792d0d04db1b812f4d24b44caa76de2bc50f4d1d1611862512d87fcebd3c0b2659082b2423bc5360d107ad7b8e8ba7438ae4509105d6b618af25e75c51e272aafaaddf1e5a227f2b2a2c96a8a83dec23223cb428136a30b290181ee20a819cf52f6c03798e7294a89f3b5137693d5a8b7a0ea38d78e43008fc4eeaf6d077ebffd3ef7952620e0af1395c38a289832df391d1710ab5b103a1ffeea8c06684c03a74399cd63797c770e3f0136d8331611502d21fb883136a82f2034358880392fc3d2fc274b799e59b89f8f90d2a5a123d3c21e5bf3540323743858fdb8912c7c6329a3aea241075ae097ebb23c8cd50f4ff46b42486e65bda6beba5f4fe6dbb30f7e61b1bf690c9f00f7513c83274cd21bb71563257a20cc38da2b88c1063bd0849c8243058ee205853342085a8edb7545f0d96a6af936a3d4612b95676665eb02e72e0875100dfa444f039eddde1422ceed8d38e6c3dbba25064f8c6cb5786f9ca67712b7840cfbd40f99b1edadd4bb9a61f48124cf3b49d68bd642404eb1dcf428eeabadfba6810a4032f8ed06b38867a7098c7744d54dcfab8f0ff941ecee69da9916d54097e080cad86dd08bf53833fec4aa4399f7124586223ec70e2c31e8c647be06df9e86a976f37901e9b134e775de2a0fd53d545c5f92236dbf5455859c138b7bb1112427049d29ed4f5dd5c43cffd3113c276d9bba910879e55efe817189fc239a204a9ebe738c0dd161d10d60a51e9dcc8c38861d41ff029ffd841086803320a17ebf5ff14b6cc2ac3dcf0ce2eea9af7ae23597233599c2321dd2b99e06d93f84989e75e30a388f47079c2af545d96f270e064a43a00c76bddf2f5be5089a69a138de844216148a1eb0b413f58d831d9b8967df297455e7538442388cdda12d157fb25896c6e2b47696c76b234a88bed4f09dfd64f2e4b77627ef03049030190fe271a5a853591ee9218a0c6b12cb3f02683d665b211dd1480cd44c9c0566ace7d751902babae14cc3821374bec774d54b4b4afd5d1811ede556a7a5ad02642a878d2d32380e7efb9082604f49d51495105f827d77945b5cfaf2f2980566b28ce3dfbf1bee2e077eb067bdfa4cc28f5d2211ca99a615e69118d9391e3feb9b13cb4a2fa9682718189ec612db889228aaa3f3345a091aeb11f41420240fbb47caf567646d9e7c762d3288f8bb2b1165cf049a191db5042fa9185fcd180b04d3007c376e0aa3d427d66d10918821f74736816044366463df7cb3ac94cea167cf1daf2d1842f130295e40bad672a22da9238ded69e241395f04d5e3c3875b8294faafbd3d90ed56ff3e01c5a0a3e349d761273143686aa26d408620c7d1a35ccc430a09e3f750d3256298c6068c0fdded270f308f79d2fcba591d723ac0cef703d8f0e7c051bae5b453abbadfab98bcc297ed4201b03ebc195c2e441cfd3b10c63c08868db36c320707ecd6a37593661d70a81f30e6db4a32f98e4fe6b950ace55923631c8f95138781fa2af78d8104fe39242f1fff6942e8e782dfa0d37c863caff9492f8e5cb70046d207c4630cc29c20e1ac105aef093261d8d335456961e552ab14d107cbe14e9de912f0e5d58d16b729270208204469f917af4e710123c3bc38a4b3f485f2926f058344db105b9239829441a2d8ababf04aea615c0e350846d9bc3b5faecdbeb450f38f615f119ad1b5dc748e88107ec2fae01f0915174feec37b3e7248ed2699d0a5fb2fc785f17d6275fbea867aad815acc8a6fd3ca4ea7357d197e5a30082ad5f35a9d894c0aebb206c6487163c9cc20442c040e6aab33d7b4b221e4ba4cbabd975836e353129559d8ddcb3c97876cdba360da0e0c1dd5b0cff7957a444027db985ebefb6154453a221076c997d3954b347f49308d2ee14d1676b75ab6ef365f3de54aaf398fd96b9040253813ba734829bc78a6db59e3f1c0ab4c878a72d6b8681157919130fd3171126994dcdcdcf68955ad64af8156702c92f7a715ce6f7ddfb70f60e80c92691efbfdebc8cae252108fb6c0010d303d9027d4a5e63413b5fb2316d32fb93c3ea52a2a7df50cc0058c76c58d73f5bb041d9fb9f3c3cda9bee0c0920079ce4f1ef8698ced664ce2e2b3b86027ae2b3bcbbae5bf7ea3693d9429cf94938dd3a2763d3f53937c46763ffee6579d018358bc69182b1c7158a09b18352ea618c11c45f07fe97cb65faca535f43237879ae3e0a31efd14679daf8fd2ce25eb8f32218fa20afc586a98fd908d3fd804cabbf56dcae272328011b252dfd83e5f0a5fdebc6acb04c5540255e1322de5fce9db5aa4cdccd74dde8990ae51cefd6c1edc1879971d3efb1f94dc41b2b23e9c9d89415b46189914a229b2f3e8b05ff78c68711385a00e9534dae6f79d15842aaec575e4ee0f098028bc74016cd3f8e93c6a0cb21a0b574ee63e367343ca9de28003d76e02d0ee2b8d622cfa3615d3628fd02499eb7bd8c1aa1f34edd9c2d059c6a7c7c978a5e4f60801e03e17c3a09793c5217f310a30db1965b8e328893cef20f4a899aa8d9fa28f7fe0a733813ed7466046776a874273ecfb57158483f4a588ad4f232adec5ba4ea651822780596de09fd54b1717bf04130619979a0e3d12ab7c35d64afb8099a1d21bc952653742f50c8e1c244d10374329cedd27fbefd37815a9b3112a4cb2fc587c4ebda381b2b01fced45cdf0b9ff8ca7d10b65ce42e728de183a82e369486a2e3345664e70674a5dac174d6616d90de8e472b62759df057119875483cfbfb103041751747f9cd12bb31e91caf79eb2db1168026a4707dc618f30",
+ "e45eef9561f3acb3672b4f38570256e8cc4d877e2998e72b022e33de8fc20f7320fe0882f2b53559e084923786e8205336a7d15f3fb88a41e7bd20767f2feaa02df2221fa7577988db0bbf61f3dfb429868688c53e130725d0279c505686f083",
+ "475a44cde0cc931edf9a44b0c1e0001766f09ade023dfe6b59a6af800e549b55",
+ "7812a320691ca8442767a51a",
+ "eaa577bd67fe79ce4586f43355c94528e306c1678946e4f7a907d2a8ee7f4281270502522119a8b09b6f05d864921cb515fddf6a1000fc2f67b52d0627998591e2acf5b6faf71c278e5754b2703662ce670dd049da8d6e280c2b84d6a9b29ce28980563c40e03381a49c54608b72faec9b272ef05cfa41957d9eaf3e944b22610c725d8efea90aaac6e782848d368ffc08784d7fe37ea1effbbbb34952def29fc511fb10a1282bb0b6334328e4d00529a44de3259b522553a07d524dc75f431cc9670127c15670c0df419826617cfb5ebdd8788d5f528a9eb1e61324eac5c1746f339aae2e2e2fae598642a389da671482128acf2d69814258d83de98f186468136868b729aa5f0874fef2ff2575a1f87439d64e049e4d0637e9c99ecb7275417af654541306615f30b75a6caaa563e4790dfb28fe9f0e7881ea2d885eefdba99efa7f878925ce7d33e86d888154a1b03189429fe20af8fa3a68d65ced9b690a709031121425cfcd7e1890ed9614f9dc3ecbd0e38c6c84e453e3204978ddc1ef8d7fc6cae28c61a472d8e089e23209f0c36e80c994af771e6505e72ba90e5543f6bad6dcd31fdd468b13533a0254e44797825764ac1f63747d8d6ca019ff16fa732068ee94be382c46b168050ba725379df31a98ab81ec8eb266a3c3f2e1cd95e5f12b3bc79b8b435e4d94098c6184631cec57e9d8913458889223a2a4541f34d2f9df380f34c3e541fc587f0a6cf08c82e99476060eb84709a292f4c7a8551bda3a9eb6735787dbb9d7f1e83937c2e0e49f2cf6e0ab0ad84c40fbafc3c7e61886a8629bea816972fa0afd0f617b6340b1af19e341875e97565c8eb0b25fcf68696ee674d2abdc29396bfd0f282543d2b72a239c6470f76d3b5bff6d1d064e6e2d06f9deef2aae8a259c034373efc820f9a2fdbce36cc27f35dd6386de3b49509d0c305757257f8674d958c580a09e768c0f6ef237416fd53c31511badb2e7cdfee636508482f01899e72052b46b5d844799cf94708520178cfec2b61c8980fa7dfaad8915b0b75ce6eb57ed4a01edcb4a35c1dfcdf8d60f3191bbcdfd522a0e321ea41c2cd87a303522d0f98b82dcbe53232ecbf0e2528de7e1be75569584bf2ec574687fde67ffe9827ebbe78f2e5bc4fb368f3c9b0f588c97f7a139bd82fe86eb605b8e29cee75d07b510da1b24fd62cd2fb366f1621e7dbf268b15937f7f7ea4acf6e615775a32c90733769996dd2c5aebe08ecba73e0bc4781d33971992b2764c1b08aa972859cb61b003406479423254a01ea85a348ef249d408157cc0962d1e24cd9c426e6e6a3784dec6fe935be1f6730b01e8683d97e21d8774b2e2655f85db7149e930a44524d4f86004cd687d8a528b6ceadd890707458cab62809110ee28f61a7277ed79dc41e573fd4a59fabf15393ed4c21bf4d5138ac843e80bbf5e1c39ac2d7f2147f35996eb51a9e835db63faaa196b8aef1823ad72523fbfcb35b5560582a48a25ab770e7528e4b3ef291e6f62f5fac916e2162b3b56304287e46839858daf322b0de083d1691d6bda44d66d085ef0d0ad364eebacdd0a43a4456035e58910d0b2dacce45b1c0beabc784f3620a3e4390c345df6117b86d4fc386523b7ceeaecc21233a2865ec6b63bffba6689fb3323402119db8f0665a4730b2e26ca6411db04f1bcc78ce6272159ed2665a286f1ad7758d6d90090a6fd320e697dafbdfef575077e282b825bd64a4dbcf92d1fc0c6f795154e8466ee4b318f2d44b6f81c52523ab68ff8367e01090c2623e00b4008e784049df873a35c29e0abcfae7acbf27236adba0b913d19a15b4af4996669aba4c656c317084347ca962ac8df15cd2f849f522016eb92de4de62944b917d88200ef9aa2def0d13e5f4ae09d2eb4a2d0800af1d704cb01975f6d59768a2b50e39e78116147fd6dcdfbc08354c1b4033bf6772fa127856a4072556a9f07bd7516d01ef41bcb519005c0a3b2a04400427ec033f1b52fe5fdc1aed8e2521fd0fff663e203defc39d7546281a98a502b8a470af16cc62a6581c9985d7ca516864b799fcc55a803ce80711484f6b81591d2402bb1499c95dfb1dee9846679c22853be87c84b4547138dc4fd46b4e79ad12773a5392540a595954112f0cb1d9be4d4eb3aaa4286b6c01520558d58587d9d7f0df3a0282011ce01c9c17111d10ad61b3675b1826c1ad37fc562bdde951b43f890555d6f74ac4fbdb9abbe8bc1e80bb6d52c13de8960a3ff8f65201265e82981dbe39e0d65cf3f1fb6c56e11f9786210383d0150a5e0cbbdb52ca8b2bc45c12fb572657380df369082685b3de9847d5014beaeef815d63e203cc911061eb53d89a312d187f9f02760bfa71083fb643f5d8c324c410070b7ebde250a185e7359837899bb1568a43fa3418f39c12feb03b148b924bfb98b99352b1fbad3f07ac8e4302f85d1fe9ee4bf7507972670ff8beca105cdeb037f1cc4f944d6ca869d0281653de5ee93a7362420fdba8b01a375ff08fe27873655953ec1c00f53613c6ab8b244e2fc1b6babdca5311428d06f57aa4882dc870165deff75ba877dd2a04d1799f26ebfac97a1be53a83ab77dbc2cd4aa45bd779f61b1283eae1a1866ec8a9c150dd0a4deceb2ddea1bc0f4206cd435600a8f190b999b952337d9eb2bdeb3aba2cb2e7000319056629dc1f00901f0880278509417223a3ea0919fcdcf12bff0771c7cc725bdca292068478ccb2e1f35ae8964e0601789a73e7e7c1769ba53f865910fc3d0085c922d7f7849d27b6e7503d521371351f9d7dfd5afc5df0effdf6ac49617fa228501ad72154a73e07781dc4b07765dbfa721d95cf1dc41e161cbd34fc7883a25e3ba6b03e504b2c3b98c8b12ff629b965c2aefc26d74faff7f784baf09c3fc38c487a9d1f5818261162f97e9dff70cf42eb5dbcd7bebb66d68f26d917ddf2a3efc0db1e3372b170b4cd18da507e44c467943f73648dba74db1053b53f989e481c3054bac22c6342fca2c26d30a859a1312e9c353bf921f68136de2b1589747bc765153927c31ebe749dcdff98b5da84c4b66085451b4c87fe1ba2142f98636bcb268c33f7b8c2b96a6525298814578377aa189dd73d5bb27ec5cd2110d8751c18a3110273df2595d4c3a00809bdeda70d86c4a8169b7010c9cdeabfbc3dd3266518226d0ade9bcc4825f18198c854de329fb8fe456dd3bf35d89bd9d2384f3f3282f6872351a18a2f852bf173ea4426de6d01b3ef4b4685aa82df7dc45b99617a8b8c8a0c65a2237b3eaae8267e1f6c453f485432529d973924a080f6a1cc2cc18f804f53209383ce3601ad9361afc331707be1c88b4370404cb7fe0bc538df04adc5c8d9ced94b4c474b19619a53dca3fddb434cac09ce10c0293fea04e8e1b19fd3ff3d174baa988d91cb604fadc59ac0b61f4f87bfd07eee20f7f3ffd96766dd6f3555cd48da7ecd71d2fef34ab082678bfc4dd007669b3fc7a937a5a46269baa7e4e4e43eff1b2b847ea70b6c6c23905d6fb2fbccd944251087ac00c35c2eedba30641797d36ef9d3cb1afc0e3e8930f5b605a847ee77106995bd44047294d04350194369c5a7bf246d1108e1d18d9a638be0c051f695ce86579db613cd8922e86c683c91800b9a34fe6339e0dd79472daa662f78f04f0151a3acd18f11faa4e1216222843b521fb998c8490ab8bab27fde36395b456501307d07b484b453b189fa339282a634af30fea99c9af8f877e61871fe743238b2cee6cb69dbd17d574b5106ebe4b0fde4ef42fab469a5ba7d62c23b67d857f1af6ac981c320db70cdbb6be41bbca60bb7a159ee1c85cb82e0a220064359c06c660b75de6b49839eea68c80283b75d9d627aa4500c0c0f21edafe4a2cf7ee079d5310479da06ba58b142614fe69cb236c51447d63db31cdff91485b46325c26d40dc6d608d46a5e2fb01df06064a022ddf6d5cce0147d5b2a5aba5f9fadc5e778010a924e00a13e21daeea2cd330f45536ef4f42c2e77be00bb53b3f9a93d3eb327dbf30baccee5d26849cfad654ff3ef2b035b78dd3ef42de3302e5514551a968a205b823dffb040ac9452ae3efb43219b02436d0761ca11470405510e534d56caeaacc40eaf9c47a39475adad266f5ddc813e71223800dd46fa7c02b078353f870049806ed7ba57b40b7c3c6272296667500c4b97dd2d7026698b6bc4985bc01be99e0097013a2632c71740888ffaf902a02bf644b38cf9a42528880d9dd142de967cc2ad3e1f1737f0cb8dc5c59c252496e8cfe4e53c82f4a28d9ba2bfa62b6415ba3e5e09040d7f3e3abfeba53e46575e8817ac5eca806ec8a84c7cf77c9fa86c9dd2940f5b96b25a92d4a8f894d4717c8f80a62a35a51d8511f1e822fd79e6fc27cc3f3097d9e3272447de6f223971657ded9e660ee4f8836359742ce7616fd0ca2de6656c71b212b34b8edc71ff36bc84ac4af58eb1adcba4b2c0cb31468dbd2c2b7ee6752981ee1d152c4e4a9b25b2ce87796820def34b662381806d2e4fc77f0b69d7a87de43d94d62a6a6526a7f8c588392890e96f9c51bb58b4f438eb5d197477ce9b160d1c898c89ab408b3c1d648be93b531a5bb4988592c5a8999ae3acbe586d947fe6dd507cddb92dff4974ae17ab99aad5aec9d07b96bd29489876f51afa67570e86b69321d9e565d86001514638403f86666dbf93f18e0a62bf65db333bb85a3ae12d8411aa3c2a423a29bacbbfeebb8a5bafd90436bfded16f992232360211086a3084d9fd1980dd96631820a2cf25c3ac5c19d164cf5ab9a852399491962100ca4fd640146b7ea5460b4fb9e46bf8d23d508a4eeb8a3e9fad8249ece3648c2ec7705a7414eb8e8d602549204cb437f589161fe40de1447d14efa4d738b775d0333526c845cef5ffcbaf5c957df1d8022176b56eeb198e7ad2dfc3d7ea46b125ed432cd04c77efc011a2dad8573345080d7c3cdf5cc160fbc86c4ee1959ee1b8258056b0f3d9343c22dbb2f7858c5f162f08cffdca1acc866aa68e5f1c00b74f66544e8a61e429335adf6f73e32fa87e48e1adf15bb6c7aeacc93713dbc31cdccc9b0e52f922842679494039c395cc1d95eb97ae4df3bb8aba9a2584d97a236f87cb22f00c0a078b045044a5c456e22b2b94a76a559de2672c880660f9785b76bcc2aaed780e05212415c6e73880ca110654ed155a1004af45d5f15ae8e5bfd4817440c5d3d5589eea2c6c344ca0d85d91460638b37f877ea4cbbed35ea75678ef2335a5922cc8541987cc256c8f58045028d33a1c4899cc32265c619ac782ff998a478996be6a0c5b102a664831b395a884f18e77885d860d6b236c52a8066d2ced25432bce79a31b23117f405ef4ebdf3517de98d288f8c3baf04b63b6817c46c14b646308e9f97170b7dbbf9d1a36480338d8eb7466df56feb6baef42cba75512954fd7e33961d247b7393726e46c6e94e156d5776a89ad3e288554470ca0bc4cf4d2d2b0c01ae4fcafcb65ccd6ead03df1d4d6577bb",
+ },
+ {
+ "228eabb5ad8b4ff13b10d13b27372bc2152dff149859ba47d9c89b741d4a5340d8fff5858a4576c55547007d7e2b3f94583ea8f0976237712bd2e5481c3988f5387e7ac2c3f18718388795b7b2d44b0a13f3faaa55311b800301c9203a511572cf8f349280bbabb9424070f415bbfe28aef8d20329ee842cef4d4c299e619b6ef1cf00718aab2accec9ac00155be2903b6fb07dfe98b0bd8d8580176b99ce4aa6be51cf59046c17ce1817d363fa63af5a241d48bcce064a438651af102ff9c6de4b86374fe24f1dfa66e16e51550dbb791af425d8fa601c70c1bb90e1a557bfe0dde730b0364eba9d2018ee751699ee219e13fa8874070935b29a1767e1d748bfbe796fe4b81a71e823605d39fa4b5b885f4610c34d1a090fa4106785e7a035a629958ad1b00cb9d36d171d575268efa1bef064fc0a6dfbae8e532466035a0c2cef96fe9f93b872f0cf804811e927b39818189412868fb104e2d56ae62f77031f0df1ae91aa11826991ca7b8af22f130a47a72cce36ddc319b32dffd294f2e192e490249ea1a6f8437173ce6392d16dda888a98bf685bc91b89b8ee1eabdfb1806fd61f018d1744fe8b03521de4bff86d4a811ca2ecd5be668e9c752a6c26aacc0cc9dd89d112785c25ca6a0a7a5267b4e37457c04a0626c8a29be30ec28ddacf47a84918bab164d07bdedae62132ab04a6f2c4e108eba9ab878caa4a1a7509521d427ad7f3dfa86fae8345dfb5e0d46ce3a94dec84f7880c7422468ea74fe0b4825b8c762b34d5d9b82ba96e0c7dcae01718ccac0044a87476ff031e3ee3c2c13f5f375a841d243c38cd9a354b6525527de1fe7e36a6e2ad95e5bbc4c97e85f8cdcd5341da777e03451838807d5dd2eb4fd15976783c140e21cfc2eb3e58e40c16374de0aecbe3e3d41c64417a472cba18762080a2348ec3f441bf229a932ea0ca7c816938655d0c81b14dfbf86aa600d0c68172fb0046ef51f601ec89309d43ad1eacd583f9d205bb1ff1a37a97b44b5e35be4945f52897eb2a74645b01a7f82054cda44e9fa9f9af9bad1a235155718713bacd08d354f3fdd95858db0040fb551e9f93ae399d5dc53a67e88bcd5a02d104dfd9d824cdd5fe262ed9266fc47b7e640f2c9d9c7a62c6d24b429fa55560aa254a824a0858482e771144d6d5b05539cf71d75bec3a22be75655e1ababec4dff9472a019f6220067374dd49252282e4945a407084633ef9c88d14833bd95335107d36afdf56a642cb739bf0a61ed53a6915baed78e9d74166ebc492b517c7c594fe6564550bb7108f43012551e65fbafc0a9874e46fb64b5b7aee0082a5d617a43b8bf9473309c6761aebc7f13b72ed460b522a6b0875b67353c705f99d1d9dc899870fcc90c632aba1fa9ced6d7a2368dc4dd3d4b38a5807415e00de6b9ea70525a6c1b67d04521efeeefc6c591fc5256d990a1123522864a029430bb7ea00dd80d283fdd6d61cc5b509221e28f73386803d97a38fb0182fd95b3b91353c6eb60ef2b3d5c8c0ab8dc9cd9be2b4cf69450d00e88cb0f0bc9a4be82b71148a37237ceaf945ab94c365625f58171eb15c1bb244a87335550d813d28f241a3296520046e65aff3291555786d7c871ec8a2d10d4b44429041c3cd6ab60f0def742de3d28393c5aca92b150697ac15504ee66d8a2aa01a6c63d7c719d6d4f94af2ed1d8670e3231a0e481095e425e6231c43ad36e3b7a3478f6a61563f5aa13237beb8a891dbb29013c325f7f91c1b055fb83c436fdf8aef49ec457946e6ab7e955427373fd9c743acfd4b9609569b591ec79c7ea7276de103a35a4a8a05c91f59e04689ba1ddd570b18ed046f785d7e4ff9fce7115ac814fe126f781828877208ddfbb2ebc919e6d1f6eb417f38bfbf22ac9633f75e58e560b85d88d0e4fad9b2e68c9ebf9675819d50c30c8982bbbc2f41e02690390bf0e16979b24e648bf15b18800aaef58c3c465f38cfd1e47bf1266c17b69523b7868d2138cb95c4bce0dd3ceb7c2267b868b6e12888d5a489fc0091b295b56a1c328b54fe1119aaf1e6d7dd52fa450b52fbfc8b84c2200ebe209060b655cad288562786673121691809366af37b76567762d1fc24f1fad3128b43c8d10e9b6954b2efcbe40124fc0a5b670dd6dd544e30263a551825282aa06be3817a8eeacf31ca8b25cba011d60b78d3d2462810764e4acb566ff371005f5481c9d36c991527143af2c44cc8cfc59c920bb4a281f2ed4d494d30ba4d900edf59e23be2f763072255cb6f1e8b24ab1d305fbfb2429cff8bda303617c034e71a17230d0e860420dbcf9fea4ab48557e4d50797179496936ec6c97686fe6d9115809e14069244d251d4bc9c8931e47e06ec051e709ba1df526b55d959b37a6f3408833aaac80cfc9cb99915eb7d83e26998f0da2492b986fe0f5047b2cab6e6d33a117df21e6a8ec7f394a3712885dab176a4d6095e5cf75dbd3f0077e5e74b1ff8b902072380cf172562884de852ff5f07c55856224fb3df8eb44764ab9284944b86ab6f176a863cdd0e7ab5616a14692f6cbf41bc63113b27689fc2fb145736aaf2a5b26d2bef3a2a59ef8bb3f3e4d360a4251d0736482e9ed7e189fc48c0973b6649988228c2ac72b23826a61cfa06b11f13c8555be6e433d87e20113eb74c94f0e51719a7b38c59eba300089d06b9bc2a72017668e5aa3153ca4282718f1762642e7c1be1f865cd9b65c6387c8fe496f1e60d5acbb78c2f71cea1f35dc955b1e7d1cdc9ca339765995d9e05dd729cdf58aa2a1451b633c374e5b6c2af1c8486ee4250a875e80e1f359c15130eb1e2575c0c7badb2af61378527fa24347ebb12c10bbb36e3c94619556b2c641d0ebb691b2706cdd667f55b8fff8fb46e3ac72f3682661a4bac2391075ff5145eb07d69d77437adec2d096c1c89208ab3e7a9ea6a0ff4a5bc1846b3683bd7c6ec4520c3c95861a5856b0191e4221c9819c67273c66729728f6035e79c0dae8842df4c0c27ada1ad18b34efcd55b94ef120762e87e8c5afdec80d5788e83f0d1533cdd7aea8f27f33266e007b274f6d48c59bcfad607e8b298be2b17322be88558c60033452826778f167f318b660607bfb2f285cadb385399636acb8f5350d819511b5e7931c5f8483529d3ab3fdb5ae2dde0ada918f1327c6c0dfbbf5ed3c8afef171910dd0169022b3cad5b08084dd5e8eb8ef1ecb17e48bf69f80e3db0ae1cc7b73d94b89696e3c3443ecb4c7ca12568201744d1858d90ff759f2d264d49edf47772bd0e0990c14dcf8c8a4c2dafa44dc6e92f4c66b03bdc4f68f28ca2d0811a433e184cced99a8e5614ca83c46ec18b47e0c7ae91037ae06c6d6d0f3dee19711c21cddafb5869416d23c5219296acda7774891877f3f8d46155d39f43ed10500ede3afa26943b83b800b54a9752250ec6ae173e920002f365d692a9b3a2f9b27124ac97b8e81b70e8c0bb7022d07ee97e962810962b03fc019695b5399f77aab414327cfc5dedd51e99453179c42ae85a42f8e06e0cec6f937224dd019c77c5a0ba32ad08107216a9c758138b730bd5b5f4b613f192839514a8621634d9dbd5840e728c1ef4a2c8bbfadc376dd80d13dcb327ce55ab536a43b570789f5c5e135ac0af79b54232613d0e989ae695aeb358c671ae71d508b58a793e19c58c3d204cdc9a021ecc634bcb0bd6a1917554ea3bd688adab8163260a914fc01d7ce05a497a5c5836cf9401cb6aa35cd008470bdecfb97a511c905badd01bbb4d0c05867661debd2162beeccd52399d5a70a929405293916f33ed0d03f8b850f4bdd77b1fb6283118d71de629577383c81cad086f4099ce7476cb787f73c96431a0df4156f7826fce9045f7e7c97bbfd618b845595203cdc8df4638430fac74a07bc5f773486731d8ad29c06695704cbe2882077a85d543551b7ba81b181ccb93d2b3071b1a38f3c762b42df8246aa64cecbdc772830ac79e766fa99e8c65225f28297a32526df9b51227bd368253737f013ae18435a912bc18cc4a95216ce449865e8bd8bc759dce9d4af52f9e789eafa37023e91946952202dfb7243cab7db2f9f98bb66f19750c547a2bf2e2ba92862ab66f33fcf465ffc41d23f0b891a3b28b3f68ea48dde6ad4802902abd22b0d7d9101bd61471c5d88ee9d9477b7cf9f6ac52e0f520c79278da22938745446f1e647ae478ecba416b941aa31f979d0633efe72910bebb8988de1d0013616f31c5da163eb6c07022649ac57422627a5642618f53103adc9918f9992c5b085e10d2744f9934bfbb994a710d6cd387c325e94278f97d5582864f1bb29a1400aaf674ea8fb99a3b42e4ac50418fd804a5b1471eaac4642d4aa338fd3d5d0dd84372b2c32c5cfe7f319acf731a9787b048cedee3833300dde639cb1386c8fbca4bae8d67fb7bd72d1696a0212e27e166e6b04a79e34b47c98502ed0bdbd8d61777537f72df569fe5ed30071b57e8724e98ccb88c07f0458cf32298cefb6ed672b255e581ac756789b57e950d57174bffd3f47bdbe4b168e7e3f1a6df508d4202d327947facfbf9526a9e5fc1a5abb179902d4584deae6cb2900391e080d3f3540b87c3a873ccfaee5b4aaff0e6516a867ea00b4d5e680fee6b91defc65c240614a1409bdd0f49c2c4f3c1d258d77abfc17a749660f49547adb236730e5a7a22fbbabdd8ca079a8efa5b605332db12f455868ab67a1ffd27d1339bdf8d150189cfbf6199c6fc27c05788138a63267eb8ac086e27286b4ef99ee9d92cfedab5ce9916675f128f206a1733f47a597232067aa12da20c7b9cab6575d7634f8c31e9a29948b528681f3f9c13b9f585ebfbff8c28a299a43e4409b31b6c02a79eeb493734fe5f9c1d9e3830572eb54229b5cf525768f695acff48c76b4a6e0936b7406ab69f06d33d3f04946db9d7966ea6e8c50ede5abadda28149edef5223a6938d5c32933070d234043feddbd65c81be218f9d7c497a1ecac30bb9162e60a9bbbcdb4fec4b212050610e2b376aadf58b3c9207860d2650d0310ae6606a8f1b266b6a13b68c3306ed413224abdf19371bac3ea1b964f28996fc70f666ff118c6a7c9f2108d327f5145919c03832f754de35f5979ae72130e39126499037d6fbb3751cbb4843b05d9dc91dd5fc1429da491f72e3069313ea243933b47109af247fcbe0c70f9024ac5a41815655ab309fcaa282d03596ba59cfee0e40f7bd657689453e98d562442fa4c585f970b6983a581b0b8eb1c5e780b3f5c1abb326213c6b5fd440c2187066ddf55f4eabf88804139392c45979440c6f05b7222bd95e963832d7fa4a4760273cc075e8b8feeccb917e8feaf7d3f766d9ae880487e69bc01872ba62b91b8af5dbffdd93fdc95e8f47ed793fc070a5991f2e9ea61439662dab218f643c1959171937aa160008a548f51f87b58f2c4fae5aed556f26bb9cd1dc2b3518458e2f5ec5d974c6e11a0ed639958cc8c1db771cc8cc8bee8727bf6452f47c9782acf548856a0e67841c3dbdb1c98572a4fc8e6cc8195a504019b4930d302a90dc20d8628ae6c90e0206cbb3d05025744db4e115cd3b650e5519a1624acbf226ebca8875b05183b2584e65289f8b9cec3f7d010cb9671a0e80bb70ca8763f1722d79e8decb6b9023baf64b5981e745c06546cc1e",
+ "ade72c2ea29cf829ffe99c2d63840b2eef9b51a9919c02128347d2e88e9f063b86326928cf6252ce4beefbae7206dc61a22d0b33c90d464d551835e3b73c1e3d6e88663deab80c35a607e4180ec079b0ee84e3b7922904e7423acaf976e837",
+ "43348cf32211d7daa300de8a4218543c8e3c7373ad10950765c39760f80b733c",
+ "e4709d225a552e90fb357413",
+ "562050bfb40451f27b1181c389508550a0f46b53d14ca73143da9dae3d3d2b466e9618db39e3219675d2b6eadded7dd9c741d7c9bf3c5619a521189607acbcf6b3964d469d966fa134444aa06d80749c873f0f976e0c5efc5be8d00a2729f03eda6a7b8630575df8b3a19388ff88daf0d00bb3e7c35a525ded90a4511ce815fe6c8904406cf72d7bfa14ca533566f7b54268835285c5402e22a63f98b5d90c86dae0a76d65eacc1ba85b3f5a1499d5f3432dd5455fab9e8bfbd266e99283c2bddf9b556410956b2f061603d1fc91194766f90da841699ba7da3d53ed5abdd8e98034f8fe734446d92b458a731aa4c578552ec1ac5d1baaccc4153a67b48a290602d5f955d61a08436b27cfb0786a80afef76e1266310a42d90feeb3bcc40ae5c4506432dcc92f7e5758ceaf277255401f5c5f4b10df93a249e38edd9effe7bacdf7fecc451d3b2cea77c9bab0403450c41929775b8c0ace46f6928f4d9cf3adf86832d298ea32b236d3201464e2ff506ef01da0e1e389e26e2b3ddc553b369b48d1aa5dd43edd5cab065e276aeff72a4c43206063fc7eea3bcc783ba2221f5b615a7a43a75cecda6bca5aa159e9208bf66af61e2e465c2daee630c4c62077ea6ef0e8b4b4e272d4e93a5f5284f9da463e1a60f815a8a31698ecdc09dff2b62f00e37aea5fd4b07a110cef27e12466c1814d3b10017cb9b8e12f2f38f10cbe31296de2570d5662b16639fcdc05db81e0d48178d055ef873501148d00903ec771400fa4873c5579dc3265028f531538f6dab1e5607a15c8b90cbfa4835107cba6f453bbdc71d08c7e423f58b44be38a9c8a610469f2551ee6177edf639cde35fe8e02f76b7ed106d691a876a4fda3b42d8ace3e0d3d4e026206c5d7d4d56fdda9dcd30fd7b74217fab3c617903f1aeffb8363443ed128af94c391810e327704d6f655e57dece97658d41e074029823850ddf7c5937af41c64465046d8544bba65c691ac69121bd272107f7eef8cfdb6a25da5da16d1033cede09129d51f6abfe63905a6fba9a64d7832fa35825447150595a60163af848eea878fb31a5fb97b1859efbfcc8586eebce8cfe64386461a9b88aa5efc1db43c64dfd5d4a45aa74803fd178f9e16a3f59acfb6e13a564d645cedd73890d0a82fb6dffeef527694a7cf2a89aed9750c3675a67505bff77de8d046087bd39a85c90aedb085e99baf04c7e3bf92e350b332da1b8af85550a00d68904ca426da61add864496d6ff442bb0b848e9aa463bb0c2085cff1a83a47d6f702bd184cfb5c139752754c8978d27b58d364bd88722b9097ee3a6ae28eabb14ca7c31e40461101e92448dbbc63b55cfe56efd078d0058c5e6146c73bcd949c4b3ec9f881b9a5f7b41ca83301261e0c674f2d35d96761baa00ce0675c082bf73dc52dc726a3e605067569a372d2bb47fc8fe1e74f00078ce6f352a6d9d97fd2834670ba3a45aa6751eafc7ed6694e1e07542860c8ea516f296ee901a3ee16b00b40419c74bf6db12c7230325e85a918f412bc2f6469c1a13a5aa77f028e327749efd05b91053f49d9f1edf49aa552c58c68257233a168db60ac55b4086ddaea275b078869cda7b69493c4b371b4e9c8361357a7ac7d3d3bbb464c960addfa8df2b208b21b090d540c440241598212d33273203d484e0930e22469c2a8e866579a4a2b3db8f8344dbf8baa1b97be0c4d976f6aaf14cc09ec52630139b894b2b6f4dad3a205a7b286253f1522b1d6e43bfa37beaf06f831c6f0945cefb2593b9b298da13b0d910582086c5d7e256ed4067bfb476dbe01bcddb437d46ba716d6ace2ff9912c8e460ad33ab3d8f97b7b08dd4ba9e01968d1949ff85b4b9d5b8da291fc0f90ab1eab1d246f67d76092b7a37528ceb388dd76f8a8f0aabb7490f02a2c8bc6498cb26350d859c466dd611bf0ceb81a8b7899c67742c22697ccee21c4963acb003d15c1a2078112bab05595917584e417db3872a0ff0a29138bbca7314449b19827525340370d7e48fdf9f7c6b4a280e78d00775a291081a5e78e7a00ff915015dd5af5f0a45690baba8b1b503bf85f326c23136f4424be4a559aed03fbc81400ac27a33dadb2155d1704950d98043dcd86df1eee78f3f266c4d14deb8126708f74b59aa15e8b497c6a52924a473f999aaf0abd3d148fee8503a1568efec7bfb0bd463402f563e4019cc9c9e1eb498aa54dcb659f43b86df0a34de4e51ec558bbbade3d69511d3fea2baf44f67e85ada7398d7f72ecadcd9e981f82b0743ed74bd33088ba4cbc85b0c99dc5382c599706dd2d51aa9f470c25a98e7e8248dec216a155495630662bf6ba0b7a4baa2cdad30e9ce3e1a65e3c23d69d5f946606ee8504dd70830aa5a8ddd84f10e064695469727d2efeb46186c9d3b7a170057636f05b9ec4c2de7d935fba504a1e7eddf7a5a95226b253b0b9eccec976ca3c57599850db40c27a51ae755c1f30d392467cb74e5c8235861d11d0f8461b0e1d84f5718d64ea92da62f4de184a6499dba473e82b3d197305de0e494f118a263237c7b4c0652327977edb427ccded35552c00a5804b9557ccf2bca2484d9da2c33f6c1bbf2c666ea10b4644a21e3905e5c4eb417ac3572e783428d23dd7222e75c356b99e8183d033034e29e618c90e66ec2f1e9fca47d82c1cffda8ad14c96045159d9437e91ecef41d24cff89009ff57e18c1a422860aa9cd31dd2a85b07422c72a5decc614a9742e62a4988f394421b6918e51c2412d749bb53b1e8fed7b2ef0873ffe14fa77bc366bbd5fa1432be465f5e25266c6c12b55df1f19b1a491acfc5c9019f122c422243d751d8eaa8ff721397915171556e999b34425f7d3ad6f6c3323b8133b4618c65ac16cb5941edc979472734bdccafc73c08939c0b1e306ae3015faa9cfa09ed6560269a1dc54c2c046a12a178144f4381f7b6fd3fd2d28f778d444d9f7a0dae00ea96c6969b78ef326a962d23275f1518f0e6a2469440612f3710b53538fe99a6179471be8c5b2d682ab3e9a5126e41ed6de000cd9e92fec3974e0f4cb2d2245d03d6ee80d6a793b16efa829d75c796f34d4e918250f457703559bb48ff78f0896be1bda403b7f1fd6a319d68478ff70d88238f2b8afc7d20e51757bb9db3bffb35a8040fc0db913c4f03d48619af7fd24cb8986b3e139058be3cc253b3de9b3bb3f8dab7b8818638279b2e6a0c29cfe16fa7250d3c74362ffa07e2977cf562140fe28afba8f61d81f7c73bdd4a2faddb00752bb049d0a57d05c6475c7387e6716ee31974169930c9fd830cef138659cf56f2212de185186c3d683fc6b7fd36e7821f69d0de041a569765066dc4a1934870a7b80f174e8f9e484942e62404a42b21658467873865ef94fc262c231527f39e82dfec91215947b99567daf75c6a28073ee4e67d4307e4b35b46f85433abd9812f35438b34598ff3b6dbd60b60747ad64565391df45ac80b272d0141702ab807fa27c6a6ba2f42c3facfae0c773940cb2943bb1353b41298258bc0d07542b69483e17ab9ce709e4160b80a0968dae9af8fc7c0324c753ca4a11a6df32dfa79a87b445c988154bb3c503e6884cf6d8f5e062a16b4ff230fbda109a6127d35e3bf2b29bfd3b18ba275af773b1981d603300035e046ef023d51874aa105d136bfcc9c7323bd0513a6b2b397ffea71afb7a8d4695411d86164917099eef504f6cff3c5cefb88f23f56c4ae3e2b09a3f353fa55630f45f06c29e8912e8c3c4f493f25eda781680585580595bba43dca9cfd400d9eaf5081d2c6697da59e012dfd0b875336b88fe16609c2e9876737b9afb868ed52417ed0c6b359d582d585ff82d98edd4e63c6b65cf43d4f69eee2af4819157b8a433966953862d1ff2c6d0cba382644a1b0033ddb7be3d1fa9a204042d7b821b293bd659dca980c108ad1db740800b9bd2fc1a163f9b4066f7604f160a7910bd947cb48ce6c81e680fc6571ff0cd12a3ded9c8cd560970ca5cb480a70a8322d5072edcd257604eba8dcf55f9ec97ea2b14fdcc72fbf615131836fb14e42b8d7171d0a06d2fb3caec2e0759e86b0d8f21e312d9211ed7fe0b48669934ffb892baf1db9aa457c07820723e5446420334bf6479f2099e01ef8adf273adfdd9ed0b741931284515d69c211cc2efead8339e450b13be71b35c36c1f00c2b8ed0cfa9792e422912e14b5b1455ef6abdbbec0035480c6cb69d21321d12ee19d528dd48f43b142cf0502eae5304ce52b7fb827552db9ab885b93e83d56a33346135aef11b7e48efca7cd52e2499a7edab0bd0562862187ff4599b2446bff11c37181092fbb05d0e05220ca6bc37f529d6599e8c29acb9f25616c27df291d4fb07430188e6470df7002f73cfe5fe6907dab0b4f90bb58130fe90241c29c6063a22c9f45d032b282eb92c93736692bd5cbde2a17552e942b595b08e6ba0c91a03b9079e9117fbba8f26ce6c5d0500c69bb6e22e3562a50baece49109c2d42b6714250665afd0f0a7e951182012f21aef4b917cd434d9ca22661437608e32666497516be34652500def6c28ef8f56f2273de5416142ce9606faf7df92ab779ed6aa74cb99bb1bfe758ffd344e1d31f479807326d1a7b98f6811e275545d69198707b0fbf027dc6a5e4815d62ef191535569a452c27c4e25ecf139df949d70dd5935bddc04f33b2f0bcf5073c51fc51c15067963a20569b5659f0e7413b347d6d5ee38a92b7e6e656c199149f07ebafe5281db6b1b2ecd9e0384b6f5a8e27ecea9a0249c61b16564964054f5f9621471a98de132e102f518c1419829e2ae2c8c5fffd1270f0a0b33a383437b0034783d50bce8bd7420c059d16364eecbd55b6ac8df8a70382734d8127f4f5895cc9e508b13c000ea053ab59b87ee639745418ffc566ceebad37a17b842d24d3423ac3f086142c622eceaadc4106f8c90c5dae1f52f407fa0bf1e6bf9385cbcbf3b61006ea3b1e66b693ce704577ca9598587f41e05d36d1de424e0e51290a5f2e2f99f1960c0253a046a49b19eef249ca2dda2af1e8dd78411088eff1e9c23c31bd20abd4fc9e7eab19500827d202f76270fe9f90e95309516343e0fca48e5a12182e91c78ebf2cdd4644629afdc90bbccb77546cd765135910ba1cd8a3e3c00fa77e585865e898bfecd06c01a0a4d7be483801099c61941c4967154af5620b171b426cf229df59d2944ba50754140c3f305c16956953be376fe6e7cf31a2e9c276bb09cc24c4b86b2b26f039b0d8511853adcb7feb8502e7641a34e3242bf2c538006bb1983345ec3cacbf219ef10efc1681d52e6e1b1c60bb556b6b8a63d1d1f6869077841d1b816f3165a35833e33d39a8c6e62a2f7c482c395768fc6a0e3cbfc7a1a6d64da53adad66c8016f76eaa73df1b8ef83012ecbe75c92a8e39b48169433f951a539b28a034d5fdd00639a5e3e17ef14dafe869064d130c90c68be4d5ceddabed1bc94e97e2cdf7313f780cd6e175a9e3eba3eaed896fe464073fcf07ae7b5bd41d58c3160f66ac95a76fdaa7a8cbaebb304fe3c8f03cef927a1182ac2281c3b32378813b24bb99e42cb0774331ad78b74d46b8ce48bbf4ef8431a82d4240edfd61b910c38570ba0bfbd4a41665117e6d5f5a97908462e62d0b76160d06aa56cc6e17aaf4607ba8263648f2a0077e306c25486f5f39a75",
+ },
+ {
+ "2f6210063cb3071b3d49339185c2cef8357b08ca826d8d1acd852540c16540f1c850f70404fe1f414853d3cd15a1c64a1cce149e3ca1b80926de4ae8438ad90bdad010decf2f201782f3e49794aae1b079f54eb59607bebde508a528927e346d4e444b1d736b34f65e198df2c36fa23c64f1f1fbf8b0b8ddb85d054bdb39b8297d0347f16f7be7cd9474c058e36294485386434b36fb28ee582e393367f15ce5f5a3d6641fbd31b331f10b1554a05da726a0f35c9b1b4af3498426b17582966a266cce452900f85af1046f45a4ccedca6ce02607fb70fa45f420f66aa38cd4c9f8a30e21a3067b940aebdaaeb7c77824a79e2ba20f26e70346dd6de96942b261e5c08288c7fe1cd1e9f680a0bdf8c46497f007a616eea95ccc17463559f8973eb919c68017e25100d9d1a196ca65fb615502076bf0b0c8bcc70ef22006895ebfa2243fba0791bae0625b762cc1718d1673948264454a200c58122d5e9b8b1e3eb05df8b7eeb297510e0d7dcf7f0be5f29f6756e4b177f109891e6825a9866359e35b10d20da7231bb5a0ea34abd0264b377d2fe9f420f27d3e5aa2e8e00541c46052966ef9b989ae5974e2054409507b867f647aa057f7deb19ac6929f0856005aec6e53a5f702fe6be403afed532b73d38fed73e6e551987f182a1e20801e7a6c8ccd1184cf0fefb4139fa166ca15395902ac40e7fed8661602853682a3b0ee307dffb44d0ea3012142a2880cb7c166ba6ea6a16c7e0882808db8023068f060e5ef1432fdb8331ffad6a7078d686d47d613e94291f1c4117e7c13aee4030fcaf223fcefdb300ed606b5dd931e4adbf45dc437eeb5fbff337812e15c15f026071423f6ef5305c559baa2ecd8ecc7cd498b043740ff3673774855d45d45fa64591d5b4970600ec91ab1b6f39d7dc0e709c41e49c355bd3b9d120ffb57095fb127bafa971a086135b917285794e83e9dac5ce76fb1a4aa4fb6b94a0dc3a9beea64b8817ec1e2b37af9dbd18ec30f2b6f6c12df1db6896c6c43b67a066038f0c4f17142b254f62c4dd1fedb950d07047919e397d06d033cb0bab6b61aefa6dee01720926b16beb9e8bc947dca9b8143b565da85d2dec182987838b267de9047f5b0d961c7971aaf54ae2c1e4aad61ff123c84e41a4566b2bd9e64247cf46b72a444d36bdced1a309b464ee5f4afe406eb68eb05ae51b76bf01b906c0ffbdeb440b11f1c9e3a4c3a809a1f7449047b356c663a1ab7f286a70d16141d11f2d151a4f06d422ab97cab539c1f9da09ad20c000c27b8fead5f0cc37329d466fa260aea934c154dc9c0a065df3d057a0f117a1c38321ae59226a8054f7d6b49a3753436c249838b0924f0e861f5627106dd8d3f0fa724a1cecda71d4a1267ed889b234ae4a7d5edcbc5d52cba389dc0152aff24d224c6a0f16dbd3b7f242807bf4b51a3f22690bdeb66eaa59e8766b3b265d784899d247a0ae1b58a06dd91c529e3691b09f9d9f55fc39afd4a00b0fc668880ef25a46a30861fba8cfd4b51262eba4138b41a2d13ddc71128c8c1242e49a51d6f49879fcfa7595ba4a4adcad3670b0b1b26382f03ff402bc70150f54bf513ba3e9a590e41b269e55616af297ebb3499e16cc8e46c0810330a602955553c0f93d668a1181a0bfd7021ad9a9f68ce39493b012da70a3dda149d0369f23f788616e0272efa322b6a54d804f340d32c890e2eb7b538f48f4c9293b584d22d0ae80d321607644271b81a76ac5b49d8e457069b0c3e909b8a222e3fa6016cb1e979e300804742f2005c68acb7b1849c088b3714c9c7af54e9de9390df0041c87924c8fa6b0aec6b6754171e059cba0d27f221f0b9d044a3aed8338dd8745651981e4b0329376f908b86ae9022699d495bbe3a148f7eb73d56eacb2e5e2180f63fcbfa680369f88eefa71f1210bc5b6b7b957f0a1437476a2112998033197673e470dbe7d9d476c97b95db8b5136f6cccc75d6e0ac1e4ace30e34e64fcc4d7e135b2c80e863ed701d3b28c25e982f1b5f8c895a4e6df7216c3c07abf8551a0ba0469c88aa7a08c7b5218a03b9b91f0935985373f65aa56286ad0e7ef2288a926f172b098123c136455b3a0f04590839e16bade7b6434a3cf048abe2612684c03dafd9cec39af508e63f07ea881014697bc24122058b5ef5d3fae835216d055f0cdf1dc06a12c95041d13ac9e15f235d11747f16ffce1cc3b8f508da520e395edd471f3759d8879ba9c2558b1188d822fd4739ed0546b0ce3bb9988db7c1dc8518ebbc62c4440e6e0653f917dcc13aca1864b71dbb67dbe7117474c936414e4f3cfab1f13eb05f3504484ce11977ab21ec523f97ba1b7ecb8fe384b634c30561cdb752fc67a2316bfa7e4d03f5f825d24a556a0460d8cfe0cc54a6f117ac52d553a5d1bb48031732716436675c5c3996b1939b127c6b0338bfaa29c7467cac9a127e455a715c9ce2b0c35a0d2f83a3d1273ee39399e6cc4980e610c752bd51652b96bf9cf34c7fa41fc9b13f5d55007483e4082ddac4675baa7822fd257452411b01de0e5e5da26e17539d64a89dd93c71d15a4c95b1a83039cb2d5f3f7fa04a817e48dfcbfb3de34ecb47f7592123caf27e17982fbfc8597af5b8aa6558f4e6c73db69328e47677afbe6ef8df82c3d1f0db6a108b2279f61822908d7b856432c32ac5ec0f3c53befab2a7ca356b9c2636f646b228b0a830d348be4ece2271814d477d4c73c0fb6e83a338b90ec4ef45cb25f7e3d6a014a9e8d2e8a6f55a383291a57f15667a73ea1daca31c7182523ca85a107efa2518d2f7f179ed4ba21fed479ef2be09669817133b2384bd85b155dfc1c4c9e6dd9ceecf06cc1ab8ebf7f07aeaae7441468b5471aed93f248a84f44c59be33274b11f651de010ab9f8fb24d3a99914e0147951c34280e7dd15ec196f9a4c86e55e7d373c7e31e6672d1b3ac6a45fa6c8c9088c0b8963d89f4ff1feea3e85cf9cf2f6c97128afd845bb131c6f62b3282bbba42745080fd457f1d3322058f1bd4be876bd01269546d1a853310b165926c1fd4e07054deb5d3fbe8f6007711d435994005aba95918c3df4cd390b165fcd139dd418ebbf661b6de57b655698a8a02ca8fad73e8c536c7110957c36e5494a831d536eccb97a2a9ef58fe58e2885aad170720ffcc57c7de601ea1cf723577a30aad8fd544317e33897c8b6c04e5191bec391ab990e197f10038c0726d371677e4a54c28d7ca5c6046e7cc4acde565b91f7f72af6109a0614160d3ae97e9257b8f71a4663b00c681e793cbb478306e97b0e04711eae7722b4845dadf2fff5bbe71ff24acffea2ee67df99bf62a098ddae9d4ebd3bc5dff04a2d9e3d1d83e8f493db3f63c9e24231b1dbe1147c79f21b0730c842f6983330c5c17dd34556d7e932074cfbe98f2dab5b0ebfd778a1e28fe2bac2d942f61a08b787ebfcdeb3d600bb130ca4922a4ffd38ffc4a1a1a7218451e45da4da67ad81ef898ece3d54cef877cb9d09f5dcf72eccbbc06e62f1e2b4d64059b0a807329780b155ce1614b68de04387d6108ef4dd3ab54b9da72e528d6eac3e16a360ae3421f3f23808a8b5e8ec3dbefcbca3c9f76905850033d78d9283bba9272c475b4e3b4d7643e62c2cc259ebbf168f890de88e82f8b26a7654ee31fe055e45609c70ae02b4942ee15678cd158f4c9e8d351d102ddf7a942458c6125e1457bea0d86ca38cf0c26e474b2b5cca77eb57ad0867cad7d25efc2b250e79396637ea3e948dbb855029cc9b452955bd04ad5a0d0514d4d773c0f298df7bc235a3ac64383a1fbd8a397a158e936b3ba81895a51daa89f51e4ae7a71a53794ff715a42f4fc3dcc9fd56df7bea4ab782534d3760e7b15605fc4dad16911656983c0ab77bce9445bbeb1537c55fef57a32c8f1404306a0a2ca7b73348cd99d0f9948875531cbb0ef7c036cd201614c33293d746c44140e0e8f82421c5bdf2bf428b249597df949fafdb5ccfe1618323f56a6ab9abab9a84a3beb6696ca918af244d34cc1cd95bbca4a87c860a0fa9ff6a04a905b0338a53f230bd5ee9c60e0e0332ca200c15dca0be5936b858d0a7b2e540b8958432e9767396c55d5cc35b60062580023b5cb2f9a5e9a1feba59a19f9a5a251e9d0e8500955a5df21da95213ced2260a2ed8f3d4b295c36cef750c89cf21985c302d5cc577aab7855409a912dbcf1d0a9800df4aa692a78607a40fd6d5a82305c58fcb3d2a82b27e8c5b91681aae62a2bf31ed55c494dbdc38eba30e83c6044945df76705228eede8470369f2e9941ddcb2f239fb3ff6bfcdb0efb5ec50f981adf0e8b213769ffbbea364b08cf8cd69abbfa2a6fe9865cc48558134a57bb5526b9d047e14a379d246de82d3d64f3c810ede280c768dd8bee25af287d5a8d94045ddbf5981382bc716ad9aedfcd66e0ab496172a24efe80649db8e1e83675fc8451e22c6564d8d6dfb285af7fec802b35f19dd8308c68952a11770247fcfecc4ed0e8a445c17b1573f0b4e3ed350f13269ceb572943fc435563459d5044699f1542335b03be6077af156b8c5a6a9f71078ad820cec4642427a9b187ee1b17036d5a5e6108cee8a7d444342eaec3afa64e77c71d3c2b3153d4e2dbb30df2b66b4d14cc45d3a4eda7e911d697e5763e23ee05311a20626df55549b8533c6ebe79737abf472f9cff08bec590943bdeb819d3f923f45b81f9a0cba1f3f800a261842d10cb4cbdba456c7fe5f0abb4a8b58891d97cfd6b669e2708922f1934809d51a1589e5f12e3bb82c9ac3e7e44e3f6e6cd63d428da624fd2f46eec38ff798a90d228efe50c9b67c63796347c8a2b53478f27605999a03c8e1f18b70e92419f646a7f49670aa12d324751aec17d0208fc296955b3098241189af8172d39a6819415cafb107c1842b369f174d6f37dd31cd728dfd0ab10f93609006342b6e4d6ccbfd1ed2bea2fdf5411442b04b1fe218916f159b20242f80b535b4e0a3024c6eff6a40bd0d3db24e51f5ff9c14e1b4a650ca4170ee70f0a3a5a58349a7d0b7a63af86347351696870b95231f76d8c5c6a20736907726341dcbb76672871d18c2157c094b929fd29d34f5bcaacd82706f89a60000cd341d98eb830b73a12335b69f3e0131ded3ce12c98bbd960d2d0696d40696a13ab43925374498d868cd8f070c9039ea6407fc2d92b9c39fe7c935bbcfcc5c0980952fb7dac79042951f49a1af828b138a87401c4104bc28cdf1e39dbd3fa63dd4d5f5ae9d85f032a43ad353bc5e6746e5a76326ab1f4e79103116ce70bc0b459200f32f85e461291e347dda92e421778b849e37a3ecb0b31ec6818e828dd3148dc74313aba43cc9d8b9a36a9dc4e229488060eb6c109f8ad6201958adec6d3bb3b04e5e558a272d44cb98e18f7a0ad8fa6ac3667a62f150830aa930f6166baac6b9081b44304988fbe1698a5b746255de26bb5988aca90bb6523cad68a7572f615f4aa58f932d8a749615cf0a7724e99de042268ceb31433e6df0a61547d576a6201b36b348c028ded5f7e94d1cd2eafc141088ff42cb3dafbbe4c402b93aa9d955df8d9d9fb57c75ac65c2c837acc44bbd4d4aff1888aed46c73d625ad7fff035e8ca0fe411c73ed8135b6b8e17a039ec74e9de0d64cb442bf8a676c0a666f68f21066332cd921ae0ed766f0516a8e19b82cf98e78add0373737a3419e13aa902310c44feae5fdf8bc64e80dce772686a31f141bcce452041bf545b908ef4a2b000e7beaf378e2afdccbbcaa42e330e5024400cf2852d3444718",
+ "fd5008477b0855f6f2486fd4f74b9fb4f6e19726c6996bc66893183bd76054d5b05c1c2b64722256ba912ab2dcca66d2abfdf972966438fff7513acfb18ea461eac08c4e32aea4ed3fcf9f1c9905ee4402e7b6984bef974340d212f160b6524b76de99a98d3e96cc0d35e8a63ad7ea3cbea1d40a906c4dd03e5fc19e1513e9",
+ "390a5e75c9ff4ad38fb6205ff47f209294337c1f25ff54a3c01eee8e1e220257",
+ "8bf183347ec1ca4bceff3374",
+ "19fa2641519e21293094e9d767ee1237f9e0715dc57172794867c3bbe2cb647f9b28a8d3f85c0ff557b91bad66f5ea16e0107757b0277fdd3ca05bf47c19bcb92a958a57e8c142a51af29bddb20af84377b6db65f77494e0dc4d2634a776b3a5d777319873bc0dacbbd4b9ebccfae849fa7e9769cdf54660ecca0d5cf4fa5190713726d54d02b3a3f21857125b8a808c0ca2f99d11dc430ed5113ee49ff8f00bcc08f0370dd510e8100e1285659a7b2c7457a6049f2af7786c4db1471ce5bd164e11c7a2165e83e03a135ae2b3429f82f677de044a067e99e0bda2d65a7270d629c00e1d528212d3aeb2896e58ee5145a93ed06a9c00705ad5c5988d3a192304c1d17661d45257c5d16799ef70771964435b12e3b2ee9d5b467c3b1992f45b7a59871b40d8daa1c280747ecb3d170257b91df1f549ce6d66455b5b6f60b7c6e95c92a67e20cffe8599ceb183de53f1dedfe19bae836447af8e053ba419660e0912cad064d6125b9e978e8d0d5f28f8a4e43ca3cdf2d4c0e9a11221d8184e9eb6c90761b0beac82d0d22793279aedb1c7db3632adbee323bc3bbde4801152694831abf5676979af26af7dcbadfba1cad1306b635840cbca76c558b37db0803b4c12befa27d16f21506b07ade4a838d6beba1816eb29ed5e3c4f132a752fc747bd9ba879156e87e6c1584e911da9f796e1fa4a055e427272559e4bd6d0f54b8257100f8a55d84c27b702bb1fe2f995425c85fd48b0a0610db5b39f7a5031407a12dae9f508b21b1378f14952d1beb2dea81d016b2d9b7f1a67b814569b69c0e619adea02a8683242d63a11d3317d060e5b4d85df5ad73127541ba5314715d187990735aa81f438f8b94070ec506ba536274d98b766c1694e54367891a602b99e370425b47a70b819277a249fa429c5bbd0530267f987e6022f25030c30f3baeedc0d13c95f3d5e4b2b87465d179a3a23b9f9e76a42ceea55226ce072f9488392f40621289124d786109d2498e74fb37e2ef466fe8bf3016d96e34204c32978775765aa80461cac48518157f86d59f6187bad4ee62fba1ddbe166b29452f4a59af1e057300c353440644a8e40ae8171ea028be2fa315804abf518847c7945e8228b7766cfdb08d3a3116b59aab8e94b6d8c8c9ef442c2dc7f923bc2cd3e5c663baca7dded976bf191fe36da16948c89c385fe71434f4aa5dd15fe0e925d2459e3b068b9d82a9cc8b8f9786bd9f5fef9baaaf2d67027d9bfd58bb2c58ec7c746b747ab62f9242e4b53ed14d6fc75f5280eca0de23717c97a2293826e19cc8eb47f946421516c349dc4ba49225b91e4e868874bdebd373700df1f3792aaa140597e58b88f90e163397dbad3941705b53d754e3e0c9003df836a7fb8d23f40362fcb5f3947a4281b24240be4ee89aa8e917b194f94345eeca224df0adc15f22a617b6427f29410bc48ea3f92216163785723efc36301d23ed52780c6fd7924bcfaa03269b13582b7c7ea9c0e4a451f38a469fbdb585dcb7c81452da77945ebe27eb26ff6e8c7b2decea289aac5af74746dc257c9bea44a0847f02c4f586e1d76f39d5bf952355a0875f177a666d1d354ad86ce5ec0aba2c2b20cab050eaffd31095395132f5af80a2d2d53b77bda49f948bbb37bdf31c8a690476488e14e542ff6841e7fbfc2eb84795696562d079dc1612274b6dff362567084f793f0bc2dd8de23392d05aeeeeac6991c9f74387153a4b7da94790375e336a00c8293bad0fcef2dd1880e7094e2e53f738247c860780ebe308410ca02ae409ae720e841f48c9677acc6e7d4ccd18c219c400f8b7e1257f692e09eaef96802b17a1cb7d93eb81d3bfcbc7af4cdf05b98e22556b3d1a8b56d6d83bb5f5724696f8f329839dbe477483ec3c09fa2e0628faeba1bf285c224bea3f6cdc7bbd768133c6ef1da14f248cc3b819b196588811b073a7291817bd1e89c65760435d8d17cbf9423744a92143e0f956e2977b39c54fdead5a57f3a04a0facca01bbf44d3b1fb9c4fa83ae1046985e3f26aa0a437999004dd8adc04c5111759849f919b93558dbc559173a23b069b59f800096d9fcf077c7640f59170bb9a6fffe64778bac272365d27ea62aa956559e90edd3f6393cc8775597bcf7d91990ab9511973d948324a27261059e93f4b5dd2f70caf12e1a08e0493cb05588618764391f355379578cf94dd33e616136eea997ec11c0d4ff064ff51a767e5558433a2e3a9a74c232d8e187f47b8cca010709eb9fea0dac8f1ea53bf18822e154ecd929c83b0eac366e30fffbd5ba6a46d734f58d26e7f5df538e18b3d827884aa857a680823131bcf30a76f1a555bcabb17b02b53aefad96fe76f7312da69719434c580d3ff1bcdcd594e6375935003d5d732cc577e11ea2abb1d04259f50aed4c3af9866e8c4a52a09809046ee330f05c4403acbc297a9416c5208fadb31ed4eb7a3b01b87bf08c75cf44c2b0df84df30872d021d6567ea649859268e5e1b5b6405e1b41e350a32c1af13722959c17c01b52c42241313b26b25995a1c89a53e248488724d280647226195746901929501df36d1e94815d7fe6c4ca2731f3181293217f71b9d7f59c2474856972013924ae4796db4cbd22d8905a6043c959941ca6b556c53d1688c439036c715d33a47a7dfc2fe40e53424c5093020d2e85e4b04aa4c704ea5bfe5a2384878da38319c59d41d66b6add2a443d9ea11edd8d18fa41004251653857733b388b453943eb33df93dcd5d549757fa2967ef0f9a5105836c48826c47fcccb2d9bc349032b286962136b848632bdcf186a08cbeaa52d195efcfc3a440bac154971d11ff4994f293b14fb8c3214ebe7ab8b3d0f2fe0b03ed7b145fafd7730a173e3cc1847f0cdf2cf629f5ea81a07bef716b1a67dd9e3b7a52fea1aaa7a393f53b5bdb5988df78a57a9dad19a8253316835acab8a6b9a9fb42d97bf29b2443322f46de386fd82bd3453ed68e2370c6eac4497b1bde7b42d569c452f377bd38bd50fa5a6792ef5c9ec6c647001149b86fedb3e2f18d4271e9cc4801aa16ecddb31b6a795fecabc613bfbc8e4f5636d71e74595c841fd11b6a6bc7f169317c1added56b82a71fc36d774bb4d661685363e9da5fd2e1f357006dc5b5bbf8b42ee3f869e75a541586fba558a8f490d641b78c27368b9b4c2db046354e9358ae9140e91cd95ebeffc6c0d2676a3ff4ab10d463bf32bed97023a80a79df191ab9858c43537a03072a17c30b1bd99efbd361590ed6b7d5b0ec4e2326fa35904ab9a48596f44491cbbc0112890f9386ed04dec30126be359a05e99b2b77fa2c8f6b7460a6cd590d71c73b2a1b23312ff89306b6e41c76ddc0a099bfa79498e36ae5cf0c560b8854dff32d2b690ce0ac4aabfa723ac6f2e97ad1083235196b464ad67fdd649aec01695d55c8b4bb198f30630ca635aa5a1915f3718341bcfd8b522f764015fa5479004d28eceea7fe67df7ee24a97a9708d528b89589f1899f13242a0d00f7464c3cdfce213699340e754533b934f4a8410224e111f31cf8e54d7b5e90cd8c68bf96edbc8d183894deefdf4fcc1a83162a3f6341dcd9a9aecf171c0df28257a68b1af1b67c54c43c3cff27fed89cc64bc46e23a49ec74a9efbab7981d9f0a018247441e4f0f5b5f68ba9325582f92de4cca4a5f878a0c5c387581e64324e3246d8f3205c838a29f1abeea24446e496421f0e742d411adb55f70272ae4a992e825a3d327e44b8b3762b25aa451d07eb4eac0322b431fa676462632daba2aba7bdeee1b438f051d21d4b1897e2ac2f95ee7c23f9996a805de8fffb3b30b855cd6c5b84c011accf4bf94d304d944079f04b5cadf8fcd6751c22a0f9165ab98998b2d89e6514641f1f3b91b8c0bf057d69c3d893fc4e041e06a2229e2ee58082ffb58cb920972ede58483287d0ace94c1becef26a410b93e4ff402e61dcc574b790d49679f18f4e2004f8b7cc357faba34a80e56821bb5b883d1a8b49c6605002152f270bbc36bc79095644e29ab08cc988deda765d67e4fff12b726d5de135ff9d0cbd9d5f9d440e548836633b93a38330d638468b59a32642da3375cdf70b062d14b46a78569c24a706e179baa2058dcae5c61fb6cadd9e015b017f26e9dbe3e6366cf5f1ec839aa3bbb21dd6c9b8e910245fa95b09b7d6cbf08a4c6c84bef257a70389be962dad14d97a893c128b73bf6580689e540d004f21edf8403f36b1ad7c9a2e83ffceb141af59700c316c8c1e3347187f24819c2ff0c9f9a2360dce354f3374374eab1643d2d8831310a8e3ca6768200ea7759822b82f7027cd450479fcc7f6d04802b15735a137ad489f1e1ee78434a253a9dd16684ad58fc91960cde6754f82e8b38edd5e798fdbbbf8fc2e2380a4e21dd94f8c1c063b18f29d8cd8d89f65deac5640799d4ca2caa29c1e72ad8bc417490d11e4051d94956fbc74289857e5f8e9e87b9a2d83074a994de0b10bc7782f6650cfbdb8c835c81cd88bdce5f04ca939b3c5cd010d4dc5d51224fcacbca9851694b8bf55b22dead859d023eee5a7ad3436a912c3fc0284456d5d72ea5f1afa8545c856676ac2dd9a057028bd3ca0f50e7070fa74152f13997c95c1834c3e67504f1a4165d2b49a96919b88f72caed60f56ca7ab5a3204fb12ad3592c725fdebb048732fc189c7dfed185c6c184a626e07d7356860d00389862d5b9701eaa4e5f7889e6db0f54633369b8d26805c08471de8fc3f8fa1fb0b0711d9e015add5373f7f8b64abaddbac3399c756244b1b07c579d33e4967e5e0cf16de29cb8a7efad07ff9039ca305772a6e45c76bd9b77e24949556766a8b8425c5e595efb431bde4ee222f9eb3fc2d002a1e2d14db2b23135266c942eea33bffd30eb0218405373240e0cd3040436ca895093bf056fd001c00ba59d90502042e6e6c0167105051628895c8164c9ab959400898309cabafdef12be53604fa57df44e0a90a81bd63c331291a93bffefe809e80db0679568f6e94e0d8e2edec0087c35bcb3c4f4725e6013bcf197156cd9d90612423348123383e45c14d27d8833f56ddb04083c069fd6e282fe69c940840f5f747dfb72ad72fd8cf9f3ded15c9e2f4727fd60b4f40e95dbe77a89b47dde7d5326942600554905d9dade9d145ab6da802643f2081678392609c2fdd1b79dd8caec137cbed315374c6f05c0758070f3bb17e23d81ccc39c6aa89913897e487fde889c5aacd422278f8571641cc4f0a93d9768aef9e45d6bd187d1ba637ce0fbd3c573d6778cf7bf5188c00dcdf13be3fd599143952b376220283e34e014e83b214bd5f64eb0ecb098ae8bef883949907cc36e22ece60b893b963cfa73d120513e285aaf70ce5add34edbdac60b3aa7b385b90e339058fb9b3cf984b06f79788016035c5ce490f2de7995b98a8c1c9c80f29603ae2b7fc41886663163e604275cb085f8453b27f4d795b9bad19ade2f98a1c99b43a7581bd991e5d0e5e1a6e713acc522ba9fe8302658a9782558e35436e714ac6bc85ad1d3cd008f24106901fa954f5fefb61210d6f8dc9ff35c480f1d14e59c0e501917a31ee9d00c6bdb06a00af5a8b08c3928cc5f37476248223627cb77eaf0e96213cb0a13e97d3fe9b9814d462690e8d68d02655a32fc271ee73db4f88a33386ea88a5857e15a28d9b3e3a96f00c7cd85aa53f9282ab8c8ca6d6a8afed43aa87fe7fc1ad59b0f0db2dd25c20af96e8c282c19fc883ef01a4060398926a1c82f07bcd3bc314580d7636b623b7bad8ddba05850291a6344df0f346fa4a321a85ee3e9c",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b",
+ "0942e506c433afcda3847f2dad",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff4b4086fbbd1b6cec23e45481eac5a25d",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314",
+ "d3d934f75ea0f210a8f6059401",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff7c59dfe246e4bb2d6a8afcebdc2beeaabf2a3f43f95a5ea639853f38719875ecdd2bbc0d81bb2a5ed59553b1e76b6365b74f618f685eb7731024bbf6794c3f4c7c5a1cf925",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314",
+ "d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc07cbb",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff7c59dfe246e4bb2d6a8afcebdc2beeaabf2a3f43f95a5ea639853f38719875ecdd2bbc0d81bb2a5ed59553b1e76b6365b74f618f68a12d0f1cc99e132db9014100d9668c91",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9b",
+ "bc",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff7c59dfe246e4bb2d6a8afcebdc2beeaabf2a3f43f95a5ea639853f38719875ecdd2bbc0d81bb2a5ed59553b1e76b6365b74f618f68d1f05b5662cd6e04de896d3ef5dae4149485a5a2093ff4ec74b20b5e5bf8e61b5c65515938c202beab3eea5a498d2f32d4d00a24b826b6efb16013ef54cbe170",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc0",
+ "7cbb22fce466da610b63af62bc83b4692f3affaf271693ac071fb86d11342d",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff7c59dfe246e4bb2d6a8afcebdc2beeaabf2a3f43f95a5ea639853f38719875ecdd2bbc0d81bb2a5ed59553b1e76b6365b74f618f68d1f05b5662cd6e04de896d3ef5dae4149485a5a2093ff4ec74b20b5e5bf8e61b5c65515938c202beab3eea5a498d2f32c38dbb37d04f8272e741da2802c54a9d9aaf8ecf38b36fc9ad0079523f6a4abd5281a22697a3180bc02662a7c13ee23599d18e5c48300dbb831509df4c172f53e524b3c15124a87ac73e5028cde6c94d8d",
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525",
+ "",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b4b840629564020c17f5c9446882e23f610e931246ec434e62de765bf22954cfae02b2ff7c59dfe246e4bb2d6a8afcebdc2beeaabf2a3f43f95a5ea639853f38719875ecdd2bbc0d81bb2a5ed59553b1e76b6365b74f618f68d1f05b5662cd6e04de896d3ef5dae4149485a5a2093ff4ec74b20b5e5bf8e61b5c65515938c202beab3eea5a498d2f32c38dbb370a9bbc3187cc260ddac991f94ce4f0d5",
+ },
+ {
+ "0fb826ddb2eb5e708de203d0438be12cf708d635ebdbae56278be09077009586b9bc646ba7c2db35a5de05e86ae71461efea96dac64430edcf117d461113cccacf303576f310ab98efb180599894ba877e50614494923163a3afa9b4c2757f91a6b40799c5b331b464b10dfc45c783c317e408ab76390e19e8b7ceaa2c4d3bd201436bc6f69c7a5a4d8756924ed95665bd5e1034971e4d80d51b2a",
+ "026866d46aa940309fdcabf92a324fbc",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "30f05cf8189bb7b8b4f560e746e228c4cc7e86e8f2fa66e1afe212d1855db51070acd5eb34ce80b2e223957df50fde4c2531d97fc9e573725e7a5e47f0dfc4da1942620320bb2deaf8b17937bae4218d04db8e76f6efe84a117292159507c9f8a09fb2c17921d7762510dbf1dac7b62b1bd7572e3e2cf008d01c445c7fa78833235034281ae180e051451c6a64f22ca9708634bd0d604e4cfcd971b13742efa5b6363e662a875daccb2b00",
+ },
+ {
+ "c7d4f8790e4c47d4daecbddf5939973521ddbf3b832e564afc66f03b5583c41c58bd956609dc3ae3c8f7c2213059575236168dba44e3044049f47c9e7840bbd0fd5036062d70e9f567ac1797056ee93c8476f6c959fa09a3ee854166c6fc36c34d6cca7adcb36f435f86db65f4c4a1793b974294914b377fd179e697751c5ac289243c65d8aca93732849c27483da083d4e218652d4fe5fec8cb953ee7f00070143dd6ece97f241b03c0424bfee2cfd2c4e738f2361df0ffe8863dcf763d408a7a167763959b7f985bc1e359a4b22c6899645ad0814bcf69d10c38474978d1c48e482723e3a6bb3f689f980c51c474eb28cfbba91a8a12eb964b32dfc303a3524ccb752f71316ed9d007e521cb5a0cf429c79d4351b02ee7fb60c7be636a10af3586dfa7b74d80875466a820c0b514e97cb12cce615ab55cba7c1b1de72bcd1cb1acc368f944ef4eaa986e6a4d8253c9337f9795d94df193c90cb0b0387dcde929905223d441717ed9dfe826613bf094ba872993d41b269e27d74e5f541b497eac9ba180dc12ffb6f1e7dc5223cce6dd541071282b97c6526e15b2c330fb41dc96e25d72f45c28e543053766d11d44252db54e584c14abbb295d7e5a58bf36eea1936095ef897a338eb1995fcedd85fc92d354dfe7ff9a115c186bb4d7a1a27835030d248c87571a38f17906cefe0261d15740b9",
+ "56",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "f89c825ca43cae1ce3fbdee85c505edd1aabefe69a0f9efd740f027aa7dee48a91ad24e69ad061648f0a52b4afb19d7ffccdc21f4b4247dfd89f5f9f998cb3c02b226173fedb6f8770aceef9271e7236fefd19fb3b87d08a5c587ac7918e80aa4b477f22602189811e270d686bc4949137a41d11d95ec96ee9d26c6126f6e923ab37638b34d1538d2e46d6df6216da4f193a3cecb731e632e109ced643056a1673059355d2d1314df35ded8364efed7de490201090a6f2d1751748585f64d26041637ba3723cbc4b60e226f10a19699d223075bc1f27d82e7f560c0db630ea670b3f8a70a8950894af4d1c7b3f674a3fa00d19ee4cc2b6174c1d259a297424bf2c3943a29a16a9830ce11abaa79cd2eb77b53a02b365b1838e7bfd5ae1bd044ffc885c61c6b2186a357e8b8f732b7ab96517969aeb70c7b493bbaca9462a61815a3c6135c748bf9c8487ac0631807aa69243fa09cd3b8efb63f8d4e090ad30b6c2f08bf4e82f191cedfa5cbe2b42268d67ecd105918181e44fc9879efd642d20be84e6f74717e03fb94fcbaa6ed3b307431d2a9384b8a2b3e5825ffce8d99af48f177e43bb4272226d8a5edd37d53807f768feb9e0733b437a1d0f84779ab68a1804e92a5eecca56364f0fa6dca152203b249fdc8fbd950fdc37c1887596308a90ba3a5751c7096bfbd1cb177bb17847b33c4379b43938a67674459cd9a06e3017ccac5b",
+ },
+ {
+ "135a28170fe89066da7bcff3a9ccc1b27dfe942a6f47b23835ef746aaea63dc10066d90f4e697528e5451b8e11dd408fdbd4b94a1c6c82515bf7bc099df9cb9d5fa4acad0d22d5f267f18078cec107a995c1f3b12d7603886dbf910ab85ca7180053c50e759b00dc8c81555a425c03d71df6894a6c8cd2d94b64e303c08a1bc1dee1cf537ccf300850856292e1656aff5bf349c87f1ca1ca8085cd400fe901edcad04146a0714ef0f6b083d715edd670e020385f3cda29bc5ff6fc6edffe5ca9ce9def6e0e3d5f04ede2db02cfb2",
+ "73afd2ab0e0e8537cae42dc6530dc4afb6934ca6",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "2c125232a59879aee36cacc4aca5085a4688c4f776667a8fbd86862b5cfb1d57c976688fdd652eafa2b88b1b8e358aa2110ff6ef13cdc1ceca9c9f087c35c38d89d6fbd8de89538070f17916ecb19ca3ef4a1c834f0bdaa1df62aaabef2e117106787056c909e61ecd208357dd5c363f11c5d6cf24992cc873cf69f59360a820fcf290bd90b2cab24c47286acb4e1033962b6d41e562a206a94796a8ab1c6b8bade804ff9bdf5ba6062d2c1f8fe0f4dfc05720bd9a612b92c26789f9f6a7ce43f5e8e3aee99a9cd7d6c11eaa611983c36935b0dda57d898a60a0ab7c4b54",
+ },
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
new file mode 100644
index 0000000000..f9e8a3a2fe
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
@@ -0,0 +1,199 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3.
+package chacha20
+
+import "encoding/binary"
+
+const rounds = 20
+
+// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
+// and 16-byte constant c, and puts the result into 64-byte array out.
+func core(out *[64]byte, in *[16]byte, k *[32]byte) {
+ j0 := uint32(0x61707865)
+ j1 := uint32(0x3320646e)
+ j2 := uint32(0x79622d32)
+ j3 := uint32(0x6b206574)
+ j4 := binary.LittleEndian.Uint32(k[0:4])
+ j5 := binary.LittleEndian.Uint32(k[4:8])
+ j6 := binary.LittleEndian.Uint32(k[8:12])
+ j7 := binary.LittleEndian.Uint32(k[12:16])
+ j8 := binary.LittleEndian.Uint32(k[16:20])
+ j9 := binary.LittleEndian.Uint32(k[20:24])
+ j10 := binary.LittleEndian.Uint32(k[24:28])
+ j11 := binary.LittleEndian.Uint32(k[28:32])
+ j12 := binary.LittleEndian.Uint32(in[0:4])
+ j13 := binary.LittleEndian.Uint32(in[4:8])
+ j14 := binary.LittleEndian.Uint32(in[8:12])
+ j15 := binary.LittleEndian.Uint32(in[12:16])
+
+ x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
+ x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
+
+ for i := 0; i < rounds; i += 2 {
+ x0 += x4
+ x12 ^= x0
+ x12 = (x12 << 16) | (x12 >> (16))
+ x8 += x12
+ x4 ^= x8
+ x4 = (x4 << 12) | (x4 >> (20))
+ x0 += x4
+ x12 ^= x0
+ x12 = (x12 << 8) | (x12 >> (24))
+ x8 += x12
+ x4 ^= x8
+ x4 = (x4 << 7) | (x4 >> (25))
+ x1 += x5
+ x13 ^= x1
+ x13 = (x13 << 16) | (x13 >> 16)
+ x9 += x13
+ x5 ^= x9
+ x5 = (x5 << 12) | (x5 >> 20)
+ x1 += x5
+ x13 ^= x1
+ x13 = (x13 << 8) | (x13 >> 24)
+ x9 += x13
+ x5 ^= x9
+ x5 = (x5 << 7) | (x5 >> 25)
+ x2 += x6
+ x14 ^= x2
+ x14 = (x14 << 16) | (x14 >> 16)
+ x10 += x14
+ x6 ^= x10
+ x6 = (x6 << 12) | (x6 >> 20)
+ x2 += x6
+ x14 ^= x2
+ x14 = (x14 << 8) | (x14 >> 24)
+ x10 += x14
+ x6 ^= x10
+ x6 = (x6 << 7) | (x6 >> 25)
+ x3 += x7
+ x15 ^= x3
+ x15 = (x15 << 16) | (x15 >> 16)
+ x11 += x15
+ x7 ^= x11
+ x7 = (x7 << 12) | (x7 >> 20)
+ x3 += x7
+ x15 ^= x3
+ x15 = (x15 << 8) | (x15 >> 24)
+ x11 += x15
+ x7 ^= x11
+ x7 = (x7 << 7) | (x7 >> 25)
+ x0 += x5
+ x15 ^= x0
+ x15 = (x15 << 16) | (x15 >> 16)
+ x10 += x15
+ x5 ^= x10
+ x5 = (x5 << 12) | (x5 >> 20)
+ x0 += x5
+ x15 ^= x0
+ x15 = (x15 << 8) | (x15 >> 24)
+ x10 += x15
+ x5 ^= x10
+ x5 = (x5 << 7) | (x5 >> 25)
+ x1 += x6
+ x12 ^= x1
+ x12 = (x12 << 16) | (x12 >> 16)
+ x11 += x12
+ x6 ^= x11
+ x6 = (x6 << 12) | (x6 >> 20)
+ x1 += x6
+ x12 ^= x1
+ x12 = (x12 << 8) | (x12 >> 24)
+ x11 += x12
+ x6 ^= x11
+ x6 = (x6 << 7) | (x6 >> 25)
+ x2 += x7
+ x13 ^= x2
+ x13 = (x13 << 16) | (x13 >> 16)
+ x8 += x13
+ x7 ^= x8
+ x7 = (x7 << 12) | (x7 >> 20)
+ x2 += x7
+ x13 ^= x2
+ x13 = (x13 << 8) | (x13 >> 24)
+ x8 += x13
+ x7 ^= x8
+ x7 = (x7 << 7) | (x7 >> 25)
+ x3 += x4
+ x14 ^= x3
+ x14 = (x14 << 16) | (x14 >> 16)
+ x9 += x14
+ x4 ^= x9
+ x4 = (x4 << 12) | (x4 >> 20)
+ x3 += x4
+ x14 ^= x3
+ x14 = (x14 << 8) | (x14 >> 24)
+ x9 += x14
+ x4 ^= x9
+ x4 = (x4 << 7) | (x4 >> 25)
+ }
+
+ x0 += j0
+ x1 += j1
+ x2 += j2
+ x3 += j3
+ x4 += j4
+ x5 += j5
+ x6 += j6
+ x7 += j7
+ x8 += j8
+ x9 += j9
+ x10 += j10
+ x11 += j11
+ x12 += j12
+ x13 += j13
+ x14 += j14
+ x15 += j15
+
+ binary.LittleEndian.PutUint32(out[0:4], x0)
+ binary.LittleEndian.PutUint32(out[4:8], x1)
+ binary.LittleEndian.PutUint32(out[8:12], x2)
+ binary.LittleEndian.PutUint32(out[12:16], x3)
+ binary.LittleEndian.PutUint32(out[16:20], x4)
+ binary.LittleEndian.PutUint32(out[20:24], x5)
+ binary.LittleEndian.PutUint32(out[24:28], x6)
+ binary.LittleEndian.PutUint32(out[28:32], x7)
+ binary.LittleEndian.PutUint32(out[32:36], x8)
+ binary.LittleEndian.PutUint32(out[36:40], x9)
+ binary.LittleEndian.PutUint32(out[40:44], x10)
+ binary.LittleEndian.PutUint32(out[44:48], x11)
+ binary.LittleEndian.PutUint32(out[48:52], x12)
+ binary.LittleEndian.PutUint32(out[52:56], x13)
+ binary.LittleEndian.PutUint32(out[56:60], x14)
+ binary.LittleEndian.PutUint32(out[60:64], x15)
+}
+
+// XORKeyStream crypts bytes from in to out using the given key and counters.
+// In and out may be the same slice but otherwise should not overlap. Counter
+// contains the raw ChaCha20 counter bytes (i.e. block counter followed by
+// nonce).
+func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
+ var block [64]byte
+ var counterCopy [16]byte
+ copy(counterCopy[:], counter[:])
+
+ for len(in) >= 64 {
+ core(&block, &counterCopy, key)
+ for i, x := range block {
+ out[i] = in[i] ^ x
+ }
+ u := uint32(1)
+ for i := 0; i < 4; i++ {
+ u += uint32(counterCopy[i])
+ counterCopy[i] = byte(u)
+ u >>= 8
+ }
+ in = in[64:]
+ out = out[64:]
+ }
+
+ if len(in) > 0 {
+ core(&block, &counterCopy, key)
+ for i, v := range in {
+ out[i] = v ^ block[i]
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go b/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
new file mode 100644
index 0000000000..ca9663f52c
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
@@ -0,0 +1,29 @@
+package chacha20
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+func TestCore(t *testing.T) {
+ // This is just a smoke test that checks the example from
+ // https://tools.ietf.org/html/rfc7539#section-2.3.2. The
+ // chacha20poly1305 package contains much more extensive tests of this
+ // code.
+ var key [32]byte
+ for i := range key {
+ key[i] = byte(i)
+ }
+
+ var input [16]byte
+ input[0] = 1
+ input[7] = 9
+ input[11] = 0x4a
+
+ var out [64]byte
+ XORKeyStream(out[:], out[:], &input, &key)
+ const expected = "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
+ if result := hex.EncodeToString(out[:]); result != expected {
+ t.Errorf("wanted %x but got %x", expected, result)
+ }
+}
diff --git a/libgo/go/golang_org/x/crypto/curve25519/curve25519.go b/libgo/go/golang_org/x/crypto/curve25519/curve25519.go
new file mode 100644
index 0000000000..6918c47fc2
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/curve25519/curve25519.go
@@ -0,0 +1,841 @@
+// 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.
+
+// We have a implementation in amd64 assembly so this code is only run on
+// non-amd64 platforms. The amd64 assembly does not support gccgo.
+// +build !amd64 gccgo appengine
+
+package curve25519
+
+// This code is a port of the public domain, "ref10" implementation of
+// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
+
+// fieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type fieldElement [10]int32
+
+func feZero(fe *fieldElement) {
+ for i := range fe {
+ fe[i] = 0
+ }
+}
+
+func feOne(fe *fieldElement) {
+ feZero(fe)
+ fe[0] = 1
+}
+
+func feAdd(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] + b[i]
+ }
+}
+
+func feSub(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] - b[i]
+ }
+}
+
+func feCopy(dst, src *fieldElement) {
+ for i := range dst {
+ dst[i] = src[i]
+ }
+}
+
+// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
+//
+// Preconditions: b in {0,1}.
+func feCSwap(f, g *fieldElement, b int32) {
+ var x fieldElement
+ b = -b
+ for i := range x {
+ x[i] = b & (f[i] ^ g[i])
+ }
+
+ for i := range f {
+ f[i] ^= x[i]
+ }
+ for i := range g {
+ g[i] ^= x[i]
+ }
+}
+
+// load3 reads a 24-bit, little-endian value from in.
+func load3(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ return r
+}
+
+// load4 reads a 32-bit, little-endian value from in.
+func load4(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ r |= int64(in[3]) << 24
+ return r
+}
+
+func feFromBytes(dst *fieldElement, src *[32]byte) {
+ h0 := load4(src[:])
+ h1 := load3(src[4:]) << 6
+ h2 := load3(src[7:]) << 5
+ h3 := load3(src[10:]) << 3
+ h4 := load3(src[13:]) << 2
+ h5 := load4(src[16:])
+ h6 := load3(src[20:]) << 7
+ h7 := load3(src[23:]) << 5
+ h8 := load3(src[26:]) << 4
+ h9 := load3(src[29:]) << 2
+
+ var carry [10]int64
+ carry[9] = (h9 + 1<<24) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + 1<<24) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + 1<<24) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + 1<<24) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + 1<<24) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + 1<<25) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + 1<<25) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + 1<<25) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + 1<<25) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + 1<<25) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ dst[0] = int32(h0)
+ dst[1] = int32(h1)
+ dst[2] = int32(h2)
+ dst[3] = int32(h3)
+ dst[4] = int32(h4)
+ dst[5] = int32(h5)
+ dst[6] = int32(h6)
+ dst[7] = int32(h7)
+ dst[8] = int32(h8)
+ dst[9] = int32(h9)
+}
+
+// feToBytes marshals h to s.
+// Preconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+// Then 0<y<1.
+//
+// Write r=h-pq.
+// Have 0<=r<=p-1=2^255-20.
+// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+// Write x=r+19(2^-255)r+y.
+// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func feToBytes(s *[32]byte, h *fieldElement) {
+ var carry [10]int32
+
+ q := (19*h[9] + (1 << 24)) >> 25
+ q = (h[0] + q) >> 26
+ q = (h[1] + q) >> 25
+ q = (h[2] + q) >> 26
+ q = (h[3] + q) >> 25
+ q = (h[4] + q) >> 26
+ q = (h[5] + q) >> 25
+ q = (h[6] + q) >> 26
+ q = (h[7] + q) >> 25
+ q = (h[8] + q) >> 26
+ q = (h[9] + q) >> 25
+
+ // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+ h[0] += 19 * q
+ // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+ carry[0] = h[0] >> 26
+ h[1] += carry[0]
+ h[0] -= carry[0] << 26
+ carry[1] = h[1] >> 25
+ h[2] += carry[1]
+ h[1] -= carry[1] << 25
+ carry[2] = h[2] >> 26
+ h[3] += carry[2]
+ h[2] -= carry[2] << 26
+ carry[3] = h[3] >> 25
+ h[4] += carry[3]
+ h[3] -= carry[3] << 25
+ carry[4] = h[4] >> 26
+ h[5] += carry[4]
+ h[4] -= carry[4] << 26
+ carry[5] = h[5] >> 25
+ h[6] += carry[5]
+ h[5] -= carry[5] << 25
+ carry[6] = h[6] >> 26
+ h[7] += carry[6]
+ h[6] -= carry[6] << 26
+ carry[7] = h[7] >> 25
+ h[8] += carry[7]
+ h[7] -= carry[7] << 25
+ carry[8] = h[8] >> 26
+ h[9] += carry[8]
+ h[8] -= carry[8] << 26
+ carry[9] = h[9] >> 25
+ h[9] -= carry[9] << 25
+ // h10 = carry9
+
+ // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+ // evidently 2^255 h10-2^255 q = 0.
+ // Goal: Output h[0]+...+2^230 h[9].
+
+ s[0] = byte(h[0] >> 0)
+ s[1] = byte(h[0] >> 8)
+ s[2] = byte(h[0] >> 16)
+ s[3] = byte((h[0] >> 24) | (h[1] << 2))
+ s[4] = byte(h[1] >> 6)
+ s[5] = byte(h[1] >> 14)
+ s[6] = byte((h[1] >> 22) | (h[2] << 3))
+ s[7] = byte(h[2] >> 5)
+ s[8] = byte(h[2] >> 13)
+ s[9] = byte((h[2] >> 21) | (h[3] << 5))
+ s[10] = byte(h[3] >> 3)
+ s[11] = byte(h[3] >> 11)
+ s[12] = byte((h[3] >> 19) | (h[4] << 6))
+ s[13] = byte(h[4] >> 2)
+ s[14] = byte(h[4] >> 10)
+ s[15] = byte(h[4] >> 18)
+ s[16] = byte(h[5] >> 0)
+ s[17] = byte(h[5] >> 8)
+ s[18] = byte(h[5] >> 16)
+ s[19] = byte((h[5] >> 24) | (h[6] << 1))
+ s[20] = byte(h[6] >> 7)
+ s[21] = byte(h[6] >> 15)
+ s[22] = byte((h[6] >> 23) | (h[7] << 3))
+ s[23] = byte(h[7] >> 5)
+ s[24] = byte(h[7] >> 13)
+ s[25] = byte((h[7] >> 21) | (h[8] << 4))
+ s[26] = byte(h[8] >> 4)
+ s[27] = byte(h[8] >> 12)
+ s[28] = byte((h[8] >> 20) | (h[9] << 6))
+ s[29] = byte(h[9] >> 2)
+ s[30] = byte(h[9] >> 10)
+ s[31] = byte(h[9] >> 18)
+}
+
+// feMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs can squeeze carries into int32.
+func feMul(h, f, g *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ g0 := g[0]
+ g1 := g[1]
+ g2 := g[2]
+ g3 := g[3]
+ g4 := g[4]
+ g5 := g[5]
+ g6 := g[6]
+ g7 := g[7]
+ g8 := g[8]
+ g9 := g[9]
+ g1_19 := 19 * g1 // 1.4*2^29
+ g2_19 := 19 * g2 // 1.4*2^30; still ok
+ g3_19 := 19 * g3
+ g4_19 := 19 * g4
+ g5_19 := 19 * g5
+ g6_19 := 19 * g6
+ g7_19 := 19 * g7
+ g8_19 := 19 * g8
+ g9_19 := 19 * g9
+ f1_2 := 2 * f1
+ f3_2 := 2 * f3
+ f5_2 := 2 * f5
+ f7_2 := 2 * f7
+ f9_2 := 2 * f9
+ f0g0 := int64(f0) * int64(g0)
+ f0g1 := int64(f0) * int64(g1)
+ f0g2 := int64(f0) * int64(g2)
+ f0g3 := int64(f0) * int64(g3)
+ f0g4 := int64(f0) * int64(g4)
+ f0g5 := int64(f0) * int64(g5)
+ f0g6 := int64(f0) * int64(g6)
+ f0g7 := int64(f0) * int64(g7)
+ f0g8 := int64(f0) * int64(g8)
+ f0g9 := int64(f0) * int64(g9)
+ f1g0 := int64(f1) * int64(g0)
+ f1g1_2 := int64(f1_2) * int64(g1)
+ f1g2 := int64(f1) * int64(g2)
+ f1g3_2 := int64(f1_2) * int64(g3)
+ f1g4 := int64(f1) * int64(g4)
+ f1g5_2 := int64(f1_2) * int64(g5)
+ f1g6 := int64(f1) * int64(g6)
+ f1g7_2 := int64(f1_2) * int64(g7)
+ f1g8 := int64(f1) * int64(g8)
+ f1g9_38 := int64(f1_2) * int64(g9_19)
+ f2g0 := int64(f2) * int64(g0)
+ f2g1 := int64(f2) * int64(g1)
+ f2g2 := int64(f2) * int64(g2)
+ f2g3 := int64(f2) * int64(g3)
+ f2g4 := int64(f2) * int64(g4)
+ f2g5 := int64(f2) * int64(g5)
+ f2g6 := int64(f2) * int64(g6)
+ f2g7 := int64(f2) * int64(g7)
+ f2g8_19 := int64(f2) * int64(g8_19)
+ f2g9_19 := int64(f2) * int64(g9_19)
+ f3g0 := int64(f3) * int64(g0)
+ f3g1_2 := int64(f3_2) * int64(g1)
+ f3g2 := int64(f3) * int64(g2)
+ f3g3_2 := int64(f3_2) * int64(g3)
+ f3g4 := int64(f3) * int64(g4)
+ f3g5_2 := int64(f3_2) * int64(g5)
+ f3g6 := int64(f3) * int64(g6)
+ f3g7_38 := int64(f3_2) * int64(g7_19)
+ f3g8_19 := int64(f3) * int64(g8_19)
+ f3g9_38 := int64(f3_2) * int64(g9_19)
+ f4g0 := int64(f4) * int64(g0)
+ f4g1 := int64(f4) * int64(g1)
+ f4g2 := int64(f4) * int64(g2)
+ f4g3 := int64(f4) * int64(g3)
+ f4g4 := int64(f4) * int64(g4)
+ f4g5 := int64(f4) * int64(g5)
+ f4g6_19 := int64(f4) * int64(g6_19)
+ f4g7_19 := int64(f4) * int64(g7_19)
+ f4g8_19 := int64(f4) * int64(g8_19)
+ f4g9_19 := int64(f4) * int64(g9_19)
+ f5g0 := int64(f5) * int64(g0)
+ f5g1_2 := int64(f5_2) * int64(g1)
+ f5g2 := int64(f5) * int64(g2)
+ f5g3_2 := int64(f5_2) * int64(g3)
+ f5g4 := int64(f5) * int64(g4)
+ f5g5_38 := int64(f5_2) * int64(g5_19)
+ f5g6_19 := int64(f5) * int64(g6_19)
+ f5g7_38 := int64(f5_2) * int64(g7_19)
+ f5g8_19 := int64(f5) * int64(g8_19)
+ f5g9_38 := int64(f5_2) * int64(g9_19)
+ f6g0 := int64(f6) * int64(g0)
+ f6g1 := int64(f6) * int64(g1)
+ f6g2 := int64(f6) * int64(g2)
+ f6g3 := int64(f6) * int64(g3)
+ f6g4_19 := int64(f6) * int64(g4_19)
+ f6g5_19 := int64(f6) * int64(g5_19)
+ f6g6_19 := int64(f6) * int64(g6_19)
+ f6g7_19 := int64(f6) * int64(g7_19)
+ f6g8_19 := int64(f6) * int64(g8_19)
+ f6g9_19 := int64(f6) * int64(g9_19)
+ f7g0 := int64(f7) * int64(g0)
+ f7g1_2 := int64(f7_2) * int64(g1)
+ f7g2 := int64(f7) * int64(g2)
+ f7g3_38 := int64(f7_2) * int64(g3_19)
+ f7g4_19 := int64(f7) * int64(g4_19)
+ f7g5_38 := int64(f7_2) * int64(g5_19)
+ f7g6_19 := int64(f7) * int64(g6_19)
+ f7g7_38 := int64(f7_2) * int64(g7_19)
+ f7g8_19 := int64(f7) * int64(g8_19)
+ f7g9_38 := int64(f7_2) * int64(g9_19)
+ f8g0 := int64(f8) * int64(g0)
+ f8g1 := int64(f8) * int64(g1)
+ f8g2_19 := int64(f8) * int64(g2_19)
+ f8g3_19 := int64(f8) * int64(g3_19)
+ f8g4_19 := int64(f8) * int64(g4_19)
+ f8g5_19 := int64(f8) * int64(g5_19)
+ f8g6_19 := int64(f8) * int64(g6_19)
+ f8g7_19 := int64(f8) * int64(g7_19)
+ f8g8_19 := int64(f8) * int64(g8_19)
+ f8g9_19 := int64(f8) * int64(g9_19)
+ f9g0 := int64(f9) * int64(g0)
+ f9g1_38 := int64(f9_2) * int64(g1_19)
+ f9g2_19 := int64(f9) * int64(g2_19)
+ f9g3_38 := int64(f9_2) * int64(g3_19)
+ f9g4_19 := int64(f9) * int64(g4_19)
+ f9g5_38 := int64(f9_2) * int64(g5_19)
+ f9g6_19 := int64(f9) * int64(g6_19)
+ f9g7_38 := int64(f9_2) * int64(g7_19)
+ f9g8_19 := int64(f9) * int64(g8_19)
+ f9g9_38 := int64(f9_2) * int64(g9_19)
+ h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
+ h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
+ h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
+ h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
+ h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
+ h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
+ h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
+ h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
+ h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
+ h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
+ var carry [10]int64
+
+ // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+ // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+ // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+ // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ // |h0| <= 2^25
+ // |h4| <= 2^25
+ // |h1| <= 1.51*2^58
+ // |h5| <= 1.51*2^58
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ // |h1| <= 2^24; from now on fits into int32
+ // |h5| <= 2^24; from now on fits into int32
+ // |h2| <= 1.21*2^59
+ // |h6| <= 1.21*2^59
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ // |h2| <= 2^25; from now on fits into int32 unchanged
+ // |h6| <= 2^25; from now on fits into int32 unchanged
+ // |h3| <= 1.51*2^58
+ // |h7| <= 1.51*2^58
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+ // |h3| <= 2^24; from now on fits into int32 unchanged
+ // |h7| <= 2^24; from now on fits into int32 unchanged
+ // |h4| <= 1.52*2^33
+ // |h8| <= 1.52*2^33
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+ // |h4| <= 2^25; from now on fits into int32 unchanged
+ // |h8| <= 2^25; from now on fits into int32 unchanged
+ // |h5| <= 1.01*2^24
+ // |h9| <= 1.51*2^58
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ // |h9| <= 2^24; from now on fits into int32 unchanged
+ // |h0| <= 1.8*2^37
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ // |h0| <= 2^25; from now on fits into int32 unchanged
+ // |h1| <= 1.01*2^24
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feSquare(h, f *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ f0_2 := 2 * f0
+ f1_2 := 2 * f1
+ f2_2 := 2 * f2
+ f3_2 := 2 * f3
+ f4_2 := 2 * f4
+ f5_2 := 2 * f5
+ f6_2 := 2 * f6
+ f7_2 := 2 * f7
+ f5_38 := 38 * f5 // 1.31*2^30
+ f6_19 := 19 * f6 // 1.31*2^30
+ f7_38 := 38 * f7 // 1.31*2^30
+ f8_19 := 19 * f8 // 1.31*2^30
+ f9_38 := 38 * f9 // 1.31*2^30
+ f0f0 := int64(f0) * int64(f0)
+ f0f1_2 := int64(f0_2) * int64(f1)
+ f0f2_2 := int64(f0_2) * int64(f2)
+ f0f3_2 := int64(f0_2) * int64(f3)
+ f0f4_2 := int64(f0_2) * int64(f4)
+ f0f5_2 := int64(f0_2) * int64(f5)
+ f0f6_2 := int64(f0_2) * int64(f6)
+ f0f7_2 := int64(f0_2) * int64(f7)
+ f0f8_2 := int64(f0_2) * int64(f8)
+ f0f9_2 := int64(f0_2) * int64(f9)
+ f1f1_2 := int64(f1_2) * int64(f1)
+ f1f2_2 := int64(f1_2) * int64(f2)
+ f1f3_4 := int64(f1_2) * int64(f3_2)
+ f1f4_2 := int64(f1_2) * int64(f4)
+ f1f5_4 := int64(f1_2) * int64(f5_2)
+ f1f6_2 := int64(f1_2) * int64(f6)
+ f1f7_4 := int64(f1_2) * int64(f7_2)
+ f1f8_2 := int64(f1_2) * int64(f8)
+ f1f9_76 := int64(f1_2) * int64(f9_38)
+ f2f2 := int64(f2) * int64(f2)
+ f2f3_2 := int64(f2_2) * int64(f3)
+ f2f4_2 := int64(f2_2) * int64(f4)
+ f2f5_2 := int64(f2_2) * int64(f5)
+ f2f6_2 := int64(f2_2) * int64(f6)
+ f2f7_2 := int64(f2_2) * int64(f7)
+ f2f8_38 := int64(f2_2) * int64(f8_19)
+ f2f9_38 := int64(f2) * int64(f9_38)
+ f3f3_2 := int64(f3_2) * int64(f3)
+ f3f4_2 := int64(f3_2) * int64(f4)
+ f3f5_4 := int64(f3_2) * int64(f5_2)
+ f3f6_2 := int64(f3_2) * int64(f6)
+ f3f7_76 := int64(f3_2) * int64(f7_38)
+ f3f8_38 := int64(f3_2) * int64(f8_19)
+ f3f9_76 := int64(f3_2) * int64(f9_38)
+ f4f4 := int64(f4) * int64(f4)
+ f4f5_2 := int64(f4_2) * int64(f5)
+ f4f6_38 := int64(f4_2) * int64(f6_19)
+ f4f7_38 := int64(f4) * int64(f7_38)
+ f4f8_38 := int64(f4_2) * int64(f8_19)
+ f4f9_38 := int64(f4) * int64(f9_38)
+ f5f5_38 := int64(f5) * int64(f5_38)
+ f5f6_38 := int64(f5_2) * int64(f6_19)
+ f5f7_76 := int64(f5_2) * int64(f7_38)
+ f5f8_38 := int64(f5_2) * int64(f8_19)
+ f5f9_76 := int64(f5_2) * int64(f9_38)
+ f6f6_19 := int64(f6) * int64(f6_19)
+ f6f7_38 := int64(f6) * int64(f7_38)
+ f6f8_38 := int64(f6_2) * int64(f8_19)
+ f6f9_38 := int64(f6) * int64(f9_38)
+ f7f7_38 := int64(f7) * int64(f7_38)
+ f7f8_38 := int64(f7_2) * int64(f8_19)
+ f7f9_76 := int64(f7_2) * int64(f9_38)
+ f8f8_19 := int64(f8) * int64(f8_19)
+ f8f9_38 := int64(f8) * int64(f9_38)
+ f9f9_38 := int64(f9) * int64(f9_38)
+ h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
+ h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
+ h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
+ h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
+ h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
+ h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
+ h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
+ h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
+ h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
+ h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
+ var carry [10]int64
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feMul121666 calculates h = f * 121666. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feMul121666(h, f *fieldElement) {
+ h0 := int64(f[0]) * 121666
+ h1 := int64(f[1]) * 121666
+ h2 := int64(f[2]) * 121666
+ h3 := int64(f[3]) * 121666
+ h4 := int64(f[4]) * 121666
+ h5 := int64(f[5]) * 121666
+ h6 := int64(f[6]) * 121666
+ h7 := int64(f[7]) * 121666
+ h8 := int64(f[8]) * 121666
+ h9 := int64(f[9]) * 121666
+ var carry [10]int64
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feInvert sets out = z^-1.
+func feInvert(out, z *fieldElement) {
+ var t0, t1, t2, t3 fieldElement
+ var i int
+
+ feSquare(&t0, z)
+ for i = 1; i < 1; i++ {
+ feSquare(&t0, &t0)
+ }
+ feSquare(&t1, &t0)
+ for i = 1; i < 2; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(&t1, z, &t1)
+ feMul(&t0, &t0, &t1)
+ feSquare(&t2, &t0)
+ for i = 1; i < 1; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t1, &t2)
+ feSquare(&t2, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 20; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 100; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t1, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(out, &t1, &t0)
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+
+ copy(e[:], in[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
+ feFromBytes(&x1, base)
+ feOne(&x2)
+ feCopy(&x3, &x1)
+ feOne(&z3)
+
+ swap := int32(0)
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int32(b)
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+ swap = int32(b)
+
+ feSub(&tmp0, &x3, &z3)
+ feSub(&tmp1, &x2, &z2)
+ feAdd(&x2, &x2, &z2)
+ feAdd(&z2, &x3, &z3)
+ feMul(&z3, &tmp0, &x2)
+ feMul(&z2, &z2, &tmp1)
+ feSquare(&tmp0, &tmp1)
+ feSquare(&tmp1, &x2)
+ feAdd(&x3, &z3, &z2)
+ feSub(&z2, &z3, &z2)
+ feMul(&x2, &tmp1, &tmp0)
+ feSub(&tmp1, &tmp1, &tmp0)
+ feSquare(&z2, &z2)
+ feMul121666(&z3, &tmp1)
+ feSquare(&x3, &x3)
+ feAdd(&tmp0, &tmp0, &z3)
+ feMul(&z3, &x1, &z2)
+ feMul(&z2, &tmp1, &tmp0)
+ }
+
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+
+ feInvert(&z2, &z2)
+ feMul(&x2, &x2, &z2)
+ feToBytes(out, &x2)
+}
diff --git a/libgo/go/golang_org/x/crypto/curve25519/curve25519_test.go b/libgo/go/golang_org/x/crypto/curve25519/curve25519_test.go
new file mode 100644
index 0000000000..14b0ee87cd
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/curve25519/curve25519_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package curve25519
+
+import (
+ "fmt"
+ "testing"
+)
+
+const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
+
+func TestBaseScalarMult(t *testing.T) {
+ var a, b [32]byte
+ in := &a
+ out := &b
+ a[0] = 1
+
+ for i := 0; i < 200; i++ {
+ ScalarBaseMult(out, in)
+ in, out = out, in
+ }
+
+ result := fmt.Sprintf("%x", in[:])
+ if result != expectedHex {
+ t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
+ }
+}
diff --git a/libgo/go/golang_org/x/crypto/curve25519/doc.go b/libgo/go/golang_org/x/crypto/curve25519/doc.go
new file mode 100644
index 0000000000..ebeea3c2d6
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/curve25519/doc.go
@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of scalar multiplication on
+// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html
+package curve25519 // import "golang.org/x/crypto/curve25519"
+
+// basePoint is the x coordinate of the generator of the curve.
+var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+// ScalarMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points and all values are in little-endian form.
+func ScalarMult(dst, in, base *[32]byte) {
+ scalarMult(dst, in, base)
+}
+
+// ScalarBaseMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points, base is the standard generator and all values
+// are in little-endian form.
+func ScalarBaseMult(dst, in *[32]byte) {
+ ScalarMult(dst, in, &basePoint)
+}
diff --git a/libgo/go/golang_org/x/crypto/curve25519/mont25519_amd64.go b/libgo/go/golang_org/x/crypto/curve25519/mont25519_amd64.go
new file mode 100644
index 0000000000..5822bd5338
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/curve25519/mont25519_amd64.go
@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package curve25519
+
+// These functions are implemented in the .s files. The names of the functions
+// in the rest of the file are also taken from the SUPERCOP sources to help
+// people following along.
+
+//go:noescape
+
+func cswap(inout *[5]uint64, v uint64)
+
+//go:noescape
+
+func ladderstep(inout *[5][5]uint64)
+
+//go:noescape
+
+func freeze(inout *[5]uint64)
+
+//go:noescape
+
+func mul(dest, a, b *[5]uint64)
+
+//go:noescape
+
+func square(out, in *[5]uint64)
+
+// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
+func mladder(xr, zr *[5]uint64, s *[32]byte) {
+ var work [5][5]uint64
+
+ work[0] = *xr
+ setint(&work[1], 1)
+ setint(&work[2], 0)
+ work[3] = *xr
+ setint(&work[4], 1)
+
+ j := uint(6)
+ var prevbit byte
+
+ for i := 31; i >= 0; i-- {
+ for j < 8 {
+ bit := ((*s)[i] >> j) & 1
+ swap := bit ^ prevbit
+ prevbit = bit
+ cswap(&work[1], uint64(swap))
+ ladderstep(&work)
+ j--
+ }
+ j = 7
+ }
+
+ *xr = work[1]
+ *zr = work[2]
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+ copy(e[:], (*in)[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var t, z [5]uint64
+ unpack(&t, base)
+ mladder(&t, &z, &e)
+ invert(&z, &z)
+ mul(&t, &t, &z)
+ pack(out, &t)
+}
+
+func setint(r *[5]uint64, v uint64) {
+ r[0] = v
+ r[1] = 0
+ r[2] = 0
+ r[3] = 0
+ r[4] = 0
+}
+
+// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
+// order.
+func unpack(r *[5]uint64, x *[32]byte) {
+ r[0] = uint64(x[0]) |
+ uint64(x[1])<<8 |
+ uint64(x[2])<<16 |
+ uint64(x[3])<<24 |
+ uint64(x[4])<<32 |
+ uint64(x[5])<<40 |
+ uint64(x[6]&7)<<48
+
+ r[1] = uint64(x[6])>>3 |
+ uint64(x[7])<<5 |
+ uint64(x[8])<<13 |
+ uint64(x[9])<<21 |
+ uint64(x[10])<<29 |
+ uint64(x[11])<<37 |
+ uint64(x[12]&63)<<45
+
+ r[2] = uint64(x[12])>>6 |
+ uint64(x[13])<<2 |
+ uint64(x[14])<<10 |
+ uint64(x[15])<<18 |
+ uint64(x[16])<<26 |
+ uint64(x[17])<<34 |
+ uint64(x[18])<<42 |
+ uint64(x[19]&1)<<50
+
+ r[3] = uint64(x[19])>>1 |
+ uint64(x[20])<<7 |
+ uint64(x[21])<<15 |
+ uint64(x[22])<<23 |
+ uint64(x[23])<<31 |
+ uint64(x[24])<<39 |
+ uint64(x[25]&15)<<47
+
+ r[4] = uint64(x[25])>>4 |
+ uint64(x[26])<<4 |
+ uint64(x[27])<<12 |
+ uint64(x[28])<<20 |
+ uint64(x[29])<<28 |
+ uint64(x[30])<<36 |
+ uint64(x[31]&127)<<44
+}
+
+// pack sets out = x where out is the usual, little-endian form of the 5,
+// 51-bit limbs in x.
+func pack(out *[32]byte, x *[5]uint64) {
+ t := *x
+ freeze(&t)
+
+ out[0] = byte(t[0])
+ out[1] = byte(t[0] >> 8)
+ out[2] = byte(t[0] >> 16)
+ out[3] = byte(t[0] >> 24)
+ out[4] = byte(t[0] >> 32)
+ out[5] = byte(t[0] >> 40)
+ out[6] = byte(t[0] >> 48)
+
+ out[6] ^= byte(t[1]<<3) & 0xf8
+ out[7] = byte(t[1] >> 5)
+ out[8] = byte(t[1] >> 13)
+ out[9] = byte(t[1] >> 21)
+ out[10] = byte(t[1] >> 29)
+ out[11] = byte(t[1] >> 37)
+ out[12] = byte(t[1] >> 45)
+
+ out[12] ^= byte(t[2]<<6) & 0xc0
+ out[13] = byte(t[2] >> 2)
+ out[14] = byte(t[2] >> 10)
+ out[15] = byte(t[2] >> 18)
+ out[16] = byte(t[2] >> 26)
+ out[17] = byte(t[2] >> 34)
+ out[18] = byte(t[2] >> 42)
+ out[19] = byte(t[2] >> 50)
+
+ out[19] ^= byte(t[3]<<1) & 0xfe
+ out[20] = byte(t[3] >> 7)
+ out[21] = byte(t[3] >> 15)
+ out[22] = byte(t[3] >> 23)
+ out[23] = byte(t[3] >> 31)
+ out[24] = byte(t[3] >> 39)
+ out[25] = byte(t[3] >> 47)
+
+ out[25] ^= byte(t[4]<<4) & 0xf0
+ out[26] = byte(t[4] >> 4)
+ out[27] = byte(t[4] >> 12)
+ out[28] = byte(t[4] >> 20)
+ out[29] = byte(t[4] >> 28)
+ out[30] = byte(t[4] >> 36)
+ out[31] = byte(t[4] >> 44)
+}
+
+// invert calculates r = x^-1 mod p using Fermat's little theorem.
+func invert(r *[5]uint64, x *[5]uint64) {
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
+
+ square(&z2, x) /* 2 */
+ square(&t, &z2) /* 4 */
+ square(&t, &t) /* 8 */
+ mul(&z9, &t, x) /* 9 */
+ mul(&z11, &z9, &z2) /* 11 */
+ square(&t, &z11) /* 22 */
+ mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
+
+ square(&t, &z2_5_0) /* 2^6 - 2^1 */
+ for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
+
+ square(&t, &z2_10_0) /* 2^11 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
+
+ square(&t, &z2_20_0) /* 2^21 - 2^1 */
+ for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
+
+ square(&t, &t) /* 2^41 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
+
+ square(&t, &z2_50_0) /* 2^51 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
+
+ square(&t, &z2_100_0) /* 2^101 - 2^1 */
+ for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
+
+ square(&t, &t) /* 2^201 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
+
+ square(&t, &t) /* 2^251 - 2^1 */
+ square(&t, &t) /* 2^252 - 2^2 */
+ square(&t, &t) /* 2^253 - 2^3 */
+
+ square(&t, &t) /* 2^254 - 2^4 */
+
+ square(&t, &t) /* 2^255 - 2^5 */
+ mul(r, &t, &z11) /* 2^255 - 21 */
+}
diff --git a/libgo/go/golang_org/x/crypto/poly1305/poly1305.go b/libgo/go/golang_org/x/crypto/poly1305/poly1305.go
new file mode 100644
index 0000000000..4a5f826f7a
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/poly1305/poly1305.go
@@ -0,0 +1,32 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package poly1305 implements Poly1305 one-time message authentication code as specified in http://cr.yp.to/mac/poly1305-20050329.pdf.
+
+Poly1305 is a fast, one-time authentication function. It is infeasible for an
+attacker to generate an authenticator for a message without the key. However, a
+key must only be used for a single message. Authenticating two different
+messages with the same key allows an attacker to forge authenticators for other
+messages with the same key.
+
+Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
+used with a fixed key in order to generate one-time keys from an nonce.
+However, in this package AES isn't used and the one-time key is specified
+directly.
+*/
+package poly1305 // import "golang.org/x/crypto/poly1305"
+
+import "crypto/subtle"
+
+// TagSize is the size, in bytes, of a poly1305 authenticator.
+const TagSize = 16
+
+// Verify returns true if mac is a valid authenticator for m with the given
+// key.
+func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
+ var tmp [16]byte
+ Sum(&tmp, m, key)
+ return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
+}
diff --git a/libgo/go/golang_org/x/crypto/poly1305/poly1305_test.go b/libgo/go/golang_org/x/crypto/poly1305/poly1305_test.go
new file mode 100644
index 0000000000..91b8e2b496
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/poly1305/poly1305_test.go
@@ -0,0 +1,92 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poly1305
+
+import (
+ "bytes"
+ "testing"
+ "unsafe"
+)
+
+var testData = []struct {
+ in, k, correct []byte
+}{
+ {
+ []byte("Hello world!"),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0},
+ },
+ {
+ make([]byte, 32),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07},
+ },
+ {
+ make([]byte, 2007),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa},
+ },
+ {
+ make([]byte, 2007),
+ make([]byte, 32),
+ make([]byte, 16),
+ },
+ {
+ // This test triggers an edge-case. See https://go-review.googlesource.com/#/c/30101/.
+ []byte{0x81, 0xd8, 0xb2, 0xe4, 0x6a, 0x25, 0x21, 0x3b, 0x58, 0xfe, 0xe4, 0x21, 0x3a, 0x2a, 0x28, 0xe9, 0x21, 0xc1, 0x2a, 0x96, 0x32, 0x51, 0x6d, 0x3b, 0x73, 0x27, 0x27, 0x27, 0xbe, 0xcf, 0x21, 0x29},
+ []byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d},
+ []byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14},
+ },
+}
+
+func testSum(t *testing.T, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+
+ for i, v := range testData {
+ in := v.in
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ copy(key[:], v.k)
+ Sum(&out, in, &key)
+ if !bytes.Equal(out[:], v.correct) {
+ t.Errorf("%d: expected %x, got %x", i, v.correct, out[:])
+ }
+ }
+}
+
+func TestSum(t *testing.T) { testSum(t, false) }
+func TestSumUnaligned(t *testing.T) { testSum(t, true) }
+
+func benchmark(b *testing.B, size int, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+ in := make([]byte, size)
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ b.SetBytes(int64(len(in)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sum(&out, in, &key)
+ }
+}
+
+func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
+func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
+func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
+func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
+
+func unalignBytes(in []byte) []byte {
+ out := make([]byte, len(in)+1)
+ if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ out = out[1:]
+ } else {
+ out = out[:len(in)]
+ }
+ copy(out, in)
+ return out
+}
diff --git a/libgo/go/golang_org/x/crypto/poly1305/sum_amd64.go b/libgo/go/golang_org/x/crypto/poly1305/sum_amd64.go
new file mode 100644
index 0000000000..4dd72fe799
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/poly1305/sum_amd64.go
@@ -0,0 +1,22 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in sum_amd64.s
+//go:noescape
+func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305(out, mPtr, uint64(len(m)), key)
+}
diff --git a/libgo/go/golang_org/x/crypto/poly1305/sum_arm.go b/libgo/go/golang_org/x/crypto/poly1305/sum_arm.go
new file mode 100644
index 0000000000..5dc321c2f3
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/poly1305/sum_arm.go
@@ -0,0 +1,22 @@
+// 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 arm,!gccgo,!appengine,!nacl
+
+package poly1305
+
+// This function is implemented in sum_arm.s
+//go:noescape
+func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
+}
diff --git a/libgo/go/golang_org/x/crypto/poly1305/sum_ref.go b/libgo/go/golang_org/x/crypto/poly1305/sum_ref.go
new file mode 100644
index 0000000000..dbe50e78a0
--- /dev/null
+++ b/libgo/go/golang_org/x/crypto/poly1305/sum_ref.go
@@ -0,0 +1,1531 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!arm gccgo appengine nacl
+
+package poly1305
+
+// Based on original, public domain implementation from NaCl by D. J.
+// Bernstein.
+
+import "math"
+
+const (
+ alpham80 = 0.00000000558793544769287109375
+ alpham48 = 24.0
+ alpham16 = 103079215104.0
+ alpha0 = 6755399441055744.0
+ alpha18 = 1770887431076116955136.0
+ alpha32 = 29014219670751100192948224.0
+ alpha50 = 7605903601369376408980219232256.0
+ alpha64 = 124615124604835863084731911901282304.0
+ alpha82 = 32667107224410092492483962313449748299776.0
+ alpha96 = 535217884764734955396857238543560676143529984.0
+ alpha112 = 35076039295941670036888435985190792471742381031424.0
+ alpha130 = 9194973245195333150150082162901855101712434733101613056.0
+ scale = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125
+ offset0 = 6755408030990331.0
+ offset1 = 29014256564239239022116864.0
+ offset2 = 124615283061160854719918951570079744.0
+ offset3 = 535219245894202480694386063513315216128475136.0
+)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ r := key
+ s := key[16:]
+ var (
+ y7 float64
+ y6 float64
+ y1 float64
+ y0 float64
+ y5 float64
+ y4 float64
+ x7 float64
+ x6 float64
+ x1 float64
+ x0 float64
+ y3 float64
+ y2 float64
+ x5 float64
+ r3lowx0 float64
+ x4 float64
+ r0lowx6 float64
+ x3 float64
+ r3highx0 float64
+ x2 float64
+ r0highx6 float64
+ r0lowx0 float64
+ sr1lowx6 float64
+ r0highx0 float64
+ sr1highx6 float64
+ sr3low float64
+ r1lowx0 float64
+ sr2lowx6 float64
+ r1highx0 float64
+ sr2highx6 float64
+ r2lowx0 float64
+ sr3lowx6 float64
+ r2highx0 float64
+ sr3highx6 float64
+ r1highx4 float64
+ r1lowx4 float64
+ r0highx4 float64
+ r0lowx4 float64
+ sr3highx4 float64
+ sr3lowx4 float64
+ sr2highx4 float64
+ sr2lowx4 float64
+ r0lowx2 float64
+ r0highx2 float64
+ r1lowx2 float64
+ r1highx2 float64
+ r2lowx2 float64
+ r2highx2 float64
+ sr3lowx2 float64
+ sr3highx2 float64
+ z0 float64
+ z1 float64
+ z2 float64
+ z3 float64
+ m0 int64
+ m1 int64
+ m2 int64
+ m3 int64
+ m00 uint32
+ m01 uint32
+ m02 uint32
+ m03 uint32
+ m10 uint32
+ m11 uint32
+ m12 uint32
+ m13 uint32
+ m20 uint32
+ m21 uint32
+ m22 uint32
+ m23 uint32
+ m30 uint32
+ m31 uint32
+ m32 uint32
+ m33 uint64
+ lbelow2 int32
+ lbelow3 int32
+ lbelow4 int32
+ lbelow5 int32
+ lbelow6 int32
+ lbelow7 int32
+ lbelow8 int32
+ lbelow9 int32
+ lbelow10 int32
+ lbelow11 int32
+ lbelow12 int32
+ lbelow13 int32
+ lbelow14 int32
+ lbelow15 int32
+ s00 uint32
+ s01 uint32
+ s02 uint32
+ s03 uint32
+ s10 uint32
+ s11 uint32
+ s12 uint32
+ s13 uint32
+ s20 uint32
+ s21 uint32
+ s22 uint32
+ s23 uint32
+ s30 uint32
+ s31 uint32
+ s32 uint32
+ s33 uint32
+ bits32 uint64
+ f uint64
+ f0 uint64
+ f1 uint64
+ f2 uint64
+ f3 uint64
+ f4 uint64
+ g uint64
+ g0 uint64
+ g1 uint64
+ g2 uint64
+ g3 uint64
+ g4 uint64
+ )
+
+ var p int32
+
+ l := int32(len(m))
+
+ r00 := uint32(r[0])
+
+ r01 := uint32(r[1])
+
+ r02 := uint32(r[2])
+ r0 := int64(2151)
+
+ r03 := uint32(r[3])
+ r03 &= 15
+ r0 <<= 51
+
+ r10 := uint32(r[4])
+ r10 &= 252
+ r01 <<= 8
+ r0 += int64(r00)
+
+ r11 := uint32(r[5])
+ r02 <<= 16
+ r0 += int64(r01)
+
+ r12 := uint32(r[6])
+ r03 <<= 24
+ r0 += int64(r02)
+
+ r13 := uint32(r[7])
+ r13 &= 15
+ r1 := int64(2215)
+ r0 += int64(r03)
+
+ d0 := r0
+ r1 <<= 51
+ r2 := int64(2279)
+
+ r20 := uint32(r[8])
+ r20 &= 252
+ r11 <<= 8
+ r1 += int64(r10)
+
+ r21 := uint32(r[9])
+ r12 <<= 16
+ r1 += int64(r11)
+
+ r22 := uint32(r[10])
+ r13 <<= 24
+ r1 += int64(r12)
+
+ r23 := uint32(r[11])
+ r23 &= 15
+ r2 <<= 51
+ r1 += int64(r13)
+
+ d1 := r1
+ r21 <<= 8
+ r2 += int64(r20)
+
+ r30 := uint32(r[12])
+ r30 &= 252
+ r22 <<= 16
+ r2 += int64(r21)
+
+ r31 := uint32(r[13])
+ r23 <<= 24
+ r2 += int64(r22)
+
+ r32 := uint32(r[14])
+ r2 += int64(r23)
+ r3 := int64(2343)
+
+ d2 := r2
+ r3 <<= 51
+
+ r33 := uint32(r[15])
+ r33 &= 15
+ r31 <<= 8
+ r3 += int64(r30)
+
+ r32 <<= 16
+ r3 += int64(r31)
+
+ r33 <<= 24
+ r3 += int64(r32)
+
+ r3 += int64(r33)
+ h0 := alpha32 - alpha32
+
+ d3 := r3
+ h1 := alpha32 - alpha32
+
+ h2 := alpha32 - alpha32
+
+ h3 := alpha32 - alpha32
+
+ h4 := alpha32 - alpha32
+
+ r0low := math.Float64frombits(uint64(d0))
+ h5 := alpha32 - alpha32
+
+ r1low := math.Float64frombits(uint64(d1))
+ h6 := alpha32 - alpha32
+
+ r2low := math.Float64frombits(uint64(d2))
+ h7 := alpha32 - alpha32
+
+ r0low -= alpha0
+
+ r1low -= alpha32
+
+ r2low -= alpha64
+
+ r0high := r0low + alpha18
+
+ r3low := math.Float64frombits(uint64(d3))
+
+ r1high := r1low + alpha50
+ sr1low := scale * r1low
+
+ r2high := r2low + alpha82
+ sr2low := scale * r2low
+
+ r0high -= alpha18
+ r0high_stack := r0high
+
+ r3low -= alpha96
+
+ r1high -= alpha50
+ r1high_stack := r1high
+
+ sr1high := sr1low + alpham80
+
+ r0low -= r0high
+
+ r2high -= alpha82
+ sr3low = scale * r3low
+
+ sr2high := sr2low + alpham48
+
+ r1low -= r1high
+ r1low_stack := r1low
+
+ sr1high -= alpham80
+ sr1high_stack := sr1high
+
+ r2low -= r2high
+ r2low_stack := r2low
+
+ sr2high -= alpham48
+ sr2high_stack := sr2high
+
+ r3high := r3low + alpha112
+ r0low_stack := r0low
+
+ sr1low -= sr1high
+ sr1low_stack := sr1low
+
+ sr3high := sr3low + alpham16
+ r2high_stack := r2high
+
+ sr2low -= sr2high
+ sr2low_stack := sr2low
+
+ r3high -= alpha112
+ r3high_stack := r3high
+
+ sr3high -= alpham16
+ sr3high_stack := sr3high
+
+ r3low -= r3high
+ r3low_stack := r3low
+
+ sr3low -= sr3high
+ sr3low_stack := sr3low
+
+ if l < 16 {
+ goto addatmost15bytes
+ }
+
+ m00 = uint32(m[p+0])
+ m0 = 2151
+
+ m0 <<= 51
+ m1 = 2215
+ m01 = uint32(m[p+1])
+
+ m1 <<= 51
+ m2 = 2279
+ m02 = uint32(m[p+2])
+
+ m2 <<= 51
+ m3 = 2343
+ m03 = uint32(m[p+3])
+
+ m10 = uint32(m[p+4])
+ m01 <<= 8
+ m0 += int64(m00)
+
+ m11 = uint32(m[p+5])
+ m02 <<= 16
+ m0 += int64(m01)
+
+ m12 = uint32(m[p+6])
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m13 = uint32(m[p+7])
+ m3 <<= 51
+ m0 += int64(m03)
+
+ m20 = uint32(m[p+8])
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m21 = uint32(m[p+9])
+ m12 <<= 16
+ m1 += int64(m11)
+
+ m22 = uint32(m[p+10])
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m23 = uint32(m[p+11])
+ m1 += int64(m13)
+
+ m30 = uint32(m[p+12])
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m31 = uint32(m[p+13])
+ m22 <<= 16
+ m2 += int64(m21)
+
+ m32 = uint32(m[p+14])
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m33 = uint64(m[p+15])
+ m2 += int64(m23)
+
+ d0 = m0
+ m31 <<= 8
+ m3 += int64(m30)
+
+ d1 = m1
+ m32 <<= 16
+ m3 += int64(m31)
+
+ d2 = m2
+ m33 += 256
+
+ m33 <<= 24
+ m3 += int64(m32)
+
+ m3 += int64(m33)
+ d3 = m3
+
+ p += 16
+ l -= 16
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z0 -= alpha0
+
+ z1 -= alpha32
+
+ z2 -= alpha64
+
+ z3 -= alpha96
+
+ h0 += z0
+
+ h1 += z1
+
+ h3 += z2
+
+ h5 += z3
+
+ if l < 16 {
+ goto multiplyaddatmost15bytes
+ }
+
+multiplyaddatleast16bytes:
+
+ m2 = 2279
+ m20 = uint32(m[p+8])
+ y7 = h7 + alpha130
+
+ m2 <<= 51
+ m3 = 2343
+ m21 = uint32(m[p+9])
+ y6 = h6 + alpha130
+
+ m3 <<= 51
+ m0 = 2151
+ m22 = uint32(m[p+10])
+ y1 = h1 + alpha32
+
+ m0 <<= 51
+ m1 = 2215
+ m23 = uint32(m[p+11])
+ y0 = h0 + alpha32
+
+ m1 <<= 51
+ m30 = uint32(m[p+12])
+ y7 -= alpha130
+
+ m21 <<= 8
+ m2 += int64(m20)
+ m31 = uint32(m[p+13])
+ y6 -= alpha130
+
+ m22 <<= 16
+ m2 += int64(m21)
+ m32 = uint32(m[p+14])
+ y1 -= alpha32
+
+ m23 <<= 24
+ m2 += int64(m22)
+ m33 = uint64(m[p+15])
+ y0 -= alpha32
+
+ m2 += int64(m23)
+ m00 = uint32(m[p+0])
+ y5 = h5 + alpha96
+
+ m31 <<= 8
+ m3 += int64(m30)
+ m01 = uint32(m[p+1])
+ y4 = h4 + alpha96
+
+ m32 <<= 16
+ m02 = uint32(m[p+2])
+ x7 = h7 - y7
+ y7 *= scale
+
+ m33 += 256
+ m03 = uint32(m[p+3])
+ x6 = h6 - y6
+ y6 *= scale
+
+ m33 <<= 24
+ m3 += int64(m31)
+ m10 = uint32(m[p+4])
+ x1 = h1 - y1
+
+ m01 <<= 8
+ m3 += int64(m32)
+ m11 = uint32(m[p+5])
+ x0 = h0 - y0
+
+ m3 += int64(m33)
+ m0 += int64(m00)
+ m12 = uint32(m[p+6])
+ y5 -= alpha96
+
+ m02 <<= 16
+ m0 += int64(m01)
+ m13 = uint32(m[p+7])
+ y4 -= alpha96
+
+ m03 <<= 24
+ m0 += int64(m02)
+ d2 = m2
+ x1 += y7
+
+ m0 += int64(m03)
+ d3 = m3
+ x0 += y6
+
+ m11 <<= 8
+ m1 += int64(m10)
+ d0 = m0
+ x7 += y5
+
+ m12 <<= 16
+ m1 += int64(m11)
+ x6 += y4
+
+ m13 <<= 24
+ m1 += int64(m12)
+ y3 = h3 + alpha64
+
+ m1 += int64(m13)
+ d1 = m1
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+ z2 = math.Float64frombits(uint64(d2))
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+ z3 = math.Float64frombits(uint64(d3))
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+ z2 -= alpha64
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+ z3 -= alpha96
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ p += 16
+ l -= 16
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ z1 = math.Float64frombits(uint64(d1))
+ h0 += sr3lowx2
+
+ z0 = math.Float64frombits(uint64(d0))
+ h1 += sr3highx2
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ if l >= 16 {
+ goto multiplyaddatleast16bytes
+ }
+
+multiplyaddatmost15bytes:
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+addatmost15bytes:
+
+ if l == 0 {
+ goto nomorebytes
+ }
+
+ lbelow2 = l - 2
+
+ lbelow3 = l - 3
+
+ lbelow2 >>= 31
+ lbelow4 = l - 4
+
+ m00 = uint32(m[p+0])
+ lbelow3 >>= 31
+ p += lbelow2
+
+ m01 = uint32(m[p+1])
+ lbelow4 >>= 31
+ p += lbelow3
+
+ m02 = uint32(m[p+2])
+ p += lbelow4
+ m0 = 2151
+
+ m03 = uint32(m[p+3])
+ m0 <<= 51
+ m1 = 2215
+
+ m0 += int64(m00)
+ m01 &^= uint32(lbelow2)
+
+ m02 &^= uint32(lbelow3)
+ m01 -= uint32(lbelow2)
+
+ m01 <<= 8
+ m03 &^= uint32(lbelow4)
+
+ m0 += int64(m01)
+ lbelow2 -= lbelow3
+
+ m02 += uint32(lbelow2)
+ lbelow3 -= lbelow4
+
+ m02 <<= 16
+ m03 += uint32(lbelow3)
+
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m0 += int64(m03)
+ lbelow5 = l - 5
+
+ lbelow6 = l - 6
+ lbelow7 = l - 7
+
+ lbelow5 >>= 31
+ lbelow8 = l - 8
+
+ lbelow6 >>= 31
+ p += lbelow5
+
+ m10 = uint32(m[p+4])
+ lbelow7 >>= 31
+ p += lbelow6
+
+ m11 = uint32(m[p+5])
+ lbelow8 >>= 31
+ p += lbelow7
+
+ m12 = uint32(m[p+6])
+ m1 <<= 51
+ p += lbelow8
+
+ m13 = uint32(m[p+7])
+ m10 &^= uint32(lbelow5)
+ lbelow4 -= lbelow5
+
+ m10 += uint32(lbelow4)
+ lbelow5 -= lbelow6
+
+ m11 &^= uint32(lbelow6)
+ m11 += uint32(lbelow5)
+
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m1 += int64(m11)
+ m12 &^= uint32(lbelow7)
+
+ lbelow6 -= lbelow7
+ m13 &^= uint32(lbelow8)
+
+ m12 += uint32(lbelow6)
+ lbelow7 -= lbelow8
+
+ m12 <<= 16
+ m13 += uint32(lbelow7)
+
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m1 += int64(m13)
+ m2 = 2279
+
+ lbelow9 = l - 9
+ m3 = 2343
+
+ lbelow10 = l - 10
+ lbelow11 = l - 11
+
+ lbelow9 >>= 31
+ lbelow12 = l - 12
+
+ lbelow10 >>= 31
+ p += lbelow9
+
+ m20 = uint32(m[p+8])
+ lbelow11 >>= 31
+ p += lbelow10
+
+ m21 = uint32(m[p+9])
+ lbelow12 >>= 31
+ p += lbelow11
+
+ m22 = uint32(m[p+10])
+ m2 <<= 51
+ p += lbelow12
+
+ m23 = uint32(m[p+11])
+ m20 &^= uint32(lbelow9)
+ lbelow8 -= lbelow9
+
+ m20 += uint32(lbelow8)
+ lbelow9 -= lbelow10
+
+ m21 &^= uint32(lbelow10)
+ m21 += uint32(lbelow9)
+
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m2 += int64(m21)
+ m22 &^= uint32(lbelow11)
+
+ lbelow10 -= lbelow11
+ m23 &^= uint32(lbelow12)
+
+ m22 += uint32(lbelow10)
+ lbelow11 -= lbelow12
+
+ m22 <<= 16
+ m23 += uint32(lbelow11)
+
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m3 <<= 51
+ lbelow13 = l - 13
+
+ lbelow13 >>= 31
+ lbelow14 = l - 14
+
+ lbelow14 >>= 31
+ p += lbelow13
+ lbelow15 = l - 15
+
+ m30 = uint32(m[p+12])
+ lbelow15 >>= 31
+ p += lbelow14
+
+ m31 = uint32(m[p+13])
+ p += lbelow15
+ m2 += int64(m23)
+
+ m32 = uint32(m[p+14])
+ m30 &^= uint32(lbelow13)
+ lbelow12 -= lbelow13
+
+ m30 += uint32(lbelow12)
+ lbelow13 -= lbelow14
+
+ m3 += int64(m30)
+ m31 &^= uint32(lbelow14)
+
+ m31 += uint32(lbelow13)
+ m32 &^= uint32(lbelow15)
+
+ m31 <<= 8
+ lbelow14 -= lbelow15
+
+ m3 += int64(m31)
+ m32 += uint32(lbelow14)
+ d0 = m0
+
+ m32 <<= 16
+ m33 = uint64(lbelow15 + 1)
+ d1 = m1
+
+ m33 <<= 24
+ m3 += int64(m32)
+ d2 = m2
+
+ m3 += int64(m33)
+ d3 = m3
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z3 -= alpha96
+
+ z2 -= alpha64
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+nomorebytes:
+
+ y7 = h7 + alpha130
+
+ y0 = h0 + alpha32
+
+ y1 = h1 + alpha32
+
+ y2 = h2 + alpha64
+
+ y7 -= alpha130
+
+ y3 = h3 + alpha64
+
+ y4 = h4 + alpha96
+
+ y5 = h5 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ y0 -= alpha32
+
+ y1 -= alpha32
+
+ y2 -= alpha64
+
+ h6 += x7
+
+ y3 -= alpha64
+
+ y4 -= alpha96
+
+ y5 -= alpha96
+
+ y6 = h6 + alpha130
+
+ x0 = h0 - y0
+
+ x1 = h1 - y1
+
+ x2 = h2 - y2
+
+ y6 -= alpha130
+
+ x0 += y7
+
+ x3 = h3 - y3
+
+ x4 = h4 - y4
+
+ x5 = h5 - y5
+
+ x6 = h6 - y6
+
+ y6 *= scale
+
+ x2 += y0
+
+ x3 += y1
+
+ x4 += y2
+
+ x0 += y6
+
+ x5 += y3
+
+ x6 += y4
+
+ x2 += x3
+
+ x0 += x1
+
+ x4 += x5
+
+ x6 += y5
+
+ x2 += offset1
+ d1 = int64(math.Float64bits(x2))
+
+ x0 += offset0
+ d0 = int64(math.Float64bits(x0))
+
+ x4 += offset2
+ d2 = int64(math.Float64bits(x4))
+
+ x6 += offset3
+ d3 = int64(math.Float64bits(x6))
+
+ f0 = uint64(d0)
+
+ f1 = uint64(d1)
+ bits32 = math.MaxUint64
+
+ f2 = uint64(d2)
+ bits32 >>= 32
+
+ f3 = uint64(d3)
+ f = f0 >> 32
+
+ f0 &= bits32
+ f &= 255
+
+ f1 += f
+ g0 = f0 + 5
+
+ g = g0 >> 32
+ g0 &= bits32
+
+ f = f1 >> 32
+ f1 &= bits32
+
+ f &= 255
+ g1 = f1 + g
+
+ g = g1 >> 32
+ f2 += f
+
+ f = f2 >> 32
+ g1 &= bits32
+
+ f2 &= bits32
+ f &= 255
+
+ f3 += f
+ g2 = f2 + g
+
+ g = g2 >> 32
+ g2 &= bits32
+
+ f4 = f3 >> 32
+ f3 &= bits32
+
+ f4 &= 255
+ g3 = f3 + g
+
+ g = g3 >> 32
+ g3 &= bits32
+
+ g4 = f4 + g
+
+ g4 = g4 - 4
+ s00 = uint32(s[0])
+
+ f = uint64(int64(g4) >> 63)
+ s01 = uint32(s[1])
+
+ f0 &= f
+ g0 &^= f
+ s02 = uint32(s[2])
+
+ f1 &= f
+ f0 |= g0
+ s03 = uint32(s[3])
+
+ g1 &^= f
+ f2 &= f
+ s10 = uint32(s[4])
+
+ f3 &= f
+ g2 &^= f
+ s11 = uint32(s[5])
+
+ g3 &^= f
+ f1 |= g1
+ s12 = uint32(s[6])
+
+ f2 |= g2
+ f3 |= g3
+ s13 = uint32(s[7])
+
+ s01 <<= 8
+ f0 += uint64(s00)
+ s20 = uint32(s[8])
+
+ s02 <<= 16
+ f0 += uint64(s01)
+ s21 = uint32(s[9])
+
+ s03 <<= 24
+ f0 += uint64(s02)
+ s22 = uint32(s[10])
+
+ s11 <<= 8
+ f1 += uint64(s10)
+ s23 = uint32(s[11])
+
+ s12 <<= 16
+ f1 += uint64(s11)
+ s30 = uint32(s[12])
+
+ s13 <<= 24
+ f1 += uint64(s12)
+ s31 = uint32(s[13])
+
+ f0 += uint64(s03)
+ f1 += uint64(s13)
+ s32 = uint32(s[14])
+
+ s21 <<= 8
+ f2 += uint64(s20)
+ s33 = uint32(s[15])
+
+ s22 <<= 16
+ f2 += uint64(s21)
+
+ s23 <<= 24
+ f2 += uint64(s22)
+
+ s31 <<= 8
+ f3 += uint64(s30)
+
+ s32 <<= 16
+ f3 += uint64(s31)
+
+ s33 <<= 24
+ f3 += uint64(s32)
+
+ f2 += uint64(s23)
+ f3 += uint64(s33)
+
+ out[0] = byte(f0)
+ f0 >>= 8
+ out[1] = byte(f0)
+ f0 >>= 8
+ out[2] = byte(f0)
+ f0 >>= 8
+ out[3] = byte(f0)
+ f0 >>= 8
+ f1 += f0
+
+ out[4] = byte(f1)
+ f1 >>= 8
+ out[5] = byte(f1)
+ f1 >>= 8
+ out[6] = byte(f1)
+ f1 >>= 8
+ out[7] = byte(f1)
+ f1 >>= 8
+ f2 += f1
+
+ out[8] = byte(f2)
+ f2 >>= 8
+ out[9] = byte(f2)
+ f2 >>= 8
+ out[10] = byte(f2)
+ f2 >>= 8
+ out[11] = byte(f2)
+ f2 >>= 8
+ f3 += f2
+
+ out[12] = byte(f3)
+ f3 >>= 8
+ out[13] = byte(f3)
+ f3 >>= 8
+ out[14] = byte(f3)
+ f3 >>= 8
+ out[15] = byte(f3)
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/encode.go b/libgo/go/golang_org/x/net/http2/hpack/encode.go
index 80d621cf35..f9bb033984 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/encode.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/encode.go
@@ -144,7 +144,7 @@ func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
// shouldIndex reports whether f should be indexed.
func (e *Encoder) shouldIndex(f HeaderField) bool {
- return !f.Sensitive && f.size() <= e.dynTab.maxSize
+ return !f.Sensitive && f.Size() <= e.dynTab.maxSize
}
// appendIndexed appends index i, as encoded in "Indexed Header Field"
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go b/libgo/go/golang_org/x/net/http2/hpack/encode_test.go
index 92286f3bad..92286f3bad 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/encode_test.go
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go b/libgo/go/golang_org/x/net/http2/hpack/hpack.go
index 2ea4949ab0..8aa197ad67 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/hpack.go
@@ -41,6 +41,14 @@ type HeaderField struct {
Sensitive bool
}
+// IsPseudo reports whether the header field is an http2 pseudo header.
+// That is, it reports whether it starts with a colon.
+// It is not otherwise guaranteed to be a valid pseudo header field,
+// though.
+func (hf HeaderField) IsPseudo() bool {
+ return len(hf.Name) != 0 && hf.Name[0] == ':'
+}
+
func (hf HeaderField) String() string {
var suffix string
if hf.Sensitive {
@@ -49,7 +57,8 @@ func (hf HeaderField) String() string {
return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
}
-func (hf *HeaderField) size() uint32 {
+// Size returns the size of an entry per RFC 7540 section 5.2.
+func (hf HeaderField) Size() uint32 {
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
// "The size of the dynamic table is the sum of the size of
// its entries. The size of an entry is the sum of its name's
@@ -171,7 +180,7 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
func (dt *dynamicTable) add(f HeaderField) {
dt.ents = append(dt.ents, f)
- dt.size += f.size()
+ dt.size += f.Size()
dt.evict()
}
@@ -179,7 +188,7 @@ func (dt *dynamicTable) add(f HeaderField) {
func (dt *dynamicTable) evict() {
base := dt.ents // keep base pointer of slice
for dt.size > dt.maxSize {
- dt.size -= dt.ents[0].size()
+ dt.size -= dt.ents[0].Size()
dt.ents = dt.ents[1:]
}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go b/libgo/go/golang_org/x/net/http2/hpack/hpack_test.go
index 6dc69f9579..4c7b17bfb1 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/hpack_test.go
@@ -524,6 +524,47 @@ func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
}
}
+func TestHuffmanDecodeExcessPadding(t *testing.T) {
+ tests := [][]byte{
+ {0xff}, // Padding Exceeds 7 bits
+ {0x1f, 0xff}, // {"a", 1 byte excess padding}
+ {0x1f, 0xff, 0xff}, // {"a", 2 byte excess padding}
+ {0x1f, 0xff, 0xff, 0xff}, // {"a", 3 byte excess padding}
+ {0xff, 0x9f, 0xff, 0xff, 0xff}, // {"a", 29 bit excess padding}
+ {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol.
+ }
+ for i, in := range tests {
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err)
+ }
+ }
+}
+
+func TestHuffmanDecodeEOS(t *testing.T) {
+ in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"}
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("error = %v; want ErrInvalidHuffman", err)
+ }
+}
+
+func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) {
+ in := []byte{0x00, 0x01} // {"0", "0", "0"}
+ var buf bytes.Buffer
+ if err := huffmanDecode(&buf, 2, in); err != ErrStringLength {
+ t.Errorf("error = %v; want ErrStringLength", err)
+ }
+}
+
+func TestHuffmanDecodeCorruptPadding(t *testing.T) {
+ in := []byte{0x00}
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("error = %v; want ErrInvalidHuffman", err)
+ }
+}
+
func TestHuffmanDecode(t *testing.T) {
tests := []struct {
inHex, want string
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go b/libgo/go/golang_org/x/net/http2/hpack/huffman.go
index eb4b1f05cd..8850e39467 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/huffman.go
@@ -48,12 +48,16 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
// maxLen bytes will return ErrStringLength.
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
n := rootHuffmanNode
- cur, nbits := uint(0), uint8(0)
+ // cur is the bit buffer that has not been fed into n.
+ // cbits is the number of low order bits in cur that are valid.
+ // sbits is the number of bits of the symbol prefix being decoded.
+ cur, cbits, sbits := uint(0), uint8(0), uint8(0)
for _, b := range v {
cur = cur<<8 | uint(b)
- nbits += 8
- for nbits >= 8 {
- idx := byte(cur >> (nbits - 8))
+ cbits += 8
+ sbits += 8
+ for cbits >= 8 {
+ idx := byte(cur >> (cbits - 8))
n = n.children[idx]
if n == nil {
return ErrInvalidHuffman
@@ -63,22 +67,40 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
return ErrStringLength
}
buf.WriteByte(n.sym)
- nbits -= n.codeLen
+ cbits -= n.codeLen
n = rootHuffmanNode
+ sbits = cbits
} else {
- nbits -= 8
+ cbits -= 8
}
}
}
- for nbits > 0 {
- n = n.children[byte(cur<<(8-nbits))]
- if n.children != nil || n.codeLen > nbits {
+ for cbits > 0 {
+ n = n.children[byte(cur<<(8-cbits))]
+ if n == nil {
+ return ErrInvalidHuffman
+ }
+ if n.children != nil || n.codeLen > cbits {
break
}
+ if maxLen != 0 && buf.Len() == maxLen {
+ return ErrStringLength
+ }
buf.WriteByte(n.sym)
- nbits -= n.codeLen
+ cbits -= n.codeLen
n = rootHuffmanNode
+ sbits = cbits
+ }
+ if sbits > 7 {
+ // Either there was an incomplete symbol, or overlong padding.
+ // Both are decoding errors per RFC 7541 section 5.2.
+ return ErrInvalidHuffman
}
+ if mask := uint(1<<cbits - 1); cur&mask != mask {
+ // Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
+ return ErrInvalidHuffman
+ }
+
return nil
}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/tables.go b/libgo/go/golang_org/x/net/http2/hpack/tables.go
index b9283a0233..b9283a0233 100644
--- a/libgo/go/internal/golang.org/x/net/http2/hpack/tables.go
+++ b/libgo/go/golang_org/x/net/http2/hpack/tables.go
diff --git a/libgo/go/golang_org/x/net/idna/idna.go b/libgo/go/golang_org/x/net/idna/idna.go
new file mode 100644
index 0000000000..3daa8979e1
--- /dev/null
+++ b/libgo/go/golang_org/x/net/idna/idna.go
@@ -0,0 +1,68 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package idna implements IDNA2008 (Internationalized Domain Names for
+// Applications), defined in RFC 5890, RFC 5891, RFC 5892, RFC 5893 and
+// RFC 5894.
+package idna // import "golang.org/x/net/idna"
+
+import (
+ "strings"
+ "unicode/utf8"
+)
+
+// TODO(nigeltao): specify when errors occur. For example, is ToASCII(".") or
+// ToASCII("foo\x00") an error? See also http://www.unicode.org/faq/idn.html#11
+
+// acePrefix is the ASCII Compatible Encoding prefix.
+const acePrefix = "xn--"
+
+// ToASCII converts a domain or domain label to its ASCII form. For example,
+// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
+// ToASCII("golang") is "golang".
+func ToASCII(s string) (string, error) {
+ if ascii(s) {
+ return s, nil
+ }
+ labels := strings.Split(s, ".")
+ for i, label := range labels {
+ if !ascii(label) {
+ a, err := encode(acePrefix, label)
+ if err != nil {
+ return "", err
+ }
+ labels[i] = a
+ }
+ }
+ return strings.Join(labels, "."), nil
+}
+
+// ToUnicode converts a domain or domain label to its Unicode form. For example,
+// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
+// ToUnicode("golang") is "golang".
+func ToUnicode(s string) (string, error) {
+ if !strings.Contains(s, acePrefix) {
+ return s, nil
+ }
+ labels := strings.Split(s, ".")
+ for i, label := range labels {
+ if strings.HasPrefix(label, acePrefix) {
+ u, err := decode(label[len(acePrefix):])
+ if err != nil {
+ return "", err
+ }
+ labels[i] = u
+ }
+ }
+ return strings.Join(labels, "."), nil
+}
+
+func ascii(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/golang_org/x/net/idna/idna_test.go b/libgo/go/golang_org/x/net/idna/idna_test.go
new file mode 100644
index 0000000000..b1bc6fa225
--- /dev/null
+++ b/libgo/go/golang_org/x/net/idna/idna_test.go
@@ -0,0 +1,43 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package idna
+
+import (
+ "testing"
+)
+
+var idnaTestCases = [...]struct {
+ ascii, unicode string
+}{
+ // Labels.
+ {"books", "books"},
+ {"xn--bcher-kva", "bücher"},
+
+ // Domains.
+ {"foo--xn--bar.org", "foo--xn--bar.org"},
+ {"golang.org", "golang.org"},
+ {"example.xn--p1ai", "example.рф"},
+ {"xn--czrw28b.tw", "商業.tw"},
+ {"www.xn--mller-kva.de", "www.müller.de"},
+}
+
+func TestIDNA(t *testing.T) {
+ for _, tc := range idnaTestCases {
+ if a, err := ToASCII(tc.unicode); err != nil {
+ t.Errorf("ToASCII(%q): %v", tc.unicode, err)
+ } else if a != tc.ascii {
+ t.Errorf("ToASCII(%q): got %q, want %q", tc.unicode, a, tc.ascii)
+ }
+
+ if u, err := ToUnicode(tc.ascii); err != nil {
+ t.Errorf("ToUnicode(%q): %v", tc.ascii, err)
+ } else if u != tc.unicode {
+ t.Errorf("ToUnicode(%q): got %q, want %q", tc.ascii, u, tc.unicode)
+ }
+ }
+}
+
+// TODO(nigeltao): test errors, once we've specified when ToASCII and ToUnicode
+// return errors.
diff --git a/libgo/go/golang_org/x/net/idna/punycode.go b/libgo/go/golang_org/x/net/idna/punycode.go
new file mode 100644
index 0000000000..92e733f6a7
--- /dev/null
+++ b/libgo/go/golang_org/x/net/idna/punycode.go
@@ -0,0 +1,200 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package idna
+
+// This file implements the Punycode algorithm from RFC 3492.
+
+import (
+ "fmt"
+ "math"
+ "strings"
+ "unicode/utf8"
+)
+
+// These parameter values are specified in section 5.
+//
+// All computation is done with int32s, so that overflow behavior is identical
+// regardless of whether int is 32-bit or 64-bit.
+const (
+ base int32 = 36
+ damp int32 = 700
+ initialBias int32 = 72
+ initialN int32 = 128
+ skew int32 = 38
+ tmax int32 = 26
+ tmin int32 = 1
+)
+
+// decode decodes a string as specified in section 6.2.
+func decode(encoded string) (string, error) {
+ if encoded == "" {
+ return "", nil
+ }
+ pos := 1 + strings.LastIndex(encoded, "-")
+ if pos == 1 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ if pos == len(encoded) {
+ return encoded[:len(encoded)-1], nil
+ }
+ output := make([]rune, 0, len(encoded))
+ if pos != 0 {
+ for _, r := range encoded[:pos-1] {
+ output = append(output, r)
+ }
+ }
+ i, n, bias := int32(0), initialN, initialBias
+ for pos < len(encoded) {
+ oldI, w := i, int32(1)
+ for k := base; ; k += base {
+ if pos == len(encoded) {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ digit, ok := decodeDigit(encoded[pos])
+ if !ok {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ pos++
+ i += digit * w
+ if i < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ t := k - bias
+ if t < tmin {
+ t = tmin
+ } else if t > tmax {
+ t = tmax
+ }
+ if digit < t {
+ break
+ }
+ w *= base - t
+ if w >= math.MaxInt32/base {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ }
+ x := int32(len(output) + 1)
+ bias = adapt(i-oldI, x, oldI == 0)
+ n += i / x
+ i %= x
+ if n > utf8.MaxRune || len(output) >= 1024 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ output = append(output, 0)
+ copy(output[i+1:], output[i:])
+ output[i] = n
+ i++
+ }
+ return string(output), nil
+}
+
+// encode encodes a string as specified in section 6.3 and prepends prefix to
+// the result.
+//
+// The "while h < length(input)" line in the specification becomes "for
+// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
+func encode(prefix, s string) (string, error) {
+ output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
+ copy(output, prefix)
+ delta, n, bias := int32(0), initialN, initialBias
+ b, remaining := int32(0), int32(0)
+ for _, r := range s {
+ if r < 0x80 {
+ b++
+ output = append(output, byte(r))
+ } else {
+ remaining++
+ }
+ }
+ h := b
+ if b > 0 {
+ output = append(output, '-')
+ }
+ for remaining != 0 {
+ m := int32(0x7fffffff)
+ for _, r := range s {
+ if m > r && r >= n {
+ m = r
+ }
+ }
+ delta += (m - n) * (h + 1)
+ if delta < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", s)
+ }
+ n = m
+ for _, r := range s {
+ if r < n {
+ delta++
+ if delta < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", s)
+ }
+ continue
+ }
+ if r > n {
+ continue
+ }
+ q := delta
+ for k := base; ; k += base {
+ t := k - bias
+ if t < tmin {
+ t = tmin
+ } else if t > tmax {
+ t = tmax
+ }
+ if q < t {
+ break
+ }
+ output = append(output, encodeDigit(t+(q-t)%(base-t)))
+ q = (q - t) / (base - t)
+ }
+ output = append(output, encodeDigit(q))
+ bias = adapt(delta, h+1, h == b)
+ delta = 0
+ h++
+ remaining--
+ }
+ delta++
+ n++
+ }
+ return string(output), nil
+}
+
+func decodeDigit(x byte) (digit int32, ok bool) {
+ switch {
+ case '0' <= x && x <= '9':
+ return int32(x - ('0' - 26)), true
+ case 'A' <= x && x <= 'Z':
+ return int32(x - 'A'), true
+ case 'a' <= x && x <= 'z':
+ return int32(x - 'a'), true
+ }
+ return 0, false
+}
+
+func encodeDigit(digit int32) byte {
+ switch {
+ case 0 <= digit && digit < 26:
+ return byte(digit + 'a')
+ case 26 <= digit && digit < 36:
+ return byte(digit + ('0' - 26))
+ }
+ panic("idna: internal error in punycode encoding")
+}
+
+// adapt is the bias adaptation function specified in section 6.1.
+func adapt(delta, numPoints int32, firstTime bool) int32 {
+ if firstTime {
+ delta /= damp
+ } else {
+ delta /= 2
+ }
+ delta += delta / numPoints
+ k := int32(0)
+ for delta > ((base-tmin)*tmax)/2 {
+ delta /= base - tmin
+ k += base
+ }
+ return k + (base-tmin+1)*delta/(delta+skew)
+}
diff --git a/libgo/go/golang_org/x/net/idna/punycode_test.go b/libgo/go/golang_org/x/net/idna/punycode_test.go
new file mode 100644
index 0000000000..bfec81decd
--- /dev/null
+++ b/libgo/go/golang_org/x/net/idna/punycode_test.go
@@ -0,0 +1,198 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package idna
+
+import (
+ "strings"
+ "testing"
+)
+
+var punycodeTestCases = [...]struct {
+ s, encoded string
+}{
+ {"", ""},
+ {"-", "--"},
+ {"-a", "-a-"},
+ {"-a-", "-a--"},
+ {"a", "a-"},
+ {"a-", "a--"},
+ {"a-b", "a-b-"},
+ {"books", "books-"},
+ {"bücher", "bcher-kva"},
+ {"Hello世界", "Hello-ck1hg65u"},
+ {"ü", "tda"},
+ {"üý", "tdac"},
+
+ // The test cases below come from RFC 3492 section 7.1 with Errata 3026.
+ {
+ // (A) Arabic (Egyptian).
+ "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" +
+ "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F",
+ "egbpdaj6bu4bxfgehfvwxn",
+ },
+ {
+ // (B) Chinese (simplified).
+ "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587",
+ "ihqwcrb4cv8a8dqg056pqjye",
+ },
+ {
+ // (C) Chinese (traditional).
+ "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587",
+ "ihqwctvzc91f659drss3x8bo0yb",
+ },
+ {
+ // (D) Czech.
+ "\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" +
+ "\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" +
+ "\u0065\u0073\u006B\u0079",
+ "Proprostnemluvesky-uyb24dma41a",
+ },
+ {
+ // (E) Hebrew.
+ "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" +
+ "\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" +
+ "\u05D1\u05E8\u05D9\u05EA",
+ "4dbcagdahymbxekheh6e0a7fei0b",
+ },
+ {
+ // (F) Hindi (Devanagari).
+ "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" +
+ "\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" +
+ "\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" +
+ "\u0939\u0948\u0902",
+ "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd",
+ },
+ {
+ // (G) Japanese (kanji and hiragana).
+ "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" +
+ "\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B",
+ "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa",
+ },
+ {
+ // (H) Korean (Hangul syllables).
+ "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" +
+ "\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" +
+ "\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C",
+ "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j" +
+ "psd879ccm6fea98c",
+ },
+ {
+ // (I) Russian (Cyrillic).
+ "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" +
+ "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" +
+ "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" +
+ "\u0438",
+ "b1abfaaepdrnnbgefbadotcwatmq2g4l",
+ },
+ {
+ // (J) Spanish.
+ "\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" +
+ "\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" +
+ "\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" +
+ "\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" +
+ "\u0061\u00F1\u006F\u006C",
+ "PorqunopuedensimplementehablarenEspaol-fmd56a",
+ },
+ {
+ // (K) Vietnamese.
+ "\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" +
+ "\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" +
+ "\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" +
+ "\u0056\u0069\u1EC7\u0074",
+ "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g",
+ },
+ {
+ // (L) 3<nen>B<gumi><kinpachi><sensei>.
+ "\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F",
+ "3B-ww4c5e180e575a65lsy2b",
+ },
+ {
+ // (M) <amuro><namie>-with-SUPER-MONKEYS.
+ "\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" +
+ "\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" +
+ "\u004F\u004E\u004B\u0045\u0059\u0053",
+ "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n",
+ },
+ {
+ // (N) Hello-Another-Way-<sorezore><no><basho>.
+ "\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" +
+ "\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" +
+ "\u305D\u308C\u305E\u308C\u306E\u5834\u6240",
+ "Hello-Another-Way--fc4qua05auwb3674vfr0b",
+ },
+ {
+ // (O) <hitotsu><yane><no><shita>2.
+ "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032",
+ "2-u9tlzr9756bt3uc0v",
+ },
+ {
+ // (P) Maji<de>Koi<suru>5<byou><mae>
+ "\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" +
+ "\u308B\u0035\u79D2\u524D",
+ "MajiKoi5-783gue6qz075azm5e",
+ },
+ {
+ // (Q) <pafii>de<runba>
+ "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0",
+ "de-jg4avhby1noc0d",
+ },
+ {
+ // (R) <sono><supiido><de>
+ "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067",
+ "d9juau41awczczp",
+ },
+ {
+ // (S) -> $1.00 <-
+ "\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" +
+ "\u003C\u002D",
+ "-> $1.00 <--",
+ },
+}
+
+func TestPunycode(t *testing.T) {
+ for _, tc := range punycodeTestCases {
+ if got, err := decode(tc.encoded); err != nil {
+ t.Errorf("decode(%q): %v", tc.encoded, err)
+ } else if got != tc.s {
+ t.Errorf("decode(%q): got %q, want %q", tc.encoded, got, tc.s)
+ }
+
+ if got, err := encode("", tc.s); err != nil {
+ t.Errorf(`encode("", %q): %v`, tc.s, err)
+ } else if got != tc.encoded {
+ t.Errorf(`encode("", %q): got %q, want %q`, tc.s, got, tc.encoded)
+ }
+ }
+}
+
+var punycodeErrorTestCases = [...]string{
+ "decode -", // A sole '-' is invalid.
+ "decode foo\x00bar", // '\x00' is not in [0-9A-Za-z].
+ "decode foo#bar", // '#' is not in [0-9A-Za-z].
+ "decode foo\u00A3bar", // '\u00A3' is not in [0-9A-Za-z].
+ "decode 9", // "9a" decodes to codepoint \u00A3; "9" is truncated.
+ "decode 99999a", // "99999a" decodes to codepoint \U0048A3C1, which is > \U0010FFFF.
+ "decode 9999999999a", // "9999999999a" overflows the int32 calculation.
+
+ "encode " + strings.Repeat("x", 65536) + "\uff00", // int32 overflow.
+}
+
+func TestPunycodeErrors(t *testing.T) {
+ for _, tc := range punycodeErrorTestCases {
+ var err error
+ switch {
+ case strings.HasPrefix(tc, "decode "):
+ _, err = decode(tc[7:])
+ case strings.HasPrefix(tc, "encode "):
+ _, err = encode("", tc[7:])
+ }
+ if err == nil {
+ if len(tc) > 256 {
+ tc = tc[:100] + "..." + tc[len(tc)-100:]
+ }
+ t.Errorf("no error for %s", tc)
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/lex/httplex/httplex.go b/libgo/go/golang_org/x/net/lex/httplex/httplex.go
new file mode 100644
index 0000000000..b6493f045a
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lex/httplex/httplex.go
@@ -0,0 +1,351 @@
+// 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 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 (
+ "net"
+ "strings"
+ "unicode/utf8"
+
+ "golang_org/x/net/idna"
+)
+
+var isTokenTable = [127]bool{
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
+}
+
+func IsTokenRune(r rune) bool {
+ i := int(r)
+ return i < len(isTokenTable) && isTokenTable[i]
+}
+
+func isNotToken(r rune) bool {
+ return !IsTokenRune(r)
+}
+
+// HeaderValuesContainsToken reports whether any string in values
+// contains the provided token, ASCII case-insensitively.
+func HeaderValuesContainsToken(values []string, token string) bool {
+ for _, v := range values {
+ if headerValueContainsToken(v, token) {
+ return true
+ }
+ }
+ return false
+}
+
+// isOWS reports whether b is an optional whitespace byte, as defined
+// by RFC 7230 section 3.2.3.
+func isOWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// trimOWS returns x with all optional whitespace removes from the
+// beginning and end.
+func trimOWS(x string) string {
+ // TODO: consider using strings.Trim(x, " \t") instead,
+ // if and when it's fast enough. See issue 10292.
+ // But this ASCII-only code will probably always beat UTF-8
+ // aware code.
+ for len(x) > 0 && isOWS(x[0]) {
+ x = x[1:]
+ }
+ for len(x) > 0 && isOWS(x[len(x)-1]) {
+ x = x[:len(x)-1]
+ }
+ return x
+}
+
+// headerValueContainsToken reports whether v (assumed to be a
+// 0#element, in the ABNF extension described in RFC 7230 section 7)
+// contains token amongst its comma-separated tokens, ASCII
+// case-insensitively.
+func headerValueContainsToken(v string, token string) bool {
+ v = trimOWS(v)
+ if comma := strings.IndexByte(v, ','); comma != -1 {
+ return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
+ }
+ return tokenEqual(v, token)
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+ if 'A' <= b && b <= 'Z' {
+ return b + ('a' - 'A')
+ }
+ return b
+}
+
+// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
+func tokenEqual(t1, t2 string) bool {
+ if len(t1) != len(t2) {
+ return false
+ }
+ for i, b := range t1 {
+ if b >= utf8.RuneSelf {
+ // No UTF-8 or non-ASCII allowed in tokens.
+ return false
+ }
+ if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// isLWS reports whether b is linear white space, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+// LWS = [CRLF] 1*( SP | HT )
+func isLWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// isCTL reports whether b is a control byte, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+// CTL = <any US-ASCII control character
+// (octets 0 - 31) and DEL (127)>
+func isCTL(b byte) bool {
+ const del = 0x7f // a CTL
+ return b < ' ' || b == del
+}
+
+// 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 !IsTokenRune(r) {
+ return false
+ }
+ }
+ return true
+}
+
+// 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 ]
+ //
+ // Where uri-host is:
+ // http://tools.ietf.org/html/rfc3986#section-3.2.2
+ //
+ // But we're going to be much more lenient for now and just
+ // search for any byte that's not a valid byte in any of those
+ // expressions.
+ for i := 0; i < len(h); i++ {
+ if !validHostByte[h[i]] {
+ return false
+ }
+ }
+ return true
+}
+
+// See the validHostHeader comment.
+var validHostByte = [256]bool{
+ '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, 'v': true, 'w': true, 'x': true,
+ 'y': true, 'z': 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, // sub-delims
+ '$': true, // sub-delims
+ '%': true, // pct-encoded (and used in IPv6 zones)
+ '&': true, // sub-delims
+ '(': true, // sub-delims
+ ')': true, // sub-delims
+ '*': true, // sub-delims
+ '+': true, // sub-delims
+ ',': true, // sub-delims
+ '-': true, // unreserved
+ '.': true, // unreserved
+ ':': true, // IPv6address + Host expression's optional port
+ ';': true, // sub-delims
+ '=': true, // sub-delims
+ '[': true,
+ '\'': true, // sub-delims
+ ']': true,
+ '_': true, // unreserved
+ '~': true, // unreserved
+}
+
+// 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 ]
+// field-value = *( field-content | LWS )
+// field-content = <the OCTETs making up the field-value
+// and consisting of either *TEXT or combinations
+// of token, separators, and quoted-string>
+//
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
+//
+// TEXT = <any OCTET except CTLs,
+// but including LWS>
+// LWS = [CRLF] 1*( SP | HT )
+// CTL = <any US-ASCII control character
+// (octets 0 - 31) and DEL (127)>
+//
+// 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) {
+ return false
+ }
+ }
+ return true
+}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+// PunycodeHostPort returns the IDNA Punycode version
+// of the provided "host" or "host:port" string.
+func PunycodeHostPort(v string) (string, error) {
+ if isASCII(v) {
+ return v, nil
+ }
+
+ host, port, err := net.SplitHostPort(v)
+ if err != nil {
+ // The input 'v' argument was just a "host" argument,
+ // without a port. This error should not be returned
+ // to the caller.
+ host = v
+ port = ""
+ }
+ host, err = idna.ToASCII(host)
+ if err != nil {
+ // Non-UTF-8? Not representable in Punycode, in any
+ // case.
+ return "", err
+ }
+ if port == "" {
+ return host, nil
+ }
+ return net.JoinHostPort(host, port), nil
+}
diff --git a/libgo/go/net/http/lex_test.go b/libgo/go/golang_org/x/net/lex/httplex/httplex_test.go
index 986fda17dc..f47adc939f 100644
--- a/libgo/go/net/http/lex_test.go
+++ b/libgo/go/golang_org/x/net/lex/httplex/httplex_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package http
+package httplex
import (
"testing"
@@ -24,7 +24,7 @@ func TestIsToken(t *testing.T) {
for i := 0; i <= 130; i++ {
r := rune(i)
expected := isChar(r) && !isCtl(r) && !isSeparator(r)
- if isToken(r) != expected {
+ if IsTokenRune(r) != expected {
t.Errorf("isToken(0x%x) = %v", r, !expected)
}
}
@@ -93,9 +93,27 @@ 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)
}
}
}
+
+func TestPunycodeHostPort(t *testing.T) {
+ tests := []struct {
+ in, want string
+ }{
+ {"www.google.com", "www.google.com"},
+ {"гофер.рф", "xn--c1ae0ajs.xn--p1ai"},
+ {"bücher.de", "xn--bcher-kva.de"},
+ {"bücher.de:8080", "xn--bcher-kva.de:8080"},
+ {"[1::6]:8080", "[1::6]:8080"},
+ }
+ for _, tt := range tests {
+ got, err := PunycodeHostPort(tt.in)
+ if tt.want != got || err != nil {
+ t.Errorf("PunycodeHostPort(%q) = %q, %v, want %q, nil", tt.in, got, err, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/lif/address.go b/libgo/go/golang_org/x/net/lif/address.go
new file mode 100644
index 0000000000..f9b34aed03
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/address.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import (
+ "errors"
+ "unsafe"
+)
+
+// An Addr represents an address associated with packet routing.
+type Addr interface {
+ // Family returns an address family.
+ Family() int
+}
+
+// An Inet4Addr represents an internet address for IPv4.
+type Inet4Addr struct {
+ IP [4]byte // IP address
+ PrefixLen int // address prefix length
+}
+
+// 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
+ PrefixLen int // address prefix length
+ ZoneID int // zone identifier
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet6Addr) Family() int { return sysAF_INET6 }
+
+// Addrs returns a list of interface addresses.
+//
+// The provided af must be an address family and name must be a data
+// link name. The zero value of af or name means a wildcard.
+func Addrs(af int, name string) ([]Addr, error) {
+ eps, err := newEndpoints(af)
+ if len(eps) == 0 {
+ return nil, err
+ }
+ defer func() {
+ for _, ep := range eps {
+ ep.close()
+ }
+ }()
+ lls, err := links(eps, name)
+ if len(lls) == 0 {
+ return nil, err
+ }
+ var as []Addr
+ for _, ll := range lls {
+ var lifr lifreq
+ for i := 0; i < len(ll.Name); i++ {
+ lifr.Name[i] = int8(ll.Name[i])
+ }
+ for _, ep := range eps {
+ ioc := int64(sysSIOCGLIFADDR)
+ err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifr))
+ if err != nil {
+ continue
+ }
+ sa := (*sockaddrStorage)(unsafe.Pointer(&lifr.Lifru[0]))
+ l := int(littleEndian.Uint32(lifr.Lifru1[:4]))
+ if l == 0 {
+ continue
+ }
+ switch sa.Family {
+ case sysAF_INET:
+ a := &Inet4Addr{PrefixLen: l}
+ copy(a.IP[:], lifr.Lifru[4:8])
+ as = append(as, a)
+ case sysAF_INET6:
+ a := &Inet6Addr{PrefixLen: l, ZoneID: int(littleEndian.Uint32(lifr.Lifru[24:28]))}
+ copy(a.IP[:], lifr.Lifru[8:24])
+ as = append(as, a)
+ }
+ }
+ }
+ return as, nil
+}
+
+func parseLinkAddr(b []byte) ([]byte, error) {
+ nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
+ l := 4 + nlen + alen + slen
+ if len(b) < l {
+ return nil, errors.New("invalid address")
+ }
+ b = b[4:]
+ var addr []byte
+ if nlen > 0 {
+ b = b[nlen:]
+ }
+ if alen > 0 {
+ addr = make([]byte, alen)
+ copy(addr, b[:alen])
+ }
+ return addr, nil
+}
diff --git a/libgo/go/golang_org/x/net/lif/address_test.go b/libgo/go/golang_org/x/net/lif/address_test.go
new file mode 100644
index 0000000000..f62ed93471
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/address_test.go
@@ -0,0 +1,121 @@
+// 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 solaris
+
+package lif
+
+import (
+ "fmt"
+ "testing"
+)
+
+type addrFamily int
+
+func (af addrFamily) String() string {
+ switch af {
+ case sysAF_UNSPEC:
+ return "unspec"
+ 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 *Inet4Addr) String() string {
+ return fmt.Sprintf("(%s %s %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.PrefixLen)
+}
+
+func (a *Inet6Addr) String() string {
+ return fmt.Sprintf("(%s %s %d %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.PrefixLen, a.ZoneID)
+}
+
+type addrPack struct {
+ af int
+ as []Addr
+}
+
+func addrPacks() ([]addrPack, error) {
+ var aps []addrPack
+ for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ as, err := Addrs(af, "")
+ if err != nil {
+ return nil, err
+ }
+ aps = append(aps, addrPack{af: af, as: as})
+ }
+ return aps, nil
+}
+
+func TestAddrs(t *testing.T) {
+ aps, err := addrPacks()
+ if len(aps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ lps, err := linkPacks()
+ if len(lps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ for _, lp := range lps {
+ n := 0
+ for _, ll := range lp.lls {
+ as, err := Addrs(lp.af, ll.Name)
+ if err != nil {
+ t.Fatal(lp.af, ll.Name, err)
+ }
+ t.Logf("af=%s name=%s %v", addrFamily(lp.af), ll.Name, as)
+ n += len(as)
+ }
+ for _, ap := range aps {
+ if ap.af != lp.af {
+ continue
+ }
+ if n != len(ap.as) {
+ t.Errorf("af=%s got %d; want %d", addrFamily(lp.af), n, len(ap.as))
+ continue
+ }
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/lif/binary.go b/libgo/go/golang_org/x/net/lif/binary.go
new file mode 100644
index 0000000000..aade9eafa2
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/binary.go
@@ -0,0 +1,68 @@
+// 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 solaris
+
+package lif
+
+// This file contains duplicates of encoding/binary package.
+//
+// This package is supposed to be used by the net package of standard
+// library. Therefore the package set used in the package must be the
+// same as net package.
+
+var littleEndian binaryLittleEndian
+
+type binaryByteOrder interface {
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ Uint64([]byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]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
+}
+
+func (binaryLittleEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // 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)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
diff --git a/libgo/go/golang_org/x/net/lif/defs_solaris.go b/libgo/go/golang_org/x/net/lif/defs_solaris.go
new file mode 100644
index 0000000000..8b84ba5e33
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/defs_solaris.go
@@ -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 ignore
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package lif
+
+/*
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_INET6 = C.AF_INET6
+
+ sysSOCK_DGRAM = C.SOCK_DGRAM
+)
+
+type sockaddrStorage C.struct_sockaddr_storage
+
+const (
+ sysLIFC_NOXMIT = C.LIFC_NOXMIT
+ sysLIFC_EXTERNAL_SOURCE = C.LIFC_EXTERNAL_SOURCE
+ sysLIFC_TEMPORARY = C.LIFC_TEMPORARY
+ sysLIFC_ALLZONES = C.LIFC_ALLZONES
+ sysLIFC_UNDER_IPMP = C.LIFC_UNDER_IPMP
+ sysLIFC_ENABLED = C.LIFC_ENABLED
+
+ sysSIOCGLIFADDR = C.SIOCGLIFADDR
+ sysSIOCGLIFDSTADDR = C.SIOCGLIFDSTADDR
+ sysSIOCGLIFFLAGS = C.SIOCGLIFFLAGS
+ sysSIOCGLIFMTU = C.SIOCGLIFMTU
+ sysSIOCGLIFNETMASK = C.SIOCGLIFNETMASK
+ sysSIOCGLIFMETRIC = C.SIOCGLIFMETRIC
+ sysSIOCGLIFNUM = C.SIOCGLIFNUM
+ sysSIOCGLIFINDEX = C.SIOCGLIFINDEX
+ sysSIOCGLIFSUBNET = C.SIOCGLIFSUBNET
+ sysSIOCGLIFLNKINFO = C.SIOCGLIFLNKINFO
+ sysSIOCGLIFCONF = C.SIOCGLIFCONF
+ sysSIOCGLIFHWADDR = C.SIOCGLIFHWADDR
+)
+
+const (
+ sysIFF_UP = C.IFF_UP
+ sysIFF_BROADCAST = C.IFF_BROADCAST
+ sysIFF_DEBUG = C.IFF_DEBUG
+ sysIFF_LOOPBACK = C.IFF_LOOPBACK
+ sysIFF_POINTOPOINT = C.IFF_POINTOPOINT
+ sysIFF_NOTRAILERS = C.IFF_NOTRAILERS
+ sysIFF_RUNNING = C.IFF_RUNNING
+ sysIFF_NOARP = C.IFF_NOARP
+ sysIFF_PROMISC = C.IFF_PROMISC
+ sysIFF_ALLMULTI = C.IFF_ALLMULTI
+ sysIFF_INTELLIGENT = C.IFF_INTELLIGENT
+ sysIFF_MULTICAST = C.IFF_MULTICAST
+ sysIFF_MULTI_BCAST = C.IFF_MULTI_BCAST
+ sysIFF_UNNUMBERED = C.IFF_UNNUMBERED
+ sysIFF_PRIVATE = C.IFF_PRIVATE
+)
+
+const (
+ sizeofLifnum = C.sizeof_struct_lifnum
+ sizeofLifreq = C.sizeof_struct_lifreq
+ sizeofLifconf = C.sizeof_struct_lifconf
+ sizeofLifIfinfoReq = C.sizeof_struct_lif_ifinfo_req
+)
+
+type sysLifnum C.struct_lifnum
+
+type lifreq C.struct_lifreq
+
+type lifconf C.struct_lifconf
+
+type lifIfinfoReq C.struct_lif_ifinfo_req
+
+const (
+ sysIFT_IPV4 = C.IFT_IPV4
+ sysIFT_IPV6 = C.IFT_IPV6
+ sysIFT_6TO4 = C.IFT_6TO4
+)
diff --git a/libgo/go/golang_org/x/net/lif/lif.go b/libgo/go/golang_org/x/net/lif/lif.go
new file mode 100644
index 0000000000..6e81f81f1c
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/lif.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+// Package lif provides basic functions for the manipulation of
+// logical network interfaces and interface addresses on Solaris.
+//
+// The package supports Solaris 11 or above.
+package lif
+
+import "syscall"
+
+type endpoint struct {
+ af int
+ s uintptr
+}
+
+func (ep *endpoint) close() error {
+ return syscall.Close(int(ep.s))
+}
+
+func newEndpoints(af int) ([]endpoint, error) {
+ var lastErr error
+ var eps []endpoint
+ afs := []int{sysAF_INET, sysAF_INET6}
+ if af != sysAF_UNSPEC {
+ afs = []int{af}
+ }
+ for _, af := range afs {
+ s, err := syscall.Socket(af, sysSOCK_DGRAM, 0)
+ if err != nil {
+ lastErr = err
+ continue
+ }
+ eps = append(eps, endpoint{af: af, s: uintptr(s)})
+ }
+ if len(eps) == 0 {
+ return nil, lastErr
+ }
+ return eps, nil
+}
diff --git a/libgo/go/golang_org/x/net/lif/link.go b/libgo/go/golang_org/x/net/lif/link.go
new file mode 100644
index 0000000000..6a77a8f5d8
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/link.go
@@ -0,0 +1,122 @@
+// 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 solaris
+
+package lif
+
+import "unsafe"
+
+// A Link represents logical data link information.
+//
+// It also represents base information for logical network interface.
+// On Solaris, each logical network interface represents network layer
+// adjacency information and the interface has a only single network
+// address or address pair for tunneling. It's usual that multiple
+// logical network interfaces share the same logical data link.
+type Link struct {
+ Name string // name, equivalent to IP interface name
+ Index int // index, equivalent to IP interface index
+ Type int // type
+ Flags int // flags
+ MTU int // maximum transmission unit, basically link MTU but may differ between IP address families
+ Addr []byte // address
+}
+
+func (ll *Link) fetch(s uintptr) {
+ var lifr lifreq
+ for i := 0; i < len(ll.Name); i++ {
+ lifr.Name[i] = int8(ll.Name[i])
+ }
+ ioc := int64(sysSIOCGLIFINDEX)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.Index = int(littleEndian.Uint32(lifr.Lifru[:4]))
+ }
+ ioc = int64(sysSIOCGLIFFLAGS)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.Flags = int(littleEndian.Uint64(lifr.Lifru[:8]))
+ }
+ ioc = int64(sysSIOCGLIFMTU)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.MTU = int(littleEndian.Uint32(lifr.Lifru[:4]))
+ }
+ switch ll.Type {
+ case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
+ default:
+ ioc = int64(sysSIOCGLIFHWADDR)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
+ }
+ }
+}
+
+// Links returns a list of logical data links.
+//
+// The provided af must be an address family and name must be a data
+// link name. The zero value of af or name means a wildcard.
+func Links(af int, name string) ([]Link, error) {
+ eps, err := newEndpoints(af)
+ if len(eps) == 0 {
+ return nil, err
+ }
+ defer func() {
+ for _, ep := range eps {
+ ep.close()
+ }
+ }()
+ return links(eps, name)
+}
+
+func links(eps []endpoint, name string) ([]Link, error) {
+ var lls []Link
+ lifn := sysLifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
+ lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
+ for _, ep := range eps {
+ lifn.Family = uint16(ep.af)
+ ioc := int64(sysSIOCGLIFNUM)
+ if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
+ continue
+ }
+ if lifn.Count == 0 {
+ continue
+ }
+ b := make([]byte, lifn.Count*sizeofLifreq)
+ lifc.Family = uint16(ep.af)
+ lifc.Len = lifn.Count * sizeofLifreq
+ lifc.Lifcu = unsafe.Pointer(&b[0])
+ ioc = int64(sysSIOCGLIFCONF)
+ if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
+ continue
+ }
+ nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h
+ for i := 0; i < int(lifn.Count); i++ {
+ lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
+ for i := 0; i < 32; i++ {
+ if lifr.Name[i] == 0 {
+ nb = nb[:i]
+ break
+ }
+ nb[i] = byte(lifr.Name[i])
+ }
+ llname := string(nb)
+ nb = nb[:32]
+ if isDupLink(lls, llname) || name != "" && name != llname {
+ continue
+ }
+ ll := Link{Name: llname, Type: int(lifr.Type)}
+ ll.fetch(ep.s)
+ lls = append(lls, ll)
+ }
+ }
+ return lls, nil
+}
+
+func isDupLink(lls []Link, name string) bool {
+ for _, ll := range lls {
+ if ll.Name == name {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/golang_org/x/net/lif/link_test.go b/libgo/go/golang_org/x/net/lif/link_test.go
new file mode 100644
index 0000000000..8fb2bf6f34
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/link_test.go
@@ -0,0 +1,61 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import (
+ "fmt"
+ "testing"
+)
+
+func (ll *Link) String() string {
+ return fmt.Sprintf("name=%s index=%d type=%d flags=%#x mtu=%d addr=%v", ll.Name, ll.Index, ll.Type, ll.Flags, ll.MTU, llAddr(ll.Addr))
+}
+
+type linkPack struct {
+ af int
+ lls []Link
+}
+
+func linkPacks() ([]linkPack, error) {
+ var lps []linkPack
+ for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ lls, err := Links(af, "")
+ if err != nil {
+ return nil, err
+ }
+ lps = append(lps, linkPack{af: af, lls: lls})
+ }
+ return lps, nil
+}
+
+func TestLinks(t *testing.T) {
+ lps, err := linkPacks()
+ if len(lps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ for _, lp := range lps {
+ n := 0
+ for _, sll := range lp.lls {
+ lls, err := Links(lp.af, sll.Name)
+ if err != nil {
+ t.Fatal(lp.af, sll.Name, err)
+ }
+ for _, ll := range lls {
+ if ll.Name != sll.Name || ll.Index != sll.Index {
+ t.Errorf("af=%s got %v; want %v", addrFamily(lp.af), &ll, &sll)
+ continue
+ }
+ t.Logf("af=%s name=%s %v", addrFamily(lp.af), sll.Name, &ll)
+ n++
+ }
+ }
+ if n != len(lp.lls) {
+ t.Errorf("af=%s got %d; want %d", addrFamily(lp.af), n, len(lp.lls))
+ continue
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/lif/syscall.go b/libgo/go/golang_org/x/net/lif/syscall.go
new file mode 100644
index 0000000000..ea7541456b
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/syscall.go
@@ -0,0 +1,22 @@
+// 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 solaris
+
+package lif
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+//extern __go_ioctl_ptr
+func libc_ioctl(int32, int32, unsafe.Pointer) int32
+
+func ioctl(s, ioc uintptr, arg unsafe.Pointer) error {
+ if libc_ioctl(int32(s), int32(ioc), arg) < 0 {
+ return syscall.GetErrno()
+ }
+ return nil
+}
diff --git a/libgo/go/golang_org/x/net/lif/zsys_solaris.go b/libgo/go/golang_org/x/net/lif/zsys_solaris.go
new file mode 100644
index 0000000000..6452dd8ebb
--- /dev/null
+++ b/libgo/go/golang_org/x/net/lif/zsys_solaris.go
@@ -0,0 +1,98 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_solaris.go
+
+package lif
+
+import "unsafe"
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_INET6 = 0x1a
+
+ sysSOCK_DGRAM = 0x1
+)
+
+type sockaddrStorage struct {
+ Family uint16
+ X_ss_pad1 [6]int8
+ X_ss_align float64
+ X_ss_pad2 [240]int8
+}
+
+const (
+ sysLIFC_NOXMIT = 0x1
+ sysLIFC_EXTERNAL_SOURCE = 0x2
+ sysLIFC_TEMPORARY = 0x4
+ sysLIFC_ALLZONES = 0x8
+ sysLIFC_UNDER_IPMP = 0x10
+ sysLIFC_ENABLED = 0x20
+
+ sysSIOCGLIFADDR = -0x3f87968f
+ sysSIOCGLIFDSTADDR = -0x3f87968d
+ sysSIOCGLIFFLAGS = -0x3f87968b
+ sysSIOCGLIFMTU = -0x3f879686
+ sysSIOCGLIFNETMASK = -0x3f879683
+ sysSIOCGLIFMETRIC = -0x3f879681
+ sysSIOCGLIFNUM = -0x3ff3967e
+ sysSIOCGLIFINDEX = -0x3f87967b
+ sysSIOCGLIFSUBNET = -0x3f879676
+ sysSIOCGLIFLNKINFO = -0x3f879674
+ sysSIOCGLIFCONF = -0x3fef965b
+ sysSIOCGLIFHWADDR = -0x3f879640
+)
+
+const (
+ sysIFF_UP = 0x1
+ sysIFF_BROADCAST = 0x2
+ sysIFF_DEBUG = 0x4
+ sysIFF_LOOPBACK = 0x8
+ sysIFF_POINTOPOINT = 0x10
+ sysIFF_NOTRAILERS = 0x20
+ sysIFF_RUNNING = 0x40
+ sysIFF_NOARP = 0x80
+ sysIFF_PROMISC = 0x100
+ sysIFF_ALLMULTI = 0x200
+ sysIFF_INTELLIGENT = 0x400
+ sysIFF_MULTICAST = 0x800
+ sysIFF_MULTI_BCAST = 0x1000
+ sysIFF_UNNUMBERED = 0x2000
+ sysIFF_PRIVATE = 0x8000
+)
+
+const (
+ sizeofLifreq = 0x178
+)
+
+type sysLifnum struct {
+ Family uint16
+ Flags int32
+ Count int32
+}
+
+type lifreq struct {
+ Name [32]int8
+ Lifru1 [4]byte
+ Type uint32
+ Lifru [336]byte
+}
+
+type lifconf struct {
+ Family uint16
+ Flags int32
+ Len int32
+ Lifcu unsafe.Pointer
+}
+
+type lifIfinfoReq struct {
+ Maxhops uint8
+ Reachtime uint32
+ Reachretrans uint32
+ Maxmtu uint32
+}
+
+const (
+ sysIFT_IPV4 = 0xc8
+ sysIFT_IPV6 = 0xc9
+ sysIFT_6TO4 = 0xca
+)
diff --git a/libgo/go/golang_org/x/net/route/address.go b/libgo/go/golang_org/x/net/route/address.go
new file mode 100644
index 0000000000..a56909c105
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/address.go
@@ -0,0 +1,281 @@
+// 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
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
+ case sysAF_INET, sysAF_INET6:
+ af = int(b[1])
+ a, err := parseInetAddr(af, b)
+ if err != nil {
+ return nil, err
+ }
+ as[i] = a
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
+ 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
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
+ }
+ }
+ return as[:], nil
+}
diff --git a/libgo/go/golang_org/x/net/route/address_darwin_test.go b/libgo/go/golang_org/x/net/route/address_darwin_test.go
new file mode 100644
index 0000000000..b86bd3df1f
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/address_darwin_test.go
@@ -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/libgo/go/golang_org/x/net/route/address_test.go b/libgo/go/golang_org/x/net/route/address_test.go
new file mode 100644
index 0000000000..2005ef7c20
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/address_test.go
@@ -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/libgo/go/golang_org/x/net/route/binary.go b/libgo/go/golang_org/x/net/route/binary.go
new file mode 100644
index 0000000000..4c561631b9
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/binary.go
@@ -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/libgo/go/golang_org/x/net/route/defs_darwin.go b/libgo/go/golang_org/x/net/route/defs_darwin.go
new file mode 100644
index 0000000000..f452ad14ce
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/defs_darwin.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package route
+
+/*
+#include <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/libgo/go/golang_org/x/net/route/defs_dragonfly.go b/libgo/go/golang_org/x/net/route/defs_dragonfly.go
new file mode 100644
index 0000000000..c737751d76
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/defs_dragonfly.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package route
+
+/*
+#include <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/libgo/go/golang_org/x/net/route/defs_freebsd.go b/libgo/go/golang_org/x/net/route/defs_freebsd.go
new file mode 100644
index 0000000000..8f834e81db
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/defs_freebsd.go
@@ -0,0 +1,329 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package route
+
+/*
+#include <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/libgo/go/golang_org/x/net/route/defs_netbsd.go b/libgo/go/golang_org/x/net/route/defs_netbsd.go
new file mode 100644
index 0000000000..b18d85e016
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/defs_netbsd.go
@@ -0,0 +1,104 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package route
+
+/*
+#include <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/libgo/go/golang_org/x/net/route/defs_openbsd.go b/libgo/go/golang_org/x/net/route/defs_openbsd.go
new file mode 100644
index 0000000000..5df7a43bc3
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/defs_openbsd.go
@@ -0,0 +1,93 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package route
+
+/*
+#include <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/libgo/go/golang_org/x/net/route/interface.go b/libgo/go/golang_org/x/net/route/interface.go
new file mode 100644
index 0000000000..854906d9c4
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface.go
@@ -0,0 +1,64 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+// An InterfaceMessage represents an interface message.
+type InterfaceMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // interface flags
+ Index int // interface index
+ Name string // interface name
+ Addrs []Addr // addresses
+
+ extOff int // offset of header extension
+ raw []byte // raw message
+}
+
+// An InterfaceAddrMessage represents an interface address message.
+type InterfaceAddrMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // interface flags
+ Index int // interface index
+ Addrs []Addr // addresses
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceMulticastAddrMessage represents an interface multicast
+// address message.
+type InterfaceMulticastAddrMessage struct {
+ Version int // message version
+ Type int // messsage type
+ Flags int // interface flags
+ Index int // interface index
+ Addrs []Addr // addresses
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMulticastAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceAnnounceMessage represents an interface announcement
+// message.
+type InterfaceAnnounceMessage struct {
+ Version int // message version
+ Type int // message type
+ Index int // interface index
+ Name string // interface name
+ What int // what type of announcement
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAnnounceMessage) Sys() []Sys { return nil }
diff --git a/libgo/go/golang_org/x/net/route/interface_announce.go b/libgo/go/golang_org/x/net/route/interface_announce.go
new file mode 100644
index 0000000000..520d657b57
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface_announce.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd netbsd
+
+package route
+
+func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAnnounceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Index: int(nativeEndian.Uint16(b[4:6])),
+ What: int(nativeEndian.Uint16(b[22:24])),
+ raw: b[:l],
+ }
+ for i := 0; i < 16; i++ {
+ if b[6+i] != 0 {
+ continue
+ }
+ m.Name = string(b[6 : 6+i])
+ break
+ }
+ return m, nil
+}
diff --git a/libgo/go/golang_org/x/net/route/interface_classic.go b/libgo/go/golang_org/x/net/route/interface_classic.go
new file mode 100644
index 0000000000..ac4e7a6805
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface_classic.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly netbsd
+
+package route
+
+import "runtime"
+
+func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ attrs := uint(nativeEndian.Uint32(b[4:8]))
+ if attrs&sysRTA_IFP == 0 {
+ return nil, nil
+ }
+ m := &InterfaceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Addrs: make([]Addr, sysRTAX_MAX),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ extOff: w.extOff,
+ raw: b[:l],
+ }
+ a, err := parseLinkAddr(b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs[sysRTAX_IFP] = a
+ m.Name = a.(*LinkAddr).Name
+ return m, nil
+}
+
+func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ raw: b[:l],
+ }
+ if runtime.GOOS == "netbsd" {
+ m.Index = int(nativeEndian.Uint16(b[16:18]))
+ } else {
+ m.Index = int(nativeEndian.Uint16(b[12:14]))
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
diff --git a/libgo/go/golang_org/x/net/route/interface_freebsd.go b/libgo/go/golang_org/x/net/route/interface_freebsd.go
new file mode 100644
index 0000000000..9f6f50c00f
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface_freebsd.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, error) {
+ var extOff, bodyOff int
+ if typ == sysNET_RT_IFLISTL {
+ if len(b) < 20 {
+ return nil, errMessageTooShort
+ }
+ extOff = int(nativeEndian.Uint16(b[18:20]))
+ bodyOff = int(nativeEndian.Uint16(b[16:18]))
+ } else {
+ extOff = w.extOff
+ bodyOff = w.bodyOff
+ }
+ if len(b) < extOff || len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
+ 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 {
+ bodyOff = w.bodyOff
+ }
+ if len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
+ 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/libgo/go/golang_org/x/net/route/interface_multicast.go b/libgo/go/golang_org/x/net/route/interface_multicast.go
new file mode 100644
index 0000000000..1e99a9cc64
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface_multicast.go
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd
+
+package route
+
+func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceMulticastAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
diff --git a/libgo/go/golang_org/x/net/route/interface_openbsd.go b/libgo/go/golang_org/x/net/route/interface_openbsd.go
new file mode 100644
index 0000000000..e4a143c1c7
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/interface_openbsd.go
@@ -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.
+
+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],
+ }
+ ll := int(nativeEndian.Uint16(b[4:6]))
+ if len(b) < ll {
+ return nil, errInvalidMessage
+ }
+ a, err := parseLinkAddr(b[ll:])
+ 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]))
+ if len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
+ 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/libgo/go/golang_org/x/net/route/message.go b/libgo/go/golang_org/x/net/route/message.go
new file mode 100644
index 0000000000..d7ae0eb50f
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/message.go
@@ -0,0 +1,76 @@
+// 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 l == 0 {
+ return nil, errInvalidMessage
+ }
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ 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/libgo/go/golang_org/x/net/route/message_darwin_test.go b/libgo/go/golang_org/x/net/route/message_darwin_test.go
new file mode 100644
index 0000000000..3fdd12df55
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/message_darwin_test.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "testing"
+
+func TestFetchAndParseRIBOnDarwin(t *testing.T) {
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ for _, typ := range []RIBType{sysNET_RT_FLAGS, sysNET_RT_DUMP2, sysNET_RT_IFLIST2} {
+ ms, err := fetchAndParseRIB(af, typ)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Errorf("%v %d %v", addrFamily(af), typ, err)
+ continue
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/message_freebsd_test.go b/libgo/go/golang_org/x/net/route/message_freebsd_test.go
new file mode 100644
index 0000000000..785c273f65
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/message_freebsd_test.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import (
+ "testing"
+ "time"
+ "unsafe"
+)
+
+func TestFetchAndParseRIBOnFreeBSD(t *testing.T) {
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ for _, typ := range []RIBType{sysNET_RT_IFMALIST} {
+ ms, err := fetchAndParseRIB(af, typ)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Errorf("%v %d %v", addrFamily(af), typ, err)
+ continue
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }
+}
+
+func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) {
+ if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil {
+ t.Skip("NET_RT_IFLISTL not supported")
+ }
+ var p uintptr
+ if kernelAlign != int(unsafe.Sizeof(p)) {
+ t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL 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/libgo/go/golang_org/x/net/route/message_test.go b/libgo/go/golang_org/x/net/route/message_test.go
new file mode 100644
index 0000000000..c0c7c57a9a
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/message_test.go
@@ -0,0 +1,118 @@
+// 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)
+ }
+}
+
+func TestParseRIBWithFuzz(t *testing.T) {
+ for _, fuzz := range []string{
+ "0\x00\x05\x050000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "0000000000000\x02000000" +
+ "00000000",
+ "\x02\x00\x05\f0000000000000000" +
+ "0\x0200000000000000",
+ "\x02\x00\x05\x100000000000000\x1200" +
+ "0\x00\xff\x00",
+ "\x02\x00\x05\f0000000000000000" +
+ "0\x12000\x00\x02\x0000",
+ "\x00\x00\x00\x01\x00",
+ "00000",
+ } {
+ for typ := RIBType(0); typ < 256; typ++ {
+ ParseRIB(typ, []byte(fuzz))
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/route.go b/libgo/go/golang_org/x/net/route/route.go
new file mode 100644
index 0000000000..c986e29ebc
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/route.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+// Package route provides basic functions for the manipulation of
+// packet routing facilities on BSD variants.
+//
+// The package supports any version of Darwin, any version of
+// DragonFly BSD, FreeBSD 7 through 11, NetBSD 6 and above, and
+// OpenBSD 5.6 and above.
+package route
+
+import (
+ "errors"
+ "os"
+ "syscall"
+)
+
+var (
+ errUnsupportedMessage = errors.New("unsupported message")
+ errMessageMismatch = errors.New("message mismatch")
+ errMessageTooShort = errors.New("message too short")
+ errInvalidMessage = errors.New("invalid message")
+ errInvalidAddr = errors.New("invalid address")
+)
+
+// A RouteMessage represents a message conveying an address prefix, a
+// nexthop address and an output interface.
+type RouteMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // route flags
+ Index int // interface index when atatched
+ Addrs []Addr // addresses
+
+ extOff int // offset of header extension
+ raw []byte // raw message
+}
+
+// A RIBType reprensents a type of routing information base.
+type RIBType int
+
+const (
+ RIBTypeRoute RIBType = syscall.NET_RT_DUMP
+ RIBTypeInterface RIBType = syscall.NET_RT_IFLIST
+)
+
+// FetchRIB fetches a routing information base from the operating
+// system.
+//
+// The provided af must be an address family.
+//
+// The provided arg must be a RIBType-specific argument.
+// When RIBType is related to routes, arg might be a set of route
+// flags. When RIBType is related to network interfaces, arg might be
+// an interface index or a set of interface flags. In most cases, zero
+// means a wildcard.
+func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) {
+ mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
+ n := uintptr(0)
+ if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ b := make([]byte, n)
+ if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ return b[:n], nil
+}
diff --git a/libgo/go/golang_org/x/net/route/route_classic.go b/libgo/go/golang_org/x/net/route/route_classic.go
new file mode 100644
index 0000000000..d333c6aa52
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/route_classic.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd
+
+package route
+
+func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &RouteMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[4:6])),
+ extOff: w.extOff,
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
diff --git a/libgo/go/golang_org/x/net/route/route_openbsd.go b/libgo/go/golang_org/x/net/route/route_openbsd.go
new file mode 100644
index 0000000000..76eae40d80
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/route_openbsd.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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],
+ }
+ ll := int(nativeEndian.Uint16(b[4:6]))
+ if len(b) < ll {
+ return nil, errInvalidMessage
+ }
+ as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[ll:])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs = as
+ return m, nil
+}
diff --git a/libgo/go/golang_org/x/net/route/route_test.go b/libgo/go/golang_org/x/net/route/route_test.go
new file mode 100644
index 0000000000..63fd8c5618
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/route_test.go
@@ -0,0 +1,386 @@
+// 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
+}
+
+// propVirtual is a proprietary virtual network interface.
+type propVirtual struct {
+ name string
+ addr, mask string
+ setupCmds []*exec.Cmd
+ teardownCmds []*exec.Cmd
+}
+
+func (pv *propVirtual) setup() error {
+ for _, cmd := range pv.setupCmds {
+ if err := cmd.Run(); err != nil {
+ pv.teardown()
+ return err
+ }
+ }
+ return nil
+}
+
+func (pv *propVirtual) teardown() error {
+ for _, cmd := range pv.teardownCmds {
+ if err := cmd.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (pv *propVirtual) configure(suffix int) error {
+ if runtime.GOOS == "openbsd" {
+ pv.name = fmt.Sprintf("vether%d", suffix)
+ } else {
+ pv.name = fmt.Sprintf("vlan%d", suffix)
+ }
+ xname, err := exec.LookPath("ifconfig")
+ if err != nil {
+ return err
+ }
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", pv.name, "create"},
+ })
+ if runtime.GOOS == "netbsd" {
+ // NetBSD requires an underlying dot1Q-capable network
+ // interface.
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
+ })
+ }
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask},
+ })
+ pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", pv.name, "destroy"},
+ })
+ return nil
+}
diff --git a/libgo/go/golang_org/x/net/route/sys.go b/libgo/go/golang_org/x/net/route/sys.go
new file mode 100644
index 0000000000..80ca83ae13
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import "unsafe"
+
+var (
+ nativeEndian binaryByteOrder
+ kernelAlign int
+ parseFns map[int]parseFn
+)
+
+func init() {
+ i := uint32(1)
+ b := (*[4]byte)(unsafe.Pointer(&i))
+ if b[0] == 1 {
+ nativeEndian = littleEndian
+ } else {
+ nativeEndian = bigEndian
+ }
+ kernelAlign, parseFns = probeRoutingStack()
+}
+
+func roundup(l int) int {
+ if l == 0 {
+ return kernelAlign
+ }
+ return (l + kernelAlign - 1) & ^(kernelAlign - 1)
+}
+
+type parseFn func(RIBType, []byte) (Message, error)
+
+type wireFormat struct {
+ extOff int // offset of header extension
+ bodyOff int // offset of message body
+}
diff --git a/libgo/go/golang_org/x/net/route/sys_darwin.go b/libgo/go/golang_org/x/net/route/sys_darwin.go
new file mode 100644
index 0000000000..fff3a0fd1d
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys_darwin.go
@@ -0,0 +1,80 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (typ RIBType) parseable() bool {
+ switch typ {
+ case sysNET_RT_STAT, sysNET_RT_TRASH:
+ return false
+ default:
+ return true
+ }
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15}
+ rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15}
+ ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15}
+ ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15}
+ ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15}
+ // Darwin kernels require 32-bit aligned access to routing facilities.
+ return 4, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFINFO2: ifm2.parseInterfaceMessage,
+ sysRTM_NEWMADDR2: ifmam2.parseInterfaceMulticastAddrMessage,
+ sysRTM_GET2: rtm2.parseRouteMessage,
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/sys_dragonfly.go b/libgo/go/golang_org/x/net/route/sys_dragonfly.go
new file mode 100644
index 0000000000..da848b3d07
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys_dragonfly.go
@@ -0,0 +1,71 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4}
+ ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4}
+ ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4}
+ return int(unsafe.Sizeof(p)), map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/sys_freebsd.go b/libgo/go/golang_org/x/net/route/sys_freebsd.go
new file mode 100644
index 0000000000..7b05c1a5a0
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys_freebsd.go
@@ -0,0 +1,150 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ if kernelAlign == 8 {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+ }
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ wordSize := int(unsafe.Sizeof(p))
+ align := int(unsafe.Sizeof(p))
+ // In the case of kern.supported_archs="amd64 i386", we need
+ // to know the underlying kernel's architecture because the
+ // alignment for routing facilities are set at the build time
+ // of the kernel.
+ conf, _ := syscall.Sysctl("kern.conftxt")
+ for i, j := 0, 0; j < len(conf); j++ {
+ if conf[j] != '\n' {
+ continue
+ }
+ s := conf[i:j]
+ i = j + 1
+ if len(s) > len("machine") && s[:len("machine")] == "machine" {
+ s = s[len("machine"):]
+ for k := 0; k < len(s); k++ {
+ if s[k] == ' ' || s[k] == '\t' {
+ s = s[1:]
+ }
+ break
+ }
+ if s == "amd64" {
+ align = 8
+ }
+ break
+ }
+ }
+ var rtm, ifm, ifam, ifmam, ifanm *wireFormat
+ if align != wordSize { // 386 emulation on amd64
+ rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
+ ifm = &wireFormat{extOff: 16}
+ ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
+ ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu}
+ ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu}
+ } else {
+ rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10}
+ ifm = &wireFormat{extOff: 16}
+ ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10}
+ ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10}
+ ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10}
+ }
+ rel, _ := syscall.SysctlUint32("kern.osreldate")
+ switch {
+ case rel < 800000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD7
+ }
+ case 800000 <= rel && rel < 900000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD8
+ }
+ case 900000 <= rel && rel < 1000000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD9
+ }
+ case 1000000 <= rel && rel < 1100000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD10
+ }
+ default:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD11
+ }
+ }
+ return align, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/sys_netbsd.go b/libgo/go/golang_org/x/net/route/sys_netbsd.go
new file mode 100644
index 0000000000..4d8076b518
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys_netbsd.go
@@ -0,0 +1,67 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7}
+ ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7}
+ // NetBSD 6 and above kernels require 64-bit aligned access to
+ // routing facilities.
+ return 8, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/sys_openbsd.go b/libgo/go/golang_org/x/net/route/sys_openbsd.go
new file mode 100644
index 0000000000..26d0438696
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/sys_openbsd.go
@@ -0,0 +1,72 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool {
+ switch typ {
+ case sysNET_RT_STATS, sysNET_RT_TABLE:
+ return false
+ default:
+ return true
+ }
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[60:64])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[24]),
+ MTU: int(nativeEndian.Uint32(m.raw[28:32])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ nooff := &wireFormat{extOff: -1, bodyOff: -1}
+ return int(unsafe.Sizeof(p)), map[int]parseFn{
+ sysRTM_ADD: nooff.parseRouteMessage,
+ sysRTM_DELETE: nooff.parseRouteMessage,
+ sysRTM_CHANGE: nooff.parseRouteMessage,
+ sysRTM_GET: nooff.parseRouteMessage,
+ sysRTM_LOSING: nooff.parseRouteMessage,
+ sysRTM_REDIRECT: nooff.parseRouteMessage,
+ sysRTM_MISS: nooff.parseRouteMessage,
+ sysRTM_LOCK: nooff.parseRouteMessage,
+ sysRTM_RESOLVE: nooff.parseRouteMessage,
+ sysRTM_NEWADDR: nooff.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: nooff.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: nooff.parseInterfaceMessage,
+ sysRTM_IFANNOUNCE: nooff.parseInterfaceAnnounceMessage,
+ }
+}
diff --git a/libgo/go/golang_org/x/net/route/syscall.go b/libgo/go/golang_org/x/net/route/syscall.go
new file mode 100644
index 0000000000..d136325a30
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/syscall.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// TODO: replace with runtime.KeepAlive when available
+//go:noescape
+func keepAlive(p unsafe.Pointer)
+
+var zero uintptr
+
+func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+ var p unsafe.Pointer
+ if len(mib) > 0 {
+ p = unsafe.Pointer(&mib[0])
+ } else {
+ p = unsafe.Pointer(&zero)
+ }
+ _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ keepAlive(p)
+ if errno != 0 {
+ return error(errno)
+ }
+ return nil
+}
diff --git a/libgo/go/golang_org/x/net/route/zsys_darwin.go b/libgo/go/golang_org/x/net/route/zsys_darwin.go
new file mode 100644
index 0000000000..265b81cd50
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_darwin.go
@@ -0,0 +1,93 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_darwin.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1e
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_STAT = 0x4
+ sysNET_RT_TRASH = 0x5
+ sysNET_RT_IFLIST2 = 0x6
+ sysNET_RT_DUMP2 = 0x7
+ sysNET_RT_MAXID = 0xa
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_MAXID = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFINFO2 = 0x12
+ sysRTM_NEWMADDR2 = 0x13
+ sysRTM_GET2 = 0x14
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrDarwin15 = 0x70
+ sizeofIfaMsghdrDarwin15 = 0x14
+ sizeofIfmaMsghdrDarwin15 = 0x10
+ sizeofIfMsghdr2Darwin15 = 0xa0
+ sizeofIfmaMsghdr2Darwin15 = 0x14
+ sizeofIfDataDarwin15 = 0x60
+ sizeofIfData64Darwin15 = 0x80
+
+ sizeofRtMsghdrDarwin15 = 0x5c
+ sizeofRtMsghdr2Darwin15 = 0x5c
+ sizeofRtMetricsDarwin15 = 0x38
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_dragonfly.go b/libgo/go/golang_org/x/net/route/zsys_dragonfly.go
new file mode 100644
index 0000000000..dd36dece0f
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_dragonfly.go
@@ -0,0 +1,92 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_dragonfly.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_MAXID = 0x4
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+ sysCTL_LWKT = 0xa
+ sysCTL_MAXID = 0xb
+)
+
+const (
+ sysRTM_VERSION = 0x6
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_MPLS1 = 0x100
+ sysRTA_MPLS2 = 0x200
+ sysRTA_MPLS3 = 0x400
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MPLS1 = 0x8
+ sysRTAX_MPLS2 = 0x9
+ sysRTAX_MPLS3 = 0xa
+ sysRTAX_MAX = 0xb
+)
+
+const (
+ sizeofIfMsghdrDragonFlyBSD4 = 0xb0
+ sizeofIfaMsghdrDragonFlyBSD4 = 0x14
+ sizeofIfmaMsghdrDragonFlyBSD4 = 0x10
+ sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18
+
+ sizeofRtMsghdrDragonFlyBSD4 = 0x98
+ sizeofRtMetricsDragonFlyBSD4 = 0x70
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_freebsd_386.go b/libgo/go/golang_org/x/net/route/zsys_freebsd_386.go
new file mode 100644
index 0000000000..9bac2e3900
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_freebsd_386.go
@@ -0,0 +1,120 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0x68
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0x6c
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x5c
+ sizeofRtMetricsFreeBSD10 = 0x38
+
+ sizeofIfMsghdrFreeBSD7 = 0x60
+ sizeofIfMsghdrFreeBSD8 = 0x60
+ sizeofIfMsghdrFreeBSD9 = 0x60
+ sizeofIfMsghdrFreeBSD10 = 0x64
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x50
+ sizeofIfDataFreeBSD8 = 0x50
+ sizeofIfDataFreeBSD9 = 0x50
+ sizeofIfDataFreeBSD10 = 0x54
+ sizeofIfDataFreeBSD11 = 0x98
+
+ // MODIFIED BY HAND FOR 386 EMULATION ON AMD64
+ // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x98
+ sizeofRtMetricsFreeBSD10Emu = 0x70
+
+ sizeofIfMsghdrFreeBSD7Emu = 0xa8
+ sizeofIfMsghdrFreeBSD8Emu = 0xa8
+ sizeofIfMsghdrFreeBSD9Emu = 0xa8
+ sizeofIfMsghdrFreeBSD10Emu = 0xa8
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x98
+ sizeofIfDataFreeBSD8Emu = 0x98
+ sizeofIfDataFreeBSD9Emu = 0x98
+ sizeofIfDataFreeBSD10Emu = 0x98
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_freebsd_amd64.go b/libgo/go/golang_org/x/net/route/zsys_freebsd_amd64.go
new file mode 100644
index 0000000000..b1920d7ac1
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_freebsd_amd64.go
@@ -0,0 +1,117 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0xb0
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0xb0
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x98
+ sizeofRtMetricsFreeBSD10 = 0x70
+
+ sizeofIfMsghdrFreeBSD7 = 0xa8
+ sizeofIfMsghdrFreeBSD8 = 0xa8
+ sizeofIfMsghdrFreeBSD9 = 0xa8
+ sizeofIfMsghdrFreeBSD10 = 0xa8
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x98
+ sizeofIfDataFreeBSD8 = 0x98
+ sizeofIfDataFreeBSD9 = 0x98
+ sizeofIfDataFreeBSD10 = 0x98
+ sizeofIfDataFreeBSD11 = 0x98
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x98
+ sizeofRtMetricsFreeBSD10Emu = 0x70
+
+ sizeofIfMsghdrFreeBSD7Emu = 0xa8
+ sizeofIfMsghdrFreeBSD8Emu = 0xa8
+ sizeofIfMsghdrFreeBSD9Emu = 0xa8
+ sizeofIfMsghdrFreeBSD10Emu = 0xa8
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x98
+ sizeofIfDataFreeBSD8Emu = 0x98
+ sizeofIfDataFreeBSD9Emu = 0x98
+ sizeofIfDataFreeBSD10Emu = 0x98
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_freebsd_arm.go b/libgo/go/golang_org/x/net/route/zsys_freebsd_arm.go
new file mode 100644
index 0000000000..a034d6fcbf
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_freebsd_arm.go
@@ -0,0 +1,117 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0x68
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0x6c
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x5c
+ sizeofRtMetricsFreeBSD10 = 0x38
+
+ sizeofIfMsghdrFreeBSD7 = 0x70
+ sizeofIfMsghdrFreeBSD8 = 0x70
+ sizeofIfMsghdrFreeBSD9 = 0x70
+ sizeofIfMsghdrFreeBSD10 = 0x70
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x60
+ sizeofIfDataFreeBSD8 = 0x60
+ sizeofIfDataFreeBSD9 = 0x60
+ sizeofIfDataFreeBSD10 = 0x60
+ sizeofIfDataFreeBSD11 = 0x98
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0x68
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0x6c
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x5c
+ sizeofRtMetricsFreeBSD10Emu = 0x38
+
+ sizeofIfMsghdrFreeBSD7Emu = 0x70
+ sizeofIfMsghdrFreeBSD8Emu = 0x70
+ sizeofIfMsghdrFreeBSD9Emu = 0x70
+ sizeofIfMsghdrFreeBSD10Emu = 0x70
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x60
+ sizeofIfDataFreeBSD8Emu = 0x60
+ sizeofIfDataFreeBSD9Emu = 0x60
+ sizeofIfDataFreeBSD10Emu = 0x60
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_netbsd.go b/libgo/go/golang_org/x/net/route/zsys_netbsd.go
new file mode 100644
index 0000000000..aa4aad1613
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_netbsd.go
@@ -0,0 +1,91 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_netbsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x22
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x18
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x5
+ sysNET_RT_MAXID = 0x6
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_DDB = 0x9
+ sysCTL_PROC = 0xa
+ sysCTL_VENDOR = 0xb
+ sysCTL_EMUL = 0xc
+ sysCTL_SECURITY = 0xd
+ sysCTL_MAXID = 0xe
+)
+
+const (
+ sysRTM_VERSION = 0x4
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFANNOUNCE = 0x10
+ sysRTM_IEEE80211 = 0x11
+ sysRTM_SETGATE = 0x12
+ sysRTM_LLINFO_UPD = 0x13
+ sysRTM_IFINFO = 0x14
+ sysRTM_CHGADDR = 0x15
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_TAG = 0x100
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_TAG = 0x8
+ sysRTAX_MAX = 0x9
+)
+
+const (
+ sizeofIfMsghdrNetBSD7 = 0x98
+ sizeofIfaMsghdrNetBSD7 = 0x18
+ sizeofIfAnnouncemsghdrNetBSD7 = 0x18
+
+ sizeofRtMsghdrNetBSD7 = 0x78
+ sizeofRtMetricsNetBSD7 = 0x50
+)
diff --git a/libgo/go/golang_org/x/net/route/zsys_openbsd.go b/libgo/go/golang_org/x/net/route/zsys_openbsd.go
new file mode 100644
index 0000000000..4fadc4e8fa
--- /dev/null
+++ b/libgo/go/golang_org/x/net/route/zsys_openbsd.go
@@ -0,0 +1,80 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_openbsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x18
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_STATS = 0x4
+ sysNET_RT_TABLE = 0x5
+ sysNET_RT_IFNAMES = 0x6
+ sysNET_RT_MAXID = 0x7
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_FS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_DDB = 0x9
+ sysCTL_VFS = 0xa
+ sysCTL_MAXID = 0xb
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_IFANNOUNCE = 0xf
+ sysRTM_DESYNC = 0x10
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_SRC = 0x100
+ sysRTA_SRCMASK = 0x200
+ sysRTA_LABEL = 0x400
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_SRC = 0x8
+ sysRTAX_SRCMASK = 0x9
+ sysRTAX_LABEL = 0xa
+ sysRTAX_MAX = 0xb
+)
diff --git a/libgo/go/golang_org/x/text/transform/transform.go b/libgo/go/golang_org/x/text/transform/transform.go
new file mode 100644
index 0000000000..fe47b9b35f
--- /dev/null
+++ b/libgo/go/golang_org/x/text/transform/transform.go
@@ -0,0 +1,705 @@
+// 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.
+
+// Package transform provides reader and writer wrappers that transform the
+// bytes passing through as well as various transformations. Example
+// transformations provided by other packages include normalization and
+// conversion between character sets.
+package transform // import "golang.org/x/text/transform"
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+var (
+ // ErrShortDst means that the destination buffer was too short to
+ // receive all of the transformed bytes.
+ ErrShortDst = errors.New("transform: short destination buffer")
+
+ // ErrShortSrc means that the source buffer has insufficient data to
+ // complete the transformation.
+ ErrShortSrc = errors.New("transform: short source buffer")
+
+ // ErrEndOfSpan means that the input and output (the transformed input)
+ // are not identical.
+ ErrEndOfSpan = errors.New("transform: input and output are not identical")
+
+ // errInconsistentByteCount means that Transform returned success (nil
+ // error) but also returned nSrc inconsistent with the src argument.
+ errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
+
+ // errShortInternal means that an internal buffer is not large enough
+ // to make progress and the Transform operation must be aborted.
+ errShortInternal = errors.New("transform: short internal buffer")
+)
+
+// Transformer transforms bytes.
+type Transformer interface {
+ // Transform writes to dst the transformed bytes read from src, and
+ // returns the number of dst bytes written and src bytes read. The
+ // atEOF argument tells whether src represents the last bytes of the
+ // input.
+ //
+ // Callers should always process the nDst bytes produced and account
+ // for the nSrc bytes consumed before considering the error err.
+ //
+ // A nil error means that all of the transformed bytes (whether freshly
+ // transformed from src or left over from previous Transform calls)
+ // were written to dst. A nil error can be returned regardless of
+ // whether atEOF is true. If err is nil then nSrc must equal len(src);
+ // the converse is not necessarily true.
+ //
+ // ErrShortDst means that dst was too short to receive all of the
+ // transformed bytes. ErrShortSrc means that src had insufficient data
+ // to complete the transformation. If both conditions apply, then
+ // either error may be returned. Other than the error conditions listed
+ // here, implementations are free to report other errors that arise.
+ Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
+
+ // Reset resets the state and allows a Transformer to be reused.
+ Reset()
+}
+
+// SpanningTransformer extends the Transformer interface with a Span method
+// that determines how much of the input already conforms to the Transformer.
+type SpanningTransformer interface {
+ Transformer
+
+ // Span returns a position in src such that transforming src[:n] results in
+ // identical output src[:n] for these bytes. It does not necessarily return
+ // the largest such n. The atEOF argument tells whether src represents the
+ // last bytes of the input.
+ //
+ // Callers should always account for the n bytes consumed before
+ // considering the error err.
+ //
+ // A nil error means that all input bytes are known to be identical to the
+ // output produced by the Transformer. A nil error can be be returned
+ // regardless of whether atEOF is true. If err is nil, then then n must
+ // equal len(src); the converse is not necessarily true.
+ //
+ // ErrEndOfSpan means that the Transformer output may differ from the
+ // input after n bytes. Note that n may be len(src), meaning that the output
+ // would contain additional bytes after otherwise identical output.
+ // ErrShortSrc means that src had insufficient data to determine whether the
+ // remaining bytes would change. Other than the error conditions listed
+ // here, implementations are free to report other errors that arise.
+ //
+ // Calling Span can modify the Transformer state as a side effect. In
+ // effect, it does the transformation just as calling Transform would, only
+ // without copying to a destination buffer and only up to a point it can
+ // determine the input and output bytes are the same. This is obviously more
+ // limited than calling Transform, but can be more efficient in terms of
+ // copying and allocating buffers. Calls to Span and Transform may be
+ // interleaved.
+ Span(src []byte, atEOF bool) (n int, err error)
+}
+
+// NopResetter can be embedded by implementations of Transformer to add a nop
+// Reset method.
+type NopResetter struct{}
+
+// Reset implements the Reset method of the Transformer interface.
+func (NopResetter) Reset() {}
+
+// Reader wraps another io.Reader by transforming the bytes read.
+type Reader struct {
+ r io.Reader
+ t Transformer
+ err error
+
+ // dst[dst0:dst1] contains bytes that have been transformed by t but
+ // not yet copied out via Read.
+ dst []byte
+ dst0, dst1 int
+
+ // src[src0:src1] contains bytes that have been read from r but not
+ // yet transformed through t.
+ src []byte
+ src0, src1 int
+
+ // transformComplete is whether the transformation is complete,
+ // regardless of whether or not it was successful.
+ transformComplete bool
+}
+
+const defaultBufSize = 4096
+
+// NewReader returns a new Reader that wraps r by transforming the bytes read
+// via t. It calls Reset on t.
+func NewReader(r io.Reader, t Transformer) *Reader {
+ t.Reset()
+ return &Reader{
+ r: r,
+ t: t,
+ dst: make([]byte, defaultBufSize),
+ src: make([]byte, defaultBufSize),
+ }
+}
+
+// Read implements the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ n, err := 0, error(nil)
+ for {
+ // Copy out any transformed bytes and return the final error if we are done.
+ if r.dst0 != r.dst1 {
+ n = copy(p, r.dst[r.dst0:r.dst1])
+ r.dst0 += n
+ if r.dst0 == r.dst1 && r.transformComplete {
+ return n, r.err
+ }
+ return n, nil
+ } else if r.transformComplete {
+ return 0, r.err
+ }
+
+ // Try to transform some source bytes, or to flush the transformer if we
+ // are out of source bytes. We do this even if r.r.Read returned an error.
+ // As the io.Reader documentation says, "process the n > 0 bytes returned
+ // before considering the error".
+ if r.src0 != r.src1 || r.err != nil {
+ r.dst0 = 0
+ r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
+ r.src0 += n
+
+ switch {
+ case err == nil:
+ if r.src0 != r.src1 {
+ r.err = errInconsistentByteCount
+ }
+ // The Transform call was successful; we are complete if we
+ // cannot read more bytes into src.
+ r.transformComplete = r.err != nil
+ continue
+ case err == ErrShortDst && (r.dst1 != 0 || n != 0):
+ // Make room in dst by copying out, and try again.
+ continue
+ case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
+ // Read more bytes into src via the code below, and try again.
+ default:
+ r.transformComplete = true
+ // The reader error (r.err) takes precedence over the
+ // transformer error (err) unless r.err is nil or io.EOF.
+ if r.err == nil || r.err == io.EOF {
+ r.err = err
+ }
+ continue
+ }
+ }
+
+ // Move any untransformed source bytes to the start of the buffer
+ // and read more bytes.
+ if r.src0 != 0 {
+ r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
+ }
+ n, r.err = r.r.Read(r.src[r.src1:])
+ r.src1 += n
+ }
+}
+
+// TODO: implement ReadByte (and ReadRune??).
+
+// Writer wraps another io.Writer by transforming the bytes read.
+// The user needs to call Close to flush unwritten bytes that may
+// be buffered.
+type Writer struct {
+ w io.Writer
+ t Transformer
+ dst []byte
+
+ // src[:n] contains bytes that have not yet passed through t.
+ src []byte
+ n int
+}
+
+// NewWriter returns a new Writer that wraps w by transforming the bytes written
+// via t. It calls Reset on t.
+func NewWriter(w io.Writer, t Transformer) *Writer {
+ t.Reset()
+ return &Writer{
+ w: w,
+ t: t,
+ dst: make([]byte, defaultBufSize),
+ src: make([]byte, defaultBufSize),
+ }
+}
+
+// Write implements the io.Writer interface. If there are not enough
+// bytes available to complete a Transform, the bytes will be buffered
+// for the next write. Call Close to convert the remaining bytes.
+func (w *Writer) Write(data []byte) (n int, err error) {
+ src := data
+ if w.n > 0 {
+ // Append bytes from data to the last remainder.
+ // TODO: limit the amount copied on first try.
+ n = copy(w.src[w.n:], data)
+ w.n += n
+ src = w.src[:w.n]
+ }
+ for {
+ nDst, nSrc, err := w.t.Transform(w.dst, src, false)
+ if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+ return n, werr
+ }
+ src = src[nSrc:]
+ if w.n == 0 {
+ n += nSrc
+ } else if len(src) <= n {
+ // Enough bytes from w.src have been consumed. We make src point
+ // to data instead to reduce the copying.
+ w.n = 0
+ n -= len(src)
+ src = data[n:]
+ if n < len(data) && (err == nil || err == ErrShortSrc) {
+ continue
+ }
+ }
+ switch err {
+ case ErrShortDst:
+ // This error is okay as long as we are making progress.
+ if nDst > 0 || nSrc > 0 {
+ continue
+ }
+ case ErrShortSrc:
+ if len(src) < len(w.src) {
+ m := copy(w.src, src)
+ // If w.n > 0, bytes from data were already copied to w.src and n
+ // was already set to the number of bytes consumed.
+ if w.n == 0 {
+ n += m
+ }
+ w.n = m
+ err = nil
+ } else if nDst > 0 || nSrc > 0 {
+ // Not enough buffer to store the remainder. Keep processing as
+ // long as there is progress. Without this case, transforms that
+ // require a lookahead larger than the buffer may result in an
+ // error. This is not something one may expect to be common in
+ // practice, but it may occur when buffers are set to small
+ // sizes during testing.
+ continue
+ }
+ case nil:
+ if w.n > 0 {
+ err = errInconsistentByteCount
+ }
+ }
+ return n, err
+ }
+}
+
+// Close implements the io.Closer interface.
+func (w *Writer) Close() error {
+ src := w.src[:w.n]
+ for {
+ nDst, nSrc, err := w.t.Transform(w.dst, src, true)
+ if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+ return werr
+ }
+ if err != ErrShortDst {
+ return err
+ }
+ src = src[nSrc:]
+ }
+}
+
+type nop struct{ NopResetter }
+
+func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ n := copy(dst, src)
+ if n < len(src) {
+ err = ErrShortDst
+ }
+ return n, n, err
+}
+
+func (nop) Span(src []byte, atEOF bool) (n int, err error) {
+ return len(src), nil
+}
+
+type discard struct{ NopResetter }
+
+func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ return 0, len(src), nil
+}
+
+var (
+ // Discard is a Transformer for which all Transform calls succeed
+ // by consuming all bytes and writing nothing.
+ Discard Transformer = discard{}
+
+ // Nop is a SpanningTransformer that copies src to dst.
+ Nop SpanningTransformer = nop{}
+)
+
+// chain is a sequence of links. A chain with N Transformers has N+1 links and
+// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
+// buffers given to chain.Transform and the middle N-1 buffers are intermediate
+// buffers owned by the chain. The i'th link transforms bytes from the i'th
+// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
+// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
+type chain struct {
+ link []link
+ err error
+ // errStart is the index at which the error occurred plus 1. Processing
+ // errStart at this level at the next call to Transform. As long as
+ // errStart > 0, chain will not consume any more source bytes.
+ errStart int
+}
+
+func (c *chain) fatalError(errIndex int, err error) {
+ if i := errIndex + 1; i > c.errStart {
+ c.errStart = i
+ c.err = err
+ }
+}
+
+type link struct {
+ t Transformer
+ // b[p:n] holds the bytes to be transformed by t.
+ b []byte
+ p int
+ n int
+}
+
+func (l *link) src() []byte {
+ return l.b[l.p:l.n]
+}
+
+func (l *link) dst() []byte {
+ return l.b[l.n:]
+}
+
+// Chain returns a Transformer that applies t in sequence.
+func Chain(t ...Transformer) Transformer {
+ if len(t) == 0 {
+ return nop{}
+ }
+ c := &chain{link: make([]link, len(t)+1)}
+ for i, tt := range t {
+ c.link[i].t = tt
+ }
+ // Allocate intermediate buffers.
+ b := make([][defaultBufSize]byte, len(t)-1)
+ for i := range b {
+ c.link[i+1].b = b[i][:]
+ }
+ return c
+}
+
+// Reset resets the state of Chain. It calls Reset on all the Transformers.
+func (c *chain) Reset() {
+ for i, l := range c.link {
+ if l.t != nil {
+ l.t.Reset()
+ }
+ c.link[i].p, c.link[i].n = 0, 0
+ }
+}
+
+// TODO: make chain use Span (is going to be fun to implement!)
+
+// Transform applies the transformers of c in sequence.
+func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ // Set up src and dst in the chain.
+ srcL := &c.link[0]
+ dstL := &c.link[len(c.link)-1]
+ srcL.b, srcL.p, srcL.n = src, 0, len(src)
+ dstL.b, dstL.n = dst, 0
+ var lastFull, needProgress bool // for detecting progress
+
+ // i is the index of the next Transformer to apply, for i in [low, high].
+ // low is the lowest index for which c.link[low] may still produce bytes.
+ // high is the highest index for which c.link[high] has a Transformer.
+ // The error returned by Transform determines whether to increase or
+ // decrease i. We try to completely fill a buffer before converting it.
+ for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
+ in, out := &c.link[i], &c.link[i+1]
+ nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
+ out.n += nDst
+ in.p += nSrc
+ if i > 0 && in.p == in.n {
+ in.p, in.n = 0, 0
+ }
+ needProgress, lastFull = lastFull, false
+ switch err0 {
+ case ErrShortDst:
+ // Process the destination buffer next. Return if we are already
+ // at the high index.
+ if i == high {
+ return dstL.n, srcL.p, ErrShortDst
+ }
+ if out.n != 0 {
+ i++
+ // If the Transformer at the next index is not able to process any
+ // source bytes there is nothing that can be done to make progress
+ // and the bytes will remain unprocessed. lastFull is used to
+ // detect this and break out of the loop with a fatal error.
+ lastFull = true
+ continue
+ }
+ // The destination buffer was too small, but is completely empty.
+ // Return a fatal error as this transformation can never complete.
+ c.fatalError(i, errShortInternal)
+ case ErrShortSrc:
+ if i == 0 {
+ // Save ErrShortSrc in err. All other errors take precedence.
+ err = ErrShortSrc
+ break
+ }
+ // Source bytes were depleted before filling up the destination buffer.
+ // Verify we made some progress, move the remaining bytes to the errStart
+ // and try to get more source bytes.
+ if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
+ // There were not enough source bytes to proceed while the source
+ // buffer cannot hold any more bytes. Return a fatal error as this
+ // transformation can never complete.
+ c.fatalError(i, errShortInternal)
+ break
+ }
+ // in.b is an internal buffer and we can make progress.
+ in.p, in.n = 0, copy(in.b, in.src())
+ fallthrough
+ case nil:
+ // if i == low, we have depleted the bytes at index i or any lower levels.
+ // In that case we increase low and i. In all other cases we decrease i to
+ // fetch more bytes before proceeding to the next index.
+ if i > low {
+ i--
+ continue
+ }
+ default:
+ c.fatalError(i, err0)
+ }
+ // Exhausted level low or fatal error: increase low and continue
+ // to process the bytes accepted so far.
+ i++
+ low = i
+ }
+
+ // If c.errStart > 0, this means we found a fatal error. We will clear
+ // all upstream buffers. At this point, no more progress can be made
+ // downstream, as Transform would have bailed while handling ErrShortDst.
+ if c.errStart > 0 {
+ for i := 1; i < c.errStart; i++ {
+ c.link[i].p, c.link[i].n = 0, 0
+ }
+ err, c.errStart, c.err = c.err, 0, nil
+ }
+ return dstL.n, srcL.p, err
+}
+
+// Deprecated: use runes.Remove instead.
+func RemoveFunc(f func(r rune) bool) Transformer {
+ return removeF(f)
+}
+
+type removeF func(r rune) bool
+
+func (removeF) Reset() {}
+
+// Transform implements the Transformer interface.
+func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
+
+ if r = rune(src[0]); r < utf8.RuneSelf {
+ sz = 1
+ } else {
+ r, sz = utf8.DecodeRune(src)
+
+ if sz == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src) {
+ err = ErrShortSrc
+ break
+ }
+ // We replace illegal bytes with RuneError. Not doing so might
+ // otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
+ // The resulting byte sequence may subsequently contain runes
+ // for which t(r) is true that were passed unnoticed.
+ if !t(r) {
+ if nDst+3 > len(dst) {
+ err = ErrShortDst
+ break
+ }
+ nDst += copy(dst[nDst:], "\uFFFD")
+ }
+ nSrc++
+ continue
+ }
+ }
+
+ if !t(r) {
+ if nDst+sz > len(dst) {
+ err = ErrShortDst
+ break
+ }
+ nDst += copy(dst[nDst:], src[:sz])
+ }
+ nSrc += sz
+ }
+ return
+}
+
+// grow returns a new []byte that is longer than b, and copies the first n bytes
+// of b to the start of the new slice.
+func grow(b []byte, n int) []byte {
+ m := len(b)
+ if m <= 32 {
+ m = 64
+ } else if m <= 256 {
+ m *= 2
+ } else {
+ m += m >> 1
+ }
+ buf := make([]byte, m)
+ copy(buf, b[:n])
+ return buf
+}
+
+const initialBufSize = 128
+
+// String returns a string with the result of converting s[:n] using t, where
+// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
+func String(t Transformer, s string) (result string, n int, err error) {
+ t.Reset()
+ if s == "" {
+ // Fast path for the common case for empty input. Results in about a
+ // 86% reduction of running time for BenchmarkStringLowerEmpty.
+ if _, _, err := t.Transform(nil, nil, true); err == nil {
+ return "", 0, nil
+ }
+ }
+
+ // Allocate only once. Note that both dst and src escape when passed to
+ // Transform.
+ buf := [2 * initialBufSize]byte{}
+ dst := buf[:initialBufSize:initialBufSize]
+ src := buf[initialBufSize : 2*initialBufSize]
+
+ // The input string s is transformed in multiple chunks (starting with a
+ // chunk size of initialBufSize). nDst and nSrc are per-chunk (or
+ // per-Transform-call) indexes, pDst and pSrc are overall indexes.
+ nDst, nSrc := 0, 0
+ pDst, pSrc := 0, 0
+
+ // pPrefix is the length of a common prefix: the first pPrefix bytes of the
+ // result will equal the first pPrefix bytes of s. It is not guaranteed to
+ // be the largest such value, but if pPrefix, len(result) and len(s) are
+ // all equal after the final transform (i.e. calling Transform with atEOF
+ // being true returned nil error) then we don't need to allocate a new
+ // result string.
+ pPrefix := 0
+ for {
+ // Invariant: pDst == pPrefix && pSrc == pPrefix.
+
+ n := copy(src, s[pSrc:])
+ nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
+ pDst += nDst
+ pSrc += nSrc
+
+ // TODO: let transformers implement an optional Spanner interface, akin
+ // to norm's QuickSpan. This would even allow us to avoid any allocation.
+ if !bytes.Equal(dst[:nDst], src[:nSrc]) {
+ break
+ }
+ pPrefix = pSrc
+ if err == ErrShortDst {
+ // A buffer can only be short if a transformer modifies its input.
+ break
+ } else if err == ErrShortSrc {
+ if nSrc == 0 {
+ // No progress was made.
+ break
+ }
+ // Equal so far and !atEOF, so continue checking.
+ } else if err != nil || pPrefix == len(s) {
+ return string(s[:pPrefix]), pPrefix, err
+ }
+ }
+ // Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
+
+ // We have transformed the first pSrc bytes of the input s to become pDst
+ // transformed bytes. Those transformed bytes are discontiguous: the first
+ // pPrefix of them equal s[:pPrefix] and the last nDst of them equal
+ // dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
+ // that they become one contiguous slice: dst[:pDst].
+ if pPrefix != 0 {
+ newDst := dst
+ if pDst > len(newDst) {
+ newDst = make([]byte, len(s)+nDst-nSrc)
+ }
+ copy(newDst[pPrefix:pDst], dst[:nDst])
+ copy(newDst[:pPrefix], s[:pPrefix])
+ dst = newDst
+ }
+
+ // Prevent duplicate Transform calls with atEOF being true at the end of
+ // the input. Also return if we have an unrecoverable error.
+ if (err == nil && pSrc == len(s)) ||
+ (err != nil && err != ErrShortDst && err != ErrShortSrc) {
+ return string(dst[:pDst]), pSrc, err
+ }
+
+ // Transform the remaining input, growing dst and src buffers as necessary.
+ for {
+ n := copy(src, s[pSrc:])
+ nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
+ pDst += nDst
+ pSrc += nSrc
+
+ // If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
+ // make progress. This may avoid excessive allocations.
+ if err == ErrShortDst {
+ if nDst == 0 {
+ dst = grow(dst, pDst)
+ }
+ } else if err == ErrShortSrc {
+ if nSrc == 0 {
+ src = grow(src, 0)
+ }
+ } else if err != nil || pSrc == len(s) {
+ return string(dst[:pDst]), pSrc, err
+ }
+ }
+}
+
+// Bytes returns a new byte slice with the result of converting b[:n] using t,
+// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
+func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
+ return doAppend(t, 0, make([]byte, len(b)), b)
+}
+
+// Append appends the result of converting src[:n] using t to dst, where
+// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
+func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
+ if len(dst) == cap(dst) {
+ n := len(src) + len(dst) // It is okay for this to be 0.
+ b := make([]byte, n)
+ dst = b[:copy(b, dst)]
+ }
+ return doAppend(t, len(dst), dst[:cap(dst)], src)
+}
+
+func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
+ t.Reset()
+ pSrc := 0
+ for {
+ nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
+ pDst += nDst
+ pSrc += nSrc
+ if err != ErrShortDst {
+ return dst[:pDst], pSrc, err
+ }
+
+ // Grow the destination buffer, but do not grow as long as we can make
+ // progress. This may avoid excessive allocations.
+ if nDst == 0 {
+ dst = grow(dst, pDst)
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/composition.go b/libgo/go/golang_org/x/text/unicode/norm/composition.go
new file mode 100644
index 0000000000..d17b278adc
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/composition.go
@@ -0,0 +1,514 @@
+// 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 norm
+
+import "unicode/utf8"
+
+const (
+ maxNonStarters = 30
+ // The maximum number of characters needed for a buffer is
+ // maxNonStarters + 1 for the starter + 1 for the GCJ
+ maxBufferSize = maxNonStarters + 2
+ maxNFCExpansion = 3 // NFC(0x1D160)
+ maxNFKCExpansion = 18 // NFKC(0xFDFA)
+
+ maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128
+)
+
+// ssState is used for reporting the segment state after inserting a rune.
+// It is returned by streamSafe.next.
+type ssState int
+
+const (
+ // Indicates a rune was successfully added to the segment.
+ ssSuccess ssState = iota
+ // Indicates a rune starts a new segment and should not be added.
+ ssStarter
+ // Indicates a rune caused a segment overflow and a CGJ should be inserted.
+ ssOverflow
+)
+
+// streamSafe implements the policy of when a CGJ should be inserted.
+type streamSafe uint8
+
+// mkStreamSafe is a shorthand for declaring a streamSafe var and calling
+// first on it.
+func mkStreamSafe(p Properties) streamSafe {
+ return streamSafe(p.nTrailingNonStarters())
+}
+
+// first inserts the first rune of a segment.
+func (ss *streamSafe) first(p Properties) {
+ if *ss != 0 {
+ panic("!= 0")
+ }
+ *ss = streamSafe(p.nTrailingNonStarters())
+}
+
+// insert returns a ssState value to indicate whether a rune represented by p
+// can be inserted.
+func (ss *streamSafe) next(p Properties) ssState {
+ if *ss > maxNonStarters {
+ panic("streamSafe was not reset")
+ }
+ n := p.nLeadingNonStarters()
+ if *ss += streamSafe(n); *ss > maxNonStarters {
+ *ss = 0
+ return ssOverflow
+ }
+ // The Stream-Safe Text Processing prescribes that the counting can stop
+ // as soon as a starter is encountered. However, there are some starters,
+ // like Jamo V and T, that can combine with other runes, leaving their
+ // successive non-starters appended to the previous, possibly causing an
+ // overflow. We will therefore consider any rune with a non-zero nLead to
+ // be a non-starter. Note that it always hold that if nLead > 0 then
+ // nLead == nTrail.
+ if n == 0 {
+ *ss = 0
+ return ssStarter
+ }
+ return ssSuccess
+}
+
+// backwards is used for checking for overflow and segment starts
+// when traversing a string backwards. Users do not need to call first
+// for the first rune. The state of the streamSafe retains the count of
+// the non-starters loaded.
+func (ss *streamSafe) backwards(p Properties) ssState {
+ if *ss > maxNonStarters {
+ panic("streamSafe was not reset")
+ }
+ c := *ss + streamSafe(p.nTrailingNonStarters())
+ if c > maxNonStarters {
+ return ssOverflow
+ }
+ *ss = c
+ if p.nLeadingNonStarters() == 0 {
+ return ssStarter
+ }
+ return ssSuccess
+}
+
+func (ss streamSafe) isMax() bool {
+ return ss == maxNonStarters
+}
+
+// GraphemeJoiner is inserted after maxNonStarters non-starter runes.
+const GraphemeJoiner = "\u034F"
+
+// reorderBuffer is used to normalize a single segment. Characters inserted with
+// insert are decomposed and reordered based on CCC. The compose method can
+// be used to recombine characters. Note that the byte buffer does not hold
+// the UTF-8 characters in order. Only the rune array is maintained in sorted
+// order. flush writes the resulting segment to a byte array.
+type reorderBuffer struct {
+ rune [maxBufferSize]Properties // Per character info.
+ byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
+ nbyte uint8 // Number or bytes.
+ ss streamSafe // For limiting length of non-starter sequence.
+ nrune int // Number of runeInfos.
+ f formInfo
+
+ src input
+ nsrc int
+ tmpBytes input
+
+ out []byte
+ flushF func(*reorderBuffer) bool
+}
+
+func (rb *reorderBuffer) init(f Form, src []byte) {
+ rb.f = *formTable[f]
+ rb.src.setBytes(src)
+ rb.nsrc = len(src)
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) initString(f Form, src string) {
+ rb.f = *formTable[f]
+ rb.src.setString(src)
+ rb.nsrc = len(src)
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) {
+ rb.out = out
+ rb.flushF = f
+}
+
+// reset discards all characters from the buffer.
+func (rb *reorderBuffer) reset() {
+ rb.nrune = 0
+ rb.nbyte = 0
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) doFlush() bool {
+ if rb.f.composing {
+ rb.compose()
+ }
+ res := rb.flushF(rb)
+ rb.reset()
+ return res
+}
+
+// appendFlush appends the normalized segment to rb.out.
+func appendFlush(rb *reorderBuffer) bool {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ rb.out = append(rb.out, rb.byte[start:end]...)
+ }
+ return true
+}
+
+// flush appends the normalized segment to out and resets rb.
+func (rb *reorderBuffer) flush(out []byte) []byte {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ out = append(out, rb.byte[start:end]...)
+ }
+ rb.reset()
+ return out
+}
+
+// flushCopy copies the normalized segment to buf and resets rb.
+// It returns the number of bytes written to buf.
+func (rb *reorderBuffer) flushCopy(buf []byte) int {
+ p := 0
+ for i := 0; i < rb.nrune; i++ {
+ runep := rb.rune[i]
+ p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size])
+ }
+ rb.reset()
+ return p
+}
+
+// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
+// It returns false if the buffer is not large enough to hold the rune.
+// It is used internally by insert and insertString only.
+func (rb *reorderBuffer) insertOrdered(info Properties) {
+ n := rb.nrune
+ b := rb.rune[:]
+ cc := info.ccc
+ if cc > 0 {
+ // Find insertion position + move elements to make room.
+ for ; n > 0; n-- {
+ if b[n-1].ccc <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ rb.nrune += 1
+ pos := uint8(rb.nbyte)
+ rb.nbyte += utf8.UTFMax
+ info.pos = pos
+ b[n] = info
+}
+
+// insertErr is an error code returned by insert. Using this type instead
+// of error improves performance up to 20% for many of the benchmarks.
+type insertErr int
+
+const (
+ iSuccess insertErr = -iota
+ iShortDst
+ iShortSrc
+)
+
+// insertFlush inserts the given rune in the buffer ordered by CCC.
+// If a decomposition with multiple segments are encountered, they leading
+// ones are flushed.
+// It returns a non-zero error code if the rune was not inserted.
+func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr {
+ if rune := src.hangul(i); rune != 0 {
+ rb.decomposeHangul(rune)
+ return iSuccess
+ }
+ if info.hasDecomposition() {
+ return rb.insertDecomposed(info.Decomposition())
+ }
+ rb.insertSingle(src, i, info)
+ return iSuccess
+}
+
+// insertUnsafe inserts the given rune in the buffer ordered by CCC.
+// It is assumed there is sufficient space to hold the runes. It is the
+// responsibility of the caller to ensure this. This can be done by checking
+// the state returned by the streamSafe type.
+func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) {
+ if rune := src.hangul(i); rune != 0 {
+ rb.decomposeHangul(rune)
+ }
+ if info.hasDecomposition() {
+ // TODO: inline.
+ rb.insertDecomposed(info.Decomposition())
+ } else {
+ rb.insertSingle(src, i, info)
+ }
+}
+
+// insertDecomposed inserts an entry in to the reorderBuffer for each rune
+// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes.
+// It flushes the buffer on each new segment start.
+func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr {
+ rb.tmpBytes.setBytes(dcomp)
+ for i := 0; i < len(dcomp); {
+ info := rb.f.info(rb.tmpBytes, i)
+ if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() {
+ return iShortDst
+ }
+ i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)])
+ rb.insertOrdered(info)
+ }
+ return iSuccess
+}
+
+// insertSingle inserts an entry in the reorderBuffer for the rune at
+// position i. info is the runeInfo for the rune at position i.
+func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) {
+ src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size))
+ rb.insertOrdered(info)
+}
+
+// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb.
+func (rb *reorderBuffer) insertCGJ() {
+ rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))})
+}
+
+// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
+func (rb *reorderBuffer) appendRune(r rune) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
+ rb.nbyte += utf8.UTFMax
+ rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)}
+ rb.nrune++
+}
+
+// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) assignRune(pos int, r rune) {
+ bn := rb.rune[pos].pos
+ sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
+ rb.rune[pos] = Properties{pos: bn, size: uint8(sz)}
+}
+
+// runeAt returns the rune at position n. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) runeAt(n int) rune {
+ inf := rb.rune[n]
+ r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
+ return r
+}
+
+// bytesAt returns the UTF-8 encoding of the rune at position n.
+// It is used for Hangul and recomposition.
+func (rb *reorderBuffer) bytesAt(n int) []byte {
+ inf := rb.rune[n]
+ return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
+}
+
+// For Hangul we combine algorithmically, instead of using tables.
+const (
+ hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
+ hangulBase0 = 0xEA
+ hangulBase1 = 0xB0
+ hangulBase2 = 0x80
+
+ hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
+ hangulEnd0 = 0xED
+ hangulEnd1 = 0x9E
+ hangulEnd2 = 0xA4
+
+ jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
+ jamoLBase0 = 0xE1
+ jamoLBase1 = 0x84
+ jamoLEnd = 0x1113
+ jamoVBase = 0x1161
+ jamoVEnd = 0x1176
+ jamoTBase = 0x11A7
+ jamoTEnd = 0x11C3
+
+ jamoTCount = 28
+ jamoVCount = 21
+ jamoVTCount = 21 * 28
+ jamoLVTCount = 19 * 21 * 28
+)
+
+const hangulUTF8Size = 3
+
+func isHangul(b []byte) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+func isHangulString(b string) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must ensure len(b) >= 2.
+func isJamoVT(b []byte) bool {
+ // True if (rune & 0xff00) == jamoLBase
+ return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
+}
+
+func isHangulWithoutJamoT(b []byte) bool {
+ c, _ := utf8.DecodeRune(b)
+ c -= hangulBase
+ return c < jamoLVTCount && c%jamoTCount == 0
+}
+
+// decomposeHangul writes the decomposed Hangul to buf and returns the number
+// of bytes written. len(buf) should be at least 9.
+func decomposeHangul(buf []byte, r rune) int {
+ const JamoUTF8Len = 3
+ r -= hangulBase
+ x := r % jamoTCount
+ r /= jamoTCount
+ utf8.EncodeRune(buf, jamoLBase+r/jamoVCount)
+ utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount)
+ if x != 0 {
+ utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x)
+ return 3 * JamoUTF8Len
+ }
+ return 2 * JamoUTF8Len
+}
+
+// decomposeHangul algorithmically decomposes a Hangul rune into
+// its Jamo components.
+// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
+func (rb *reorderBuffer) decomposeHangul(r rune) {
+ r -= hangulBase
+ x := r % jamoTCount
+ r /= jamoTCount
+ rb.appendRune(jamoLBase + r/jamoVCount)
+ rb.appendRune(jamoVBase + r%jamoVCount)
+ if x != 0 {
+ rb.appendRune(jamoTBase + x)
+ }
+}
+
+// combineHangul algorithmically combines Jamo character components into Hangul.
+// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
+func (rb *reorderBuffer) combineHangul(s, i, k int) {
+ b := rb.rune[:]
+ bn := rb.nrune
+ for ; i < bn; i++ {
+ cccB := b[k-1].ccc
+ cccC := b[i].ccc
+ if cccB == 0 {
+ s = k - 1
+ }
+ if s != k-1 && cccB >= cccC {
+ // b[i] is blocked by greater-equal cccX below it
+ b[k] = b[i]
+ k++
+ } else {
+ l := rb.runeAt(s) // also used to compare to hangulBase
+ v := rb.runeAt(i) // also used to compare to jamoT
+ switch {
+ case jamoLBase <= l && l < jamoLEnd &&
+ jamoVBase <= v && v < jamoVEnd:
+ // 11xx plus 116x to LV
+ rb.assignRune(s, hangulBase+
+ (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
+ case hangulBase <= l && l < hangulEnd &&
+ jamoTBase < v && v < jamoTEnd &&
+ ((l-hangulBase)%jamoTCount) == 0:
+ // ACxx plus 11Ax to LVT
+ rb.assignRune(s, l+v-jamoTBase)
+ default:
+ b[k] = b[i]
+ k++
+ }
+ }
+ }
+ rb.nrune = k
+}
+
+// compose recombines the runes in the buffer.
+// It should only be used to recompose a single segment, as it will not
+// handle alternations between Hangul and non-Hangul characters correctly.
+func (rb *reorderBuffer) compose() {
+ // UAX #15, section X5 , including Corrigendum #5
+ // "In any character sequence beginning with starter S, a character C is
+ // blocked from S if and only if there is some character B between S
+ // and C, and either B is a starter or it has the same or higher
+ // combining class as C."
+ bn := rb.nrune
+ if bn == 0 {
+ return
+ }
+ k := 1
+ b := rb.rune[:]
+ for s, i := 0, 1; i < bn; i++ {
+ if isJamoVT(rb.bytesAt(i)) {
+ // Redo from start in Hangul mode. Necessary to support
+ // U+320E..U+321E in NFKC mode.
+ rb.combineHangul(s, i, k)
+ return
+ }
+ ii := b[i]
+ // We can only use combineForward as a filter if we later
+ // get the info for the combined character. This is more
+ // expensive than using the filter. Using combinesBackward()
+ // is safe.
+ if ii.combinesBackward() {
+ cccB := b[k-1].ccc
+ cccC := ii.ccc
+ blocked := false // b[i] blocked by starter or greater or equal CCC?
+ if cccB == 0 {
+ s = k - 1
+ } else {
+ blocked = s != k-1 && cccB >= cccC
+ }
+ if !blocked {
+ combined := combine(rb.runeAt(s), rb.runeAt(i))
+ if combined != 0 {
+ rb.assignRune(s, combined)
+ continue
+ }
+ }
+ }
+ b[k] = b[i]
+ k++
+ }
+ rb.nrune = k
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/forminfo.go b/libgo/go/golang_org/x/text/unicode/norm/forminfo.go
new file mode 100644
index 0000000000..15a67c653a
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/forminfo.go
@@ -0,0 +1,256 @@
+// 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 norm
+
+// This file contains Form-specific logic and wrappers for data in tables.go.
+
+// Rune info is stored in a separate trie per composing form. A composing form
+// and its corresponding decomposing form share the same trie. Each trie maps
+// a rune to a uint16. The values take two forms. For v >= 0x8000:
+// bits
+// 15: 1 (inverse of NFD_QD bit of qcInfo)
+// 13..7: qcInfo (see below). isYesD is always true (no decompostion).
+// 6..0: ccc (compressed CCC value).
+// For v < 0x8000, the respective rune has a decomposition and v is an index
+// into a byte array of UTF-8 decomposition sequences and additional info and
+// has the form:
+// <header> <decomp_byte>* [<tccc> [<lccc>]]
+// The header contains the number of bytes in the decomposition (excluding this
+// length byte). The two most significant bits of this length byte correspond
+// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1.
+// The byte sequence is followed by a trailing and leading CCC if the values
+// for these are not zero. The value of v determines which ccc are appended
+// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
+// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC
+// there is an additional leading ccc. The value of tccc itself is the
+// trailing CCC shifted left 2 bits. The two least-significant bits of tccc
+// are the number of trailing non-starters.
+
+const (
+ qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo
+ headerLenMask = 0x3F // extract the length value from the header byte
+ headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
+)
+
+// Properties provides access to normalization properties of a rune.
+type Properties struct {
+ pos uint8 // start position in reorderBuffer; used in composition.go
+ size uint8 // length of UTF-8 encoding of this rune
+ ccc uint8 // leading canonical combining class (ccc if not decomposition)
+ tccc uint8 // trailing canonical combining class (ccc if not decomposition)
+ nLead uint8 // number of leading non-starters.
+ flags qcInfo // quick check flags
+ index uint16
+}
+
+// functions dispatchable per form
+type lookupFunc func(b input, i int) Properties
+
+// formInfo holds Form-specific functions and tables.
+type formInfo struct {
+ form Form
+ composing, compatibility bool // form type
+ info lookupFunc
+ nextMain iterFunc
+}
+
+var formTable []*formInfo
+
+func init() {
+ formTable = make([]*formInfo, 4)
+
+ for i := range formTable {
+ f := &formInfo{}
+ formTable[i] = f
+ f.form = Form(i)
+ if Form(i) == NFKD || Form(i) == NFKC {
+ f.compatibility = true
+ f.info = lookupInfoNFKC
+ } else {
+ f.info = lookupInfoNFC
+ }
+ f.nextMain = nextDecomposed
+ if Form(i) == NFC || Form(i) == NFKC {
+ f.nextMain = nextComposed
+ f.composing = true
+ }
+ }
+}
+
+// We do not distinguish between boundaries for NFC, NFD, etc. to avoid
+// unexpected behavior for the user. For example, in NFD, there is a boundary
+// after 'a'. However, 'a' might combine with modifiers, so from the application's
+// perspective it is not a good boundary. We will therefore always use the
+// boundaries for the combining variants.
+
+// BoundaryBefore returns true if this rune starts a new segment and
+// cannot combine with any rune on the left.
+func (p Properties) BoundaryBefore() bool {
+ if p.ccc == 0 && !p.combinesBackward() {
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+// BoundaryAfter returns true if runes cannot combine with or otherwise
+// interact with this or previous runes.
+func (p Properties) BoundaryAfter() bool {
+ // TODO: loosen these conditions.
+ return p.isInert()
+}
+
+// We pack quick check data in 4 bits:
+// 5: Combines forward (0 == false, 1 == true)
+// 4..3: NFC_QC Yes(00), No (10), or Maybe (11)
+// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
+// 1..0: Number of trailing non-starters.
+//
+// When all 4 bits are zero, the character is inert, meaning it is never
+// influenced by normalization.
+type qcInfo uint8
+
+func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
+func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
+
+func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 }
+func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe
+func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD
+
+func (p Properties) isInert() bool {
+ return p.flags&qcInfoMask == 0 && p.ccc == 0
+}
+
+func (p Properties) multiSegment() bool {
+ return p.index >= firstMulti && p.index < endMulti
+}
+
+func (p Properties) nLeadingNonStarters() uint8 {
+ return p.nLead
+}
+
+func (p Properties) nTrailingNonStarters() uint8 {
+ return uint8(p.flags & 0x03)
+}
+
+// Decomposition returns the decomposition for the underlying rune
+// or nil if there is none.
+func (p Properties) Decomposition() []byte {
+ // TODO: create the decomposition for Hangul?
+ if p.index == 0 {
+ return nil
+ }
+ i := p.index
+ n := decomps[i] & headerLenMask
+ i++
+ return decomps[i : i+uint16(n)]
+}
+
+// Size returns the length of UTF-8 encoding of the rune.
+func (p Properties) Size() int {
+ return int(p.size)
+}
+
+// CCC returns the canonical combining class of the underlying rune.
+func (p Properties) CCC() uint8 {
+ if p.index >= firstCCCZeroExcept {
+ return 0
+ }
+ return ccc[p.ccc]
+}
+
+// LeadCCC returns the CCC of the first rune in the decomposition.
+// If there is no decomposition, LeadCCC equals CCC.
+func (p Properties) LeadCCC() uint8 {
+ return ccc[p.ccc]
+}
+
+// TrailCCC returns the CCC of the last rune in the decomposition.
+// If there is no decomposition, TrailCCC equals CCC.
+func (p Properties) TrailCCC() uint8 {
+ return ccc[p.tccc]
+}
+
+// Recomposition
+// We use 32-bit keys instead of 64-bit for the two codepoint keys.
+// This clips off the bits of three entries, but we know this will not
+// result in a collision. In the unlikely event that changes to
+// UnicodeData.txt introduce collisions, the compiler will catch it.
+// Note that the recomposition map for NFC and NFKC are identical.
+
+// combine returns the combined rune or 0 if it doesn't exist.
+func combine(a, b rune) rune {
+ key := uint32(uint16(a))<<16 + uint32(uint16(b))
+ return recompMap[key]
+}
+
+func lookupInfoNFC(b input, i int) Properties {
+ v, sz := b.charinfoNFC(i)
+ return compInfo(v, sz)
+}
+
+func lookupInfoNFKC(b input, i int) Properties {
+ v, sz := b.charinfoNFKC(i)
+ return compInfo(v, sz)
+}
+
+// Properties returns properties for the first rune in s.
+func (f Form) Properties(s []byte) Properties {
+ if f == NFC || f == NFD {
+ return compInfo(nfcData.lookup(s))
+ }
+ return compInfo(nfkcData.lookup(s))
+}
+
+// PropertiesString returns properties for the first rune in s.
+func (f Form) PropertiesString(s string) Properties {
+ if f == NFC || f == NFD {
+ return compInfo(nfcData.lookupString(s))
+ }
+ return compInfo(nfkcData.lookupString(s))
+}
+
+// compInfo converts the information contained in v and sz
+// to a Properties. See the comment at the top of the file
+// for more information on the format.
+func compInfo(v uint16, sz int) Properties {
+ if v == 0 {
+ return Properties{size: uint8(sz)}
+ } else if v >= 0x8000 {
+ p := Properties{
+ size: uint8(sz),
+ ccc: uint8(v),
+ tccc: uint8(v),
+ flags: qcInfo(v >> 8),
+ }
+ if p.ccc > 0 || p.combinesBackward() {
+ p.nLead = uint8(p.flags & 0x3)
+ }
+ return p
+ }
+ // has decomposition
+ h := decomps[v]
+ f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4
+ p := Properties{size: uint8(sz), flags: f, index: v}
+ if v >= firstCCC {
+ v += uint16(h&headerLenMask) + 1
+ c := decomps[v]
+ p.tccc = c >> 2
+ p.flags |= qcInfo(c & 0x3)
+ if v >= firstLeadingCCC {
+ p.nLead = c & 0x3
+ if v >= firstStarterWithNLead {
+ // We were tricked. Remove the decomposition.
+ p.flags &= 0x03
+ p.index = 0
+ return p
+ }
+ p.ccc = decomps[v+1]
+ }
+ }
+ return p
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/input.go b/libgo/go/golang_org/x/text/unicode/norm/input.go
new file mode 100644
index 0000000000..045d4ccce2
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/input.go
@@ -0,0 +1,105 @@
+// 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 norm
+
+import "unicode/utf8"
+
+type input struct {
+ str string
+ bytes []byte
+}
+
+func inputBytes(str []byte) input {
+ return input{bytes: str}
+}
+
+func inputString(str string) input {
+ return input{str: str}
+}
+
+func (in *input) setBytes(str []byte) {
+ in.str = ""
+ in.bytes = str
+}
+
+func (in *input) setString(str string) {
+ in.str = str
+ in.bytes = nil
+}
+
+func (in *input) _byte(p int) byte {
+ if in.bytes == nil {
+ return in.str[p]
+ }
+ return in.bytes[p]
+}
+
+func (in *input) skipASCII(p, max int) int {
+ if in.bytes == nil {
+ for ; p < max && in.str[p] < utf8.RuneSelf; p++ {
+ }
+ } else {
+ for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ {
+ }
+ }
+ return p
+}
+
+func (in *input) skipContinuationBytes(p int) int {
+ if in.bytes == nil {
+ for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ {
+ }
+ } else {
+ for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ {
+ }
+ }
+ return p
+}
+
+func (in *input) appendSlice(buf []byte, b, e int) []byte {
+ if in.bytes != nil {
+ return append(buf, in.bytes[b:e]...)
+ }
+ for i := b; i < e; i++ {
+ buf = append(buf, in.str[i])
+ }
+ return buf
+}
+
+func (in *input) copySlice(buf []byte, b, e int) int {
+ if in.bytes == nil {
+ return copy(buf, in.str[b:e])
+ }
+ return copy(buf, in.bytes[b:e])
+}
+
+func (in *input) charinfoNFC(p int) (uint16, int) {
+ if in.bytes == nil {
+ return nfcData.lookupString(in.str[p:])
+ }
+ return nfcData.lookup(in.bytes[p:])
+}
+
+func (in *input) charinfoNFKC(p int) (uint16, int) {
+ if in.bytes == nil {
+ return nfkcData.lookupString(in.str[p:])
+ }
+ return nfkcData.lookup(in.bytes[p:])
+}
+
+func (in *input) hangul(p int) (r rune) {
+ if in.bytes == nil {
+ if !isHangulString(in.str[p:]) {
+ return 0
+ }
+ r, _ = utf8.DecodeRuneInString(in.str[p:])
+ } else {
+ if !isHangul(in.bytes[p:]) {
+ return 0
+ }
+ r, _ = utf8.DecodeRune(in.bytes[p:])
+ }
+ return r
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/iter.go b/libgo/go/golang_org/x/text/unicode/norm/iter.go
new file mode 100644
index 0000000000..0a42a72de8
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/iter.go
@@ -0,0 +1,450 @@
+// 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 norm
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+// MaxSegmentSize is the maximum size of a byte buffer needed to consider any
+// sequence of starter and non-starter runes for the purpose of normalization.
+const MaxSegmentSize = maxByteBufferSize
+
+// An Iter iterates over a string or byte slice, while normalizing it
+// to a given Form.
+type Iter struct {
+ rb reorderBuffer
+ buf [maxByteBufferSize]byte
+ info Properties // first character saved from previous iteration
+ next iterFunc // implementation of next depends on form
+ asciiF iterFunc
+
+ p int // current position in input source
+ multiSeg []byte // remainder of multi-segment decomposition
+}
+
+type iterFunc func(*Iter) []byte
+
+// Init initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) Init(f Form, src []byte) {
+ i.p = 0
+ if len(src) == 0 {
+ i.setDone()
+ i.rb.nsrc = 0
+ return
+ }
+ i.multiSeg = nil
+ i.rb.init(f, src)
+ i.next = i.rb.f.nextMain
+ i.asciiF = nextASCIIBytes
+ i.info = i.rb.f.info(i.rb.src, i.p)
+}
+
+// InitString initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) InitString(f Form, src string) {
+ i.p = 0
+ if len(src) == 0 {
+ i.setDone()
+ i.rb.nsrc = 0
+ return
+ }
+ i.multiSeg = nil
+ i.rb.initString(f, src)
+ i.next = i.rb.f.nextMain
+ i.asciiF = nextASCIIString
+ i.info = i.rb.f.info(i.rb.src, i.p)
+}
+
+// Seek sets the segment to be returned by the next call to Next to start
+// at position p. It is the responsibility of the caller to set p to the
+// start of a UTF8 rune.
+func (i *Iter) Seek(offset int64, whence int) (int64, error) {
+ var abs int64
+ switch whence {
+ case 0:
+ abs = offset
+ case 1:
+ abs = int64(i.p) + offset
+ case 2:
+ abs = int64(i.rb.nsrc) + offset
+ default:
+ return 0, fmt.Errorf("norm: invalid whence")
+ }
+ if abs < 0 {
+ return 0, fmt.Errorf("norm: negative position")
+ }
+ if int(abs) >= i.rb.nsrc {
+ i.setDone()
+ return int64(i.p), nil
+ }
+ i.p = int(abs)
+ i.multiSeg = nil
+ i.next = i.rb.f.nextMain
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ return abs, nil
+}
+
+// returnSlice returns a slice of the underlying input type as a byte slice.
+// If the underlying is of type []byte, it will simply return a slice.
+// If the underlying is of type string, it will copy the slice to the buffer
+// and return that.
+func (i *Iter) returnSlice(a, b int) []byte {
+ if i.rb.src.bytes == nil {
+ return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])]
+ }
+ return i.rb.src.bytes[a:b]
+}
+
+// Pos returns the byte position at which the next call to Next will commence processing.
+func (i *Iter) Pos() int {
+ return i.p
+}
+
+func (i *Iter) setDone() {
+ i.next = nextDone
+ i.p = i.rb.nsrc
+}
+
+// Done returns true if there is no more input to process.
+func (i *Iter) Done() bool {
+ return i.p >= i.rb.nsrc
+}
+
+// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input.
+// For any input a and b for which f(a) == f(b), subsequent calls
+// to Next will return the same segments.
+// Modifying runes are grouped together with the preceding starter, if such a starter exists.
+// Although not guaranteed, n will typically be the smallest possible n.
+func (i *Iter) Next() []byte {
+ return i.next(i)
+}
+
+func nextASCIIBytes(i *Iter) []byte {
+ p := i.p + 1
+ if p >= i.rb.nsrc {
+ i.setDone()
+ return i.rb.src.bytes[i.p:p]
+ }
+ if i.rb.src.bytes[p] < utf8.RuneSelf {
+ p0 := i.p
+ i.p = p
+ return i.rb.src.bytes[p0:p]
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+func nextASCIIString(i *Iter) []byte {
+ p := i.p + 1
+ if p >= i.rb.nsrc {
+ i.buf[0] = i.rb.src.str[i.p]
+ i.setDone()
+ return i.buf[:1]
+ }
+ if i.rb.src.str[p] < utf8.RuneSelf {
+ i.buf[0] = i.rb.src.str[i.p]
+ i.p = p
+ return i.buf[:1]
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+func nextHangul(i *Iter) []byte {
+ p := i.p
+ next := p + hangulUTF8Size
+ if next >= i.rb.nsrc {
+ i.setDone()
+ } else if i.rb.src.hangul(next) == 0 {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+ }
+ i.p = next
+ return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))]
+}
+
+func nextDone(i *Iter) []byte {
+ return nil
+}
+
+// nextMulti is used for iterating over multi-segment decompositions
+// for decomposing normal forms.
+func nextMulti(i *Iter) []byte {
+ j := 0
+ d := i.multiSeg
+ // skip first rune
+ for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ {
+ }
+ for j < len(d) {
+ info := i.rb.f.info(input{bytes: d}, j)
+ if info.BoundaryBefore() {
+ i.multiSeg = d[j:]
+ return d[:j]
+ }
+ j += int(info.size)
+ }
+ // treat last segment as normal decomposition
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+// nextMultiNorm is used for iterating over multi-segment decompositions
+// for composing normal forms.
+func nextMultiNorm(i *Iter) []byte {
+ j := 0
+ d := i.multiSeg
+ for j < len(d) {
+ info := i.rb.f.info(input{bytes: d}, j)
+ if info.BoundaryBefore() {
+ i.rb.compose()
+ seg := i.buf[:i.rb.flushCopy(i.buf[:])]
+ i.rb.ss.first(info)
+ i.rb.insertUnsafe(input{bytes: d}, j, info)
+ i.multiSeg = d[j+int(info.size):]
+ return seg
+ }
+ i.rb.ss.next(info)
+ i.rb.insertUnsafe(input{bytes: d}, j, info)
+ j += int(info.size)
+ }
+ i.multiSeg = nil
+ i.next = nextComposed
+ return doNormComposed(i)
+}
+
+// nextDecomposed is the implementation of Next for forms NFD and NFKD.
+func nextDecomposed(i *Iter) (next []byte) {
+ outp := 0
+ inCopyStart, outCopyStart := i.p, 0
+ ss := mkStreamSafe(i.info)
+ for {
+ if sz := int(i.info.size); sz <= 1 {
+ p := i.p
+ i.p++ // ASCII or illegal byte. Either way, advance by 1.
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ return i.returnSlice(p, i.p)
+ } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
+ i.next = i.asciiF
+ return i.returnSlice(p, i.p)
+ }
+ outp++
+ } else if d := i.info.Decomposition(); d != nil {
+ // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero.
+ // Case 1: there is a leftover to copy. In this case the decomposition
+ // must begin with a modifier and should always be appended.
+ // Case 2: no leftover. Simply return d if followed by a ccc == 0 value.
+ p := outp + len(d)
+ if outp > 0 {
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ if p > len(i.buf) {
+ return i.buf[:outp]
+ }
+ } else if i.info.multiSegment() {
+ // outp must be 0 as multi-segment decompositions always
+ // start a new segment.
+ if i.multiSeg == nil {
+ i.multiSeg = d
+ i.next = nextMulti
+ return nextMulti(i)
+ }
+ // We are in the last segment. Treat as normal decomposition.
+ d = i.multiSeg
+ i.multiSeg = nil
+ p = len(d)
+ }
+ prevCC := i.info.tccc
+ if i.p += sz; i.p >= i.rb.nsrc {
+ i.setDone()
+ i.info = Properties{} // Force BoundaryBefore to succeed.
+ } else {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+ switch ss.next(i.info) {
+ case ssOverflow:
+ i.next = nextCGJDecompose
+ fallthrough
+ case ssStarter:
+ if outp > 0 {
+ copy(i.buf[outp:], d)
+ return i.buf[:p]
+ }
+ return d
+ }
+ copy(i.buf[outp:], d)
+ outp = p
+ inCopyStart, outCopyStart = i.p, outp
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ continue
+ } else if r := i.rb.src.hangul(i.p); r != 0 {
+ outp = decomposeHangul(i.buf[:], r)
+ i.p += hangulUTF8Size
+ inCopyStart, outCopyStart = i.p, outp
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ } else if i.rb.src.hangul(i.p) != 0 {
+ i.next = nextHangul
+ return i.buf[:outp]
+ }
+ } else {
+ p := outp + sz
+ if p > len(i.buf) {
+ break
+ }
+ outp = p
+ i.p += sz
+ }
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ prevCC := i.info.tccc
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if v := ss.next(i.info); v == ssStarter {
+ break
+ } else if v == ssOverflow {
+ i.next = nextCGJDecompose
+ break
+ }
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ }
+ if outCopyStart == 0 {
+ return i.returnSlice(inCopyStart, i.p)
+ } else if inCopyStart < i.p {
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ }
+ return i.buf[:outp]
+doNorm:
+ // Insert what we have decomposed so far in the reorderBuffer.
+ // As we will only reorder, there will always be enough room.
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ i.rb.insertDecomposed(i.buf[0:outp])
+ return doNormDecomposed(i)
+}
+
+func doNormDecomposed(i *Iter) []byte {
+ for {
+ if s := i.rb.ss.next(i.info); s == ssOverflow {
+ i.next = nextCGJDecompose
+ break
+ }
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.ccc == 0 {
+ break
+ }
+ }
+ // new segment or too many combining characters: exit normalization
+ return i.buf[:i.rb.flushCopy(i.buf[:])]
+}
+
+func nextCGJDecompose(i *Iter) []byte {
+ i.rb.ss = 0
+ i.rb.insertCGJ()
+ i.next = nextDecomposed
+ buf := doNormDecomposed(i)
+ return buf
+}
+
+// nextComposed is the implementation of Next for forms NFC and NFKC.
+func nextComposed(i *Iter) []byte {
+ outp, startp := 0, i.p
+ var prevCC uint8
+ ss := mkStreamSafe(i.info)
+ for {
+ if !i.info.isYesC() {
+ goto doNorm
+ }
+ prevCC = i.info.tccc
+ sz := int(i.info.size)
+ if sz == 0 {
+ sz = 1 // illegal rune: copy byte-by-byte
+ }
+ p := outp + sz
+ if p > len(i.buf) {
+ break
+ }
+ outp = p
+ i.p += sz
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
+ i.next = i.asciiF
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if v := ss.next(i.info); v == ssStarter {
+ break
+ } else if v == ssOverflow {
+ i.next = nextCGJCompose
+ break
+ }
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ }
+ return i.returnSlice(startp, i.p)
+doNorm:
+ i.p = startp
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.multiSegment() {
+ d := i.info.Decomposition()
+ info := i.rb.f.info(input{bytes: d}, 0)
+ i.rb.insertUnsafe(input{bytes: d}, 0, info)
+ i.multiSeg = d[int(info.size):]
+ i.next = nextMultiNorm
+ return nextMultiNorm(i)
+ }
+ i.rb.ss.first(i.info)
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ return doNormComposed(i)
+}
+
+func doNormComposed(i *Iter) []byte {
+ // First rune should already be inserted.
+ for {
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if s := i.rb.ss.next(i.info); s == ssStarter {
+ break
+ } else if s == ssOverflow {
+ i.next = nextCGJCompose
+ break
+ }
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ }
+ i.rb.compose()
+ seg := i.buf[:i.rb.flushCopy(i.buf[:])]
+ return seg
+}
+
+func nextCGJCompose(i *Iter) []byte {
+ i.rb.ss = 0 // instead of first
+ i.rb.insertCGJ()
+ i.next = nextComposed
+ // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter,
+ // even if they are not. This is particularly dubious for U+FF9E and UFF9A.
+ // If we ever change that, insert a check here.
+ i.rb.ss.first(i.info)
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ return doNormComposed(i)
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/normalize.go b/libgo/go/golang_org/x/text/unicode/norm/normalize.go
new file mode 100644
index 0000000000..15c962e2e9
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/normalize.go
@@ -0,0 +1,608 @@
+// 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.
+
+//go:generate go run maketables.go triegen.go
+//go:generate go run maketables.go triegen.go -test
+
+// Package norm contains types and functions for normalizing Unicode strings.
+package norm // import "golang.org/x/text/unicode/norm"
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+// A Form denotes a canonical representation of Unicode code points.
+// The Unicode-defined normalization and equivalence forms are:
+//
+// NFC Unicode Normalization Form C
+// NFD Unicode Normalization Form D
+// NFKC Unicode Normalization Form KC
+// NFKD Unicode Normalization Form KD
+//
+// For a Form f, this documentation uses the notation f(x) to mean
+// the bytes or string x converted to the given form.
+// A position n in x is called a boundary if conversion to the form can
+// proceed independently on both sides:
+// f(x) == append(f(x[0:n]), f(x[n:])...)
+//
+// References: http://unicode.org/reports/tr15/ and
+// http://unicode.org/notes/tn5/.
+type Form int
+
+const (
+ NFC Form = iota
+ NFD
+ NFKC
+ NFKD
+)
+
+// Bytes returns f(b). May return b if f(b) = b.
+func (f Form) Bytes(b []byte) []byte {
+ src := inputBytes(b)
+ ft := formTable[f]
+ n, ok := ft.quickSpan(src, 0, len(b), true)
+ if ok {
+ return b
+ }
+ out := make([]byte, n, len(b))
+ copy(out, b[0:n])
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush}
+ return doAppendInner(&rb, n)
+}
+
+// String returns f(s).
+func (f Form) String(s string) string {
+ src := inputString(s)
+ ft := formTable[f]
+ n, ok := ft.quickSpan(src, 0, len(s), true)
+ if ok {
+ return s
+ }
+ out := make([]byte, n, len(s))
+ copy(out, s[0:n])
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush}
+ return string(doAppendInner(&rb, n))
+}
+
+// IsNormal returns true if b == f(b).
+func (f Form) IsNormal(b []byte) bool {
+ src := inputBytes(b)
+ ft := formTable[f]
+ bp, ok := ft.quickSpan(src, 0, len(b), true)
+ if ok {
+ return true
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)}
+ rb.setFlusher(nil, cmpNormalBytes)
+ for bp < len(b) {
+ rb.out = b[bp:]
+ if bp = decomposeSegment(&rb, bp, true); bp < 0 {
+ return false
+ }
+ bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true)
+ }
+ return true
+}
+
+func cmpNormalBytes(rb *reorderBuffer) bool {
+ b := rb.out
+ for i := 0; i < rb.nrune; i++ {
+ info := rb.rune[i]
+ if int(info.size) > len(b) {
+ return false
+ }
+ p := info.pos
+ pe := p + info.size
+ for ; p < pe; p++ {
+ if b[0] != rb.byte[p] {
+ return false
+ }
+ b = b[1:]
+ }
+ }
+ return true
+}
+
+// IsNormalString returns true if s == f(s).
+func (f Form) IsNormalString(s string) bool {
+ src := inputString(s)
+ ft := formTable[f]
+ bp, ok := ft.quickSpan(src, 0, len(s), true)
+ if ok {
+ return true
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)}
+ rb.setFlusher(nil, func(rb *reorderBuffer) bool {
+ for i := 0; i < rb.nrune; i++ {
+ info := rb.rune[i]
+ if bp+int(info.size) > len(s) {
+ return false
+ }
+ p := info.pos
+ pe := p + info.size
+ for ; p < pe; p++ {
+ if s[bp] != rb.byte[p] {
+ return false
+ }
+ bp++
+ }
+ }
+ return true
+ })
+ for bp < len(s) {
+ if bp = decomposeSegment(&rb, bp, true); bp < 0 {
+ return false
+ }
+ bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true)
+ }
+ return true
+}
+
+// patchTail fixes a case where a rune may be incorrectly normalized
+// if it is followed by illegal continuation bytes. It returns the
+// patched buffer and whether the decomposition is still in progress.
+func patchTail(rb *reorderBuffer) bool {
+ info, p := lastRuneStart(&rb.f, rb.out)
+ if p == -1 || info.size == 0 {
+ return true
+ }
+ end := p + int(info.size)
+ extra := len(rb.out) - end
+ if extra > 0 {
+ // Potentially allocating memory. However, this only
+ // happens with ill-formed UTF-8.
+ x := make([]byte, 0)
+ x = append(x, rb.out[len(rb.out)-extra:]...)
+ rb.out = rb.out[:end]
+ decomposeToLastBoundary(rb)
+ rb.doFlush()
+ rb.out = append(rb.out, x...)
+ return false
+ }
+ buf := rb.out[p:]
+ rb.out = rb.out[:p]
+ decomposeToLastBoundary(rb)
+ if s := rb.ss.next(info); s == ssStarter {
+ rb.doFlush()
+ rb.ss.first(info)
+ } else if s == ssOverflow {
+ rb.doFlush()
+ rb.insertCGJ()
+ rb.ss = 0
+ }
+ rb.insertUnsafe(inputBytes(buf), 0, info)
+ return true
+}
+
+func appendQuick(rb *reorderBuffer, i int) int {
+ if rb.nsrc == i {
+ return i
+ }
+ end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true)
+ rb.out = rb.src.appendSlice(rb.out, i, end)
+ return end
+}
+
+// Append returns f(append(out, b...)).
+// The buffer out must be nil, empty, or equal to f(out).
+func (f Form) Append(out []byte, src ...byte) []byte {
+ return f.doAppend(out, inputBytes(src), len(src))
+}
+
+func (f Form) doAppend(out []byte, src input, n int) []byte {
+ if n == 0 {
+ return out
+ }
+ ft := formTable[f]
+ // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer.
+ if len(out) == 0 {
+ p, _ := ft.quickSpan(src, 0, n, true)
+ out = src.appendSlice(out, 0, p)
+ if p == n {
+ return out
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush}
+ return doAppendInner(&rb, p)
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: n}
+ return doAppend(&rb, out, 0)
+}
+
+func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
+ rb.setFlusher(out, appendFlush)
+ src, n := rb.src, rb.nsrc
+ doMerge := len(out) > 0
+ if q := src.skipContinuationBytes(p); q > p {
+ // Move leading non-starters to destination.
+ rb.out = src.appendSlice(rb.out, p, q)
+ p = q
+ doMerge = patchTail(rb)
+ }
+ fd := &rb.f
+ if doMerge {
+ var info Properties
+ if p < n {
+ info = fd.info(src, p)
+ if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
+ if p == 0 {
+ decomposeToLastBoundary(rb)
+ }
+ p = decomposeSegment(rb, p, true)
+ }
+ }
+ if info.size == 0 {
+ rb.doFlush()
+ // Append incomplete UTF-8 encoding.
+ return src.appendSlice(rb.out, p, n)
+ }
+ if rb.nrune > 0 {
+ return doAppendInner(rb, p)
+ }
+ }
+ p = appendQuick(rb, p)
+ return doAppendInner(rb, p)
+}
+
+func doAppendInner(rb *reorderBuffer, p int) []byte {
+ for n := rb.nsrc; p < n; {
+ p = decomposeSegment(rb, p, true)
+ p = appendQuick(rb, p)
+ }
+ return rb.out
+}
+
+// AppendString returns f(append(out, []byte(s))).
+// The buffer out must be nil, empty, or equal to f(out).
+func (f Form) AppendString(out []byte, src string) []byte {
+ return f.doAppend(out, inputString(src), len(src))
+}
+
+// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpan(b []byte) int {
+ n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true)
+ return n
+}
+
+// Span implements transform.SpanningTransformer. It returns a boundary n such
+// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n.
+func (f Form) Span(b []byte, atEOF bool) (n int, err error) {
+ n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF)
+ if n < len(b) {
+ if !ok {
+ err = transform.ErrEndOfSpan
+ } else {
+ err = transform.ErrShortSrc
+ }
+ }
+ return n, err
+}
+
+// SpanString returns a boundary n such that s[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) SpanString(s string, atEOF bool) (n int, err error) {
+ n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF)
+ if n < len(s) {
+ if !ok {
+ err = transform.ErrEndOfSpan
+ } else {
+ err = transform.ErrShortSrc
+ }
+ }
+ return n, err
+}
+
+// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and
+// whether any non-normalized parts were found. If atEOF is false, n will
+// not point past the last segment if this segment might be become
+// non-normalized by appending other runes.
+func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) {
+ var lastCC uint8
+ ss := streamSafe(0)
+ lastSegStart := i
+ for n = end; i < n; {
+ if j := src.skipASCII(i, n); i != j {
+ i = j
+ lastSegStart = i - 1
+ lastCC = 0
+ ss = 0
+ continue
+ }
+ info := f.info(src, i)
+ if info.size == 0 {
+ if atEOF {
+ // include incomplete runes
+ return n, true
+ }
+ return lastSegStart, true
+ }
+ // This block needs to be before the next, because it is possible to
+ // have an overflow for runes that are starters (e.g. with U+FF9E).
+ switch ss.next(info) {
+ case ssStarter:
+ ss.first(info)
+ lastSegStart = i
+ case ssOverflow:
+ return lastSegStart, false
+ case ssSuccess:
+ if lastCC > info.ccc {
+ return lastSegStart, false
+ }
+ }
+ if f.composing {
+ if !info.isYesC() {
+ break
+ }
+ } else {
+ if !info.isYesD() {
+ break
+ }
+ }
+ lastCC = info.ccc
+ i += int(info.size)
+ }
+ if i == n {
+ if !atEOF {
+ n = lastSegStart
+ }
+ return n, true
+ }
+ return lastSegStart, false
+}
+
+// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpanString(s string) int {
+ n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true)
+ return n
+}
+
+// FirstBoundary returns the position i of the first boundary in b
+// or -1 if b contains no boundary.
+func (f Form) FirstBoundary(b []byte) int {
+ return f.firstBoundary(inputBytes(b), len(b))
+}
+
+func (f Form) firstBoundary(src input, nsrc int) int {
+ i := src.skipContinuationBytes(0)
+ if i >= nsrc {
+ return -1
+ }
+ fd := formTable[f]
+ ss := streamSafe(0)
+ // We should call ss.first here, but we can't as the first rune is
+ // skipped already. This means FirstBoundary can't really determine
+ // CGJ insertion points correctly. Luckily it doesn't have to.
+ for {
+ info := fd.info(src, i)
+ if info.size == 0 {
+ return -1
+ }
+ if s := ss.next(info); s != ssSuccess {
+ return i
+ }
+ i += int(info.size)
+ if i >= nsrc {
+ if !info.BoundaryAfter() && !ss.isMax() {
+ return -1
+ }
+ return nsrc
+ }
+ }
+}
+
+// FirstBoundaryInString returns the position i of the first boundary in s
+// or -1 if s contains no boundary.
+func (f Form) FirstBoundaryInString(s string) int {
+ return f.firstBoundary(inputString(s), len(s))
+}
+
+// NextBoundary reports the index of the boundary between the first and next
+// segment in b or -1 if atEOF is false and there are not enough bytes to
+// determine this boundary.
+func (f Form) NextBoundary(b []byte, atEOF bool) int {
+ return f.nextBoundary(inputBytes(b), len(b), atEOF)
+}
+
+// NextBoundaryInString reports the index of the boundary between the first and
+// next segment in b or -1 if atEOF is false and there are not enough bytes to
+// determine this boundary.
+func (f Form) NextBoundaryInString(s string, atEOF bool) int {
+ return f.nextBoundary(inputString(s), len(s), atEOF)
+}
+
+func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
+ if nsrc == 0 {
+ if atEOF {
+ return 0
+ }
+ return -1
+ }
+ fd := formTable[f]
+ info := fd.info(src, 0)
+ if info.size == 0 {
+ if atEOF {
+ return 1
+ }
+ return -1
+ }
+ ss := streamSafe(0)
+ ss.first(info)
+
+ for i := int(info.size); i < nsrc; i += int(info.size) {
+ info = fd.info(src, i)
+ if info.size == 0 {
+ if atEOF {
+ return i
+ }
+ return -1
+ }
+ if s := ss.next(info); s != ssSuccess {
+ return i
+ }
+ }
+ if !atEOF && !info.BoundaryAfter() && !ss.isMax() {
+ return -1
+ }
+ return nsrc
+}
+
+// LastBoundary returns the position i of the last boundary in b
+// or -1 if b contains no boundary.
+func (f Form) LastBoundary(b []byte) int {
+ return lastBoundary(formTable[f], b)
+}
+
+func lastBoundary(fd *formInfo, b []byte) int {
+ i := len(b)
+ info, p := lastRuneStart(fd, b)
+ if p == -1 {
+ return -1
+ }
+ if info.size == 0 { // ends with incomplete rune
+ if p == 0 { // starts with incomplete rune
+ return -1
+ }
+ i = p
+ info, p = lastRuneStart(fd, b[:i])
+ if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter
+ return i
+ }
+ }
+ if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8
+ return i
+ }
+ if info.BoundaryAfter() {
+ return i
+ }
+ ss := streamSafe(0)
+ v := ss.backwards(info)
+ for i = p; i >= 0 && v != ssStarter; i = p {
+ info, p = lastRuneStart(fd, b[:i])
+ if v = ss.backwards(info); v == ssOverflow {
+ break
+ }
+ if p+int(info.size) != i {
+ if p == -1 { // no boundary found
+ return -1
+ }
+ return i // boundary after an illegal UTF-8 encoding
+ }
+ }
+ return i
+}
+
+// decomposeSegment scans the first segment in src into rb. It inserts 0x034f
+// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters
+// and returns the number of bytes consumed from src or iShortDst or iShortSrc.
+func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
+ // Force one character to be consumed.
+ info := rb.f.info(rb.src, sp)
+ if info.size == 0 {
+ return 0
+ }
+ if rb.nrune > 0 {
+ if s := rb.ss.next(info); s == ssStarter {
+ goto end
+ } else if s == ssOverflow {
+ rb.insertCGJ()
+ goto end
+ }
+ } else {
+ rb.ss.first(info)
+ }
+ if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
+ return int(err)
+ }
+ for {
+ sp += int(info.size)
+ if sp >= rb.nsrc {
+ if !atEOF && !info.BoundaryAfter() {
+ return int(iShortSrc)
+ }
+ break
+ }
+ info = rb.f.info(rb.src, sp)
+ if info.size == 0 {
+ if !atEOF {
+ return int(iShortSrc)
+ }
+ break
+ }
+ if s := rb.ss.next(info); s == ssStarter {
+ break
+ } else if s == ssOverflow {
+ rb.insertCGJ()
+ break
+ }
+ if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
+ return int(err)
+ }
+ }
+end:
+ if !rb.doFlush() {
+ return int(iShortDst)
+ }
+ return sp
+}
+
+// lastRuneStart returns the runeInfo and position of the last
+// rune in buf or the zero runeInfo and -1 if no rune was found.
+func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) {
+ p := len(buf) - 1
+ for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- {
+ }
+ if p < 0 {
+ return Properties{}, -1
+ }
+ return fd.info(inputBytes(buf), p), p
+}
+
+// decomposeToLastBoundary finds an open segment at the end of the buffer
+// and scans it into rb. Returns the buffer minus the last segment.
+func decomposeToLastBoundary(rb *reorderBuffer) {
+ fd := &rb.f
+ info, i := lastRuneStart(fd, rb.out)
+ if int(info.size) != len(rb.out)-i {
+ // illegal trailing continuation bytes
+ return
+ }
+ if info.BoundaryAfter() {
+ return
+ }
+ var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order
+ padd := 0
+ ss := streamSafe(0)
+ p := len(rb.out)
+ for {
+ add[padd] = info
+ v := ss.backwards(info)
+ if v == ssOverflow {
+ // Note that if we have an overflow, it the string we are appending to
+ // is not correctly normalized. In this case the behavior is undefined.
+ break
+ }
+ padd++
+ p -= int(info.size)
+ if v == ssStarter || p < 0 {
+ break
+ }
+ info, i = lastRuneStart(fd, rb.out[:p])
+ if int(info.size) != p-i {
+ break
+ }
+ }
+ rb.ss = ss
+ // Copy bytes for insertion as we may need to overwrite rb.out.
+ var buf [maxBufferSize * utf8.UTFMax]byte
+ cp := buf[:copy(buf[:], rb.out[p:])]
+ rb.out = rb.out[:p]
+ for padd--; padd >= 0; padd-- {
+ info = add[padd]
+ rb.insertUnsafe(inputBytes(cp), 0, info)
+ cp = cp[info.size:]
+ }
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/readwriter.go b/libgo/go/golang_org/x/text/unicode/norm/readwriter.go
new file mode 100644
index 0000000000..d926ee903e
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/readwriter.go
@@ -0,0 +1,125 @@
+// 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 norm
+
+import "io"
+
+type normWriter struct {
+ rb reorderBuffer
+ w io.Writer
+ buf []byte
+}
+
+// Write implements the standard write interface. If the last characters are
+// not at a normalization boundary, the bytes will be buffered for the next
+// write. The remaining bytes will be written on close.
+func (w *normWriter) Write(data []byte) (n int, err error) {
+ // Process data in pieces to keep w.buf size bounded.
+ const chunk = 4000
+
+ for len(data) > 0 {
+ // Normalize into w.buf.
+ m := len(data)
+ if m > chunk {
+ m = chunk
+ }
+ w.rb.src = inputBytes(data[:m])
+ w.rb.nsrc = m
+ w.buf = doAppend(&w.rb, w.buf, 0)
+ data = data[m:]
+ n += m
+
+ // Write out complete prefix, save remainder.
+ // Note that lastBoundary looks back at most 31 runes.
+ i := lastBoundary(&w.rb.f, w.buf)
+ if i == -1 {
+ i = 0
+ }
+ if i > 0 {
+ if _, err = w.w.Write(w.buf[:i]); err != nil {
+ break
+ }
+ bn := copy(w.buf, w.buf[i:])
+ w.buf = w.buf[:bn]
+ }
+ }
+ return n, err
+}
+
+// Close forces data that remains in the buffer to be written.
+func (w *normWriter) Close() error {
+ if len(w.buf) > 0 {
+ _, err := w.w.Write(w.buf)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Writer returns a new writer that implements Write(b)
+// by writing f(b) to w. The returned writer may use an
+// an internal buffer to maintain state across Write calls.
+// Calling its Close method writes any buffered data to w.
+func (f Form) Writer(w io.Writer) io.WriteCloser {
+ wr := &normWriter{rb: reorderBuffer{}, w: w}
+ wr.rb.init(f, nil)
+ return wr
+}
+
+type normReader struct {
+ rb reorderBuffer
+ r io.Reader
+ inbuf []byte
+ outbuf []byte
+ bufStart int
+ lastBoundary int
+ err error
+}
+
+// Read implements the standard read interface.
+func (r *normReader) Read(p []byte) (int, error) {
+ for {
+ if r.lastBoundary-r.bufStart > 0 {
+ n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
+ r.bufStart += n
+ if r.lastBoundary-r.bufStart > 0 {
+ return n, nil
+ }
+ return n, r.err
+ }
+ if r.err != nil {
+ return 0, r.err
+ }
+ outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
+ r.outbuf = r.outbuf[0:outn]
+ r.bufStart = 0
+
+ n, err := r.r.Read(r.inbuf)
+ r.rb.src = inputBytes(r.inbuf[0:n])
+ r.rb.nsrc, r.err = n, err
+ if n > 0 {
+ r.outbuf = doAppend(&r.rb, r.outbuf, 0)
+ }
+ if err == io.EOF {
+ r.lastBoundary = len(r.outbuf)
+ } else {
+ r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
+ if r.lastBoundary == -1 {
+ r.lastBoundary = 0
+ }
+ }
+ }
+}
+
+// Reader returns a new reader that implements Read
+// by reading data from r and returning f(data).
+func (f Form) Reader(r io.Reader) io.Reader {
+ const chunk = 4000
+ buf := make([]byte, chunk)
+ rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
+ rr.rb.init(f, buf)
+ return rr
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/tables.go b/libgo/go/golang_org/x/text/unicode/norm/tables.go
new file mode 100644
index 0000000000..a56697b571
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/tables.go
@@ -0,0 +1,7627 @@
+// This file was generated by go generate; DO NOT EDIT
+
+package norm
+
+const (
+ // Version is the Unicode edition from which the tables are derived.
+ Version = "9.0.0"
+
+ // MaxTransformChunkSize indicates the maximum number of bytes that Transform
+ // may need to write atomically for any Form. Making a destination buffer at
+ // least this size ensures that Transform can always make progress and that
+ // the user does not need to grow the buffer on an ErrShortDst.
+ MaxTransformChunkSize = 35 + maxNonStarters*4
+)
+
+var ccc = [55]uint8{
+ 0, 1, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 84, 91, 103, 107, 118, 122, 129, 130,
+ 132, 202, 214, 216, 218, 220, 222, 224,
+ 226, 228, 230, 232, 233, 234, 240,
+}
+
+const (
+ firstMulti = 0x186D
+ firstCCC = 0x2C9E
+ endMulti = 0x2F60
+ firstLeadingCCC = 0x4A44
+ firstCCCZeroExcept = 0x4A5A
+ firstStarterWithNLead = 0x4A81
+ lastDecomp = 0x4A83
+ maxDecomp = 0x8000
+)
+
+// decomps: 19075 bytes
+var decomps = [...]byte{
+ // Bytes 0 - 3f
+ 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41,
+ 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41,
+ 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41,
+ 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41,
+ 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41,
+ 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41,
+ 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41,
+ 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41,
+ // Bytes 40 - 7f
+ 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41,
+ 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41,
+ 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41,
+ 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41,
+ 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41,
+ 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,
+ 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41,
+ 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41,
+ // Bytes 80 - bf
+ 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41,
+ 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41,
+ 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41,
+ 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41,
+ 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41,
+ 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41,
+ 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41,
+ 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42,
+ // Bytes c0 - ff
+ 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5,
+ 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2,
+ 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42,
+ 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1,
+ 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6,
+ 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42,
+ 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90,
+ 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9,
+ // Bytes 100 - 13f
+ 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42,
+ 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F,
+ 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9,
+ 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42,
+ 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB,
+ 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9,
+ 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42,
+ 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5,
+ // Bytes 140 - 17f
+ 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9,
+ 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42,
+ 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A,
+ 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA,
+ 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42,
+ 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F,
+ 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE,
+ 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42,
+ // Bytes 180 - 1bf
+ 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97,
+ 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE,
+ 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42,
+ 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F,
+ 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE,
+ 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42,
+ 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8,
+ 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE,
+ // Bytes 1c0 - 1ff
+ 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42,
+ 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7,
+ 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE,
+ 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42,
+ 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF,
+ 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF,
+ 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42,
+ 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87,
+ // Bytes 200 - 23f
+ 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF,
+ 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42,
+ 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90,
+ 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7,
+ 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42,
+ 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2,
+ 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8,
+ 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42,
+ // Bytes 240 - 27f
+ 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB,
+ 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8,
+ 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42,
+ 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3,
+ 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8,
+ 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42,
+ 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81,
+ 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9,
+ // Bytes 280 - 2bf
+ 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42,
+ 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89,
+ 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9,
+ 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42,
+ 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE,
+ 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA,
+ 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42,
+ 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C,
+ // Bytes 2c0 - 2ff
+ 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA,
+ 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42,
+ 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9,
+ 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA,
+ 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42,
+ 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81,
+ 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB,
+ 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42,
+ // Bytes 300 - 33f
+ 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90,
+ 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43,
+ 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43,
+ 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43,
+ 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43,
+ 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43,
+ 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43,
+ 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43,
+ // Bytes 340 - 37f
+ 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43,
+ 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43,
+ 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43,
+ 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43,
+ 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43,
+ 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43,
+ 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43,
+ 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43,
+ // Bytes 380 - 3bf
+ 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43,
+ 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43,
+ 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43,
+ 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43,
+ 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43,
+ 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43,
+ 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43,
+ 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43,
+ // Bytes 3c0 - 3ff
+ 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43,
+ 0xE1, 0x86, 0x84, 0x43, 0xE1, 0x86, 0x85, 0x43,
+ 0xE1, 0x86, 0x88, 0x43, 0xE1, 0x86, 0x91, 0x43,
+ 0xE1, 0x86, 0x92, 0x43, 0xE1, 0x86, 0x94, 0x43,
+ 0xE1, 0x86, 0x9E, 0x43, 0xE1, 0x86, 0xA1, 0x43,
+ 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43,
+ 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43,
+ 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43,
+ // Bytes 400 - 43f
+ 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43,
+ 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43,
+ 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43,
+ 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43,
+ 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43,
+ 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43,
+ 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43,
+ 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43,
+ // Bytes 440 - 47f
+ 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43,
+ 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43,
+ 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43,
+ 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43,
+ 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43,
+ 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43,
+ 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43,
+ 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43,
+ // Bytes 480 - 4bf
+ 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43,
+ 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43,
+ 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43,
+ 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43,
+ 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43,
+ 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43,
+ 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43,
+ 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43,
+ // Bytes 4c0 - 4ff
+ 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43,
+ 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43,
+ 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43,
+ 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43,
+ 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43,
+ 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43,
+ 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43,
+ 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43,
+ // Bytes 500 - 53f
+ 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43,
+ 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43,
+ 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43,
+ 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43,
+ 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43,
+ 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43,
+ 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43,
+ 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43,
+ // Bytes 540 - 57f
+ 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43,
+ 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43,
+ 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43,
+ 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43,
+ 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43,
+ 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43,
+ 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43,
+ 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43,
+ // Bytes 580 - 5bf
+ 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43,
+ 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43,
+ 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43,
+ 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43,
+ 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43,
+ 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43,
+ 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43,
+ 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43,
+ // Bytes 5c0 - 5ff
+ 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43,
+ 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43,
+ 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43,
+ 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43,
+ 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43,
+ 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43,
+ 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43,
+ 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43,
+ // Bytes 600 - 63f
+ 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43,
+ 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43,
+ 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43,
+ 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43,
+ 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43,
+ 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43,
+ 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43,
+ 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43,
+ // Bytes 640 - 67f
+ 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43,
+ 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43,
+ 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43,
+ 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43,
+ 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43,
+ 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43,
+ 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43,
+ 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43,
+ // Bytes 680 - 6bf
+ 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43,
+ 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43,
+ 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43,
+ 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43,
+ 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43,
+ 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43,
+ 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43,
+ 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43,
+ // Bytes 6c0 - 6ff
+ 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43,
+ 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43,
+ 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43,
+ 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43,
+ 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43,
+ 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43,
+ 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43,
+ 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43,
+ // Bytes 700 - 73f
+ 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43,
+ 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43,
+ 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43,
+ 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43,
+ 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43,
+ 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43,
+ 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43,
+ 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43,
+ // Bytes 740 - 77f
+ 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43,
+ 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43,
+ 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43,
+ 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43,
+ 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43,
+ 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43,
+ 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43,
+ 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43,
+ // Bytes 780 - 7bf
+ 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43,
+ 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43,
+ 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43,
+ 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43,
+ 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43,
+ 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43,
+ 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43,
+ 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43,
+ // Bytes 7c0 - 7ff
+ 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43,
+ 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43,
+ 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43,
+ 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43,
+ 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43,
+ 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43,
+ 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43,
+ 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43,
+ // Bytes 800 - 83f
+ 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43,
+ 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43,
+ 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43,
+ 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43,
+ 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43,
+ 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43,
+ 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43,
+ 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43,
+ // Bytes 840 - 87f
+ 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43,
+ 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43,
+ 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43,
+ 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43,
+ 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43,
+ 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43,
+ 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43,
+ 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43,
+ // Bytes 880 - 8bf
+ 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43,
+ 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43,
+ 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43,
+ 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43,
+ 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43,
+ 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43,
+ 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43,
+ 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43,
+ // Bytes 8c0 - 8ff
+ 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43,
+ 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43,
+ 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43,
+ 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43,
+ 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43,
+ 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43,
+ 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43,
+ 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43,
+ // Bytes 900 - 93f
+ 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43,
+ 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43,
+ 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43,
+ 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43,
+ 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43,
+ 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43,
+ 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43,
+ 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43,
+ // Bytes 940 - 97f
+ 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43,
+ 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43,
+ 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43,
+ 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43,
+ 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43,
+ 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43,
+ 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43,
+ 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43,
+ // Bytes 980 - 9bf
+ 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43,
+ 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43,
+ 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43,
+ 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43,
+ 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43,
+ 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43,
+ 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43,
+ 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43,
+ // Bytes 9c0 - 9ff
+ 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43,
+ 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43,
+ 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43,
+ 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43,
+ 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43,
+ 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43,
+ 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43,
+ 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43,
+ // Bytes a00 - a3f
+ 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43,
+ 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43,
+ 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43,
+ 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43,
+ 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43,
+ 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43,
+ 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43,
+ 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43,
+ // Bytes a40 - a7f
+ 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43,
+ 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43,
+ 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43,
+ 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43,
+ 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43,
+ 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43,
+ 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43,
+ 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43,
+ // Bytes a80 - abf
+ 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43,
+ 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43,
+ 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43,
+ 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43,
+ 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43,
+ 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43,
+ 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43,
+ 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43,
+ // Bytes ac0 - aff
+ 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43,
+ 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43,
+ 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43,
+ 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43,
+ 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43,
+ 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43,
+ 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43,
+ 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43,
+ // Bytes b00 - b3f
+ 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43,
+ 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43,
+ 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43,
+ 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43,
+ 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43,
+ 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43,
+ 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43,
+ 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43,
+ // Bytes b40 - b7f
+ 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43,
+ 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43,
+ 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43,
+ 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43,
+ 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43,
+ 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43,
+ 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43,
+ 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43,
+ // Bytes b80 - bbf
+ 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43,
+ 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43,
+ 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43,
+ 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43,
+ 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43,
+ 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43,
+ 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43,
+ 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43,
+ // Bytes bc0 - bff
+ 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43,
+ 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43,
+ 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43,
+ 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43,
+ 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43,
+ 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43,
+ 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43,
+ 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43,
+ // Bytes c00 - c3f
+ 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43,
+ 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43,
+ 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43,
+ 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43,
+ 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43,
+ 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43,
+ 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43,
+ 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43,
+ // Bytes c40 - c7f
+ 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43,
+ 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43,
+ 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43,
+ 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43,
+ 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43,
+ 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43,
+ 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43,
+ 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43,
+ // Bytes c80 - cbf
+ 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43,
+ 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43,
+ 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43,
+ 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43,
+ 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43,
+ 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43,
+ 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43,
+ 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43,
+ // Bytes cc0 - cff
+ 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43,
+ 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43,
+ 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43,
+ 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43,
+ 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43,
+ 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43,
+ 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43,
+ 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43,
+ // Bytes d00 - d3f
+ 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43,
+ 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43,
+ 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43,
+ 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43,
+ 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43,
+ 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43,
+ 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43,
+ 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43,
+ // Bytes d40 - d7f
+ 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43,
+ 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43,
+ 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43,
+ 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43,
+ 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43,
+ 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43,
+ 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43,
+ 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43,
+ // Bytes d80 - dbf
+ 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43,
+ 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43,
+ 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43,
+ 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43,
+ 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43,
+ 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43,
+ 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43,
+ 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43,
+ // Bytes dc0 - dff
+ 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43,
+ 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43,
+ 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43,
+ 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43,
+ 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43,
+ 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43,
+ 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43,
+ 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43,
+ // Bytes e00 - e3f
+ 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43,
+ 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43,
+ 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43,
+ 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43,
+ 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43,
+ 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43,
+ 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43,
+ 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43,
+ // Bytes e40 - e7f
+ 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43,
+ 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43,
+ 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43,
+ 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43,
+ 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43,
+ 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43,
+ 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43,
+ 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43,
+ // Bytes e80 - ebf
+ 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43,
+ 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43,
+ 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43,
+ 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43,
+ 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43,
+ 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43,
+ 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43,
+ 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43,
+ // Bytes ec0 - eff
+ 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43,
+ 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43,
+ 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43,
+ 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43,
+ 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43,
+ 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43,
+ 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43,
+ 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43,
+ // Bytes f00 - f3f
+ 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43,
+ 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43,
+ 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43,
+ 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43,
+ 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43,
+ 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43,
+ 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43,
+ 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43,
+ // Bytes f40 - f7f
+ 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43,
+ 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43,
+ 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43,
+ 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43,
+ 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43,
+ 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43,
+ 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43,
+ 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43,
+ // Bytes f80 - fbf
+ 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43,
+ 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43,
+ 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43,
+ 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43,
+ 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43,
+ 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43,
+ 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43,
+ 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43,
+ // Bytes fc0 - fff
+ 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43,
+ 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43,
+ 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43,
+ 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43,
+ 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43,
+ 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43,
+ 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43,
+ 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43,
+ // Bytes 1000 - 103f
+ 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43,
+ 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43,
+ 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43,
+ 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43,
+ 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43,
+ 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43,
+ 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43,
+ 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43,
+ // Bytes 1040 - 107f
+ 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43,
+ 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43,
+ 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43,
+ 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43,
+ 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43,
+ 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43,
+ 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43,
+ 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43,
+ // Bytes 1080 - 10bf
+ 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43,
+ 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43,
+ 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43,
+ 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43,
+ 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43,
+ 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43,
+ 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43,
+ 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43,
+ // Bytes 10c0 - 10ff
+ 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43,
+ 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43,
+ 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43,
+ 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43,
+ 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43,
+ 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43,
+ 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43,
+ 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43,
+ // Bytes 1100 - 113f
+ 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43,
+ 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43,
+ 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43,
+ 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43,
+ 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43,
+ 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43,
+ 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43,
+ 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43,
+ // Bytes 1140 - 117f
+ 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43,
+ 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43,
+ 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43,
+ 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43,
+ 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43,
+ 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43,
+ 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43,
+ 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43,
+ // Bytes 1180 - 11bf
+ 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43,
+ 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43,
+ 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43,
+ 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43,
+ 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43,
+ 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43,
+ 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43,
+ 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43,
+ // Bytes 11c0 - 11ff
+ 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43,
+ 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43,
+ 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43,
+ 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43,
+ 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43,
+ 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43,
+ 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43,
+ 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43,
+ // Bytes 1200 - 123f
+ 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43,
+ 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43,
+ 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43,
+ 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43,
+ 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43,
+ 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43,
+ 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43,
+ 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43,
+ // Bytes 1240 - 127f
+ 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43,
+ 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43,
+ 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43,
+ 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43,
+ 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43,
+ 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43,
+ 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43,
+ 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43,
+ // Bytes 1280 - 12bf
+ 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43,
+ 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43,
+ 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43,
+ 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43,
+ 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43,
+ 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43,
+ 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43,
+ 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43,
+ // Bytes 12c0 - 12ff
+ 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43,
+ 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43,
+ 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43,
+ 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43,
+ 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43,
+ 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43,
+ 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43,
+ 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43,
+ // Bytes 1300 - 133f
+ 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43,
+ 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43,
+ 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43,
+ 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43,
+ 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43,
+ 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43,
+ 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43,
+ 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43,
+ // Bytes 1340 - 137f
+ 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43,
+ 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43,
+ 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43,
+ 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43,
+ 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43,
+ 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43,
+ 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43,
+ 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43,
+ // Bytes 1380 - 13bf
+ 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43,
+ 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43,
+ 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43,
+ 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43,
+ 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43,
+ 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43,
+ 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43,
+ 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43,
+ // Bytes 13c0 - 13ff
+ 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43,
+ 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43,
+ 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43,
+ 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43,
+ 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43,
+ 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43,
+ 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43,
+ 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43,
+ // Bytes 1400 - 143f
+ 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43,
+ 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43,
+ 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43,
+ 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43,
+ 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43,
+ 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43,
+ 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43,
+ 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43,
+ // Bytes 1440 - 147f
+ 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0x8D, 0x43,
+ 0xE9, 0x85, 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43,
+ 0xE9, 0x86, 0xB4, 0x43, 0xE9, 0x87, 0x86, 0x43,
+ 0xE9, 0x87, 0x8C, 0x43, 0xE9, 0x87, 0x8F, 0x43,
+ 0xE9, 0x87, 0x91, 0x43, 0xE9, 0x88, 0xB4, 0x43,
+ 0xE9, 0x88, 0xB8, 0x43, 0xE9, 0x89, 0xB6, 0x43,
+ 0xE9, 0x89, 0xBC, 0x43, 0xE9, 0x8B, 0x97, 0x43,
+ 0xE9, 0x8B, 0x98, 0x43, 0xE9, 0x8C, 0x84, 0x43,
+ // Bytes 1480 - 14bf
+ 0xE9, 0x8D, 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43,
+ 0xE9, 0x90, 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43,
+ 0xE9, 0x96, 0x80, 0x43, 0xE9, 0x96, 0x8B, 0x43,
+ 0xE9, 0x96, 0xAD, 0x43, 0xE9, 0x96, 0xB7, 0x43,
+ 0xE9, 0x98, 0x9C, 0x43, 0xE9, 0x98, 0xAE, 0x43,
+ 0xE9, 0x99, 0x8B, 0x43, 0xE9, 0x99, 0x8D, 0x43,
+ 0xE9, 0x99, 0xB5, 0x43, 0xE9, 0x99, 0xB8, 0x43,
+ 0xE9, 0x99, 0xBC, 0x43, 0xE9, 0x9A, 0x86, 0x43,
+ // Bytes 14c0 - 14ff
+ 0xE9, 0x9A, 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43,
+ 0xE9, 0x9A, 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43,
+ 0xE9, 0x9A, 0xB9, 0x43, 0xE9, 0x9B, 0x83, 0x43,
+ 0xE9, 0x9B, 0xA2, 0x43, 0xE9, 0x9B, 0xA3, 0x43,
+ 0xE9, 0x9B, 0xA8, 0x43, 0xE9, 0x9B, 0xB6, 0x43,
+ 0xE9, 0x9B, 0xB7, 0x43, 0xE9, 0x9C, 0xA3, 0x43,
+ 0xE9, 0x9C, 0xB2, 0x43, 0xE9, 0x9D, 0x88, 0x43,
+ 0xE9, 0x9D, 0x91, 0x43, 0xE9, 0x9D, 0x96, 0x43,
+ // Bytes 1500 - 153f
+ 0xE9, 0x9D, 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43,
+ 0xE9, 0x9D, 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43,
+ 0xE9, 0x9F, 0x9B, 0x43, 0xE9, 0x9F, 0xA0, 0x43,
+ 0xE9, 0x9F, 0xAD, 0x43, 0xE9, 0x9F, 0xB3, 0x43,
+ 0xE9, 0x9F, 0xBF, 0x43, 0xE9, 0xA0, 0x81, 0x43,
+ 0xE9, 0xA0, 0x85, 0x43, 0xE9, 0xA0, 0x8B, 0x43,
+ 0xE9, 0xA0, 0x98, 0x43, 0xE9, 0xA0, 0xA9, 0x43,
+ 0xE9, 0xA0, 0xBB, 0x43, 0xE9, 0xA1, 0x9E, 0x43,
+ // Bytes 1540 - 157f
+ 0xE9, 0xA2, 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43,
+ 0xE9, 0xA3, 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43,
+ 0xE9, 0xA3, 0xAF, 0x43, 0xE9, 0xA3, 0xBC, 0x43,
+ 0xE9, 0xA4, 0xA8, 0x43, 0xE9, 0xA4, 0xA9, 0x43,
+ 0xE9, 0xA6, 0x96, 0x43, 0xE9, 0xA6, 0x99, 0x43,
+ 0xE9, 0xA6, 0xA7, 0x43, 0xE9, 0xA6, 0xAC, 0x43,
+ 0xE9, 0xA7, 0x82, 0x43, 0xE9, 0xA7, 0xB1, 0x43,
+ 0xE9, 0xA7, 0xBE, 0x43, 0xE9, 0xA9, 0xAA, 0x43,
+ // Bytes 1580 - 15bf
+ 0xE9, 0xAA, 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43,
+ 0xE9, 0xAB, 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43,
+ 0xE9, 0xAC, 0xA5, 0x43, 0xE9, 0xAC, 0xAF, 0x43,
+ 0xE9, 0xAC, 0xB2, 0x43, 0xE9, 0xAC, 0xBC, 0x43,
+ 0xE9, 0xAD, 0x9A, 0x43, 0xE9, 0xAD, 0xAF, 0x43,
+ 0xE9, 0xB1, 0x80, 0x43, 0xE9, 0xB1, 0x97, 0x43,
+ 0xE9, 0xB3, 0xA5, 0x43, 0xE9, 0xB3, 0xBD, 0x43,
+ 0xE9, 0xB5, 0xA7, 0x43, 0xE9, 0xB6, 0xB4, 0x43,
+ // Bytes 15c0 - 15ff
+ 0xE9, 0xB7, 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43,
+ 0xE9, 0xB9, 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43,
+ 0xE9, 0xBA, 0x97, 0x43, 0xE9, 0xBA, 0x9F, 0x43,
+ 0xE9, 0xBA, 0xA5, 0x43, 0xE9, 0xBA, 0xBB, 0x43,
+ 0xE9, 0xBB, 0x83, 0x43, 0xE9, 0xBB, 0x8D, 0x43,
+ 0xE9, 0xBB, 0x8E, 0x43, 0xE9, 0xBB, 0x91, 0x43,
+ 0xE9, 0xBB, 0xB9, 0x43, 0xE9, 0xBB, 0xBD, 0x43,
+ 0xE9, 0xBB, 0xBE, 0x43, 0xE9, 0xBC, 0x85, 0x43,
+ // Bytes 1600 - 163f
+ 0xE9, 0xBC, 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43,
+ 0xE9, 0xBC, 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43,
+ 0xE9, 0xBC, 0xA0, 0x43, 0xE9, 0xBC, 0xBB, 0x43,
+ 0xE9, 0xBD, 0x83, 0x43, 0xE9, 0xBD, 0x8A, 0x43,
+ 0xE9, 0xBD, 0x92, 0x43, 0xE9, 0xBE, 0x8D, 0x43,
+ 0xE9, 0xBE, 0x8E, 0x43, 0xE9, 0xBE, 0x9C, 0x43,
+ 0xE9, 0xBE, 0x9F, 0x43, 0xE9, 0xBE, 0xA0, 0x43,
+ 0xEA, 0x9C, 0xA7, 0x43, 0xEA, 0x9D, 0xAF, 0x43,
+ // Bytes 1640 - 167f
+ 0xEA, 0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x44,
+ 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94,
+ 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0,
+ 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA,
+ 0x44, 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0,
+ 0xA3, 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44,
+ 0xF0, 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93,
+ 0xA4, 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0,
+ // Bytes 1680 - 16bf
+ 0xA1, 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88,
+ 0x44, 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1,
+ 0xB4, 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44,
+ 0xF0, 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86,
+ 0x83, 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0,
+ 0xA2, 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94,
+ 0x44, 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2,
+ 0xA1, 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44,
+ // Bytes 16c0 - 16ff
+ 0xF0, 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80,
+ 0x8A, 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0,
+ 0xA3, 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93,
+ 0x44, 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3,
+ 0x8F, 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44,
+ 0xF0, 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A,
+ 0xA3, 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0,
+ 0xA3, 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA,
+ // Bytes 1700 - 173f
+ 0x44, 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3,
+ 0xB4, 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44,
+ 0xF0, 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE,
+ 0x8E, 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0,
+ 0xA4, 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB,
+ 0x44, 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4,
+ 0x9C, 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44,
+ 0xF0, 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2,
+ // Bytes 1740 - 177f
+ 0x92, 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0,
+ 0xA4, 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84,
+ 0x44, 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5,
+ 0x83, 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44,
+ 0xF0, 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89,
+ 0x89, 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0,
+ 0xA5, 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A,
+ 0x44, 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5,
+ // Bytes 1780 - 17bf
+ 0xA5, 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44,
+ 0xF0, 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2,
+ 0x80, 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0,
+ 0xA5, 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A,
+ 0x44, 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6,
+ 0x89, 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44,
+ 0xF0, 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93,
+ 0x9A, 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0,
+ // Bytes 17c0 - 17ff
+ 0xA6, 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7,
+ 0x44, 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6,
+ 0xAC, 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44,
+ 0xF0, 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5,
+ 0xAB, 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0,
+ 0xA6, 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92,
+ 0x44, 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7,
+ 0x99, 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44,
+ // Bytes 1800 - 183f
+ 0xF0, 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2,
+ 0xA8, 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0,
+ 0xA7, 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92,
+ 0x44, 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8,
+ 0x9C, 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44,
+ 0xF0, 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85,
+ 0x85, 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0,
+ 0xA9, 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A,
+ // Bytes 1840 - 187f
+ 0x44, 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9,
+ 0x96, 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44,
+ 0xF0, 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84,
+ 0x85, 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0,
+ 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92,
+ 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x42, 0x21, 0x21,
+ 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30,
+ 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42,
+ // Bytes 1880 - 18bf
+ 0x31, 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31,
+ 0x42, 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31,
+ 0x34, 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42,
+ 0x31, 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39,
+ 0x42, 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32,
+ 0x30, 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42,
+ 0x32, 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35,
+ 0x42, 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32,
+ // Bytes 18c0 - 18ff
+ 0x38, 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42,
+ 0x33, 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31,
+ 0x42, 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33,
+ 0x34, 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42,
+ 0x33, 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39,
+ 0x42, 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34,
+ 0x30, 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42,
+ 0x34, 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35,
+ // Bytes 1900 - 193f
+ 0x42, 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34,
+ 0x38, 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42,
+ 0x35, 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C,
+ 0x42, 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37,
+ 0x2E, 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42,
+ 0x39, 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D,
+ 0x42, 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41,
+ 0x55, 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42,
+ // Bytes 1940 - 197f
+ 0x44, 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A,
+ 0x42, 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48,
+ 0x50, 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42,
+ 0x48, 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A,
+ 0x42, 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49,
+ 0x58, 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42,
+ 0x4B, 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A,
+ 0x42, 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D,
+ // Bytes 1980 - 19bf
+ 0x44, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42,
+ 0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F,
+ 0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50,
+ 0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42,
+ 0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76,
+ 0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57,
+ 0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42,
+ 0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64,
+ // Bytes 19c0 - 19ff
+ 0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64,
+ 0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42,
+ 0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66,
+ 0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66,
+ 0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42,
+ 0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76,
+ 0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B,
+ 0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42,
+ // Bytes 1a00 - 1a3f
+ 0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74,
+ 0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C,
+ 0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42,
+ 0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56,
+ 0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D,
+ 0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42,
+ 0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46,
+ 0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E,
+ // Bytes 1a40 - 1a7f
+ 0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42,
+ 0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46,
+ 0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70,
+ 0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42,
+ 0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69,
+ 0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29,
+ 0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29,
+ 0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29,
+ // Bytes 1a80 - 1abf
+ 0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29,
+ 0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29,
+ 0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29,
+ 0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29,
+ 0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29,
+ 0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29,
+ 0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29,
+ 0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29,
+ // Bytes 1ac0 - 1aff
+ 0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29,
+ 0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29,
+ 0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29,
+ 0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29,
+ 0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29,
+ 0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29,
+ 0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29,
+ 0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29,
+ // Bytes 1b00 - 1b3f
+ 0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29,
+ 0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29,
+ 0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29,
+ 0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29,
+ 0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29,
+ 0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29,
+ 0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29,
+ 0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29,
+ // Bytes 1b40 - 1b7f
+ 0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29,
+ 0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29,
+ 0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29,
+ 0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E,
+ 0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E,
+ 0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E,
+ 0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E,
+ 0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E,
+ // Bytes 1b80 - 1bbf
+ 0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E,
+ 0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D,
+ 0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E,
+ 0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A,
+ 0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49,
+ 0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7,
+ 0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61,
+ 0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D,
+ // Bytes 1bc0 - 1bff
+ 0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45,
+ 0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A,
+ 0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49,
+ 0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73,
+ 0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72,
+ 0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75,
+ 0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32,
+ 0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32,
+ // Bytes 1c00 - 1c3f
+ 0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67,
+ 0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C,
+ 0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61,
+ 0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A,
+ 0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32,
+ 0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9,
+ 0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7,
+ 0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32,
+ // Bytes 1c40 - 1c7f
+ 0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C,
+ 0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69,
+ 0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43,
+ 0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E,
+ 0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46,
+ 0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57,
+ 0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C,
+ 0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73,
+ // Bytes 1c80 - 1cbf
+ 0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31,
+ 0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44,
+ 0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34,
+ 0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28,
+ 0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29,
+ 0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31,
+ 0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44,
+ 0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81,
+ // Bytes 1cc0 - 1cff
+ 0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31,
+ 0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9,
+ 0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6,
+ 0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44,
+ 0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C,
+ 0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34,
+ 0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88,
+ 0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6,
+ // Bytes 1d00 - 1d3f
+ 0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44,
+ 0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97,
+ 0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36,
+ 0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5,
+ 0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7,
+ 0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44,
+ 0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82,
+ 0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39,
+ // Bytes 1d40 - 1d7f
+ 0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9,
+ 0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E,
+ 0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44,
+ 0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69,
+ 0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5,
+ 0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB,
+ 0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4,
+ 0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44,
+ // Bytes 1d80 - 1dbf
+ 0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9,
+ 0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8,
+ 0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE,
+ 0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8,
+ 0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44,
+ 0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9,
+ 0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8,
+ 0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC,
+ // Bytes 1dc0 - 1dff
+ 0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA,
+ 0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44,
+ 0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9,
+ 0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8,
+ 0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB,
+ 0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44,
+ 0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9,
+ // Bytes 1e00 - 1e3f
+ 0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8,
+ 0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC,
+ 0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44,
+ 0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8,
+ 0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE,
+ // Bytes 1e40 - 1e7f
+ 0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44,
+ 0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9,
+ 0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8,
+ 0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD,
+ 0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3,
+ 0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44,
+ 0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9,
+ 0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8,
+ // Bytes 1e80 - 1ebf
+ 0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD,
+ 0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4,
+ 0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44,
+ 0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9,
+ 0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8,
+ 0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE,
+ 0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5,
+ 0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44,
+ // Bytes 1ec0 - 1eff
+ 0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8,
+ 0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8,
+ 0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1,
+ 0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6,
+ 0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44,
+ 0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9,
+ 0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8,
+ 0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85,
+ // Bytes 1f00 - 1f3f
+ 0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9,
+ 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44,
+ 0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8,
+ 0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8,
+ 0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A,
+ 0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81,
+ 0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44,
+ 0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9,
+ // Bytes 1f40 - 1f7f
+ 0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9,
+ 0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85,
+ 0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9,
+ 0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85,
+ 0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83,
+ // Bytes 1f80 - 1fbf
+ 0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9,
+ 0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87,
+ 0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9,
+ // Bytes 1fc0 - 1fff
+ 0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89,
+ 0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86,
+ 0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44,
+ 0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8,
+ 0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9,
+ 0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86,
+ 0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86,
+ 0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44,
+ // Bytes 2000 - 203f
+ 0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9,
+ 0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9,
+ 0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4,
+ 0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A,
+ 0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44,
+ 0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8,
+ 0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9,
+ 0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87,
+ // Bytes 2040 - 207f
+ 0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44,
+ 0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84,
+ 0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28,
+ 0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28,
+ // Bytes 2080 - 20bf
+ 0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28,
+ 0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29,
+ 0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28,
+ 0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8,
+ 0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29,
+ // Bytes 20c0 - 20ff
+ 0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28,
+ 0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB,
+ 0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29,
+ 0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28,
+ 0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85,
+ 0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29,
+ 0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28,
+ 0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90,
+ // Bytes 2100 - 213f
+ 0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29,
+ 0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28,
+ 0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD,
+ 0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29,
+ 0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28,
+ 0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C,
+ 0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
+ 0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28,
+ // Bytes 2140 - 217f
+ 0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89,
+ 0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29,
+ 0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28,
+ 0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5,
+ 0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29,
+ 0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28,
+ 0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3,
+ 0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29,
+ // Bytes 2180 - 21bf
+ 0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31,
+ 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6,
+ 0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7,
+ 0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5,
+ 0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31,
+ 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6,
+ // Bytes 21c0 - 21ff
+ 0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ // Bytes 2200 - 223f
+ 0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31,
+ 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81,
+ 0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35,
+ 0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31,
+ 0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81,
+ 0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39,
+ // Bytes 2240 - 227f
+ 0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9,
+ 0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9,
+ 0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6,
+ // Bytes 2280 - 22bf
+ 0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5,
+ 0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33,
+ 0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
+ 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6,
+ 0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34,
+ 0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
+ // Bytes 22c0 - 22ff
+ 0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81,
+ 0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36,
+ 0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37,
+ 0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88,
+ 0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D,
+ 0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31,
+ 0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2,
+ 0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88,
+ // Bytes 2300 - 233f
+ 0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85,
+ 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46,
+ 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE,
+ // Bytes 2340 - 237f
+ 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46,
+ 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8,
+ 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
+ // Bytes 2380 - 23bf
+ 0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89,
+ 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
+ 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC,
+ 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
+ 0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89,
+ // Bytes 23c0 - 23ff
+ 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46,
+ 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8,
+ 0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3,
+ 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8,
+ 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE,
+ 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46,
+ // Bytes 2400 - 243f
+ 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8,
+ 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5,
+ 0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9,
+ 0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9,
+ 0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A,
+ 0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46,
+ 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8,
+ // Bytes 2440 - 247f
+ 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8,
+ 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
+ 0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A,
+ 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46,
+ 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8,
+ 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81,
+ // Bytes 2480 - 24bf
+ 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9,
+ 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84,
+ 0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85,
+ 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
+ 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
+ 0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84,
+ 0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8,
+ // Bytes 24c0 - 24ff
+ 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+ 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46,
+ 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9,
+ 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC,
+ // Bytes 2500 - 253f
+ 0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
+ 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A,
+ 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46,
+ 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9,
+ 0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85,
+ 0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
+ // Bytes 2540 - 257f
+ 0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46,
+ 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9,
+ 0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9,
+ 0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A,
+ // Bytes 2580 - 25bf
+ 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46,
+ 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
+ 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A,
+ 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+ 0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC,
+ 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46,
+ // Bytes 25c0 - 25ff
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9,
+ 0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88,
+ 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9,
+ // Bytes 2600 - 263f
+ 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
+ 0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2,
+ 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46,
+ 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0,
+ 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD,
+ // Bytes 2640 - 267f
+ 0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82,
+ 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0,
+ 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE,
+ 0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7,
+ 0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46,
+ 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0,
+ 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE,
+ 0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1,
+ // Bytes 2680 - 26bf
+ 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0,
+ 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE,
+ 0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46,
+ 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2,
+ 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81,
+ 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88,
+ 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3,
+ // Bytes 26c0 - 26ff
+ 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82,
+ 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
+ 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46,
+ 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3,
+ 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83,
+ 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA,
+ 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3,
+ 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD,
+ // Bytes 2700 - 273f
+ 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90,
+ 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46,
+ 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72,
+ 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3,
+ 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28,
+ 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48,
+ 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29,
+ 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1,
+ // Bytes 2740 - 277f
+ 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85,
+ 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1,
+ 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87,
+ 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
+ 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
+ 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48,
+ 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29,
+ // Bytes 2780 - 27bf
+ 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1,
+ 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85,
+ 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1,
+ 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91,
+ 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
+ 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61,
+ 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8,
+ 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48,
+ // Bytes 27c0 - 27ff
+ 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87,
+ 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9,
+ 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7,
+ 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8,
+ 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84,
+ 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8,
+ 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2,
+ // Bytes 2800 - 283f
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2,
+ 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
+ 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE,
+ 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3,
+ 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95,
+ 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3,
+ 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B,
+ // Bytes 2840 - 287f
+ 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
+ 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3,
+ 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95,
+ 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3,
+ 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C,
+ 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
+ 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3,
+ 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95,
+ // Bytes 2880 - 28bf
+ 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6,
+ 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3,
+ 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9,
+ 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1,
+ // Bytes 28c0 - 28ff
+ 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3,
+ 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A,
+ 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86,
+ 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3,
+ 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
+ 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3,
+ // Bytes 2900 - 293f
+ 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
+ 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3,
+ 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98,
+ 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3,
+ // Bytes 2940 - 297f
+ 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
+ 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E,
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3,
+ 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF,
+ 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
+ // Bytes 2980 - 29bf
+ 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF,
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2,
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2,
+ 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+ 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3,
+ 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82,
+ 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3,
+ // Bytes 29c0 - 29ff
+ 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB,
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3,
+ 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B,
+ // Bytes 2a00 - 2a3f
+ 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3,
+ 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC,
+ 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C,
+ 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ // Bytes 2a40 - 2a7f
+ 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
+ 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF,
+ 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ // Bytes 2a80 - 2abf
+ 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83,
+ 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C,
+ 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83,
+ 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC,
+ // Bytes 2ac0 - 2aff
+ 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
+ 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4,
+ 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9,
+ // Bytes 2b00 - 2b3f
+ 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7,
+ 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83,
+ 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5,
+ // Bytes 2b40 - 2b7f
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B,
+ 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E,
+ // Bytes 2b80 - 2bbf
+ 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83,
+ 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84,
+ 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3,
+ // Bytes 2bc0 - 2bff
+ 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ // Bytes 2c00 - 2c3f
+ 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3,
+ 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83,
+ 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3,
+ 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83,
+ 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88,
+ 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88,
+ // Bytes 2c40 - 2c7f
+ 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7,
+ 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3,
+ 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9,
+ // Bytes 2c80 - 2cbf
+ 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84,
+ 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9,
+ 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0,
+ 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0,
+ 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0,
+ // Bytes 2cc0 - 2cff
+ 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0,
+ 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
+ 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
+ 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
+ 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
+ 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
+ 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0,
+ // Bytes 2d00 - 2d3f
+ 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0,
+ 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1,
+ 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1,
+ 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ // Bytes 2d40 - 2d7f
+ 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0,
+ // Bytes 2d80 - 2dbf
+ 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01,
+ 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84,
+ 0xA7, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0,
+ 0x91, 0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D,
+ 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0,
+ 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01,
+ 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92,
+ 0xBA, 0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0,
+ // Bytes 2dc0 - 2dff
+ 0x91, 0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96,
+ 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0,
+ 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01,
+ 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0,
+ 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99, 0xE0,
+ 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x12, 0x44, 0x44,
+ 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC,
+ 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9,
+ // Bytes 2e00 - 2e3f
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9,
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5,
+ 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x01,
+ // Bytes 2e40 - 2e7f
+ 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x01,
+ 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x01,
+ // Bytes 2e80 - 2ebf
+ 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x01,
+ 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3,
+ 0x82, 0x99, 0x0D, 0x4C, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4,
+ 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C,
+ 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ // Bytes 2ec0 - 2eff
+ 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83,
+ 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
+ 0x82, 0x99, 0x0D, 0x4F, 0xE1, 0x84, 0x8E, 0xE1,
+ 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80,
+ 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82,
+ 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3,
+ // Bytes 2f00 - 2f3f
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3,
+ 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F,
+ 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95,
+ // Bytes 2f40 - 2f7f
+ 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+ 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x01,
+ 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x01,
+ 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC,
+ 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03,
+ 0x41, 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81,
+ 0xC9, 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41,
+ // Bytes 2f80 - 2fbf
+ 0xCC, 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9,
+ 0x03, 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC,
+ 0x8F, 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03,
+ 0x41, 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8,
+ 0xA5, 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5,
+ 0x03, 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC,
+ 0x82, 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03,
+ // Bytes 2fc0 - 2fff
+ 0x43, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87,
+ 0xC9, 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC,
+ 0xB1, 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03,
+ 0x45, 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83,
+ 0xC9, 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45,
+ 0xCC, 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9,
+ // Bytes 3000 - 303f
+ 0x03, 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03,
+ 0x45, 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8,
+ 0xA5, 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45,
+ 0xCC, 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9,
+ 0x03, 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC,
+ 0x82, 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03,
+ 0x47, 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87,
+ // Bytes 3040 - 307f
+ 0xC9, 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47,
+ 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9,
+ 0x03, 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC,
+ 0x88, 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03,
+ 0x48, 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49,
+ 0xCC, 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9,
+ 0x03, 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC,
+ // Bytes 3080 - 30bf
+ 0x83, 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03,
+ 0x49, 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87,
+ 0xC9, 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9,
+ 0x03, 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03,
+ 0x49, 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82,
+ 0xC9, 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B,
+ // Bytes 30c0 - 30ff
+ 0xCC, 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC,
+ 0xB1, 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03,
+ 0x4C, 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9,
+ 0x03, 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03,
+ // Bytes 3100 - 313f
+ 0x4E, 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83,
+ 0xC9, 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC,
+ 0xAD, 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03,
+ 0x4F, 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81,
+ 0xC9, 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F,
+ 0xCC, 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9,
+ // Bytes 3140 - 317f
+ 0x03, 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC,
+ 0x8F, 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03,
+ 0x50, 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87,
+ 0xC9, 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52,
+ 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC,
+ 0x91, 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03,
+ 0x52, 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82,
+ // Bytes 3180 - 31bf
+ 0xC9, 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53,
+ 0xCC, 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x54, 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9,
+ 0x03, 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC,
+ // Bytes 31c0 - 31ff
+ 0x82, 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03,
+ 0x55, 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A,
+ 0xC9, 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9,
+ 0x03, 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03,
+ 0x55, 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD,
+ 0xB5, 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56,
+ // Bytes 3200 - 323f
+ 0xCC, 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC,
+ 0x81, 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03,
+ 0x57, 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88,
+ 0xC9, 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58,
+ 0xCC, 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9,
+ 0x03, 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC,
+ 0x81, 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03,
+ // Bytes 3240 - 327f
+ 0x59, 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84,
+ 0xC9, 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59,
+ 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9,
+ 0x03, 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC,
+ 0x81, 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03,
+ 0x5A, 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9,
+ // Bytes 3280 - 32bf
+ 0x03, 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC,
+ 0x83, 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03,
+ 0x61, 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61,
+ 0xCC, 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5,
+ 0x03, 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC,
+ 0x87, 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x62, 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81,
+ // Bytes 32c0 - 32ff
+ 0xC9, 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63,
+ 0xCC, 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x64, 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD,
+ 0xB5, 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65,
+ 0xCC, 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9,
+ 0x03, 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC,
+ // Bytes 3300 - 333f
+ 0x86, 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03,
+ 0x65, 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89,
+ 0xC9, 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65,
+ 0xCC, 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9,
+ 0x03, 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC,
+ 0xAD, 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03,
+ 0x66, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81,
+ 0xC9, 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67,
+ // Bytes 3340 - 337f
+ 0xCC, 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9,
+ 0x03, 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03,
+ 0x68, 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87,
+ 0xC9, 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC,
+ 0xAE, 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03,
+ // Bytes 3380 - 33bf
+ 0x69, 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81,
+ 0xC9, 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69,
+ 0xCC, 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9,
+ 0x03, 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC,
+ 0x89, 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03,
+ 0x69, 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91,
+ 0xC9, 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69,
+ 0xCC, 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5,
+ // Bytes 33c0 - 33ff
+ 0x03, 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03,
+ 0x6B, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3,
+ 0xB5, 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9,
+ 0x03, 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC,
+ 0xA7, 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03,
+ 0x6C, 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81,
+ // Bytes 3400 - 343f
+ 0xC9, 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9,
+ 0x03, 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC,
+ 0x83, 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03,
+ 0x6E, 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3,
+ 0xB5, 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E,
+ 0xCC, 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5,
+ 0x03, 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC,
+ // Bytes 3440 - 347f
+ 0x81, 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03,
+ 0x6F, 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B,
+ 0xC9, 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F,
+ 0xCC, 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9,
+ 0x03, 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC,
+ 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03,
+ 0x72, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72,
+ // Bytes 3480 - 34bf
+ 0xCC, 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC,
+ 0x82, 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03,
+ 0x73, 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74,
+ 0xCC, 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC,
+ 0xA6, 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03,
+ // Bytes 34c0 - 34ff
+ 0x74, 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1,
+ 0xB5, 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75,
+ 0xCC, 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9,
+ 0x03, 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC,
+ 0x89, 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03,
+ 0x75, 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75,
+ 0xCC, 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5,
+ // Bytes 3500 - 353f
+ 0x03, 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC,
+ 0xA8, 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03,
+ 0x75, 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83,
+ 0xC9, 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77,
+ 0xCC, 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9,
+ 0x03, 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC,
+ 0x87, 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03,
+ 0x77, 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3,
+ // Bytes 3540 - 357f
+ 0xB5, 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78,
+ 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9,
+ 0x03, 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC,
+ 0x82, 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03,
+ 0x79, 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87,
+ 0xC9, 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79,
+ 0xCC, 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9,
+ 0x03, 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC,
+ // Bytes 3580 - 35bf
+ 0x81, 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03,
+ 0x7A, 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A,
+ 0xCC, 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80,
+ 0xCA, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04,
+ 0xC2, 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86,
+ 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84,
+ 0xC9, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04,
+ // Bytes 35c0 - 35ff
+ 0xC3, 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6,
+ 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81,
+ 0xC9, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04,
+ 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92,
+ 0xCC, 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80,
+ 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04,
+ 0xCE, 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85,
+ // Bytes 3600 - 363f
+ 0xD9, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97,
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04,
+ 0xCE, 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99,
+ 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84,
+ 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04,
+ 0xCE, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F,
+ // Bytes 3640 - 367f
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04,
+ 0xCE, 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5,
+ 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84,
+ 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04,
+ 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04,
+ // Bytes 3680 - 36bf
+ 0xCE, 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85,
+ 0xD9, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7,
+ 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80,
+ 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04,
+ 0xCE, 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82,
+ // Bytes 36c0 - 36ff
+ 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81,
+ 0xCC, 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94,
+ 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85,
+ 0xCC, 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86,
+ 0xC9, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04,
+ 0xCF, 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92,
+ // Bytes 3700 - 373f
+ 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81,
+ 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04,
+ 0xD0, 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04,
+ // Bytes 3740 - 377f
+ 0xD0, 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98,
+ 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84,
+ 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04,
+ 0xD0, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A,
+ 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04,
+ 0xD0, 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B,
+ // Bytes 3780 - 37bf
+ 0xC9, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5,
+ 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6,
+ // Bytes 37c0 - 37ff
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04,
+ 0xD0, 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8,
+ 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04,
+ 0xD0, 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83,
+ 0xCC, 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04,
+ // Bytes 3800 - 383f
+ 0xD1, 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD1, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4,
+ 0xCC, 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F,
+ 0xC9, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD3, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88,
+ // Bytes 3840 - 387f
+ 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04,
+ 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7,
+ 0xD9, 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94,
+ 0xC9, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04,
+ 0xDB, 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92,
+ 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94,
+ 0xC9, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
+ 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
+ // Bytes 3880 - 38bf
+ 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41,
+ 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC,
+ 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86,
+ 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x83, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89,
+ 0xCA, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA,
+ 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05,
+ 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41,
+ // Bytes 38c0 - 38ff
+ 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC,
+ 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7,
+ 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ 0x80, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81,
+ 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA,
+ 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05,
+ 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45,
+ 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC,
+ // Bytes 3900 - 393f
+ 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7,
+ 0xCC, 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC,
+ 0x81, 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84,
+ 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
+ 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F,
+ 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC,
+ 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83,
+ // Bytes 3940 - 397f
+ 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC,
+ 0x88, 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80,
+ 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA,
+ 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
+ 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F,
+ 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC,
+ 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B,
+ 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ // Bytes 3980 - 39bf
+ 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3,
+ 0xB6, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA,
+ 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05,
+ 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53,
+ 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC,
+ 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3,
+ 0xCC, 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC,
+ 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88,
+ // Bytes 39c0 - 39ff
+ 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05,
+ 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55,
+ 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC,
+ 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B,
+ 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x83, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89,
+ 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
+ // Bytes 3a00 - 3a3f
+ 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
+ 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61,
+ 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC,
+ 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86,
+ 0xCC, 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC,
+ 0x81, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83,
+ 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA,
+ 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
+ // Bytes 3a40 - 3a7f
+ 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61,
+ 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC,
+ 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3,
+ 0xCC, 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC,
+ 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80,
+ 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA,
+ 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05,
+ 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65,
+ // Bytes 3a80 - 3abf
+ 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC,
+ 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3,
+ 0xCC, 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC,
+ 0x86, 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81,
+ 0xCA, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA,
+ 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
+ 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F,
+ 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC,
+ // Bytes 3ac0 - 3aff
+ 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83,
+ 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC,
+ 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88,
+ 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA,
+ 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05,
+ 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F,
+ 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC,
+ 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B,
+ // Bytes 3b00 - 3b3f
+ 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC,
+ 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89,
+ 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
+ 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05,
+ 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72,
+ 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC,
+ 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C,
+ 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC,
+ // Bytes 3b40 - 3b7f
+ 0x87, 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81,
+ 0xCA, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA,
+ 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05,
+ 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75,
+ 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B,
+ 0xCC, 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC,
+ 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83,
+ // Bytes 3b80 - 3bbf
+ 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA,
+ 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05,
+ 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1,
+ 0xBE, 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE,
+ 0xBF, 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE,
+ 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC,
+ 0x81, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82,
+ 0xCA, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05,
+ // Bytes 3bc0 - 3bff
+ 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87,
+ 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05,
+ // Bytes 3c00 - 3c3f
+ 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
+ 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ // Bytes 3c40 - 3c7f
+ 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
+ 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
+ // Bytes 3c80 - 3cbf
+ 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
+ 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2,
+ // Bytes 3cc0 - 3cff
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05,
+ 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ // Bytes 3d00 - 3d3f
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ // Bytes 3d40 - 3d7f
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ // Bytes 3d80 - 3dbf
+ 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ // Bytes 3dc0 - 3dff
+ 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ // Bytes 3e00 - 3e3f
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ // Bytes 3e40 - 3e7f
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
+ // Bytes 3e80 - 3ebf
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ // Bytes 3ec0 - 3eff
+ 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85,
+ 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11,
+ // Bytes 3f00 - 3f3f
+ 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 3f40 - 3f7f
+ 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 3f80 - 3fbf
+ 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D,
+ // Bytes 3fc0 - 3fff
+ 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4000 - 403f
+ 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4040 - 407f
+ 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4080 - 40bf
+ 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 40c0 - 40ff
+ 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ // Bytes 4100 - 413f
+ 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD,
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ // Bytes 4140 - 417f
+ 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
+ // Bytes 4180 - 41bf
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ // Bytes 41c0 - 41ff
+ 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD,
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
+ // Bytes 4200 - 423f
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
+ 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
+ 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82,
+ // Bytes 4240 - 427f
+ 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0,
+ 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82,
+ 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2,
+ 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43,
+ 0x20, 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84,
+ 0xC9, 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20,
+ 0xCC, 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9,
+ 0x43, 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC,
+ // Bytes 4280 - 42bf
+ 0x8A, 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43,
+ 0x20, 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94,
+ 0xC9, 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20,
+ 0xCC, 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5,
+ 0x43, 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD,
+ 0x85, 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43,
+ 0x20, 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D,
+ 0x61, 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20,
+ // Bytes 42c0 - 42ff
+ 0xD9, 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D,
+ 0x43, 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9,
+ 0x92, 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43,
+ 0x73, 0xCC, 0x87, 0xC9, 0x43, 0xE1, 0x85, 0xA1,
+ 0x01, 0x43, 0xE1, 0x85, 0xA2, 0x01, 0x43, 0xE1,
+ 0x85, 0xA3, 0x01, 0x43, 0xE1, 0x85, 0xA4, 0x01,
+ 0x43, 0xE1, 0x85, 0xA5, 0x01, 0x43, 0xE1, 0x85,
+ 0xA6, 0x01, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x43,
+ // Bytes 4300 - 433f
+ 0xE1, 0x85, 0xA8, 0x01, 0x43, 0xE1, 0x85, 0xA9,
+ 0x01, 0x43, 0xE1, 0x85, 0xAA, 0x01, 0x43, 0xE1,
+ 0x85, 0xAB, 0x01, 0x43, 0xE1, 0x85, 0xAC, 0x01,
+ 0x43, 0xE1, 0x85, 0xAD, 0x01, 0x43, 0xE1, 0x85,
+ 0xAE, 0x01, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x43,
+ 0xE1, 0x85, 0xB0, 0x01, 0x43, 0xE1, 0x85, 0xB1,
+ 0x01, 0x43, 0xE1, 0x85, 0xB2, 0x01, 0x43, 0xE1,
+ 0x85, 0xB3, 0x01, 0x43, 0xE1, 0x85, 0xB4, 0x01,
+ // Bytes 4340 - 437f
+ 0x43, 0xE1, 0x85, 0xB5, 0x01, 0x43, 0xE1, 0x86,
+ 0xAA, 0x01, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x43,
+ 0xE1, 0x86, 0xAD, 0x01, 0x43, 0xE1, 0x86, 0xB0,
+ 0x01, 0x43, 0xE1, 0x86, 0xB1, 0x01, 0x43, 0xE1,
+ 0x86, 0xB2, 0x01, 0x43, 0xE1, 0x86, 0xB3, 0x01,
+ 0x43, 0xE1, 0x86, 0xB4, 0x01, 0x43, 0xE1, 0x86,
+ 0xB5, 0x01, 0x44, 0x20, 0xE3, 0x82, 0x99, 0x0D,
+ 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, 0x44, 0xC2,
+ // Bytes 4380 - 43bf
+ 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, 0x91, 0xCC,
+ 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, 0x81, 0xC9,
+ 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
+ 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x9F, 0xCC,
+ 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x81, 0xC9,
+ 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x44, 0xCE,
+ 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB1, 0xCC,
+ 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, 0x81, 0xC9,
+ // Bytes 43c0 - 43ff
+ 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
+ 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xBF, 0xCC,
+ 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, 0x81, 0xC9,
+ 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, 0x44, 0xD7,
+ 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, 0x90, 0xD6,
+ 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x92, 0xD6,
+ // Bytes 4400 - 443f
+ 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, 0x95, 0xD6,
+ 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, 0x99, 0xD6,
+ 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ // Bytes 4440 - 447f
+ 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x9C, 0xD6,
+ 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA3, 0xD6,
+ 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, 0x44, 0xD7,
+ 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA7, 0xD6,
+ 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, 0xBC, 0x41,
+ // Bytes 4480 - 44bf
+ 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+ 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, 0xA9, 0xD7,
+ 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, 0xBC, 0x41,
+ 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, 0x44, 0xD8,
+ 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, 0xA7, 0xD9,
+ 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
+ 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x44, 0xD8,
+ 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, 0xB1, 0xD9,
+ // Bytes 44c0 - 44ff
+ 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, 0x8B, 0x59,
+ 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, 0x44, 0xD9,
+ 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, 0x80, 0xD9,
+ 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, 0x91, 0x71,
+ 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, 0x44, 0xD9,
+ 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x88, 0xD9,
+ 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, 0xB0, 0x79,
+ 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x44, 0xDB,
+ // Bytes 4500 - 453f
+ 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, 0x95, 0xD9,
+ 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x80,
+ 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
+ 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xCA, 0x45,
+ 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x45, 0x20,
+ 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xCC, 0x94,
+ 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCC,
+ // Bytes 4540 - 457f
+ 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCD, 0x82,
+ 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x72,
+ 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, 0x72, 0x45,
+ 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, 0x45, 0x20,
+ 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9,
+ 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, 0x91,
+ 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, 0x9D, 0xCC,
+ 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
+ // Bytes 4580 - 45bf
+ 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
+ 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
+ 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
+ 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, 0x8E, 0xD9,
+ 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x8F, 0xD9,
+ 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x90, 0xD9,
+ 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, 0xE0, 0xA4,
+ // Bytes 45c0 - 45ff
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, 0xE0, 0xA6,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6,
+ // Bytes 4600 - 463f
+ 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8,
+ 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC,
+ // Bytes 4640 - 467f
+ 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC,
+ 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, 0xE0, 0xBE,
+ 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE,
+ 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, 0xE3, 0x82,
+ 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, 0x97, 0xF0,
+ 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x85,
+ 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0,
+ 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xAD,
+ // Bytes 4680 - 46bf
+ 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
+ 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, 0xE0, 0xBE,
+ 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
+ 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0,
+ 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+ 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x85,
+ // Bytes 46c0 - 46ff
+ 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+ 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0xAE,
+ 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, 0x4C, 0xF0,
+ 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+ 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86,
+ 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+ // Bytes 4700 - 473f
+ 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE,
+ 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x83, 0x41,
+ 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, 0x86, 0xC9,
+ 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, 0x41, 0xCC,
+ 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, 0xC9, 0x83,
+ 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, 0xCC, 0xA7,
+ // Bytes 4740 - 477f
+ 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, 0x83, 0x45,
+ 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, 0xA3, 0xB5,
+ 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, 0x49, 0xCC,
+ 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, 0xB5, 0x83,
+ 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, 0xCC, 0x83,
+ 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, 0x83, 0x4F,
+ 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, 0x88, 0xC9,
+ 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, 0x4F, 0xCC,
+ // Bytes 4780 - 47bf
+ 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, 0xA5, 0x83,
+ 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, 0xCC, 0x81,
+ 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, 0x83, 0x53,
+ 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, 0x83, 0xC9,
+ 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, 0x55, 0xCC,
+ 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, 0xAD, 0x83,
+ 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, 0xCC, 0x86,
+ 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, 0x83, 0x61,
+ // Bytes 47c0 - 47ff
+ 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, 0x8A, 0xC9,
+ 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, 0x63, 0xCC,
+ 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, 0xC9, 0x83,
+ 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, 0xCC, 0xA3,
+ 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, 0x83, 0x69,
+ 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, 0xA3, 0xB5,
+ 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, 0x6F, 0xCC,
+ 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, 0xC9, 0x83,
+ // Bytes 4800 - 483f
+ 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, 0xCC, 0x88,
+ 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, 0x83, 0x6F,
+ 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0xA8, 0xA5,
+ 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, 0x73, 0xCC,
+ 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, 0xC9, 0x83,
+ 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, 0xCC, 0x83,
+ 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, 0x83, 0x75,
+ 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, 0x9B, 0xAD,
+ // Bytes 4840 - 487f
+ 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
+ 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x95, 0xCC,
+ 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, 0x94, 0xC9,
+ 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
+ 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x99, 0xCC,
+ 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, 0x94, 0xC9,
+ 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
+ 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA5, 0xCC,
+ // Bytes 4880 - 48bf
+ 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x93, 0xC9,
+ 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
+ 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, 0xB1, 0xCC,
+ 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x93, 0xC9,
+ 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
+ 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, 0xB5, 0xCC,
+ 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, 0x94, 0xC9,
+ 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, 0x84, 0xCE,
+ // Bytes 48c0 - 48ff
+ 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x94, 0xC9,
+ 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, 0x84, 0xCE,
+ 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, 0xB9, 0xCC,
+ 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x94, 0xC9,
+ 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
+ 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x85, 0xCC,
+ 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x93, 0xC9,
+ // Bytes 4900 - 493f
+ 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
+ 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, 0x89, 0xCC,
+ 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x93, 0xC9,
+ 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
+ 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, 0x91, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+ // Bytes 4940 - 497f
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+ 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+ // Bytes 4980 - 49bf
+ 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
+ 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ // Bytes 49c0 - 49ff
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ // Bytes 4a00 - 4a3f
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+ 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+ // Bytes 4a40 - 4a7f
+ 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, 0x80, 0xC9,
+ 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, 0x42, 0xCC,
+ 0x93, 0xC9, 0x32, 0x44, 0xCC, 0x88, 0xCC, 0x81,
+ 0xCA, 0x32, 0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03,
+ 0x43, 0xE3, 0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0,
+ 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46,
+ 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26,
+ 0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
+ // Bytes 4a80 - 4abf
+ 0x26, 0x00, 0x01,
+}
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *nfcTrie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfcValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = nfcIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *nfcTrie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfcValues[c0]
+ }
+ i := nfcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *nfcTrie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfcValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := nfcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = nfcIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *nfcTrie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfcValues[c0]
+ }
+ i := nfcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: ad355b768fddb1b6.
+type nfcTrie struct{}
+
+func newNfcTrie(i int) *nfcTrie {
+ return &nfcTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 {
+ switch {
+ case n < 44:
+ return uint16(nfcValues[n<<6+uint32(b)])
+ default:
+ n -= 44
+ return uint16(nfcSparse.lookup(n, b))
+ }
+}
+
+// nfcValues: 46 blocks, 2944 entries, 5888 bytes
+// The third block is the zero block.
+var nfcValues = [2944]uint16{
+ // Block 0x0, offset 0x0
+ 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
+ // Block 0x1, offset 0x40
+ 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
+ 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
+ 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
+ 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
+ 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
+ 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
+ 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
+ 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
+ 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
+ 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
+ 0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
+ 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
+ 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
+ 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
+ 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
+ 0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
+ 0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
+ 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
+ 0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
+ 0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
+ // Block 0x4, offset 0x100
+ 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
+ 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
+ 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
+ 0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
+ 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
+ 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
+ 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
+ 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
+ 0x130: 0x308c, 0x134: 0x30b4, 0x135: 0x33c0,
+ 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
+ 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8,
+ // Block 0x5, offset 0x140
+ 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
+ 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f,
+ 0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
+ 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
+ 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
+ 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
+ 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
+ 0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
+ 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
+ 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
+ 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0xa000,
+ // Block 0x6, offset 0x180
+ 0x184: 0x8100, 0x185: 0x8100,
+ 0x186: 0x8100,
+ 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
+ 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
+ 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
+ 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
+ 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
+ 0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
+ 0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334,
+ 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
+ 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
+ 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
+ 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
+ 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
+ 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
+ 0x1de: 0x305a, 0x1df: 0x3366,
+ 0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
+ 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
+ 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
+ // Block 0x8, offset 0x200
+ 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
+ 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
+ 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
+ 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
+ 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
+ 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
+ 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
+ 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
+ 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
+ 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
+ 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
+ // Block 0x9, offset 0x240
+ 0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
+ 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
+ 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
+ 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
+ 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
+ 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
+ 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
+ 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
+ 0x274: 0x0170,
+ 0x27a: 0x8100,
+ 0x27e: 0x0037,
+ // Block 0xa, offset 0x280
+ 0x284: 0x8100, 0x285: 0x35a1,
+ 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625,
+ 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000,
+ 0x295: 0xa000, 0x297: 0xa000,
+ 0x299: 0xa000,
+ 0x29f: 0xa000, 0x2a1: 0xa000,
+ 0x2a5: 0xa000, 0x2a9: 0xa000,
+ 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
+ 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
+ 0x2b7: 0xa000, 0x2b9: 0xa000,
+ 0x2bf: 0xa000,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x3721, 0x2c1: 0x372d, 0x2c3: 0x371b,
+ 0x2c6: 0xa000, 0x2c7: 0x3709,
+ 0x2cc: 0x375d, 0x2cd: 0x3745, 0x2ce: 0x376f, 0x2d0: 0xa000,
+ 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000,
+ 0x2d8: 0xa000, 0x2d9: 0x3751, 0x2da: 0xa000,
+ 0x2de: 0xa000, 0x2e3: 0xa000,
+ 0x2e7: 0xa000,
+ 0x2eb: 0xa000, 0x2ed: 0xa000,
+ 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000,
+ 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x37d5, 0x2fa: 0xa000,
+ 0x2fe: 0xa000,
+ // Block 0xc, offset 0x300
+ 0x301: 0x3733, 0x302: 0x37b7,
+ 0x310: 0x370f, 0x311: 0x3793,
+ 0x312: 0x3715, 0x313: 0x3799, 0x316: 0x3727, 0x317: 0x37ab,
+ 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3829, 0x31b: 0x382f, 0x31c: 0x3739, 0x31d: 0x37bd,
+ 0x31e: 0x373f, 0x31f: 0x37c3, 0x322: 0x374b, 0x323: 0x37cf,
+ 0x324: 0x3757, 0x325: 0x37db, 0x326: 0x3763, 0x327: 0x37e7, 0x328: 0xa000, 0x329: 0xa000,
+ 0x32a: 0x3835, 0x32b: 0x383b, 0x32c: 0x378d, 0x32d: 0x3811, 0x32e: 0x3769, 0x32f: 0x37ed,
+ 0x330: 0x3775, 0x331: 0x37f9, 0x332: 0x377b, 0x333: 0x37ff, 0x334: 0x3781, 0x335: 0x3805,
+ 0x338: 0x3787, 0x339: 0x380b,
+ // Block 0xd, offset 0x340
+ 0x351: 0x812d,
+ 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132,
+ 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132,
+ 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d,
+ 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132,
+ 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132,
+ 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a,
+ 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f,
+ 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112,
+ // Block 0xe, offset 0x380
+ 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116,
+ 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c,
+ 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132,
+ 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132,
+ 0x39e: 0x8132, 0x39f: 0x812d,
+ 0x3b0: 0x811e,
+ // Block 0xf, offset 0x3c0
+ 0x3c5: 0xa000,
+ 0x3c6: 0x2d26, 0x3c7: 0xa000, 0x3c8: 0x2d2e, 0x3c9: 0xa000, 0x3ca: 0x2d36, 0x3cb: 0xa000,
+ 0x3cc: 0x2d3e, 0x3cd: 0xa000, 0x3ce: 0x2d46, 0x3d1: 0xa000,
+ 0x3d2: 0x2d4e,
+ 0x3f4: 0x8102, 0x3f5: 0x9900,
+ 0x3fa: 0xa000, 0x3fb: 0x2d56,
+ 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000,
+ // Block 0x10, offset 0x400
+ 0x400: 0x2f97, 0x401: 0x32a3, 0x402: 0x2fa1, 0x403: 0x32ad, 0x404: 0x2fa6, 0x405: 0x32b2,
+ 0x406: 0x2fab, 0x407: 0x32b7, 0x408: 0x38cc, 0x409: 0x3a5b, 0x40a: 0x2fc4, 0x40b: 0x32d0,
+ 0x40c: 0x2fce, 0x40d: 0x32da, 0x40e: 0x2fdd, 0x40f: 0x32e9, 0x410: 0x2fd3, 0x411: 0x32df,
+ 0x412: 0x2fd8, 0x413: 0x32e4, 0x414: 0x38ef, 0x415: 0x3a7e, 0x416: 0x38f6, 0x417: 0x3a85,
+ 0x418: 0x3019, 0x419: 0x3325, 0x41a: 0x301e, 0x41b: 0x332a, 0x41c: 0x3904, 0x41d: 0x3a93,
+ 0x41e: 0x3023, 0x41f: 0x332f, 0x420: 0x3032, 0x421: 0x333e, 0x422: 0x3050, 0x423: 0x335c,
+ 0x424: 0x305f, 0x425: 0x336b, 0x426: 0x3055, 0x427: 0x3361, 0x428: 0x3064, 0x429: 0x3370,
+ 0x42a: 0x3069, 0x42b: 0x3375, 0x42c: 0x30af, 0x42d: 0x33bb, 0x42e: 0x390b, 0x42f: 0x3a9a,
+ 0x430: 0x30b9, 0x431: 0x33ca, 0x432: 0x30c3, 0x433: 0x33d4, 0x434: 0x30cd, 0x435: 0x33de,
+ 0x436: 0x475a, 0x437: 0x47eb, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7,
+ 0x43c: 0x30e1, 0x43d: 0x33f2, 0x43e: 0x30eb, 0x43f: 0x33fc,
+ // Block 0x11, offset 0x440
+ 0x440: 0x30f0, 0x441: 0x3401, 0x442: 0x30f5, 0x443: 0x3406, 0x444: 0x3109, 0x445: 0x341a,
+ 0x446: 0x3113, 0x447: 0x3424, 0x448: 0x3122, 0x449: 0x3433, 0x44a: 0x311d, 0x44b: 0x342e,
+ 0x44c: 0x3935, 0x44d: 0x3ac4, 0x44e: 0x3943, 0x44f: 0x3ad2, 0x450: 0x394a, 0x451: 0x3ad9,
+ 0x452: 0x3951, 0x453: 0x3ae0, 0x454: 0x314f, 0x455: 0x3460, 0x456: 0x3154, 0x457: 0x3465,
+ 0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x4787, 0x45b: 0x4818, 0x45c: 0x3997, 0x45d: 0x3b26,
+ 0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4796, 0x463: 0x4827,
+ 0x464: 0x399e, 0x465: 0x3b2d, 0x466: 0x39a5, 0x467: 0x3b34, 0x468: 0x39ac, 0x469: 0x3b3b,
+ 0x46a: 0x3190, 0x46b: 0x34a1, 0x46c: 0x319a, 0x46d: 0x34b0, 0x46e: 0x31ae, 0x46f: 0x34c4,
+ 0x470: 0x31a9, 0x471: 0x34bf, 0x472: 0x31ea, 0x473: 0x3500, 0x474: 0x31f9, 0x475: 0x350f,
+ 0x476: 0x31f4, 0x477: 0x350a, 0x478: 0x39b3, 0x479: 0x3b42, 0x47a: 0x39ba, 0x47b: 0x3b49,
+ 0x47c: 0x31fe, 0x47d: 0x3514, 0x47e: 0x3203, 0x47f: 0x3519,
+ // Block 0x12, offset 0x480
+ 0x480: 0x3208, 0x481: 0x351e, 0x482: 0x320d, 0x483: 0x3523, 0x484: 0x321c, 0x485: 0x3532,
+ 0x486: 0x3217, 0x487: 0x352d, 0x488: 0x3221, 0x489: 0x353c, 0x48a: 0x3226, 0x48b: 0x3541,
+ 0x48c: 0x322b, 0x48d: 0x3546, 0x48e: 0x3249, 0x48f: 0x3564, 0x490: 0x3262, 0x491: 0x3582,
+ 0x492: 0x3271, 0x493: 0x3591, 0x494: 0x3276, 0x495: 0x3596, 0x496: 0x337a, 0x497: 0x34a6,
+ 0x498: 0x3537, 0x499: 0x3573, 0x49b: 0x35d1,
+ 0x4a0: 0x4737, 0x4a1: 0x47c8, 0x4a2: 0x2f83, 0x4a3: 0x328f,
+ 0x4a4: 0x3878, 0x4a5: 0x3a07, 0x4a6: 0x3871, 0x4a7: 0x3a00, 0x4a8: 0x3886, 0x4a9: 0x3a15,
+ 0x4aa: 0x387f, 0x4ab: 0x3a0e, 0x4ac: 0x38be, 0x4ad: 0x3a4d, 0x4ae: 0x3894, 0x4af: 0x3a23,
+ 0x4b0: 0x388d, 0x4b1: 0x3a1c, 0x4b2: 0x38a2, 0x4b3: 0x3a31, 0x4b4: 0x389b, 0x4b5: 0x3a2a,
+ 0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x474b, 0x4b9: 0x47dc, 0x4ba: 0x3000, 0x4bb: 0x330c,
+ 0x4bc: 0x2fec, 0x4bd: 0x32f8, 0x4be: 0x38da, 0x4bf: 0x3a69,
+ // Block 0x13, offset 0x4c0
+ 0x4c0: 0x38d3, 0x4c1: 0x3a62, 0x4c2: 0x38e8, 0x4c3: 0x3a77, 0x4c4: 0x38e1, 0x4c5: 0x3a70,
+ 0x4c6: 0x38fd, 0x4c7: 0x3a8c, 0x4c8: 0x3091, 0x4c9: 0x339d, 0x4ca: 0x30a5, 0x4cb: 0x33b1,
+ 0x4cc: 0x477d, 0x4cd: 0x480e, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf,
+ 0x4d2: 0x3919, 0x4d3: 0x3aa8, 0x4d4: 0x392e, 0x4d5: 0x3abd, 0x4d6: 0x3927, 0x4d7: 0x3ab6,
+ 0x4d8: 0x3989, 0x4d9: 0x3b18, 0x4da: 0x396d, 0x4db: 0x3afc, 0x4dc: 0x3966, 0x4dd: 0x3af5,
+ 0x4de: 0x397b, 0x4df: 0x3b0a, 0x4e0: 0x3974, 0x4e1: 0x3b03, 0x4e2: 0x3982, 0x4e3: 0x3b11,
+ 0x4e4: 0x31e5, 0x4e5: 0x34fb, 0x4e6: 0x31c7, 0x4e7: 0x34dd, 0x4e8: 0x39e4, 0x4e9: 0x3b73,
+ 0x4ea: 0x39dd, 0x4eb: 0x3b6c, 0x4ec: 0x39f2, 0x4ed: 0x3b81, 0x4ee: 0x39eb, 0x4ef: 0x3b7a,
+ 0x4f0: 0x39f9, 0x4f1: 0x3b88, 0x4f2: 0x3230, 0x4f3: 0x354b, 0x4f4: 0x3258, 0x4f5: 0x3578,
+ 0x4f6: 0x3253, 0x4f7: 0x356e, 0x4f8: 0x323f, 0x4f9: 0x355a,
+ // Block 0x14, offset 0x500
+ 0x500: 0x489a, 0x501: 0x48a0, 0x502: 0x49b4, 0x503: 0x49cc, 0x504: 0x49bc, 0x505: 0x49d4,
+ 0x506: 0x49c4, 0x507: 0x49dc, 0x508: 0x4840, 0x509: 0x4846, 0x50a: 0x4924, 0x50b: 0x493c,
+ 0x50c: 0x492c, 0x50d: 0x4944, 0x50e: 0x4934, 0x50f: 0x494c, 0x510: 0x48ac, 0x511: 0x48b2,
+ 0x512: 0x3db8, 0x513: 0x3dc8, 0x514: 0x3dc0, 0x515: 0x3dd0,
+ 0x518: 0x484c, 0x519: 0x4852, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00,
+ 0x520: 0x48c4, 0x521: 0x48ca, 0x522: 0x49e4, 0x523: 0x49fc,
+ 0x524: 0x49ec, 0x525: 0x4a04, 0x526: 0x49f4, 0x527: 0x4a0c, 0x528: 0x4858, 0x529: 0x485e,
+ 0x52a: 0x4954, 0x52b: 0x496c, 0x52c: 0x495c, 0x52d: 0x4974, 0x52e: 0x4964, 0x52f: 0x497c,
+ 0x530: 0x48dc, 0x531: 0x48e2, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38,
+ 0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x4864, 0x539: 0x486a, 0x53a: 0x3d18, 0x53b: 0x3d30,
+ 0x53c: 0x3d20, 0x53d: 0x3d38, 0x53e: 0x3d28, 0x53f: 0x3d40,
+ // Block 0x15, offset 0x540
+ 0x540: 0x48e8, 0x541: 0x48ee, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60,
+ 0x548: 0x4870, 0x549: 0x4876, 0x54a: 0x3d48, 0x54b: 0x3d58,
+ 0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x48fa, 0x551: 0x4900,
+ 0x552: 0x3e80, 0x553: 0x3e98, 0x554: 0x3e88, 0x555: 0x3ea0, 0x556: 0x3e90, 0x557: 0x3ea8,
+ 0x559: 0x487c, 0x55b: 0x3d68, 0x55d: 0x3d70,
+ 0x55f: 0x3d78, 0x560: 0x4912, 0x561: 0x4918, 0x562: 0x4a14, 0x563: 0x4a2c,
+ 0x564: 0x4a1c, 0x565: 0x4a34, 0x566: 0x4a24, 0x567: 0x4a3c, 0x568: 0x4882, 0x569: 0x4888,
+ 0x56a: 0x4984, 0x56b: 0x499c, 0x56c: 0x498c, 0x56d: 0x49a4, 0x56e: 0x4994, 0x56f: 0x49ac,
+ 0x570: 0x488e, 0x571: 0x43b4, 0x572: 0x3691, 0x573: 0x43ba, 0x574: 0x48b8, 0x575: 0x43c0,
+ 0x576: 0x36a3, 0x577: 0x43c6, 0x578: 0x36c1, 0x579: 0x43cc, 0x57a: 0x36d9, 0x57b: 0x43d2,
+ 0x57c: 0x4906, 0x57d: 0x43d8,
+ // Block 0x16, offset 0x580
+ 0x580: 0x3da0, 0x581: 0x3da8, 0x582: 0x4184, 0x583: 0x41a2, 0x584: 0x418e, 0x585: 0x41ac,
+ 0x586: 0x4198, 0x587: 0x41b6, 0x588: 0x3cd8, 0x589: 0x3ce0, 0x58a: 0x40d0, 0x58b: 0x40ee,
+ 0x58c: 0x40da, 0x58d: 0x40f8, 0x58e: 0x40e4, 0x58f: 0x4102, 0x590: 0x3de8, 0x591: 0x3df0,
+ 0x592: 0x41c0, 0x593: 0x41de, 0x594: 0x41ca, 0x595: 0x41e8, 0x596: 0x41d4, 0x597: 0x41f2,
+ 0x598: 0x3d08, 0x599: 0x3d10, 0x59a: 0x410c, 0x59b: 0x412a, 0x59c: 0x4116, 0x59d: 0x4134,
+ 0x59e: 0x4120, 0x59f: 0x413e, 0x5a0: 0x3ec0, 0x5a1: 0x3ec8, 0x5a2: 0x41fc, 0x5a3: 0x421a,
+ 0x5a4: 0x4206, 0x5a5: 0x4224, 0x5a6: 0x4210, 0x5a7: 0x422e, 0x5a8: 0x3d80, 0x5a9: 0x3d88,
+ 0x5aa: 0x4148, 0x5ab: 0x4166, 0x5ac: 0x4152, 0x5ad: 0x4170, 0x5ae: 0x415c, 0x5af: 0x417a,
+ 0x5b0: 0x3685, 0x5b1: 0x367f, 0x5b2: 0x3d90, 0x5b3: 0x368b, 0x5b4: 0x3d98,
+ 0x5b6: 0x48a6, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x4384,
+ 0x5bc: 0x35fb, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100,
+ // Block 0x17, offset 0x5c0
+ 0x5c0: 0x8100, 0x5c1: 0x35a7, 0x5c2: 0x3dd8, 0x5c3: 0x369d, 0x5c4: 0x3de0,
+ 0x5c6: 0x48d0, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x438a, 0x5ca: 0x360d, 0x5cb: 0x4390,
+ 0x5cc: 0x3619, 0x5cd: 0x3b8f, 0x5ce: 0x3b96, 0x5cf: 0x3b9d, 0x5d0: 0x36b5, 0x5d1: 0x36af,
+ 0x5d2: 0x3e00, 0x5d3: 0x457a, 0x5d6: 0x36bb, 0x5d7: 0x3e10,
+ 0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4396, 0x5dd: 0x3ba4,
+ 0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x4582,
+ 0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b,
+ 0x5ea: 0x364f, 0x5eb: 0x43a2, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x437e, 0x5ef: 0x0081,
+ 0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8,
+ 0x5f6: 0x491e, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x439c, 0x5fa: 0x366d, 0x5fb: 0x43ae,
+ 0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100,
+ // Block 0x18, offset 0x600
+ 0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000,
+ 0x607: 0x3c14, 0x608: 0xa000, 0x609: 0x3c1b,
+ 0x60d: 0xa000,
+ 0x620: 0x2f65, 0x621: 0xa000, 0x622: 0x3c29,
+ 0x624: 0xa000, 0x625: 0xa000,
+ 0x62d: 0x3c22, 0x62e: 0x2f60, 0x62f: 0x2f6a,
+ 0x630: 0x3c30, 0x631: 0x3c37, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c3e, 0x635: 0x3c45,
+ 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c4c, 0x639: 0x3c53, 0x63a: 0xa000, 0x63b: 0xa000,
+ 0x63c: 0xa000, 0x63d: 0xa000,
+ // Block 0x19, offset 0x640
+ 0x640: 0x3c5a, 0x641: 0x3c61, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3c76, 0x645: 0x3c7d,
+ 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3c84, 0x649: 0x3c8b,
+ 0x651: 0xa000,
+ 0x652: 0xa000,
+ 0x662: 0xa000,
+ 0x668: 0xa000, 0x669: 0xa000,
+ 0x66b: 0xa000, 0x66c: 0x3ca0, 0x66d: 0x3ca7, 0x66e: 0x3cae, 0x66f: 0x3cb5,
+ 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000,
+ // Block 0x1a, offset 0x680
+ 0x686: 0xa000, 0x68b: 0xa000,
+ 0x68c: 0x3f08, 0x68d: 0xa000, 0x68e: 0x3f10, 0x68f: 0xa000, 0x690: 0x3f18, 0x691: 0xa000,
+ 0x692: 0x3f20, 0x693: 0xa000, 0x694: 0x3f28, 0x695: 0xa000, 0x696: 0x3f30, 0x697: 0xa000,
+ 0x698: 0x3f38, 0x699: 0xa000, 0x69a: 0x3f40, 0x69b: 0xa000, 0x69c: 0x3f48, 0x69d: 0xa000,
+ 0x69e: 0x3f50, 0x69f: 0xa000, 0x6a0: 0x3f58, 0x6a1: 0xa000, 0x6a2: 0x3f60,
+ 0x6a4: 0xa000, 0x6a5: 0x3f68, 0x6a6: 0xa000, 0x6a7: 0x3f70, 0x6a8: 0xa000, 0x6a9: 0x3f78,
+ 0x6af: 0xa000,
+ 0x6b0: 0x3f80, 0x6b1: 0x3f88, 0x6b2: 0xa000, 0x6b3: 0x3f90, 0x6b4: 0x3f98, 0x6b5: 0xa000,
+ 0x6b6: 0x3fa0, 0x6b7: 0x3fa8, 0x6b8: 0xa000, 0x6b9: 0x3fb0, 0x6ba: 0x3fb8, 0x6bb: 0xa000,
+ 0x6bc: 0x3fc0, 0x6bd: 0x3fc8,
+ // Block 0x1b, offset 0x6c0
+ 0x6d4: 0x3f00,
+ 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000,
+ 0x6de: 0x3fd0,
+ 0x6e6: 0xa000,
+ 0x6eb: 0xa000, 0x6ec: 0x3fe0, 0x6ed: 0xa000, 0x6ee: 0x3fe8, 0x6ef: 0xa000,
+ 0x6f0: 0x3ff0, 0x6f1: 0xa000, 0x6f2: 0x3ff8, 0x6f3: 0xa000, 0x6f4: 0x4000, 0x6f5: 0xa000,
+ 0x6f6: 0x4008, 0x6f7: 0xa000, 0x6f8: 0x4010, 0x6f9: 0xa000, 0x6fa: 0x4018, 0x6fb: 0xa000,
+ 0x6fc: 0x4020, 0x6fd: 0xa000, 0x6fe: 0x4028, 0x6ff: 0xa000,
+ // Block 0x1c, offset 0x700
+ 0x700: 0x4030, 0x701: 0xa000, 0x702: 0x4038, 0x704: 0xa000, 0x705: 0x4040,
+ 0x706: 0xa000, 0x707: 0x4048, 0x708: 0xa000, 0x709: 0x4050,
+ 0x70f: 0xa000, 0x710: 0x4058, 0x711: 0x4060,
+ 0x712: 0xa000, 0x713: 0x4068, 0x714: 0x4070, 0x715: 0xa000, 0x716: 0x4078, 0x717: 0x4080,
+ 0x718: 0xa000, 0x719: 0x4088, 0x71a: 0x4090, 0x71b: 0xa000, 0x71c: 0x4098, 0x71d: 0x40a0,
+ 0x72f: 0xa000,
+ 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x3fd8,
+ 0x737: 0x40a8, 0x738: 0x40b0, 0x739: 0x40b8, 0x73a: 0x40c0,
+ 0x73d: 0xa000, 0x73e: 0x40c8,
+ // Block 0x1d, offset 0x740
+ 0x740: 0x1377, 0x741: 0x0cfb, 0x742: 0x13d3, 0x743: 0x139f, 0x744: 0x0e57, 0x745: 0x06eb,
+ 0x746: 0x08df, 0x747: 0x162b, 0x748: 0x162b, 0x749: 0x0a0b, 0x74a: 0x145f, 0x74b: 0x0943,
+ 0x74c: 0x0a07, 0x74d: 0x0bef, 0x74e: 0x0fcf, 0x74f: 0x115f, 0x750: 0x1297, 0x751: 0x12d3,
+ 0x752: 0x1307, 0x753: 0x141b, 0x754: 0x0d73, 0x755: 0x0dff, 0x756: 0x0eab, 0x757: 0x0f43,
+ 0x758: 0x125f, 0x759: 0x1447, 0x75a: 0x1573, 0x75b: 0x070f, 0x75c: 0x08b3, 0x75d: 0x0d87,
+ 0x75e: 0x0ecf, 0x75f: 0x1293, 0x760: 0x15c3, 0x761: 0x0ab3, 0x762: 0x0e77, 0x763: 0x1283,
+ 0x764: 0x1317, 0x765: 0x0c23, 0x766: 0x11bb, 0x767: 0x12df, 0x768: 0x0b1f, 0x769: 0x0d0f,
+ 0x76a: 0x0e17, 0x76b: 0x0f1b, 0x76c: 0x1427, 0x76d: 0x074f, 0x76e: 0x07e7, 0x76f: 0x0853,
+ 0x770: 0x0c8b, 0x771: 0x0d7f, 0x772: 0x0ecb, 0x773: 0x0fef, 0x774: 0x1177, 0x775: 0x128b,
+ 0x776: 0x12a3, 0x777: 0x13c7, 0x778: 0x14ef, 0x779: 0x15a3, 0x77a: 0x15bf, 0x77b: 0x102b,
+ 0x77c: 0x106b, 0x77d: 0x1123, 0x77e: 0x1243, 0x77f: 0x147b,
+ // Block 0x1e, offset 0x780
+ 0x780: 0x15cb, 0x781: 0x134b, 0x782: 0x09c7, 0x783: 0x0b3b, 0x784: 0x10db, 0x785: 0x119b,
+ 0x786: 0x0eff, 0x787: 0x1033, 0x788: 0x1397, 0x789: 0x14e7, 0x78a: 0x09c3, 0x78b: 0x0a8f,
+ 0x78c: 0x0d77, 0x78d: 0x0e2b, 0x78e: 0x0e5f, 0x78f: 0x1113, 0x790: 0x113b, 0x791: 0x14a7,
+ 0x792: 0x084f, 0x793: 0x11a7, 0x794: 0x07f3, 0x795: 0x07ef, 0x796: 0x1097, 0x797: 0x1127,
+ 0x798: 0x125b, 0x799: 0x14af, 0x79a: 0x1367, 0x79b: 0x0c27, 0x79c: 0x0d73, 0x79d: 0x1357,
+ 0x79e: 0x06f7, 0x79f: 0x0a63, 0x7a0: 0x0b93, 0x7a1: 0x0f2f, 0x7a2: 0x0faf, 0x7a3: 0x0873,
+ 0x7a4: 0x103b, 0x7a5: 0x075f, 0x7a6: 0x0b77, 0x7a7: 0x06d7, 0x7a8: 0x0deb, 0x7a9: 0x0ca3,
+ 0x7aa: 0x110f, 0x7ab: 0x08c7, 0x7ac: 0x09b3, 0x7ad: 0x0ffb, 0x7ae: 0x1263, 0x7af: 0x133b,
+ 0x7b0: 0x0db7, 0x7b1: 0x13f7, 0x7b2: 0x0de3, 0x7b3: 0x0c37, 0x7b4: 0x121b, 0x7b5: 0x0c57,
+ 0x7b6: 0x0fab, 0x7b7: 0x072b, 0x7b8: 0x07a7, 0x7b9: 0x07eb, 0x7ba: 0x0d53, 0x7bb: 0x10fb,
+ 0x7bc: 0x11f3, 0x7bd: 0x1347, 0x7be: 0x145b, 0x7bf: 0x085b,
+ // Block 0x1f, offset 0x7c0
+ 0x7c0: 0x090f, 0x7c1: 0x0a17, 0x7c2: 0x0b2f, 0x7c3: 0x0cbf, 0x7c4: 0x0e7b, 0x7c5: 0x103f,
+ 0x7c6: 0x1497, 0x7c7: 0x157b, 0x7c8: 0x15cf, 0x7c9: 0x15e7, 0x7ca: 0x0837, 0x7cb: 0x0cf3,
+ 0x7cc: 0x0da3, 0x7cd: 0x13eb, 0x7ce: 0x0afb, 0x7cf: 0x0bd7, 0x7d0: 0x0bf3, 0x7d1: 0x0c83,
+ 0x7d2: 0x0e6b, 0x7d3: 0x0eb7, 0x7d4: 0x0f67, 0x7d5: 0x108b, 0x7d6: 0x112f, 0x7d7: 0x1193,
+ 0x7d8: 0x13db, 0x7d9: 0x126b, 0x7da: 0x1403, 0x7db: 0x147f, 0x7dc: 0x080f, 0x7dd: 0x083b,
+ 0x7de: 0x0923, 0x7df: 0x0ea7, 0x7e0: 0x12f3, 0x7e1: 0x133b, 0x7e2: 0x0b1b, 0x7e3: 0x0b8b,
+ 0x7e4: 0x0c4f, 0x7e5: 0x0daf, 0x7e6: 0x10d7, 0x7e7: 0x0f23, 0x7e8: 0x073b, 0x7e9: 0x097f,
+ 0x7ea: 0x0a63, 0x7eb: 0x0ac7, 0x7ec: 0x0b97, 0x7ed: 0x0f3f, 0x7ee: 0x0f5b, 0x7ef: 0x116b,
+ 0x7f0: 0x118b, 0x7f1: 0x1463, 0x7f2: 0x14e3, 0x7f3: 0x14f3, 0x7f4: 0x152f, 0x7f5: 0x0753,
+ 0x7f6: 0x107f, 0x7f7: 0x144f, 0x7f8: 0x14cb, 0x7f9: 0x0baf, 0x7fa: 0x0717, 0x7fb: 0x0777,
+ 0x7fc: 0x0a67, 0x7fd: 0x0a87, 0x7fe: 0x0caf, 0x7ff: 0x0d73,
+ // Block 0x20, offset 0x800
+ 0x800: 0x0ec3, 0x801: 0x0fcb, 0x802: 0x1277, 0x803: 0x1417, 0x804: 0x1623, 0x805: 0x0ce3,
+ 0x806: 0x14a3, 0x807: 0x0833, 0x808: 0x0d2f, 0x809: 0x0d3b, 0x80a: 0x0e0f, 0x80b: 0x0e47,
+ 0x80c: 0x0f4b, 0x80d: 0x0fa7, 0x80e: 0x1027, 0x80f: 0x110b, 0x810: 0x153b, 0x811: 0x07af,
+ 0x812: 0x0c03, 0x813: 0x14b3, 0x814: 0x0767, 0x815: 0x0aab, 0x816: 0x0e2f, 0x817: 0x13df,
+ 0x818: 0x0b67, 0x819: 0x0bb7, 0x81a: 0x0d43, 0x81b: 0x0f2f, 0x81c: 0x14bb, 0x81d: 0x0817,
+ 0x81e: 0x08ff, 0x81f: 0x0a97, 0x820: 0x0cd3, 0x821: 0x0d1f, 0x822: 0x0d5f, 0x823: 0x0df3,
+ 0x824: 0x0f47, 0x825: 0x0fbb, 0x826: 0x1157, 0x827: 0x12f7, 0x828: 0x1303, 0x829: 0x1457,
+ 0x82a: 0x14d7, 0x82b: 0x0883, 0x82c: 0x0e4b, 0x82d: 0x0903, 0x82e: 0x0ec7, 0x82f: 0x0f6b,
+ 0x830: 0x1287, 0x831: 0x14bf, 0x832: 0x15ab, 0x833: 0x15d3, 0x834: 0x0d37, 0x835: 0x0e27,
+ 0x836: 0x11c3, 0x837: 0x10b7, 0x838: 0x10c3, 0x839: 0x10e7, 0x83a: 0x0f17, 0x83b: 0x0e9f,
+ 0x83c: 0x1363, 0x83d: 0x0733, 0x83e: 0x122b, 0x83f: 0x081b,
+ // Block 0x21, offset 0x840
+ 0x840: 0x080b, 0x841: 0x0b0b, 0x842: 0x0c2b, 0x843: 0x10f3, 0x844: 0x0a53, 0x845: 0x0e03,
+ 0x846: 0x0cef, 0x847: 0x13e7, 0x848: 0x12e7, 0x849: 0x14ab, 0x84a: 0x1323, 0x84b: 0x0b27,
+ 0x84c: 0x0787, 0x84d: 0x095b, 0x850: 0x09af,
+ 0x852: 0x0cdf, 0x855: 0x07f7, 0x856: 0x0f1f, 0x857: 0x0fe3,
+ 0x858: 0x1047, 0x859: 0x1063, 0x85a: 0x1067, 0x85b: 0x107b, 0x85c: 0x14fb, 0x85d: 0x10eb,
+ 0x85e: 0x116f, 0x860: 0x128f, 0x862: 0x1353,
+ 0x865: 0x1407, 0x866: 0x1433,
+ 0x86a: 0x154f, 0x86b: 0x1553, 0x86c: 0x1557, 0x86d: 0x15bb, 0x86e: 0x142b, 0x86f: 0x14c7,
+ 0x870: 0x0757, 0x871: 0x077b, 0x872: 0x078f, 0x873: 0x084b, 0x874: 0x0857, 0x875: 0x0897,
+ 0x876: 0x094b, 0x877: 0x0967, 0x878: 0x096f, 0x879: 0x09ab, 0x87a: 0x09b7, 0x87b: 0x0a93,
+ 0x87c: 0x0a9b, 0x87d: 0x0ba3, 0x87e: 0x0bcb, 0x87f: 0x0bd3,
+ // Block 0x22, offset 0x880
+ 0x880: 0x0beb, 0x881: 0x0c97, 0x882: 0x0cc7, 0x883: 0x0ce7, 0x884: 0x0d57, 0x885: 0x0e1b,
+ 0x886: 0x0e37, 0x887: 0x0e67, 0x888: 0x0ebb, 0x889: 0x0edb, 0x88a: 0x0f4f, 0x88b: 0x102f,
+ 0x88c: 0x104b, 0x88d: 0x1053, 0x88e: 0x104f, 0x88f: 0x1057, 0x890: 0x105b, 0x891: 0x105f,
+ 0x892: 0x1073, 0x893: 0x1077, 0x894: 0x109b, 0x895: 0x10af, 0x896: 0x10cb, 0x897: 0x112f,
+ 0x898: 0x1137, 0x899: 0x113f, 0x89a: 0x1153, 0x89b: 0x117b, 0x89c: 0x11cb, 0x89d: 0x11ff,
+ 0x89e: 0x11ff, 0x89f: 0x1267, 0x8a0: 0x130f, 0x8a1: 0x1327, 0x8a2: 0x135b, 0x8a3: 0x135f,
+ 0x8a4: 0x13a3, 0x8a5: 0x13a7, 0x8a6: 0x13ff, 0x8a7: 0x1407, 0x8a8: 0x14db, 0x8a9: 0x151f,
+ 0x8aa: 0x1537, 0x8ab: 0x0b9b, 0x8ac: 0x171e, 0x8ad: 0x11e3,
+ 0x8b0: 0x06df, 0x8b1: 0x07e3, 0x8b2: 0x07a3, 0x8b3: 0x074b, 0x8b4: 0x078b, 0x8b5: 0x07b7,
+ 0x8b6: 0x0847, 0x8b7: 0x0863, 0x8b8: 0x094b, 0x8b9: 0x0937, 0x8ba: 0x0947, 0x8bb: 0x0963,
+ 0x8bc: 0x09af, 0x8bd: 0x09bf, 0x8be: 0x0a03, 0x8bf: 0x0a0f,
+ // Block 0x23, offset 0x8c0
+ 0x8c0: 0x0a2b, 0x8c1: 0x0a3b, 0x8c2: 0x0b23, 0x8c3: 0x0b2b, 0x8c4: 0x0b5b, 0x8c5: 0x0b7b,
+ 0x8c6: 0x0bab, 0x8c7: 0x0bc3, 0x8c8: 0x0bb3, 0x8c9: 0x0bd3, 0x8ca: 0x0bc7, 0x8cb: 0x0beb,
+ 0x8cc: 0x0c07, 0x8cd: 0x0c5f, 0x8ce: 0x0c6b, 0x8cf: 0x0c73, 0x8d0: 0x0c9b, 0x8d1: 0x0cdf,
+ 0x8d2: 0x0d0f, 0x8d3: 0x0d13, 0x8d4: 0x0d27, 0x8d5: 0x0da7, 0x8d6: 0x0db7, 0x8d7: 0x0e0f,
+ 0x8d8: 0x0e5b, 0x8d9: 0x0e53, 0x8da: 0x0e67, 0x8db: 0x0e83, 0x8dc: 0x0ebb, 0x8dd: 0x1013,
+ 0x8de: 0x0edf, 0x8df: 0x0f13, 0x8e0: 0x0f1f, 0x8e1: 0x0f5f, 0x8e2: 0x0f7b, 0x8e3: 0x0f9f,
+ 0x8e4: 0x0fc3, 0x8e5: 0x0fc7, 0x8e6: 0x0fe3, 0x8e7: 0x0fe7, 0x8e8: 0x0ff7, 0x8e9: 0x100b,
+ 0x8ea: 0x1007, 0x8eb: 0x1037, 0x8ec: 0x10b3, 0x8ed: 0x10cb, 0x8ee: 0x10e3, 0x8ef: 0x111b,
+ 0x8f0: 0x112f, 0x8f1: 0x114b, 0x8f2: 0x117b, 0x8f3: 0x122f, 0x8f4: 0x1257, 0x8f5: 0x12cb,
+ 0x8f6: 0x1313, 0x8f7: 0x131f, 0x8f8: 0x1327, 0x8f9: 0x133f, 0x8fa: 0x1353, 0x8fb: 0x1343,
+ 0x8fc: 0x135b, 0x8fd: 0x1357, 0x8fe: 0x134f, 0x8ff: 0x135f,
+ // Block 0x24, offset 0x900
+ 0x900: 0x136b, 0x901: 0x13a7, 0x902: 0x13e3, 0x903: 0x1413, 0x904: 0x144b, 0x905: 0x146b,
+ 0x906: 0x14b7, 0x907: 0x14db, 0x908: 0x14fb, 0x909: 0x150f, 0x90a: 0x151f, 0x90b: 0x152b,
+ 0x90c: 0x1537, 0x90d: 0x158b, 0x90e: 0x162b, 0x90f: 0x16b5, 0x910: 0x16b0, 0x911: 0x16e2,
+ 0x912: 0x0607, 0x913: 0x062f, 0x914: 0x0633, 0x915: 0x1764, 0x916: 0x1791, 0x917: 0x1809,
+ 0x918: 0x1617, 0x919: 0x1627,
+ // Block 0x25, offset 0x940
+ 0x940: 0x06fb, 0x941: 0x06f3, 0x942: 0x0703, 0x943: 0x1647, 0x944: 0x0747, 0x945: 0x0757,
+ 0x946: 0x075b, 0x947: 0x0763, 0x948: 0x076b, 0x949: 0x076f, 0x94a: 0x077b, 0x94b: 0x0773,
+ 0x94c: 0x05b3, 0x94d: 0x165b, 0x94e: 0x078f, 0x94f: 0x0793, 0x950: 0x0797, 0x951: 0x07b3,
+ 0x952: 0x164c, 0x953: 0x05b7, 0x954: 0x079f, 0x955: 0x07bf, 0x956: 0x1656, 0x957: 0x07cf,
+ 0x958: 0x07d7, 0x959: 0x0737, 0x95a: 0x07df, 0x95b: 0x07e3, 0x95c: 0x1831, 0x95d: 0x07ff,
+ 0x95e: 0x0807, 0x95f: 0x05bf, 0x960: 0x081f, 0x961: 0x0823, 0x962: 0x082b, 0x963: 0x082f,
+ 0x964: 0x05c3, 0x965: 0x0847, 0x966: 0x084b, 0x967: 0x0857, 0x968: 0x0863, 0x969: 0x0867,
+ 0x96a: 0x086b, 0x96b: 0x0873, 0x96c: 0x0893, 0x96d: 0x0897, 0x96e: 0x089f, 0x96f: 0x08af,
+ 0x970: 0x08b7, 0x971: 0x08bb, 0x972: 0x08bb, 0x973: 0x08bb, 0x974: 0x166a, 0x975: 0x0e93,
+ 0x976: 0x08cf, 0x977: 0x08d7, 0x978: 0x166f, 0x979: 0x08e3, 0x97a: 0x08eb, 0x97b: 0x08f3,
+ 0x97c: 0x091b, 0x97d: 0x0907, 0x97e: 0x0913, 0x97f: 0x0917,
+ // Block 0x26, offset 0x980
+ 0x980: 0x091f, 0x981: 0x0927, 0x982: 0x092b, 0x983: 0x0933, 0x984: 0x093b, 0x985: 0x093f,
+ 0x986: 0x093f, 0x987: 0x0947, 0x988: 0x094f, 0x989: 0x0953, 0x98a: 0x095f, 0x98b: 0x0983,
+ 0x98c: 0x0967, 0x98d: 0x0987, 0x98e: 0x096b, 0x98f: 0x0973, 0x990: 0x080b, 0x991: 0x09cf,
+ 0x992: 0x0997, 0x993: 0x099b, 0x994: 0x099f, 0x995: 0x0993, 0x996: 0x09a7, 0x997: 0x09a3,
+ 0x998: 0x09bb, 0x999: 0x1674, 0x99a: 0x09d7, 0x99b: 0x09db, 0x99c: 0x09e3, 0x99d: 0x09ef,
+ 0x99e: 0x09f7, 0x99f: 0x0a13, 0x9a0: 0x1679, 0x9a1: 0x167e, 0x9a2: 0x0a1f, 0x9a3: 0x0a23,
+ 0x9a4: 0x0a27, 0x9a5: 0x0a1b, 0x9a6: 0x0a2f, 0x9a7: 0x05c7, 0x9a8: 0x05cb, 0x9a9: 0x0a37,
+ 0x9aa: 0x0a3f, 0x9ab: 0x0a3f, 0x9ac: 0x1683, 0x9ad: 0x0a5b, 0x9ae: 0x0a5f, 0x9af: 0x0a63,
+ 0x9b0: 0x0a6b, 0x9b1: 0x1688, 0x9b2: 0x0a73, 0x9b3: 0x0a77, 0x9b4: 0x0b4f, 0x9b5: 0x0a7f,
+ 0x9b6: 0x05cf, 0x9b7: 0x0a8b, 0x9b8: 0x0a9b, 0x9b9: 0x0aa7, 0x9ba: 0x0aa3, 0x9bb: 0x1692,
+ 0x9bc: 0x0aaf, 0x9bd: 0x1697, 0x9be: 0x0abb, 0x9bf: 0x0ab7,
+ // Block 0x27, offset 0x9c0
+ 0x9c0: 0x0abf, 0x9c1: 0x0acf, 0x9c2: 0x0ad3, 0x9c3: 0x05d3, 0x9c4: 0x0ae3, 0x9c5: 0x0aeb,
+ 0x9c6: 0x0aef, 0x9c7: 0x0af3, 0x9c8: 0x05d7, 0x9c9: 0x169c, 0x9ca: 0x05db, 0x9cb: 0x0b0f,
+ 0x9cc: 0x0b13, 0x9cd: 0x0b17, 0x9ce: 0x0b1f, 0x9cf: 0x1863, 0x9d0: 0x0b37, 0x9d1: 0x16a6,
+ 0x9d2: 0x16a6, 0x9d3: 0x11d7, 0x9d4: 0x0b47, 0x9d5: 0x0b47, 0x9d6: 0x05df, 0x9d7: 0x16c9,
+ 0x9d8: 0x179b, 0x9d9: 0x0b57, 0x9da: 0x0b5f, 0x9db: 0x05e3, 0x9dc: 0x0b73, 0x9dd: 0x0b83,
+ 0x9de: 0x0b87, 0x9df: 0x0b8f, 0x9e0: 0x0b9f, 0x9e1: 0x05eb, 0x9e2: 0x05e7, 0x9e3: 0x0ba3,
+ 0x9e4: 0x16ab, 0x9e5: 0x0ba7, 0x9e6: 0x0bbb, 0x9e7: 0x0bbf, 0x9e8: 0x0bc3, 0x9e9: 0x0bbf,
+ 0x9ea: 0x0bcf, 0x9eb: 0x0bd3, 0x9ec: 0x0be3, 0x9ed: 0x0bdb, 0x9ee: 0x0bdf, 0x9ef: 0x0be7,
+ 0x9f0: 0x0beb, 0x9f1: 0x0bef, 0x9f2: 0x0bfb, 0x9f3: 0x0bff, 0x9f4: 0x0c17, 0x9f5: 0x0c1f,
+ 0x9f6: 0x0c2f, 0x9f7: 0x0c43, 0x9f8: 0x16ba, 0x9f9: 0x0c3f, 0x9fa: 0x0c33, 0x9fb: 0x0c4b,
+ 0x9fc: 0x0c53, 0x9fd: 0x0c67, 0x9fe: 0x16bf, 0x9ff: 0x0c6f,
+ // Block 0x28, offset 0xa00
+ 0xa00: 0x0c63, 0xa01: 0x0c5b, 0xa02: 0x05ef, 0xa03: 0x0c77, 0xa04: 0x0c7f, 0xa05: 0x0c87,
+ 0xa06: 0x0c7b, 0xa07: 0x05f3, 0xa08: 0x0c97, 0xa09: 0x0c9f, 0xa0a: 0x16c4, 0xa0b: 0x0ccb,
+ 0xa0c: 0x0cff, 0xa0d: 0x0cdb, 0xa0e: 0x05ff, 0xa0f: 0x0ce7, 0xa10: 0x05fb, 0xa11: 0x05f7,
+ 0xa12: 0x07c3, 0xa13: 0x07c7, 0xa14: 0x0d03, 0xa15: 0x0ceb, 0xa16: 0x11ab, 0xa17: 0x0663,
+ 0xa18: 0x0d0f, 0xa19: 0x0d13, 0xa1a: 0x0d17, 0xa1b: 0x0d2b, 0xa1c: 0x0d23, 0xa1d: 0x16dd,
+ 0xa1e: 0x0603, 0xa1f: 0x0d3f, 0xa20: 0x0d33, 0xa21: 0x0d4f, 0xa22: 0x0d57, 0xa23: 0x16e7,
+ 0xa24: 0x0d5b, 0xa25: 0x0d47, 0xa26: 0x0d63, 0xa27: 0x0607, 0xa28: 0x0d67, 0xa29: 0x0d6b,
+ 0xa2a: 0x0d6f, 0xa2b: 0x0d7b, 0xa2c: 0x16ec, 0xa2d: 0x0d83, 0xa2e: 0x060b, 0xa2f: 0x0d8f,
+ 0xa30: 0x16f1, 0xa31: 0x0d93, 0xa32: 0x060f, 0xa33: 0x0d9f, 0xa34: 0x0dab, 0xa35: 0x0db7,
+ 0xa36: 0x0dbb, 0xa37: 0x16f6, 0xa38: 0x168d, 0xa39: 0x16fb, 0xa3a: 0x0ddb, 0xa3b: 0x1700,
+ 0xa3c: 0x0de7, 0xa3d: 0x0def, 0xa3e: 0x0ddf, 0xa3f: 0x0dfb,
+ // Block 0x29, offset 0xa40
+ 0xa40: 0x0e0b, 0xa41: 0x0e1b, 0xa42: 0x0e0f, 0xa43: 0x0e13, 0xa44: 0x0e1f, 0xa45: 0x0e23,
+ 0xa46: 0x1705, 0xa47: 0x0e07, 0xa48: 0x0e3b, 0xa49: 0x0e3f, 0xa4a: 0x0613, 0xa4b: 0x0e53,
+ 0xa4c: 0x0e4f, 0xa4d: 0x170a, 0xa4e: 0x0e33, 0xa4f: 0x0e6f, 0xa50: 0x170f, 0xa51: 0x1714,
+ 0xa52: 0x0e73, 0xa53: 0x0e87, 0xa54: 0x0e83, 0xa55: 0x0e7f, 0xa56: 0x0617, 0xa57: 0x0e8b,
+ 0xa58: 0x0e9b, 0xa59: 0x0e97, 0xa5a: 0x0ea3, 0xa5b: 0x1651, 0xa5c: 0x0eb3, 0xa5d: 0x1719,
+ 0xa5e: 0x0ebf, 0xa5f: 0x1723, 0xa60: 0x0ed3, 0xa61: 0x0edf, 0xa62: 0x0ef3, 0xa63: 0x1728,
+ 0xa64: 0x0f07, 0xa65: 0x0f0b, 0xa66: 0x172d, 0xa67: 0x1732, 0xa68: 0x0f27, 0xa69: 0x0f37,
+ 0xa6a: 0x061b, 0xa6b: 0x0f3b, 0xa6c: 0x061f, 0xa6d: 0x061f, 0xa6e: 0x0f53, 0xa6f: 0x0f57,
+ 0xa70: 0x0f5f, 0xa71: 0x0f63, 0xa72: 0x0f6f, 0xa73: 0x0623, 0xa74: 0x0f87, 0xa75: 0x1737,
+ 0xa76: 0x0fa3, 0xa77: 0x173c, 0xa78: 0x0faf, 0xa79: 0x16a1, 0xa7a: 0x0fbf, 0xa7b: 0x1741,
+ 0xa7c: 0x1746, 0xa7d: 0x174b, 0xa7e: 0x0627, 0xa7f: 0x062b,
+ // Block 0x2a, offset 0xa80
+ 0xa80: 0x0ff7, 0xa81: 0x1755, 0xa82: 0x1750, 0xa83: 0x175a, 0xa84: 0x175f, 0xa85: 0x0fff,
+ 0xa86: 0x1003, 0xa87: 0x1003, 0xa88: 0x100b, 0xa89: 0x0633, 0xa8a: 0x100f, 0xa8b: 0x0637,
+ 0xa8c: 0x063b, 0xa8d: 0x1769, 0xa8e: 0x1023, 0xa8f: 0x102b, 0xa90: 0x1037, 0xa91: 0x063f,
+ 0xa92: 0x176e, 0xa93: 0x105b, 0xa94: 0x1773, 0xa95: 0x1778, 0xa96: 0x107b, 0xa97: 0x1093,
+ 0xa98: 0x0643, 0xa99: 0x109b, 0xa9a: 0x109f, 0xa9b: 0x10a3, 0xa9c: 0x177d, 0xa9d: 0x1782,
+ 0xa9e: 0x1782, 0xa9f: 0x10bb, 0xaa0: 0x0647, 0xaa1: 0x1787, 0xaa2: 0x10cf, 0xaa3: 0x10d3,
+ 0xaa4: 0x064b, 0xaa5: 0x178c, 0xaa6: 0x10ef, 0xaa7: 0x064f, 0xaa8: 0x10ff, 0xaa9: 0x10f7,
+ 0xaaa: 0x1107, 0xaab: 0x1796, 0xaac: 0x111f, 0xaad: 0x0653, 0xaae: 0x112b, 0xaaf: 0x1133,
+ 0xab0: 0x1143, 0xab1: 0x0657, 0xab2: 0x17a0, 0xab3: 0x17a5, 0xab4: 0x065b, 0xab5: 0x17aa,
+ 0xab6: 0x115b, 0xab7: 0x17af, 0xab8: 0x1167, 0xab9: 0x1173, 0xaba: 0x117b, 0xabb: 0x17b4,
+ 0xabc: 0x17b9, 0xabd: 0x118f, 0xabe: 0x17be, 0xabf: 0x1197,
+ // Block 0x2b, offset 0xac0
+ 0xac0: 0x16ce, 0xac1: 0x065f, 0xac2: 0x11af, 0xac3: 0x11b3, 0xac4: 0x0667, 0xac5: 0x11b7,
+ 0xac6: 0x0a33, 0xac7: 0x17c3, 0xac8: 0x17c8, 0xac9: 0x16d3, 0xaca: 0x16d8, 0xacb: 0x11d7,
+ 0xacc: 0x11db, 0xacd: 0x13f3, 0xace: 0x066b, 0xacf: 0x1207, 0xad0: 0x1203, 0xad1: 0x120b,
+ 0xad2: 0x083f, 0xad3: 0x120f, 0xad4: 0x1213, 0xad5: 0x1217, 0xad6: 0x121f, 0xad7: 0x17cd,
+ 0xad8: 0x121b, 0xad9: 0x1223, 0xada: 0x1237, 0xadb: 0x123b, 0xadc: 0x1227, 0xadd: 0x123f,
+ 0xade: 0x1253, 0xadf: 0x1267, 0xae0: 0x1233, 0xae1: 0x1247, 0xae2: 0x124b, 0xae3: 0x124f,
+ 0xae4: 0x17d2, 0xae5: 0x17dc, 0xae6: 0x17d7, 0xae7: 0x066f, 0xae8: 0x126f, 0xae9: 0x1273,
+ 0xaea: 0x127b, 0xaeb: 0x17f0, 0xaec: 0x127f, 0xaed: 0x17e1, 0xaee: 0x0673, 0xaef: 0x0677,
+ 0xaf0: 0x17e6, 0xaf1: 0x17eb, 0xaf2: 0x067b, 0xaf3: 0x129f, 0xaf4: 0x12a3, 0xaf5: 0x12a7,
+ 0xaf6: 0x12ab, 0xaf7: 0x12b7, 0xaf8: 0x12b3, 0xaf9: 0x12bf, 0xafa: 0x12bb, 0xafb: 0x12cb,
+ 0xafc: 0x12c3, 0xafd: 0x12c7, 0xafe: 0x12cf, 0xaff: 0x067f,
+ // Block 0x2c, offset 0xb00
+ 0xb00: 0x12d7, 0xb01: 0x12db, 0xb02: 0x0683, 0xb03: 0x12eb, 0xb04: 0x12ef, 0xb05: 0x17f5,
+ 0xb06: 0x12fb, 0xb07: 0x12ff, 0xb08: 0x0687, 0xb09: 0x130b, 0xb0a: 0x05bb, 0xb0b: 0x17fa,
+ 0xb0c: 0x17ff, 0xb0d: 0x068b, 0xb0e: 0x068f, 0xb0f: 0x1337, 0xb10: 0x134f, 0xb11: 0x136b,
+ 0xb12: 0x137b, 0xb13: 0x1804, 0xb14: 0x138f, 0xb15: 0x1393, 0xb16: 0x13ab, 0xb17: 0x13b7,
+ 0xb18: 0x180e, 0xb19: 0x1660, 0xb1a: 0x13c3, 0xb1b: 0x13bf, 0xb1c: 0x13cb, 0xb1d: 0x1665,
+ 0xb1e: 0x13d7, 0xb1f: 0x13e3, 0xb20: 0x1813, 0xb21: 0x1818, 0xb22: 0x1423, 0xb23: 0x142f,
+ 0xb24: 0x1437, 0xb25: 0x181d, 0xb26: 0x143b, 0xb27: 0x1467, 0xb28: 0x1473, 0xb29: 0x1477,
+ 0xb2a: 0x146f, 0xb2b: 0x1483, 0xb2c: 0x1487, 0xb2d: 0x1822, 0xb2e: 0x1493, 0xb2f: 0x0693,
+ 0xb30: 0x149b, 0xb31: 0x1827, 0xb32: 0x0697, 0xb33: 0x14d3, 0xb34: 0x0ac3, 0xb35: 0x14eb,
+ 0xb36: 0x182c, 0xb37: 0x1836, 0xb38: 0x069b, 0xb39: 0x069f, 0xb3a: 0x1513, 0xb3b: 0x183b,
+ 0xb3c: 0x06a3, 0xb3d: 0x1840, 0xb3e: 0x152b, 0xb3f: 0x152b,
+ // Block 0x2d, offset 0xb40
+ 0xb40: 0x1533, 0xb41: 0x1845, 0xb42: 0x154b, 0xb43: 0x06a7, 0xb44: 0x155b, 0xb45: 0x1567,
+ 0xb46: 0x156f, 0xb47: 0x1577, 0xb48: 0x06ab, 0xb49: 0x184a, 0xb4a: 0x158b, 0xb4b: 0x15a7,
+ 0xb4c: 0x15b3, 0xb4d: 0x06af, 0xb4e: 0x06b3, 0xb4f: 0x15b7, 0xb50: 0x184f, 0xb51: 0x06b7,
+ 0xb52: 0x1854, 0xb53: 0x1859, 0xb54: 0x185e, 0xb55: 0x15db, 0xb56: 0x06bb, 0xb57: 0x15ef,
+ 0xb58: 0x15f7, 0xb59: 0x15fb, 0xb5a: 0x1603, 0xb5b: 0x160b, 0xb5c: 0x1613, 0xb5d: 0x1868,
+}
+
+// nfcIndex: 22 blocks, 1408 entries, 1408 bytes
+// Block 0 is the zero block.
+var nfcIndex = [1408]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04,
+ 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30,
+ 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33,
+ 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38,
+ 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+ 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
+ 0xf0: 0x13,
+ // Block 0x4, offset 0x100
+ 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f,
+ 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46,
+ 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c,
+ 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54,
+ // Block 0x5, offset 0x140
+ 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a,
+ 0x14d: 0x5b,
+ 0x15c: 0x5c, 0x15f: 0x5d,
+ 0x162: 0x5e, 0x164: 0x5f,
+ 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65,
+ 0x170: 0x66, 0x173: 0x67, 0x177: 0x68,
+ 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15,
+ // Block 0x6, offset 0x180
+ 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d,
+ 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70,
+ 0x1ab: 0x71,
+ 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, 0x1c4: 0x76, 0x1c5: 0x77,
+ 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a,
+ // Block 0x8, offset 0x200
+ 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d,
+ 0x220: 0x7e, 0x223: 0x7f, 0x224: 0x80, 0x225: 0x81, 0x226: 0x82, 0x227: 0x83,
+ 0x22a: 0x84, 0x22b: 0x85, 0x22f: 0x86,
+ 0x230: 0x87, 0x231: 0x88, 0x232: 0x89, 0x233: 0x8a, 0x234: 0x8b, 0x235: 0x8c, 0x236: 0x8d, 0x237: 0x87,
+ 0x238: 0x88, 0x239: 0x89, 0x23a: 0x8a, 0x23b: 0x8b, 0x23c: 0x8c, 0x23d: 0x8d, 0x23e: 0x87, 0x23f: 0x88,
+ // Block 0x9, offset 0x240
+ 0x240: 0x89, 0x241: 0x8a, 0x242: 0x8b, 0x243: 0x8c, 0x244: 0x8d, 0x245: 0x87, 0x246: 0x88, 0x247: 0x89,
+ 0x248: 0x8a, 0x249: 0x8b, 0x24a: 0x8c, 0x24b: 0x8d, 0x24c: 0x87, 0x24d: 0x88, 0x24e: 0x89, 0x24f: 0x8a,
+ 0x250: 0x8b, 0x251: 0x8c, 0x252: 0x8d, 0x253: 0x87, 0x254: 0x88, 0x255: 0x89, 0x256: 0x8a, 0x257: 0x8b,
+ 0x258: 0x8c, 0x259: 0x8d, 0x25a: 0x87, 0x25b: 0x88, 0x25c: 0x89, 0x25d: 0x8a, 0x25e: 0x8b, 0x25f: 0x8c,
+ 0x260: 0x8d, 0x261: 0x87, 0x262: 0x88, 0x263: 0x89, 0x264: 0x8a, 0x265: 0x8b, 0x266: 0x8c, 0x267: 0x8d,
+ 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26c: 0x8b, 0x26d: 0x8c, 0x26e: 0x8d, 0x26f: 0x87,
+ 0x270: 0x88, 0x271: 0x89, 0x272: 0x8a, 0x273: 0x8b, 0x274: 0x8c, 0x275: 0x8d, 0x276: 0x87, 0x277: 0x88,
+ 0x278: 0x89, 0x279: 0x8a, 0x27a: 0x8b, 0x27b: 0x8c, 0x27c: 0x8d, 0x27d: 0x87, 0x27e: 0x88, 0x27f: 0x89,
+ // Block 0xa, offset 0x280
+ 0x280: 0x8a, 0x281: 0x8b, 0x282: 0x8c, 0x283: 0x8d, 0x284: 0x87, 0x285: 0x88, 0x286: 0x89, 0x287: 0x8a,
+ 0x288: 0x8b, 0x289: 0x8c, 0x28a: 0x8d, 0x28b: 0x87, 0x28c: 0x88, 0x28d: 0x89, 0x28e: 0x8a, 0x28f: 0x8b,
+ 0x290: 0x8c, 0x291: 0x8d, 0x292: 0x87, 0x293: 0x88, 0x294: 0x89, 0x295: 0x8a, 0x296: 0x8b, 0x297: 0x8c,
+ 0x298: 0x8d, 0x299: 0x87, 0x29a: 0x88, 0x29b: 0x89, 0x29c: 0x8a, 0x29d: 0x8b, 0x29e: 0x8c, 0x29f: 0x8d,
+ 0x2a0: 0x87, 0x2a1: 0x88, 0x2a2: 0x89, 0x2a3: 0x8a, 0x2a4: 0x8b, 0x2a5: 0x8c, 0x2a6: 0x8d, 0x2a7: 0x87,
+ 0x2a8: 0x88, 0x2a9: 0x89, 0x2aa: 0x8a, 0x2ab: 0x8b, 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x87, 0x2af: 0x88,
+ 0x2b0: 0x89, 0x2b1: 0x8a, 0x2b2: 0x8b, 0x2b3: 0x8c, 0x2b4: 0x8d, 0x2b5: 0x87, 0x2b6: 0x88, 0x2b7: 0x89,
+ 0x2b8: 0x8a, 0x2b9: 0x8b, 0x2ba: 0x8c, 0x2bb: 0x8d, 0x2bc: 0x87, 0x2bd: 0x88, 0x2be: 0x89, 0x2bf: 0x8a,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x8b, 0x2c1: 0x8c, 0x2c2: 0x8d, 0x2c3: 0x87, 0x2c4: 0x88, 0x2c5: 0x89, 0x2c6: 0x8a, 0x2c7: 0x8b,
+ 0x2c8: 0x8c, 0x2c9: 0x8d, 0x2ca: 0x87, 0x2cb: 0x88, 0x2cc: 0x89, 0x2cd: 0x8a, 0x2ce: 0x8b, 0x2cf: 0x8c,
+ 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d,
+ 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e,
+ // Block 0xc, offset 0x300
+ 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e,
+ 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91,
+ 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95,
+ 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b,
+ // Block 0xd, offset 0x340
+ 0x347: 0x9c,
+ 0x34b: 0x9d, 0x34d: 0x9e,
+ 0x368: 0x9f, 0x36b: 0xa0,
+ // Block 0xe, offset 0x380
+ 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4,
+ 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3e, 0x38d: 0xa7,
+ 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac,
+ 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae,
+ 0x3b0: 0x73,
+ // Block 0xf, offset 0x3c0
+ 0x3eb: 0xaf, 0x3ec: 0xb0,
+ // Block 0x10, offset 0x400
+ 0x432: 0xb1,
+ // Block 0x11, offset 0x440
+ 0x445: 0xb2, 0x446: 0xb3, 0x447: 0xb4,
+ 0x449: 0xb5,
+ // Block 0x12, offset 0x480
+ 0x480: 0xb6,
+ 0x4a3: 0xb7, 0x4a5: 0xb8,
+ // Block 0x13, offset 0x4c0
+ 0x4c8: 0xb9,
+ // Block 0x14, offset 0x500
+ 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a,
+ 0x528: 0x2b,
+ // Block 0x15, offset 0x540
+ 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
+ 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
+ 0x56f: 0x12,
+}
+
+// nfcSparseOffset: 142 entries, 284 bytes
+var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc7, 0xce, 0xd6, 0xd9, 0xdb, 0xdd, 0xdf, 0xe4, 0xf5, 0x101, 0x103, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x118, 0x11b, 0x11d, 0x120, 0x123, 0x127, 0x12c, 0x135, 0x137, 0x13a, 0x13c, 0x147, 0x157, 0x15b, 0x169, 0x16c, 0x172, 0x178, 0x183, 0x187, 0x189, 0x18b, 0x18d, 0x18f, 0x191, 0x197, 0x19b, 0x19d, 0x19f, 0x1a7, 0x1ab, 0x1ae, 0x1b0, 0x1b2, 0x1b4, 0x1b7, 0x1b9, 0x1bb, 0x1bd, 0x1bf, 0x1c5, 0x1c8, 0x1ca, 0x1d1, 0x1d7, 0x1dd, 0x1e5, 0x1eb, 0x1f1, 0x1f7, 0x1fb, 0x209, 0x212, 0x215, 0x218, 0x21a, 0x21d, 0x21f, 0x223, 0x228, 0x22a, 0x22c, 0x231, 0x237, 0x239, 0x23b, 0x23d, 0x243, 0x246, 0x249, 0x251, 0x258, 0x25b, 0x25e, 0x260, 0x268, 0x26b, 0x272, 0x275, 0x27b, 0x27d, 0x280, 0x282, 0x284, 0x286, 0x288, 0x295, 0x29f, 0x2a1, 0x2a3, 0x2a9, 0x2ab, 0x2ae}
+
+// nfcSparseValues: 688 entries, 2752 bytes
+var nfcSparseValues = [688]valueRange{
+ // Block 0x0, offset 0x0
+ {value: 0x0000, lo: 0x04},
+ {value: 0xa100, lo: 0xa8, hi: 0xa8},
+ {value: 0x8100, lo: 0xaf, hi: 0xaf},
+ {value: 0x8100, lo: 0xb4, hi: 0xb4},
+ {value: 0x8100, lo: 0xb8, hi: 0xb8},
+ // Block 0x1, offset 0x5
+ {value: 0x0091, lo: 0x03},
+ {value: 0x4778, lo: 0xa0, hi: 0xa1},
+ {value: 0x47aa, lo: 0xaf, hi: 0xb0},
+ {value: 0xa000, lo: 0xb7, hi: 0xb7},
+ // Block 0x2, offset 0x9
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ // Block 0x3, offset 0xb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x98, hi: 0x9d},
+ // Block 0x4, offset 0xd
+ {value: 0x0006, lo: 0x0a},
+ {value: 0xa000, lo: 0x81, hi: 0x81},
+ {value: 0xa000, lo: 0x85, hi: 0x85},
+ {value: 0xa000, lo: 0x89, hi: 0x89},
+ {value: 0x48d6, lo: 0x8a, hi: 0x8a},
+ {value: 0x48f4, lo: 0x8b, hi: 0x8b},
+ {value: 0x36c7, lo: 0x8c, hi: 0x8c},
+ {value: 0x36df, lo: 0x8d, hi: 0x8d},
+ {value: 0x490c, lo: 0x8e, hi: 0x8e},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x36fd, lo: 0x93, hi: 0x94},
+ // Block 0x5, offset 0x18
+ {value: 0x0000, lo: 0x0f},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0xa000, lo: 0x8d, hi: 0x8d},
+ {value: 0x37a5, lo: 0x90, hi: 0x90},
+ {value: 0x37b1, lo: 0x91, hi: 0x91},
+ {value: 0x379f, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x96, hi: 0x96},
+ {value: 0x3817, lo: 0x97, hi: 0x97},
+ {value: 0x37e1, lo: 0x9c, hi: 0x9c},
+ {value: 0x37c9, lo: 0x9d, hi: 0x9d},
+ {value: 0x37f3, lo: 0x9e, hi: 0x9e},
+ {value: 0xa000, lo: 0xb4, hi: 0xb5},
+ {value: 0x381d, lo: 0xb6, hi: 0xb6},
+ {value: 0x3823, lo: 0xb7, hi: 0xb7},
+ // Block 0x6, offset 0x28
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x83, hi: 0x87},
+ // Block 0x7, offset 0x2a
+ {value: 0x0001, lo: 0x04},
+ {value: 0x8113, lo: 0x81, hi: 0x82},
+ {value: 0x8132, lo: 0x84, hi: 0x84},
+ {value: 0x812d, lo: 0x85, hi: 0x85},
+ {value: 0x810d, lo: 0x87, hi: 0x87},
+ // Block 0x8, offset 0x2f
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x97},
+ {value: 0x8119, lo: 0x98, hi: 0x98},
+ {value: 0x811a, lo: 0x99, hi: 0x99},
+ {value: 0x811b, lo: 0x9a, hi: 0x9a},
+ {value: 0x3841, lo: 0xa2, hi: 0xa2},
+ {value: 0x3847, lo: 0xa3, hi: 0xa3},
+ {value: 0x3853, lo: 0xa4, hi: 0xa4},
+ {value: 0x384d, lo: 0xa5, hi: 0xa5},
+ {value: 0x3859, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xa7, hi: 0xa7},
+ // Block 0x9, offset 0x3a
+ {value: 0x0000, lo: 0x0e},
+ {value: 0x386b, lo: 0x80, hi: 0x80},
+ {value: 0xa000, lo: 0x81, hi: 0x81},
+ {value: 0x385f, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x3865, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x95, hi: 0x95},
+ {value: 0x8132, lo: 0x96, hi: 0x9c},
+ {value: 0x8132, lo: 0x9f, hi: 0xa2},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa4},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xaa, hi: 0xaa},
+ {value: 0x8132, lo: 0xab, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ // Block 0xa, offset 0x49
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x811f, lo: 0x91, hi: 0x91},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x812d, lo: 0xb1, hi: 0xb1},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb5, hi: 0xb6},
+ {value: 0x812d, lo: 0xb7, hi: 0xb9},
+ {value: 0x8132, lo: 0xba, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbc},
+ {value: 0x8132, lo: 0xbd, hi: 0xbd},
+ {value: 0x812d, lo: 0xbe, hi: 0xbe},
+ {value: 0x8132, lo: 0xbf, hi: 0xbf},
+ // Block 0xb, offset 0x56
+ {value: 0x0005, lo: 0x07},
+ {value: 0x8132, lo: 0x80, hi: 0x80},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x83},
+ {value: 0x812d, lo: 0x84, hi: 0x85},
+ {value: 0x812d, lo: 0x86, hi: 0x87},
+ {value: 0x812d, lo: 0x88, hi: 0x89},
+ {value: 0x8132, lo: 0x8a, hi: 0x8a},
+ // Block 0xc, offset 0x5e
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xab, hi: 0xb1},
+ {value: 0x812d, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb3},
+ // Block 0xd, offset 0x62
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0x96, hi: 0x99},
+ {value: 0x8132, lo: 0x9b, hi: 0xa3},
+ {value: 0x8132, lo: 0xa5, hi: 0xa7},
+ {value: 0x8132, lo: 0xa9, hi: 0xad},
+ // Block 0xe, offset 0x67
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x99, hi: 0x9b},
+ // Block 0xf, offset 0x69
+ {value: 0x0000, lo: 0x10},
+ {value: 0x8132, lo: 0x94, hi: 0xa1},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8132, lo: 0xaa, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xaf},
+ {value: 0x8116, lo: 0xb0, hi: 0xb0},
+ {value: 0x8117, lo: 0xb1, hi: 0xb1},
+ {value: 0x8118, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb5},
+ {value: 0x812d, lo: 0xb6, hi: 0xb6},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x812d, lo: 0xb9, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbf},
+ // Block 0x10, offset 0x7a
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0xa8, hi: 0xa8},
+ {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
+ {value: 0xa000, lo: 0xb0, hi: 0xb0},
+ {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
+ {value: 0xa000, lo: 0xb3, hi: 0xb3},
+ {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
+ {value: 0x9902, lo: 0xbc, hi: 0xbc},
+ // Block 0x11, offset 0x82
+ {value: 0x0008, lo: 0x06},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x91, hi: 0x91},
+ {value: 0x812d, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x93, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x94},
+ {value: 0x45b2, lo: 0x98, hi: 0x9f},
+ // Block 0x12, offset 0x89
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x13, offset 0x8c
+ {value: 0x0008, lo: 0x06},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2c9e, lo: 0x8b, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x45f2, lo: 0x9c, hi: 0x9d},
+ {value: 0x4602, lo: 0x9f, hi: 0x9f},
+ // Block 0x14, offset 0x93
+ {value: 0x0000, lo: 0x03},
+ {value: 0x462a, lo: 0xb3, hi: 0xb3},
+ {value: 0x4632, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x15, offset 0x97
+ {value: 0x0008, lo: 0x03},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x460a, lo: 0x99, hi: 0x9b},
+ {value: 0x4622, lo: 0x9e, hi: 0x9e},
+ // Block 0x16, offset 0x9b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x17, offset 0x9d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ // Block 0x18, offset 0x9f
+ {value: 0x0000, lo: 0x08},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2cb6, lo: 0x88, hi: 0x88},
+ {value: 0x2cae, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cbe, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x96, hi: 0x97},
+ {value: 0x463a, lo: 0x9c, hi: 0x9c},
+ {value: 0x4642, lo: 0x9d, hi: 0x9d},
+ // Block 0x19, offset 0xa8
+ {value: 0x0000, lo: 0x03},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x2cc6, lo: 0x94, hi: 0x94},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1a, offset 0xac
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cce, lo: 0x8a, hi: 0x8a},
+ {value: 0x2cde, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1b, offset 0xb3
+ {value: 0x1801, lo: 0x04},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x3ef0, lo: 0x88, hi: 0x88},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8120, lo: 0x95, hi: 0x96},
+ // Block 0x1c, offset 0xb8
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0xa000, lo: 0xbf, hi: 0xbf},
+ // Block 0x1d, offset 0xbb
+ {value: 0x0000, lo: 0x09},
+ {value: 0x2ce6, lo: 0x80, hi: 0x80},
+ {value: 0x9900, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x2cee, lo: 0x87, hi: 0x87},
+ {value: 0x2cf6, lo: 0x88, hi: 0x88},
+ {value: 0x2f50, lo: 0x8a, hi: 0x8a},
+ {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x95, hi: 0x96},
+ // Block 0x1e, offset 0xc5
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1f, offset 0xc7
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
+ {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d06, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x20, offset 0xce
+ {value: 0x6bea, lo: 0x07},
+ {value: 0x9904, lo: 0x8a, hi: 0x8a},
+ {value: 0x9900, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
+ {value: 0x2f58, lo: 0x9c, hi: 0x9c},
+ {value: 0x2de3, lo: 0x9d, hi: 0x9d},
+ {value: 0x2d16, lo: 0x9e, hi: 0x9f},
+ // Block 0x21, offset 0xd6
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8122, lo: 0xb8, hi: 0xb9},
+ {value: 0x8104, lo: 0xba, hi: 0xba},
+ // Block 0x22, offset 0xd9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8123, lo: 0x88, hi: 0x8b},
+ // Block 0x23, offset 0xdb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8124, lo: 0xb8, hi: 0xb9},
+ // Block 0x24, offset 0xdd
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8125, lo: 0x88, hi: 0x8b},
+ // Block 0x25, offset 0xdf
+ {value: 0x0000, lo: 0x04},
+ {value: 0x812d, lo: 0x98, hi: 0x99},
+ {value: 0x812d, lo: 0xb5, hi: 0xb5},
+ {value: 0x812d, lo: 0xb7, hi: 0xb7},
+ {value: 0x812b, lo: 0xb9, hi: 0xb9},
+ // Block 0x26, offset 0xe4
+ {value: 0x0000, lo: 0x10},
+ {value: 0x2644, lo: 0x83, hi: 0x83},
+ {value: 0x264b, lo: 0x8d, hi: 0x8d},
+ {value: 0x2652, lo: 0x92, hi: 0x92},
+ {value: 0x2659, lo: 0x97, hi: 0x97},
+ {value: 0x2660, lo: 0x9c, hi: 0x9c},
+ {value: 0x263d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8126, lo: 0xb1, hi: 0xb1},
+ {value: 0x8127, lo: 0xb2, hi: 0xb2},
+ {value: 0x4a66, lo: 0xb3, hi: 0xb3},
+ {value: 0x8128, lo: 0xb4, hi: 0xb4},
+ {value: 0x4a6f, lo: 0xb5, hi: 0xb5},
+ {value: 0x464a, lo: 0xb6, hi: 0xb6},
+ {value: 0x8200, lo: 0xb7, hi: 0xb7},
+ {value: 0x4652, lo: 0xb8, hi: 0xb8},
+ {value: 0x8200, lo: 0xb9, hi: 0xb9},
+ {value: 0x8127, lo: 0xba, hi: 0xbd},
+ // Block 0x27, offset 0xf5
+ {value: 0x0000, lo: 0x0b},
+ {value: 0x8127, lo: 0x80, hi: 0x80},
+ {value: 0x4a78, lo: 0x81, hi: 0x81},
+ {value: 0x8132, lo: 0x82, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0x86, hi: 0x87},
+ {value: 0x266e, lo: 0x93, hi: 0x93},
+ {value: 0x2675, lo: 0x9d, hi: 0x9d},
+ {value: 0x267c, lo: 0xa2, hi: 0xa2},
+ {value: 0x2683, lo: 0xa7, hi: 0xa7},
+ {value: 0x268a, lo: 0xac, hi: 0xac},
+ {value: 0x2667, lo: 0xb9, hi: 0xb9},
+ // Block 0x28, offset 0x101
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x86, hi: 0x86},
+ // Block 0x29, offset 0x103
+ {value: 0x0000, lo: 0x05},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
+ {value: 0x9900, lo: 0xae, hi: 0xae},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x2a, offset 0x109
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ // Block 0x2b, offset 0x10b
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x80, hi: 0x92},
+ // Block 0x2c, offset 0x10d
+ {value: 0x0000, lo: 0x01},
+ {value: 0xb900, lo: 0xa1, hi: 0xb5},
+ // Block 0x2d, offset 0x10f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xa8, hi: 0xbf},
+ // Block 0x2e, offset 0x111
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0x80, hi: 0x82},
+ // Block 0x2f, offset 0x113
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9d, hi: 0x9f},
+ // Block 0x30, offset 0x115
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x94, hi: 0x94},
+ {value: 0x8104, lo: 0xb4, hi: 0xb4},
+ // Block 0x31, offset 0x118
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x9d, hi: 0x9d},
+ // Block 0x32, offset 0x11b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8131, lo: 0xa9, hi: 0xa9},
+ // Block 0x33, offset 0x11d
+ {value: 0x0004, lo: 0x02},
+ {value: 0x812e, lo: 0xb9, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbb},
+ // Block 0x34, offset 0x120
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x97, hi: 0x97},
+ {value: 0x812d, lo: 0x98, hi: 0x98},
+ // Block 0x35, offset 0x123
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8104, lo: 0xa0, hi: 0xa0},
+ {value: 0x8132, lo: 0xb5, hi: 0xbc},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x36, offset 0x127
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ {value: 0x812d, lo: 0xb5, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x37, offset 0x12c
+ {value: 0x0000, lo: 0x08},
+ {value: 0x2d66, lo: 0x80, hi: 0x80},
+ {value: 0x2d6e, lo: 0x81, hi: 0x81},
+ {value: 0xa000, lo: 0x82, hi: 0x82},
+ {value: 0x2d76, lo: 0x83, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xab, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xac},
+ {value: 0x8132, lo: 0xad, hi: 0xb3},
+ // Block 0x38, offset 0x135
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xaa, hi: 0xab},
+ // Block 0x39, offset 0x137
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xa6, hi: 0xa6},
+ {value: 0x8104, lo: 0xb2, hi: 0xb3},
+ // Block 0x3a, offset 0x13a
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x3b, offset 0x13c
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x92},
+ {value: 0x8101, lo: 0x94, hi: 0x94},
+ {value: 0x812d, lo: 0x95, hi: 0x99},
+ {value: 0x8132, lo: 0x9a, hi: 0x9b},
+ {value: 0x812d, lo: 0x9c, hi: 0x9f},
+ {value: 0x8132, lo: 0xa0, hi: 0xa0},
+ {value: 0x8101, lo: 0xa2, hi: 0xa8},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ {value: 0x8132, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb8, hi: 0xb9},
+ // Block 0x3c, offset 0x147
+ {value: 0x0000, lo: 0x0f},
+ {value: 0x8132, lo: 0x80, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x82},
+ {value: 0x8132, lo: 0x83, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8a},
+ {value: 0x8132, lo: 0x8b, hi: 0x8c},
+ {value: 0x8135, lo: 0x8d, hi: 0x8d},
+ {value: 0x812a, lo: 0x8e, hi: 0x8e},
+ {value: 0x812d, lo: 0x8f, hi: 0x8f},
+ {value: 0x8129, lo: 0x90, hi: 0x90},
+ {value: 0x8132, lo: 0x91, hi: 0xb5},
+ {value: 0x8132, lo: 0xbb, hi: 0xbb},
+ {value: 0x8134, lo: 0xbc, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ {value: 0x8132, lo: 0xbe, hi: 0xbe},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x3d, offset 0x157
+ {value: 0x0004, lo: 0x03},
+ {value: 0x0433, lo: 0x80, hi: 0x81},
+ {value: 0x8100, lo: 0x97, hi: 0x97},
+ {value: 0x8100, lo: 0xbe, hi: 0xbe},
+ // Block 0x3e, offset 0x15b
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x8132, lo: 0x90, hi: 0x91},
+ {value: 0x8101, lo: 0x92, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x97},
+ {value: 0x8101, lo: 0x98, hi: 0x9a},
+ {value: 0x8132, lo: 0x9b, hi: 0x9c},
+ {value: 0x8132, lo: 0xa1, hi: 0xa1},
+ {value: 0x8101, lo: 0xa5, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa7},
+ {value: 0x812d, lo: 0xa8, hi: 0xa8},
+ {value: 0x8132, lo: 0xa9, hi: 0xa9},
+ {value: 0x8101, lo: 0xaa, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xaf},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ // Block 0x3f, offset 0x169
+ {value: 0x427b, lo: 0x02},
+ {value: 0x01b8, lo: 0xa6, hi: 0xa6},
+ {value: 0x0057, lo: 0xaa, hi: 0xab},
+ // Block 0x40, offset 0x16c
+ {value: 0x0007, lo: 0x05},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
+ {value: 0x3bc7, lo: 0xae, hi: 0xae},
+ // Block 0x41, offset 0x172
+ {value: 0x000e, lo: 0x05},
+ {value: 0x3bce, lo: 0x8d, hi: 0x8e},
+ {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ // Block 0x42, offset 0x178
+ {value: 0x6408, lo: 0x0a},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0x3be3, lo: 0x84, hi: 0x84},
+ {value: 0xa000, lo: 0x88, hi: 0x88},
+ {value: 0x3bea, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
+ {value: 0xa000, lo: 0xa3, hi: 0xa3},
+ {value: 0x3bf8, lo: 0xa4, hi: 0xa5},
+ {value: 0x3bff, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xbc, hi: 0xbc},
+ // Block 0x43, offset 0x183
+ {value: 0x0007, lo: 0x03},
+ {value: 0x3c68, lo: 0xa0, hi: 0xa1},
+ {value: 0x3c92, lo: 0xa2, hi: 0xa3},
+ {value: 0x3cbc, lo: 0xaa, hi: 0xad},
+ // Block 0x44, offset 0x187
+ {value: 0x0004, lo: 0x01},
+ {value: 0x048b, lo: 0xa9, hi: 0xaa},
+ // Block 0x45, offset 0x189
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4573, lo: 0x9c, hi: 0x9c},
+ // Block 0x46, offset 0x18b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xaf, hi: 0xb1},
+ // Block 0x47, offset 0x18d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x48, offset 0x18f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xa0, hi: 0xbf},
+ // Block 0x49, offset 0x191
+ {value: 0x0000, lo: 0x05},
+ {value: 0x812c, lo: 0xaa, hi: 0xaa},
+ {value: 0x8131, lo: 0xab, hi: 0xab},
+ {value: 0x8133, lo: 0xac, hi: 0xac},
+ {value: 0x812e, lo: 0xad, hi: 0xad},
+ {value: 0x812f, lo: 0xae, hi: 0xaf},
+ // Block 0x4a, offset 0x197
+ {value: 0x0000, lo: 0x03},
+ {value: 0x4a81, lo: 0xb3, hi: 0xb3},
+ {value: 0x4a81, lo: 0xb5, hi: 0xb6},
+ {value: 0x4a81, lo: 0xba, hi: 0xbf},
+ // Block 0x4b, offset 0x19b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4a81, lo: 0x8f, hi: 0xa3},
+ // Block 0x4c, offset 0x19d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0xae, hi: 0xbe},
+ // Block 0x4d, offset 0x19f
+ {value: 0x0000, lo: 0x07},
+ {value: 0x8100, lo: 0x84, hi: 0x84},
+ {value: 0x8100, lo: 0x87, hi: 0x87},
+ {value: 0x8100, lo: 0x90, hi: 0x90},
+ {value: 0x8100, lo: 0x9e, hi: 0x9e},
+ {value: 0x8100, lo: 0xa1, hi: 0xa1},
+ {value: 0x8100, lo: 0xb2, hi: 0xb2},
+ {value: 0x8100, lo: 0xbb, hi: 0xbb},
+ // Block 0x4e, offset 0x1a7
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8100, lo: 0x80, hi: 0x80},
+ {value: 0x8100, lo: 0x8b, hi: 0x8b},
+ {value: 0x8100, lo: 0x8e, hi: 0x8e},
+ // Block 0x4f, offset 0x1ab
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xaf, hi: 0xaf},
+ {value: 0x8132, lo: 0xb4, hi: 0xbd},
+ // Block 0x50, offset 0x1ae
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9e, hi: 0x9f},
+ // Block 0x51, offset 0x1b0
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb1},
+ // Block 0x52, offset 0x1b2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ // Block 0x53, offset 0x1b4
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xa0, hi: 0xb1},
+ // Block 0x54, offset 0x1b7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xab, hi: 0xad},
+ // Block 0x55, offset 0x1b9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x93, hi: 0x93},
+ // Block 0x56, offset 0x1bb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb3, hi: 0xb3},
+ // Block 0x57, offset 0x1bd
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ // Block 0x58, offset 0x1bf
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x8132, lo: 0xbe, hi: 0xbf},
+ // Block 0x59, offset 0x1c5
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ // Block 0x5a, offset 0x1c8
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xad, hi: 0xad},
+ // Block 0x5b, offset 0x1ca
+ {value: 0x0000, lo: 0x06},
+ {value: 0xe500, lo: 0x80, hi: 0x80},
+ {value: 0xc600, lo: 0x81, hi: 0x9b},
+ {value: 0xe500, lo: 0x9c, hi: 0x9c},
+ {value: 0xc600, lo: 0x9d, hi: 0xb7},
+ {value: 0xe500, lo: 0xb8, hi: 0xb8},
+ {value: 0xc600, lo: 0xb9, hi: 0xbf},
+ // Block 0x5c, offset 0x1d1
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x93},
+ {value: 0xe500, lo: 0x94, hi: 0x94},
+ {value: 0xc600, lo: 0x95, hi: 0xaf},
+ {value: 0xe500, lo: 0xb0, hi: 0xb0},
+ {value: 0xc600, lo: 0xb1, hi: 0xbf},
+ // Block 0x5d, offset 0x1d7
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8b},
+ {value: 0xe500, lo: 0x8c, hi: 0x8c},
+ {value: 0xc600, lo: 0x8d, hi: 0xa7},
+ {value: 0xe500, lo: 0xa8, hi: 0xa8},
+ {value: 0xc600, lo: 0xa9, hi: 0xbf},
+ // Block 0x5e, offset 0x1dd
+ {value: 0x0000, lo: 0x07},
+ {value: 0xc600, lo: 0x80, hi: 0x83},
+ {value: 0xe500, lo: 0x84, hi: 0x84},
+ {value: 0xc600, lo: 0x85, hi: 0x9f},
+ {value: 0xe500, lo: 0xa0, hi: 0xa0},
+ {value: 0xc600, lo: 0xa1, hi: 0xbb},
+ {value: 0xe500, lo: 0xbc, hi: 0xbc},
+ {value: 0xc600, lo: 0xbd, hi: 0xbf},
+ // Block 0x5f, offset 0x1e5
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x97},
+ {value: 0xe500, lo: 0x98, hi: 0x98},
+ {value: 0xc600, lo: 0x99, hi: 0xb3},
+ {value: 0xe500, lo: 0xb4, hi: 0xb4},
+ {value: 0xc600, lo: 0xb5, hi: 0xbf},
+ // Block 0x60, offset 0x1eb
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8f},
+ {value: 0xe500, lo: 0x90, hi: 0x90},
+ {value: 0xc600, lo: 0x91, hi: 0xab},
+ {value: 0xe500, lo: 0xac, hi: 0xac},
+ {value: 0xc600, lo: 0xad, hi: 0xbf},
+ // Block 0x61, offset 0x1f1
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ {value: 0xe500, lo: 0xa4, hi: 0xa4},
+ {value: 0xc600, lo: 0xa5, hi: 0xbf},
+ // Block 0x62, offset 0x1f7
+ {value: 0x0000, lo: 0x03},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ // Block 0x63, offset 0x1fb
+ {value: 0x0006, lo: 0x0d},
+ {value: 0x4426, lo: 0x9d, hi: 0x9d},
+ {value: 0x8115, lo: 0x9e, hi: 0x9e},
+ {value: 0x4498, lo: 0x9f, hi: 0x9f},
+ {value: 0x4486, lo: 0xaa, hi: 0xab},
+ {value: 0x458a, lo: 0xac, hi: 0xac},
+ {value: 0x4592, lo: 0xad, hi: 0xad},
+ {value: 0x43de, lo: 0xae, hi: 0xb1},
+ {value: 0x43fc, lo: 0xb2, hi: 0xb4},
+ {value: 0x4414, lo: 0xb5, hi: 0xb6},
+ {value: 0x4420, lo: 0xb8, hi: 0xb8},
+ {value: 0x442c, lo: 0xb9, hi: 0xbb},
+ {value: 0x4444, lo: 0xbc, hi: 0xbc},
+ {value: 0x444a, lo: 0xbe, hi: 0xbe},
+ // Block 0x64, offset 0x209
+ {value: 0x0006, lo: 0x08},
+ {value: 0x4450, lo: 0x80, hi: 0x81},
+ {value: 0x445c, lo: 0x83, hi: 0x84},
+ {value: 0x446e, lo: 0x86, hi: 0x89},
+ {value: 0x4492, lo: 0x8a, hi: 0x8a},
+ {value: 0x440e, lo: 0x8b, hi: 0x8b},
+ {value: 0x43f6, lo: 0x8c, hi: 0x8c},
+ {value: 0x443e, lo: 0x8d, hi: 0x8d},
+ {value: 0x4468, lo: 0x8e, hi: 0x8e},
+ // Block 0x65, offset 0x212
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0xa4, hi: 0xa5},
+ {value: 0x8100, lo: 0xb0, hi: 0xb1},
+ // Block 0x66, offset 0x215
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0x9b, hi: 0x9d},
+ {value: 0x8200, lo: 0x9e, hi: 0xa3},
+ // Block 0x67, offset 0x218
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x90, hi: 0x90},
+ // Block 0x68, offset 0x21a
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0x99, hi: 0x99},
+ {value: 0x8200, lo: 0xb2, hi: 0xb4},
+ // Block 0x69, offset 0x21d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0xbc, hi: 0xbd},
+ // Block 0x6a, offset 0x21f
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xa0, hi: 0xa6},
+ {value: 0x812d, lo: 0xa7, hi: 0xad},
+ {value: 0x8132, lo: 0xae, hi: 0xaf},
+ // Block 0x6b, offset 0x223
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8100, lo: 0x89, hi: 0x8c},
+ {value: 0x8100, lo: 0xb0, hi: 0xb2},
+ {value: 0x8100, lo: 0xb4, hi: 0xb4},
+ {value: 0x8100, lo: 0xb6, hi: 0xbf},
+ // Block 0x6c, offset 0x228
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x81, hi: 0x8c},
+ // Block 0x6d, offset 0x22a
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0xb5, hi: 0xba},
+ // Block 0x6e, offset 0x22c
+ {value: 0x0000, lo: 0x04},
+ {value: 0x4a81, lo: 0x9e, hi: 0x9f},
+ {value: 0x4a81, lo: 0xa3, hi: 0xa3},
+ {value: 0x4a81, lo: 0xa5, hi: 0xa6},
+ {value: 0x4a81, lo: 0xaa, hi: 0xaf},
+ // Block 0x6f, offset 0x231
+ {value: 0x0000, lo: 0x05},
+ {value: 0x4a81, lo: 0x82, hi: 0x87},
+ {value: 0x4a81, lo: 0x8a, hi: 0x8f},
+ {value: 0x4a81, lo: 0x92, hi: 0x97},
+ {value: 0x4a81, lo: 0x9a, hi: 0x9c},
+ {value: 0x8100, lo: 0xa3, hi: 0xa3},
+ // Block 0x70, offset 0x237
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x71, offset 0x239
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xa0, hi: 0xa0},
+ // Block 0x72, offset 0x23b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb6, hi: 0xba},
+ // Block 0x73, offset 0x23d
+ {value: 0x002c, lo: 0x05},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x8f, hi: 0x8f},
+ {value: 0x8132, lo: 0xb8, hi: 0xb8},
+ {value: 0x8101, lo: 0xb9, hi: 0xba},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x74, offset 0x243
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xa5, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ // Block 0x75, offset 0x246
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x76, offset 0x249
+ {value: 0x17fe, lo: 0x07},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x4238, lo: 0x9a, hi: 0x9a},
+ {value: 0xa000, lo: 0x9b, hi: 0x9b},
+ {value: 0x4242, lo: 0x9c, hi: 0x9c},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x424c, lo: 0xab, hi: 0xab},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x77, offset 0x251
+ {value: 0x0000, lo: 0x06},
+ {value: 0x8132, lo: 0x80, hi: 0x82},
+ {value: 0x9900, lo: 0xa7, hi: 0xa7},
+ {value: 0x2d7e, lo: 0xae, hi: 0xae},
+ {value: 0x2d88, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb1, hi: 0xb2},
+ {value: 0x8104, lo: 0xb3, hi: 0xb4},
+ // Block 0x78, offset 0x258
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x79, offset 0x25b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb5, hi: 0xb5},
+ {value: 0x8102, lo: 0xb6, hi: 0xb6},
+ // Block 0x7a, offset 0x25e
+ {value: 0x0002, lo: 0x01},
+ {value: 0x8102, lo: 0xa9, hi: 0xaa},
+ // Block 0x7b, offset 0x260
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2d92, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x8132, lo: 0xa6, hi: 0xac},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ // Block 0x7c, offset 0x268
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x86, hi: 0x86},
+ // Block 0x7d, offset 0x26b
+ {value: 0x6b5a, lo: 0x06},
+ {value: 0x9900, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xb9, hi: 0xb9},
+ {value: 0x9900, lo: 0xba, hi: 0xba},
+ {value: 0x2db0, lo: 0xbb, hi: 0xbb},
+ {value: 0x2da6, lo: 0xbc, hi: 0xbd},
+ {value: 0x2dba, lo: 0xbe, hi: 0xbe},
+ // Block 0x7e, offset 0x272
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x83, hi: 0x83},
+ // Block 0x7f, offset 0x275
+ {value: 0x0000, lo: 0x05},
+ {value: 0x9900, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb8, hi: 0xb9},
+ {value: 0x2dc4, lo: 0xba, hi: 0xba},
+ {value: 0x2dce, lo: 0xbb, hi: 0xbb},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x80, offset 0x27b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0x80, hi: 0x80},
+ // Block 0x81, offset 0x27d
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x82, offset 0x280
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xab, hi: 0xab},
+ // Block 0x83, offset 0x282
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0xb0, hi: 0xb4},
+ // Block 0x84, offset 0x284
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb6},
+ // Block 0x85, offset 0x286
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0x9e, hi: 0x9e},
+ // Block 0x86, offset 0x288
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x4662, lo: 0x9e, hi: 0x9e},
+ {value: 0x466c, lo: 0x9f, hi: 0x9f},
+ {value: 0x46a0, lo: 0xa0, hi: 0xa0},
+ {value: 0x46ae, lo: 0xa1, hi: 0xa1},
+ {value: 0x46bc, lo: 0xa2, hi: 0xa2},
+ {value: 0x46ca, lo: 0xa3, hi: 0xa3},
+ {value: 0x46d8, lo: 0xa4, hi: 0xa4},
+ {value: 0x812b, lo: 0xa5, hi: 0xa6},
+ {value: 0x8101, lo: 0xa7, hi: 0xa9},
+ {value: 0x8130, lo: 0xad, hi: 0xad},
+ {value: 0x812b, lo: 0xae, hi: 0xb2},
+ {value: 0x812d, lo: 0xbb, hi: 0xbf},
+ // Block 0x87, offset 0x295
+ {value: 0x0000, lo: 0x09},
+ {value: 0x812d, lo: 0x80, hi: 0x82},
+ {value: 0x8132, lo: 0x85, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8b},
+ {value: 0x8132, lo: 0xaa, hi: 0xad},
+ {value: 0x4676, lo: 0xbb, hi: 0xbb},
+ {value: 0x4680, lo: 0xbc, hi: 0xbc},
+ {value: 0x46e6, lo: 0xbd, hi: 0xbd},
+ {value: 0x4702, lo: 0xbe, hi: 0xbe},
+ {value: 0x46f4, lo: 0xbf, hi: 0xbf},
+ // Block 0x88, offset 0x29f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4710, lo: 0x80, hi: 0x80},
+ // Block 0x89, offset 0x2a1
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x82, hi: 0x84},
+ // Block 0x8a, offset 0x2a3
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0x80, hi: 0x86},
+ {value: 0x8132, lo: 0x88, hi: 0x98},
+ {value: 0x8132, lo: 0x9b, hi: 0xa1},
+ {value: 0x8132, lo: 0xa3, hi: 0xa4},
+ {value: 0x8132, lo: 0xa6, hi: 0xaa},
+ // Block 0x8b, offset 0x2a9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x90, hi: 0x96},
+ // Block 0x8c, offset 0x2ab
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x84, hi: 0x89},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x8d, offset 0x2ae
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x93, hi: 0x93},
+}
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *nfkcTrie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfkcValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfkcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfkcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = nfkcIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *nfkcTrie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfkcValues[c0]
+ }
+ i := nfkcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *nfkcTrie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfkcValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfkcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := nfkcIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = nfkcIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = nfkcIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfkcValues[c0]
+ }
+ i := nfkcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: 146925fc21092b17.
+type nfkcTrie struct{}
+
+func newNfkcTrie(i int) *nfkcTrie {
+ return &nfkcTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 {
+ switch {
+ case n < 90:
+ return uint16(nfkcValues[n<<6+uint32(b)])
+ default:
+ n -= 90
+ return uint16(nfkcSparse.lookup(n, b))
+ }
+}
+
+// nfkcValues: 92 blocks, 5888 entries, 11776 bytes
+// The third block is the zero block.
+var nfkcValues = [5888]uint16{
+ // Block 0x0, offset 0x0
+ 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
+ // Block 0x1, offset 0x40
+ 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
+ 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
+ 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
+ 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
+ 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
+ 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
+ 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
+ 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
+ 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
+ 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
+ 0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
+ 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
+ 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
+ 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
+ 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
+ 0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
+ 0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
+ 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
+ 0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
+ 0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
+ // Block 0x4, offset 0x100
+ 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
+ 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
+ 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
+ 0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
+ 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
+ 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
+ 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
+ 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
+ 0x130: 0x308c, 0x132: 0x195d, 0x133: 0x19e7, 0x134: 0x30b4, 0x135: 0x33c0,
+ 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
+ 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, 0x13f: 0x1bac,
+ // Block 0x5, offset 0x140
+ 0x140: 0x1c34, 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
+ 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, 0x149: 0x1c5c,
+ 0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
+ 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
+ 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
+ 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
+ 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
+ 0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
+ 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
+ 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
+ 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0x00a7,
+ // Block 0x6, offset 0x180
+ 0x184: 0x2dee, 0x185: 0x2df4,
+ 0x186: 0x2dfa, 0x187: 0x1972, 0x188: 0x1975, 0x189: 0x1a08, 0x18a: 0x1987, 0x18b: 0x198a,
+ 0x18c: 0x1a3e, 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
+ 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
+ 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
+ 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
+ 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
+ 0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
+ 0x1b0: 0x33c5, 0x1b1: 0x1942, 0x1b2: 0x1945, 0x1b3: 0x19cf, 0x1b4: 0x3028, 0x1b5: 0x3334,
+ 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
+ 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
+ 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
+ 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
+ 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
+ 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
+ 0x1de: 0x305a, 0x1df: 0x3366,
+ 0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
+ 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
+ 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
+ // Block 0x8, offset 0x200
+ 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
+ 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
+ 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
+ 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
+ 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
+ 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
+ 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
+ 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
+ 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
+ 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
+ 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
+ // Block 0x9, offset 0x240
+ 0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
+ 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
+ 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
+ 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
+ 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
+ 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
+ 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
+ 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
+ 0x274: 0x0170,
+ 0x27a: 0x42a5,
+ 0x27e: 0x0037,
+ // Block 0xa, offset 0x280
+ 0x284: 0x425a, 0x285: 0x4511,
+ 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625,
+ 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000,
+ 0x295: 0xa000, 0x297: 0xa000,
+ 0x299: 0xa000,
+ 0x29f: 0xa000, 0x2a1: 0xa000,
+ 0x2a5: 0xa000, 0x2a9: 0xa000,
+ 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
+ 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
+ 0x2b7: 0xa000, 0x2b9: 0xa000,
+ 0x2bf: 0xa000,
+ // Block 0xb, offset 0x2c0
+ 0x2c1: 0xa000, 0x2c5: 0xa000,
+ 0x2c9: 0xa000, 0x2ca: 0x48d6, 0x2cb: 0x48f4,
+ 0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x490c, 0x2d0: 0x01be, 0x2d1: 0x01d0,
+ 0x2d2: 0x01ac, 0x2d3: 0x43a2, 0x2d4: 0x43a8, 0x2d5: 0x01fa, 0x2d6: 0x01e8,
+ 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7,
+ 0x2f9: 0x01a6,
+ // Block 0xc, offset 0x300
+ 0x300: 0x3721, 0x301: 0x372d, 0x303: 0x371b,
+ 0x306: 0xa000, 0x307: 0x3709,
+ 0x30c: 0x375d, 0x30d: 0x3745, 0x30e: 0x376f, 0x310: 0xa000,
+ 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000,
+ 0x318: 0xa000, 0x319: 0x3751, 0x31a: 0xa000,
+ 0x31e: 0xa000, 0x323: 0xa000,
+ 0x327: 0xa000,
+ 0x32b: 0xa000, 0x32d: 0xa000,
+ 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000,
+ 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x37d5, 0x33a: 0xa000,
+ 0x33e: 0xa000,
+ // Block 0xd, offset 0x340
+ 0x341: 0x3733, 0x342: 0x37b7,
+ 0x350: 0x370f, 0x351: 0x3793,
+ 0x352: 0x3715, 0x353: 0x3799, 0x356: 0x3727, 0x357: 0x37ab,
+ 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3829, 0x35b: 0x382f, 0x35c: 0x3739, 0x35d: 0x37bd,
+ 0x35e: 0x373f, 0x35f: 0x37c3, 0x362: 0x374b, 0x363: 0x37cf,
+ 0x364: 0x3757, 0x365: 0x37db, 0x366: 0x3763, 0x367: 0x37e7, 0x368: 0xa000, 0x369: 0xa000,
+ 0x36a: 0x3835, 0x36b: 0x383b, 0x36c: 0x378d, 0x36d: 0x3811, 0x36e: 0x3769, 0x36f: 0x37ed,
+ 0x370: 0x3775, 0x371: 0x37f9, 0x372: 0x377b, 0x373: 0x37ff, 0x374: 0x3781, 0x375: 0x3805,
+ 0x378: 0x3787, 0x379: 0x380b,
+ // Block 0xe, offset 0x380
+ 0x387: 0x1d61,
+ 0x391: 0x812d,
+ 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132,
+ 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132,
+ 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d,
+ 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132,
+ 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132,
+ 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a,
+ 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f,
+ 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112,
+ // Block 0xf, offset 0x3c0
+ 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116,
+ 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c,
+ 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132,
+ 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132,
+ 0x3de: 0x8132, 0x3df: 0x812d,
+ 0x3f0: 0x811e, 0x3f5: 0x1d84,
+ 0x3f6: 0x2013, 0x3f7: 0x204f, 0x3f8: 0x204a,
+ // Block 0x10, offset 0x400
+ 0x405: 0xa000,
+ 0x406: 0x2d26, 0x407: 0xa000, 0x408: 0x2d2e, 0x409: 0xa000, 0x40a: 0x2d36, 0x40b: 0xa000,
+ 0x40c: 0x2d3e, 0x40d: 0xa000, 0x40e: 0x2d46, 0x411: 0xa000,
+ 0x412: 0x2d4e,
+ 0x434: 0x8102, 0x435: 0x9900,
+ 0x43a: 0xa000, 0x43b: 0x2d56,
+ 0x43c: 0xa000, 0x43d: 0x2d5e, 0x43e: 0xa000, 0x43f: 0xa000,
+ // Block 0x11, offset 0x440
+ 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8,
+ 0x446: 0x0413, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107,
+ 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0,
+ 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x0417, 0x455: 0x041b, 0x456: 0x00a1, 0x457: 0x00a9,
+ 0x458: 0x00ab, 0x459: 0x0423, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x0427, 0x45d: 0x01be,
+ 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5,
+ 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa,
+ 0x46a: 0x01fd,
+ 0x478: 0x020c,
+ // Block 0x12, offset 0x480
+ 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101,
+ 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116,
+ 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x042b, 0x4a8: 0x016a, 0x4a9: 0x0128,
+ 0x4aa: 0x042f, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137,
+ 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec,
+ 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5,
+ 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0,
+ // Block 0x13, offset 0x4c0
+ 0x4c0: 0x2f97, 0x4c1: 0x32a3, 0x4c2: 0x2fa1, 0x4c3: 0x32ad, 0x4c4: 0x2fa6, 0x4c5: 0x32b2,
+ 0x4c6: 0x2fab, 0x4c7: 0x32b7, 0x4c8: 0x38cc, 0x4c9: 0x3a5b, 0x4ca: 0x2fc4, 0x4cb: 0x32d0,
+ 0x4cc: 0x2fce, 0x4cd: 0x32da, 0x4ce: 0x2fdd, 0x4cf: 0x32e9, 0x4d0: 0x2fd3, 0x4d1: 0x32df,
+ 0x4d2: 0x2fd8, 0x4d3: 0x32e4, 0x4d4: 0x38ef, 0x4d5: 0x3a7e, 0x4d6: 0x38f6, 0x4d7: 0x3a85,
+ 0x4d8: 0x3019, 0x4d9: 0x3325, 0x4da: 0x301e, 0x4db: 0x332a, 0x4dc: 0x3904, 0x4dd: 0x3a93,
+ 0x4de: 0x3023, 0x4df: 0x332f, 0x4e0: 0x3032, 0x4e1: 0x333e, 0x4e2: 0x3050, 0x4e3: 0x335c,
+ 0x4e4: 0x305f, 0x4e5: 0x336b, 0x4e6: 0x3055, 0x4e7: 0x3361, 0x4e8: 0x3064, 0x4e9: 0x3370,
+ 0x4ea: 0x3069, 0x4eb: 0x3375, 0x4ec: 0x30af, 0x4ed: 0x33bb, 0x4ee: 0x390b, 0x4ef: 0x3a9a,
+ 0x4f0: 0x30b9, 0x4f1: 0x33ca, 0x4f2: 0x30c3, 0x4f3: 0x33d4, 0x4f4: 0x30cd, 0x4f5: 0x33de,
+ 0x4f6: 0x475a, 0x4f7: 0x47eb, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7,
+ 0x4fc: 0x30e1, 0x4fd: 0x33f2, 0x4fe: 0x30eb, 0x4ff: 0x33fc,
+ // Block 0x14, offset 0x500
+ 0x500: 0x30f0, 0x501: 0x3401, 0x502: 0x30f5, 0x503: 0x3406, 0x504: 0x3109, 0x505: 0x341a,
+ 0x506: 0x3113, 0x507: 0x3424, 0x508: 0x3122, 0x509: 0x3433, 0x50a: 0x311d, 0x50b: 0x342e,
+ 0x50c: 0x3935, 0x50d: 0x3ac4, 0x50e: 0x3943, 0x50f: 0x3ad2, 0x510: 0x394a, 0x511: 0x3ad9,
+ 0x512: 0x3951, 0x513: 0x3ae0, 0x514: 0x314f, 0x515: 0x3460, 0x516: 0x3154, 0x517: 0x3465,
+ 0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x4787, 0x51b: 0x4818, 0x51c: 0x3997, 0x51d: 0x3b26,
+ 0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4796, 0x523: 0x4827,
+ 0x524: 0x399e, 0x525: 0x3b2d, 0x526: 0x39a5, 0x527: 0x3b34, 0x528: 0x39ac, 0x529: 0x3b3b,
+ 0x52a: 0x3190, 0x52b: 0x34a1, 0x52c: 0x319a, 0x52d: 0x34b0, 0x52e: 0x31ae, 0x52f: 0x34c4,
+ 0x530: 0x31a9, 0x531: 0x34bf, 0x532: 0x31ea, 0x533: 0x3500, 0x534: 0x31f9, 0x535: 0x350f,
+ 0x536: 0x31f4, 0x537: 0x350a, 0x538: 0x39b3, 0x539: 0x3b42, 0x53a: 0x39ba, 0x53b: 0x3b49,
+ 0x53c: 0x31fe, 0x53d: 0x3514, 0x53e: 0x3203, 0x53f: 0x3519,
+ // Block 0x15, offset 0x540
+ 0x540: 0x3208, 0x541: 0x351e, 0x542: 0x320d, 0x543: 0x3523, 0x544: 0x321c, 0x545: 0x3532,
+ 0x546: 0x3217, 0x547: 0x352d, 0x548: 0x3221, 0x549: 0x353c, 0x54a: 0x3226, 0x54b: 0x3541,
+ 0x54c: 0x322b, 0x54d: 0x3546, 0x54e: 0x3249, 0x54f: 0x3564, 0x550: 0x3262, 0x551: 0x3582,
+ 0x552: 0x3271, 0x553: 0x3591, 0x554: 0x3276, 0x555: 0x3596, 0x556: 0x337a, 0x557: 0x34a6,
+ 0x558: 0x3537, 0x559: 0x3573, 0x55a: 0x1be0, 0x55b: 0x42d7,
+ 0x560: 0x4737, 0x561: 0x47c8, 0x562: 0x2f83, 0x563: 0x328f,
+ 0x564: 0x3878, 0x565: 0x3a07, 0x566: 0x3871, 0x567: 0x3a00, 0x568: 0x3886, 0x569: 0x3a15,
+ 0x56a: 0x387f, 0x56b: 0x3a0e, 0x56c: 0x38be, 0x56d: 0x3a4d, 0x56e: 0x3894, 0x56f: 0x3a23,
+ 0x570: 0x388d, 0x571: 0x3a1c, 0x572: 0x38a2, 0x573: 0x3a31, 0x574: 0x389b, 0x575: 0x3a2a,
+ 0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x474b, 0x579: 0x47dc, 0x57a: 0x3000, 0x57b: 0x330c,
+ 0x57c: 0x2fec, 0x57d: 0x32f8, 0x57e: 0x38da, 0x57f: 0x3a69,
+ // Block 0x16, offset 0x580
+ 0x580: 0x38d3, 0x581: 0x3a62, 0x582: 0x38e8, 0x583: 0x3a77, 0x584: 0x38e1, 0x585: 0x3a70,
+ 0x586: 0x38fd, 0x587: 0x3a8c, 0x588: 0x3091, 0x589: 0x339d, 0x58a: 0x30a5, 0x58b: 0x33b1,
+ 0x58c: 0x477d, 0x58d: 0x480e, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf,
+ 0x592: 0x3919, 0x593: 0x3aa8, 0x594: 0x392e, 0x595: 0x3abd, 0x596: 0x3927, 0x597: 0x3ab6,
+ 0x598: 0x3989, 0x599: 0x3b18, 0x59a: 0x396d, 0x59b: 0x3afc, 0x59c: 0x3966, 0x59d: 0x3af5,
+ 0x59e: 0x397b, 0x59f: 0x3b0a, 0x5a0: 0x3974, 0x5a1: 0x3b03, 0x5a2: 0x3982, 0x5a3: 0x3b11,
+ 0x5a4: 0x31e5, 0x5a5: 0x34fb, 0x5a6: 0x31c7, 0x5a7: 0x34dd, 0x5a8: 0x39e4, 0x5a9: 0x3b73,
+ 0x5aa: 0x39dd, 0x5ab: 0x3b6c, 0x5ac: 0x39f2, 0x5ad: 0x3b81, 0x5ae: 0x39eb, 0x5af: 0x3b7a,
+ 0x5b0: 0x39f9, 0x5b1: 0x3b88, 0x5b2: 0x3230, 0x5b3: 0x354b, 0x5b4: 0x3258, 0x5b5: 0x3578,
+ 0x5b6: 0x3253, 0x5b7: 0x356e, 0x5b8: 0x323f, 0x5b9: 0x355a,
+ // Block 0x17, offset 0x5c0
+ 0x5c0: 0x489a, 0x5c1: 0x48a0, 0x5c2: 0x49b4, 0x5c3: 0x49cc, 0x5c4: 0x49bc, 0x5c5: 0x49d4,
+ 0x5c6: 0x49c4, 0x5c7: 0x49dc, 0x5c8: 0x4840, 0x5c9: 0x4846, 0x5ca: 0x4924, 0x5cb: 0x493c,
+ 0x5cc: 0x492c, 0x5cd: 0x4944, 0x5ce: 0x4934, 0x5cf: 0x494c, 0x5d0: 0x48ac, 0x5d1: 0x48b2,
+ 0x5d2: 0x3db8, 0x5d3: 0x3dc8, 0x5d4: 0x3dc0, 0x5d5: 0x3dd0,
+ 0x5d8: 0x484c, 0x5d9: 0x4852, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00,
+ 0x5e0: 0x48c4, 0x5e1: 0x48ca, 0x5e2: 0x49e4, 0x5e3: 0x49fc,
+ 0x5e4: 0x49ec, 0x5e5: 0x4a04, 0x5e6: 0x49f4, 0x5e7: 0x4a0c, 0x5e8: 0x4858, 0x5e9: 0x485e,
+ 0x5ea: 0x4954, 0x5eb: 0x496c, 0x5ec: 0x495c, 0x5ed: 0x4974, 0x5ee: 0x4964, 0x5ef: 0x497c,
+ 0x5f0: 0x48dc, 0x5f1: 0x48e2, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38,
+ 0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x4864, 0x5f9: 0x486a, 0x5fa: 0x3d18, 0x5fb: 0x3d30,
+ 0x5fc: 0x3d20, 0x5fd: 0x3d38, 0x5fe: 0x3d28, 0x5ff: 0x3d40,
+ // Block 0x18, offset 0x600
+ 0x600: 0x48e8, 0x601: 0x48ee, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60,
+ 0x608: 0x4870, 0x609: 0x4876, 0x60a: 0x3d48, 0x60b: 0x3d58,
+ 0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x48fa, 0x611: 0x4900,
+ 0x612: 0x3e80, 0x613: 0x3e98, 0x614: 0x3e88, 0x615: 0x3ea0, 0x616: 0x3e90, 0x617: 0x3ea8,
+ 0x619: 0x487c, 0x61b: 0x3d68, 0x61d: 0x3d70,
+ 0x61f: 0x3d78, 0x620: 0x4912, 0x621: 0x4918, 0x622: 0x4a14, 0x623: 0x4a2c,
+ 0x624: 0x4a1c, 0x625: 0x4a34, 0x626: 0x4a24, 0x627: 0x4a3c, 0x628: 0x4882, 0x629: 0x4888,
+ 0x62a: 0x4984, 0x62b: 0x499c, 0x62c: 0x498c, 0x62d: 0x49a4, 0x62e: 0x4994, 0x62f: 0x49ac,
+ 0x630: 0x488e, 0x631: 0x43b4, 0x632: 0x3691, 0x633: 0x43ba, 0x634: 0x48b8, 0x635: 0x43c0,
+ 0x636: 0x36a3, 0x637: 0x43c6, 0x638: 0x36c1, 0x639: 0x43cc, 0x63a: 0x36d9, 0x63b: 0x43d2,
+ 0x63c: 0x4906, 0x63d: 0x43d8,
+ // Block 0x19, offset 0x640
+ 0x640: 0x3da0, 0x641: 0x3da8, 0x642: 0x4184, 0x643: 0x41a2, 0x644: 0x418e, 0x645: 0x41ac,
+ 0x646: 0x4198, 0x647: 0x41b6, 0x648: 0x3cd8, 0x649: 0x3ce0, 0x64a: 0x40d0, 0x64b: 0x40ee,
+ 0x64c: 0x40da, 0x64d: 0x40f8, 0x64e: 0x40e4, 0x64f: 0x4102, 0x650: 0x3de8, 0x651: 0x3df0,
+ 0x652: 0x41c0, 0x653: 0x41de, 0x654: 0x41ca, 0x655: 0x41e8, 0x656: 0x41d4, 0x657: 0x41f2,
+ 0x658: 0x3d08, 0x659: 0x3d10, 0x65a: 0x410c, 0x65b: 0x412a, 0x65c: 0x4116, 0x65d: 0x4134,
+ 0x65e: 0x4120, 0x65f: 0x413e, 0x660: 0x3ec0, 0x661: 0x3ec8, 0x662: 0x41fc, 0x663: 0x421a,
+ 0x664: 0x4206, 0x665: 0x4224, 0x666: 0x4210, 0x667: 0x422e, 0x668: 0x3d80, 0x669: 0x3d88,
+ 0x66a: 0x4148, 0x66b: 0x4166, 0x66c: 0x4152, 0x66d: 0x4170, 0x66e: 0x415c, 0x66f: 0x417a,
+ 0x670: 0x3685, 0x671: 0x367f, 0x672: 0x3d90, 0x673: 0x368b, 0x674: 0x3d98,
+ 0x676: 0x48a6, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x4384,
+ 0x67c: 0x35fb, 0x67d: 0x4287, 0x67e: 0x01d3, 0x67f: 0x4287,
+ // Block 0x1a, offset 0x680
+ 0x680: 0x42a0, 0x681: 0x4518, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0,
+ 0x686: 0x48d0, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x438a, 0x68a: 0x360d, 0x68b: 0x4390,
+ 0x68c: 0x3619, 0x68d: 0x451f, 0x68e: 0x4526, 0x68f: 0x452d, 0x690: 0x36b5, 0x691: 0x36af,
+ 0x692: 0x3e00, 0x693: 0x457a, 0x696: 0x36bb, 0x697: 0x3e10,
+ 0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4396, 0x69d: 0x4534,
+ 0x69e: 0x453b, 0x69f: 0x4542, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x4582,
+ 0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b,
+ 0x6aa: 0x364f, 0x6ab: 0x43a2, 0x6ac: 0x3649, 0x6ad: 0x450a, 0x6ae: 0x4511, 0x6af: 0x0081,
+ 0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8,
+ 0x6b6: 0x491e, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x439c, 0x6ba: 0x366d, 0x6bb: 0x43ae,
+ 0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c,
+ // Block 0x1b, offset 0x6c0
+ 0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8,
+ 0x6c6: 0x1bec, 0x6c7: 0x00e9, 0x6c9: 0x1c58, 0x6ca: 0x008f, 0x6cb: 0x0051,
+ 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053,
+ 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x198d,
+ 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065,
+ 0x6e0: 0x199f, 0x6e1: 0x1bc8, 0x6e2: 0x19a8,
+ 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075,
+ 0x6ea: 0x0057, 0x6eb: 0x42d2, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b,
+ 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215,
+ 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1b98,
+ 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0,
+ // Block 0x1c, offset 0x700
+ 0x700: 0x0463, 0x705: 0x0049,
+ 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095,
+ 0x710: 0x222e, 0x711: 0x223a,
+ 0x712: 0x22ee, 0x713: 0x2216, 0x714: 0x229a, 0x715: 0x2222, 0x716: 0x22a0, 0x717: 0x22b8,
+ 0x718: 0x22c4, 0x719: 0x2228, 0x71a: 0x22ca, 0x71b: 0x2234, 0x71c: 0x22be, 0x71d: 0x22d0,
+ 0x71e: 0x22d6, 0x71f: 0x1cbc, 0x720: 0x0053, 0x721: 0x195a, 0x722: 0x1ba4, 0x723: 0x1963,
+ 0x724: 0x006d, 0x725: 0x19ab, 0x726: 0x1bd0, 0x727: 0x1d48, 0x728: 0x1966, 0x729: 0x0071,
+ 0x72a: 0x19b7, 0x72b: 0x1bd4, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b,
+ 0x730: 0x0093, 0x731: 0x19e4, 0x732: 0x1c18, 0x733: 0x19ed, 0x734: 0x00ad, 0x735: 0x1a62,
+ 0x736: 0x1c4c, 0x737: 0x1d5c, 0x738: 0x19f0, 0x739: 0x00b1, 0x73a: 0x1a65, 0x73b: 0x1c50,
+ 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b,
+ // Block 0x1d, offset 0x740
+ 0x741: 0x3c06, 0x743: 0xa000, 0x744: 0x3c0d, 0x745: 0xa000,
+ 0x747: 0x3c14, 0x748: 0xa000, 0x749: 0x3c1b,
+ 0x74d: 0xa000,
+ 0x760: 0x2f65, 0x761: 0xa000, 0x762: 0x3c29,
+ 0x764: 0xa000, 0x765: 0xa000,
+ 0x76d: 0x3c22, 0x76e: 0x2f60, 0x76f: 0x2f6a,
+ 0x770: 0x3c30, 0x771: 0x3c37, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c3e, 0x775: 0x3c45,
+ 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c4c, 0x779: 0x3c53, 0x77a: 0xa000, 0x77b: 0xa000,
+ 0x77c: 0xa000, 0x77d: 0xa000,
+ // Block 0x1e, offset 0x780
+ 0x780: 0x3c5a, 0x781: 0x3c61, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3c76, 0x785: 0x3c7d,
+ 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3c84, 0x789: 0x3c8b,
+ 0x791: 0xa000,
+ 0x792: 0xa000,
+ 0x7a2: 0xa000,
+ 0x7a8: 0xa000, 0x7a9: 0xa000,
+ 0x7ab: 0xa000, 0x7ac: 0x3ca0, 0x7ad: 0x3ca7, 0x7ae: 0x3cae, 0x7af: 0x3cb5,
+ 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000,
+ // Block 0x1f, offset 0x7c0
+ 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029,
+ 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1882,
+ 0x7ea: 0x1885, 0x7eb: 0x1888, 0x7ec: 0x188b, 0x7ed: 0x188e, 0x7ee: 0x1891, 0x7ef: 0x1894,
+ 0x7f0: 0x1897, 0x7f1: 0x189a, 0x7f2: 0x189d, 0x7f3: 0x18a6, 0x7f4: 0x1a68, 0x7f5: 0x1a6c,
+ 0x7f6: 0x1a70, 0x7f7: 0x1a74, 0x7f8: 0x1a78, 0x7f9: 0x1a7c, 0x7fa: 0x1a80, 0x7fb: 0x1a84,
+ 0x7fc: 0x1a88, 0x7fd: 0x1c80, 0x7fe: 0x1c85, 0x7ff: 0x1c8a,
+ // Block 0x20, offset 0x800
+ 0x800: 0x1c8f, 0x801: 0x1c94, 0x802: 0x1c99, 0x803: 0x1c9e, 0x804: 0x1ca3, 0x805: 0x1ca8,
+ 0x806: 0x1cad, 0x807: 0x1cb2, 0x808: 0x187f, 0x809: 0x18a3, 0x80a: 0x18c7, 0x80b: 0x18eb,
+ 0x80c: 0x190f, 0x80d: 0x1918, 0x80e: 0x191e, 0x80f: 0x1924, 0x810: 0x192a, 0x811: 0x1b60,
+ 0x812: 0x1b64, 0x813: 0x1b68, 0x814: 0x1b6c, 0x815: 0x1b70, 0x816: 0x1b74, 0x817: 0x1b78,
+ 0x818: 0x1b7c, 0x819: 0x1b80, 0x81a: 0x1b84, 0x81b: 0x1b88, 0x81c: 0x1af4, 0x81d: 0x1af8,
+ 0x81e: 0x1afc, 0x81f: 0x1b00, 0x820: 0x1b04, 0x821: 0x1b08, 0x822: 0x1b0c, 0x823: 0x1b10,
+ 0x824: 0x1b14, 0x825: 0x1b18, 0x826: 0x1b1c, 0x827: 0x1b20, 0x828: 0x1b24, 0x829: 0x1b28,
+ 0x82a: 0x1b2c, 0x82b: 0x1b30, 0x82c: 0x1b34, 0x82d: 0x1b38, 0x82e: 0x1b3c, 0x82f: 0x1b40,
+ 0x830: 0x1b44, 0x831: 0x1b48, 0x832: 0x1b4c, 0x833: 0x1b50, 0x834: 0x1b54, 0x835: 0x1b58,
+ 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d,
+ 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055,
+ // Block 0x21, offset 0x840
+ 0x840: 0x06bf, 0x841: 0x06e3, 0x842: 0x06ef, 0x843: 0x06ff, 0x844: 0x0707, 0x845: 0x0713,
+ 0x846: 0x071b, 0x847: 0x0723, 0x848: 0x072f, 0x849: 0x0783, 0x84a: 0x079b, 0x84b: 0x07ab,
+ 0x84c: 0x07bb, 0x84d: 0x07cb, 0x84e: 0x07db, 0x84f: 0x07fb, 0x850: 0x07ff, 0x851: 0x0803,
+ 0x852: 0x0837, 0x853: 0x085f, 0x854: 0x086f, 0x855: 0x0877, 0x856: 0x087b, 0x857: 0x0887,
+ 0x858: 0x08a3, 0x859: 0x08a7, 0x85a: 0x08bf, 0x85b: 0x08c3, 0x85c: 0x08cb, 0x85d: 0x08db,
+ 0x85e: 0x0977, 0x85f: 0x098b, 0x860: 0x09cb, 0x861: 0x09df, 0x862: 0x09e7, 0x863: 0x09eb,
+ 0x864: 0x09fb, 0x865: 0x0a17, 0x866: 0x0a43, 0x867: 0x0a4f, 0x868: 0x0a6f, 0x869: 0x0a7b,
+ 0x86a: 0x0a7f, 0x86b: 0x0a83, 0x86c: 0x0a9b, 0x86d: 0x0a9f, 0x86e: 0x0acb, 0x86f: 0x0ad7,
+ 0x870: 0x0adf, 0x871: 0x0ae7, 0x872: 0x0af7, 0x873: 0x0aff, 0x874: 0x0b07, 0x875: 0x0b33,
+ 0x876: 0x0b37, 0x877: 0x0b3f, 0x878: 0x0b43, 0x879: 0x0b4b, 0x87a: 0x0b53, 0x87b: 0x0b63,
+ 0x87c: 0x0b7f, 0x87d: 0x0bf7, 0x87e: 0x0c0b, 0x87f: 0x0c0f,
+ // Block 0x22, offset 0x880
+ 0x880: 0x0c8f, 0x881: 0x0c93, 0x882: 0x0ca7, 0x883: 0x0cab, 0x884: 0x0cb3, 0x885: 0x0cbb,
+ 0x886: 0x0cc3, 0x887: 0x0ccf, 0x888: 0x0cf7, 0x889: 0x0d07, 0x88a: 0x0d1b, 0x88b: 0x0d8b,
+ 0x88c: 0x0d97, 0x88d: 0x0da7, 0x88e: 0x0db3, 0x88f: 0x0dbf, 0x890: 0x0dc7, 0x891: 0x0dcb,
+ 0x892: 0x0dcf, 0x893: 0x0dd3, 0x894: 0x0dd7, 0x895: 0x0e8f, 0x896: 0x0ed7, 0x897: 0x0ee3,
+ 0x898: 0x0ee7, 0x899: 0x0eeb, 0x89a: 0x0eef, 0x89b: 0x0ef7, 0x89c: 0x0efb, 0x89d: 0x0f0f,
+ 0x89e: 0x0f2b, 0x89f: 0x0f33, 0x8a0: 0x0f73, 0x8a1: 0x0f77, 0x8a2: 0x0f7f, 0x8a3: 0x0f83,
+ 0x8a4: 0x0f8b, 0x8a5: 0x0f8f, 0x8a6: 0x0fb3, 0x8a7: 0x0fb7, 0x8a8: 0x0fd3, 0x8a9: 0x0fd7,
+ 0x8aa: 0x0fdb, 0x8ab: 0x0fdf, 0x8ac: 0x0ff3, 0x8ad: 0x1017, 0x8ae: 0x101b, 0x8af: 0x101f,
+ 0x8b0: 0x1043, 0x8b1: 0x1083, 0x8b2: 0x1087, 0x8b3: 0x10a7, 0x8b4: 0x10b7, 0x8b5: 0x10bf,
+ 0x8b6: 0x10df, 0x8b7: 0x1103, 0x8b8: 0x1147, 0x8b9: 0x114f, 0x8ba: 0x1163, 0x8bb: 0x116f,
+ 0x8bc: 0x1177, 0x8bd: 0x117f, 0x8be: 0x1183, 0x8bf: 0x1187,
+ // Block 0x23, offset 0x8c0
+ 0x8c0: 0x119f, 0x8c1: 0x11a3, 0x8c2: 0x11bf, 0x8c3: 0x11c7, 0x8c4: 0x11cf, 0x8c5: 0x11d3,
+ 0x8c6: 0x11df, 0x8c7: 0x11e7, 0x8c8: 0x11eb, 0x8c9: 0x11ef, 0x8ca: 0x11f7, 0x8cb: 0x11fb,
+ 0x8cc: 0x129b, 0x8cd: 0x12af, 0x8ce: 0x12e3, 0x8cf: 0x12e7, 0x8d0: 0x12ef, 0x8d1: 0x131b,
+ 0x8d2: 0x1323, 0x8d3: 0x132b, 0x8d4: 0x1333, 0x8d5: 0x136f, 0x8d6: 0x1373, 0x8d7: 0x137b,
+ 0x8d8: 0x137f, 0x8d9: 0x1383, 0x8da: 0x13af, 0x8db: 0x13b3, 0x8dc: 0x13bb, 0x8dd: 0x13cf,
+ 0x8de: 0x13d3, 0x8df: 0x13ef, 0x8e0: 0x13f7, 0x8e1: 0x13fb, 0x8e2: 0x141f, 0x8e3: 0x143f,
+ 0x8e4: 0x1453, 0x8e5: 0x1457, 0x8e6: 0x145f, 0x8e7: 0x148b, 0x8e8: 0x148f, 0x8e9: 0x149f,
+ 0x8ea: 0x14c3, 0x8eb: 0x14cf, 0x8ec: 0x14df, 0x8ed: 0x14f7, 0x8ee: 0x14ff, 0x8ef: 0x1503,
+ 0x8f0: 0x1507, 0x8f1: 0x150b, 0x8f2: 0x1517, 0x8f3: 0x151b, 0x8f4: 0x1523, 0x8f5: 0x153f,
+ 0x8f6: 0x1543, 0x8f7: 0x1547, 0x8f8: 0x155f, 0x8f9: 0x1563, 0x8fa: 0x156b, 0x8fb: 0x157f,
+ 0x8fc: 0x1583, 0x8fd: 0x1587, 0x8fe: 0x158f, 0x8ff: 0x1593,
+ // Block 0x24, offset 0x900
+ 0x906: 0xa000, 0x90b: 0xa000,
+ 0x90c: 0x3f08, 0x90d: 0xa000, 0x90e: 0x3f10, 0x90f: 0xa000, 0x910: 0x3f18, 0x911: 0xa000,
+ 0x912: 0x3f20, 0x913: 0xa000, 0x914: 0x3f28, 0x915: 0xa000, 0x916: 0x3f30, 0x917: 0xa000,
+ 0x918: 0x3f38, 0x919: 0xa000, 0x91a: 0x3f40, 0x91b: 0xa000, 0x91c: 0x3f48, 0x91d: 0xa000,
+ 0x91e: 0x3f50, 0x91f: 0xa000, 0x920: 0x3f58, 0x921: 0xa000, 0x922: 0x3f60,
+ 0x924: 0xa000, 0x925: 0x3f68, 0x926: 0xa000, 0x927: 0x3f70, 0x928: 0xa000, 0x929: 0x3f78,
+ 0x92f: 0xa000,
+ 0x930: 0x3f80, 0x931: 0x3f88, 0x932: 0xa000, 0x933: 0x3f90, 0x934: 0x3f98, 0x935: 0xa000,
+ 0x936: 0x3fa0, 0x937: 0x3fa8, 0x938: 0xa000, 0x939: 0x3fb0, 0x93a: 0x3fb8, 0x93b: 0xa000,
+ 0x93c: 0x3fc0, 0x93d: 0x3fc8,
+ // Block 0x25, offset 0x940
+ 0x954: 0x3f00,
+ 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x4372, 0x95c: 0x4378, 0x95d: 0xa000,
+ 0x95e: 0x3fd0, 0x95f: 0x26b4,
+ 0x966: 0xa000,
+ 0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000,
+ 0x970: 0x3ff0, 0x971: 0xa000, 0x972: 0x3ff8, 0x973: 0xa000, 0x974: 0x4000, 0x975: 0xa000,
+ 0x976: 0x4008, 0x977: 0xa000, 0x978: 0x4010, 0x979: 0xa000, 0x97a: 0x4018, 0x97b: 0xa000,
+ 0x97c: 0x4020, 0x97d: 0xa000, 0x97e: 0x4028, 0x97f: 0xa000,
+ // Block 0x26, offset 0x980
+ 0x980: 0x4030, 0x981: 0xa000, 0x982: 0x4038, 0x984: 0xa000, 0x985: 0x4040,
+ 0x986: 0xa000, 0x987: 0x4048, 0x988: 0xa000, 0x989: 0x4050,
+ 0x98f: 0xa000, 0x990: 0x4058, 0x991: 0x4060,
+ 0x992: 0xa000, 0x993: 0x4068, 0x994: 0x4070, 0x995: 0xa000, 0x996: 0x4078, 0x997: 0x4080,
+ 0x998: 0xa000, 0x999: 0x4088, 0x99a: 0x4090, 0x99b: 0xa000, 0x99c: 0x4098, 0x99d: 0x40a0,
+ 0x9af: 0xa000,
+ 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x3fd8,
+ 0x9b7: 0x40a8, 0x9b8: 0x40b0, 0x9b9: 0x40b8, 0x9ba: 0x40c0,
+ 0x9bd: 0xa000, 0x9be: 0x40c8, 0x9bf: 0x26c9,
+ // Block 0x27, offset 0x9c0
+ 0x9c0: 0x0367, 0x9c1: 0x032b, 0x9c2: 0x032f, 0x9c3: 0x0333, 0x9c4: 0x037b, 0x9c5: 0x0337,
+ 0x9c6: 0x033b, 0x9c7: 0x033f, 0x9c8: 0x0343, 0x9c9: 0x0347, 0x9ca: 0x034b, 0x9cb: 0x034f,
+ 0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x42dc, 0x9d0: 0x42e1, 0x9d1: 0x42e6,
+ 0x9d2: 0x42eb, 0x9d3: 0x42f0, 0x9d4: 0x42f5, 0x9d5: 0x42fa, 0x9d6: 0x42ff, 0x9d7: 0x4304,
+ 0x9d8: 0x4309, 0x9d9: 0x430e, 0x9da: 0x4313, 0x9db: 0x4318, 0x9dc: 0x431d, 0x9dd: 0x4322,
+ 0x9de: 0x4327, 0x9df: 0x432c, 0x9e0: 0x4331, 0x9e1: 0x4336, 0x9e2: 0x433b, 0x9e3: 0x4340,
+ 0x9e4: 0x03c3, 0x9e5: 0x035f, 0x9e6: 0x0363, 0x9e7: 0x03e7, 0x9e8: 0x03eb, 0x9e9: 0x03ef,
+ 0x9ea: 0x03f3, 0x9eb: 0x03f7, 0x9ec: 0x03fb, 0x9ed: 0x03ff, 0x9ee: 0x036b, 0x9ef: 0x0403,
+ 0x9f0: 0x0407, 0x9f1: 0x036f, 0x9f2: 0x0373, 0x9f3: 0x0377, 0x9f4: 0x037f, 0x9f5: 0x0383,
+ 0x9f6: 0x0387, 0x9f7: 0x038b, 0x9f8: 0x038f, 0x9f9: 0x0393, 0x9fa: 0x0397, 0x9fb: 0x039b,
+ 0x9fc: 0x039f, 0x9fd: 0x03a3, 0x9fe: 0x03a7, 0x9ff: 0x03ab,
+ // Block 0x28, offset 0xa00
+ 0xa00: 0x03af, 0xa01: 0x03b3, 0xa02: 0x040b, 0xa03: 0x040f, 0xa04: 0x03b7, 0xa05: 0x03bb,
+ 0xa06: 0x03bf, 0xa07: 0x03c7, 0xa08: 0x03cb, 0xa09: 0x03cf, 0xa0a: 0x03d3, 0xa0b: 0x03d7,
+ 0xa0c: 0x03db, 0xa0d: 0x03df, 0xa0e: 0x03e3,
+ 0xa12: 0x06bf, 0xa13: 0x071b, 0xa14: 0x06cb, 0xa15: 0x097b, 0xa16: 0x06cf, 0xa17: 0x06e7,
+ 0xa18: 0x06d3, 0xa19: 0x0f93, 0xa1a: 0x0707, 0xa1b: 0x06db, 0xa1c: 0x06c3, 0xa1d: 0x09ff,
+ 0xa1e: 0x098f, 0xa1f: 0x072f,
+ // Block 0x29, offset 0xa40
+ 0xa40: 0x2054, 0xa41: 0x205a, 0xa42: 0x2060, 0xa43: 0x2066, 0xa44: 0x206c, 0xa45: 0x2072,
+ 0xa46: 0x2078, 0xa47: 0x207e, 0xa48: 0x2084, 0xa49: 0x208a, 0xa4a: 0x2090, 0xa4b: 0x2096,
+ 0xa4c: 0x209c, 0xa4d: 0x20a2, 0xa4e: 0x2726, 0xa4f: 0x272f, 0xa50: 0x2738, 0xa51: 0x2741,
+ 0xa52: 0x274a, 0xa53: 0x2753, 0xa54: 0x275c, 0xa55: 0x2765, 0xa56: 0x276e, 0xa57: 0x2780,
+ 0xa58: 0x2789, 0xa59: 0x2792, 0xa5a: 0x279b, 0xa5b: 0x27a4, 0xa5c: 0x2777, 0xa5d: 0x2bac,
+ 0xa5e: 0x2aed, 0xa60: 0x20a8, 0xa61: 0x20c0, 0xa62: 0x20b4, 0xa63: 0x2108,
+ 0xa64: 0x20c6, 0xa65: 0x20e4, 0xa66: 0x20ae, 0xa67: 0x20de, 0xa68: 0x20ba, 0xa69: 0x20f0,
+ 0xa6a: 0x2120, 0xa6b: 0x213e, 0xa6c: 0x2138, 0xa6d: 0x212c, 0xa6e: 0x217a, 0xa6f: 0x210e,
+ 0xa70: 0x211a, 0xa71: 0x2132, 0xa72: 0x2126, 0xa73: 0x2150, 0xa74: 0x20fc, 0xa75: 0x2144,
+ 0xa76: 0x216e, 0xa77: 0x2156, 0xa78: 0x20ea, 0xa79: 0x20cc, 0xa7a: 0x2102, 0xa7b: 0x2114,
+ 0xa7c: 0x214a, 0xa7d: 0x20d2, 0xa7e: 0x2174, 0xa7f: 0x20f6,
+ // Block 0x2a, offset 0xa80
+ 0xa80: 0x215c, 0xa81: 0x20d8, 0xa82: 0x2162, 0xa83: 0x2168, 0xa84: 0x092f, 0xa85: 0x0b03,
+ 0xa86: 0x0ca7, 0xa87: 0x10c7,
+ 0xa90: 0x1bc4, 0xa91: 0x18a9,
+ 0xa92: 0x18ac, 0xa93: 0x18af, 0xa94: 0x18b2, 0xa95: 0x18b5, 0xa96: 0x18b8, 0xa97: 0x18bb,
+ 0xa98: 0x18be, 0xa99: 0x18c1, 0xa9a: 0x18ca, 0xa9b: 0x18cd, 0xa9c: 0x18d0, 0xa9d: 0x18d3,
+ 0xa9e: 0x18d6, 0xa9f: 0x18d9, 0xaa0: 0x0313, 0xaa1: 0x031b, 0xaa2: 0x031f, 0xaa3: 0x0327,
+ 0xaa4: 0x032b, 0xaa5: 0x032f, 0xaa6: 0x0337, 0xaa7: 0x033f, 0xaa8: 0x0343, 0xaa9: 0x034b,
+ 0xaaa: 0x034f, 0xaab: 0x0353, 0xaac: 0x0357, 0xaad: 0x035b, 0xaae: 0x2e18, 0xaaf: 0x2e20,
+ 0xab0: 0x2e28, 0xab1: 0x2e30, 0xab2: 0x2e38, 0xab3: 0x2e40, 0xab4: 0x2e48, 0xab5: 0x2e50,
+ 0xab6: 0x2e60, 0xab7: 0x2e68, 0xab8: 0x2e70, 0xab9: 0x2e78, 0xaba: 0x2e80, 0xabb: 0x2e88,
+ 0xabc: 0x2ed3, 0xabd: 0x2e9b, 0xabe: 0x2e58,
+ // Block 0x2b, offset 0xac0
+ 0xac0: 0x06bf, 0xac1: 0x071b, 0xac2: 0x06cb, 0xac3: 0x097b, 0xac4: 0x071f, 0xac5: 0x07af,
+ 0xac6: 0x06c7, 0xac7: 0x07ab, 0xac8: 0x070b, 0xac9: 0x0887, 0xaca: 0x0d07, 0xacb: 0x0e8f,
+ 0xacc: 0x0dd7, 0xacd: 0x0d1b, 0xace: 0x145f, 0xacf: 0x098b, 0xad0: 0x0ccf, 0xad1: 0x0d4b,
+ 0xad2: 0x0d0b, 0xad3: 0x104b, 0xad4: 0x08fb, 0xad5: 0x0f03, 0xad6: 0x1387, 0xad7: 0x105f,
+ 0xad8: 0x0843, 0xad9: 0x108f, 0xada: 0x0f9b, 0xadb: 0x0a17, 0xadc: 0x140f, 0xadd: 0x077f,
+ 0xade: 0x08ab, 0xadf: 0x0df7, 0xae0: 0x1527, 0xae1: 0x0743, 0xae2: 0x07d3, 0xae3: 0x0d9b,
+ 0xae4: 0x06cf, 0xae5: 0x06e7, 0xae6: 0x06d3, 0xae7: 0x0adb, 0xae8: 0x08ef, 0xae9: 0x087f,
+ 0xaea: 0x0a57, 0xaeb: 0x0a4b, 0xaec: 0x0feb, 0xaed: 0x073f, 0xaee: 0x139b, 0xaef: 0x089b,
+ 0xaf0: 0x09f3, 0xaf1: 0x18dc, 0xaf2: 0x18df, 0xaf3: 0x18e2, 0xaf4: 0x18e5, 0xaf5: 0x18ee,
+ 0xaf6: 0x18f1, 0xaf7: 0x18f4, 0xaf8: 0x18f7, 0xaf9: 0x18fa, 0xafa: 0x18fd, 0xafb: 0x1900,
+ 0xafc: 0x1903, 0xafd: 0x1906, 0xafe: 0x1909, 0xaff: 0x1912,
+ // Block 0x2c, offset 0xb00
+ 0xb00: 0x1cc6, 0xb01: 0x1cd5, 0xb02: 0x1ce4, 0xb03: 0x1cf3, 0xb04: 0x1d02, 0xb05: 0x1d11,
+ 0xb06: 0x1d20, 0xb07: 0x1d2f, 0xb08: 0x1d3e, 0xb09: 0x218c, 0xb0a: 0x219e, 0xb0b: 0x21b0,
+ 0xb0c: 0x1954, 0xb0d: 0x1c04, 0xb0e: 0x19d2, 0xb0f: 0x1ba8, 0xb10: 0x04cb, 0xb11: 0x04d3,
+ 0xb12: 0x04db, 0xb13: 0x04e3, 0xb14: 0x04eb, 0xb15: 0x04ef, 0xb16: 0x04f3, 0xb17: 0x04f7,
+ 0xb18: 0x04fb, 0xb19: 0x04ff, 0xb1a: 0x0503, 0xb1b: 0x0507, 0xb1c: 0x050b, 0xb1d: 0x050f,
+ 0xb1e: 0x0513, 0xb1f: 0x0517, 0xb20: 0x051b, 0xb21: 0x0523, 0xb22: 0x0527, 0xb23: 0x052b,
+ 0xb24: 0x052f, 0xb25: 0x0533, 0xb26: 0x0537, 0xb27: 0x053b, 0xb28: 0x053f, 0xb29: 0x0543,
+ 0xb2a: 0x0547, 0xb2b: 0x054b, 0xb2c: 0x054f, 0xb2d: 0x0553, 0xb2e: 0x0557, 0xb2f: 0x055b,
+ 0xb30: 0x055f, 0xb31: 0x0563, 0xb32: 0x0567, 0xb33: 0x056f, 0xb34: 0x0577, 0xb35: 0x057f,
+ 0xb36: 0x0583, 0xb37: 0x0587, 0xb38: 0x058b, 0xb39: 0x058f, 0xb3a: 0x0593, 0xb3b: 0x0597,
+ 0xb3c: 0x059b, 0xb3d: 0x059f, 0xb3e: 0x05a3,
+ // Block 0x2d, offset 0xb40
+ 0xb40: 0x2b0c, 0xb41: 0x29a8, 0xb42: 0x2b1c, 0xb43: 0x2880, 0xb44: 0x2ee4, 0xb45: 0x288a,
+ 0xb46: 0x2894, 0xb47: 0x2f28, 0xb48: 0x29b5, 0xb49: 0x289e, 0xb4a: 0x28a8, 0xb4b: 0x28b2,
+ 0xb4c: 0x29dc, 0xb4d: 0x29e9, 0xb4e: 0x29c2, 0xb4f: 0x29cf, 0xb50: 0x2ea9, 0xb51: 0x29f6,
+ 0xb52: 0x2a03, 0xb53: 0x2bbe, 0xb54: 0x26bb, 0xb55: 0x2bd1, 0xb56: 0x2be4, 0xb57: 0x2b2c,
+ 0xb58: 0x2a10, 0xb59: 0x2bf7, 0xb5a: 0x2c0a, 0xb5b: 0x2a1d, 0xb5c: 0x28bc, 0xb5d: 0x28c6,
+ 0xb5e: 0x2eb7, 0xb5f: 0x2a2a, 0xb60: 0x2b3c, 0xb61: 0x2ef5, 0xb62: 0x28d0, 0xb63: 0x28da,
+ 0xb64: 0x2a37, 0xb65: 0x28e4, 0xb66: 0x28ee, 0xb67: 0x26d0, 0xb68: 0x26d7, 0xb69: 0x28f8,
+ 0xb6a: 0x2902, 0xb6b: 0x2c1d, 0xb6c: 0x2a44, 0xb6d: 0x2b4c, 0xb6e: 0x2c30, 0xb6f: 0x2a51,
+ 0xb70: 0x2916, 0xb71: 0x290c, 0xb72: 0x2f3c, 0xb73: 0x2a5e, 0xb74: 0x2c43, 0xb75: 0x2920,
+ 0xb76: 0x2b5c, 0xb77: 0x292a, 0xb78: 0x2a78, 0xb79: 0x2934, 0xb7a: 0x2a85, 0xb7b: 0x2f06,
+ 0xb7c: 0x2a6b, 0xb7d: 0x2b6c, 0xb7e: 0x2a92, 0xb7f: 0x26de,
+ // Block 0x2e, offset 0xb80
+ 0xb80: 0x2f17, 0xb81: 0x293e, 0xb82: 0x2948, 0xb83: 0x2a9f, 0xb84: 0x2952, 0xb85: 0x295c,
+ 0xb86: 0x2966, 0xb87: 0x2b7c, 0xb88: 0x2aac, 0xb89: 0x26e5, 0xb8a: 0x2c56, 0xb8b: 0x2e90,
+ 0xb8c: 0x2b8c, 0xb8d: 0x2ab9, 0xb8e: 0x2ec5, 0xb8f: 0x2970, 0xb90: 0x297a, 0xb91: 0x2ac6,
+ 0xb92: 0x26ec, 0xb93: 0x2ad3, 0xb94: 0x2b9c, 0xb95: 0x26f3, 0xb96: 0x2c69, 0xb97: 0x2984,
+ 0xb98: 0x1cb7, 0xb99: 0x1ccb, 0xb9a: 0x1cda, 0xb9b: 0x1ce9, 0xb9c: 0x1cf8, 0xb9d: 0x1d07,
+ 0xb9e: 0x1d16, 0xb9f: 0x1d25, 0xba0: 0x1d34, 0xba1: 0x1d43, 0xba2: 0x2192, 0xba3: 0x21a4,
+ 0xba4: 0x21b6, 0xba5: 0x21c2, 0xba6: 0x21ce, 0xba7: 0x21da, 0xba8: 0x21e6, 0xba9: 0x21f2,
+ 0xbaa: 0x21fe, 0xbab: 0x220a, 0xbac: 0x2246, 0xbad: 0x2252, 0xbae: 0x225e, 0xbaf: 0x226a,
+ 0xbb0: 0x2276, 0xbb1: 0x1c14, 0xbb2: 0x19c6, 0xbb3: 0x1936, 0xbb4: 0x1be4, 0xbb5: 0x1a47,
+ 0xbb6: 0x1a56, 0xbb7: 0x19cc, 0xbb8: 0x1bfc, 0xbb9: 0x1c00, 0xbba: 0x1960, 0xbbb: 0x2701,
+ 0xbbc: 0x270f, 0xbbd: 0x26fa, 0xbbe: 0x2708, 0xbbf: 0x2ae0,
+ // Block 0x2f, offset 0xbc0
+ 0xbc0: 0x1a4a, 0xbc1: 0x1a32, 0xbc2: 0x1c60, 0xbc3: 0x1a1a, 0xbc4: 0x19f3, 0xbc5: 0x1969,
+ 0xbc6: 0x1978, 0xbc7: 0x1948, 0xbc8: 0x1bf0, 0xbc9: 0x1d52, 0xbca: 0x1a4d, 0xbcb: 0x1a35,
+ 0xbcc: 0x1c64, 0xbcd: 0x1c70, 0xbce: 0x1a26, 0xbcf: 0x19fc, 0xbd0: 0x1957, 0xbd1: 0x1c1c,
+ 0xbd2: 0x1bb0, 0xbd3: 0x1b9c, 0xbd4: 0x1bcc, 0xbd5: 0x1c74, 0xbd6: 0x1a29, 0xbd7: 0x19c9,
+ 0xbd8: 0x19ff, 0xbd9: 0x19de, 0xbda: 0x1a41, 0xbdb: 0x1c78, 0xbdc: 0x1a2c, 0xbdd: 0x19c0,
+ 0xbde: 0x1a02, 0xbdf: 0x1c3c, 0xbe0: 0x1bf4, 0xbe1: 0x1a14, 0xbe2: 0x1c24, 0xbe3: 0x1c40,
+ 0xbe4: 0x1bf8, 0xbe5: 0x1a17, 0xbe6: 0x1c28, 0xbe7: 0x22e8, 0xbe8: 0x22fc, 0xbe9: 0x1996,
+ 0xbea: 0x1c20, 0xbeb: 0x1bb4, 0xbec: 0x1ba0, 0xbed: 0x1c48, 0xbee: 0x2716, 0xbef: 0x27ad,
+ 0xbf0: 0x1a59, 0xbf1: 0x1a44, 0xbf2: 0x1c7c, 0xbf3: 0x1a2f, 0xbf4: 0x1a50, 0xbf5: 0x1a38,
+ 0xbf6: 0x1c68, 0xbf7: 0x1a1d, 0xbf8: 0x19f6, 0xbf9: 0x1981, 0xbfa: 0x1a53, 0xbfb: 0x1a3b,
+ 0xbfc: 0x1c6c, 0xbfd: 0x1a20, 0xbfe: 0x19f9, 0xbff: 0x1984,
+ // Block 0x30, offset 0xc00
+ 0xc00: 0x1c2c, 0xc01: 0x1bb8, 0xc02: 0x1d4d, 0xc03: 0x1939, 0xc04: 0x19ba, 0xc05: 0x19bd,
+ 0xc06: 0x22f5, 0xc07: 0x1b94, 0xc08: 0x19c3, 0xc09: 0x194b, 0xc0a: 0x19e1, 0xc0b: 0x194e,
+ 0xc0c: 0x19ea, 0xc0d: 0x196c, 0xc0e: 0x196f, 0xc0f: 0x1a05, 0xc10: 0x1a0b, 0xc11: 0x1a0e,
+ 0xc12: 0x1c30, 0xc13: 0x1a11, 0xc14: 0x1a23, 0xc15: 0x1c38, 0xc16: 0x1c44, 0xc17: 0x1990,
+ 0xc18: 0x1d57, 0xc19: 0x1bbc, 0xc1a: 0x1993, 0xc1b: 0x1a5c, 0xc1c: 0x19a5, 0xc1d: 0x19b4,
+ 0xc1e: 0x22e2, 0xc1f: 0x22dc, 0xc20: 0x1cc1, 0xc21: 0x1cd0, 0xc22: 0x1cdf, 0xc23: 0x1cee,
+ 0xc24: 0x1cfd, 0xc25: 0x1d0c, 0xc26: 0x1d1b, 0xc27: 0x1d2a, 0xc28: 0x1d39, 0xc29: 0x2186,
+ 0xc2a: 0x2198, 0xc2b: 0x21aa, 0xc2c: 0x21bc, 0xc2d: 0x21c8, 0xc2e: 0x21d4, 0xc2f: 0x21e0,
+ 0xc30: 0x21ec, 0xc31: 0x21f8, 0xc32: 0x2204, 0xc33: 0x2240, 0xc34: 0x224c, 0xc35: 0x2258,
+ 0xc36: 0x2264, 0xc37: 0x2270, 0xc38: 0x227c, 0xc39: 0x2282, 0xc3a: 0x2288, 0xc3b: 0x228e,
+ 0xc3c: 0x2294, 0xc3d: 0x22a6, 0xc3e: 0x22ac, 0xc3f: 0x1c10,
+ // Block 0x31, offset 0xc40
+ 0xc40: 0x1377, 0xc41: 0x0cfb, 0xc42: 0x13d3, 0xc43: 0x139f, 0xc44: 0x0e57, 0xc45: 0x06eb,
+ 0xc46: 0x08df, 0xc47: 0x162b, 0xc48: 0x162b, 0xc49: 0x0a0b, 0xc4a: 0x145f, 0xc4b: 0x0943,
+ 0xc4c: 0x0a07, 0xc4d: 0x0bef, 0xc4e: 0x0fcf, 0xc4f: 0x115f, 0xc50: 0x1297, 0xc51: 0x12d3,
+ 0xc52: 0x1307, 0xc53: 0x141b, 0xc54: 0x0d73, 0xc55: 0x0dff, 0xc56: 0x0eab, 0xc57: 0x0f43,
+ 0xc58: 0x125f, 0xc59: 0x1447, 0xc5a: 0x1573, 0xc5b: 0x070f, 0xc5c: 0x08b3, 0xc5d: 0x0d87,
+ 0xc5e: 0x0ecf, 0xc5f: 0x1293, 0xc60: 0x15c3, 0xc61: 0x0ab3, 0xc62: 0x0e77, 0xc63: 0x1283,
+ 0xc64: 0x1317, 0xc65: 0x0c23, 0xc66: 0x11bb, 0xc67: 0x12df, 0xc68: 0x0b1f, 0xc69: 0x0d0f,
+ 0xc6a: 0x0e17, 0xc6b: 0x0f1b, 0xc6c: 0x1427, 0xc6d: 0x074f, 0xc6e: 0x07e7, 0xc6f: 0x0853,
+ 0xc70: 0x0c8b, 0xc71: 0x0d7f, 0xc72: 0x0ecb, 0xc73: 0x0fef, 0xc74: 0x1177, 0xc75: 0x128b,
+ 0xc76: 0x12a3, 0xc77: 0x13c7, 0xc78: 0x14ef, 0xc79: 0x15a3, 0xc7a: 0x15bf, 0xc7b: 0x102b,
+ 0xc7c: 0x106b, 0xc7d: 0x1123, 0xc7e: 0x1243, 0xc7f: 0x147b,
+ // Block 0x32, offset 0xc80
+ 0xc80: 0x15cb, 0xc81: 0x134b, 0xc82: 0x09c7, 0xc83: 0x0b3b, 0xc84: 0x10db, 0xc85: 0x119b,
+ 0xc86: 0x0eff, 0xc87: 0x1033, 0xc88: 0x1397, 0xc89: 0x14e7, 0xc8a: 0x09c3, 0xc8b: 0x0a8f,
+ 0xc8c: 0x0d77, 0xc8d: 0x0e2b, 0xc8e: 0x0e5f, 0xc8f: 0x1113, 0xc90: 0x113b, 0xc91: 0x14a7,
+ 0xc92: 0x084f, 0xc93: 0x11a7, 0xc94: 0x07f3, 0xc95: 0x07ef, 0xc96: 0x1097, 0xc97: 0x1127,
+ 0xc98: 0x125b, 0xc99: 0x14af, 0xc9a: 0x1367, 0xc9b: 0x0c27, 0xc9c: 0x0d73, 0xc9d: 0x1357,
+ 0xc9e: 0x06f7, 0xc9f: 0x0a63, 0xca0: 0x0b93, 0xca1: 0x0f2f, 0xca2: 0x0faf, 0xca3: 0x0873,
+ 0xca4: 0x103b, 0xca5: 0x075f, 0xca6: 0x0b77, 0xca7: 0x06d7, 0xca8: 0x0deb, 0xca9: 0x0ca3,
+ 0xcaa: 0x110f, 0xcab: 0x08c7, 0xcac: 0x09b3, 0xcad: 0x0ffb, 0xcae: 0x1263, 0xcaf: 0x133b,
+ 0xcb0: 0x0db7, 0xcb1: 0x13f7, 0xcb2: 0x0de3, 0xcb3: 0x0c37, 0xcb4: 0x121b, 0xcb5: 0x0c57,
+ 0xcb6: 0x0fab, 0xcb7: 0x072b, 0xcb8: 0x07a7, 0xcb9: 0x07eb, 0xcba: 0x0d53, 0xcbb: 0x10fb,
+ 0xcbc: 0x11f3, 0xcbd: 0x1347, 0xcbe: 0x145b, 0xcbf: 0x085b,
+ // Block 0x33, offset 0xcc0
+ 0xcc0: 0x090f, 0xcc1: 0x0a17, 0xcc2: 0x0b2f, 0xcc3: 0x0cbf, 0xcc4: 0x0e7b, 0xcc5: 0x103f,
+ 0xcc6: 0x1497, 0xcc7: 0x157b, 0xcc8: 0x15cf, 0xcc9: 0x15e7, 0xcca: 0x0837, 0xccb: 0x0cf3,
+ 0xccc: 0x0da3, 0xccd: 0x13eb, 0xcce: 0x0afb, 0xccf: 0x0bd7, 0xcd0: 0x0bf3, 0xcd1: 0x0c83,
+ 0xcd2: 0x0e6b, 0xcd3: 0x0eb7, 0xcd4: 0x0f67, 0xcd5: 0x108b, 0xcd6: 0x112f, 0xcd7: 0x1193,
+ 0xcd8: 0x13db, 0xcd9: 0x126b, 0xcda: 0x1403, 0xcdb: 0x147f, 0xcdc: 0x080f, 0xcdd: 0x083b,
+ 0xcde: 0x0923, 0xcdf: 0x0ea7, 0xce0: 0x12f3, 0xce1: 0x133b, 0xce2: 0x0b1b, 0xce3: 0x0b8b,
+ 0xce4: 0x0c4f, 0xce5: 0x0daf, 0xce6: 0x10d7, 0xce7: 0x0f23, 0xce8: 0x073b, 0xce9: 0x097f,
+ 0xcea: 0x0a63, 0xceb: 0x0ac7, 0xcec: 0x0b97, 0xced: 0x0f3f, 0xcee: 0x0f5b, 0xcef: 0x116b,
+ 0xcf0: 0x118b, 0xcf1: 0x1463, 0xcf2: 0x14e3, 0xcf3: 0x14f3, 0xcf4: 0x152f, 0xcf5: 0x0753,
+ 0xcf6: 0x107f, 0xcf7: 0x144f, 0xcf8: 0x14cb, 0xcf9: 0x0baf, 0xcfa: 0x0717, 0xcfb: 0x0777,
+ 0xcfc: 0x0a67, 0xcfd: 0x0a87, 0xcfe: 0x0caf, 0xcff: 0x0d73,
+ // Block 0x34, offset 0xd00
+ 0xd00: 0x0ec3, 0xd01: 0x0fcb, 0xd02: 0x1277, 0xd03: 0x1417, 0xd04: 0x1623, 0xd05: 0x0ce3,
+ 0xd06: 0x14a3, 0xd07: 0x0833, 0xd08: 0x0d2f, 0xd09: 0x0d3b, 0xd0a: 0x0e0f, 0xd0b: 0x0e47,
+ 0xd0c: 0x0f4b, 0xd0d: 0x0fa7, 0xd0e: 0x1027, 0xd0f: 0x110b, 0xd10: 0x153b, 0xd11: 0x07af,
+ 0xd12: 0x0c03, 0xd13: 0x14b3, 0xd14: 0x0767, 0xd15: 0x0aab, 0xd16: 0x0e2f, 0xd17: 0x13df,
+ 0xd18: 0x0b67, 0xd19: 0x0bb7, 0xd1a: 0x0d43, 0xd1b: 0x0f2f, 0xd1c: 0x14bb, 0xd1d: 0x0817,
+ 0xd1e: 0x08ff, 0xd1f: 0x0a97, 0xd20: 0x0cd3, 0xd21: 0x0d1f, 0xd22: 0x0d5f, 0xd23: 0x0df3,
+ 0xd24: 0x0f47, 0xd25: 0x0fbb, 0xd26: 0x1157, 0xd27: 0x12f7, 0xd28: 0x1303, 0xd29: 0x1457,
+ 0xd2a: 0x14d7, 0xd2b: 0x0883, 0xd2c: 0x0e4b, 0xd2d: 0x0903, 0xd2e: 0x0ec7, 0xd2f: 0x0f6b,
+ 0xd30: 0x1287, 0xd31: 0x14bf, 0xd32: 0x15ab, 0xd33: 0x15d3, 0xd34: 0x0d37, 0xd35: 0x0e27,
+ 0xd36: 0x11c3, 0xd37: 0x10b7, 0xd38: 0x10c3, 0xd39: 0x10e7, 0xd3a: 0x0f17, 0xd3b: 0x0e9f,
+ 0xd3c: 0x1363, 0xd3d: 0x0733, 0xd3e: 0x122b, 0xd3f: 0x081b,
+ // Block 0x35, offset 0xd40
+ 0xd40: 0x080b, 0xd41: 0x0b0b, 0xd42: 0x0c2b, 0xd43: 0x10f3, 0xd44: 0x0a53, 0xd45: 0x0e03,
+ 0xd46: 0x0cef, 0xd47: 0x13e7, 0xd48: 0x12e7, 0xd49: 0x14ab, 0xd4a: 0x1323, 0xd4b: 0x0b27,
+ 0xd4c: 0x0787, 0xd4d: 0x095b, 0xd50: 0x09af,
+ 0xd52: 0x0cdf, 0xd55: 0x07f7, 0xd56: 0x0f1f, 0xd57: 0x0fe3,
+ 0xd58: 0x1047, 0xd59: 0x1063, 0xd5a: 0x1067, 0xd5b: 0x107b, 0xd5c: 0x14fb, 0xd5d: 0x10eb,
+ 0xd5e: 0x116f, 0xd60: 0x128f, 0xd62: 0x1353,
+ 0xd65: 0x1407, 0xd66: 0x1433,
+ 0xd6a: 0x154f, 0xd6b: 0x1553, 0xd6c: 0x1557, 0xd6d: 0x15bb, 0xd6e: 0x142b, 0xd6f: 0x14c7,
+ 0xd70: 0x0757, 0xd71: 0x077b, 0xd72: 0x078f, 0xd73: 0x084b, 0xd74: 0x0857, 0xd75: 0x0897,
+ 0xd76: 0x094b, 0xd77: 0x0967, 0xd78: 0x096f, 0xd79: 0x09ab, 0xd7a: 0x09b7, 0xd7b: 0x0a93,
+ 0xd7c: 0x0a9b, 0xd7d: 0x0ba3, 0xd7e: 0x0bcb, 0xd7f: 0x0bd3,
+ // Block 0x36, offset 0xd80
+ 0xd80: 0x0beb, 0xd81: 0x0c97, 0xd82: 0x0cc7, 0xd83: 0x0ce7, 0xd84: 0x0d57, 0xd85: 0x0e1b,
+ 0xd86: 0x0e37, 0xd87: 0x0e67, 0xd88: 0x0ebb, 0xd89: 0x0edb, 0xd8a: 0x0f4f, 0xd8b: 0x102f,
+ 0xd8c: 0x104b, 0xd8d: 0x1053, 0xd8e: 0x104f, 0xd8f: 0x1057, 0xd90: 0x105b, 0xd91: 0x105f,
+ 0xd92: 0x1073, 0xd93: 0x1077, 0xd94: 0x109b, 0xd95: 0x10af, 0xd96: 0x10cb, 0xd97: 0x112f,
+ 0xd98: 0x1137, 0xd99: 0x113f, 0xd9a: 0x1153, 0xd9b: 0x117b, 0xd9c: 0x11cb, 0xd9d: 0x11ff,
+ 0xd9e: 0x11ff, 0xd9f: 0x1267, 0xda0: 0x130f, 0xda1: 0x1327, 0xda2: 0x135b, 0xda3: 0x135f,
+ 0xda4: 0x13a3, 0xda5: 0x13a7, 0xda6: 0x13ff, 0xda7: 0x1407, 0xda8: 0x14db, 0xda9: 0x151f,
+ 0xdaa: 0x1537, 0xdab: 0x0b9b, 0xdac: 0x171e, 0xdad: 0x11e3,
+ 0xdb0: 0x06df, 0xdb1: 0x07e3, 0xdb2: 0x07a3, 0xdb3: 0x074b, 0xdb4: 0x078b, 0xdb5: 0x07b7,
+ 0xdb6: 0x0847, 0xdb7: 0x0863, 0xdb8: 0x094b, 0xdb9: 0x0937, 0xdba: 0x0947, 0xdbb: 0x0963,
+ 0xdbc: 0x09af, 0xdbd: 0x09bf, 0xdbe: 0x0a03, 0xdbf: 0x0a0f,
+ // Block 0x37, offset 0xdc0
+ 0xdc0: 0x0a2b, 0xdc1: 0x0a3b, 0xdc2: 0x0b23, 0xdc3: 0x0b2b, 0xdc4: 0x0b5b, 0xdc5: 0x0b7b,
+ 0xdc6: 0x0bab, 0xdc7: 0x0bc3, 0xdc8: 0x0bb3, 0xdc9: 0x0bd3, 0xdca: 0x0bc7, 0xdcb: 0x0beb,
+ 0xdcc: 0x0c07, 0xdcd: 0x0c5f, 0xdce: 0x0c6b, 0xdcf: 0x0c73, 0xdd0: 0x0c9b, 0xdd1: 0x0cdf,
+ 0xdd2: 0x0d0f, 0xdd3: 0x0d13, 0xdd4: 0x0d27, 0xdd5: 0x0da7, 0xdd6: 0x0db7, 0xdd7: 0x0e0f,
+ 0xdd8: 0x0e5b, 0xdd9: 0x0e53, 0xdda: 0x0e67, 0xddb: 0x0e83, 0xddc: 0x0ebb, 0xddd: 0x1013,
+ 0xdde: 0x0edf, 0xddf: 0x0f13, 0xde0: 0x0f1f, 0xde1: 0x0f5f, 0xde2: 0x0f7b, 0xde3: 0x0f9f,
+ 0xde4: 0x0fc3, 0xde5: 0x0fc7, 0xde6: 0x0fe3, 0xde7: 0x0fe7, 0xde8: 0x0ff7, 0xde9: 0x100b,
+ 0xdea: 0x1007, 0xdeb: 0x1037, 0xdec: 0x10b3, 0xded: 0x10cb, 0xdee: 0x10e3, 0xdef: 0x111b,
+ 0xdf0: 0x112f, 0xdf1: 0x114b, 0xdf2: 0x117b, 0xdf3: 0x122f, 0xdf4: 0x1257, 0xdf5: 0x12cb,
+ 0xdf6: 0x1313, 0xdf7: 0x131f, 0xdf8: 0x1327, 0xdf9: 0x133f, 0xdfa: 0x1353, 0xdfb: 0x1343,
+ 0xdfc: 0x135b, 0xdfd: 0x1357, 0xdfe: 0x134f, 0xdff: 0x135f,
+ // Block 0x38, offset 0xe00
+ 0xe00: 0x136b, 0xe01: 0x13a7, 0xe02: 0x13e3, 0xe03: 0x1413, 0xe04: 0x144b, 0xe05: 0x146b,
+ 0xe06: 0x14b7, 0xe07: 0x14db, 0xe08: 0x14fb, 0xe09: 0x150f, 0xe0a: 0x151f, 0xe0b: 0x152b,
+ 0xe0c: 0x1537, 0xe0d: 0x158b, 0xe0e: 0x162b, 0xe0f: 0x16b5, 0xe10: 0x16b0, 0xe11: 0x16e2,
+ 0xe12: 0x0607, 0xe13: 0x062f, 0xe14: 0x0633, 0xe15: 0x1764, 0xe16: 0x1791, 0xe17: 0x1809,
+ 0xe18: 0x1617, 0xe19: 0x1627,
+ // Block 0x39, offset 0xe40
+ 0xe40: 0x19d5, 0xe41: 0x19d8, 0xe42: 0x19db, 0xe43: 0x1c08, 0xe44: 0x1c0c, 0xe45: 0x1a5f,
+ 0xe46: 0x1a5f,
+ 0xe53: 0x1d75, 0xe54: 0x1d66, 0xe55: 0x1d6b, 0xe56: 0x1d7a, 0xe57: 0x1d70,
+ 0xe5d: 0x4426,
+ 0xe5e: 0x8115, 0xe5f: 0x4498, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221,
+ 0xe64: 0x0224, 0xe65: 0x0227, 0xe66: 0x022a, 0xe67: 0x0230, 0xe68: 0x0233, 0xe69: 0x0017,
+ 0xe6a: 0x4486, 0xe6b: 0x448c, 0xe6c: 0x458a, 0xe6d: 0x4592, 0xe6e: 0x43de, 0xe6f: 0x43e4,
+ 0xe70: 0x43ea, 0xe71: 0x43f0, 0xe72: 0x43fc, 0xe73: 0x4402, 0xe74: 0x4408, 0xe75: 0x4414,
+ 0xe76: 0x441a, 0xe78: 0x4420, 0xe79: 0x442c, 0xe7a: 0x4432, 0xe7b: 0x4438,
+ 0xe7c: 0x4444, 0xe7e: 0x444a,
+ // Block 0x3a, offset 0xe80
+ 0xe80: 0x4450, 0xe81: 0x4456, 0xe83: 0x445c, 0xe84: 0x4462,
+ 0xe86: 0x446e, 0xe87: 0x4474, 0xe88: 0x447a, 0xe89: 0x4480, 0xe8a: 0x4492, 0xe8b: 0x440e,
+ 0xe8c: 0x43f6, 0xe8d: 0x443e, 0xe8e: 0x4468, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299,
+ 0xe92: 0x02a2, 0xe93: 0x02a2, 0xe94: 0x02a2, 0xe95: 0x02a2, 0xe96: 0x02a5, 0xe97: 0x02a5,
+ 0xe98: 0x02a5, 0xe99: 0x02a5, 0xe9a: 0x02ab, 0xe9b: 0x02ab, 0xe9c: 0x02ab, 0xe9d: 0x02ab,
+ 0xe9e: 0x029f, 0xe9f: 0x029f, 0xea0: 0x029f, 0xea1: 0x029f, 0xea2: 0x02a8, 0xea3: 0x02a8,
+ 0xea4: 0x02a8, 0xea5: 0x02a8, 0xea6: 0x029c, 0xea7: 0x029c, 0xea8: 0x029c, 0xea9: 0x029c,
+ 0xeaa: 0x02cf, 0xeab: 0x02cf, 0xeac: 0x02cf, 0xead: 0x02cf, 0xeae: 0x02d2, 0xeaf: 0x02d2,
+ 0xeb0: 0x02d2, 0xeb1: 0x02d2, 0xeb2: 0x02b1, 0xeb3: 0x02b1, 0xeb4: 0x02b1, 0xeb5: 0x02b1,
+ 0xeb6: 0x02ae, 0xeb7: 0x02ae, 0xeb8: 0x02ae, 0xeb9: 0x02ae, 0xeba: 0x02b4, 0xebb: 0x02b4,
+ 0xebc: 0x02b4, 0xebd: 0x02b4, 0xebe: 0x02b7, 0xebf: 0x02b7,
+ // Block 0x3b, offset 0xec0
+ 0xec0: 0x02b7, 0xec1: 0x02b7, 0xec2: 0x02c0, 0xec3: 0x02c0, 0xec4: 0x02bd, 0xec5: 0x02bd,
+ 0xec6: 0x02c3, 0xec7: 0x02c3, 0xec8: 0x02ba, 0xec9: 0x02ba, 0xeca: 0x02c9, 0xecb: 0x02c9,
+ 0xecc: 0x02c6, 0xecd: 0x02c6, 0xece: 0x02d5, 0xecf: 0x02d5, 0xed0: 0x02d5, 0xed1: 0x02d5,
+ 0xed2: 0x02db, 0xed3: 0x02db, 0xed4: 0x02db, 0xed5: 0x02db, 0xed6: 0x02e1, 0xed7: 0x02e1,
+ 0xed8: 0x02e1, 0xed9: 0x02e1, 0xeda: 0x02de, 0xedb: 0x02de, 0xedc: 0x02de, 0xedd: 0x02de,
+ 0xede: 0x02e4, 0xedf: 0x02e4, 0xee0: 0x02e7, 0xee1: 0x02e7, 0xee2: 0x02e7, 0xee3: 0x02e7,
+ 0xee4: 0x4504, 0xee5: 0x4504, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed,
+ 0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308,
+ 0xef0: 0x44fe, 0xef1: 0x44fe,
+ // Block 0x3c, offset 0xf00
+ 0xf13: 0x02d8, 0xf14: 0x02d8, 0xf15: 0x02d8, 0xf16: 0x02d8, 0xf17: 0x02f6,
+ 0xf18: 0x02f6, 0xf19: 0x02f3, 0xf1a: 0x02f3, 0xf1b: 0x02f9, 0xf1c: 0x02f9, 0xf1d: 0x204f,
+ 0xf1e: 0x02ff, 0xf1f: 0x02ff, 0xf20: 0x02f0, 0xf21: 0x02f0, 0xf22: 0x02fc, 0xf23: 0x02fc,
+ 0xf24: 0x0305, 0xf25: 0x0305, 0xf26: 0x0305, 0xf27: 0x0305, 0xf28: 0x028d, 0xf29: 0x028d,
+ 0xf2a: 0x25aa, 0xf2b: 0x25aa, 0xf2c: 0x261a, 0xf2d: 0x261a, 0xf2e: 0x25e9, 0xf2f: 0x25e9,
+ 0xf30: 0x2605, 0xf31: 0x2605, 0xf32: 0x25fe, 0xf33: 0x25fe, 0xf34: 0x260c, 0xf35: 0x260c,
+ 0xf36: 0x2613, 0xf37: 0x2613, 0xf38: 0x2613, 0xf39: 0x25f0, 0xf3a: 0x25f0, 0xf3b: 0x25f0,
+ 0xf3c: 0x0302, 0xf3d: 0x0302, 0xf3e: 0x0302, 0xf3f: 0x0302,
+ // Block 0x3d, offset 0xf40
+ 0xf40: 0x25b1, 0xf41: 0x25b8, 0xf42: 0x25d4, 0xf43: 0x25f0, 0xf44: 0x25f7, 0xf45: 0x1d89,
+ 0xf46: 0x1d8e, 0xf47: 0x1d93, 0xf48: 0x1da2, 0xf49: 0x1db1, 0xf4a: 0x1db6, 0xf4b: 0x1dbb,
+ 0xf4c: 0x1dc0, 0xf4d: 0x1dc5, 0xf4e: 0x1dd4, 0xf4f: 0x1de3, 0xf50: 0x1de8, 0xf51: 0x1ded,
+ 0xf52: 0x1dfc, 0xf53: 0x1e0b, 0xf54: 0x1e10, 0xf55: 0x1e15, 0xf56: 0x1e1a, 0xf57: 0x1e29,
+ 0xf58: 0x1e2e, 0xf59: 0x1e3d, 0xf5a: 0x1e42, 0xf5b: 0x1e47, 0xf5c: 0x1e56, 0xf5d: 0x1e5b,
+ 0xf5e: 0x1e60, 0xf5f: 0x1e6a, 0xf60: 0x1ea6, 0xf61: 0x1eb5, 0xf62: 0x1ec4, 0xf63: 0x1ec9,
+ 0xf64: 0x1ece, 0xf65: 0x1ed8, 0xf66: 0x1ee7, 0xf67: 0x1eec, 0xf68: 0x1efb, 0xf69: 0x1f00,
+ 0xf6a: 0x1f05, 0xf6b: 0x1f14, 0xf6c: 0x1f19, 0xf6d: 0x1f28, 0xf6e: 0x1f2d, 0xf6f: 0x1f32,
+ 0xf70: 0x1f37, 0xf71: 0x1f3c, 0xf72: 0x1f41, 0xf73: 0x1f46, 0xf74: 0x1f4b, 0xf75: 0x1f50,
+ 0xf76: 0x1f55, 0xf77: 0x1f5a, 0xf78: 0x1f5f, 0xf79: 0x1f64, 0xf7a: 0x1f69, 0xf7b: 0x1f6e,
+ 0xf7c: 0x1f73, 0xf7d: 0x1f78, 0xf7e: 0x1f7d, 0xf7f: 0x1f87,
+ // Block 0x3e, offset 0xf80
+ 0xf80: 0x1f8c, 0xf81: 0x1f91, 0xf82: 0x1f96, 0xf83: 0x1fa0, 0xf84: 0x1fa5, 0xf85: 0x1faf,
+ 0xf86: 0x1fb4, 0xf87: 0x1fb9, 0xf88: 0x1fbe, 0xf89: 0x1fc3, 0xf8a: 0x1fc8, 0xf8b: 0x1fcd,
+ 0xf8c: 0x1fd2, 0xf8d: 0x1fd7, 0xf8e: 0x1fe6, 0xf8f: 0x1ff5, 0xf90: 0x1ffa, 0xf91: 0x1fff,
+ 0xf92: 0x2004, 0xf93: 0x2009, 0xf94: 0x200e, 0xf95: 0x2018, 0xf96: 0x201d, 0xf97: 0x2022,
+ 0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x44b6, 0xf9c: 0x44bc, 0xf9d: 0x44f2,
+ 0xf9e: 0x4549, 0xf9f: 0x4550, 0xfa0: 0x4557, 0xfa1: 0x455e, 0xfa2: 0x4565, 0xfa3: 0x456c,
+ 0xfa4: 0x25c6, 0xfa5: 0x25cd, 0xfa6: 0x25d4, 0xfa7: 0x25db, 0xfa8: 0x25f0, 0xfa9: 0x25f7,
+ 0xfaa: 0x1d98, 0xfab: 0x1d9d, 0xfac: 0x1da2, 0xfad: 0x1da7, 0xfae: 0x1db1, 0xfaf: 0x1db6,
+ 0xfb0: 0x1dca, 0xfb1: 0x1dcf, 0xfb2: 0x1dd4, 0xfb3: 0x1dd9, 0xfb4: 0x1de3, 0xfb5: 0x1de8,
+ 0xfb6: 0x1df2, 0xfb7: 0x1df7, 0xfb8: 0x1dfc, 0xfb9: 0x1e01, 0xfba: 0x1e0b, 0xfbb: 0x1e10,
+ 0xfbc: 0x1f3c, 0xfbd: 0x1f41, 0xfbe: 0x1f50, 0xfbf: 0x1f55,
+ // Block 0x3f, offset 0xfc0
+ 0xfc0: 0x1f5a, 0xfc1: 0x1f6e, 0xfc2: 0x1f73, 0xfc3: 0x1f78, 0xfc4: 0x1f7d, 0xfc5: 0x1f96,
+ 0xfc6: 0x1fa0, 0xfc7: 0x1fa5, 0xfc8: 0x1faa, 0xfc9: 0x1fbe, 0xfca: 0x1fdc, 0xfcb: 0x1fe1,
+ 0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x44f2, 0xfd1: 0x2027,
+ 0xfd2: 0x202c, 0xfd3: 0x2031, 0xfd4: 0x2036, 0xfd5: 0x2040, 0xfd6: 0x2045, 0xfd7: 0x25b1,
+ 0xfd8: 0x25b8, 0xfd9: 0x25bf, 0xfda: 0x25d4, 0xfdb: 0x25e2, 0xfdc: 0x1d89, 0xfdd: 0x1d8e,
+ 0xfde: 0x1d93, 0xfdf: 0x1da2, 0xfe0: 0x1dac, 0xfe1: 0x1dbb, 0xfe2: 0x1dc0, 0xfe3: 0x1dc5,
+ 0xfe4: 0x1dd4, 0xfe5: 0x1dde, 0xfe6: 0x1dfc, 0xfe7: 0x1e15, 0xfe8: 0x1e1a, 0xfe9: 0x1e29,
+ 0xfea: 0x1e2e, 0xfeb: 0x1e3d, 0xfec: 0x1e47, 0xfed: 0x1e56, 0xfee: 0x1e5b, 0xfef: 0x1e60,
+ 0xff0: 0x1e6a, 0xff1: 0x1ea6, 0xff2: 0x1eab, 0xff3: 0x1eb5, 0xff4: 0x1ec4, 0xff5: 0x1ec9,
+ 0xff6: 0x1ece, 0xff7: 0x1ed8, 0xff8: 0x1ee7, 0xff9: 0x1efb, 0xffa: 0x1f00, 0xffb: 0x1f05,
+ 0xffc: 0x1f14, 0xffd: 0x1f19, 0xffe: 0x1f28, 0xfff: 0x1f2d,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x1f32, 0x1001: 0x1f37, 0x1002: 0x1f46, 0x1003: 0x1f4b, 0x1004: 0x1f5f, 0x1005: 0x1f64,
+ 0x1006: 0x1f69, 0x1007: 0x1f6e, 0x1008: 0x1f73, 0x1009: 0x1f87, 0x100a: 0x1f8c, 0x100b: 0x1f91,
+ 0x100c: 0x1f96, 0x100d: 0x1f9b, 0x100e: 0x1faf, 0x100f: 0x1fb4, 0x1010: 0x1fb9, 0x1011: 0x1fbe,
+ 0x1012: 0x1fcd, 0x1013: 0x1fd2, 0x1014: 0x1fd7, 0x1015: 0x1fe6, 0x1016: 0x1ff0, 0x1017: 0x1fff,
+ 0x1018: 0x2004, 0x1019: 0x44e6, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031,
+ 0x101e: 0x203b, 0x101f: 0x25d4, 0x1020: 0x25e2, 0x1021: 0x1da2, 0x1022: 0x1dac, 0x1023: 0x1dd4,
+ 0x1024: 0x1dde, 0x1025: 0x1dfc, 0x1026: 0x1e06, 0x1027: 0x1e6a, 0x1028: 0x1e6f, 0x1029: 0x1e92,
+ 0x102a: 0x1e97, 0x102b: 0x1f6e, 0x102c: 0x1f73, 0x102d: 0x1f96, 0x102e: 0x1fe6, 0x102f: 0x1ff0,
+ 0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x459a, 0x1033: 0x45a2, 0x1034: 0x45aa, 0x1035: 0x1ef1,
+ 0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74,
+ 0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33,
+ // Block 0x41, offset 0x1040
+ 0x1040: 0x1e38, 0x1041: 0x1e1f, 0x1042: 0x1e24, 0x1043: 0x1e4c, 0x1044: 0x1e51, 0x1045: 0x1eba,
+ 0x1046: 0x1ebf, 0x1047: 0x1edd, 0x1048: 0x1ee2, 0x1049: 0x1e7e, 0x104a: 0x1e83, 0x104b: 0x1e88,
+ 0x104c: 0x1e92, 0x104d: 0x1e8d, 0x104e: 0x1e65, 0x104f: 0x1eb0, 0x1050: 0x1ed3, 0x1051: 0x1ef1,
+ 0x1052: 0x1ef6, 0x1053: 0x1f0a, 0x1054: 0x1f0f, 0x1055: 0x1f1e, 0x1056: 0x1f23, 0x1057: 0x1e74,
+ 0x1058: 0x1e79, 0x1059: 0x1e9c, 0x105a: 0x1ea1, 0x105b: 0x1e33, 0x105c: 0x1e38, 0x105d: 0x1e1f,
+ 0x105e: 0x1e24, 0x105f: 0x1e4c, 0x1060: 0x1e51, 0x1061: 0x1eba, 0x1062: 0x1ebf, 0x1063: 0x1edd,
+ 0x1064: 0x1ee2, 0x1065: 0x1e7e, 0x1066: 0x1e83, 0x1067: 0x1e88, 0x1068: 0x1e92, 0x1069: 0x1e8d,
+ 0x106a: 0x1e65, 0x106b: 0x1eb0, 0x106c: 0x1ed3, 0x106d: 0x1e7e, 0x106e: 0x1e83, 0x106f: 0x1e88,
+ 0x1070: 0x1e92, 0x1071: 0x1e6f, 0x1072: 0x1e97, 0x1073: 0x1eec, 0x1074: 0x1e56, 0x1075: 0x1e5b,
+ 0x1076: 0x1e60, 0x1077: 0x1e7e, 0x1078: 0x1e83, 0x1079: 0x1e88, 0x107a: 0x1eec, 0x107b: 0x1efb,
+ 0x107c: 0x449e, 0x107d: 0x449e,
+ // Block 0x42, offset 0x1080
+ 0x1090: 0x2311, 0x1091: 0x2326,
+ 0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357,
+ 0x1098: 0x237a, 0x1099: 0x237a, 0x109a: 0x239d, 0x109b: 0x2396, 0x109c: 0x23b2, 0x109d: 0x23a4,
+ 0x109e: 0x23ab, 0x109f: 0x23ce, 0x10a0: 0x23ce, 0x10a1: 0x23c7, 0x10a2: 0x23d5, 0x10a3: 0x23d5,
+ 0x10a4: 0x23ff, 0x10a5: 0x23ff, 0x10a6: 0x241b, 0x10a7: 0x23e3, 0x10a8: 0x23e3, 0x10a9: 0x23dc,
+ 0x10aa: 0x23f1, 0x10ab: 0x23f1, 0x10ac: 0x23f8, 0x10ad: 0x23f8, 0x10ae: 0x2422, 0x10af: 0x2430,
+ 0x10b0: 0x2430, 0x10b1: 0x2437, 0x10b2: 0x2437, 0x10b3: 0x243e, 0x10b4: 0x2445, 0x10b5: 0x244c,
+ 0x10b6: 0x2453, 0x10b7: 0x2453, 0x10b8: 0x245a, 0x10b9: 0x2468, 0x10ba: 0x2476, 0x10bb: 0x246f,
+ 0x10bc: 0x247d, 0x10bd: 0x247d, 0x10be: 0x2492, 0x10bf: 0x2499,
+ // Block 0x43, offset 0x10c0
+ 0x10c0: 0x24ca, 0x10c1: 0x24d8, 0x10c2: 0x24d1, 0x10c3: 0x24b5, 0x10c4: 0x24b5, 0x10c5: 0x24df,
+ 0x10c6: 0x24df, 0x10c7: 0x24e6, 0x10c8: 0x24e6, 0x10c9: 0x2510, 0x10ca: 0x2517, 0x10cb: 0x251e,
+ 0x10cc: 0x24f4, 0x10cd: 0x2502, 0x10ce: 0x2525, 0x10cf: 0x252c,
+ 0x10d2: 0x24fb, 0x10d3: 0x2580, 0x10d4: 0x2587, 0x10d5: 0x255d, 0x10d6: 0x2564, 0x10d7: 0x2548,
+ 0x10d8: 0x2548, 0x10d9: 0x254f, 0x10da: 0x2579, 0x10db: 0x2572, 0x10dc: 0x259c, 0x10dd: 0x259c,
+ 0x10de: 0x230a, 0x10df: 0x231f, 0x10e0: 0x2318, 0x10e1: 0x2342, 0x10e2: 0x233b, 0x10e3: 0x2365,
+ 0x10e4: 0x235e, 0x10e5: 0x2388, 0x10e6: 0x236c, 0x10e7: 0x2381, 0x10e8: 0x23b9, 0x10e9: 0x2406,
+ 0x10ea: 0x23ea, 0x10eb: 0x2429, 0x10ec: 0x24c3, 0x10ed: 0x24ed, 0x10ee: 0x2595, 0x10ef: 0x258e,
+ 0x10f0: 0x25a3, 0x10f1: 0x253a, 0x10f2: 0x24a0, 0x10f3: 0x256b, 0x10f4: 0x2492, 0x10f5: 0x24ca,
+ 0x10f6: 0x2461, 0x10f7: 0x24ae, 0x10f8: 0x2541, 0x10f9: 0x2533, 0x10fa: 0x24bc, 0x10fb: 0x24a7,
+ 0x10fc: 0x24bc, 0x10fd: 0x2541, 0x10fe: 0x2373, 0x10ff: 0x238f,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x2509, 0x1101: 0x2484, 0x1102: 0x2303, 0x1103: 0x24a7, 0x1104: 0x244c, 0x1105: 0x241b,
+ 0x1106: 0x23c0, 0x1107: 0x2556,
+ 0x1130: 0x2414, 0x1131: 0x248b, 0x1132: 0x27bf, 0x1133: 0x27b6, 0x1134: 0x27ec, 0x1135: 0x27da,
+ 0x1136: 0x27c8, 0x1137: 0x27e3, 0x1138: 0x27f5, 0x1139: 0x240d, 0x113a: 0x2c7c, 0x113b: 0x2afc,
+ 0x113c: 0x27d1,
+ // Block 0x45, offset 0x1140
+ 0x1150: 0x0019, 0x1151: 0x0483,
+ 0x1152: 0x0487, 0x1153: 0x0035, 0x1154: 0x0037, 0x1155: 0x0003, 0x1156: 0x003f, 0x1157: 0x04bf,
+ 0x1158: 0x04c3, 0x1159: 0x1b5c,
+ 0x1160: 0x8132, 0x1161: 0x8132, 0x1162: 0x8132, 0x1163: 0x8132,
+ 0x1164: 0x8132, 0x1165: 0x8132, 0x1166: 0x8132, 0x1167: 0x812d, 0x1168: 0x812d, 0x1169: 0x812d,
+ 0x116a: 0x812d, 0x116b: 0x812d, 0x116c: 0x812d, 0x116d: 0x812d, 0x116e: 0x8132, 0x116f: 0x8132,
+ 0x1170: 0x1873, 0x1171: 0x0443, 0x1172: 0x043f, 0x1173: 0x007f, 0x1174: 0x007f, 0x1175: 0x0011,
+ 0x1176: 0x0013, 0x1177: 0x00b7, 0x1178: 0x00bb, 0x1179: 0x04b7, 0x117a: 0x04bb, 0x117b: 0x04ab,
+ 0x117c: 0x04af, 0x117d: 0x0493, 0x117e: 0x0497, 0x117f: 0x048b,
+ // Block 0x46, offset 0x1180
+ 0x1180: 0x048f, 0x1181: 0x049b, 0x1182: 0x049f, 0x1183: 0x04a3, 0x1184: 0x04a7,
+ 0x1187: 0x0077, 0x1188: 0x007b, 0x1189: 0x4269, 0x118a: 0x4269, 0x118b: 0x4269,
+ 0x118c: 0x4269, 0x118d: 0x007f, 0x118e: 0x007f, 0x118f: 0x007f, 0x1190: 0x0019, 0x1191: 0x0483,
+ 0x1192: 0x001d, 0x1194: 0x0037, 0x1195: 0x0035, 0x1196: 0x003f, 0x1197: 0x0003,
+ 0x1198: 0x0443, 0x1199: 0x0011, 0x119a: 0x0013, 0x119b: 0x00b7, 0x119c: 0x00bb, 0x119d: 0x04b7,
+ 0x119e: 0x04bb, 0x119f: 0x0007, 0x11a0: 0x000d, 0x11a1: 0x0015, 0x11a2: 0x0017, 0x11a3: 0x001b,
+ 0x11a4: 0x0039, 0x11a5: 0x003d, 0x11a6: 0x003b, 0x11a8: 0x0079, 0x11a9: 0x0009,
+ 0x11aa: 0x000b, 0x11ab: 0x0041,
+ 0x11b0: 0x42aa, 0x11b1: 0x44c2, 0x11b2: 0x42af, 0x11b4: 0x42b4,
+ 0x11b6: 0x42b9, 0x11b7: 0x44c8, 0x11b8: 0x42be, 0x11b9: 0x44ce, 0x11ba: 0x42c3, 0x11bb: 0x44d4,
+ 0x11bc: 0x42c8, 0x11bd: 0x44da, 0x11be: 0x42cd, 0x11bf: 0x44e0,
+ // Block 0x47, offset 0x11c0
+ 0x11c0: 0x0236, 0x11c1: 0x44a4, 0x11c2: 0x44a4, 0x11c3: 0x44aa, 0x11c4: 0x44aa, 0x11c5: 0x44ec,
+ 0x11c6: 0x44ec, 0x11c7: 0x44b0, 0x11c8: 0x44b0, 0x11c9: 0x44f8, 0x11ca: 0x44f8, 0x11cb: 0x44f8,
+ 0x11cc: 0x44f8, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c,
+ 0x11d2: 0x023c, 0x11d3: 0x023f, 0x11d4: 0x023f, 0x11d5: 0x0242, 0x11d6: 0x0242, 0x11d7: 0x0242,
+ 0x11d8: 0x0242, 0x11d9: 0x0245, 0x11da: 0x0245, 0x11db: 0x0245, 0x11dc: 0x0245, 0x11dd: 0x0248,
+ 0x11de: 0x0248, 0x11df: 0x0248, 0x11e0: 0x0248, 0x11e1: 0x024b, 0x11e2: 0x024b, 0x11e3: 0x024b,
+ 0x11e4: 0x024b, 0x11e5: 0x024e, 0x11e6: 0x024e, 0x11e7: 0x024e, 0x11e8: 0x024e, 0x11e9: 0x0251,
+ 0x11ea: 0x0251, 0x11eb: 0x0254, 0x11ec: 0x0254, 0x11ed: 0x0257, 0x11ee: 0x0257, 0x11ef: 0x025a,
+ 0x11f0: 0x025a, 0x11f1: 0x025d, 0x11f2: 0x025d, 0x11f3: 0x025d, 0x11f4: 0x025d, 0x11f5: 0x0260,
+ 0x11f6: 0x0260, 0x11f7: 0x0260, 0x11f8: 0x0260, 0x11f9: 0x0263, 0x11fa: 0x0263, 0x11fb: 0x0263,
+ 0x11fc: 0x0263, 0x11fd: 0x0266, 0x11fe: 0x0266, 0x11ff: 0x0266,
+ // Block 0x48, offset 0x1200
+ 0x1200: 0x0266, 0x1201: 0x0269, 0x1202: 0x0269, 0x1203: 0x0269, 0x1204: 0x0269, 0x1205: 0x026c,
+ 0x1206: 0x026c, 0x1207: 0x026c, 0x1208: 0x026c, 0x1209: 0x026f, 0x120a: 0x026f, 0x120b: 0x026f,
+ 0x120c: 0x026f, 0x120d: 0x0272, 0x120e: 0x0272, 0x120f: 0x0272, 0x1210: 0x0272, 0x1211: 0x0275,
+ 0x1212: 0x0275, 0x1213: 0x0275, 0x1214: 0x0275, 0x1215: 0x0278, 0x1216: 0x0278, 0x1217: 0x0278,
+ 0x1218: 0x0278, 0x1219: 0x027b, 0x121a: 0x027b, 0x121b: 0x027b, 0x121c: 0x027b, 0x121d: 0x027e,
+ 0x121e: 0x027e, 0x121f: 0x027e, 0x1220: 0x027e, 0x1221: 0x0281, 0x1222: 0x0281, 0x1223: 0x0281,
+ 0x1224: 0x0281, 0x1225: 0x0284, 0x1226: 0x0284, 0x1227: 0x0284, 0x1228: 0x0284, 0x1229: 0x0287,
+ 0x122a: 0x0287, 0x122b: 0x0287, 0x122c: 0x0287, 0x122d: 0x028a, 0x122e: 0x028a, 0x122f: 0x028d,
+ 0x1230: 0x028d, 0x1231: 0x0290, 0x1232: 0x0290, 0x1233: 0x0290, 0x1234: 0x0290, 0x1235: 0x2e00,
+ 0x1236: 0x2e00, 0x1237: 0x2e08, 0x1238: 0x2e08, 0x1239: 0x2e10, 0x123a: 0x2e10, 0x123b: 0x1f82,
+ 0x123c: 0x1f82,
+ // Block 0x49, offset 0x1240
+ 0x1240: 0x0081, 0x1241: 0x0083, 0x1242: 0x0085, 0x1243: 0x0087, 0x1244: 0x0089, 0x1245: 0x008b,
+ 0x1246: 0x008d, 0x1247: 0x008f, 0x1248: 0x0091, 0x1249: 0x0093, 0x124a: 0x0095, 0x124b: 0x0097,
+ 0x124c: 0x0099, 0x124d: 0x009b, 0x124e: 0x009d, 0x124f: 0x009f, 0x1250: 0x00a1, 0x1251: 0x00a3,
+ 0x1252: 0x00a5, 0x1253: 0x00a7, 0x1254: 0x00a9, 0x1255: 0x00ab, 0x1256: 0x00ad, 0x1257: 0x00af,
+ 0x1258: 0x00b1, 0x1259: 0x00b3, 0x125a: 0x00b5, 0x125b: 0x00b7, 0x125c: 0x00b9, 0x125d: 0x00bb,
+ 0x125e: 0x00bd, 0x125f: 0x0477, 0x1260: 0x047b, 0x1261: 0x0487, 0x1262: 0x049b, 0x1263: 0x049f,
+ 0x1264: 0x0483, 0x1265: 0x05ab, 0x1266: 0x05a3, 0x1267: 0x04c7, 0x1268: 0x04cf, 0x1269: 0x04d7,
+ 0x126a: 0x04df, 0x126b: 0x04e7, 0x126c: 0x056b, 0x126d: 0x0573, 0x126e: 0x057b, 0x126f: 0x051f,
+ 0x1270: 0x05af, 0x1271: 0x04cb, 0x1272: 0x04d3, 0x1273: 0x04db, 0x1274: 0x04e3, 0x1275: 0x04eb,
+ 0x1276: 0x04ef, 0x1277: 0x04f3, 0x1278: 0x04f7, 0x1279: 0x04fb, 0x127a: 0x04ff, 0x127b: 0x0503,
+ 0x127c: 0x0507, 0x127d: 0x050b, 0x127e: 0x050f, 0x127f: 0x0513,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x0517, 0x1281: 0x051b, 0x1282: 0x0523, 0x1283: 0x0527, 0x1284: 0x052b, 0x1285: 0x052f,
+ 0x1286: 0x0533, 0x1287: 0x0537, 0x1288: 0x053b, 0x1289: 0x053f, 0x128a: 0x0543, 0x128b: 0x0547,
+ 0x128c: 0x054b, 0x128d: 0x054f, 0x128e: 0x0553, 0x128f: 0x0557, 0x1290: 0x055b, 0x1291: 0x055f,
+ 0x1292: 0x0563, 0x1293: 0x0567, 0x1294: 0x056f, 0x1295: 0x0577, 0x1296: 0x057f, 0x1297: 0x0583,
+ 0x1298: 0x0587, 0x1299: 0x058b, 0x129a: 0x058f, 0x129b: 0x0593, 0x129c: 0x0597, 0x129d: 0x05a7,
+ 0x129e: 0x4a5a, 0x129f: 0x4a60, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4345,
+ 0x12a4: 0x031b, 0x12a5: 0x434a, 0x12a6: 0x434f, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327,
+ 0x12aa: 0x4354, 0x12ab: 0x4359, 0x12ac: 0x435e, 0x12ad: 0x4363, 0x12ae: 0x4368, 0x12af: 0x436d,
+ 0x12b0: 0x0367, 0x12b1: 0x032b, 0x12b2: 0x032f, 0x12b3: 0x0333, 0x12b4: 0x037b, 0x12b5: 0x0337,
+ 0x12b6: 0x033b, 0x12b7: 0x033f, 0x12b8: 0x0343, 0x12b9: 0x0347, 0x12ba: 0x034b, 0x12bb: 0x034f,
+ 0x12bc: 0x0353, 0x12bd: 0x0357, 0x12be: 0x035b,
+ // Block 0x4b, offset 0x12c0
+ 0x12c2: 0x42dc, 0x12c3: 0x42e1, 0x12c4: 0x42e6, 0x12c5: 0x42eb,
+ 0x12c6: 0x42f0, 0x12c7: 0x42f5, 0x12ca: 0x42fa, 0x12cb: 0x42ff,
+ 0x12cc: 0x4304, 0x12cd: 0x4309, 0x12ce: 0x430e, 0x12cf: 0x4313,
+ 0x12d2: 0x4318, 0x12d3: 0x431d, 0x12d4: 0x4322, 0x12d5: 0x4327, 0x12d6: 0x432c, 0x12d7: 0x4331,
+ 0x12da: 0x4336, 0x12db: 0x433b, 0x12dc: 0x4340,
+ 0x12e0: 0x00bf, 0x12e1: 0x00c2, 0x12e2: 0x00cb, 0x12e3: 0x4264,
+ 0x12e4: 0x00c8, 0x12e5: 0x00c5, 0x12e6: 0x0447, 0x12e8: 0x046b, 0x12e9: 0x044b,
+ 0x12ea: 0x044f, 0x12eb: 0x0453, 0x12ec: 0x0457, 0x12ed: 0x046f, 0x12ee: 0x0473,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x0063, 0x1301: 0x0065, 0x1302: 0x0067, 0x1303: 0x0069, 0x1304: 0x006b, 0x1305: 0x006d,
+ 0x1306: 0x006f, 0x1307: 0x0071, 0x1308: 0x0073, 0x1309: 0x0075, 0x130a: 0x0083, 0x130b: 0x0085,
+ 0x130c: 0x0087, 0x130d: 0x0089, 0x130e: 0x008b, 0x130f: 0x008d, 0x1310: 0x008f, 0x1311: 0x0091,
+ 0x1312: 0x0093, 0x1313: 0x0095, 0x1314: 0x0097, 0x1315: 0x0099, 0x1316: 0x009b, 0x1317: 0x009d,
+ 0x1318: 0x009f, 0x1319: 0x00a1, 0x131a: 0x00a3, 0x131b: 0x00a5, 0x131c: 0x00a7, 0x131d: 0x00a9,
+ 0x131e: 0x00ab, 0x131f: 0x00ad, 0x1320: 0x00af, 0x1321: 0x00b1, 0x1322: 0x00b3, 0x1323: 0x00b5,
+ 0x1324: 0x00dd, 0x1325: 0x00f2, 0x1328: 0x0173, 0x1329: 0x0176,
+ 0x132a: 0x0179, 0x132b: 0x017c, 0x132c: 0x017f, 0x132d: 0x0182, 0x132e: 0x0185, 0x132f: 0x0188,
+ 0x1330: 0x018b, 0x1331: 0x018e, 0x1332: 0x0191, 0x1333: 0x0194, 0x1334: 0x0197, 0x1335: 0x019a,
+ 0x1336: 0x019d, 0x1337: 0x01a0, 0x1338: 0x01a3, 0x1339: 0x0188, 0x133a: 0x01a6, 0x133b: 0x01a9,
+ 0x133c: 0x01ac, 0x133d: 0x01af, 0x133e: 0x01b2, 0x133f: 0x01b5,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x01fd, 0x1341: 0x0200, 0x1342: 0x0203, 0x1343: 0x045b, 0x1344: 0x01c7, 0x1345: 0x01d0,
+ 0x1346: 0x01d6, 0x1347: 0x01fa, 0x1348: 0x01eb, 0x1349: 0x01e8, 0x134a: 0x0206, 0x134b: 0x0209,
+ 0x134e: 0x0021, 0x134f: 0x0023, 0x1350: 0x0025, 0x1351: 0x0027,
+ 0x1352: 0x0029, 0x1353: 0x002b, 0x1354: 0x002d, 0x1355: 0x002f, 0x1356: 0x0031, 0x1357: 0x0033,
+ 0x1358: 0x0021, 0x1359: 0x0023, 0x135a: 0x0025, 0x135b: 0x0027, 0x135c: 0x0029, 0x135d: 0x002b,
+ 0x135e: 0x002d, 0x135f: 0x002f, 0x1360: 0x0031, 0x1361: 0x0033, 0x1362: 0x0021, 0x1363: 0x0023,
+ 0x1364: 0x0025, 0x1365: 0x0027, 0x1366: 0x0029, 0x1367: 0x002b, 0x1368: 0x002d, 0x1369: 0x002f,
+ 0x136a: 0x0031, 0x136b: 0x0033, 0x136c: 0x0021, 0x136d: 0x0023, 0x136e: 0x0025, 0x136f: 0x0027,
+ 0x1370: 0x0029, 0x1371: 0x002b, 0x1372: 0x002d, 0x1373: 0x002f, 0x1374: 0x0031, 0x1375: 0x0033,
+ 0x1376: 0x0021, 0x1377: 0x0023, 0x1378: 0x0025, 0x1379: 0x0027, 0x137a: 0x0029, 0x137b: 0x002b,
+ 0x137c: 0x002d, 0x137d: 0x002f, 0x137e: 0x0031, 0x137f: 0x0033,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1385: 0x028a,
+ 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138a: 0x027b, 0x138b: 0x027e,
+ 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263,
+ 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e,
+ 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, 0x139c: 0x0293, 0x139d: 0x02e4,
+ 0x139e: 0x02cc, 0x139f: 0x0296, 0x13a1: 0x023c, 0x13a2: 0x0248,
+ 0x13a4: 0x0287, 0x13a7: 0x024b, 0x13a9: 0x0290,
+ 0x13aa: 0x027b, 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f,
+ 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b4: 0x0260, 0x13b5: 0x0242,
+ 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b9: 0x0266, 0x13bb: 0x0272,
+ // Block 0x4f, offset 0x13c0
+ 0x13c2: 0x0248,
+ 0x13c7: 0x024b, 0x13c9: 0x0290, 0x13cb: 0x027e,
+ 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d1: 0x0263,
+ 0x13d2: 0x0278, 0x13d4: 0x0260, 0x13d7: 0x024e,
+ 0x13d9: 0x0266, 0x13db: 0x0272, 0x13dd: 0x02e4,
+ 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248,
+ 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e8: 0x0269, 0x13e9: 0x0290,
+ 0x13ea: 0x027b, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f,
+ 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242,
+ 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fa: 0x026c, 0x13fb: 0x0272,
+ 0x13fc: 0x0293, 0x13fe: 0x02cc,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x0239, 0x1401: 0x023c, 0x1402: 0x0248, 0x1403: 0x0251, 0x1404: 0x0287, 0x1405: 0x028a,
+ 0x1406: 0x025a, 0x1407: 0x024b, 0x1408: 0x0269, 0x1409: 0x0290, 0x140b: 0x027e,
+ 0x140c: 0x0281, 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1410: 0x0275, 0x1411: 0x0263,
+ 0x1412: 0x0278, 0x1413: 0x0257, 0x1414: 0x0260, 0x1415: 0x0242, 0x1416: 0x0245, 0x1417: 0x024e,
+ 0x1418: 0x0254, 0x1419: 0x0266, 0x141a: 0x026c, 0x141b: 0x0272,
+ 0x1421: 0x023c, 0x1422: 0x0248, 0x1423: 0x0251,
+ 0x1425: 0x028a, 0x1426: 0x025a, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290,
+ 0x142b: 0x027e, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f,
+ 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1433: 0x0257, 0x1434: 0x0260, 0x1435: 0x0242,
+ 0x1436: 0x0245, 0x1437: 0x024e, 0x1438: 0x0254, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x1879, 0x1441: 0x1876, 0x1442: 0x187c, 0x1443: 0x18a0, 0x1444: 0x18c4, 0x1445: 0x18e8,
+ 0x1446: 0x190c, 0x1447: 0x1915, 0x1448: 0x191b, 0x1449: 0x1921, 0x144a: 0x1927,
+ 0x1450: 0x1a8c, 0x1451: 0x1a90,
+ 0x1452: 0x1a94, 0x1453: 0x1a98, 0x1454: 0x1a9c, 0x1455: 0x1aa0, 0x1456: 0x1aa4, 0x1457: 0x1aa8,
+ 0x1458: 0x1aac, 0x1459: 0x1ab0, 0x145a: 0x1ab4, 0x145b: 0x1ab8, 0x145c: 0x1abc, 0x145d: 0x1ac0,
+ 0x145e: 0x1ac4, 0x145f: 0x1ac8, 0x1460: 0x1acc, 0x1461: 0x1ad0, 0x1462: 0x1ad4, 0x1463: 0x1ad8,
+ 0x1464: 0x1adc, 0x1465: 0x1ae0, 0x1466: 0x1ae4, 0x1467: 0x1ae8, 0x1468: 0x1aec, 0x1469: 0x1af0,
+ 0x146a: 0x271e, 0x146b: 0x0047, 0x146c: 0x0065, 0x146d: 0x193c, 0x146e: 0x19b1,
+ 0x1470: 0x0043, 0x1471: 0x0045, 0x1472: 0x0047, 0x1473: 0x0049, 0x1474: 0x004b, 0x1475: 0x004d,
+ 0x1476: 0x004f, 0x1477: 0x0051, 0x1478: 0x0053, 0x1479: 0x0055, 0x147a: 0x0057, 0x147b: 0x0059,
+ 0x147c: 0x005b, 0x147d: 0x005d, 0x147e: 0x005f, 0x147f: 0x0061,
+ // Block 0x52, offset 0x1480
+ 0x1480: 0x26ad, 0x1481: 0x26c2, 0x1482: 0x0503,
+ 0x1490: 0x0c0f, 0x1491: 0x0a47,
+ 0x1492: 0x08d3, 0x1493: 0x465a, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff,
+ 0x1498: 0x0727, 0x1499: 0x0cd7, 0x149a: 0x0eaf, 0x149b: 0x0caf, 0x149c: 0x0827, 0x149d: 0x0b6b,
+ 0x149e: 0x07bf, 0x149f: 0x0cb7, 0x14a0: 0x0813, 0x14a1: 0x1117, 0x14a2: 0x0f83, 0x14a3: 0x138b,
+ 0x14a4: 0x09d3, 0x14a5: 0x090b, 0x14a6: 0x0e63, 0x14a7: 0x0c1b, 0x14a8: 0x0c47, 0x14a9: 0x06bf,
+ 0x14aa: 0x06cb, 0x14ab: 0x140b, 0x14ac: 0x0adb, 0x14ad: 0x06e7, 0x14ae: 0x08ef, 0x14af: 0x0c3b,
+ 0x14b0: 0x13b3, 0x14b1: 0x0c13, 0x14b2: 0x106f, 0x14b3: 0x10ab, 0x14b4: 0x08f7, 0x14b5: 0x0e43,
+ 0x14b6: 0x0d0b, 0x14b7: 0x0d07, 0x14b8: 0x0f97, 0x14b9: 0x082b, 0x14ba: 0x0957, 0x14bb: 0x1443,
+ // Block 0x53, offset 0x14c0
+ 0x14c0: 0x06fb, 0x14c1: 0x06f3, 0x14c2: 0x0703, 0x14c3: 0x1647, 0x14c4: 0x0747, 0x14c5: 0x0757,
+ 0x14c6: 0x075b, 0x14c7: 0x0763, 0x14c8: 0x076b, 0x14c9: 0x076f, 0x14ca: 0x077b, 0x14cb: 0x0773,
+ 0x14cc: 0x05b3, 0x14cd: 0x165b, 0x14ce: 0x078f, 0x14cf: 0x0793, 0x14d0: 0x0797, 0x14d1: 0x07b3,
+ 0x14d2: 0x164c, 0x14d3: 0x05b7, 0x14d4: 0x079f, 0x14d5: 0x07bf, 0x14d6: 0x1656, 0x14d7: 0x07cf,
+ 0x14d8: 0x07d7, 0x14d9: 0x0737, 0x14da: 0x07df, 0x14db: 0x07e3, 0x14dc: 0x1831, 0x14dd: 0x07ff,
+ 0x14de: 0x0807, 0x14df: 0x05bf, 0x14e0: 0x081f, 0x14e1: 0x0823, 0x14e2: 0x082b, 0x14e3: 0x082f,
+ 0x14e4: 0x05c3, 0x14e5: 0x0847, 0x14e6: 0x084b, 0x14e7: 0x0857, 0x14e8: 0x0863, 0x14e9: 0x0867,
+ 0x14ea: 0x086b, 0x14eb: 0x0873, 0x14ec: 0x0893, 0x14ed: 0x0897, 0x14ee: 0x089f, 0x14ef: 0x08af,
+ 0x14f0: 0x08b7, 0x14f1: 0x08bb, 0x14f2: 0x08bb, 0x14f3: 0x08bb, 0x14f4: 0x166a, 0x14f5: 0x0e93,
+ 0x14f6: 0x08cf, 0x14f7: 0x08d7, 0x14f8: 0x166f, 0x14f9: 0x08e3, 0x14fa: 0x08eb, 0x14fb: 0x08f3,
+ 0x14fc: 0x091b, 0x14fd: 0x0907, 0x14fe: 0x0913, 0x14ff: 0x0917,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x091f, 0x1501: 0x0927, 0x1502: 0x092b, 0x1503: 0x0933, 0x1504: 0x093b, 0x1505: 0x093f,
+ 0x1506: 0x093f, 0x1507: 0x0947, 0x1508: 0x094f, 0x1509: 0x0953, 0x150a: 0x095f, 0x150b: 0x0983,
+ 0x150c: 0x0967, 0x150d: 0x0987, 0x150e: 0x096b, 0x150f: 0x0973, 0x1510: 0x080b, 0x1511: 0x09cf,
+ 0x1512: 0x0997, 0x1513: 0x099b, 0x1514: 0x099f, 0x1515: 0x0993, 0x1516: 0x09a7, 0x1517: 0x09a3,
+ 0x1518: 0x09bb, 0x1519: 0x1674, 0x151a: 0x09d7, 0x151b: 0x09db, 0x151c: 0x09e3, 0x151d: 0x09ef,
+ 0x151e: 0x09f7, 0x151f: 0x0a13, 0x1520: 0x1679, 0x1521: 0x167e, 0x1522: 0x0a1f, 0x1523: 0x0a23,
+ 0x1524: 0x0a27, 0x1525: 0x0a1b, 0x1526: 0x0a2f, 0x1527: 0x05c7, 0x1528: 0x05cb, 0x1529: 0x0a37,
+ 0x152a: 0x0a3f, 0x152b: 0x0a3f, 0x152c: 0x1683, 0x152d: 0x0a5b, 0x152e: 0x0a5f, 0x152f: 0x0a63,
+ 0x1530: 0x0a6b, 0x1531: 0x1688, 0x1532: 0x0a73, 0x1533: 0x0a77, 0x1534: 0x0b4f, 0x1535: 0x0a7f,
+ 0x1536: 0x05cf, 0x1537: 0x0a8b, 0x1538: 0x0a9b, 0x1539: 0x0aa7, 0x153a: 0x0aa3, 0x153b: 0x1692,
+ 0x153c: 0x0aaf, 0x153d: 0x1697, 0x153e: 0x0abb, 0x153f: 0x0ab7,
+ // Block 0x55, offset 0x1540
+ 0x1540: 0x0abf, 0x1541: 0x0acf, 0x1542: 0x0ad3, 0x1543: 0x05d3, 0x1544: 0x0ae3, 0x1545: 0x0aeb,
+ 0x1546: 0x0aef, 0x1547: 0x0af3, 0x1548: 0x05d7, 0x1549: 0x169c, 0x154a: 0x05db, 0x154b: 0x0b0f,
+ 0x154c: 0x0b13, 0x154d: 0x0b17, 0x154e: 0x0b1f, 0x154f: 0x1863, 0x1550: 0x0b37, 0x1551: 0x16a6,
+ 0x1552: 0x16a6, 0x1553: 0x11d7, 0x1554: 0x0b47, 0x1555: 0x0b47, 0x1556: 0x05df, 0x1557: 0x16c9,
+ 0x1558: 0x179b, 0x1559: 0x0b57, 0x155a: 0x0b5f, 0x155b: 0x05e3, 0x155c: 0x0b73, 0x155d: 0x0b83,
+ 0x155e: 0x0b87, 0x155f: 0x0b8f, 0x1560: 0x0b9f, 0x1561: 0x05eb, 0x1562: 0x05e7, 0x1563: 0x0ba3,
+ 0x1564: 0x16ab, 0x1565: 0x0ba7, 0x1566: 0x0bbb, 0x1567: 0x0bbf, 0x1568: 0x0bc3, 0x1569: 0x0bbf,
+ 0x156a: 0x0bcf, 0x156b: 0x0bd3, 0x156c: 0x0be3, 0x156d: 0x0bdb, 0x156e: 0x0bdf, 0x156f: 0x0be7,
+ 0x1570: 0x0beb, 0x1571: 0x0bef, 0x1572: 0x0bfb, 0x1573: 0x0bff, 0x1574: 0x0c17, 0x1575: 0x0c1f,
+ 0x1576: 0x0c2f, 0x1577: 0x0c43, 0x1578: 0x16ba, 0x1579: 0x0c3f, 0x157a: 0x0c33, 0x157b: 0x0c4b,
+ 0x157c: 0x0c53, 0x157d: 0x0c67, 0x157e: 0x16bf, 0x157f: 0x0c6f,
+ // Block 0x56, offset 0x1580
+ 0x1580: 0x0c63, 0x1581: 0x0c5b, 0x1582: 0x05ef, 0x1583: 0x0c77, 0x1584: 0x0c7f, 0x1585: 0x0c87,
+ 0x1586: 0x0c7b, 0x1587: 0x05f3, 0x1588: 0x0c97, 0x1589: 0x0c9f, 0x158a: 0x16c4, 0x158b: 0x0ccb,
+ 0x158c: 0x0cff, 0x158d: 0x0cdb, 0x158e: 0x05ff, 0x158f: 0x0ce7, 0x1590: 0x05fb, 0x1591: 0x05f7,
+ 0x1592: 0x07c3, 0x1593: 0x07c7, 0x1594: 0x0d03, 0x1595: 0x0ceb, 0x1596: 0x11ab, 0x1597: 0x0663,
+ 0x1598: 0x0d0f, 0x1599: 0x0d13, 0x159a: 0x0d17, 0x159b: 0x0d2b, 0x159c: 0x0d23, 0x159d: 0x16dd,
+ 0x159e: 0x0603, 0x159f: 0x0d3f, 0x15a0: 0x0d33, 0x15a1: 0x0d4f, 0x15a2: 0x0d57, 0x15a3: 0x16e7,
+ 0x15a4: 0x0d5b, 0x15a5: 0x0d47, 0x15a6: 0x0d63, 0x15a7: 0x0607, 0x15a8: 0x0d67, 0x15a9: 0x0d6b,
+ 0x15aa: 0x0d6f, 0x15ab: 0x0d7b, 0x15ac: 0x16ec, 0x15ad: 0x0d83, 0x15ae: 0x060b, 0x15af: 0x0d8f,
+ 0x15b0: 0x16f1, 0x15b1: 0x0d93, 0x15b2: 0x060f, 0x15b3: 0x0d9f, 0x15b4: 0x0dab, 0x15b5: 0x0db7,
+ 0x15b6: 0x0dbb, 0x15b7: 0x16f6, 0x15b8: 0x168d, 0x15b9: 0x16fb, 0x15ba: 0x0ddb, 0x15bb: 0x1700,
+ 0x15bc: 0x0de7, 0x15bd: 0x0def, 0x15be: 0x0ddf, 0x15bf: 0x0dfb,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x0e0b, 0x15c1: 0x0e1b, 0x15c2: 0x0e0f, 0x15c3: 0x0e13, 0x15c4: 0x0e1f, 0x15c5: 0x0e23,
+ 0x15c6: 0x1705, 0x15c7: 0x0e07, 0x15c8: 0x0e3b, 0x15c9: 0x0e3f, 0x15ca: 0x0613, 0x15cb: 0x0e53,
+ 0x15cc: 0x0e4f, 0x15cd: 0x170a, 0x15ce: 0x0e33, 0x15cf: 0x0e6f, 0x15d0: 0x170f, 0x15d1: 0x1714,
+ 0x15d2: 0x0e73, 0x15d3: 0x0e87, 0x15d4: 0x0e83, 0x15d5: 0x0e7f, 0x15d6: 0x0617, 0x15d7: 0x0e8b,
+ 0x15d8: 0x0e9b, 0x15d9: 0x0e97, 0x15da: 0x0ea3, 0x15db: 0x1651, 0x15dc: 0x0eb3, 0x15dd: 0x1719,
+ 0x15de: 0x0ebf, 0x15df: 0x1723, 0x15e0: 0x0ed3, 0x15e1: 0x0edf, 0x15e2: 0x0ef3, 0x15e3: 0x1728,
+ 0x15e4: 0x0f07, 0x15e5: 0x0f0b, 0x15e6: 0x172d, 0x15e7: 0x1732, 0x15e8: 0x0f27, 0x15e9: 0x0f37,
+ 0x15ea: 0x061b, 0x15eb: 0x0f3b, 0x15ec: 0x061f, 0x15ed: 0x061f, 0x15ee: 0x0f53, 0x15ef: 0x0f57,
+ 0x15f0: 0x0f5f, 0x15f1: 0x0f63, 0x15f2: 0x0f6f, 0x15f3: 0x0623, 0x15f4: 0x0f87, 0x15f5: 0x1737,
+ 0x15f6: 0x0fa3, 0x15f7: 0x173c, 0x15f8: 0x0faf, 0x15f9: 0x16a1, 0x15fa: 0x0fbf, 0x15fb: 0x1741,
+ 0x15fc: 0x1746, 0x15fd: 0x174b, 0x15fe: 0x0627, 0x15ff: 0x062b,
+ // Block 0x58, offset 0x1600
+ 0x1600: 0x0ff7, 0x1601: 0x1755, 0x1602: 0x1750, 0x1603: 0x175a, 0x1604: 0x175f, 0x1605: 0x0fff,
+ 0x1606: 0x1003, 0x1607: 0x1003, 0x1608: 0x100b, 0x1609: 0x0633, 0x160a: 0x100f, 0x160b: 0x0637,
+ 0x160c: 0x063b, 0x160d: 0x1769, 0x160e: 0x1023, 0x160f: 0x102b, 0x1610: 0x1037, 0x1611: 0x063f,
+ 0x1612: 0x176e, 0x1613: 0x105b, 0x1614: 0x1773, 0x1615: 0x1778, 0x1616: 0x107b, 0x1617: 0x1093,
+ 0x1618: 0x0643, 0x1619: 0x109b, 0x161a: 0x109f, 0x161b: 0x10a3, 0x161c: 0x177d, 0x161d: 0x1782,
+ 0x161e: 0x1782, 0x161f: 0x10bb, 0x1620: 0x0647, 0x1621: 0x1787, 0x1622: 0x10cf, 0x1623: 0x10d3,
+ 0x1624: 0x064b, 0x1625: 0x178c, 0x1626: 0x10ef, 0x1627: 0x064f, 0x1628: 0x10ff, 0x1629: 0x10f7,
+ 0x162a: 0x1107, 0x162b: 0x1796, 0x162c: 0x111f, 0x162d: 0x0653, 0x162e: 0x112b, 0x162f: 0x1133,
+ 0x1630: 0x1143, 0x1631: 0x0657, 0x1632: 0x17a0, 0x1633: 0x17a5, 0x1634: 0x065b, 0x1635: 0x17aa,
+ 0x1636: 0x115b, 0x1637: 0x17af, 0x1638: 0x1167, 0x1639: 0x1173, 0x163a: 0x117b, 0x163b: 0x17b4,
+ 0x163c: 0x17b9, 0x163d: 0x118f, 0x163e: 0x17be, 0x163f: 0x1197,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x16ce, 0x1641: 0x065f, 0x1642: 0x11af, 0x1643: 0x11b3, 0x1644: 0x0667, 0x1645: 0x11b7,
+ 0x1646: 0x0a33, 0x1647: 0x17c3, 0x1648: 0x17c8, 0x1649: 0x16d3, 0x164a: 0x16d8, 0x164b: 0x11d7,
+ 0x164c: 0x11db, 0x164d: 0x13f3, 0x164e: 0x066b, 0x164f: 0x1207, 0x1650: 0x1203, 0x1651: 0x120b,
+ 0x1652: 0x083f, 0x1653: 0x120f, 0x1654: 0x1213, 0x1655: 0x1217, 0x1656: 0x121f, 0x1657: 0x17cd,
+ 0x1658: 0x121b, 0x1659: 0x1223, 0x165a: 0x1237, 0x165b: 0x123b, 0x165c: 0x1227, 0x165d: 0x123f,
+ 0x165e: 0x1253, 0x165f: 0x1267, 0x1660: 0x1233, 0x1661: 0x1247, 0x1662: 0x124b, 0x1663: 0x124f,
+ 0x1664: 0x17d2, 0x1665: 0x17dc, 0x1666: 0x17d7, 0x1667: 0x066f, 0x1668: 0x126f, 0x1669: 0x1273,
+ 0x166a: 0x127b, 0x166b: 0x17f0, 0x166c: 0x127f, 0x166d: 0x17e1, 0x166e: 0x0673, 0x166f: 0x0677,
+ 0x1670: 0x17e6, 0x1671: 0x17eb, 0x1672: 0x067b, 0x1673: 0x129f, 0x1674: 0x12a3, 0x1675: 0x12a7,
+ 0x1676: 0x12ab, 0x1677: 0x12b7, 0x1678: 0x12b3, 0x1679: 0x12bf, 0x167a: 0x12bb, 0x167b: 0x12cb,
+ 0x167c: 0x12c3, 0x167d: 0x12c7, 0x167e: 0x12cf, 0x167f: 0x067f,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x12d7, 0x1681: 0x12db, 0x1682: 0x0683, 0x1683: 0x12eb, 0x1684: 0x12ef, 0x1685: 0x17f5,
+ 0x1686: 0x12fb, 0x1687: 0x12ff, 0x1688: 0x0687, 0x1689: 0x130b, 0x168a: 0x05bb, 0x168b: 0x17fa,
+ 0x168c: 0x17ff, 0x168d: 0x068b, 0x168e: 0x068f, 0x168f: 0x1337, 0x1690: 0x134f, 0x1691: 0x136b,
+ 0x1692: 0x137b, 0x1693: 0x1804, 0x1694: 0x138f, 0x1695: 0x1393, 0x1696: 0x13ab, 0x1697: 0x13b7,
+ 0x1698: 0x180e, 0x1699: 0x1660, 0x169a: 0x13c3, 0x169b: 0x13bf, 0x169c: 0x13cb, 0x169d: 0x1665,
+ 0x169e: 0x13d7, 0x169f: 0x13e3, 0x16a0: 0x1813, 0x16a1: 0x1818, 0x16a2: 0x1423, 0x16a3: 0x142f,
+ 0x16a4: 0x1437, 0x16a5: 0x181d, 0x16a6: 0x143b, 0x16a7: 0x1467, 0x16a8: 0x1473, 0x16a9: 0x1477,
+ 0x16aa: 0x146f, 0x16ab: 0x1483, 0x16ac: 0x1487, 0x16ad: 0x1822, 0x16ae: 0x1493, 0x16af: 0x0693,
+ 0x16b0: 0x149b, 0x16b1: 0x1827, 0x16b2: 0x0697, 0x16b3: 0x14d3, 0x16b4: 0x0ac3, 0x16b5: 0x14eb,
+ 0x16b6: 0x182c, 0x16b7: 0x1836, 0x16b8: 0x069b, 0x16b9: 0x069f, 0x16ba: 0x1513, 0x16bb: 0x183b,
+ 0x16bc: 0x06a3, 0x16bd: 0x1840, 0x16be: 0x152b, 0x16bf: 0x152b,
+ // Block 0x5b, offset 0x16c0
+ 0x16c0: 0x1533, 0x16c1: 0x1845, 0x16c2: 0x154b, 0x16c3: 0x06a7, 0x16c4: 0x155b, 0x16c5: 0x1567,
+ 0x16c6: 0x156f, 0x16c7: 0x1577, 0x16c8: 0x06ab, 0x16c9: 0x184a, 0x16ca: 0x158b, 0x16cb: 0x15a7,
+ 0x16cc: 0x15b3, 0x16cd: 0x06af, 0x16ce: 0x06b3, 0x16cf: 0x15b7, 0x16d0: 0x184f, 0x16d1: 0x06b7,
+ 0x16d2: 0x1854, 0x16d3: 0x1859, 0x16d4: 0x185e, 0x16d5: 0x15db, 0x16d6: 0x06bb, 0x16d7: 0x15ef,
+ 0x16d8: 0x15f7, 0x16d9: 0x15fb, 0x16da: 0x1603, 0x16db: 0x160b, 0x16dc: 0x1613, 0x16dd: 0x1868,
+}
+
+// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes
+// Block 0 is the zero block.
+var nfkcIndex = [1408]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc2: 0x5a, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5b, 0xc7: 0x04,
+ 0xc8: 0x05, 0xca: 0x5c, 0xcb: 0x5d, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09,
+ 0xd0: 0x0a, 0xd1: 0x5e, 0xd2: 0x5f, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x60,
+ 0xd8: 0x61, 0xd9: 0x0d, 0xdb: 0x62, 0xdc: 0x63, 0xdd: 0x64, 0xdf: 0x65,
+ 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+ 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
+ 0xf0: 0x13,
+ // Block 0x4, offset 0x100
+ 0x120: 0x66, 0x121: 0x67, 0x123: 0x68, 0x124: 0x69, 0x125: 0x6a, 0x126: 0x6b, 0x127: 0x6c,
+ 0x128: 0x6d, 0x129: 0x6e, 0x12a: 0x6f, 0x12b: 0x70, 0x12c: 0x6b, 0x12d: 0x71, 0x12e: 0x72, 0x12f: 0x73,
+ 0x131: 0x74, 0x132: 0x75, 0x133: 0x76, 0x134: 0x77, 0x135: 0x78, 0x137: 0x79,
+ 0x138: 0x7a, 0x139: 0x7b, 0x13a: 0x7c, 0x13b: 0x7d, 0x13c: 0x7e, 0x13d: 0x7f, 0x13e: 0x80, 0x13f: 0x81,
+ // Block 0x5, offset 0x140
+ 0x140: 0x82, 0x142: 0x83, 0x143: 0x84, 0x144: 0x85, 0x145: 0x86, 0x146: 0x87, 0x147: 0x88,
+ 0x14d: 0x89,
+ 0x15c: 0x8a, 0x15f: 0x8b,
+ 0x162: 0x8c, 0x164: 0x8d,
+ 0x168: 0x8e, 0x169: 0x8f, 0x16a: 0x90, 0x16c: 0x0e, 0x16d: 0x91, 0x16e: 0x92, 0x16f: 0x93,
+ 0x170: 0x94, 0x173: 0x95, 0x174: 0x96, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x97,
+ 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18,
+ // Block 0x6, offset 0x180
+ 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9c, 0x187: 0x9d,
+ 0x188: 0x9e, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9f, 0x18c: 0xa0,
+ 0x191: 0x1d, 0x192: 0x1e, 0x193: 0xa1,
+ 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4,
+ 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8,
+ 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xab,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0xac, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xad, 0x1c5: 0x25, 0x1c6: 0x26,
+ 0x1c8: 0x27, 0x1c9: 0x28, 0x1ca: 0x29, 0x1cb: 0x2a, 0x1cc: 0x2b, 0x1cd: 0x2c, 0x1ce: 0x2d, 0x1cf: 0x2e,
+ // Block 0x8, offset 0x200
+ 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2,
+ 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8,
+ 0x22a: 0xb9, 0x22b: 0xba, 0x22d: 0xbb, 0x22f: 0xbc,
+ 0x230: 0xbd, 0x231: 0xbe, 0x232: 0xbf, 0x233: 0xc0, 0x234: 0xc1, 0x235: 0xc2, 0x236: 0xc3, 0x237: 0xbd,
+ 0x238: 0xbe, 0x239: 0xbf, 0x23a: 0xc0, 0x23b: 0xc1, 0x23c: 0xc2, 0x23d: 0xc3, 0x23e: 0xbd, 0x23f: 0xbe,
+ // Block 0x9, offset 0x240
+ 0x240: 0xbf, 0x241: 0xc0, 0x242: 0xc1, 0x243: 0xc2, 0x244: 0xc3, 0x245: 0xbd, 0x246: 0xbe, 0x247: 0xbf,
+ 0x248: 0xc0, 0x249: 0xc1, 0x24a: 0xc2, 0x24b: 0xc3, 0x24c: 0xbd, 0x24d: 0xbe, 0x24e: 0xbf, 0x24f: 0xc0,
+ 0x250: 0xc1, 0x251: 0xc2, 0x252: 0xc3, 0x253: 0xbd, 0x254: 0xbe, 0x255: 0xbf, 0x256: 0xc0, 0x257: 0xc1,
+ 0x258: 0xc2, 0x259: 0xc3, 0x25a: 0xbd, 0x25b: 0xbe, 0x25c: 0xbf, 0x25d: 0xc0, 0x25e: 0xc1, 0x25f: 0xc2,
+ 0x260: 0xc3, 0x261: 0xbd, 0x262: 0xbe, 0x263: 0xbf, 0x264: 0xc0, 0x265: 0xc1, 0x266: 0xc2, 0x267: 0xc3,
+ 0x268: 0xbd, 0x269: 0xbe, 0x26a: 0xbf, 0x26b: 0xc0, 0x26c: 0xc1, 0x26d: 0xc2, 0x26e: 0xc3, 0x26f: 0xbd,
+ 0x270: 0xbe, 0x271: 0xbf, 0x272: 0xc0, 0x273: 0xc1, 0x274: 0xc2, 0x275: 0xc3, 0x276: 0xbd, 0x277: 0xbe,
+ 0x278: 0xbf, 0x279: 0xc0, 0x27a: 0xc1, 0x27b: 0xc2, 0x27c: 0xc3, 0x27d: 0xbd, 0x27e: 0xbe, 0x27f: 0xbf,
+ // Block 0xa, offset 0x280
+ 0x280: 0xc0, 0x281: 0xc1, 0x282: 0xc2, 0x283: 0xc3, 0x284: 0xbd, 0x285: 0xbe, 0x286: 0xbf, 0x287: 0xc0,
+ 0x288: 0xc1, 0x289: 0xc2, 0x28a: 0xc3, 0x28b: 0xbd, 0x28c: 0xbe, 0x28d: 0xbf, 0x28e: 0xc0, 0x28f: 0xc1,
+ 0x290: 0xc2, 0x291: 0xc3, 0x292: 0xbd, 0x293: 0xbe, 0x294: 0xbf, 0x295: 0xc0, 0x296: 0xc1, 0x297: 0xc2,
+ 0x298: 0xc3, 0x299: 0xbd, 0x29a: 0xbe, 0x29b: 0xbf, 0x29c: 0xc0, 0x29d: 0xc1, 0x29e: 0xc2, 0x29f: 0xc3,
+ 0x2a0: 0xbd, 0x2a1: 0xbe, 0x2a2: 0xbf, 0x2a3: 0xc0, 0x2a4: 0xc1, 0x2a5: 0xc2, 0x2a6: 0xc3, 0x2a7: 0xbd,
+ 0x2a8: 0xbe, 0x2a9: 0xbf, 0x2aa: 0xc0, 0x2ab: 0xc1, 0x2ac: 0xc2, 0x2ad: 0xc3, 0x2ae: 0xbd, 0x2af: 0xbe,
+ 0x2b0: 0xbf, 0x2b1: 0xc0, 0x2b2: 0xc1, 0x2b3: 0xc2, 0x2b4: 0xc3, 0x2b5: 0xbd, 0x2b6: 0xbe, 0x2b7: 0xbf,
+ 0x2b8: 0xc0, 0x2b9: 0xc1, 0x2ba: 0xc2, 0x2bb: 0xc3, 0x2bc: 0xbd, 0x2bd: 0xbe, 0x2be: 0xbf, 0x2bf: 0xc0,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0xc1, 0x2c1: 0xc2, 0x2c2: 0xc3, 0x2c3: 0xbd, 0x2c4: 0xbe, 0x2c5: 0xbf, 0x2c6: 0xc0, 0x2c7: 0xc1,
+ 0x2c8: 0xc2, 0x2c9: 0xc3, 0x2ca: 0xbd, 0x2cb: 0xbe, 0x2cc: 0xbf, 0x2cd: 0xc0, 0x2ce: 0xc1, 0x2cf: 0xc2,
+ 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3,
+ 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4,
+ // Block 0xc, offset 0x300
+ 0x324: 0x2f, 0x325: 0x30, 0x326: 0x31, 0x327: 0x32,
+ 0x328: 0x33, 0x329: 0x34, 0x32a: 0x35, 0x32b: 0x36, 0x32c: 0x37, 0x32d: 0x38, 0x32e: 0x39, 0x32f: 0x3a,
+ 0x330: 0x3b, 0x331: 0x3c, 0x332: 0x3d, 0x333: 0x3e, 0x334: 0x3f, 0x335: 0x40, 0x336: 0x41, 0x337: 0x42,
+ 0x338: 0x43, 0x339: 0x44, 0x33a: 0x45, 0x33b: 0x46, 0x33c: 0xc5, 0x33d: 0x47, 0x33e: 0x48, 0x33f: 0x49,
+ // Block 0xd, offset 0x340
+ 0x347: 0xc6,
+ 0x34b: 0xc7, 0x34d: 0xc8,
+ 0x368: 0xc9, 0x36b: 0xca,
+ // Block 0xe, offset 0x380
+ 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce,
+ 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6b, 0x38d: 0xd1,
+ 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6,
+ 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9,
+ 0x3b0: 0xd7,
+ // Block 0xf, offset 0x3c0
+ 0x3eb: 0xda, 0x3ec: 0xdb,
+ // Block 0x10, offset 0x400
+ 0x432: 0xdc,
+ // Block 0x11, offset 0x440
+ 0x445: 0xdd, 0x446: 0xde, 0x447: 0xdf,
+ 0x449: 0xe0,
+ 0x450: 0xe1, 0x451: 0xe2, 0x452: 0xe3, 0x453: 0xe4, 0x454: 0xe5, 0x455: 0xe6, 0x456: 0xe7, 0x457: 0xe8,
+ 0x458: 0xe9, 0x459: 0xea, 0x45a: 0x4a, 0x45b: 0xeb, 0x45c: 0xec, 0x45d: 0xed, 0x45e: 0xee, 0x45f: 0x4b,
+ // Block 0x12, offset 0x480
+ 0x480: 0xef,
+ 0x4a3: 0xf0, 0x4a5: 0xf1,
+ 0x4b8: 0x4c, 0x4b9: 0x4d, 0x4ba: 0x4e,
+ // Block 0x13, offset 0x4c0
+ 0x4c4: 0x4f, 0x4c5: 0xf2, 0x4c6: 0xf3,
+ 0x4c8: 0x50, 0x4c9: 0xf4,
+ // Block 0x14, offset 0x500
+ 0x520: 0x51, 0x521: 0x52, 0x522: 0x53, 0x523: 0x54, 0x524: 0x55, 0x525: 0x56, 0x526: 0x57, 0x527: 0x58,
+ 0x528: 0x59,
+ // Block 0x15, offset 0x540
+ 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
+ 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
+ 0x56f: 0x12,
+}
+
+// nfkcSparseOffset: 155 entries, 310 bytes
+var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd4, 0xdb, 0xe3, 0xe7, 0xe9, 0xec, 0xf0, 0xf6, 0x107, 0x113, 0x115, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12c, 0x12f, 0x131, 0x134, 0x137, 0x13b, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x176, 0x184, 0x192, 0x1a2, 0x1b0, 0x1b7, 0x1bd, 0x1cc, 0x1d0, 0x1d2, 0x1d6, 0x1d8, 0x1db, 0x1dd, 0x1e0, 0x1e2, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1f7, 0x201, 0x20b, 0x20e, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x22b, 0x22e, 0x232, 0x234, 0x23b, 0x241, 0x247, 0x24f, 0x255, 0x25b, 0x261, 0x265, 0x267, 0x269, 0x26b, 0x26d, 0x273, 0x276, 0x279, 0x281, 0x288, 0x28b, 0x28e, 0x290, 0x298, 0x29b, 0x2a2, 0x2a5, 0x2ab, 0x2ad, 0x2af, 0x2b2, 0x2b4, 0x2b6, 0x2b8, 0x2ba, 0x2c7, 0x2d1, 0x2d3, 0x2d5, 0x2d9, 0x2de, 0x2ea, 0x2ef, 0x2f8, 0x2fe, 0x303, 0x307, 0x30c, 0x310, 0x320, 0x32e, 0x33c, 0x34a, 0x350, 0x352, 0x355, 0x35f, 0x361}
+
+// nfkcSparseValues: 875 entries, 3500 bytes
+var nfkcSparseValues = [875]valueRange{
+ // Block 0x0, offset 0x0
+ {value: 0x0002, lo: 0x0d},
+ {value: 0x0001, lo: 0xa0, hi: 0xa0},
+ {value: 0x4278, lo: 0xa8, hi: 0xa8},
+ {value: 0x0083, lo: 0xaa, hi: 0xaa},
+ {value: 0x4264, lo: 0xaf, hi: 0xaf},
+ {value: 0x0025, lo: 0xb2, hi: 0xb3},
+ {value: 0x425a, lo: 0xb4, hi: 0xb4},
+ {value: 0x01dc, lo: 0xb5, hi: 0xb5},
+ {value: 0x4291, lo: 0xb8, hi: 0xb8},
+ {value: 0x0023, lo: 0xb9, hi: 0xb9},
+ {value: 0x009f, lo: 0xba, hi: 0xba},
+ {value: 0x221c, lo: 0xbc, hi: 0xbc},
+ {value: 0x2210, lo: 0xbd, hi: 0xbd},
+ {value: 0x22b2, lo: 0xbe, hi: 0xbe},
+ // Block 0x1, offset 0xe
+ {value: 0x0091, lo: 0x03},
+ {value: 0x4778, lo: 0xa0, hi: 0xa1},
+ {value: 0x47aa, lo: 0xaf, hi: 0xb0},
+ {value: 0xa000, lo: 0xb7, hi: 0xb7},
+ // Block 0x2, offset 0x12
+ {value: 0x0003, lo: 0x08},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x0091, lo: 0xb0, hi: 0xb0},
+ {value: 0x0119, lo: 0xb1, hi: 0xb1},
+ {value: 0x0095, lo: 0xb2, hi: 0xb2},
+ {value: 0x00a5, lo: 0xb3, hi: 0xb3},
+ {value: 0x0143, lo: 0xb4, hi: 0xb6},
+ {value: 0x00af, lo: 0xb7, hi: 0xb7},
+ {value: 0x00b3, lo: 0xb8, hi: 0xb8},
+ // Block 0x3, offset 0x1b
+ {value: 0x000a, lo: 0x09},
+ {value: 0x426e, lo: 0x98, hi: 0x98},
+ {value: 0x4273, lo: 0x99, hi: 0x9a},
+ {value: 0x4296, lo: 0x9b, hi: 0x9b},
+ {value: 0x425f, lo: 0x9c, hi: 0x9c},
+ {value: 0x4282, lo: 0x9d, hi: 0x9d},
+ {value: 0x0113, lo: 0xa0, hi: 0xa0},
+ {value: 0x0099, lo: 0xa1, hi: 0xa1},
+ {value: 0x00a7, lo: 0xa2, hi: 0xa3},
+ {value: 0x0167, lo: 0xa4, hi: 0xa4},
+ // Block 0x4, offset 0x25
+ {value: 0x0000, lo: 0x0f},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0xa000, lo: 0x8d, hi: 0x8d},
+ {value: 0x37a5, lo: 0x90, hi: 0x90},
+ {value: 0x37b1, lo: 0x91, hi: 0x91},
+ {value: 0x379f, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x96, hi: 0x96},
+ {value: 0x3817, lo: 0x97, hi: 0x97},
+ {value: 0x37e1, lo: 0x9c, hi: 0x9c},
+ {value: 0x37c9, lo: 0x9d, hi: 0x9d},
+ {value: 0x37f3, lo: 0x9e, hi: 0x9e},
+ {value: 0xa000, lo: 0xb4, hi: 0xb5},
+ {value: 0x381d, lo: 0xb6, hi: 0xb6},
+ {value: 0x3823, lo: 0xb7, hi: 0xb7},
+ // Block 0x5, offset 0x35
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x83, hi: 0x87},
+ // Block 0x6, offset 0x37
+ {value: 0x0001, lo: 0x04},
+ {value: 0x8113, lo: 0x81, hi: 0x82},
+ {value: 0x8132, lo: 0x84, hi: 0x84},
+ {value: 0x812d, lo: 0x85, hi: 0x85},
+ {value: 0x810d, lo: 0x87, hi: 0x87},
+ // Block 0x7, offset 0x3c
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x97},
+ {value: 0x8119, lo: 0x98, hi: 0x98},
+ {value: 0x811a, lo: 0x99, hi: 0x99},
+ {value: 0x811b, lo: 0x9a, hi: 0x9a},
+ {value: 0x3841, lo: 0xa2, hi: 0xa2},
+ {value: 0x3847, lo: 0xa3, hi: 0xa3},
+ {value: 0x3853, lo: 0xa4, hi: 0xa4},
+ {value: 0x384d, lo: 0xa5, hi: 0xa5},
+ {value: 0x3859, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xa7, hi: 0xa7},
+ // Block 0x8, offset 0x47
+ {value: 0x0000, lo: 0x0e},
+ {value: 0x386b, lo: 0x80, hi: 0x80},
+ {value: 0xa000, lo: 0x81, hi: 0x81},
+ {value: 0x385f, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x3865, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x95, hi: 0x95},
+ {value: 0x8132, lo: 0x96, hi: 0x9c},
+ {value: 0x8132, lo: 0x9f, hi: 0xa2},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa4},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xaa, hi: 0xaa},
+ {value: 0x8132, lo: 0xab, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ // Block 0x9, offset 0x56
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x811f, lo: 0x91, hi: 0x91},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x812d, lo: 0xb1, hi: 0xb1},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb5, hi: 0xb6},
+ {value: 0x812d, lo: 0xb7, hi: 0xb9},
+ {value: 0x8132, lo: 0xba, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbc},
+ {value: 0x8132, lo: 0xbd, hi: 0xbd},
+ {value: 0x812d, lo: 0xbe, hi: 0xbe},
+ {value: 0x8132, lo: 0xbf, hi: 0xbf},
+ // Block 0xa, offset 0x63
+ {value: 0x0005, lo: 0x07},
+ {value: 0x8132, lo: 0x80, hi: 0x80},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x83},
+ {value: 0x812d, lo: 0x84, hi: 0x85},
+ {value: 0x812d, lo: 0x86, hi: 0x87},
+ {value: 0x812d, lo: 0x88, hi: 0x89},
+ {value: 0x8132, lo: 0x8a, hi: 0x8a},
+ // Block 0xb, offset 0x6b
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xab, hi: 0xb1},
+ {value: 0x812d, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb3},
+ // Block 0xc, offset 0x6f
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0x96, hi: 0x99},
+ {value: 0x8132, lo: 0x9b, hi: 0xa3},
+ {value: 0x8132, lo: 0xa5, hi: 0xa7},
+ {value: 0x8132, lo: 0xa9, hi: 0xad},
+ // Block 0xd, offset 0x74
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x99, hi: 0x9b},
+ // Block 0xe, offset 0x76
+ {value: 0x0000, lo: 0x10},
+ {value: 0x8132, lo: 0x94, hi: 0xa1},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8132, lo: 0xaa, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xaf},
+ {value: 0x8116, lo: 0xb0, hi: 0xb0},
+ {value: 0x8117, lo: 0xb1, hi: 0xb1},
+ {value: 0x8118, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb5},
+ {value: 0x812d, lo: 0xb6, hi: 0xb6},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x812d, lo: 0xb9, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbf},
+ // Block 0xf, offset 0x87
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0xa8, hi: 0xa8},
+ {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
+ {value: 0xa000, lo: 0xb0, hi: 0xb0},
+ {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
+ {value: 0xa000, lo: 0xb3, hi: 0xb3},
+ {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
+ {value: 0x9902, lo: 0xbc, hi: 0xbc},
+ // Block 0x10, offset 0x8f
+ {value: 0x0008, lo: 0x06},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x91, hi: 0x91},
+ {value: 0x812d, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x93, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x94},
+ {value: 0x45b2, lo: 0x98, hi: 0x9f},
+ // Block 0x11, offset 0x96
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x12, offset 0x99
+ {value: 0x0008, lo: 0x06},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2c9e, lo: 0x8b, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x45f2, lo: 0x9c, hi: 0x9d},
+ {value: 0x4602, lo: 0x9f, hi: 0x9f},
+ // Block 0x13, offset 0xa0
+ {value: 0x0000, lo: 0x03},
+ {value: 0x462a, lo: 0xb3, hi: 0xb3},
+ {value: 0x4632, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x14, offset 0xa4
+ {value: 0x0008, lo: 0x03},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x460a, lo: 0x99, hi: 0x9b},
+ {value: 0x4622, lo: 0x9e, hi: 0x9e},
+ // Block 0x15, offset 0xa8
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x16, offset 0xaa
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ // Block 0x17, offset 0xac
+ {value: 0x0000, lo: 0x08},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2cb6, lo: 0x88, hi: 0x88},
+ {value: 0x2cae, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cbe, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x96, hi: 0x97},
+ {value: 0x463a, lo: 0x9c, hi: 0x9c},
+ {value: 0x4642, lo: 0x9d, hi: 0x9d},
+ // Block 0x18, offset 0xb5
+ {value: 0x0000, lo: 0x03},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x2cc6, lo: 0x94, hi: 0x94},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x19, offset 0xb9
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cce, lo: 0x8a, hi: 0x8a},
+ {value: 0x2cde, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1a, offset 0xc0
+ {value: 0x1801, lo: 0x04},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x3ef0, lo: 0x88, hi: 0x88},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8120, lo: 0x95, hi: 0x96},
+ // Block 0x1b, offset 0xc5
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0xa000, lo: 0xbf, hi: 0xbf},
+ // Block 0x1c, offset 0xc8
+ {value: 0x0000, lo: 0x09},
+ {value: 0x2ce6, lo: 0x80, hi: 0x80},
+ {value: 0x9900, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x2cee, lo: 0x87, hi: 0x87},
+ {value: 0x2cf6, lo: 0x88, hi: 0x88},
+ {value: 0x2f50, lo: 0x8a, hi: 0x8a},
+ {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x95, hi: 0x96},
+ // Block 0x1d, offset 0xd2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1e, offset 0xd4
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
+ {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d06, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1f, offset 0xdb
+ {value: 0x6bea, lo: 0x07},
+ {value: 0x9904, lo: 0x8a, hi: 0x8a},
+ {value: 0x9900, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
+ {value: 0x2f58, lo: 0x9c, hi: 0x9c},
+ {value: 0x2de3, lo: 0x9d, hi: 0x9d},
+ {value: 0x2d16, lo: 0x9e, hi: 0x9f},
+ // Block 0x20, offset 0xe3
+ {value: 0x0000, lo: 0x03},
+ {value: 0x2621, lo: 0xb3, hi: 0xb3},
+ {value: 0x8122, lo: 0xb8, hi: 0xb9},
+ {value: 0x8104, lo: 0xba, hi: 0xba},
+ // Block 0x21, offset 0xe7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8123, lo: 0x88, hi: 0x8b},
+ // Block 0x22, offset 0xe9
+ {value: 0x0000, lo: 0x02},
+ {value: 0x2636, lo: 0xb3, hi: 0xb3},
+ {value: 0x8124, lo: 0xb8, hi: 0xb9},
+ // Block 0x23, offset 0xec
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8125, lo: 0x88, hi: 0x8b},
+ {value: 0x2628, lo: 0x9c, hi: 0x9c},
+ {value: 0x262f, lo: 0x9d, hi: 0x9d},
+ // Block 0x24, offset 0xf0
+ {value: 0x0000, lo: 0x05},
+ {value: 0x030b, lo: 0x8c, hi: 0x8c},
+ {value: 0x812d, lo: 0x98, hi: 0x99},
+ {value: 0x812d, lo: 0xb5, hi: 0xb5},
+ {value: 0x812d, lo: 0xb7, hi: 0xb7},
+ {value: 0x812b, lo: 0xb9, hi: 0xb9},
+ // Block 0x25, offset 0xf6
+ {value: 0x0000, lo: 0x10},
+ {value: 0x2644, lo: 0x83, hi: 0x83},
+ {value: 0x264b, lo: 0x8d, hi: 0x8d},
+ {value: 0x2652, lo: 0x92, hi: 0x92},
+ {value: 0x2659, lo: 0x97, hi: 0x97},
+ {value: 0x2660, lo: 0x9c, hi: 0x9c},
+ {value: 0x263d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8126, lo: 0xb1, hi: 0xb1},
+ {value: 0x8127, lo: 0xb2, hi: 0xb2},
+ {value: 0x4a66, lo: 0xb3, hi: 0xb3},
+ {value: 0x8128, lo: 0xb4, hi: 0xb4},
+ {value: 0x4a6f, lo: 0xb5, hi: 0xb5},
+ {value: 0x464a, lo: 0xb6, hi: 0xb6},
+ {value: 0x468a, lo: 0xb7, hi: 0xb7},
+ {value: 0x4652, lo: 0xb8, hi: 0xb8},
+ {value: 0x4695, lo: 0xb9, hi: 0xb9},
+ {value: 0x8127, lo: 0xba, hi: 0xbd},
+ // Block 0x26, offset 0x107
+ {value: 0x0000, lo: 0x0b},
+ {value: 0x8127, lo: 0x80, hi: 0x80},
+ {value: 0x4a78, lo: 0x81, hi: 0x81},
+ {value: 0x8132, lo: 0x82, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0x86, hi: 0x87},
+ {value: 0x266e, lo: 0x93, hi: 0x93},
+ {value: 0x2675, lo: 0x9d, hi: 0x9d},
+ {value: 0x267c, lo: 0xa2, hi: 0xa2},
+ {value: 0x2683, lo: 0xa7, hi: 0xa7},
+ {value: 0x268a, lo: 0xac, hi: 0xac},
+ {value: 0x2667, lo: 0xb9, hi: 0xb9},
+ // Block 0x27, offset 0x113
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x86, hi: 0x86},
+ // Block 0x28, offset 0x115
+ {value: 0x0000, lo: 0x05},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
+ {value: 0x9900, lo: 0xae, hi: 0xae},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x29, offset 0x11b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ // Block 0x2a, offset 0x11d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x030f, lo: 0xbc, hi: 0xbc},
+ // Block 0x2b, offset 0x11f
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x80, hi: 0x92},
+ // Block 0x2c, offset 0x121
+ {value: 0x0000, lo: 0x01},
+ {value: 0xb900, lo: 0xa1, hi: 0xb5},
+ // Block 0x2d, offset 0x123
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xa8, hi: 0xbf},
+ // Block 0x2e, offset 0x125
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0x80, hi: 0x82},
+ // Block 0x2f, offset 0x127
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9d, hi: 0x9f},
+ // Block 0x30, offset 0x129
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x94, hi: 0x94},
+ {value: 0x8104, lo: 0xb4, hi: 0xb4},
+ // Block 0x31, offset 0x12c
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x9d, hi: 0x9d},
+ // Block 0x32, offset 0x12f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8131, lo: 0xa9, hi: 0xa9},
+ // Block 0x33, offset 0x131
+ {value: 0x0004, lo: 0x02},
+ {value: 0x812e, lo: 0xb9, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbb},
+ // Block 0x34, offset 0x134
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x97, hi: 0x97},
+ {value: 0x812d, lo: 0x98, hi: 0x98},
+ // Block 0x35, offset 0x137
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8104, lo: 0xa0, hi: 0xa0},
+ {value: 0x8132, lo: 0xb5, hi: 0xbc},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x36, offset 0x13b
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ {value: 0x812d, lo: 0xb5, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x37, offset 0x140
+ {value: 0x0000, lo: 0x08},
+ {value: 0x2d66, lo: 0x80, hi: 0x80},
+ {value: 0x2d6e, lo: 0x81, hi: 0x81},
+ {value: 0xa000, lo: 0x82, hi: 0x82},
+ {value: 0x2d76, lo: 0x83, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xab, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xac},
+ {value: 0x8132, lo: 0xad, hi: 0xb3},
+ // Block 0x38, offset 0x149
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xaa, hi: 0xab},
+ // Block 0x39, offset 0x14b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xa6, hi: 0xa6},
+ {value: 0x8104, lo: 0xb2, hi: 0xb3},
+ // Block 0x3a, offset 0x14e
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x3b, offset 0x150
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x92},
+ {value: 0x8101, lo: 0x94, hi: 0x94},
+ {value: 0x812d, lo: 0x95, hi: 0x99},
+ {value: 0x8132, lo: 0x9a, hi: 0x9b},
+ {value: 0x812d, lo: 0x9c, hi: 0x9f},
+ {value: 0x8132, lo: 0xa0, hi: 0xa0},
+ {value: 0x8101, lo: 0xa2, hi: 0xa8},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ {value: 0x8132, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb8, hi: 0xb9},
+ // Block 0x3c, offset 0x15b
+ {value: 0x0002, lo: 0x0a},
+ {value: 0x0043, lo: 0xac, hi: 0xac},
+ {value: 0x00d1, lo: 0xad, hi: 0xad},
+ {value: 0x0045, lo: 0xae, hi: 0xae},
+ {value: 0x0049, lo: 0xb0, hi: 0xb1},
+ {value: 0x00e6, lo: 0xb2, hi: 0xb2},
+ {value: 0x004f, lo: 0xb3, hi: 0xba},
+ {value: 0x005f, lo: 0xbc, hi: 0xbc},
+ {value: 0x00ef, lo: 0xbd, hi: 0xbd},
+ {value: 0x0061, lo: 0xbe, hi: 0xbe},
+ {value: 0x0065, lo: 0xbf, hi: 0xbf},
+ // Block 0x3d, offset 0x166
+ {value: 0x0000, lo: 0x0f},
+ {value: 0x8132, lo: 0x80, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x82},
+ {value: 0x8132, lo: 0x83, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8a},
+ {value: 0x8132, lo: 0x8b, hi: 0x8c},
+ {value: 0x8135, lo: 0x8d, hi: 0x8d},
+ {value: 0x812a, lo: 0x8e, hi: 0x8e},
+ {value: 0x812d, lo: 0x8f, hi: 0x8f},
+ {value: 0x8129, lo: 0x90, hi: 0x90},
+ {value: 0x8132, lo: 0x91, hi: 0xb5},
+ {value: 0x8132, lo: 0xbb, hi: 0xbb},
+ {value: 0x8134, lo: 0xbc, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ {value: 0x8132, lo: 0xbe, hi: 0xbe},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x3e, offset 0x176
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x0001, lo: 0x80, hi: 0x8a},
+ {value: 0x043b, lo: 0x91, hi: 0x91},
+ {value: 0x429b, lo: 0x97, hi: 0x97},
+ {value: 0x001d, lo: 0xa4, hi: 0xa4},
+ {value: 0x1873, lo: 0xa5, hi: 0xa5},
+ {value: 0x1b5c, lo: 0xa6, hi: 0xa6},
+ {value: 0x0001, lo: 0xaf, hi: 0xaf},
+ {value: 0x2691, lo: 0xb3, hi: 0xb3},
+ {value: 0x27fe, lo: 0xb4, hi: 0xb4},
+ {value: 0x2698, lo: 0xb6, hi: 0xb6},
+ {value: 0x2808, lo: 0xb7, hi: 0xb7},
+ {value: 0x186d, lo: 0xbc, hi: 0xbc},
+ {value: 0x4269, lo: 0xbe, hi: 0xbe},
+ // Block 0x3f, offset 0x184
+ {value: 0x0002, lo: 0x0d},
+ {value: 0x1933, lo: 0x87, hi: 0x87},
+ {value: 0x1930, lo: 0x88, hi: 0x88},
+ {value: 0x1870, lo: 0x89, hi: 0x89},
+ {value: 0x298e, lo: 0x97, hi: 0x97},
+ {value: 0x0001, lo: 0x9f, hi: 0x9f},
+ {value: 0x0021, lo: 0xb0, hi: 0xb0},
+ {value: 0x0093, lo: 0xb1, hi: 0xb1},
+ {value: 0x0029, lo: 0xb4, hi: 0xb9},
+ {value: 0x0017, lo: 0xba, hi: 0xba},
+ {value: 0x0467, lo: 0xbb, hi: 0xbb},
+ {value: 0x003b, lo: 0xbc, hi: 0xbc},
+ {value: 0x0011, lo: 0xbd, hi: 0xbe},
+ {value: 0x009d, lo: 0xbf, hi: 0xbf},
+ // Block 0x40, offset 0x192
+ {value: 0x0002, lo: 0x0f},
+ {value: 0x0021, lo: 0x80, hi: 0x89},
+ {value: 0x0017, lo: 0x8a, hi: 0x8a},
+ {value: 0x0467, lo: 0x8b, hi: 0x8b},
+ {value: 0x003b, lo: 0x8c, hi: 0x8c},
+ {value: 0x0011, lo: 0x8d, hi: 0x8e},
+ {value: 0x0083, lo: 0x90, hi: 0x90},
+ {value: 0x008b, lo: 0x91, hi: 0x91},
+ {value: 0x009f, lo: 0x92, hi: 0x92},
+ {value: 0x00b1, lo: 0x93, hi: 0x93},
+ {value: 0x0104, lo: 0x94, hi: 0x94},
+ {value: 0x0091, lo: 0x95, hi: 0x95},
+ {value: 0x0097, lo: 0x96, hi: 0x99},
+ {value: 0x00a1, lo: 0x9a, hi: 0x9a},
+ {value: 0x00a7, lo: 0x9b, hi: 0x9c},
+ {value: 0x1999, lo: 0xa8, hi: 0xa8},
+ // Block 0x41, offset 0x1a2
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x8132, lo: 0x90, hi: 0x91},
+ {value: 0x8101, lo: 0x92, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x97},
+ {value: 0x8101, lo: 0x98, hi: 0x9a},
+ {value: 0x8132, lo: 0x9b, hi: 0x9c},
+ {value: 0x8132, lo: 0xa1, hi: 0xa1},
+ {value: 0x8101, lo: 0xa5, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa7},
+ {value: 0x812d, lo: 0xa8, hi: 0xa8},
+ {value: 0x8132, lo: 0xa9, hi: 0xa9},
+ {value: 0x8101, lo: 0xaa, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xaf},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ // Block 0x42, offset 0x1b0
+ {value: 0x0007, lo: 0x06},
+ {value: 0x2180, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
+ {value: 0x3bc7, lo: 0xae, hi: 0xae},
+ // Block 0x43, offset 0x1b7
+ {value: 0x000e, lo: 0x05},
+ {value: 0x3bce, lo: 0x8d, hi: 0x8e},
+ {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ // Block 0x44, offset 0x1bd
+ {value: 0x0173, lo: 0x0e},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0x3be3, lo: 0x84, hi: 0x84},
+ {value: 0xa000, lo: 0x88, hi: 0x88},
+ {value: 0x3bea, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
+ {value: 0xa000, lo: 0xa3, hi: 0xa3},
+ {value: 0x3bf8, lo: 0xa4, hi: 0xa4},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x3bff, lo: 0xa6, hi: 0xa6},
+ {value: 0x269f, lo: 0xac, hi: 0xad},
+ {value: 0x26a6, lo: 0xaf, hi: 0xaf},
+ {value: 0x281c, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xbc, hi: 0xbc},
+ // Block 0x45, offset 0x1cc
+ {value: 0x0007, lo: 0x03},
+ {value: 0x3c68, lo: 0xa0, hi: 0xa1},
+ {value: 0x3c92, lo: 0xa2, hi: 0xa3},
+ {value: 0x3cbc, lo: 0xaa, hi: 0xad},
+ // Block 0x46, offset 0x1d0
+ {value: 0x0004, lo: 0x01},
+ {value: 0x048b, lo: 0xa9, hi: 0xaa},
+ // Block 0x47, offset 0x1d2
+ {value: 0x0002, lo: 0x03},
+ {value: 0x0057, lo: 0x80, hi: 0x8f},
+ {value: 0x0083, lo: 0x90, hi: 0xa9},
+ {value: 0x0021, lo: 0xaa, hi: 0xaa},
+ // Block 0x48, offset 0x1d6
+ {value: 0x0000, lo: 0x01},
+ {value: 0x299b, lo: 0x8c, hi: 0x8c},
+ // Block 0x49, offset 0x1d8
+ {value: 0x0263, lo: 0x02},
+ {value: 0x1b8c, lo: 0xb4, hi: 0xb4},
+ {value: 0x192d, lo: 0xb5, hi: 0xb6},
+ // Block 0x4a, offset 0x1db
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4573, lo: 0x9c, hi: 0x9c},
+ // Block 0x4b, offset 0x1dd
+ {value: 0x0000, lo: 0x02},
+ {value: 0x0095, lo: 0xbc, hi: 0xbc},
+ {value: 0x006d, lo: 0xbd, hi: 0xbd},
+ // Block 0x4c, offset 0x1e0
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xaf, hi: 0xb1},
+ // Block 0x4d, offset 0x1e2
+ {value: 0x0000, lo: 0x02},
+ {value: 0x047f, lo: 0xaf, hi: 0xaf},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x4e, offset 0x1e5
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xa0, hi: 0xbf},
+ // Block 0x4f, offset 0x1e7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x0dc3, lo: 0x9f, hi: 0x9f},
+ // Block 0x50, offset 0x1e9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x162f, lo: 0xb3, hi: 0xb3},
+ // Block 0x51, offset 0x1eb
+ {value: 0x0004, lo: 0x0b},
+ {value: 0x1597, lo: 0x80, hi: 0x82},
+ {value: 0x15af, lo: 0x83, hi: 0x83},
+ {value: 0x15c7, lo: 0x84, hi: 0x85},
+ {value: 0x15d7, lo: 0x86, hi: 0x89},
+ {value: 0x15eb, lo: 0x8a, hi: 0x8c},
+ {value: 0x15ff, lo: 0x8d, hi: 0x8d},
+ {value: 0x1607, lo: 0x8e, hi: 0x8e},
+ {value: 0x160f, lo: 0x8f, hi: 0x90},
+ {value: 0x161b, lo: 0x91, hi: 0x93},
+ {value: 0x162b, lo: 0x94, hi: 0x94},
+ {value: 0x1633, lo: 0x95, hi: 0x95},
+ // Block 0x52, offset 0x1f7
+ {value: 0x0004, lo: 0x09},
+ {value: 0x0001, lo: 0x80, hi: 0x80},
+ {value: 0x812c, lo: 0xaa, hi: 0xaa},
+ {value: 0x8131, lo: 0xab, hi: 0xab},
+ {value: 0x8133, lo: 0xac, hi: 0xac},
+ {value: 0x812e, lo: 0xad, hi: 0xad},
+ {value: 0x812f, lo: 0xae, hi: 0xae},
+ {value: 0x812f, lo: 0xaf, hi: 0xaf},
+ {value: 0x04b3, lo: 0xb6, hi: 0xb6},
+ {value: 0x0887, lo: 0xb8, hi: 0xba},
+ // Block 0x53, offset 0x201
+ {value: 0x0005, lo: 0x09},
+ {value: 0x0313, lo: 0xb1, hi: 0xb1},
+ {value: 0x0317, lo: 0xb2, hi: 0xb2},
+ {value: 0x4345, lo: 0xb3, hi: 0xb3},
+ {value: 0x031b, lo: 0xb4, hi: 0xb4},
+ {value: 0x434a, lo: 0xb5, hi: 0xb6},
+ {value: 0x031f, lo: 0xb7, hi: 0xb7},
+ {value: 0x0323, lo: 0xb8, hi: 0xb8},
+ {value: 0x0327, lo: 0xb9, hi: 0xb9},
+ {value: 0x4354, lo: 0xba, hi: 0xbf},
+ // Block 0x54, offset 0x20b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xaf, hi: 0xaf},
+ {value: 0x8132, lo: 0xb4, hi: 0xbd},
+ // Block 0x55, offset 0x20e
+ {value: 0x0000, lo: 0x03},
+ {value: 0x020f, lo: 0x9c, hi: 0x9c},
+ {value: 0x0212, lo: 0x9d, hi: 0x9d},
+ {value: 0x8132, lo: 0x9e, hi: 0x9f},
+ // Block 0x56, offset 0x212
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb1},
+ // Block 0x57, offset 0x214
+ {value: 0x0000, lo: 0x01},
+ {value: 0x163b, lo: 0xb0, hi: 0xb0},
+ // Block 0x58, offset 0x216
+ {value: 0x000c, lo: 0x01},
+ {value: 0x00d7, lo: 0xb8, hi: 0xb9},
+ // Block 0x59, offset 0x218
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ // Block 0x5a, offset 0x21a
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xa0, hi: 0xb1},
+ // Block 0x5b, offset 0x21d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xab, hi: 0xad},
+ // Block 0x5c, offset 0x21f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x93, hi: 0x93},
+ // Block 0x5d, offset 0x221
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb3, hi: 0xb3},
+ // Block 0x5e, offset 0x223
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ // Block 0x5f, offset 0x225
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x8132, lo: 0xbe, hi: 0xbf},
+ // Block 0x60, offset 0x22b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ // Block 0x61, offset 0x22e
+ {value: 0x0008, lo: 0x03},
+ {value: 0x1637, lo: 0x9c, hi: 0x9d},
+ {value: 0x0125, lo: 0x9e, hi: 0x9e},
+ {value: 0x1643, lo: 0x9f, hi: 0x9f},
+ // Block 0x62, offset 0x232
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xad, hi: 0xad},
+ // Block 0x63, offset 0x234
+ {value: 0x0000, lo: 0x06},
+ {value: 0xe500, lo: 0x80, hi: 0x80},
+ {value: 0xc600, lo: 0x81, hi: 0x9b},
+ {value: 0xe500, lo: 0x9c, hi: 0x9c},
+ {value: 0xc600, lo: 0x9d, hi: 0xb7},
+ {value: 0xe500, lo: 0xb8, hi: 0xb8},
+ {value: 0xc600, lo: 0xb9, hi: 0xbf},
+ // Block 0x64, offset 0x23b
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x93},
+ {value: 0xe500, lo: 0x94, hi: 0x94},
+ {value: 0xc600, lo: 0x95, hi: 0xaf},
+ {value: 0xe500, lo: 0xb0, hi: 0xb0},
+ {value: 0xc600, lo: 0xb1, hi: 0xbf},
+ // Block 0x65, offset 0x241
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8b},
+ {value: 0xe500, lo: 0x8c, hi: 0x8c},
+ {value: 0xc600, lo: 0x8d, hi: 0xa7},
+ {value: 0xe500, lo: 0xa8, hi: 0xa8},
+ {value: 0xc600, lo: 0xa9, hi: 0xbf},
+ // Block 0x66, offset 0x247
+ {value: 0x0000, lo: 0x07},
+ {value: 0xc600, lo: 0x80, hi: 0x83},
+ {value: 0xe500, lo: 0x84, hi: 0x84},
+ {value: 0xc600, lo: 0x85, hi: 0x9f},
+ {value: 0xe500, lo: 0xa0, hi: 0xa0},
+ {value: 0xc600, lo: 0xa1, hi: 0xbb},
+ {value: 0xe500, lo: 0xbc, hi: 0xbc},
+ {value: 0xc600, lo: 0xbd, hi: 0xbf},
+ // Block 0x67, offset 0x24f
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x97},
+ {value: 0xe500, lo: 0x98, hi: 0x98},
+ {value: 0xc600, lo: 0x99, hi: 0xb3},
+ {value: 0xe500, lo: 0xb4, hi: 0xb4},
+ {value: 0xc600, lo: 0xb5, hi: 0xbf},
+ // Block 0x68, offset 0x255
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8f},
+ {value: 0xe500, lo: 0x90, hi: 0x90},
+ {value: 0xc600, lo: 0x91, hi: 0xab},
+ {value: 0xe500, lo: 0xac, hi: 0xac},
+ {value: 0xc600, lo: 0xad, hi: 0xbf},
+ // Block 0x69, offset 0x25b
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ {value: 0xe500, lo: 0xa4, hi: 0xa4},
+ {value: 0xc600, lo: 0xa5, hi: 0xbf},
+ // Block 0x6a, offset 0x261
+ {value: 0x0000, lo: 0x03},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ // Block 0x6b, offset 0x265
+ {value: 0x0002, lo: 0x01},
+ {value: 0x0003, lo: 0x81, hi: 0xbf},
+ // Block 0x6c, offset 0x267
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x6d, offset 0x269
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xa0, hi: 0xa0},
+ // Block 0x6e, offset 0x26b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb6, hi: 0xba},
+ // Block 0x6f, offset 0x26d
+ {value: 0x002c, lo: 0x05},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x8f, hi: 0x8f},
+ {value: 0x8132, lo: 0xb8, hi: 0xb8},
+ {value: 0x8101, lo: 0xb9, hi: 0xba},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x70, offset 0x273
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xa5, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ // Block 0x71, offset 0x276
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x72, offset 0x279
+ {value: 0x17fe, lo: 0x07},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x4238, lo: 0x9a, hi: 0x9a},
+ {value: 0xa000, lo: 0x9b, hi: 0x9b},
+ {value: 0x4242, lo: 0x9c, hi: 0x9c},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x424c, lo: 0xab, hi: 0xab},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x73, offset 0x281
+ {value: 0x0000, lo: 0x06},
+ {value: 0x8132, lo: 0x80, hi: 0x82},
+ {value: 0x9900, lo: 0xa7, hi: 0xa7},
+ {value: 0x2d7e, lo: 0xae, hi: 0xae},
+ {value: 0x2d88, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb1, hi: 0xb2},
+ {value: 0x8104, lo: 0xb3, hi: 0xb4},
+ // Block 0x74, offset 0x288
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x75, offset 0x28b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb5, hi: 0xb5},
+ {value: 0x8102, lo: 0xb6, hi: 0xb6},
+ // Block 0x76, offset 0x28e
+ {value: 0x0002, lo: 0x01},
+ {value: 0x8102, lo: 0xa9, hi: 0xaa},
+ // Block 0x77, offset 0x290
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2d92, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x8132, lo: 0xa6, hi: 0xac},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ // Block 0x78, offset 0x298
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x86, hi: 0x86},
+ // Block 0x79, offset 0x29b
+ {value: 0x6b5a, lo: 0x06},
+ {value: 0x9900, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xb9, hi: 0xb9},
+ {value: 0x9900, lo: 0xba, hi: 0xba},
+ {value: 0x2db0, lo: 0xbb, hi: 0xbb},
+ {value: 0x2da6, lo: 0xbc, hi: 0xbd},
+ {value: 0x2dba, lo: 0xbe, hi: 0xbe},
+ // Block 0x7a, offset 0x2a2
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x83, hi: 0x83},
+ // Block 0x7b, offset 0x2a5
+ {value: 0x0000, lo: 0x05},
+ {value: 0x9900, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb8, hi: 0xb9},
+ {value: 0x2dc4, lo: 0xba, hi: 0xba},
+ {value: 0x2dce, lo: 0xbb, hi: 0xbb},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x7c, offset 0x2ab
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0x80, hi: 0x80},
+ // Block 0x7d, offset 0x2ad
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x7e, offset 0x2af
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x7f, offset 0x2b2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xab, hi: 0xab},
+ // Block 0x80, offset 0x2b4
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0xb0, hi: 0xb4},
+ // Block 0x81, offset 0x2b6
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb6},
+ // Block 0x82, offset 0x2b8
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0x9e, hi: 0x9e},
+ // Block 0x83, offset 0x2ba
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x4662, lo: 0x9e, hi: 0x9e},
+ {value: 0x466c, lo: 0x9f, hi: 0x9f},
+ {value: 0x46a0, lo: 0xa0, hi: 0xa0},
+ {value: 0x46ae, lo: 0xa1, hi: 0xa1},
+ {value: 0x46bc, lo: 0xa2, hi: 0xa2},
+ {value: 0x46ca, lo: 0xa3, hi: 0xa3},
+ {value: 0x46d8, lo: 0xa4, hi: 0xa4},
+ {value: 0x812b, lo: 0xa5, hi: 0xa6},
+ {value: 0x8101, lo: 0xa7, hi: 0xa9},
+ {value: 0x8130, lo: 0xad, hi: 0xad},
+ {value: 0x812b, lo: 0xae, hi: 0xb2},
+ {value: 0x812d, lo: 0xbb, hi: 0xbf},
+ // Block 0x84, offset 0x2c7
+ {value: 0x0000, lo: 0x09},
+ {value: 0x812d, lo: 0x80, hi: 0x82},
+ {value: 0x8132, lo: 0x85, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8b},
+ {value: 0x8132, lo: 0xaa, hi: 0xad},
+ {value: 0x4676, lo: 0xbb, hi: 0xbb},
+ {value: 0x4680, lo: 0xbc, hi: 0xbc},
+ {value: 0x46e6, lo: 0xbd, hi: 0xbd},
+ {value: 0x4702, lo: 0xbe, hi: 0xbe},
+ {value: 0x46f4, lo: 0xbf, hi: 0xbf},
+ // Block 0x85, offset 0x2d1
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4710, lo: 0x80, hi: 0x80},
+ // Block 0x86, offset 0x2d3
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x82, hi: 0x84},
+ // Block 0x87, offset 0x2d5
+ {value: 0x0002, lo: 0x03},
+ {value: 0x0043, lo: 0x80, hi: 0x99},
+ {value: 0x0083, lo: 0x9a, hi: 0xb3},
+ {value: 0x0043, lo: 0xb4, hi: 0xbf},
+ // Block 0x88, offset 0x2d9
+ {value: 0x0002, lo: 0x04},
+ {value: 0x005b, lo: 0x80, hi: 0x8d},
+ {value: 0x0083, lo: 0x8e, hi: 0x94},
+ {value: 0x0093, lo: 0x96, hi: 0xa7},
+ {value: 0x0043, lo: 0xa8, hi: 0xbf},
+ // Block 0x89, offset 0x2de
+ {value: 0x0002, lo: 0x0b},
+ {value: 0x0073, lo: 0x80, hi: 0x81},
+ {value: 0x0083, lo: 0x82, hi: 0x9b},
+ {value: 0x0043, lo: 0x9c, hi: 0x9c},
+ {value: 0x0047, lo: 0x9e, hi: 0x9f},
+ {value: 0x004f, lo: 0xa2, hi: 0xa2},
+ {value: 0x0055, lo: 0xa5, hi: 0xa6},
+ {value: 0x005d, lo: 0xa9, hi: 0xac},
+ {value: 0x0067, lo: 0xae, hi: 0xb5},
+ {value: 0x0083, lo: 0xb6, hi: 0xb9},
+ {value: 0x008d, lo: 0xbb, hi: 0xbb},
+ {value: 0x0091, lo: 0xbd, hi: 0xbf},
+ // Block 0x8a, offset 0x2ea
+ {value: 0x0002, lo: 0x04},
+ {value: 0x0097, lo: 0x80, hi: 0x83},
+ {value: 0x00a1, lo: 0x85, hi: 0x8f},
+ {value: 0x0043, lo: 0x90, hi: 0xa9},
+ {value: 0x0083, lo: 0xaa, hi: 0xbf},
+ // Block 0x8b, offset 0x2ef
+ {value: 0x0002, lo: 0x08},
+ {value: 0x00af, lo: 0x80, hi: 0x83},
+ {value: 0x0043, lo: 0x84, hi: 0x85},
+ {value: 0x0049, lo: 0x87, hi: 0x8a},
+ {value: 0x0055, lo: 0x8d, hi: 0x94},
+ {value: 0x0067, lo: 0x96, hi: 0x9c},
+ {value: 0x0083, lo: 0x9e, hi: 0xb7},
+ {value: 0x0043, lo: 0xb8, hi: 0xb9},
+ {value: 0x0049, lo: 0xbb, hi: 0xbe},
+ // Block 0x8c, offset 0x2f8
+ {value: 0x0002, lo: 0x05},
+ {value: 0x0053, lo: 0x80, hi: 0x84},
+ {value: 0x005f, lo: 0x86, hi: 0x86},
+ {value: 0x0067, lo: 0x8a, hi: 0x90},
+ {value: 0x0083, lo: 0x92, hi: 0xab},
+ {value: 0x0043, lo: 0xac, hi: 0xbf},
+ // Block 0x8d, offset 0x2fe
+ {value: 0x0002, lo: 0x04},
+ {value: 0x006b, lo: 0x80, hi: 0x85},
+ {value: 0x0083, lo: 0x86, hi: 0x9f},
+ {value: 0x0043, lo: 0xa0, hi: 0xb9},
+ {value: 0x0083, lo: 0xba, hi: 0xbf},
+ // Block 0x8e, offset 0x303
+ {value: 0x0002, lo: 0x03},
+ {value: 0x008f, lo: 0x80, hi: 0x93},
+ {value: 0x0043, lo: 0x94, hi: 0xad},
+ {value: 0x0083, lo: 0xae, hi: 0xbf},
+ // Block 0x8f, offset 0x307
+ {value: 0x0002, lo: 0x04},
+ {value: 0x00a7, lo: 0x80, hi: 0x87},
+ {value: 0x0043, lo: 0x88, hi: 0xa1},
+ {value: 0x0083, lo: 0xa2, hi: 0xbb},
+ {value: 0x0043, lo: 0xbc, hi: 0xbf},
+ // Block 0x90, offset 0x30c
+ {value: 0x0002, lo: 0x03},
+ {value: 0x004b, lo: 0x80, hi: 0x95},
+ {value: 0x0083, lo: 0x96, hi: 0xaf},
+ {value: 0x0043, lo: 0xb0, hi: 0xbf},
+ // Block 0x91, offset 0x310
+ {value: 0x0003, lo: 0x0f},
+ {value: 0x01b8, lo: 0x80, hi: 0x80},
+ {value: 0x045f, lo: 0x81, hi: 0x81},
+ {value: 0x01bb, lo: 0x82, hi: 0x9a},
+ {value: 0x045b, lo: 0x9b, hi: 0x9b},
+ {value: 0x01c7, lo: 0x9c, hi: 0x9c},
+ {value: 0x01d0, lo: 0x9d, hi: 0x9d},
+ {value: 0x01d6, lo: 0x9e, hi: 0x9e},
+ {value: 0x01fa, lo: 0x9f, hi: 0x9f},
+ {value: 0x01eb, lo: 0xa0, hi: 0xa0},
+ {value: 0x01e8, lo: 0xa1, hi: 0xa1},
+ {value: 0x0173, lo: 0xa2, hi: 0xb2},
+ {value: 0x0188, lo: 0xb3, hi: 0xb3},
+ {value: 0x01a6, lo: 0xb4, hi: 0xba},
+ {value: 0x045f, lo: 0xbb, hi: 0xbb},
+ {value: 0x01bb, lo: 0xbc, hi: 0xbf},
+ // Block 0x92, offset 0x320
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01c7, lo: 0x80, hi: 0x94},
+ {value: 0x045b, lo: 0x95, hi: 0x95},
+ {value: 0x01c7, lo: 0x96, hi: 0x96},
+ {value: 0x01d0, lo: 0x97, hi: 0x97},
+ {value: 0x01d6, lo: 0x98, hi: 0x98},
+ {value: 0x01fa, lo: 0x99, hi: 0x99},
+ {value: 0x01eb, lo: 0x9a, hi: 0x9a},
+ {value: 0x01e8, lo: 0x9b, hi: 0x9b},
+ {value: 0x0173, lo: 0x9c, hi: 0xac},
+ {value: 0x0188, lo: 0xad, hi: 0xad},
+ {value: 0x01a6, lo: 0xae, hi: 0xb4},
+ {value: 0x045f, lo: 0xb5, hi: 0xb5},
+ {value: 0x01bb, lo: 0xb6, hi: 0xbf},
+ // Block 0x93, offset 0x32e
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01d9, lo: 0x80, hi: 0x8e},
+ {value: 0x045b, lo: 0x8f, hi: 0x8f},
+ {value: 0x01c7, lo: 0x90, hi: 0x90},
+ {value: 0x01d0, lo: 0x91, hi: 0x91},
+ {value: 0x01d6, lo: 0x92, hi: 0x92},
+ {value: 0x01fa, lo: 0x93, hi: 0x93},
+ {value: 0x01eb, lo: 0x94, hi: 0x94},
+ {value: 0x01e8, lo: 0x95, hi: 0x95},
+ {value: 0x0173, lo: 0x96, hi: 0xa6},
+ {value: 0x0188, lo: 0xa7, hi: 0xa7},
+ {value: 0x01a6, lo: 0xa8, hi: 0xae},
+ {value: 0x045f, lo: 0xaf, hi: 0xaf},
+ {value: 0x01bb, lo: 0xb0, hi: 0xbf},
+ // Block 0x94, offset 0x33c
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01eb, lo: 0x80, hi: 0x88},
+ {value: 0x045b, lo: 0x89, hi: 0x89},
+ {value: 0x01c7, lo: 0x8a, hi: 0x8a},
+ {value: 0x01d0, lo: 0x8b, hi: 0x8b},
+ {value: 0x01d6, lo: 0x8c, hi: 0x8c},
+ {value: 0x01fa, lo: 0x8d, hi: 0x8d},
+ {value: 0x01eb, lo: 0x8e, hi: 0x8e},
+ {value: 0x01e8, lo: 0x8f, hi: 0x8f},
+ {value: 0x0173, lo: 0x90, hi: 0xa0},
+ {value: 0x0188, lo: 0xa1, hi: 0xa1},
+ {value: 0x01a6, lo: 0xa2, hi: 0xa8},
+ {value: 0x045f, lo: 0xa9, hi: 0xa9},
+ {value: 0x01bb, lo: 0xaa, hi: 0xbf},
+ // Block 0x95, offset 0x34a
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0x80, hi: 0x86},
+ {value: 0x8132, lo: 0x88, hi: 0x98},
+ {value: 0x8132, lo: 0x9b, hi: 0xa1},
+ {value: 0x8132, lo: 0xa3, hi: 0xa4},
+ {value: 0x8132, lo: 0xa6, hi: 0xaa},
+ // Block 0x96, offset 0x350
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x90, hi: 0x96},
+ // Block 0x97, offset 0x352
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x84, hi: 0x89},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x98, offset 0x355
+ {value: 0x0002, lo: 0x09},
+ {value: 0x0063, lo: 0x80, hi: 0x89},
+ {value: 0x1951, lo: 0x8a, hi: 0x8a},
+ {value: 0x1981, lo: 0x8b, hi: 0x8b},
+ {value: 0x199c, lo: 0x8c, hi: 0x8c},
+ {value: 0x19a2, lo: 0x8d, hi: 0x8d},
+ {value: 0x1bc0, lo: 0x8e, hi: 0x8e},
+ {value: 0x19ae, lo: 0x8f, hi: 0x8f},
+ {value: 0x197b, lo: 0xaa, hi: 0xaa},
+ {value: 0x197e, lo: 0xab, hi: 0xab},
+ // Block 0x99, offset 0x35f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x193f, lo: 0x90, hi: 0x90},
+ // Block 0x9a, offset 0x361
+ {value: 0x0028, lo: 0x09},
+ {value: 0x2862, lo: 0x80, hi: 0x80},
+ {value: 0x2826, lo: 0x81, hi: 0x81},
+ {value: 0x2830, lo: 0x82, hi: 0x82},
+ {value: 0x2844, lo: 0x83, hi: 0x84},
+ {value: 0x284e, lo: 0x85, hi: 0x86},
+ {value: 0x283a, lo: 0x87, hi: 0x87},
+ {value: 0x2858, lo: 0x88, hi: 0x88},
+ {value: 0x0b6f, lo: 0x90, hi: 0x90},
+ {value: 0x08e7, lo: 0x91, hi: 0x91},
+}
+
+// recompMap: 7520 bytes (entries only)
+var recompMap = map[uint32]rune{
+ 0x00410300: 0x00C0,
+ 0x00410301: 0x00C1,
+ 0x00410302: 0x00C2,
+ 0x00410303: 0x00C3,
+ 0x00410308: 0x00C4,
+ 0x0041030A: 0x00C5,
+ 0x00430327: 0x00C7,
+ 0x00450300: 0x00C8,
+ 0x00450301: 0x00C9,
+ 0x00450302: 0x00CA,
+ 0x00450308: 0x00CB,
+ 0x00490300: 0x00CC,
+ 0x00490301: 0x00CD,
+ 0x00490302: 0x00CE,
+ 0x00490308: 0x00CF,
+ 0x004E0303: 0x00D1,
+ 0x004F0300: 0x00D2,
+ 0x004F0301: 0x00D3,
+ 0x004F0302: 0x00D4,
+ 0x004F0303: 0x00D5,
+ 0x004F0308: 0x00D6,
+ 0x00550300: 0x00D9,
+ 0x00550301: 0x00DA,
+ 0x00550302: 0x00DB,
+ 0x00550308: 0x00DC,
+ 0x00590301: 0x00DD,
+ 0x00610300: 0x00E0,
+ 0x00610301: 0x00E1,
+ 0x00610302: 0x00E2,
+ 0x00610303: 0x00E3,
+ 0x00610308: 0x00E4,
+ 0x0061030A: 0x00E5,
+ 0x00630327: 0x00E7,
+ 0x00650300: 0x00E8,
+ 0x00650301: 0x00E9,
+ 0x00650302: 0x00EA,
+ 0x00650308: 0x00EB,
+ 0x00690300: 0x00EC,
+ 0x00690301: 0x00ED,
+ 0x00690302: 0x00EE,
+ 0x00690308: 0x00EF,
+ 0x006E0303: 0x00F1,
+ 0x006F0300: 0x00F2,
+ 0x006F0301: 0x00F3,
+ 0x006F0302: 0x00F4,
+ 0x006F0303: 0x00F5,
+ 0x006F0308: 0x00F6,
+ 0x00750300: 0x00F9,
+ 0x00750301: 0x00FA,
+ 0x00750302: 0x00FB,
+ 0x00750308: 0x00FC,
+ 0x00790301: 0x00FD,
+ 0x00790308: 0x00FF,
+ 0x00410304: 0x0100,
+ 0x00610304: 0x0101,
+ 0x00410306: 0x0102,
+ 0x00610306: 0x0103,
+ 0x00410328: 0x0104,
+ 0x00610328: 0x0105,
+ 0x00430301: 0x0106,
+ 0x00630301: 0x0107,
+ 0x00430302: 0x0108,
+ 0x00630302: 0x0109,
+ 0x00430307: 0x010A,
+ 0x00630307: 0x010B,
+ 0x0043030C: 0x010C,
+ 0x0063030C: 0x010D,
+ 0x0044030C: 0x010E,
+ 0x0064030C: 0x010F,
+ 0x00450304: 0x0112,
+ 0x00650304: 0x0113,
+ 0x00450306: 0x0114,
+ 0x00650306: 0x0115,
+ 0x00450307: 0x0116,
+ 0x00650307: 0x0117,
+ 0x00450328: 0x0118,
+ 0x00650328: 0x0119,
+ 0x0045030C: 0x011A,
+ 0x0065030C: 0x011B,
+ 0x00470302: 0x011C,
+ 0x00670302: 0x011D,
+ 0x00470306: 0x011E,
+ 0x00670306: 0x011F,
+ 0x00470307: 0x0120,
+ 0x00670307: 0x0121,
+ 0x00470327: 0x0122,
+ 0x00670327: 0x0123,
+ 0x00480302: 0x0124,
+ 0x00680302: 0x0125,
+ 0x00490303: 0x0128,
+ 0x00690303: 0x0129,
+ 0x00490304: 0x012A,
+ 0x00690304: 0x012B,
+ 0x00490306: 0x012C,
+ 0x00690306: 0x012D,
+ 0x00490328: 0x012E,
+ 0x00690328: 0x012F,
+ 0x00490307: 0x0130,
+ 0x004A0302: 0x0134,
+ 0x006A0302: 0x0135,
+ 0x004B0327: 0x0136,
+ 0x006B0327: 0x0137,
+ 0x004C0301: 0x0139,
+ 0x006C0301: 0x013A,
+ 0x004C0327: 0x013B,
+ 0x006C0327: 0x013C,
+ 0x004C030C: 0x013D,
+ 0x006C030C: 0x013E,
+ 0x004E0301: 0x0143,
+ 0x006E0301: 0x0144,
+ 0x004E0327: 0x0145,
+ 0x006E0327: 0x0146,
+ 0x004E030C: 0x0147,
+ 0x006E030C: 0x0148,
+ 0x004F0304: 0x014C,
+ 0x006F0304: 0x014D,
+ 0x004F0306: 0x014E,
+ 0x006F0306: 0x014F,
+ 0x004F030B: 0x0150,
+ 0x006F030B: 0x0151,
+ 0x00520301: 0x0154,
+ 0x00720301: 0x0155,
+ 0x00520327: 0x0156,
+ 0x00720327: 0x0157,
+ 0x0052030C: 0x0158,
+ 0x0072030C: 0x0159,
+ 0x00530301: 0x015A,
+ 0x00730301: 0x015B,
+ 0x00530302: 0x015C,
+ 0x00730302: 0x015D,
+ 0x00530327: 0x015E,
+ 0x00730327: 0x015F,
+ 0x0053030C: 0x0160,
+ 0x0073030C: 0x0161,
+ 0x00540327: 0x0162,
+ 0x00740327: 0x0163,
+ 0x0054030C: 0x0164,
+ 0x0074030C: 0x0165,
+ 0x00550303: 0x0168,
+ 0x00750303: 0x0169,
+ 0x00550304: 0x016A,
+ 0x00750304: 0x016B,
+ 0x00550306: 0x016C,
+ 0x00750306: 0x016D,
+ 0x0055030A: 0x016E,
+ 0x0075030A: 0x016F,
+ 0x0055030B: 0x0170,
+ 0x0075030B: 0x0171,
+ 0x00550328: 0x0172,
+ 0x00750328: 0x0173,
+ 0x00570302: 0x0174,
+ 0x00770302: 0x0175,
+ 0x00590302: 0x0176,
+ 0x00790302: 0x0177,
+ 0x00590308: 0x0178,
+ 0x005A0301: 0x0179,
+ 0x007A0301: 0x017A,
+ 0x005A0307: 0x017B,
+ 0x007A0307: 0x017C,
+ 0x005A030C: 0x017D,
+ 0x007A030C: 0x017E,
+ 0x004F031B: 0x01A0,
+ 0x006F031B: 0x01A1,
+ 0x0055031B: 0x01AF,
+ 0x0075031B: 0x01B0,
+ 0x0041030C: 0x01CD,
+ 0x0061030C: 0x01CE,
+ 0x0049030C: 0x01CF,
+ 0x0069030C: 0x01D0,
+ 0x004F030C: 0x01D1,
+ 0x006F030C: 0x01D2,
+ 0x0055030C: 0x01D3,
+ 0x0075030C: 0x01D4,
+ 0x00DC0304: 0x01D5,
+ 0x00FC0304: 0x01D6,
+ 0x00DC0301: 0x01D7,
+ 0x00FC0301: 0x01D8,
+ 0x00DC030C: 0x01D9,
+ 0x00FC030C: 0x01DA,
+ 0x00DC0300: 0x01DB,
+ 0x00FC0300: 0x01DC,
+ 0x00C40304: 0x01DE,
+ 0x00E40304: 0x01DF,
+ 0x02260304: 0x01E0,
+ 0x02270304: 0x01E1,
+ 0x00C60304: 0x01E2,
+ 0x00E60304: 0x01E3,
+ 0x0047030C: 0x01E6,
+ 0x0067030C: 0x01E7,
+ 0x004B030C: 0x01E8,
+ 0x006B030C: 0x01E9,
+ 0x004F0328: 0x01EA,
+ 0x006F0328: 0x01EB,
+ 0x01EA0304: 0x01EC,
+ 0x01EB0304: 0x01ED,
+ 0x01B7030C: 0x01EE,
+ 0x0292030C: 0x01EF,
+ 0x006A030C: 0x01F0,
+ 0x00470301: 0x01F4,
+ 0x00670301: 0x01F5,
+ 0x004E0300: 0x01F8,
+ 0x006E0300: 0x01F9,
+ 0x00C50301: 0x01FA,
+ 0x00E50301: 0x01FB,
+ 0x00C60301: 0x01FC,
+ 0x00E60301: 0x01FD,
+ 0x00D80301: 0x01FE,
+ 0x00F80301: 0x01FF,
+ 0x0041030F: 0x0200,
+ 0x0061030F: 0x0201,
+ 0x00410311: 0x0202,
+ 0x00610311: 0x0203,
+ 0x0045030F: 0x0204,
+ 0x0065030F: 0x0205,
+ 0x00450311: 0x0206,
+ 0x00650311: 0x0207,
+ 0x0049030F: 0x0208,
+ 0x0069030F: 0x0209,
+ 0x00490311: 0x020A,
+ 0x00690311: 0x020B,
+ 0x004F030F: 0x020C,
+ 0x006F030F: 0x020D,
+ 0x004F0311: 0x020E,
+ 0x006F0311: 0x020F,
+ 0x0052030F: 0x0210,
+ 0x0072030F: 0x0211,
+ 0x00520311: 0x0212,
+ 0x00720311: 0x0213,
+ 0x0055030F: 0x0214,
+ 0x0075030F: 0x0215,
+ 0x00550311: 0x0216,
+ 0x00750311: 0x0217,
+ 0x00530326: 0x0218,
+ 0x00730326: 0x0219,
+ 0x00540326: 0x021A,
+ 0x00740326: 0x021B,
+ 0x0048030C: 0x021E,
+ 0x0068030C: 0x021F,
+ 0x00410307: 0x0226,
+ 0x00610307: 0x0227,
+ 0x00450327: 0x0228,
+ 0x00650327: 0x0229,
+ 0x00D60304: 0x022A,
+ 0x00F60304: 0x022B,
+ 0x00D50304: 0x022C,
+ 0x00F50304: 0x022D,
+ 0x004F0307: 0x022E,
+ 0x006F0307: 0x022F,
+ 0x022E0304: 0x0230,
+ 0x022F0304: 0x0231,
+ 0x00590304: 0x0232,
+ 0x00790304: 0x0233,
+ 0x00A80301: 0x0385,
+ 0x03910301: 0x0386,
+ 0x03950301: 0x0388,
+ 0x03970301: 0x0389,
+ 0x03990301: 0x038A,
+ 0x039F0301: 0x038C,
+ 0x03A50301: 0x038E,
+ 0x03A90301: 0x038F,
+ 0x03CA0301: 0x0390,
+ 0x03990308: 0x03AA,
+ 0x03A50308: 0x03AB,
+ 0x03B10301: 0x03AC,
+ 0x03B50301: 0x03AD,
+ 0x03B70301: 0x03AE,
+ 0x03B90301: 0x03AF,
+ 0x03CB0301: 0x03B0,
+ 0x03B90308: 0x03CA,
+ 0x03C50308: 0x03CB,
+ 0x03BF0301: 0x03CC,
+ 0x03C50301: 0x03CD,
+ 0x03C90301: 0x03CE,
+ 0x03D20301: 0x03D3,
+ 0x03D20308: 0x03D4,
+ 0x04150300: 0x0400,
+ 0x04150308: 0x0401,
+ 0x04130301: 0x0403,
+ 0x04060308: 0x0407,
+ 0x041A0301: 0x040C,
+ 0x04180300: 0x040D,
+ 0x04230306: 0x040E,
+ 0x04180306: 0x0419,
+ 0x04380306: 0x0439,
+ 0x04350300: 0x0450,
+ 0x04350308: 0x0451,
+ 0x04330301: 0x0453,
+ 0x04560308: 0x0457,
+ 0x043A0301: 0x045C,
+ 0x04380300: 0x045D,
+ 0x04430306: 0x045E,
+ 0x0474030F: 0x0476,
+ 0x0475030F: 0x0477,
+ 0x04160306: 0x04C1,
+ 0x04360306: 0x04C2,
+ 0x04100306: 0x04D0,
+ 0x04300306: 0x04D1,
+ 0x04100308: 0x04D2,
+ 0x04300308: 0x04D3,
+ 0x04150306: 0x04D6,
+ 0x04350306: 0x04D7,
+ 0x04D80308: 0x04DA,
+ 0x04D90308: 0x04DB,
+ 0x04160308: 0x04DC,
+ 0x04360308: 0x04DD,
+ 0x04170308: 0x04DE,
+ 0x04370308: 0x04DF,
+ 0x04180304: 0x04E2,
+ 0x04380304: 0x04E3,
+ 0x04180308: 0x04E4,
+ 0x04380308: 0x04E5,
+ 0x041E0308: 0x04E6,
+ 0x043E0308: 0x04E7,
+ 0x04E80308: 0x04EA,
+ 0x04E90308: 0x04EB,
+ 0x042D0308: 0x04EC,
+ 0x044D0308: 0x04ED,
+ 0x04230304: 0x04EE,
+ 0x04430304: 0x04EF,
+ 0x04230308: 0x04F0,
+ 0x04430308: 0x04F1,
+ 0x0423030B: 0x04F2,
+ 0x0443030B: 0x04F3,
+ 0x04270308: 0x04F4,
+ 0x04470308: 0x04F5,
+ 0x042B0308: 0x04F8,
+ 0x044B0308: 0x04F9,
+ 0x06270653: 0x0622,
+ 0x06270654: 0x0623,
+ 0x06480654: 0x0624,
+ 0x06270655: 0x0625,
+ 0x064A0654: 0x0626,
+ 0x06D50654: 0x06C0,
+ 0x06C10654: 0x06C2,
+ 0x06D20654: 0x06D3,
+ 0x0928093C: 0x0929,
+ 0x0930093C: 0x0931,
+ 0x0933093C: 0x0934,
+ 0x09C709BE: 0x09CB,
+ 0x09C709D7: 0x09CC,
+ 0x0B470B56: 0x0B48,
+ 0x0B470B3E: 0x0B4B,
+ 0x0B470B57: 0x0B4C,
+ 0x0B920BD7: 0x0B94,
+ 0x0BC60BBE: 0x0BCA,
+ 0x0BC70BBE: 0x0BCB,
+ 0x0BC60BD7: 0x0BCC,
+ 0x0C460C56: 0x0C48,
+ 0x0CBF0CD5: 0x0CC0,
+ 0x0CC60CD5: 0x0CC7,
+ 0x0CC60CD6: 0x0CC8,
+ 0x0CC60CC2: 0x0CCA,
+ 0x0CCA0CD5: 0x0CCB,
+ 0x0D460D3E: 0x0D4A,
+ 0x0D470D3E: 0x0D4B,
+ 0x0D460D57: 0x0D4C,
+ 0x0DD90DCA: 0x0DDA,
+ 0x0DD90DCF: 0x0DDC,
+ 0x0DDC0DCA: 0x0DDD,
+ 0x0DD90DDF: 0x0DDE,
+ 0x1025102E: 0x1026,
+ 0x1B051B35: 0x1B06,
+ 0x1B071B35: 0x1B08,
+ 0x1B091B35: 0x1B0A,
+ 0x1B0B1B35: 0x1B0C,
+ 0x1B0D1B35: 0x1B0E,
+ 0x1B111B35: 0x1B12,
+ 0x1B3A1B35: 0x1B3B,
+ 0x1B3C1B35: 0x1B3D,
+ 0x1B3E1B35: 0x1B40,
+ 0x1B3F1B35: 0x1B41,
+ 0x1B421B35: 0x1B43,
+ 0x00410325: 0x1E00,
+ 0x00610325: 0x1E01,
+ 0x00420307: 0x1E02,
+ 0x00620307: 0x1E03,
+ 0x00420323: 0x1E04,
+ 0x00620323: 0x1E05,
+ 0x00420331: 0x1E06,
+ 0x00620331: 0x1E07,
+ 0x00C70301: 0x1E08,
+ 0x00E70301: 0x1E09,
+ 0x00440307: 0x1E0A,
+ 0x00640307: 0x1E0B,
+ 0x00440323: 0x1E0C,
+ 0x00640323: 0x1E0D,
+ 0x00440331: 0x1E0E,
+ 0x00640331: 0x1E0F,
+ 0x00440327: 0x1E10,
+ 0x00640327: 0x1E11,
+ 0x0044032D: 0x1E12,
+ 0x0064032D: 0x1E13,
+ 0x01120300: 0x1E14,
+ 0x01130300: 0x1E15,
+ 0x01120301: 0x1E16,
+ 0x01130301: 0x1E17,
+ 0x0045032D: 0x1E18,
+ 0x0065032D: 0x1E19,
+ 0x00450330: 0x1E1A,
+ 0x00650330: 0x1E1B,
+ 0x02280306: 0x1E1C,
+ 0x02290306: 0x1E1D,
+ 0x00460307: 0x1E1E,
+ 0x00660307: 0x1E1F,
+ 0x00470304: 0x1E20,
+ 0x00670304: 0x1E21,
+ 0x00480307: 0x1E22,
+ 0x00680307: 0x1E23,
+ 0x00480323: 0x1E24,
+ 0x00680323: 0x1E25,
+ 0x00480308: 0x1E26,
+ 0x00680308: 0x1E27,
+ 0x00480327: 0x1E28,
+ 0x00680327: 0x1E29,
+ 0x0048032E: 0x1E2A,
+ 0x0068032E: 0x1E2B,
+ 0x00490330: 0x1E2C,
+ 0x00690330: 0x1E2D,
+ 0x00CF0301: 0x1E2E,
+ 0x00EF0301: 0x1E2F,
+ 0x004B0301: 0x1E30,
+ 0x006B0301: 0x1E31,
+ 0x004B0323: 0x1E32,
+ 0x006B0323: 0x1E33,
+ 0x004B0331: 0x1E34,
+ 0x006B0331: 0x1E35,
+ 0x004C0323: 0x1E36,
+ 0x006C0323: 0x1E37,
+ 0x1E360304: 0x1E38,
+ 0x1E370304: 0x1E39,
+ 0x004C0331: 0x1E3A,
+ 0x006C0331: 0x1E3B,
+ 0x004C032D: 0x1E3C,
+ 0x006C032D: 0x1E3D,
+ 0x004D0301: 0x1E3E,
+ 0x006D0301: 0x1E3F,
+ 0x004D0307: 0x1E40,
+ 0x006D0307: 0x1E41,
+ 0x004D0323: 0x1E42,
+ 0x006D0323: 0x1E43,
+ 0x004E0307: 0x1E44,
+ 0x006E0307: 0x1E45,
+ 0x004E0323: 0x1E46,
+ 0x006E0323: 0x1E47,
+ 0x004E0331: 0x1E48,
+ 0x006E0331: 0x1E49,
+ 0x004E032D: 0x1E4A,
+ 0x006E032D: 0x1E4B,
+ 0x00D50301: 0x1E4C,
+ 0x00F50301: 0x1E4D,
+ 0x00D50308: 0x1E4E,
+ 0x00F50308: 0x1E4F,
+ 0x014C0300: 0x1E50,
+ 0x014D0300: 0x1E51,
+ 0x014C0301: 0x1E52,
+ 0x014D0301: 0x1E53,
+ 0x00500301: 0x1E54,
+ 0x00700301: 0x1E55,
+ 0x00500307: 0x1E56,
+ 0x00700307: 0x1E57,
+ 0x00520307: 0x1E58,
+ 0x00720307: 0x1E59,
+ 0x00520323: 0x1E5A,
+ 0x00720323: 0x1E5B,
+ 0x1E5A0304: 0x1E5C,
+ 0x1E5B0304: 0x1E5D,
+ 0x00520331: 0x1E5E,
+ 0x00720331: 0x1E5F,
+ 0x00530307: 0x1E60,
+ 0x00730307: 0x1E61,
+ 0x00530323: 0x1E62,
+ 0x00730323: 0x1E63,
+ 0x015A0307: 0x1E64,
+ 0x015B0307: 0x1E65,
+ 0x01600307: 0x1E66,
+ 0x01610307: 0x1E67,
+ 0x1E620307: 0x1E68,
+ 0x1E630307: 0x1E69,
+ 0x00540307: 0x1E6A,
+ 0x00740307: 0x1E6B,
+ 0x00540323: 0x1E6C,
+ 0x00740323: 0x1E6D,
+ 0x00540331: 0x1E6E,
+ 0x00740331: 0x1E6F,
+ 0x0054032D: 0x1E70,
+ 0x0074032D: 0x1E71,
+ 0x00550324: 0x1E72,
+ 0x00750324: 0x1E73,
+ 0x00550330: 0x1E74,
+ 0x00750330: 0x1E75,
+ 0x0055032D: 0x1E76,
+ 0x0075032D: 0x1E77,
+ 0x01680301: 0x1E78,
+ 0x01690301: 0x1E79,
+ 0x016A0308: 0x1E7A,
+ 0x016B0308: 0x1E7B,
+ 0x00560303: 0x1E7C,
+ 0x00760303: 0x1E7D,
+ 0x00560323: 0x1E7E,
+ 0x00760323: 0x1E7F,
+ 0x00570300: 0x1E80,
+ 0x00770300: 0x1E81,
+ 0x00570301: 0x1E82,
+ 0x00770301: 0x1E83,
+ 0x00570308: 0x1E84,
+ 0x00770308: 0x1E85,
+ 0x00570307: 0x1E86,
+ 0x00770307: 0x1E87,
+ 0x00570323: 0x1E88,
+ 0x00770323: 0x1E89,
+ 0x00580307: 0x1E8A,
+ 0x00780307: 0x1E8B,
+ 0x00580308: 0x1E8C,
+ 0x00780308: 0x1E8D,
+ 0x00590307: 0x1E8E,
+ 0x00790307: 0x1E8F,
+ 0x005A0302: 0x1E90,
+ 0x007A0302: 0x1E91,
+ 0x005A0323: 0x1E92,
+ 0x007A0323: 0x1E93,
+ 0x005A0331: 0x1E94,
+ 0x007A0331: 0x1E95,
+ 0x00680331: 0x1E96,
+ 0x00740308: 0x1E97,
+ 0x0077030A: 0x1E98,
+ 0x0079030A: 0x1E99,
+ 0x017F0307: 0x1E9B,
+ 0x00410323: 0x1EA0,
+ 0x00610323: 0x1EA1,
+ 0x00410309: 0x1EA2,
+ 0x00610309: 0x1EA3,
+ 0x00C20301: 0x1EA4,
+ 0x00E20301: 0x1EA5,
+ 0x00C20300: 0x1EA6,
+ 0x00E20300: 0x1EA7,
+ 0x00C20309: 0x1EA8,
+ 0x00E20309: 0x1EA9,
+ 0x00C20303: 0x1EAA,
+ 0x00E20303: 0x1EAB,
+ 0x1EA00302: 0x1EAC,
+ 0x1EA10302: 0x1EAD,
+ 0x01020301: 0x1EAE,
+ 0x01030301: 0x1EAF,
+ 0x01020300: 0x1EB0,
+ 0x01030300: 0x1EB1,
+ 0x01020309: 0x1EB2,
+ 0x01030309: 0x1EB3,
+ 0x01020303: 0x1EB4,
+ 0x01030303: 0x1EB5,
+ 0x1EA00306: 0x1EB6,
+ 0x1EA10306: 0x1EB7,
+ 0x00450323: 0x1EB8,
+ 0x00650323: 0x1EB9,
+ 0x00450309: 0x1EBA,
+ 0x00650309: 0x1EBB,
+ 0x00450303: 0x1EBC,
+ 0x00650303: 0x1EBD,
+ 0x00CA0301: 0x1EBE,
+ 0x00EA0301: 0x1EBF,
+ 0x00CA0300: 0x1EC0,
+ 0x00EA0300: 0x1EC1,
+ 0x00CA0309: 0x1EC2,
+ 0x00EA0309: 0x1EC3,
+ 0x00CA0303: 0x1EC4,
+ 0x00EA0303: 0x1EC5,
+ 0x1EB80302: 0x1EC6,
+ 0x1EB90302: 0x1EC7,
+ 0x00490309: 0x1EC8,
+ 0x00690309: 0x1EC9,
+ 0x00490323: 0x1ECA,
+ 0x00690323: 0x1ECB,
+ 0x004F0323: 0x1ECC,
+ 0x006F0323: 0x1ECD,
+ 0x004F0309: 0x1ECE,
+ 0x006F0309: 0x1ECF,
+ 0x00D40301: 0x1ED0,
+ 0x00F40301: 0x1ED1,
+ 0x00D40300: 0x1ED2,
+ 0x00F40300: 0x1ED3,
+ 0x00D40309: 0x1ED4,
+ 0x00F40309: 0x1ED5,
+ 0x00D40303: 0x1ED6,
+ 0x00F40303: 0x1ED7,
+ 0x1ECC0302: 0x1ED8,
+ 0x1ECD0302: 0x1ED9,
+ 0x01A00301: 0x1EDA,
+ 0x01A10301: 0x1EDB,
+ 0x01A00300: 0x1EDC,
+ 0x01A10300: 0x1EDD,
+ 0x01A00309: 0x1EDE,
+ 0x01A10309: 0x1EDF,
+ 0x01A00303: 0x1EE0,
+ 0x01A10303: 0x1EE1,
+ 0x01A00323: 0x1EE2,
+ 0x01A10323: 0x1EE3,
+ 0x00550323: 0x1EE4,
+ 0x00750323: 0x1EE5,
+ 0x00550309: 0x1EE6,
+ 0x00750309: 0x1EE7,
+ 0x01AF0301: 0x1EE8,
+ 0x01B00301: 0x1EE9,
+ 0x01AF0300: 0x1EEA,
+ 0x01B00300: 0x1EEB,
+ 0x01AF0309: 0x1EEC,
+ 0x01B00309: 0x1EED,
+ 0x01AF0303: 0x1EEE,
+ 0x01B00303: 0x1EEF,
+ 0x01AF0323: 0x1EF0,
+ 0x01B00323: 0x1EF1,
+ 0x00590300: 0x1EF2,
+ 0x00790300: 0x1EF3,
+ 0x00590323: 0x1EF4,
+ 0x00790323: 0x1EF5,
+ 0x00590309: 0x1EF6,
+ 0x00790309: 0x1EF7,
+ 0x00590303: 0x1EF8,
+ 0x00790303: 0x1EF9,
+ 0x03B10313: 0x1F00,
+ 0x03B10314: 0x1F01,
+ 0x1F000300: 0x1F02,
+ 0x1F010300: 0x1F03,
+ 0x1F000301: 0x1F04,
+ 0x1F010301: 0x1F05,
+ 0x1F000342: 0x1F06,
+ 0x1F010342: 0x1F07,
+ 0x03910313: 0x1F08,
+ 0x03910314: 0x1F09,
+ 0x1F080300: 0x1F0A,
+ 0x1F090300: 0x1F0B,
+ 0x1F080301: 0x1F0C,
+ 0x1F090301: 0x1F0D,
+ 0x1F080342: 0x1F0E,
+ 0x1F090342: 0x1F0F,
+ 0x03B50313: 0x1F10,
+ 0x03B50314: 0x1F11,
+ 0x1F100300: 0x1F12,
+ 0x1F110300: 0x1F13,
+ 0x1F100301: 0x1F14,
+ 0x1F110301: 0x1F15,
+ 0x03950313: 0x1F18,
+ 0x03950314: 0x1F19,
+ 0x1F180300: 0x1F1A,
+ 0x1F190300: 0x1F1B,
+ 0x1F180301: 0x1F1C,
+ 0x1F190301: 0x1F1D,
+ 0x03B70313: 0x1F20,
+ 0x03B70314: 0x1F21,
+ 0x1F200300: 0x1F22,
+ 0x1F210300: 0x1F23,
+ 0x1F200301: 0x1F24,
+ 0x1F210301: 0x1F25,
+ 0x1F200342: 0x1F26,
+ 0x1F210342: 0x1F27,
+ 0x03970313: 0x1F28,
+ 0x03970314: 0x1F29,
+ 0x1F280300: 0x1F2A,
+ 0x1F290300: 0x1F2B,
+ 0x1F280301: 0x1F2C,
+ 0x1F290301: 0x1F2D,
+ 0x1F280342: 0x1F2E,
+ 0x1F290342: 0x1F2F,
+ 0x03B90313: 0x1F30,
+ 0x03B90314: 0x1F31,
+ 0x1F300300: 0x1F32,
+ 0x1F310300: 0x1F33,
+ 0x1F300301: 0x1F34,
+ 0x1F310301: 0x1F35,
+ 0x1F300342: 0x1F36,
+ 0x1F310342: 0x1F37,
+ 0x03990313: 0x1F38,
+ 0x03990314: 0x1F39,
+ 0x1F380300: 0x1F3A,
+ 0x1F390300: 0x1F3B,
+ 0x1F380301: 0x1F3C,
+ 0x1F390301: 0x1F3D,
+ 0x1F380342: 0x1F3E,
+ 0x1F390342: 0x1F3F,
+ 0x03BF0313: 0x1F40,
+ 0x03BF0314: 0x1F41,
+ 0x1F400300: 0x1F42,
+ 0x1F410300: 0x1F43,
+ 0x1F400301: 0x1F44,
+ 0x1F410301: 0x1F45,
+ 0x039F0313: 0x1F48,
+ 0x039F0314: 0x1F49,
+ 0x1F480300: 0x1F4A,
+ 0x1F490300: 0x1F4B,
+ 0x1F480301: 0x1F4C,
+ 0x1F490301: 0x1F4D,
+ 0x03C50313: 0x1F50,
+ 0x03C50314: 0x1F51,
+ 0x1F500300: 0x1F52,
+ 0x1F510300: 0x1F53,
+ 0x1F500301: 0x1F54,
+ 0x1F510301: 0x1F55,
+ 0x1F500342: 0x1F56,
+ 0x1F510342: 0x1F57,
+ 0x03A50314: 0x1F59,
+ 0x1F590300: 0x1F5B,
+ 0x1F590301: 0x1F5D,
+ 0x1F590342: 0x1F5F,
+ 0x03C90313: 0x1F60,
+ 0x03C90314: 0x1F61,
+ 0x1F600300: 0x1F62,
+ 0x1F610300: 0x1F63,
+ 0x1F600301: 0x1F64,
+ 0x1F610301: 0x1F65,
+ 0x1F600342: 0x1F66,
+ 0x1F610342: 0x1F67,
+ 0x03A90313: 0x1F68,
+ 0x03A90314: 0x1F69,
+ 0x1F680300: 0x1F6A,
+ 0x1F690300: 0x1F6B,
+ 0x1F680301: 0x1F6C,
+ 0x1F690301: 0x1F6D,
+ 0x1F680342: 0x1F6E,
+ 0x1F690342: 0x1F6F,
+ 0x03B10300: 0x1F70,
+ 0x03B50300: 0x1F72,
+ 0x03B70300: 0x1F74,
+ 0x03B90300: 0x1F76,
+ 0x03BF0300: 0x1F78,
+ 0x03C50300: 0x1F7A,
+ 0x03C90300: 0x1F7C,
+ 0x1F000345: 0x1F80,
+ 0x1F010345: 0x1F81,
+ 0x1F020345: 0x1F82,
+ 0x1F030345: 0x1F83,
+ 0x1F040345: 0x1F84,
+ 0x1F050345: 0x1F85,
+ 0x1F060345: 0x1F86,
+ 0x1F070345: 0x1F87,
+ 0x1F080345: 0x1F88,
+ 0x1F090345: 0x1F89,
+ 0x1F0A0345: 0x1F8A,
+ 0x1F0B0345: 0x1F8B,
+ 0x1F0C0345: 0x1F8C,
+ 0x1F0D0345: 0x1F8D,
+ 0x1F0E0345: 0x1F8E,
+ 0x1F0F0345: 0x1F8F,
+ 0x1F200345: 0x1F90,
+ 0x1F210345: 0x1F91,
+ 0x1F220345: 0x1F92,
+ 0x1F230345: 0x1F93,
+ 0x1F240345: 0x1F94,
+ 0x1F250345: 0x1F95,
+ 0x1F260345: 0x1F96,
+ 0x1F270345: 0x1F97,
+ 0x1F280345: 0x1F98,
+ 0x1F290345: 0x1F99,
+ 0x1F2A0345: 0x1F9A,
+ 0x1F2B0345: 0x1F9B,
+ 0x1F2C0345: 0x1F9C,
+ 0x1F2D0345: 0x1F9D,
+ 0x1F2E0345: 0x1F9E,
+ 0x1F2F0345: 0x1F9F,
+ 0x1F600345: 0x1FA0,
+ 0x1F610345: 0x1FA1,
+ 0x1F620345: 0x1FA2,
+ 0x1F630345: 0x1FA3,
+ 0x1F640345: 0x1FA4,
+ 0x1F650345: 0x1FA5,
+ 0x1F660345: 0x1FA6,
+ 0x1F670345: 0x1FA7,
+ 0x1F680345: 0x1FA8,
+ 0x1F690345: 0x1FA9,
+ 0x1F6A0345: 0x1FAA,
+ 0x1F6B0345: 0x1FAB,
+ 0x1F6C0345: 0x1FAC,
+ 0x1F6D0345: 0x1FAD,
+ 0x1F6E0345: 0x1FAE,
+ 0x1F6F0345: 0x1FAF,
+ 0x03B10306: 0x1FB0,
+ 0x03B10304: 0x1FB1,
+ 0x1F700345: 0x1FB2,
+ 0x03B10345: 0x1FB3,
+ 0x03AC0345: 0x1FB4,
+ 0x03B10342: 0x1FB6,
+ 0x1FB60345: 0x1FB7,
+ 0x03910306: 0x1FB8,
+ 0x03910304: 0x1FB9,
+ 0x03910300: 0x1FBA,
+ 0x03910345: 0x1FBC,
+ 0x00A80342: 0x1FC1,
+ 0x1F740345: 0x1FC2,
+ 0x03B70345: 0x1FC3,
+ 0x03AE0345: 0x1FC4,
+ 0x03B70342: 0x1FC6,
+ 0x1FC60345: 0x1FC7,
+ 0x03950300: 0x1FC8,
+ 0x03970300: 0x1FCA,
+ 0x03970345: 0x1FCC,
+ 0x1FBF0300: 0x1FCD,
+ 0x1FBF0301: 0x1FCE,
+ 0x1FBF0342: 0x1FCF,
+ 0x03B90306: 0x1FD0,
+ 0x03B90304: 0x1FD1,
+ 0x03CA0300: 0x1FD2,
+ 0x03B90342: 0x1FD6,
+ 0x03CA0342: 0x1FD7,
+ 0x03990306: 0x1FD8,
+ 0x03990304: 0x1FD9,
+ 0x03990300: 0x1FDA,
+ 0x1FFE0300: 0x1FDD,
+ 0x1FFE0301: 0x1FDE,
+ 0x1FFE0342: 0x1FDF,
+ 0x03C50306: 0x1FE0,
+ 0x03C50304: 0x1FE1,
+ 0x03CB0300: 0x1FE2,
+ 0x03C10313: 0x1FE4,
+ 0x03C10314: 0x1FE5,
+ 0x03C50342: 0x1FE6,
+ 0x03CB0342: 0x1FE7,
+ 0x03A50306: 0x1FE8,
+ 0x03A50304: 0x1FE9,
+ 0x03A50300: 0x1FEA,
+ 0x03A10314: 0x1FEC,
+ 0x00A80300: 0x1FED,
+ 0x1F7C0345: 0x1FF2,
+ 0x03C90345: 0x1FF3,
+ 0x03CE0345: 0x1FF4,
+ 0x03C90342: 0x1FF6,
+ 0x1FF60345: 0x1FF7,
+ 0x039F0300: 0x1FF8,
+ 0x03A90300: 0x1FFA,
+ 0x03A90345: 0x1FFC,
+ 0x21900338: 0x219A,
+ 0x21920338: 0x219B,
+ 0x21940338: 0x21AE,
+ 0x21D00338: 0x21CD,
+ 0x21D40338: 0x21CE,
+ 0x21D20338: 0x21CF,
+ 0x22030338: 0x2204,
+ 0x22080338: 0x2209,
+ 0x220B0338: 0x220C,
+ 0x22230338: 0x2224,
+ 0x22250338: 0x2226,
+ 0x223C0338: 0x2241,
+ 0x22430338: 0x2244,
+ 0x22450338: 0x2247,
+ 0x22480338: 0x2249,
+ 0x003D0338: 0x2260,
+ 0x22610338: 0x2262,
+ 0x224D0338: 0x226D,
+ 0x003C0338: 0x226E,
+ 0x003E0338: 0x226F,
+ 0x22640338: 0x2270,
+ 0x22650338: 0x2271,
+ 0x22720338: 0x2274,
+ 0x22730338: 0x2275,
+ 0x22760338: 0x2278,
+ 0x22770338: 0x2279,
+ 0x227A0338: 0x2280,
+ 0x227B0338: 0x2281,
+ 0x22820338: 0x2284,
+ 0x22830338: 0x2285,
+ 0x22860338: 0x2288,
+ 0x22870338: 0x2289,
+ 0x22A20338: 0x22AC,
+ 0x22A80338: 0x22AD,
+ 0x22A90338: 0x22AE,
+ 0x22AB0338: 0x22AF,
+ 0x227C0338: 0x22E0,
+ 0x227D0338: 0x22E1,
+ 0x22910338: 0x22E2,
+ 0x22920338: 0x22E3,
+ 0x22B20338: 0x22EA,
+ 0x22B30338: 0x22EB,
+ 0x22B40338: 0x22EC,
+ 0x22B50338: 0x22ED,
+ 0x304B3099: 0x304C,
+ 0x304D3099: 0x304E,
+ 0x304F3099: 0x3050,
+ 0x30513099: 0x3052,
+ 0x30533099: 0x3054,
+ 0x30553099: 0x3056,
+ 0x30573099: 0x3058,
+ 0x30593099: 0x305A,
+ 0x305B3099: 0x305C,
+ 0x305D3099: 0x305E,
+ 0x305F3099: 0x3060,
+ 0x30613099: 0x3062,
+ 0x30643099: 0x3065,
+ 0x30663099: 0x3067,
+ 0x30683099: 0x3069,
+ 0x306F3099: 0x3070,
+ 0x306F309A: 0x3071,
+ 0x30723099: 0x3073,
+ 0x3072309A: 0x3074,
+ 0x30753099: 0x3076,
+ 0x3075309A: 0x3077,
+ 0x30783099: 0x3079,
+ 0x3078309A: 0x307A,
+ 0x307B3099: 0x307C,
+ 0x307B309A: 0x307D,
+ 0x30463099: 0x3094,
+ 0x309D3099: 0x309E,
+ 0x30AB3099: 0x30AC,
+ 0x30AD3099: 0x30AE,
+ 0x30AF3099: 0x30B0,
+ 0x30B13099: 0x30B2,
+ 0x30B33099: 0x30B4,
+ 0x30B53099: 0x30B6,
+ 0x30B73099: 0x30B8,
+ 0x30B93099: 0x30BA,
+ 0x30BB3099: 0x30BC,
+ 0x30BD3099: 0x30BE,
+ 0x30BF3099: 0x30C0,
+ 0x30C13099: 0x30C2,
+ 0x30C43099: 0x30C5,
+ 0x30C63099: 0x30C7,
+ 0x30C83099: 0x30C9,
+ 0x30CF3099: 0x30D0,
+ 0x30CF309A: 0x30D1,
+ 0x30D23099: 0x30D3,
+ 0x30D2309A: 0x30D4,
+ 0x30D53099: 0x30D6,
+ 0x30D5309A: 0x30D7,
+ 0x30D83099: 0x30D9,
+ 0x30D8309A: 0x30DA,
+ 0x30DB3099: 0x30DC,
+ 0x30DB309A: 0x30DD,
+ 0x30A63099: 0x30F4,
+ 0x30EF3099: 0x30F7,
+ 0x30F03099: 0x30F8,
+ 0x30F13099: 0x30F9,
+ 0x30F23099: 0x30FA,
+ 0x30FD3099: 0x30FE,
+ 0x109910BA: 0x1109A,
+ 0x109B10BA: 0x1109C,
+ 0x10A510BA: 0x110AB,
+ 0x11311127: 0x1112E,
+ 0x11321127: 0x1112F,
+ 0x1347133E: 0x1134B,
+ 0x13471357: 0x1134C,
+ 0x14B914BA: 0x114BB,
+ 0x14B914B0: 0x114BC,
+ 0x14B914BD: 0x114BE,
+ 0x15B815AF: 0x115BA,
+ 0x15B915AF: 0x115BB,
+}
+
+// Total size of tables: 53KB (53976 bytes)
diff --git a/libgo/go/golang_org/x/text/unicode/norm/transform.go b/libgo/go/golang_org/x/text/unicode/norm/transform.go
new file mode 100644
index 0000000000..b341789b4c
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/transform.go
@@ -0,0 +1,88 @@
+// 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.
+
+package norm
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+// Reset implements the Reset method of the transform.Transformer interface.
+func (Form) Reset() {}
+
+// Transform implements the Transform method of the transform.Transformer
+// interface. It may need to write segments of up to MaxSegmentSize at once.
+// Users should either catch ErrShortDst and allow dst to grow or have dst be at
+// least of size MaxTransformChunkSize to be guaranteed of progress.
+func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ n := 0
+ // Cap the maximum number of src bytes to check.
+ b := src
+ eof := atEOF
+ if ns := len(dst); ns < len(b) {
+ err = transform.ErrShortDst
+ eof = false
+ b = b[:ns]
+ }
+ i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
+ n += copy(dst[n:], b[n:i])
+ if !ok {
+ nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
+ return nDst + n, nSrc + n, err
+ }
+ if n < len(src) && !atEOF {
+ err = transform.ErrShortSrc
+ }
+ return n, n, err
+}
+
+func flushTransform(rb *reorderBuffer) bool {
+ // Write out (must fully fit in dst, or else it is a ErrShortDst).
+ if len(rb.out) < rb.nrune*utf8.UTFMax {
+ return false
+ }
+ rb.out = rb.out[rb.flushCopy(rb.out):]
+ return true
+}
+
+var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}
+
+// transform implements the transform.Transformer interface. It is only called
+// when quickSpan does not pass for a given string.
+func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ // TODO: get rid of reorderBuffer. See CL 23460044.
+ rb := reorderBuffer{}
+ rb.init(f, src)
+ for {
+ // Load segment into reorder buffer.
+ rb.setFlusher(dst[nDst:], flushTransform)
+ end := decomposeSegment(&rb, nSrc, atEOF)
+ if end < 0 {
+ return nDst, nSrc, errs[-end]
+ }
+ nDst = len(dst) - len(rb.out)
+ nSrc = end
+
+ // Next quickSpan.
+ end = rb.nsrc
+ eof := atEOF
+ if n := nSrc + len(dst) - nDst; n < end {
+ err = transform.ErrShortDst
+ end = n
+ eof = false
+ }
+ end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
+ n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
+ nSrc += n
+ nDst += n
+ if ok {
+ if n < rb.nsrc && !atEOF {
+ err = transform.ErrShortSrc
+ }
+ return nDst, nSrc, err
+ }
+ }
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/trie.go b/libgo/go/golang_org/x/text/unicode/norm/trie.go
new file mode 100644
index 0000000000..423386bf43
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/trie.go
@@ -0,0 +1,54 @@
+// 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 norm
+
+type valueRange struct {
+ value uint16 // header: value:stride
+ lo, hi byte // header: lo:n
+}
+
+type sparseBlocks struct {
+ values []valueRange
+ offset []uint16
+}
+
+var nfcSparse = sparseBlocks{
+ values: nfcSparseValues[:],
+ offset: nfcSparseOffset[:],
+}
+
+var nfkcSparse = sparseBlocks{
+ values: nfkcSparseValues[:],
+ offset: nfkcSparseOffset[:],
+}
+
+var (
+ nfcData = newNfcTrie(0)
+ nfkcData = newNfkcTrie(0)
+)
+
+// lookupValue determines the type of block n and looks up the value for b.
+// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
+// is a list of ranges with an accompanying value. Given a matching range r,
+// the value for b is by r.value + (b - r.lo) * stride.
+func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
+ offset := t.offset[n]
+ header := t.values[offset]
+ lo := offset + 1
+ hi := lo + uint16(header.lo)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := t.values[m]
+ if r.lo <= b && b <= r.hi {
+ return r.value + uint16(b-r.lo)*header.value
+ }
+ if b < r.lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return 0
+}
diff --git a/libgo/go/golang_org/x/text/unicode/norm/triegen.go b/libgo/go/golang_org/x/text/unicode/norm/triegen.go
new file mode 100644
index 0000000000..45d711900d
--- /dev/null
+++ b/libgo/go/golang_org/x/text/unicode/norm/triegen.go
@@ -0,0 +1,117 @@
+// 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.
+
+// +build ignore
+
+// Trie table generator.
+// Used by make*tables tools to generate a go file with trie data structures
+// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
+// sequence are used to lookup offsets in the index table to be used for the
+// next byte. The last byte is used to index into a table with 16-bit values.
+
+package main
+
+import (
+ "fmt"
+ "io"
+)
+
+const maxSparseEntries = 16
+
+type normCompacter struct {
+ sparseBlocks [][]uint64
+ sparseOffset []uint16
+ sparseCount int
+ name string
+}
+
+func mostFrequentStride(a []uint64) int {
+ counts := make(map[int]int)
+ var v int
+ for _, x := range a {
+ if stride := int(x) - v; v != 0 && stride >= 0 {
+ counts[stride]++
+ }
+ v = int(x)
+ }
+ var maxs, maxc int
+ for stride, cnt := range counts {
+ if cnt > maxc || (cnt == maxc && stride < maxs) {
+ maxs, maxc = stride, cnt
+ }
+ }
+ return maxs
+}
+
+func countSparseEntries(a []uint64) int {
+ stride := mostFrequentStride(a)
+ var v, count int
+ for _, tv := range a {
+ if int(tv)-v != stride {
+ if tv != 0 {
+ count++
+ }
+ }
+ v = int(tv)
+ }
+ return count
+}
+
+func (c *normCompacter) Size(v []uint64) (sz int, ok bool) {
+ if n := countSparseEntries(v); n <= maxSparseEntries {
+ return (n+1)*4 + 2, true
+ }
+ return 0, false
+}
+
+func (c *normCompacter) Store(v []uint64) uint32 {
+ h := uint32(len(c.sparseOffset))
+ c.sparseBlocks = append(c.sparseBlocks, v)
+ c.sparseOffset = append(c.sparseOffset, uint16(c.sparseCount))
+ c.sparseCount += countSparseEntries(v) + 1
+ return h
+}
+
+func (c *normCompacter) Handler() string {
+ return c.name + "Sparse.lookup"
+}
+
+func (c *normCompacter) Print(w io.Writer) (retErr error) {
+ p := func(f string, x ...interface{}) {
+ if _, err := fmt.Fprintf(w, f, x...); retErr == nil && err != nil {
+ retErr = err
+ }
+ }
+
+ ls := len(c.sparseBlocks)
+ p("// %sSparseOffset: %d entries, %d bytes\n", c.name, ls, ls*2)
+ p("var %sSparseOffset = %#v\n\n", c.name, c.sparseOffset)
+
+ ns := c.sparseCount
+ p("// %sSparseValues: %d entries, %d bytes\n", c.name, ns, ns*4)
+ p("var %sSparseValues = [%d]valueRange {", c.name, ns)
+ for i, b := range c.sparseBlocks {
+ p("\n// Block %#x, offset %#x", i, c.sparseOffset[i])
+ var v int
+ stride := mostFrequentStride(b)
+ n := countSparseEntries(b)
+ p("\n{value:%#04x,lo:%#02x},", stride, uint8(n))
+ for i, nv := range b {
+ if int(nv)-v != stride {
+ if v != 0 {
+ p(",hi:%#02x},", 0x80+i-1)
+ }
+ if nv != 0 {
+ p("\n{value:%#04x,lo:%#02x", nv, 0x80+i)
+ }
+ }
+ v = int(nv)
+ }
+ if v != 0 {
+ p(",hi:%#02x},", 0x80+len(b)-1)
+ }
+ }
+ p("\n}\n\n")
+ return
+}
diff --git a/libgo/go/golang_org/x/text/width/kind_string.go b/libgo/go/golang_org/x/text/width/kind_string.go
new file mode 100644
index 0000000000..ab4fee542f
--- /dev/null
+++ b/libgo/go/golang_org/x/text/width/kind_string.go
@@ -0,0 +1,16 @@
+// Code generated by "stringer -type=Kind"; DO NOT EDIT
+
+package width
+
+import "fmt"
+
+const _Kind_name = "NeutralEastAsianAmbiguousEastAsianWideEastAsianNarrowEastAsianFullwidthEastAsianHalfwidth"
+
+var _Kind_index = [...]uint8{0, 7, 25, 38, 53, 71, 89}
+
+func (i Kind) String() string {
+ if i < 0 || i >= Kind(len(_Kind_index)-1) {
+ return fmt.Sprintf("Kind(%d)", i)
+ }
+ return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
+}
diff --git a/libgo/go/golang_org/x/text/width/tables.go b/libgo/go/golang_org/x/text/width/tables.go
new file mode 100644
index 0000000000..242da0fdb9
--- /dev/null
+++ b/libgo/go/golang_org/x/text/width/tables.go
@@ -0,0 +1,1284 @@
+// This file was generated by go generate; DO NOT EDIT
+
+package width
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "9.0.0"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return widthValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = widthIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = widthIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = widthIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return widthValues[c0]
+ }
+ i := widthIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = widthIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = widthIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return widthValues[c0], 1
+ case c0 < 0xC2:
+ return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+ case c0 < 0xE0: // 2-byte UTF-8
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c1), 2
+ case c0 < 0xF0: // 3-byte UTF-8
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = widthIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c2), 3
+ case c0 < 0xF8: // 4-byte UTF-8
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := widthIndex[c0]
+ c1 := s[1]
+ if c1 < 0x80 || 0xC0 <= c1 {
+ return 0, 1 // Illegal UTF-8: not a continuation byte.
+ }
+ o := uint32(i)<<6 + uint32(c1)
+ i = widthIndex[o]
+ c2 := s[2]
+ if c2 < 0x80 || 0xC0 <= c2 {
+ return 0, 2 // Illegal UTF-8: not a continuation byte.
+ }
+ o = uint32(i)<<6 + uint32(c2)
+ i = widthIndex[o]
+ c3 := s[3]
+ if c3 < 0x80 || 0xC0 <= c3 {
+ return 0, 3 // Illegal UTF-8: not a continuation byte.
+ }
+ return t.lookupValue(uint32(i), c3), 4
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return widthValues[c0]
+ }
+ i := widthIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = widthIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = widthIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// widthTrie. Total size: 14080 bytes (13.75 KiB). Checksum: 3b8aeb3dc03667a3.
+type widthTrie struct{}
+
+func newWidthTrie(i int) *widthTrie {
+ return &widthTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *widthTrie) lookupValue(n uint32, b byte) uint16 {
+ switch {
+ default:
+ return uint16(widthValues[n<<6+uint32(b)])
+ }
+}
+
+// widthValues: 99 blocks, 6336 entries, 12672 bytes
+// The third block is the zero block.
+var widthValues = [6336]uint16{
+ // Block 0x0, offset 0x0
+ 0x20: 0x6001, 0x21: 0x6002, 0x22: 0x6002, 0x23: 0x6002,
+ 0x24: 0x6002, 0x25: 0x6002, 0x26: 0x6002, 0x27: 0x6002, 0x28: 0x6002, 0x29: 0x6002,
+ 0x2a: 0x6002, 0x2b: 0x6002, 0x2c: 0x6002, 0x2d: 0x6002, 0x2e: 0x6002, 0x2f: 0x6002,
+ 0x30: 0x6002, 0x31: 0x6002, 0x32: 0x6002, 0x33: 0x6002, 0x34: 0x6002, 0x35: 0x6002,
+ 0x36: 0x6002, 0x37: 0x6002, 0x38: 0x6002, 0x39: 0x6002, 0x3a: 0x6002, 0x3b: 0x6002,
+ 0x3c: 0x6002, 0x3d: 0x6002, 0x3e: 0x6002, 0x3f: 0x6002,
+ // Block 0x1, offset 0x40
+ 0x40: 0x6003, 0x41: 0x6003, 0x42: 0x6003, 0x43: 0x6003, 0x44: 0x6003, 0x45: 0x6003,
+ 0x46: 0x6003, 0x47: 0x6003, 0x48: 0x6003, 0x49: 0x6003, 0x4a: 0x6003, 0x4b: 0x6003,
+ 0x4c: 0x6003, 0x4d: 0x6003, 0x4e: 0x6003, 0x4f: 0x6003, 0x50: 0x6003, 0x51: 0x6003,
+ 0x52: 0x6003, 0x53: 0x6003, 0x54: 0x6003, 0x55: 0x6003, 0x56: 0x6003, 0x57: 0x6003,
+ 0x58: 0x6003, 0x59: 0x6003, 0x5a: 0x6003, 0x5b: 0x6003, 0x5c: 0x6003, 0x5d: 0x6003,
+ 0x5e: 0x6003, 0x5f: 0x6003, 0x60: 0x6004, 0x61: 0x6004, 0x62: 0x6004, 0x63: 0x6004,
+ 0x64: 0x6004, 0x65: 0x6004, 0x66: 0x6004, 0x67: 0x6004, 0x68: 0x6004, 0x69: 0x6004,
+ 0x6a: 0x6004, 0x6b: 0x6004, 0x6c: 0x6004, 0x6d: 0x6004, 0x6e: 0x6004, 0x6f: 0x6004,
+ 0x70: 0x6004, 0x71: 0x6004, 0x72: 0x6004, 0x73: 0x6004, 0x74: 0x6004, 0x75: 0x6004,
+ 0x76: 0x6004, 0x77: 0x6004, 0x78: 0x6004, 0x79: 0x6004, 0x7a: 0x6004, 0x7b: 0x6004,
+ 0x7c: 0x6004, 0x7d: 0x6004, 0x7e: 0x6004,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xe1: 0x2000, 0xe2: 0x6005, 0xe3: 0x6005,
+ 0xe4: 0x2000, 0xe5: 0x6006, 0xe6: 0x6005, 0xe7: 0x2000, 0xe8: 0x2000,
+ 0xea: 0x2000, 0xec: 0x6007, 0xed: 0x2000, 0xee: 0x2000, 0xef: 0x6008,
+ 0xf0: 0x2000, 0xf1: 0x2000, 0xf2: 0x2000, 0xf3: 0x2000, 0xf4: 0x2000,
+ 0xf6: 0x2000, 0xf7: 0x2000, 0xf8: 0x2000, 0xf9: 0x2000, 0xfa: 0x2000,
+ 0xfc: 0x2000, 0xfd: 0x2000, 0xfe: 0x2000, 0xff: 0x2000,
+ // Block 0x4, offset 0x100
+ 0x106: 0x2000,
+ 0x110: 0x2000,
+ 0x117: 0x2000,
+ 0x118: 0x2000,
+ 0x11e: 0x2000, 0x11f: 0x2000, 0x120: 0x2000, 0x121: 0x2000,
+ 0x126: 0x2000, 0x128: 0x2000, 0x129: 0x2000,
+ 0x12a: 0x2000, 0x12c: 0x2000, 0x12d: 0x2000,
+ 0x130: 0x2000, 0x132: 0x2000, 0x133: 0x2000,
+ 0x137: 0x2000, 0x138: 0x2000, 0x139: 0x2000, 0x13a: 0x2000,
+ 0x13c: 0x2000, 0x13e: 0x2000,
+ // Block 0x5, offset 0x140
+ 0x141: 0x2000,
+ 0x151: 0x2000,
+ 0x153: 0x2000,
+ 0x15b: 0x2000,
+ 0x166: 0x2000, 0x167: 0x2000,
+ 0x16b: 0x2000,
+ 0x171: 0x2000, 0x172: 0x2000, 0x173: 0x2000,
+ 0x178: 0x2000,
+ 0x17f: 0x2000,
+ // Block 0x6, offset 0x180
+ 0x180: 0x2000, 0x181: 0x2000, 0x182: 0x2000, 0x184: 0x2000,
+ 0x188: 0x2000, 0x189: 0x2000, 0x18a: 0x2000, 0x18b: 0x2000,
+ 0x18d: 0x2000,
+ 0x192: 0x2000, 0x193: 0x2000,
+ 0x1a6: 0x2000, 0x1a7: 0x2000,
+ 0x1ab: 0x2000,
+ // Block 0x7, offset 0x1c0
+ 0x1ce: 0x2000, 0x1d0: 0x2000,
+ 0x1d2: 0x2000, 0x1d4: 0x2000, 0x1d6: 0x2000,
+ 0x1d8: 0x2000, 0x1da: 0x2000, 0x1dc: 0x2000,
+ // Block 0x8, offset 0x200
+ 0x211: 0x2000,
+ 0x221: 0x2000,
+ // Block 0x9, offset 0x240
+ 0x244: 0x2000,
+ 0x247: 0x2000, 0x249: 0x2000, 0x24a: 0x2000, 0x24b: 0x2000,
+ 0x24d: 0x2000, 0x250: 0x2000,
+ 0x258: 0x2000, 0x259: 0x2000, 0x25a: 0x2000, 0x25b: 0x2000, 0x25d: 0x2000,
+ 0x25f: 0x2000,
+ // Block 0xa, offset 0x280
+ 0x280: 0x2000, 0x281: 0x2000, 0x282: 0x2000, 0x283: 0x2000, 0x284: 0x2000, 0x285: 0x2000,
+ 0x286: 0x2000, 0x287: 0x2000, 0x288: 0x2000, 0x289: 0x2000, 0x28a: 0x2000, 0x28b: 0x2000,
+ 0x28c: 0x2000, 0x28d: 0x2000, 0x28e: 0x2000, 0x28f: 0x2000, 0x290: 0x2000, 0x291: 0x2000,
+ 0x292: 0x2000, 0x293: 0x2000, 0x294: 0x2000, 0x295: 0x2000, 0x296: 0x2000, 0x297: 0x2000,
+ 0x298: 0x2000, 0x299: 0x2000, 0x29a: 0x2000, 0x29b: 0x2000, 0x29c: 0x2000, 0x29d: 0x2000,
+ 0x29e: 0x2000, 0x29f: 0x2000, 0x2a0: 0x2000, 0x2a1: 0x2000, 0x2a2: 0x2000, 0x2a3: 0x2000,
+ 0x2a4: 0x2000, 0x2a5: 0x2000, 0x2a6: 0x2000, 0x2a7: 0x2000, 0x2a8: 0x2000, 0x2a9: 0x2000,
+ 0x2aa: 0x2000, 0x2ab: 0x2000, 0x2ac: 0x2000, 0x2ad: 0x2000, 0x2ae: 0x2000, 0x2af: 0x2000,
+ 0x2b0: 0x2000, 0x2b1: 0x2000, 0x2b2: 0x2000, 0x2b3: 0x2000, 0x2b4: 0x2000, 0x2b5: 0x2000,
+ 0x2b6: 0x2000, 0x2b7: 0x2000, 0x2b8: 0x2000, 0x2b9: 0x2000, 0x2ba: 0x2000, 0x2bb: 0x2000,
+ 0x2bc: 0x2000, 0x2bd: 0x2000, 0x2be: 0x2000, 0x2bf: 0x2000,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x2000, 0x2c1: 0x2000, 0x2c2: 0x2000, 0x2c3: 0x2000, 0x2c4: 0x2000, 0x2c5: 0x2000,
+ 0x2c6: 0x2000, 0x2c7: 0x2000, 0x2c8: 0x2000, 0x2c9: 0x2000, 0x2ca: 0x2000, 0x2cb: 0x2000,
+ 0x2cc: 0x2000, 0x2cd: 0x2000, 0x2ce: 0x2000, 0x2cf: 0x2000, 0x2d0: 0x2000, 0x2d1: 0x2000,
+ 0x2d2: 0x2000, 0x2d3: 0x2000, 0x2d4: 0x2000, 0x2d5: 0x2000, 0x2d6: 0x2000, 0x2d7: 0x2000,
+ 0x2d8: 0x2000, 0x2d9: 0x2000, 0x2da: 0x2000, 0x2db: 0x2000, 0x2dc: 0x2000, 0x2dd: 0x2000,
+ 0x2de: 0x2000, 0x2df: 0x2000, 0x2e0: 0x2000, 0x2e1: 0x2000, 0x2e2: 0x2000, 0x2e3: 0x2000,
+ 0x2e4: 0x2000, 0x2e5: 0x2000, 0x2e6: 0x2000, 0x2e7: 0x2000, 0x2e8: 0x2000, 0x2e9: 0x2000,
+ 0x2ea: 0x2000, 0x2eb: 0x2000, 0x2ec: 0x2000, 0x2ed: 0x2000, 0x2ee: 0x2000, 0x2ef: 0x2000,
+ // Block 0xc, offset 0x300
+ 0x311: 0x2000,
+ 0x312: 0x2000, 0x313: 0x2000, 0x314: 0x2000, 0x315: 0x2000, 0x316: 0x2000, 0x317: 0x2000,
+ 0x318: 0x2000, 0x319: 0x2000, 0x31a: 0x2000, 0x31b: 0x2000, 0x31c: 0x2000, 0x31d: 0x2000,
+ 0x31e: 0x2000, 0x31f: 0x2000, 0x320: 0x2000, 0x321: 0x2000, 0x323: 0x2000,
+ 0x324: 0x2000, 0x325: 0x2000, 0x326: 0x2000, 0x327: 0x2000, 0x328: 0x2000, 0x329: 0x2000,
+ 0x331: 0x2000, 0x332: 0x2000, 0x333: 0x2000, 0x334: 0x2000, 0x335: 0x2000,
+ 0x336: 0x2000, 0x337: 0x2000, 0x338: 0x2000, 0x339: 0x2000, 0x33a: 0x2000, 0x33b: 0x2000,
+ 0x33c: 0x2000, 0x33d: 0x2000, 0x33e: 0x2000, 0x33f: 0x2000,
+ // Block 0xd, offset 0x340
+ 0x340: 0x2000, 0x341: 0x2000, 0x343: 0x2000, 0x344: 0x2000, 0x345: 0x2000,
+ 0x346: 0x2000, 0x347: 0x2000, 0x348: 0x2000, 0x349: 0x2000,
+ // Block 0xe, offset 0x380
+ 0x381: 0x2000,
+ 0x390: 0x2000, 0x391: 0x2000,
+ 0x392: 0x2000, 0x393: 0x2000, 0x394: 0x2000, 0x395: 0x2000, 0x396: 0x2000, 0x397: 0x2000,
+ 0x398: 0x2000, 0x399: 0x2000, 0x39a: 0x2000, 0x39b: 0x2000, 0x39c: 0x2000, 0x39d: 0x2000,
+ 0x39e: 0x2000, 0x39f: 0x2000, 0x3a0: 0x2000, 0x3a1: 0x2000, 0x3a2: 0x2000, 0x3a3: 0x2000,
+ 0x3a4: 0x2000, 0x3a5: 0x2000, 0x3a6: 0x2000, 0x3a7: 0x2000, 0x3a8: 0x2000, 0x3a9: 0x2000,
+ 0x3aa: 0x2000, 0x3ab: 0x2000, 0x3ac: 0x2000, 0x3ad: 0x2000, 0x3ae: 0x2000, 0x3af: 0x2000,
+ 0x3b0: 0x2000, 0x3b1: 0x2000, 0x3b2: 0x2000, 0x3b3: 0x2000, 0x3b4: 0x2000, 0x3b5: 0x2000,
+ 0x3b6: 0x2000, 0x3b7: 0x2000, 0x3b8: 0x2000, 0x3b9: 0x2000, 0x3ba: 0x2000, 0x3bb: 0x2000,
+ 0x3bc: 0x2000, 0x3bd: 0x2000, 0x3be: 0x2000, 0x3bf: 0x2000,
+ // Block 0xf, offset 0x3c0
+ 0x3c0: 0x2000, 0x3c1: 0x2000, 0x3c2: 0x2000, 0x3c3: 0x2000, 0x3c4: 0x2000, 0x3c5: 0x2000,
+ 0x3c6: 0x2000, 0x3c7: 0x2000, 0x3c8: 0x2000, 0x3c9: 0x2000, 0x3ca: 0x2000, 0x3cb: 0x2000,
+ 0x3cc: 0x2000, 0x3cd: 0x2000, 0x3ce: 0x2000, 0x3cf: 0x2000, 0x3d1: 0x2000,
+ // Block 0x10, offset 0x400
+ 0x400: 0x4000, 0x401: 0x4000, 0x402: 0x4000, 0x403: 0x4000, 0x404: 0x4000, 0x405: 0x4000,
+ 0x406: 0x4000, 0x407: 0x4000, 0x408: 0x4000, 0x409: 0x4000, 0x40a: 0x4000, 0x40b: 0x4000,
+ 0x40c: 0x4000, 0x40d: 0x4000, 0x40e: 0x4000, 0x40f: 0x4000, 0x410: 0x4000, 0x411: 0x4000,
+ 0x412: 0x4000, 0x413: 0x4000, 0x414: 0x4000, 0x415: 0x4000, 0x416: 0x4000, 0x417: 0x4000,
+ 0x418: 0x4000, 0x419: 0x4000, 0x41a: 0x4000, 0x41b: 0x4000, 0x41c: 0x4000, 0x41d: 0x4000,
+ 0x41e: 0x4000, 0x41f: 0x4000, 0x420: 0x4000, 0x421: 0x4000, 0x422: 0x4000, 0x423: 0x4000,
+ 0x424: 0x4000, 0x425: 0x4000, 0x426: 0x4000, 0x427: 0x4000, 0x428: 0x4000, 0x429: 0x4000,
+ 0x42a: 0x4000, 0x42b: 0x4000, 0x42c: 0x4000, 0x42d: 0x4000, 0x42e: 0x4000, 0x42f: 0x4000,
+ 0x430: 0x4000, 0x431: 0x4000, 0x432: 0x4000, 0x433: 0x4000, 0x434: 0x4000, 0x435: 0x4000,
+ 0x436: 0x4000, 0x437: 0x4000, 0x438: 0x4000, 0x439: 0x4000, 0x43a: 0x4000, 0x43b: 0x4000,
+ 0x43c: 0x4000, 0x43d: 0x4000, 0x43e: 0x4000, 0x43f: 0x4000,
+ // Block 0x11, offset 0x440
+ 0x440: 0x4000, 0x441: 0x4000, 0x442: 0x4000, 0x443: 0x4000, 0x444: 0x4000, 0x445: 0x4000,
+ 0x446: 0x4000, 0x447: 0x4000, 0x448: 0x4000, 0x449: 0x4000, 0x44a: 0x4000, 0x44b: 0x4000,
+ 0x44c: 0x4000, 0x44d: 0x4000, 0x44e: 0x4000, 0x44f: 0x4000, 0x450: 0x4000, 0x451: 0x4000,
+ 0x452: 0x4000, 0x453: 0x4000, 0x454: 0x4000, 0x455: 0x4000, 0x456: 0x4000, 0x457: 0x4000,
+ 0x458: 0x4000, 0x459: 0x4000, 0x45a: 0x4000, 0x45b: 0x4000, 0x45c: 0x4000, 0x45d: 0x4000,
+ 0x45e: 0x4000, 0x45f: 0x4000,
+ // Block 0x12, offset 0x480
+ 0x490: 0x2000,
+ 0x493: 0x2000, 0x494: 0x2000, 0x495: 0x2000, 0x496: 0x2000,
+ 0x498: 0x2000, 0x499: 0x2000, 0x49c: 0x2000, 0x49d: 0x2000,
+ 0x4a0: 0x2000, 0x4a1: 0x2000, 0x4a2: 0x2000,
+ 0x4a4: 0x2000, 0x4a5: 0x2000, 0x4a6: 0x2000, 0x4a7: 0x2000,
+ 0x4b0: 0x2000, 0x4b2: 0x2000, 0x4b3: 0x2000, 0x4b5: 0x2000,
+ 0x4bb: 0x2000,
+ 0x4be: 0x2000,
+ // Block 0x13, offset 0x4c0
+ 0x4f4: 0x2000,
+ 0x4ff: 0x2000,
+ // Block 0x14, offset 0x500
+ 0x501: 0x2000, 0x502: 0x2000, 0x503: 0x2000, 0x504: 0x2000,
+ 0x529: 0xa009,
+ 0x52c: 0x2000,
+ // Block 0x15, offset 0x540
+ 0x543: 0x2000, 0x545: 0x2000,
+ 0x549: 0x2000,
+ 0x553: 0x2000, 0x556: 0x2000,
+ 0x561: 0x2000, 0x562: 0x2000,
+ 0x566: 0x2000,
+ 0x56b: 0x2000,
+ // Block 0x16, offset 0x580
+ 0x593: 0x2000, 0x594: 0x2000,
+ 0x59b: 0x2000, 0x59c: 0x2000, 0x59d: 0x2000,
+ 0x59e: 0x2000, 0x5a0: 0x2000, 0x5a1: 0x2000, 0x5a2: 0x2000, 0x5a3: 0x2000,
+ 0x5a4: 0x2000, 0x5a5: 0x2000, 0x5a6: 0x2000, 0x5a7: 0x2000, 0x5a8: 0x2000, 0x5a9: 0x2000,
+ 0x5aa: 0x2000, 0x5ab: 0x2000,
+ 0x5b0: 0x2000, 0x5b1: 0x2000, 0x5b2: 0x2000, 0x5b3: 0x2000, 0x5b4: 0x2000, 0x5b5: 0x2000,
+ 0x5b6: 0x2000, 0x5b7: 0x2000, 0x5b8: 0x2000, 0x5b9: 0x2000,
+ // Block 0x17, offset 0x5c0
+ 0x5c9: 0x2000,
+ 0x5d0: 0x200a, 0x5d1: 0x200b,
+ 0x5d2: 0x200a, 0x5d3: 0x200c, 0x5d4: 0x2000, 0x5d5: 0x2000, 0x5d6: 0x2000, 0x5d7: 0x2000,
+ 0x5d8: 0x2000, 0x5d9: 0x2000,
+ 0x5f8: 0x2000, 0x5f9: 0x2000,
+ // Block 0x18, offset 0x600
+ 0x612: 0x2000, 0x614: 0x2000,
+ 0x627: 0x2000,
+ // Block 0x19, offset 0x640
+ 0x640: 0x2000, 0x642: 0x2000, 0x643: 0x2000,
+ 0x647: 0x2000, 0x648: 0x2000, 0x64b: 0x2000,
+ 0x64f: 0x2000, 0x651: 0x2000,
+ 0x655: 0x2000,
+ 0x65a: 0x2000, 0x65d: 0x2000,
+ 0x65e: 0x2000, 0x65f: 0x2000, 0x660: 0x2000, 0x663: 0x2000,
+ 0x665: 0x2000, 0x667: 0x2000, 0x668: 0x2000, 0x669: 0x2000,
+ 0x66a: 0x2000, 0x66b: 0x2000, 0x66c: 0x2000, 0x66e: 0x2000,
+ 0x674: 0x2000, 0x675: 0x2000,
+ 0x676: 0x2000, 0x677: 0x2000,
+ 0x67c: 0x2000, 0x67d: 0x2000,
+ // Block 0x1a, offset 0x680
+ 0x688: 0x2000,
+ 0x68c: 0x2000,
+ 0x692: 0x2000,
+ 0x6a0: 0x2000, 0x6a1: 0x2000,
+ 0x6a4: 0x2000, 0x6a5: 0x2000, 0x6a6: 0x2000, 0x6a7: 0x2000,
+ 0x6aa: 0x2000, 0x6ab: 0x2000, 0x6ae: 0x2000, 0x6af: 0x2000,
+ // Block 0x1b, offset 0x6c0
+ 0x6c2: 0x2000, 0x6c3: 0x2000,
+ 0x6c6: 0x2000, 0x6c7: 0x2000,
+ 0x6d5: 0x2000,
+ 0x6d9: 0x2000,
+ 0x6e5: 0x2000,
+ 0x6ff: 0x2000,
+ // Block 0x1c, offset 0x700
+ 0x712: 0x2000,
+ 0x71a: 0x4000, 0x71b: 0x4000,
+ 0x729: 0x4000,
+ 0x72a: 0x4000,
+ // Block 0x1d, offset 0x740
+ 0x769: 0x4000,
+ 0x76a: 0x4000, 0x76b: 0x4000, 0x76c: 0x4000,
+ 0x770: 0x4000, 0x773: 0x4000,
+ // Block 0x1e, offset 0x780
+ 0x7a0: 0x2000, 0x7a1: 0x2000, 0x7a2: 0x2000, 0x7a3: 0x2000,
+ 0x7a4: 0x2000, 0x7a5: 0x2000, 0x7a6: 0x2000, 0x7a7: 0x2000, 0x7a8: 0x2000, 0x7a9: 0x2000,
+ 0x7aa: 0x2000, 0x7ab: 0x2000, 0x7ac: 0x2000, 0x7ad: 0x2000, 0x7ae: 0x2000, 0x7af: 0x2000,
+ 0x7b0: 0x2000, 0x7b1: 0x2000, 0x7b2: 0x2000, 0x7b3: 0x2000, 0x7b4: 0x2000, 0x7b5: 0x2000,
+ 0x7b6: 0x2000, 0x7b7: 0x2000, 0x7b8: 0x2000, 0x7b9: 0x2000, 0x7ba: 0x2000, 0x7bb: 0x2000,
+ 0x7bc: 0x2000, 0x7bd: 0x2000, 0x7be: 0x2000, 0x7bf: 0x2000,
+ // Block 0x1f, offset 0x7c0
+ 0x7c0: 0x2000, 0x7c1: 0x2000, 0x7c2: 0x2000, 0x7c3: 0x2000, 0x7c4: 0x2000, 0x7c5: 0x2000,
+ 0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7c9: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000,
+ 0x7cc: 0x2000, 0x7cd: 0x2000, 0x7ce: 0x2000, 0x7cf: 0x2000, 0x7d0: 0x2000, 0x7d1: 0x2000,
+ 0x7d2: 0x2000, 0x7d3: 0x2000, 0x7d4: 0x2000, 0x7d5: 0x2000, 0x7d6: 0x2000, 0x7d7: 0x2000,
+ 0x7d8: 0x2000, 0x7d9: 0x2000, 0x7da: 0x2000, 0x7db: 0x2000, 0x7dc: 0x2000, 0x7dd: 0x2000,
+ 0x7de: 0x2000, 0x7df: 0x2000, 0x7e0: 0x2000, 0x7e1: 0x2000, 0x7e2: 0x2000, 0x7e3: 0x2000,
+ 0x7e4: 0x2000, 0x7e5: 0x2000, 0x7e6: 0x2000, 0x7e7: 0x2000, 0x7e8: 0x2000, 0x7e9: 0x2000,
+ 0x7eb: 0x2000, 0x7ec: 0x2000, 0x7ed: 0x2000, 0x7ee: 0x2000, 0x7ef: 0x2000,
+ 0x7f0: 0x2000, 0x7f1: 0x2000, 0x7f2: 0x2000, 0x7f3: 0x2000, 0x7f4: 0x2000, 0x7f5: 0x2000,
+ 0x7f6: 0x2000, 0x7f7: 0x2000, 0x7f8: 0x2000, 0x7f9: 0x2000, 0x7fa: 0x2000, 0x7fb: 0x2000,
+ 0x7fc: 0x2000, 0x7fd: 0x2000, 0x7fe: 0x2000, 0x7ff: 0x2000,
+ // Block 0x20, offset 0x800
+ 0x800: 0x2000, 0x801: 0x2000, 0x802: 0x200d, 0x803: 0x2000, 0x804: 0x2000, 0x805: 0x2000,
+ 0x806: 0x2000, 0x807: 0x2000, 0x808: 0x2000, 0x809: 0x2000, 0x80a: 0x2000, 0x80b: 0x2000,
+ 0x80c: 0x2000, 0x80d: 0x2000, 0x80e: 0x2000, 0x80f: 0x2000, 0x810: 0x2000, 0x811: 0x2000,
+ 0x812: 0x2000, 0x813: 0x2000, 0x814: 0x2000, 0x815: 0x2000, 0x816: 0x2000, 0x817: 0x2000,
+ 0x818: 0x2000, 0x819: 0x2000, 0x81a: 0x2000, 0x81b: 0x2000, 0x81c: 0x2000, 0x81d: 0x2000,
+ 0x81e: 0x2000, 0x81f: 0x2000, 0x820: 0x2000, 0x821: 0x2000, 0x822: 0x2000, 0x823: 0x2000,
+ 0x824: 0x2000, 0x825: 0x2000, 0x826: 0x2000, 0x827: 0x2000, 0x828: 0x2000, 0x829: 0x2000,
+ 0x82a: 0x2000, 0x82b: 0x2000, 0x82c: 0x2000, 0x82d: 0x2000, 0x82e: 0x2000, 0x82f: 0x2000,
+ 0x830: 0x2000, 0x831: 0x2000, 0x832: 0x2000, 0x833: 0x2000, 0x834: 0x2000, 0x835: 0x2000,
+ 0x836: 0x2000, 0x837: 0x2000, 0x838: 0x2000, 0x839: 0x2000, 0x83a: 0x2000, 0x83b: 0x2000,
+ 0x83c: 0x2000, 0x83d: 0x2000, 0x83e: 0x2000, 0x83f: 0x2000,
+ // Block 0x21, offset 0x840
+ 0x840: 0x2000, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, 0x845: 0x2000,
+ 0x846: 0x2000, 0x847: 0x2000, 0x848: 0x2000, 0x849: 0x2000, 0x84a: 0x2000, 0x84b: 0x2000,
+ 0x850: 0x2000, 0x851: 0x2000,
+ 0x852: 0x2000, 0x853: 0x2000, 0x854: 0x2000, 0x855: 0x2000, 0x856: 0x2000, 0x857: 0x2000,
+ 0x858: 0x2000, 0x859: 0x2000, 0x85a: 0x2000, 0x85b: 0x2000, 0x85c: 0x2000, 0x85d: 0x2000,
+ 0x85e: 0x2000, 0x85f: 0x2000, 0x860: 0x2000, 0x861: 0x2000, 0x862: 0x2000, 0x863: 0x2000,
+ 0x864: 0x2000, 0x865: 0x2000, 0x866: 0x2000, 0x867: 0x2000, 0x868: 0x2000, 0x869: 0x2000,
+ 0x86a: 0x2000, 0x86b: 0x2000, 0x86c: 0x2000, 0x86d: 0x2000, 0x86e: 0x2000, 0x86f: 0x2000,
+ 0x870: 0x2000, 0x871: 0x2000, 0x872: 0x2000, 0x873: 0x2000,
+ // Block 0x22, offset 0x880
+ 0x880: 0x2000, 0x881: 0x2000, 0x882: 0x2000, 0x883: 0x2000, 0x884: 0x2000, 0x885: 0x2000,
+ 0x886: 0x2000, 0x887: 0x2000, 0x888: 0x2000, 0x889: 0x2000, 0x88a: 0x2000, 0x88b: 0x2000,
+ 0x88c: 0x2000, 0x88d: 0x2000, 0x88e: 0x2000, 0x88f: 0x2000,
+ 0x892: 0x2000, 0x893: 0x2000, 0x894: 0x2000, 0x895: 0x2000,
+ 0x8a0: 0x200e, 0x8a1: 0x2000, 0x8a3: 0x2000,
+ 0x8a4: 0x2000, 0x8a5: 0x2000, 0x8a6: 0x2000, 0x8a7: 0x2000, 0x8a8: 0x2000, 0x8a9: 0x2000,
+ 0x8b2: 0x2000, 0x8b3: 0x2000,
+ 0x8b6: 0x2000, 0x8b7: 0x2000,
+ 0x8bc: 0x2000, 0x8bd: 0x2000,
+ // Block 0x23, offset 0x8c0
+ 0x8c0: 0x2000, 0x8c1: 0x2000,
+ 0x8c6: 0x2000, 0x8c7: 0x2000, 0x8c8: 0x2000, 0x8cb: 0x200f,
+ 0x8ce: 0x2000, 0x8cf: 0x2000, 0x8d0: 0x2000, 0x8d1: 0x2000,
+ 0x8e2: 0x2000, 0x8e3: 0x2000,
+ 0x8e4: 0x2000, 0x8e5: 0x2000,
+ 0x8ef: 0x2000,
+ 0x8fd: 0x4000, 0x8fe: 0x4000,
+ // Block 0x24, offset 0x900
+ 0x905: 0x2000,
+ 0x906: 0x2000, 0x909: 0x2000,
+ 0x90e: 0x2000, 0x90f: 0x2000,
+ 0x914: 0x4000, 0x915: 0x4000,
+ 0x91c: 0x2000,
+ 0x91e: 0x2000,
+ // Block 0x25, offset 0x940
+ 0x940: 0x2000, 0x942: 0x2000,
+ 0x948: 0x4000, 0x949: 0x4000, 0x94a: 0x4000, 0x94b: 0x4000,
+ 0x94c: 0x4000, 0x94d: 0x4000, 0x94e: 0x4000, 0x94f: 0x4000, 0x950: 0x4000, 0x951: 0x4000,
+ 0x952: 0x4000, 0x953: 0x4000,
+ 0x960: 0x2000, 0x961: 0x2000, 0x963: 0x2000,
+ 0x964: 0x2000, 0x965: 0x2000, 0x967: 0x2000, 0x968: 0x2000, 0x969: 0x2000,
+ 0x96a: 0x2000, 0x96c: 0x2000, 0x96d: 0x2000, 0x96f: 0x2000,
+ 0x97f: 0x4000,
+ // Block 0x26, offset 0x980
+ 0x993: 0x4000,
+ 0x99e: 0x2000, 0x99f: 0x2000, 0x9a1: 0x4000,
+ 0x9aa: 0x4000, 0x9ab: 0x4000,
+ 0x9bd: 0x4000, 0x9be: 0x4000, 0x9bf: 0x2000,
+ // Block 0x27, offset 0x9c0
+ 0x9c4: 0x4000, 0x9c5: 0x4000,
+ 0x9c6: 0x2000, 0x9c7: 0x2000, 0x9c8: 0x2000, 0x9c9: 0x2000, 0x9ca: 0x2000, 0x9cb: 0x2000,
+ 0x9cc: 0x2000, 0x9cd: 0x2000, 0x9ce: 0x4000, 0x9cf: 0x2000, 0x9d0: 0x2000, 0x9d1: 0x2000,
+ 0x9d2: 0x2000, 0x9d3: 0x2000, 0x9d4: 0x4000, 0x9d5: 0x2000, 0x9d6: 0x2000, 0x9d7: 0x2000,
+ 0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000,
+ 0x9de: 0x2000, 0x9df: 0x2000, 0x9e0: 0x2000, 0x9e1: 0x2000, 0x9e3: 0x2000,
+ 0x9e8: 0x2000, 0x9e9: 0x2000,
+ 0x9ea: 0x4000, 0x9eb: 0x2000, 0x9ec: 0x2000, 0x9ed: 0x2000, 0x9ee: 0x2000, 0x9ef: 0x2000,
+ 0x9f0: 0x2000, 0x9f1: 0x2000, 0x9f2: 0x4000, 0x9f3: 0x4000, 0x9f4: 0x2000, 0x9f5: 0x4000,
+ 0x9f6: 0x2000, 0x9f7: 0x2000, 0x9f8: 0x2000, 0x9f9: 0x2000, 0x9fa: 0x4000, 0x9fb: 0x2000,
+ 0x9fc: 0x2000, 0x9fd: 0x4000, 0x9fe: 0x2000, 0x9ff: 0x2000,
+ // Block 0x28, offset 0xa00
+ 0xa05: 0x4000,
+ 0xa0a: 0x4000, 0xa0b: 0x4000,
+ 0xa28: 0x4000,
+ 0xa3d: 0x2000,
+ // Block 0x29, offset 0xa40
+ 0xa4c: 0x4000, 0xa4e: 0x4000,
+ 0xa53: 0x4000, 0xa54: 0x4000, 0xa55: 0x4000, 0xa57: 0x4000,
+ 0xa76: 0x2000, 0xa77: 0x2000, 0xa78: 0x2000, 0xa79: 0x2000, 0xa7a: 0x2000, 0xa7b: 0x2000,
+ 0xa7c: 0x2000, 0xa7d: 0x2000, 0xa7e: 0x2000, 0xa7f: 0x2000,
+ // Block 0x2a, offset 0xa80
+ 0xa95: 0x4000, 0xa96: 0x4000, 0xa97: 0x4000,
+ 0xab0: 0x4000,
+ 0xabf: 0x4000,
+ // Block 0x2b, offset 0xac0
+ 0xae6: 0x6000, 0xae7: 0x6000, 0xae8: 0x6000, 0xae9: 0x6000,
+ 0xaea: 0x6000, 0xaeb: 0x6000, 0xaec: 0x6000, 0xaed: 0x6000,
+ // Block 0x2c, offset 0xb00
+ 0xb05: 0x6010,
+ 0xb06: 0x6011,
+ // Block 0x2d, offset 0xb40
+ 0xb5b: 0x4000, 0xb5c: 0x4000,
+ // Block 0x2e, offset 0xb80
+ 0xb90: 0x4000,
+ 0xb95: 0x4000, 0xb96: 0x2000, 0xb97: 0x2000,
+ 0xb98: 0x2000, 0xb99: 0x2000,
+ // Block 0x2f, offset 0xbc0
+ 0xbc0: 0x4000, 0xbc1: 0x4000, 0xbc2: 0x4000, 0xbc3: 0x4000, 0xbc4: 0x4000, 0xbc5: 0x4000,
+ 0xbc6: 0x4000, 0xbc7: 0x4000, 0xbc8: 0x4000, 0xbc9: 0x4000, 0xbca: 0x4000, 0xbcb: 0x4000,
+ 0xbcc: 0x4000, 0xbcd: 0x4000, 0xbce: 0x4000, 0xbcf: 0x4000, 0xbd0: 0x4000, 0xbd1: 0x4000,
+ 0xbd2: 0x4000, 0xbd3: 0x4000, 0xbd4: 0x4000, 0xbd5: 0x4000, 0xbd6: 0x4000, 0xbd7: 0x4000,
+ 0xbd8: 0x4000, 0xbd9: 0x4000, 0xbdb: 0x4000, 0xbdc: 0x4000, 0xbdd: 0x4000,
+ 0xbde: 0x4000, 0xbdf: 0x4000, 0xbe0: 0x4000, 0xbe1: 0x4000, 0xbe2: 0x4000, 0xbe3: 0x4000,
+ 0xbe4: 0x4000, 0xbe5: 0x4000, 0xbe6: 0x4000, 0xbe7: 0x4000, 0xbe8: 0x4000, 0xbe9: 0x4000,
+ 0xbea: 0x4000, 0xbeb: 0x4000, 0xbec: 0x4000, 0xbed: 0x4000, 0xbee: 0x4000, 0xbef: 0x4000,
+ 0xbf0: 0x4000, 0xbf1: 0x4000, 0xbf2: 0x4000, 0xbf3: 0x4000, 0xbf4: 0x4000, 0xbf5: 0x4000,
+ 0xbf6: 0x4000, 0xbf7: 0x4000, 0xbf8: 0x4000, 0xbf9: 0x4000, 0xbfa: 0x4000, 0xbfb: 0x4000,
+ 0xbfc: 0x4000, 0xbfd: 0x4000, 0xbfe: 0x4000, 0xbff: 0x4000,
+ // Block 0x30, offset 0xc00
+ 0xc00: 0x4000, 0xc01: 0x4000, 0xc02: 0x4000, 0xc03: 0x4000, 0xc04: 0x4000, 0xc05: 0x4000,
+ 0xc06: 0x4000, 0xc07: 0x4000, 0xc08: 0x4000, 0xc09: 0x4000, 0xc0a: 0x4000, 0xc0b: 0x4000,
+ 0xc0c: 0x4000, 0xc0d: 0x4000, 0xc0e: 0x4000, 0xc0f: 0x4000, 0xc10: 0x4000, 0xc11: 0x4000,
+ 0xc12: 0x4000, 0xc13: 0x4000, 0xc14: 0x4000, 0xc15: 0x4000, 0xc16: 0x4000, 0xc17: 0x4000,
+ 0xc18: 0x4000, 0xc19: 0x4000, 0xc1a: 0x4000, 0xc1b: 0x4000, 0xc1c: 0x4000, 0xc1d: 0x4000,
+ 0xc1e: 0x4000, 0xc1f: 0x4000, 0xc20: 0x4000, 0xc21: 0x4000, 0xc22: 0x4000, 0xc23: 0x4000,
+ 0xc24: 0x4000, 0xc25: 0x4000, 0xc26: 0x4000, 0xc27: 0x4000, 0xc28: 0x4000, 0xc29: 0x4000,
+ 0xc2a: 0x4000, 0xc2b: 0x4000, 0xc2c: 0x4000, 0xc2d: 0x4000, 0xc2e: 0x4000, 0xc2f: 0x4000,
+ 0xc30: 0x4000, 0xc31: 0x4000, 0xc32: 0x4000, 0xc33: 0x4000,
+ // Block 0x31, offset 0xc40
+ 0xc40: 0x4000, 0xc41: 0x4000, 0xc42: 0x4000, 0xc43: 0x4000, 0xc44: 0x4000, 0xc45: 0x4000,
+ 0xc46: 0x4000, 0xc47: 0x4000, 0xc48: 0x4000, 0xc49: 0x4000, 0xc4a: 0x4000, 0xc4b: 0x4000,
+ 0xc4c: 0x4000, 0xc4d: 0x4000, 0xc4e: 0x4000, 0xc4f: 0x4000, 0xc50: 0x4000, 0xc51: 0x4000,
+ 0xc52: 0x4000, 0xc53: 0x4000, 0xc54: 0x4000, 0xc55: 0x4000,
+ 0xc70: 0x4000, 0xc71: 0x4000, 0xc72: 0x4000, 0xc73: 0x4000, 0xc74: 0x4000, 0xc75: 0x4000,
+ 0xc76: 0x4000, 0xc77: 0x4000, 0xc78: 0x4000, 0xc79: 0x4000, 0xc7a: 0x4000, 0xc7b: 0x4000,
+ // Block 0x32, offset 0xc80
+ 0xc80: 0x9012, 0xc81: 0x4013, 0xc82: 0x4014, 0xc83: 0x4000, 0xc84: 0x4000, 0xc85: 0x4000,
+ 0xc86: 0x4000, 0xc87: 0x4000, 0xc88: 0x4000, 0xc89: 0x4000, 0xc8a: 0x4000, 0xc8b: 0x4000,
+ 0xc8c: 0x4015, 0xc8d: 0x4015, 0xc8e: 0x4000, 0xc8f: 0x4000, 0xc90: 0x4000, 0xc91: 0x4000,
+ 0xc92: 0x4000, 0xc93: 0x4000, 0xc94: 0x4000, 0xc95: 0x4000, 0xc96: 0x4000, 0xc97: 0x4000,
+ 0xc98: 0x4000, 0xc99: 0x4000, 0xc9a: 0x4000, 0xc9b: 0x4000, 0xc9c: 0x4000, 0xc9d: 0x4000,
+ 0xc9e: 0x4000, 0xc9f: 0x4000, 0xca0: 0x4000, 0xca1: 0x4000, 0xca2: 0x4000, 0xca3: 0x4000,
+ 0xca4: 0x4000, 0xca5: 0x4000, 0xca6: 0x4000, 0xca7: 0x4000, 0xca8: 0x4000, 0xca9: 0x4000,
+ 0xcaa: 0x4000, 0xcab: 0x4000, 0xcac: 0x4000, 0xcad: 0x4000, 0xcae: 0x4000, 0xcaf: 0x4000,
+ 0xcb0: 0x4000, 0xcb1: 0x4000, 0xcb2: 0x4000, 0xcb3: 0x4000, 0xcb4: 0x4000, 0xcb5: 0x4000,
+ 0xcb6: 0x4000, 0xcb7: 0x4000, 0xcb8: 0x4000, 0xcb9: 0x4000, 0xcba: 0x4000, 0xcbb: 0x4000,
+ 0xcbc: 0x4000, 0xcbd: 0x4000, 0xcbe: 0x4000,
+ // Block 0x33, offset 0xcc0
+ 0xcc1: 0x4000, 0xcc2: 0x4000, 0xcc3: 0x4000, 0xcc4: 0x4000, 0xcc5: 0x4000,
+ 0xcc6: 0x4000, 0xcc7: 0x4000, 0xcc8: 0x4000, 0xcc9: 0x4000, 0xcca: 0x4000, 0xccb: 0x4000,
+ 0xccc: 0x4000, 0xccd: 0x4000, 0xcce: 0x4000, 0xccf: 0x4000, 0xcd0: 0x4000, 0xcd1: 0x4000,
+ 0xcd2: 0x4000, 0xcd3: 0x4000, 0xcd4: 0x4000, 0xcd5: 0x4000, 0xcd6: 0x4000, 0xcd7: 0x4000,
+ 0xcd8: 0x4000, 0xcd9: 0x4000, 0xcda: 0x4000, 0xcdb: 0x4000, 0xcdc: 0x4000, 0xcdd: 0x4000,
+ 0xcde: 0x4000, 0xcdf: 0x4000, 0xce0: 0x4000, 0xce1: 0x4000, 0xce2: 0x4000, 0xce3: 0x4000,
+ 0xce4: 0x4000, 0xce5: 0x4000, 0xce6: 0x4000, 0xce7: 0x4000, 0xce8: 0x4000, 0xce9: 0x4000,
+ 0xcea: 0x4000, 0xceb: 0x4000, 0xcec: 0x4000, 0xced: 0x4000, 0xcee: 0x4000, 0xcef: 0x4000,
+ 0xcf0: 0x4000, 0xcf1: 0x4000, 0xcf2: 0x4000, 0xcf3: 0x4000, 0xcf4: 0x4000, 0xcf5: 0x4000,
+ 0xcf6: 0x4000, 0xcf7: 0x4000, 0xcf8: 0x4000, 0xcf9: 0x4000, 0xcfa: 0x4000, 0xcfb: 0x4000,
+ 0xcfc: 0x4000, 0xcfd: 0x4000, 0xcfe: 0x4000, 0xcff: 0x4000,
+ // Block 0x34, offset 0xd00
+ 0xd00: 0x4000, 0xd01: 0x4000, 0xd02: 0x4000, 0xd03: 0x4000, 0xd04: 0x4000, 0xd05: 0x4000,
+ 0xd06: 0x4000, 0xd07: 0x4000, 0xd08: 0x4000, 0xd09: 0x4000, 0xd0a: 0x4000, 0xd0b: 0x4000,
+ 0xd0c: 0x4000, 0xd0d: 0x4000, 0xd0e: 0x4000, 0xd0f: 0x4000, 0xd10: 0x4000, 0xd11: 0x4000,
+ 0xd12: 0x4000, 0xd13: 0x4000, 0xd14: 0x4000, 0xd15: 0x4000, 0xd16: 0x4000,
+ 0xd19: 0x4016, 0xd1a: 0x4017, 0xd1b: 0x4000, 0xd1c: 0x4000, 0xd1d: 0x4000,
+ 0xd1e: 0x4000, 0xd1f: 0x4000, 0xd20: 0x4000, 0xd21: 0x4018, 0xd22: 0x4019, 0xd23: 0x401a,
+ 0xd24: 0x401b, 0xd25: 0x401c, 0xd26: 0x401d, 0xd27: 0x401e, 0xd28: 0x401f, 0xd29: 0x4020,
+ 0xd2a: 0x4021, 0xd2b: 0x4022, 0xd2c: 0x4000, 0xd2d: 0x4010, 0xd2e: 0x4000, 0xd2f: 0x4023,
+ 0xd30: 0x4000, 0xd31: 0x4024, 0xd32: 0x4000, 0xd33: 0x4025, 0xd34: 0x4000, 0xd35: 0x4026,
+ 0xd36: 0x4000, 0xd37: 0x401a, 0xd38: 0x4000, 0xd39: 0x4027, 0xd3a: 0x4000, 0xd3b: 0x4028,
+ 0xd3c: 0x4000, 0xd3d: 0x4020, 0xd3e: 0x4000, 0xd3f: 0x4029,
+ // Block 0x35, offset 0xd40
+ 0xd40: 0x4000, 0xd41: 0x402a, 0xd42: 0x4000, 0xd43: 0x402b, 0xd44: 0x402c, 0xd45: 0x4000,
+ 0xd46: 0x4017, 0xd47: 0x4000, 0xd48: 0x402d, 0xd49: 0x4000, 0xd4a: 0x402e, 0xd4b: 0x402f,
+ 0xd4c: 0x4030, 0xd4d: 0x4017, 0xd4e: 0x4016, 0xd4f: 0x4017, 0xd50: 0x4000, 0xd51: 0x4000,
+ 0xd52: 0x4031, 0xd53: 0x4000, 0xd54: 0x4000, 0xd55: 0x4031, 0xd56: 0x4000, 0xd57: 0x4000,
+ 0xd58: 0x4032, 0xd59: 0x4000, 0xd5a: 0x4000, 0xd5b: 0x4032, 0xd5c: 0x4000, 0xd5d: 0x4000,
+ 0xd5e: 0x4033, 0xd5f: 0x402e, 0xd60: 0x4034, 0xd61: 0x4035, 0xd62: 0x4034, 0xd63: 0x4036,
+ 0xd64: 0x4037, 0xd65: 0x4024, 0xd66: 0x4035, 0xd67: 0x4025, 0xd68: 0x4038, 0xd69: 0x4038,
+ 0xd6a: 0x4039, 0xd6b: 0x4039, 0xd6c: 0x403a, 0xd6d: 0x403a, 0xd6e: 0x4000, 0xd6f: 0x4035,
+ 0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x403b, 0xd73: 0x403c, 0xd74: 0x4000, 0xd75: 0x4000,
+ 0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x403d,
+ 0xd7c: 0x401c, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000,
+ // Block 0x36, offset 0xd80
+ 0xd85: 0x4000,
+ 0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000,
+ 0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000,
+ 0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000,
+ 0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000,
+ 0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000,
+ 0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000,
+ 0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000,
+ 0xdb1: 0x403e, 0xdb2: 0x403e, 0xdb3: 0x403e, 0xdb4: 0x403e, 0xdb5: 0x403e,
+ 0xdb6: 0x403e, 0xdb7: 0x403e, 0xdb8: 0x403e, 0xdb9: 0x403e, 0xdba: 0x403e, 0xdbb: 0x403e,
+ 0xdbc: 0x403e, 0xdbd: 0x403e, 0xdbe: 0x403e, 0xdbf: 0x403e,
+ // Block 0x37, offset 0xdc0
+ 0xdc0: 0x4037, 0xdc1: 0x4037, 0xdc2: 0x4037, 0xdc3: 0x4037, 0xdc4: 0x4037, 0xdc5: 0x4037,
+ 0xdc6: 0x4037, 0xdc7: 0x4037, 0xdc8: 0x4037, 0xdc9: 0x4037, 0xdca: 0x4037, 0xdcb: 0x4037,
+ 0xdcc: 0x4037, 0xdcd: 0x4037, 0xdce: 0x4037, 0xdcf: 0x400e, 0xdd0: 0x403f, 0xdd1: 0x4040,
+ 0xdd2: 0x4041, 0xdd3: 0x4040, 0xdd4: 0x403f, 0xdd5: 0x4042, 0xdd6: 0x4043, 0xdd7: 0x4044,
+ 0xdd8: 0x4040, 0xdd9: 0x4041, 0xdda: 0x4040, 0xddb: 0x4045, 0xddc: 0x4009, 0xddd: 0x4045,
+ 0xdde: 0x4046, 0xddf: 0x4045, 0xde0: 0x4047, 0xde1: 0x400b, 0xde2: 0x400a, 0xde3: 0x400c,
+ 0xde4: 0x4048, 0xde5: 0x4000, 0xde6: 0x4000, 0xde7: 0x4000, 0xde8: 0x4000, 0xde9: 0x4000,
+ 0xdea: 0x4000, 0xdeb: 0x4000, 0xdec: 0x4000, 0xded: 0x4000, 0xdee: 0x4000, 0xdef: 0x4000,
+ 0xdf0: 0x4000, 0xdf1: 0x4000, 0xdf2: 0x4000, 0xdf3: 0x4000, 0xdf4: 0x4000, 0xdf5: 0x4000,
+ 0xdf6: 0x4000, 0xdf7: 0x4000, 0xdf8: 0x4000, 0xdf9: 0x4000, 0xdfa: 0x4000, 0xdfb: 0x4000,
+ 0xdfc: 0x4000, 0xdfd: 0x4000, 0xdfe: 0x4000, 0xdff: 0x4000,
+ // Block 0x38, offset 0xe00
+ 0xe00: 0x4000, 0xe01: 0x4000, 0xe02: 0x4000, 0xe03: 0x4000, 0xe04: 0x4000, 0xe05: 0x4000,
+ 0xe06: 0x4000, 0xe07: 0x4000, 0xe08: 0x4000, 0xe09: 0x4000, 0xe0a: 0x4000, 0xe0b: 0x4000,
+ 0xe0c: 0x4000, 0xe0d: 0x4000, 0xe0e: 0x4000, 0xe10: 0x4000, 0xe11: 0x4000,
+ 0xe12: 0x4000, 0xe13: 0x4000, 0xe14: 0x4000, 0xe15: 0x4000, 0xe16: 0x4000, 0xe17: 0x4000,
+ 0xe18: 0x4000, 0xe19: 0x4000, 0xe1a: 0x4000, 0xe1b: 0x4000, 0xe1c: 0x4000, 0xe1d: 0x4000,
+ 0xe1e: 0x4000, 0xe1f: 0x4000, 0xe20: 0x4000, 0xe21: 0x4000, 0xe22: 0x4000, 0xe23: 0x4000,
+ 0xe24: 0x4000, 0xe25: 0x4000, 0xe26: 0x4000, 0xe27: 0x4000, 0xe28: 0x4000, 0xe29: 0x4000,
+ 0xe2a: 0x4000, 0xe2b: 0x4000, 0xe2c: 0x4000, 0xe2d: 0x4000, 0xe2e: 0x4000, 0xe2f: 0x4000,
+ 0xe30: 0x4000, 0xe31: 0x4000, 0xe32: 0x4000, 0xe33: 0x4000, 0xe34: 0x4000, 0xe35: 0x4000,
+ 0xe36: 0x4000, 0xe37: 0x4000, 0xe38: 0x4000, 0xe39: 0x4000, 0xe3a: 0x4000,
+ // Block 0x39, offset 0xe40
+ 0xe40: 0x4000, 0xe41: 0x4000, 0xe42: 0x4000, 0xe43: 0x4000, 0xe44: 0x4000, 0xe45: 0x4000,
+ 0xe46: 0x4000, 0xe47: 0x4000, 0xe48: 0x4000, 0xe49: 0x4000, 0xe4a: 0x4000, 0xe4b: 0x4000,
+ 0xe4c: 0x4000, 0xe4d: 0x4000, 0xe4e: 0x4000, 0xe4f: 0x4000, 0xe50: 0x4000, 0xe51: 0x4000,
+ 0xe52: 0x4000, 0xe53: 0x4000, 0xe54: 0x4000, 0xe55: 0x4000, 0xe56: 0x4000, 0xe57: 0x4000,
+ 0xe58: 0x4000, 0xe59: 0x4000, 0xe5a: 0x4000, 0xe5b: 0x4000, 0xe5c: 0x4000, 0xe5d: 0x4000,
+ 0xe5e: 0x4000, 0xe5f: 0x4000, 0xe60: 0x4000, 0xe61: 0x4000, 0xe62: 0x4000, 0xe63: 0x4000,
+ 0xe70: 0x4000, 0xe71: 0x4000, 0xe72: 0x4000, 0xe73: 0x4000, 0xe74: 0x4000, 0xe75: 0x4000,
+ 0xe76: 0x4000, 0xe77: 0x4000, 0xe78: 0x4000, 0xe79: 0x4000, 0xe7a: 0x4000, 0xe7b: 0x4000,
+ 0xe7c: 0x4000, 0xe7d: 0x4000, 0xe7e: 0x4000, 0xe7f: 0x4000,
+ // Block 0x3a, offset 0xe80
+ 0xe80: 0x4000, 0xe81: 0x4000, 0xe82: 0x4000, 0xe83: 0x4000, 0xe84: 0x4000, 0xe85: 0x4000,
+ 0xe86: 0x4000, 0xe87: 0x4000, 0xe88: 0x4000, 0xe89: 0x4000, 0xe8a: 0x4000, 0xe8b: 0x4000,
+ 0xe8c: 0x4000, 0xe8d: 0x4000, 0xe8e: 0x4000, 0xe8f: 0x4000, 0xe90: 0x4000, 0xe91: 0x4000,
+ 0xe92: 0x4000, 0xe93: 0x4000, 0xe94: 0x4000, 0xe95: 0x4000, 0xe96: 0x4000, 0xe97: 0x4000,
+ 0xe98: 0x4000, 0xe99: 0x4000, 0xe9a: 0x4000, 0xe9b: 0x4000, 0xe9c: 0x4000, 0xe9d: 0x4000,
+ 0xe9e: 0x4000, 0xea0: 0x4000, 0xea1: 0x4000, 0xea2: 0x4000, 0xea3: 0x4000,
+ 0xea4: 0x4000, 0xea5: 0x4000, 0xea6: 0x4000, 0xea7: 0x4000, 0xea8: 0x4000, 0xea9: 0x4000,
+ 0xeaa: 0x4000, 0xeab: 0x4000, 0xeac: 0x4000, 0xead: 0x4000, 0xeae: 0x4000, 0xeaf: 0x4000,
+ 0xeb0: 0x4000, 0xeb1: 0x4000, 0xeb2: 0x4000, 0xeb3: 0x4000, 0xeb4: 0x4000, 0xeb5: 0x4000,
+ 0xeb6: 0x4000, 0xeb7: 0x4000, 0xeb8: 0x4000, 0xeb9: 0x4000, 0xeba: 0x4000, 0xebb: 0x4000,
+ 0xebc: 0x4000, 0xebd: 0x4000, 0xebe: 0x4000, 0xebf: 0x4000,
+ // Block 0x3b, offset 0xec0
+ 0xec0: 0x4000, 0xec1: 0x4000, 0xec2: 0x4000, 0xec3: 0x4000, 0xec4: 0x4000, 0xec5: 0x4000,
+ 0xec6: 0x4000, 0xec7: 0x4000, 0xec8: 0x2000, 0xec9: 0x2000, 0xeca: 0x2000, 0xecb: 0x2000,
+ 0xecc: 0x2000, 0xecd: 0x2000, 0xece: 0x2000, 0xecf: 0x2000, 0xed0: 0x4000, 0xed1: 0x4000,
+ 0xed2: 0x4000, 0xed3: 0x4000, 0xed4: 0x4000, 0xed5: 0x4000, 0xed6: 0x4000, 0xed7: 0x4000,
+ 0xed8: 0x4000, 0xed9: 0x4000, 0xeda: 0x4000, 0xedb: 0x4000, 0xedc: 0x4000, 0xedd: 0x4000,
+ 0xede: 0x4000, 0xedf: 0x4000, 0xee0: 0x4000, 0xee1: 0x4000, 0xee2: 0x4000, 0xee3: 0x4000,
+ 0xee4: 0x4000, 0xee5: 0x4000, 0xee6: 0x4000, 0xee7: 0x4000, 0xee8: 0x4000, 0xee9: 0x4000,
+ 0xeea: 0x4000, 0xeeb: 0x4000, 0xeec: 0x4000, 0xeed: 0x4000, 0xeee: 0x4000, 0xeef: 0x4000,
+ 0xef0: 0x4000, 0xef1: 0x4000, 0xef2: 0x4000, 0xef3: 0x4000, 0xef4: 0x4000, 0xef5: 0x4000,
+ 0xef6: 0x4000, 0xef7: 0x4000, 0xef8: 0x4000, 0xef9: 0x4000, 0xefa: 0x4000, 0xefb: 0x4000,
+ 0xefc: 0x4000, 0xefd: 0x4000, 0xefe: 0x4000, 0xeff: 0x4000,
+ // Block 0x3c, offset 0xf00
+ 0xf00: 0x4000, 0xf01: 0x4000, 0xf02: 0x4000, 0xf03: 0x4000, 0xf04: 0x4000, 0xf05: 0x4000,
+ 0xf06: 0x4000, 0xf07: 0x4000, 0xf08: 0x4000, 0xf09: 0x4000, 0xf0a: 0x4000, 0xf0b: 0x4000,
+ 0xf0c: 0x4000, 0xf0d: 0x4000, 0xf0e: 0x4000, 0xf0f: 0x4000, 0xf10: 0x4000, 0xf11: 0x4000,
+ 0xf12: 0x4000, 0xf13: 0x4000, 0xf14: 0x4000, 0xf15: 0x4000, 0xf16: 0x4000, 0xf17: 0x4000,
+ 0xf18: 0x4000, 0xf19: 0x4000, 0xf1a: 0x4000, 0xf1b: 0x4000, 0xf1c: 0x4000, 0xf1d: 0x4000,
+ 0xf1e: 0x4000, 0xf1f: 0x4000, 0xf20: 0x4000, 0xf21: 0x4000, 0xf22: 0x4000, 0xf23: 0x4000,
+ 0xf24: 0x4000, 0xf25: 0x4000, 0xf26: 0x4000, 0xf27: 0x4000, 0xf28: 0x4000, 0xf29: 0x4000,
+ 0xf2a: 0x4000, 0xf2b: 0x4000, 0xf2c: 0x4000, 0xf2d: 0x4000, 0xf2e: 0x4000, 0xf2f: 0x4000,
+ 0xf30: 0x4000, 0xf31: 0x4000, 0xf32: 0x4000, 0xf33: 0x4000, 0xf34: 0x4000, 0xf35: 0x4000,
+ 0xf36: 0x4000, 0xf37: 0x4000, 0xf38: 0x4000, 0xf39: 0x4000, 0xf3a: 0x4000, 0xf3b: 0x4000,
+ 0xf3c: 0x4000, 0xf3d: 0x4000, 0xf3e: 0x4000,
+ // Block 0x3d, offset 0xf40
+ 0xf40: 0x4000, 0xf41: 0x4000, 0xf42: 0x4000, 0xf43: 0x4000, 0xf44: 0x4000, 0xf45: 0x4000,
+ 0xf46: 0x4000, 0xf47: 0x4000, 0xf48: 0x4000, 0xf49: 0x4000, 0xf4a: 0x4000, 0xf4b: 0x4000,
+ 0xf4c: 0x4000, 0xf50: 0x4000, 0xf51: 0x4000,
+ 0xf52: 0x4000, 0xf53: 0x4000, 0xf54: 0x4000, 0xf55: 0x4000, 0xf56: 0x4000, 0xf57: 0x4000,
+ 0xf58: 0x4000, 0xf59: 0x4000, 0xf5a: 0x4000, 0xf5b: 0x4000, 0xf5c: 0x4000, 0xf5d: 0x4000,
+ 0xf5e: 0x4000, 0xf5f: 0x4000, 0xf60: 0x4000, 0xf61: 0x4000, 0xf62: 0x4000, 0xf63: 0x4000,
+ 0xf64: 0x4000, 0xf65: 0x4000, 0xf66: 0x4000, 0xf67: 0x4000, 0xf68: 0x4000, 0xf69: 0x4000,
+ 0xf6a: 0x4000, 0xf6b: 0x4000, 0xf6c: 0x4000, 0xf6d: 0x4000, 0xf6e: 0x4000, 0xf6f: 0x4000,
+ 0xf70: 0x4000, 0xf71: 0x4000, 0xf72: 0x4000, 0xf73: 0x4000, 0xf74: 0x4000, 0xf75: 0x4000,
+ 0xf76: 0x4000, 0xf77: 0x4000, 0xf78: 0x4000, 0xf79: 0x4000, 0xf7a: 0x4000, 0xf7b: 0x4000,
+ 0xf7c: 0x4000, 0xf7d: 0x4000, 0xf7e: 0x4000, 0xf7f: 0x4000,
+ // Block 0x3e, offset 0xf80
+ 0xf80: 0x4000, 0xf81: 0x4000, 0xf82: 0x4000, 0xf83: 0x4000, 0xf84: 0x4000, 0xf85: 0x4000,
+ 0xf86: 0x4000,
+ // Block 0x3f, offset 0xfc0
+ 0xfe0: 0x4000, 0xfe1: 0x4000, 0xfe2: 0x4000, 0xfe3: 0x4000,
+ 0xfe4: 0x4000, 0xfe5: 0x4000, 0xfe6: 0x4000, 0xfe7: 0x4000, 0xfe8: 0x4000, 0xfe9: 0x4000,
+ 0xfea: 0x4000, 0xfeb: 0x4000, 0xfec: 0x4000, 0xfed: 0x4000, 0xfee: 0x4000, 0xfef: 0x4000,
+ 0xff0: 0x4000, 0xff1: 0x4000, 0xff2: 0x4000, 0xff3: 0x4000, 0xff4: 0x4000, 0xff5: 0x4000,
+ 0xff6: 0x4000, 0xff7: 0x4000, 0xff8: 0x4000, 0xff9: 0x4000, 0xffa: 0x4000, 0xffb: 0x4000,
+ 0xffc: 0x4000,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x4000, 0x1001: 0x4000, 0x1002: 0x4000, 0x1003: 0x4000, 0x1004: 0x4000, 0x1005: 0x4000,
+ 0x1006: 0x4000, 0x1007: 0x4000, 0x1008: 0x4000, 0x1009: 0x4000, 0x100a: 0x4000, 0x100b: 0x4000,
+ 0x100c: 0x4000, 0x100d: 0x4000, 0x100e: 0x4000, 0x100f: 0x4000, 0x1010: 0x4000, 0x1011: 0x4000,
+ 0x1012: 0x4000, 0x1013: 0x4000, 0x1014: 0x4000, 0x1015: 0x4000, 0x1016: 0x4000, 0x1017: 0x4000,
+ 0x1018: 0x4000, 0x1019: 0x4000, 0x101a: 0x4000, 0x101b: 0x4000, 0x101c: 0x4000, 0x101d: 0x4000,
+ 0x101e: 0x4000, 0x101f: 0x4000, 0x1020: 0x4000, 0x1021: 0x4000, 0x1022: 0x4000, 0x1023: 0x4000,
+ // Block 0x41, offset 0x1040
+ 0x1040: 0x2000, 0x1041: 0x2000, 0x1042: 0x2000, 0x1043: 0x2000, 0x1044: 0x2000, 0x1045: 0x2000,
+ 0x1046: 0x2000, 0x1047: 0x2000, 0x1048: 0x2000, 0x1049: 0x2000, 0x104a: 0x2000, 0x104b: 0x2000,
+ 0x104c: 0x2000, 0x104d: 0x2000, 0x104e: 0x2000, 0x104f: 0x2000, 0x1050: 0x4000, 0x1051: 0x4000,
+ 0x1052: 0x4000, 0x1053: 0x4000, 0x1054: 0x4000, 0x1055: 0x4000, 0x1056: 0x4000, 0x1057: 0x4000,
+ 0x1058: 0x4000, 0x1059: 0x4000,
+ 0x1070: 0x4000, 0x1071: 0x4000, 0x1072: 0x4000, 0x1073: 0x4000, 0x1074: 0x4000, 0x1075: 0x4000,
+ 0x1076: 0x4000, 0x1077: 0x4000, 0x1078: 0x4000, 0x1079: 0x4000, 0x107a: 0x4000, 0x107b: 0x4000,
+ 0x107c: 0x4000, 0x107d: 0x4000, 0x107e: 0x4000, 0x107f: 0x4000,
+ // Block 0x42, offset 0x1080
+ 0x1080: 0x4000, 0x1081: 0x4000, 0x1082: 0x4000, 0x1083: 0x4000, 0x1084: 0x4000, 0x1085: 0x4000,
+ 0x1086: 0x4000, 0x1087: 0x4000, 0x1088: 0x4000, 0x1089: 0x4000, 0x108a: 0x4000, 0x108b: 0x4000,
+ 0x108c: 0x4000, 0x108d: 0x4000, 0x108e: 0x4000, 0x108f: 0x4000, 0x1090: 0x4000, 0x1091: 0x4000,
+ 0x1092: 0x4000, 0x1094: 0x4000, 0x1095: 0x4000, 0x1096: 0x4000, 0x1097: 0x4000,
+ 0x1098: 0x4000, 0x1099: 0x4000, 0x109a: 0x4000, 0x109b: 0x4000, 0x109c: 0x4000, 0x109d: 0x4000,
+ 0x109e: 0x4000, 0x109f: 0x4000, 0x10a0: 0x4000, 0x10a1: 0x4000, 0x10a2: 0x4000, 0x10a3: 0x4000,
+ 0x10a4: 0x4000, 0x10a5: 0x4000, 0x10a6: 0x4000, 0x10a8: 0x4000, 0x10a9: 0x4000,
+ 0x10aa: 0x4000, 0x10ab: 0x4000,
+ // Block 0x43, offset 0x10c0
+ 0x10c1: 0x9012, 0x10c2: 0x9012, 0x10c3: 0x9012, 0x10c4: 0x9012, 0x10c5: 0x9012,
+ 0x10c6: 0x9012, 0x10c7: 0x9012, 0x10c8: 0x9012, 0x10c9: 0x9012, 0x10ca: 0x9012, 0x10cb: 0x9012,
+ 0x10cc: 0x9012, 0x10cd: 0x9012, 0x10ce: 0x9012, 0x10cf: 0x9012, 0x10d0: 0x9012, 0x10d1: 0x9012,
+ 0x10d2: 0x9012, 0x10d3: 0x9012, 0x10d4: 0x9012, 0x10d5: 0x9012, 0x10d6: 0x9012, 0x10d7: 0x9012,
+ 0x10d8: 0x9012, 0x10d9: 0x9012, 0x10da: 0x9012, 0x10db: 0x9012, 0x10dc: 0x9012, 0x10dd: 0x9012,
+ 0x10de: 0x9012, 0x10df: 0x9012, 0x10e0: 0x9049, 0x10e1: 0x9049, 0x10e2: 0x9049, 0x10e3: 0x9049,
+ 0x10e4: 0x9049, 0x10e5: 0x9049, 0x10e6: 0x9049, 0x10e7: 0x9049, 0x10e8: 0x9049, 0x10e9: 0x9049,
+ 0x10ea: 0x9049, 0x10eb: 0x9049, 0x10ec: 0x9049, 0x10ed: 0x9049, 0x10ee: 0x9049, 0x10ef: 0x9049,
+ 0x10f0: 0x9049, 0x10f1: 0x9049, 0x10f2: 0x9049, 0x10f3: 0x9049, 0x10f4: 0x9049, 0x10f5: 0x9049,
+ 0x10f6: 0x9049, 0x10f7: 0x9049, 0x10f8: 0x9049, 0x10f9: 0x9049, 0x10fa: 0x9049, 0x10fb: 0x9049,
+ 0x10fc: 0x9049, 0x10fd: 0x9049, 0x10fe: 0x9049, 0x10ff: 0x9049,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x9049, 0x1101: 0x9049, 0x1102: 0x9049, 0x1103: 0x9049, 0x1104: 0x9049, 0x1105: 0x9049,
+ 0x1106: 0x9049, 0x1107: 0x9049, 0x1108: 0x9049, 0x1109: 0x9049, 0x110a: 0x9049, 0x110b: 0x9049,
+ 0x110c: 0x9049, 0x110d: 0x9049, 0x110e: 0x9049, 0x110f: 0x9049, 0x1110: 0x9049, 0x1111: 0x9049,
+ 0x1112: 0x9049, 0x1113: 0x9049, 0x1114: 0x9049, 0x1115: 0x9049, 0x1116: 0x9049, 0x1117: 0x9049,
+ 0x1118: 0x9049, 0x1119: 0x9049, 0x111a: 0x9049, 0x111b: 0x9049, 0x111c: 0x9049, 0x111d: 0x9049,
+ 0x111e: 0x9049, 0x111f: 0x904a, 0x1120: 0x904b, 0x1121: 0xb04c, 0x1122: 0xb04d, 0x1123: 0xb04d,
+ 0x1124: 0xb04e, 0x1125: 0xb04f, 0x1126: 0xb050, 0x1127: 0xb051, 0x1128: 0xb052, 0x1129: 0xb053,
+ 0x112a: 0xb054, 0x112b: 0xb055, 0x112c: 0xb056, 0x112d: 0xb057, 0x112e: 0xb058, 0x112f: 0xb059,
+ 0x1130: 0xb05a, 0x1131: 0xb05b, 0x1132: 0xb05c, 0x1133: 0xb05d, 0x1134: 0xb05e, 0x1135: 0xb05f,
+ 0x1136: 0xb060, 0x1137: 0xb061, 0x1138: 0xb062, 0x1139: 0xb063, 0x113a: 0xb064, 0x113b: 0xb065,
+ 0x113c: 0xb052, 0x113d: 0xb066, 0x113e: 0xb067, 0x113f: 0xb055,
+ // Block 0x45, offset 0x1140
+ 0x1140: 0xb068, 0x1141: 0xb069, 0x1142: 0xb06a, 0x1143: 0xb06b, 0x1144: 0xb05a, 0x1145: 0xb056,
+ 0x1146: 0xb06c, 0x1147: 0xb06d, 0x1148: 0xb06b, 0x1149: 0xb06e, 0x114a: 0xb06b, 0x114b: 0xb06f,
+ 0x114c: 0xb06f, 0x114d: 0xb070, 0x114e: 0xb070, 0x114f: 0xb071, 0x1150: 0xb056, 0x1151: 0xb072,
+ 0x1152: 0xb073, 0x1153: 0xb072, 0x1154: 0xb074, 0x1155: 0xb073, 0x1156: 0xb075, 0x1157: 0xb075,
+ 0x1158: 0xb076, 0x1159: 0xb076, 0x115a: 0xb077, 0x115b: 0xb077, 0x115c: 0xb073, 0x115d: 0xb078,
+ 0x115e: 0xb079, 0x115f: 0xb067, 0x1160: 0xb07a, 0x1161: 0xb07b, 0x1162: 0xb07b, 0x1163: 0xb07b,
+ 0x1164: 0xb07b, 0x1165: 0xb07b, 0x1166: 0xb07b, 0x1167: 0xb07b, 0x1168: 0xb07b, 0x1169: 0xb07b,
+ 0x116a: 0xb07b, 0x116b: 0xb07b, 0x116c: 0xb07b, 0x116d: 0xb07b, 0x116e: 0xb07b, 0x116f: 0xb07b,
+ 0x1170: 0xb07c, 0x1171: 0xb07c, 0x1172: 0xb07c, 0x1173: 0xb07c, 0x1174: 0xb07c, 0x1175: 0xb07c,
+ 0x1176: 0xb07c, 0x1177: 0xb07c, 0x1178: 0xb07c, 0x1179: 0xb07c, 0x117a: 0xb07c, 0x117b: 0xb07c,
+ 0x117c: 0xb07c, 0x117d: 0xb07c, 0x117e: 0xb07c,
+ // Block 0x46, offset 0x1180
+ 0x1182: 0xb07d, 0x1183: 0xb07e, 0x1184: 0xb07f, 0x1185: 0xb080,
+ 0x1186: 0xb07f, 0x1187: 0xb07e, 0x118a: 0xb081, 0x118b: 0xb082,
+ 0x118c: 0xb083, 0x118d: 0xb07f, 0x118e: 0xb080, 0x118f: 0xb07f,
+ 0x1192: 0xb084, 0x1193: 0xb085, 0x1194: 0xb084, 0x1195: 0xb086, 0x1196: 0xb084, 0x1197: 0xb087,
+ 0x119a: 0xb088, 0x119b: 0xb089, 0x119c: 0xb08a,
+ 0x11a0: 0x908b, 0x11a1: 0x908b, 0x11a2: 0x908c, 0x11a3: 0x908d,
+ 0x11a4: 0x908b, 0x11a5: 0x908e, 0x11a6: 0x908f, 0x11a8: 0xb090, 0x11a9: 0xb091,
+ 0x11aa: 0xb092, 0x11ab: 0xb091, 0x11ac: 0xb093, 0x11ad: 0xb094, 0x11ae: 0xb095,
+ 0x11bd: 0x2000,
+ // Block 0x47, offset 0x11c0
+ 0x11e0: 0x4000,
+ // Block 0x48, offset 0x1200
+ 0x1200: 0x4000, 0x1201: 0x4000, 0x1202: 0x4000, 0x1203: 0x4000, 0x1204: 0x4000, 0x1205: 0x4000,
+ 0x1206: 0x4000, 0x1207: 0x4000, 0x1208: 0x4000, 0x1209: 0x4000, 0x120a: 0x4000, 0x120b: 0x4000,
+ 0x120c: 0x4000, 0x120d: 0x4000, 0x120e: 0x4000, 0x120f: 0x4000, 0x1210: 0x4000, 0x1211: 0x4000,
+ 0x1212: 0x4000, 0x1213: 0x4000, 0x1214: 0x4000, 0x1215: 0x4000, 0x1216: 0x4000, 0x1217: 0x4000,
+ 0x1218: 0x4000, 0x1219: 0x4000, 0x121a: 0x4000, 0x121b: 0x4000, 0x121c: 0x4000, 0x121d: 0x4000,
+ 0x121e: 0x4000, 0x121f: 0x4000, 0x1220: 0x4000, 0x1221: 0x4000, 0x1222: 0x4000, 0x1223: 0x4000,
+ 0x1224: 0x4000, 0x1225: 0x4000, 0x1226: 0x4000, 0x1227: 0x4000, 0x1228: 0x4000, 0x1229: 0x4000,
+ 0x122a: 0x4000, 0x122b: 0x4000, 0x122c: 0x4000,
+ // Block 0x49, offset 0x1240
+ 0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
+ 0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000, 0x1249: 0x4000, 0x124a: 0x4000, 0x124b: 0x4000,
+ 0x124c: 0x4000, 0x124d: 0x4000, 0x124e: 0x4000, 0x124f: 0x4000, 0x1250: 0x4000, 0x1251: 0x4000,
+ 0x1252: 0x4000, 0x1253: 0x4000, 0x1254: 0x4000, 0x1255: 0x4000, 0x1256: 0x4000, 0x1257: 0x4000,
+ 0x1258: 0x4000, 0x1259: 0x4000, 0x125a: 0x4000, 0x125b: 0x4000, 0x125c: 0x4000, 0x125d: 0x4000,
+ 0x125e: 0x4000, 0x125f: 0x4000, 0x1260: 0x4000, 0x1261: 0x4000, 0x1262: 0x4000, 0x1263: 0x4000,
+ 0x1264: 0x4000, 0x1265: 0x4000, 0x1266: 0x4000, 0x1267: 0x4000, 0x1268: 0x4000, 0x1269: 0x4000,
+ 0x126a: 0x4000, 0x126b: 0x4000, 0x126c: 0x4000, 0x126d: 0x4000, 0x126e: 0x4000, 0x126f: 0x4000,
+ 0x1270: 0x4000, 0x1271: 0x4000, 0x1272: 0x4000,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x4000, 0x1281: 0x4000,
+ // Block 0x4b, offset 0x12c0
+ 0x12c4: 0x4000,
+ // Block 0x4c, offset 0x1300
+ 0x130f: 0x4000,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x2000, 0x1341: 0x2000, 0x1342: 0x2000, 0x1343: 0x2000, 0x1344: 0x2000, 0x1345: 0x2000,
+ 0x1346: 0x2000, 0x1347: 0x2000, 0x1348: 0x2000, 0x1349: 0x2000, 0x134a: 0x2000,
+ 0x1350: 0x2000, 0x1351: 0x2000,
+ 0x1352: 0x2000, 0x1353: 0x2000, 0x1354: 0x2000, 0x1355: 0x2000, 0x1356: 0x2000, 0x1357: 0x2000,
+ 0x1358: 0x2000, 0x1359: 0x2000, 0x135a: 0x2000, 0x135b: 0x2000, 0x135c: 0x2000, 0x135d: 0x2000,
+ 0x135e: 0x2000, 0x135f: 0x2000, 0x1360: 0x2000, 0x1361: 0x2000, 0x1362: 0x2000, 0x1363: 0x2000,
+ 0x1364: 0x2000, 0x1365: 0x2000, 0x1366: 0x2000, 0x1367: 0x2000, 0x1368: 0x2000, 0x1369: 0x2000,
+ 0x136a: 0x2000, 0x136b: 0x2000, 0x136c: 0x2000, 0x136d: 0x2000,
+ 0x1370: 0x2000, 0x1371: 0x2000, 0x1372: 0x2000, 0x1373: 0x2000, 0x1374: 0x2000, 0x1375: 0x2000,
+ 0x1376: 0x2000, 0x1377: 0x2000, 0x1378: 0x2000, 0x1379: 0x2000, 0x137a: 0x2000, 0x137b: 0x2000,
+ 0x137c: 0x2000, 0x137d: 0x2000, 0x137e: 0x2000, 0x137f: 0x2000,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x2000, 0x1381: 0x2000, 0x1382: 0x2000, 0x1383: 0x2000, 0x1384: 0x2000, 0x1385: 0x2000,
+ 0x1386: 0x2000, 0x1387: 0x2000, 0x1388: 0x2000, 0x1389: 0x2000, 0x138a: 0x2000, 0x138b: 0x2000,
+ 0x138c: 0x2000, 0x138d: 0x2000, 0x138e: 0x2000, 0x138f: 0x2000, 0x1390: 0x2000, 0x1391: 0x2000,
+ 0x1392: 0x2000, 0x1393: 0x2000, 0x1394: 0x2000, 0x1395: 0x2000, 0x1396: 0x2000, 0x1397: 0x2000,
+ 0x1398: 0x2000, 0x1399: 0x2000, 0x139a: 0x2000, 0x139b: 0x2000, 0x139c: 0x2000, 0x139d: 0x2000,
+ 0x139e: 0x2000, 0x139f: 0x2000, 0x13a0: 0x2000, 0x13a1: 0x2000, 0x13a2: 0x2000, 0x13a3: 0x2000,
+ 0x13a4: 0x2000, 0x13a5: 0x2000, 0x13a6: 0x2000, 0x13a7: 0x2000, 0x13a8: 0x2000, 0x13a9: 0x2000,
+ 0x13b0: 0x2000, 0x13b1: 0x2000, 0x13b2: 0x2000, 0x13b3: 0x2000, 0x13b4: 0x2000, 0x13b5: 0x2000,
+ 0x13b6: 0x2000, 0x13b7: 0x2000, 0x13b8: 0x2000, 0x13b9: 0x2000, 0x13ba: 0x2000, 0x13bb: 0x2000,
+ 0x13bc: 0x2000, 0x13bd: 0x2000, 0x13be: 0x2000, 0x13bf: 0x2000,
+ // Block 0x4f, offset 0x13c0
+ 0x13c0: 0x2000, 0x13c1: 0x2000, 0x13c2: 0x2000, 0x13c3: 0x2000, 0x13c4: 0x2000, 0x13c5: 0x2000,
+ 0x13c6: 0x2000, 0x13c7: 0x2000, 0x13c8: 0x2000, 0x13c9: 0x2000, 0x13ca: 0x2000, 0x13cb: 0x2000,
+ 0x13cc: 0x2000, 0x13cd: 0x2000, 0x13ce: 0x4000, 0x13cf: 0x2000, 0x13d0: 0x2000, 0x13d1: 0x4000,
+ 0x13d2: 0x4000, 0x13d3: 0x4000, 0x13d4: 0x4000, 0x13d5: 0x4000, 0x13d6: 0x4000, 0x13d7: 0x4000,
+ 0x13d8: 0x4000, 0x13d9: 0x4000, 0x13da: 0x4000, 0x13db: 0x2000, 0x13dc: 0x2000, 0x13dd: 0x2000,
+ 0x13de: 0x2000, 0x13df: 0x2000, 0x13e0: 0x2000, 0x13e1: 0x2000, 0x13e2: 0x2000, 0x13e3: 0x2000,
+ 0x13e4: 0x2000, 0x13e5: 0x2000, 0x13e6: 0x2000, 0x13e7: 0x2000, 0x13e8: 0x2000, 0x13e9: 0x2000,
+ 0x13ea: 0x2000, 0x13eb: 0x2000, 0x13ec: 0x2000,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x4000, 0x1401: 0x4000, 0x1402: 0x4000,
+ 0x1410: 0x4000, 0x1411: 0x4000,
+ 0x1412: 0x4000, 0x1413: 0x4000, 0x1414: 0x4000, 0x1415: 0x4000, 0x1416: 0x4000, 0x1417: 0x4000,
+ 0x1418: 0x4000, 0x1419: 0x4000, 0x141a: 0x4000, 0x141b: 0x4000, 0x141c: 0x4000, 0x141d: 0x4000,
+ 0x141e: 0x4000, 0x141f: 0x4000, 0x1420: 0x4000, 0x1421: 0x4000, 0x1422: 0x4000, 0x1423: 0x4000,
+ 0x1424: 0x4000, 0x1425: 0x4000, 0x1426: 0x4000, 0x1427: 0x4000, 0x1428: 0x4000, 0x1429: 0x4000,
+ 0x142a: 0x4000, 0x142b: 0x4000, 0x142c: 0x4000, 0x142d: 0x4000, 0x142e: 0x4000, 0x142f: 0x4000,
+ 0x1430: 0x4000, 0x1431: 0x4000, 0x1432: 0x4000, 0x1433: 0x4000, 0x1434: 0x4000, 0x1435: 0x4000,
+ 0x1436: 0x4000, 0x1437: 0x4000, 0x1438: 0x4000, 0x1439: 0x4000, 0x143a: 0x4000, 0x143b: 0x4000,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x4000, 0x1441: 0x4000, 0x1442: 0x4000, 0x1443: 0x4000, 0x1444: 0x4000, 0x1445: 0x4000,
+ 0x1446: 0x4000, 0x1447: 0x4000, 0x1448: 0x4000,
+ 0x1450: 0x4000, 0x1451: 0x4000,
+ // Block 0x52, offset 0x1480
+ 0x1480: 0x4000, 0x1481: 0x4000, 0x1482: 0x4000, 0x1483: 0x4000, 0x1484: 0x4000, 0x1485: 0x4000,
+ 0x1486: 0x4000, 0x1487: 0x4000, 0x1488: 0x4000, 0x1489: 0x4000, 0x148a: 0x4000, 0x148b: 0x4000,
+ 0x148c: 0x4000, 0x148d: 0x4000, 0x148e: 0x4000, 0x148f: 0x4000, 0x1490: 0x4000, 0x1491: 0x4000,
+ 0x1492: 0x4000, 0x1493: 0x4000, 0x1494: 0x4000, 0x1495: 0x4000, 0x1496: 0x4000, 0x1497: 0x4000,
+ 0x1498: 0x4000, 0x1499: 0x4000, 0x149a: 0x4000, 0x149b: 0x4000, 0x149c: 0x4000, 0x149d: 0x4000,
+ 0x149e: 0x4000, 0x149f: 0x4000, 0x14a0: 0x4000,
+ 0x14ad: 0x4000, 0x14ae: 0x4000, 0x14af: 0x4000,
+ 0x14b0: 0x4000, 0x14b1: 0x4000, 0x14b2: 0x4000, 0x14b3: 0x4000, 0x14b4: 0x4000, 0x14b5: 0x4000,
+ 0x14b7: 0x4000, 0x14b8: 0x4000, 0x14b9: 0x4000, 0x14ba: 0x4000, 0x14bb: 0x4000,
+ 0x14bc: 0x4000, 0x14bd: 0x4000, 0x14be: 0x4000, 0x14bf: 0x4000,
+ // Block 0x53, offset 0x14c0
+ 0x14c0: 0x4000, 0x14c1: 0x4000, 0x14c2: 0x4000, 0x14c3: 0x4000, 0x14c4: 0x4000, 0x14c5: 0x4000,
+ 0x14c6: 0x4000, 0x14c7: 0x4000, 0x14c8: 0x4000, 0x14c9: 0x4000, 0x14ca: 0x4000, 0x14cb: 0x4000,
+ 0x14cc: 0x4000, 0x14cd: 0x4000, 0x14ce: 0x4000, 0x14cf: 0x4000, 0x14d0: 0x4000, 0x14d1: 0x4000,
+ 0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
+ 0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x4000, 0x14dc: 0x4000, 0x14dd: 0x4000,
+ 0x14de: 0x4000, 0x14df: 0x4000, 0x14e0: 0x4000, 0x14e1: 0x4000, 0x14e2: 0x4000, 0x14e3: 0x4000,
+ 0x14e4: 0x4000, 0x14e5: 0x4000, 0x14e6: 0x4000, 0x14e7: 0x4000, 0x14e8: 0x4000, 0x14e9: 0x4000,
+ 0x14ea: 0x4000, 0x14eb: 0x4000, 0x14ec: 0x4000, 0x14ed: 0x4000, 0x14ee: 0x4000, 0x14ef: 0x4000,
+ 0x14f0: 0x4000, 0x14f1: 0x4000, 0x14f2: 0x4000, 0x14f3: 0x4000, 0x14f4: 0x4000, 0x14f5: 0x4000,
+ 0x14f6: 0x4000, 0x14f7: 0x4000, 0x14f8: 0x4000, 0x14f9: 0x4000, 0x14fa: 0x4000, 0x14fb: 0x4000,
+ 0x14fc: 0x4000, 0x14fe: 0x4000, 0x14ff: 0x4000,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000, 0x1503: 0x4000, 0x1504: 0x4000, 0x1505: 0x4000,
+ 0x1506: 0x4000, 0x1507: 0x4000, 0x1508: 0x4000, 0x1509: 0x4000, 0x150a: 0x4000, 0x150b: 0x4000,
+ 0x150c: 0x4000, 0x150d: 0x4000, 0x150e: 0x4000, 0x150f: 0x4000, 0x1510: 0x4000, 0x1511: 0x4000,
+ 0x1512: 0x4000, 0x1513: 0x4000,
+ 0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
+ 0x1524: 0x4000, 0x1525: 0x4000, 0x1526: 0x4000, 0x1527: 0x4000, 0x1528: 0x4000, 0x1529: 0x4000,
+ 0x152a: 0x4000, 0x152b: 0x4000, 0x152c: 0x4000, 0x152d: 0x4000, 0x152e: 0x4000, 0x152f: 0x4000,
+ 0x1530: 0x4000, 0x1531: 0x4000, 0x1532: 0x4000, 0x1533: 0x4000, 0x1534: 0x4000, 0x1535: 0x4000,
+ 0x1536: 0x4000, 0x1537: 0x4000, 0x1538: 0x4000, 0x1539: 0x4000, 0x153a: 0x4000, 0x153b: 0x4000,
+ 0x153c: 0x4000, 0x153d: 0x4000, 0x153e: 0x4000, 0x153f: 0x4000,
+ // Block 0x55, offset 0x1540
+ 0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
+ 0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000, 0x1549: 0x4000, 0x154a: 0x4000,
+ 0x154f: 0x4000, 0x1550: 0x4000, 0x1551: 0x4000,
+ 0x1552: 0x4000, 0x1553: 0x4000,
+ 0x1560: 0x4000, 0x1561: 0x4000, 0x1562: 0x4000, 0x1563: 0x4000,
+ 0x1564: 0x4000, 0x1565: 0x4000, 0x1566: 0x4000, 0x1567: 0x4000, 0x1568: 0x4000, 0x1569: 0x4000,
+ 0x156a: 0x4000, 0x156b: 0x4000, 0x156c: 0x4000, 0x156d: 0x4000, 0x156e: 0x4000, 0x156f: 0x4000,
+ 0x1570: 0x4000, 0x1574: 0x4000,
+ 0x1578: 0x4000, 0x1579: 0x4000, 0x157a: 0x4000, 0x157b: 0x4000,
+ 0x157c: 0x4000, 0x157d: 0x4000, 0x157e: 0x4000, 0x157f: 0x4000,
+ // Block 0x56, offset 0x1580
+ 0x1580: 0x4000, 0x1582: 0x4000, 0x1583: 0x4000, 0x1584: 0x4000, 0x1585: 0x4000,
+ 0x1586: 0x4000, 0x1587: 0x4000, 0x1588: 0x4000, 0x1589: 0x4000, 0x158a: 0x4000, 0x158b: 0x4000,
+ 0x158c: 0x4000, 0x158d: 0x4000, 0x158e: 0x4000, 0x158f: 0x4000, 0x1590: 0x4000, 0x1591: 0x4000,
+ 0x1592: 0x4000, 0x1593: 0x4000, 0x1594: 0x4000, 0x1595: 0x4000, 0x1596: 0x4000, 0x1597: 0x4000,
+ 0x1598: 0x4000, 0x1599: 0x4000, 0x159a: 0x4000, 0x159b: 0x4000, 0x159c: 0x4000, 0x159d: 0x4000,
+ 0x159e: 0x4000, 0x159f: 0x4000, 0x15a0: 0x4000, 0x15a1: 0x4000, 0x15a2: 0x4000, 0x15a3: 0x4000,
+ 0x15a4: 0x4000, 0x15a5: 0x4000, 0x15a6: 0x4000, 0x15a7: 0x4000, 0x15a8: 0x4000, 0x15a9: 0x4000,
+ 0x15aa: 0x4000, 0x15ab: 0x4000, 0x15ac: 0x4000, 0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
+ 0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
+ 0x15b6: 0x4000, 0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
+ 0x15bc: 0x4000, 0x15bd: 0x4000, 0x15be: 0x4000, 0x15bf: 0x4000,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x4000, 0x15c1: 0x4000, 0x15c2: 0x4000, 0x15c3: 0x4000, 0x15c4: 0x4000, 0x15c5: 0x4000,
+ 0x15c6: 0x4000, 0x15c7: 0x4000, 0x15c8: 0x4000, 0x15c9: 0x4000, 0x15ca: 0x4000, 0x15cb: 0x4000,
+ 0x15cc: 0x4000, 0x15cd: 0x4000, 0x15ce: 0x4000, 0x15cf: 0x4000, 0x15d0: 0x4000, 0x15d1: 0x4000,
+ 0x15d2: 0x4000, 0x15d3: 0x4000, 0x15d4: 0x4000, 0x15d5: 0x4000, 0x15d6: 0x4000, 0x15d7: 0x4000,
+ 0x15d8: 0x4000, 0x15d9: 0x4000, 0x15da: 0x4000, 0x15db: 0x4000, 0x15dc: 0x4000, 0x15dd: 0x4000,
+ 0x15de: 0x4000, 0x15df: 0x4000, 0x15e0: 0x4000, 0x15e1: 0x4000, 0x15e2: 0x4000, 0x15e3: 0x4000,
+ 0x15e4: 0x4000, 0x15e5: 0x4000, 0x15e6: 0x4000, 0x15e7: 0x4000, 0x15e8: 0x4000, 0x15e9: 0x4000,
+ 0x15ea: 0x4000, 0x15eb: 0x4000, 0x15ec: 0x4000, 0x15ed: 0x4000, 0x15ee: 0x4000, 0x15ef: 0x4000,
+ 0x15f0: 0x4000, 0x15f1: 0x4000, 0x15f2: 0x4000, 0x15f3: 0x4000, 0x15f4: 0x4000, 0x15f5: 0x4000,
+ 0x15f6: 0x4000, 0x15f7: 0x4000, 0x15f8: 0x4000, 0x15f9: 0x4000, 0x15fa: 0x4000, 0x15fb: 0x4000,
+ 0x15fc: 0x4000, 0x15ff: 0x4000,
+ // Block 0x58, offset 0x1600
+ 0x1600: 0x4000, 0x1601: 0x4000, 0x1602: 0x4000, 0x1603: 0x4000, 0x1604: 0x4000, 0x1605: 0x4000,
+ 0x1606: 0x4000, 0x1607: 0x4000, 0x1608: 0x4000, 0x1609: 0x4000, 0x160a: 0x4000, 0x160b: 0x4000,
+ 0x160c: 0x4000, 0x160d: 0x4000, 0x160e: 0x4000, 0x160f: 0x4000, 0x1610: 0x4000, 0x1611: 0x4000,
+ 0x1612: 0x4000, 0x1613: 0x4000, 0x1614: 0x4000, 0x1615: 0x4000, 0x1616: 0x4000, 0x1617: 0x4000,
+ 0x1618: 0x4000, 0x1619: 0x4000, 0x161a: 0x4000, 0x161b: 0x4000, 0x161c: 0x4000, 0x161d: 0x4000,
+ 0x161e: 0x4000, 0x161f: 0x4000, 0x1620: 0x4000, 0x1621: 0x4000, 0x1622: 0x4000, 0x1623: 0x4000,
+ 0x1624: 0x4000, 0x1625: 0x4000, 0x1626: 0x4000, 0x1627: 0x4000, 0x1628: 0x4000, 0x1629: 0x4000,
+ 0x162a: 0x4000, 0x162b: 0x4000, 0x162c: 0x4000, 0x162d: 0x4000, 0x162e: 0x4000, 0x162f: 0x4000,
+ 0x1630: 0x4000, 0x1631: 0x4000, 0x1632: 0x4000, 0x1633: 0x4000, 0x1634: 0x4000, 0x1635: 0x4000,
+ 0x1636: 0x4000, 0x1637: 0x4000, 0x1638: 0x4000, 0x1639: 0x4000, 0x163a: 0x4000, 0x163b: 0x4000,
+ 0x163c: 0x4000, 0x163d: 0x4000,
+ // Block 0x59, offset 0x1640
+ 0x164b: 0x4000,
+ 0x164c: 0x4000, 0x164d: 0x4000, 0x164e: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
+ 0x1652: 0x4000, 0x1653: 0x4000, 0x1654: 0x4000, 0x1655: 0x4000, 0x1656: 0x4000, 0x1657: 0x4000,
+ 0x1658: 0x4000, 0x1659: 0x4000, 0x165a: 0x4000, 0x165b: 0x4000, 0x165c: 0x4000, 0x165d: 0x4000,
+ 0x165e: 0x4000, 0x165f: 0x4000, 0x1660: 0x4000, 0x1661: 0x4000, 0x1662: 0x4000, 0x1663: 0x4000,
+ 0x1664: 0x4000, 0x1665: 0x4000, 0x1666: 0x4000, 0x1667: 0x4000,
+ 0x167a: 0x4000,
+ // Block 0x5a, offset 0x1680
+ 0x1695: 0x4000, 0x1696: 0x4000,
+ 0x16a4: 0x4000,
+ // Block 0x5b, offset 0x16c0
+ 0x16fb: 0x4000,
+ 0x16fc: 0x4000, 0x16fd: 0x4000, 0x16fe: 0x4000, 0x16ff: 0x4000,
+ // Block 0x5c, offset 0x1700
+ 0x1700: 0x4000, 0x1701: 0x4000, 0x1702: 0x4000, 0x1703: 0x4000, 0x1704: 0x4000, 0x1705: 0x4000,
+ 0x1706: 0x4000, 0x1707: 0x4000, 0x1708: 0x4000, 0x1709: 0x4000, 0x170a: 0x4000, 0x170b: 0x4000,
+ 0x170c: 0x4000, 0x170d: 0x4000, 0x170e: 0x4000, 0x170f: 0x4000,
+ // Block 0x5d, offset 0x1740
+ 0x1740: 0x4000, 0x1741: 0x4000, 0x1742: 0x4000, 0x1743: 0x4000, 0x1744: 0x4000, 0x1745: 0x4000,
+ 0x174c: 0x4000, 0x1750: 0x4000, 0x1751: 0x4000,
+ 0x1752: 0x4000,
+ 0x176b: 0x4000, 0x176c: 0x4000,
+ 0x1774: 0x4000, 0x1775: 0x4000,
+ 0x1776: 0x4000,
+ // Block 0x5e, offset 0x1780
+ 0x1790: 0x4000, 0x1791: 0x4000,
+ 0x1792: 0x4000, 0x1793: 0x4000, 0x1794: 0x4000, 0x1795: 0x4000, 0x1796: 0x4000, 0x1797: 0x4000,
+ 0x1798: 0x4000, 0x1799: 0x4000, 0x179a: 0x4000, 0x179b: 0x4000, 0x179c: 0x4000, 0x179d: 0x4000,
+ 0x179e: 0x4000, 0x17a0: 0x4000, 0x17a1: 0x4000, 0x17a2: 0x4000, 0x17a3: 0x4000,
+ 0x17a4: 0x4000, 0x17a5: 0x4000, 0x17a6: 0x4000, 0x17a7: 0x4000,
+ 0x17b0: 0x4000, 0x17b3: 0x4000, 0x17b4: 0x4000, 0x17b5: 0x4000,
+ 0x17b6: 0x4000, 0x17b7: 0x4000, 0x17b8: 0x4000, 0x17b9: 0x4000, 0x17ba: 0x4000, 0x17bb: 0x4000,
+ 0x17bc: 0x4000, 0x17bd: 0x4000, 0x17be: 0x4000,
+ // Block 0x5f, offset 0x17c0
+ 0x17c0: 0x4000, 0x17c1: 0x4000, 0x17c2: 0x4000, 0x17c3: 0x4000, 0x17c4: 0x4000, 0x17c5: 0x4000,
+ 0x17c6: 0x4000, 0x17c7: 0x4000, 0x17c8: 0x4000, 0x17c9: 0x4000, 0x17ca: 0x4000, 0x17cb: 0x4000,
+ 0x17d0: 0x4000, 0x17d1: 0x4000,
+ 0x17d2: 0x4000, 0x17d3: 0x4000, 0x17d4: 0x4000, 0x17d5: 0x4000, 0x17d6: 0x4000, 0x17d7: 0x4000,
+ 0x17d8: 0x4000, 0x17d9: 0x4000, 0x17da: 0x4000, 0x17db: 0x4000, 0x17dc: 0x4000, 0x17dd: 0x4000,
+ 0x17de: 0x4000,
+ // Block 0x60, offset 0x1800
+ 0x1800: 0x4000, 0x1801: 0x4000, 0x1802: 0x4000, 0x1803: 0x4000, 0x1804: 0x4000, 0x1805: 0x4000,
+ 0x1806: 0x4000, 0x1807: 0x4000, 0x1808: 0x4000, 0x1809: 0x4000, 0x180a: 0x4000, 0x180b: 0x4000,
+ 0x180c: 0x4000, 0x180d: 0x4000, 0x180e: 0x4000, 0x180f: 0x4000, 0x1810: 0x4000, 0x1811: 0x4000,
+ // Block 0x61, offset 0x1840
+ 0x1840: 0x4000,
+ // Block 0x62, offset 0x1880
+ 0x1880: 0x2000, 0x1881: 0x2000, 0x1882: 0x2000, 0x1883: 0x2000, 0x1884: 0x2000, 0x1885: 0x2000,
+ 0x1886: 0x2000, 0x1887: 0x2000, 0x1888: 0x2000, 0x1889: 0x2000, 0x188a: 0x2000, 0x188b: 0x2000,
+ 0x188c: 0x2000, 0x188d: 0x2000, 0x188e: 0x2000, 0x188f: 0x2000, 0x1890: 0x2000, 0x1891: 0x2000,
+ 0x1892: 0x2000, 0x1893: 0x2000, 0x1894: 0x2000, 0x1895: 0x2000, 0x1896: 0x2000, 0x1897: 0x2000,
+ 0x1898: 0x2000, 0x1899: 0x2000, 0x189a: 0x2000, 0x189b: 0x2000, 0x189c: 0x2000, 0x189d: 0x2000,
+ 0x189e: 0x2000, 0x189f: 0x2000, 0x18a0: 0x2000, 0x18a1: 0x2000, 0x18a2: 0x2000, 0x18a3: 0x2000,
+ 0x18a4: 0x2000, 0x18a5: 0x2000, 0x18a6: 0x2000, 0x18a7: 0x2000, 0x18a8: 0x2000, 0x18a9: 0x2000,
+ 0x18aa: 0x2000, 0x18ab: 0x2000, 0x18ac: 0x2000, 0x18ad: 0x2000, 0x18ae: 0x2000, 0x18af: 0x2000,
+ 0x18b0: 0x2000, 0x18b1: 0x2000, 0x18b2: 0x2000, 0x18b3: 0x2000, 0x18b4: 0x2000, 0x18b5: 0x2000,
+ 0x18b6: 0x2000, 0x18b7: 0x2000, 0x18b8: 0x2000, 0x18b9: 0x2000, 0x18ba: 0x2000, 0x18bb: 0x2000,
+ 0x18bc: 0x2000, 0x18bd: 0x2000,
+}
+
+// widthIndex: 22 blocks, 1408 entries, 1408 bytes
+// Block 0 is the zero block.
+var widthIndex = [1408]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05,
+ 0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b,
+ 0xd0: 0x0c, 0xd1: 0x0d,
+ 0xe1: 0x02, 0xe2: 0x03, 0xe3: 0x04, 0xe4: 0x05, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06,
+ 0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a,
+ 0xf0: 0x0f, 0xf3: 0x12, 0xf4: 0x13,
+ // Block 0x4, offset 0x100
+ 0x104: 0x0e, 0x105: 0x0f,
+ // Block 0x5, offset 0x140
+ 0x140: 0x10, 0x141: 0x11, 0x142: 0x12, 0x144: 0x13, 0x145: 0x14, 0x146: 0x15, 0x147: 0x16,
+ 0x148: 0x17, 0x149: 0x18, 0x14a: 0x19, 0x14c: 0x1a, 0x14f: 0x1b,
+ 0x151: 0x1c, 0x152: 0x08, 0x153: 0x1d, 0x154: 0x1e, 0x155: 0x1f, 0x156: 0x20, 0x157: 0x21,
+ 0x158: 0x22, 0x159: 0x23, 0x15a: 0x24, 0x15b: 0x25, 0x15c: 0x26, 0x15d: 0x27, 0x15e: 0x28, 0x15f: 0x29,
+ 0x166: 0x2a,
+ 0x16c: 0x2b, 0x16d: 0x2c,
+ 0x17a: 0x2d, 0x17b: 0x2e, 0x17c: 0x0e, 0x17d: 0x0e, 0x17e: 0x0e, 0x17f: 0x2f,
+ // Block 0x6, offset 0x180
+ 0x180: 0x30, 0x181: 0x31, 0x182: 0x32, 0x183: 0x33, 0x184: 0x34, 0x185: 0x35, 0x186: 0x36, 0x187: 0x37,
+ 0x188: 0x38, 0x189: 0x39, 0x18a: 0x0e, 0x18b: 0x3a, 0x18c: 0x0e, 0x18d: 0x0e, 0x18e: 0x0e, 0x18f: 0x0e,
+ 0x190: 0x0e, 0x191: 0x0e, 0x192: 0x0e, 0x193: 0x0e, 0x194: 0x0e, 0x195: 0x0e, 0x196: 0x0e, 0x197: 0x0e,
+ 0x198: 0x0e, 0x199: 0x0e, 0x19a: 0x0e, 0x19b: 0x0e, 0x19c: 0x0e, 0x19d: 0x0e, 0x19e: 0x0e, 0x19f: 0x0e,
+ 0x1a0: 0x0e, 0x1a1: 0x0e, 0x1a2: 0x0e, 0x1a3: 0x0e, 0x1a4: 0x0e, 0x1a5: 0x0e, 0x1a6: 0x0e, 0x1a7: 0x0e,
+ 0x1a8: 0x0e, 0x1a9: 0x0e, 0x1aa: 0x0e, 0x1ab: 0x0e, 0x1ac: 0x0e, 0x1ad: 0x0e, 0x1ae: 0x0e, 0x1af: 0x0e,
+ 0x1b0: 0x0e, 0x1b1: 0x0e, 0x1b2: 0x0e, 0x1b3: 0x0e, 0x1b4: 0x0e, 0x1b5: 0x0e, 0x1b6: 0x0e, 0x1b7: 0x0e,
+ 0x1b8: 0x0e, 0x1b9: 0x0e, 0x1ba: 0x0e, 0x1bb: 0x0e, 0x1bc: 0x0e, 0x1bd: 0x0e, 0x1be: 0x0e, 0x1bf: 0x0e,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x0e, 0x1c1: 0x0e, 0x1c2: 0x0e, 0x1c3: 0x0e, 0x1c4: 0x0e, 0x1c5: 0x0e, 0x1c6: 0x0e, 0x1c7: 0x0e,
+ 0x1c8: 0x0e, 0x1c9: 0x0e, 0x1ca: 0x0e, 0x1cb: 0x0e, 0x1cc: 0x0e, 0x1cd: 0x0e, 0x1ce: 0x0e, 0x1cf: 0x0e,
+ 0x1d0: 0x0e, 0x1d1: 0x0e, 0x1d2: 0x0e, 0x1d3: 0x0e, 0x1d4: 0x0e, 0x1d5: 0x0e, 0x1d6: 0x0e, 0x1d7: 0x0e,
+ 0x1d8: 0x0e, 0x1d9: 0x0e, 0x1da: 0x0e, 0x1db: 0x0e, 0x1dc: 0x0e, 0x1dd: 0x0e, 0x1de: 0x0e, 0x1df: 0x0e,
+ 0x1e0: 0x0e, 0x1e1: 0x0e, 0x1e2: 0x0e, 0x1e3: 0x0e, 0x1e4: 0x0e, 0x1e5: 0x0e, 0x1e6: 0x0e, 0x1e7: 0x0e,
+ 0x1e8: 0x0e, 0x1e9: 0x0e, 0x1ea: 0x0e, 0x1eb: 0x0e, 0x1ec: 0x0e, 0x1ed: 0x0e, 0x1ee: 0x0e, 0x1ef: 0x0e,
+ 0x1f0: 0x0e, 0x1f1: 0x0e, 0x1f2: 0x0e, 0x1f3: 0x0e, 0x1f4: 0x0e, 0x1f5: 0x0e, 0x1f6: 0x0e,
+ 0x1f8: 0x0e, 0x1f9: 0x0e, 0x1fa: 0x0e, 0x1fb: 0x0e, 0x1fc: 0x0e, 0x1fd: 0x0e, 0x1fe: 0x0e, 0x1ff: 0x0e,
+ // Block 0x8, offset 0x200
+ 0x200: 0x0e, 0x201: 0x0e, 0x202: 0x0e, 0x203: 0x0e, 0x204: 0x0e, 0x205: 0x0e, 0x206: 0x0e, 0x207: 0x0e,
+ 0x208: 0x0e, 0x209: 0x0e, 0x20a: 0x0e, 0x20b: 0x0e, 0x20c: 0x0e, 0x20d: 0x0e, 0x20e: 0x0e, 0x20f: 0x0e,
+ 0x210: 0x0e, 0x211: 0x0e, 0x212: 0x0e, 0x213: 0x0e, 0x214: 0x0e, 0x215: 0x0e, 0x216: 0x0e, 0x217: 0x0e,
+ 0x218: 0x0e, 0x219: 0x0e, 0x21a: 0x0e, 0x21b: 0x0e, 0x21c: 0x0e, 0x21d: 0x0e, 0x21e: 0x0e, 0x21f: 0x0e,
+ 0x220: 0x0e, 0x221: 0x0e, 0x222: 0x0e, 0x223: 0x0e, 0x224: 0x0e, 0x225: 0x0e, 0x226: 0x0e, 0x227: 0x0e,
+ 0x228: 0x0e, 0x229: 0x0e, 0x22a: 0x0e, 0x22b: 0x0e, 0x22c: 0x0e, 0x22d: 0x0e, 0x22e: 0x0e, 0x22f: 0x0e,
+ 0x230: 0x0e, 0x231: 0x0e, 0x232: 0x0e, 0x233: 0x0e, 0x234: 0x0e, 0x235: 0x0e, 0x236: 0x0e, 0x237: 0x0e,
+ 0x238: 0x0e, 0x239: 0x0e, 0x23a: 0x0e, 0x23b: 0x0e, 0x23c: 0x0e, 0x23d: 0x0e, 0x23e: 0x0e, 0x23f: 0x0e,
+ // Block 0x9, offset 0x240
+ 0x240: 0x0e, 0x241: 0x0e, 0x242: 0x0e, 0x243: 0x0e, 0x244: 0x0e, 0x245: 0x0e, 0x246: 0x0e, 0x247: 0x0e,
+ 0x248: 0x0e, 0x249: 0x0e, 0x24a: 0x0e, 0x24b: 0x0e, 0x24c: 0x0e, 0x24d: 0x0e, 0x24e: 0x0e, 0x24f: 0x0e,
+ 0x250: 0x0e, 0x251: 0x0e, 0x252: 0x3b, 0x253: 0x3c,
+ 0x265: 0x3d,
+ 0x270: 0x0e, 0x271: 0x0e, 0x272: 0x0e, 0x273: 0x0e, 0x274: 0x0e, 0x275: 0x0e, 0x276: 0x0e, 0x277: 0x0e,
+ 0x278: 0x0e, 0x279: 0x0e, 0x27a: 0x0e, 0x27b: 0x0e, 0x27c: 0x0e, 0x27d: 0x0e, 0x27e: 0x0e, 0x27f: 0x0e,
+ // Block 0xa, offset 0x280
+ 0x280: 0x0e, 0x281: 0x0e, 0x282: 0x0e, 0x283: 0x0e, 0x284: 0x0e, 0x285: 0x0e, 0x286: 0x0e, 0x287: 0x0e,
+ 0x288: 0x0e, 0x289: 0x0e, 0x28a: 0x0e, 0x28b: 0x0e, 0x28c: 0x0e, 0x28d: 0x0e, 0x28e: 0x0e, 0x28f: 0x0e,
+ 0x290: 0x0e, 0x291: 0x0e, 0x292: 0x0e, 0x293: 0x0e, 0x294: 0x0e, 0x295: 0x0e, 0x296: 0x0e, 0x297: 0x0e,
+ 0x298: 0x0e, 0x299: 0x0e, 0x29a: 0x0e, 0x29b: 0x0e, 0x29c: 0x0e, 0x29d: 0x0e, 0x29e: 0x3e,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x08, 0x2c1: 0x08, 0x2c2: 0x08, 0x2c3: 0x08, 0x2c4: 0x08, 0x2c5: 0x08, 0x2c6: 0x08, 0x2c7: 0x08,
+ 0x2c8: 0x08, 0x2c9: 0x08, 0x2ca: 0x08, 0x2cb: 0x08, 0x2cc: 0x08, 0x2cd: 0x08, 0x2ce: 0x08, 0x2cf: 0x08,
+ 0x2d0: 0x08, 0x2d1: 0x08, 0x2d2: 0x08, 0x2d3: 0x08, 0x2d4: 0x08, 0x2d5: 0x08, 0x2d6: 0x08, 0x2d7: 0x08,
+ 0x2d8: 0x08, 0x2d9: 0x08, 0x2da: 0x08, 0x2db: 0x08, 0x2dc: 0x08, 0x2dd: 0x08, 0x2de: 0x08, 0x2df: 0x08,
+ 0x2e0: 0x08, 0x2e1: 0x08, 0x2e2: 0x08, 0x2e3: 0x08, 0x2e4: 0x08, 0x2e5: 0x08, 0x2e6: 0x08, 0x2e7: 0x08,
+ 0x2e8: 0x08, 0x2e9: 0x08, 0x2ea: 0x08, 0x2eb: 0x08, 0x2ec: 0x08, 0x2ed: 0x08, 0x2ee: 0x08, 0x2ef: 0x08,
+ 0x2f0: 0x08, 0x2f1: 0x08, 0x2f2: 0x08, 0x2f3: 0x08, 0x2f4: 0x08, 0x2f5: 0x08, 0x2f6: 0x08, 0x2f7: 0x08,
+ 0x2f8: 0x08, 0x2f9: 0x08, 0x2fa: 0x08, 0x2fb: 0x08, 0x2fc: 0x08, 0x2fd: 0x08, 0x2fe: 0x08, 0x2ff: 0x08,
+ // Block 0xc, offset 0x300
+ 0x300: 0x08, 0x301: 0x08, 0x302: 0x08, 0x303: 0x08, 0x304: 0x08, 0x305: 0x08, 0x306: 0x08, 0x307: 0x08,
+ 0x308: 0x08, 0x309: 0x08, 0x30a: 0x08, 0x30b: 0x08, 0x30c: 0x08, 0x30d: 0x08, 0x30e: 0x08, 0x30f: 0x08,
+ 0x310: 0x08, 0x311: 0x08, 0x312: 0x08, 0x313: 0x08, 0x314: 0x08, 0x315: 0x08, 0x316: 0x08, 0x317: 0x08,
+ 0x318: 0x08, 0x319: 0x08, 0x31a: 0x08, 0x31b: 0x08, 0x31c: 0x08, 0x31d: 0x08, 0x31e: 0x08, 0x31f: 0x08,
+ 0x320: 0x08, 0x321: 0x08, 0x322: 0x08, 0x323: 0x08, 0x324: 0x0e, 0x325: 0x0e, 0x326: 0x0e, 0x327: 0x0e,
+ 0x328: 0x0e, 0x329: 0x0e, 0x32a: 0x0e, 0x32b: 0x0e,
+ 0x338: 0x3f, 0x339: 0x40, 0x33c: 0x41, 0x33d: 0x42, 0x33e: 0x43, 0x33f: 0x44,
+ // Block 0xd, offset 0x340
+ 0x37f: 0x45,
+ // Block 0xe, offset 0x380
+ 0x380: 0x0e, 0x381: 0x0e, 0x382: 0x0e, 0x383: 0x0e, 0x384: 0x0e, 0x385: 0x0e, 0x386: 0x0e, 0x387: 0x0e,
+ 0x388: 0x0e, 0x389: 0x0e, 0x38a: 0x0e, 0x38b: 0x0e, 0x38c: 0x0e, 0x38d: 0x0e, 0x38e: 0x0e, 0x38f: 0x0e,
+ 0x390: 0x0e, 0x391: 0x0e, 0x392: 0x0e, 0x393: 0x0e, 0x394: 0x0e, 0x395: 0x0e, 0x396: 0x0e, 0x397: 0x0e,
+ 0x398: 0x0e, 0x399: 0x0e, 0x39a: 0x0e, 0x39b: 0x0e, 0x39c: 0x0e, 0x39d: 0x0e, 0x39e: 0x0e, 0x39f: 0x46,
+ 0x3a0: 0x0e, 0x3a1: 0x0e, 0x3a2: 0x0e, 0x3a3: 0x0e, 0x3a4: 0x0e, 0x3a5: 0x0e, 0x3a6: 0x0e, 0x3a7: 0x0e,
+ 0x3a8: 0x0e, 0x3a9: 0x0e, 0x3aa: 0x0e, 0x3ab: 0x47,
+ // Block 0xf, offset 0x3c0
+ 0x3c0: 0x48,
+ // Block 0x10, offset 0x400
+ 0x400: 0x49, 0x403: 0x4a, 0x404: 0x4b, 0x405: 0x4c, 0x406: 0x4d,
+ 0x408: 0x4e, 0x409: 0x4f, 0x40c: 0x50, 0x40d: 0x51, 0x40e: 0x52, 0x40f: 0x53,
+ 0x410: 0x3a, 0x411: 0x54, 0x412: 0x0e, 0x413: 0x55, 0x414: 0x56, 0x415: 0x57, 0x416: 0x58, 0x417: 0x59,
+ 0x418: 0x0e, 0x419: 0x5a, 0x41a: 0x0e, 0x41b: 0x5b,
+ 0x424: 0x5c, 0x425: 0x5d, 0x426: 0x5e, 0x427: 0x5f,
+ // Block 0x11, offset 0x440
+ 0x456: 0x0b, 0x457: 0x06,
+ 0x458: 0x0c, 0x45b: 0x0d, 0x45f: 0x0e,
+ 0x460: 0x06, 0x461: 0x06, 0x462: 0x06, 0x463: 0x06, 0x464: 0x06, 0x465: 0x06, 0x466: 0x06, 0x467: 0x06,
+ 0x468: 0x06, 0x469: 0x06, 0x46a: 0x06, 0x46b: 0x06, 0x46c: 0x06, 0x46d: 0x06, 0x46e: 0x06, 0x46f: 0x06,
+ 0x470: 0x06, 0x471: 0x06, 0x472: 0x06, 0x473: 0x06, 0x474: 0x06, 0x475: 0x06, 0x476: 0x06, 0x477: 0x06,
+ 0x478: 0x06, 0x479: 0x06, 0x47a: 0x06, 0x47b: 0x06, 0x47c: 0x06, 0x47d: 0x06, 0x47e: 0x06, 0x47f: 0x06,
+ // Block 0x12, offset 0x480
+ 0x484: 0x08, 0x485: 0x08, 0x486: 0x08, 0x487: 0x09,
+ // Block 0x13, offset 0x4c0
+ 0x4c0: 0x08, 0x4c1: 0x08, 0x4c2: 0x08, 0x4c3: 0x08, 0x4c4: 0x08, 0x4c5: 0x08, 0x4c6: 0x08, 0x4c7: 0x08,
+ 0x4c8: 0x08, 0x4c9: 0x08, 0x4ca: 0x08, 0x4cb: 0x08, 0x4cc: 0x08, 0x4cd: 0x08, 0x4ce: 0x08, 0x4cf: 0x08,
+ 0x4d0: 0x08, 0x4d1: 0x08, 0x4d2: 0x08, 0x4d3: 0x08, 0x4d4: 0x08, 0x4d5: 0x08, 0x4d6: 0x08, 0x4d7: 0x08,
+ 0x4d8: 0x08, 0x4d9: 0x08, 0x4da: 0x08, 0x4db: 0x08, 0x4dc: 0x08, 0x4dd: 0x08, 0x4de: 0x08, 0x4df: 0x08,
+ 0x4e0: 0x08, 0x4e1: 0x08, 0x4e2: 0x08, 0x4e3: 0x08, 0x4e4: 0x08, 0x4e5: 0x08, 0x4e6: 0x08, 0x4e7: 0x08,
+ 0x4e8: 0x08, 0x4e9: 0x08, 0x4ea: 0x08, 0x4eb: 0x08, 0x4ec: 0x08, 0x4ed: 0x08, 0x4ee: 0x08, 0x4ef: 0x08,
+ 0x4f0: 0x08, 0x4f1: 0x08, 0x4f2: 0x08, 0x4f3: 0x08, 0x4f4: 0x08, 0x4f5: 0x08, 0x4f6: 0x08, 0x4f7: 0x08,
+ 0x4f8: 0x08, 0x4f9: 0x08, 0x4fa: 0x08, 0x4fb: 0x08, 0x4fc: 0x08, 0x4fd: 0x08, 0x4fe: 0x08, 0x4ff: 0x60,
+ // Block 0x14, offset 0x500
+ 0x520: 0x10,
+ 0x530: 0x09, 0x531: 0x09, 0x532: 0x09, 0x533: 0x09, 0x534: 0x09, 0x535: 0x09, 0x536: 0x09, 0x537: 0x09,
+ 0x538: 0x09, 0x539: 0x09, 0x53a: 0x09, 0x53b: 0x09, 0x53c: 0x09, 0x53d: 0x09, 0x53e: 0x09, 0x53f: 0x11,
+ // Block 0x15, offset 0x540
+ 0x540: 0x09, 0x541: 0x09, 0x542: 0x09, 0x543: 0x09, 0x544: 0x09, 0x545: 0x09, 0x546: 0x09, 0x547: 0x09,
+ 0x548: 0x09, 0x549: 0x09, 0x54a: 0x09, 0x54b: 0x09, 0x54c: 0x09, 0x54d: 0x09, 0x54e: 0x09, 0x54f: 0x11,
+}
+
+// inverseData contains 4-byte entries of the following format:
+// <length> <modified UTF-8-encoded rune> <0 padding>
+// The last byte of the UTF-8-encoded rune is xor-ed with the last byte of the
+// UTF-8 encoding of the original rune. Mappings often have the following
+// pattern:
+// A -> A (U+FF21 -> U+0041)
+// ï¼¢ -> B (U+FF22 -> U+0042)
+// ...
+// By xor-ing the last byte the same entry can be shared by many mappings. This
+// reduces the total number of distinct entries by about two thirds.
+// The resulting entry for the aforementioned mappings is
+// { 0x01, 0xE0, 0x00, 0x00 }
+// Using this entry to map U+FF21 (UTF-8 [EF BC A1]), we get
+// E0 ^ A1 = 41.
+// Similarly, for U+FF22 (UTF-8 [EF BC A2]), we get
+// E0 ^ A2 = 42.
+// Note that because of the xor-ing, the byte sequence stored in the entry is
+// not valid UTF-8.
+var inverseData = [150][4]byte{
+ {0x00, 0x00, 0x00, 0x00},
+ {0x03, 0xe3, 0x80, 0xa0},
+ {0x03, 0xef, 0xbc, 0xa0},
+ {0x03, 0xef, 0xbc, 0xe0},
+ {0x03, 0xef, 0xbd, 0xe0},
+ {0x03, 0xef, 0xbf, 0x02},
+ {0x03, 0xef, 0xbf, 0x00},
+ {0x03, 0xef, 0xbf, 0x0e},
+ {0x03, 0xef, 0xbf, 0x0c},
+ {0x03, 0xef, 0xbf, 0x0f},
+ {0x03, 0xef, 0xbf, 0x39},
+ {0x03, 0xef, 0xbf, 0x3b},
+ {0x03, 0xef, 0xbf, 0x3f},
+ {0x03, 0xef, 0xbf, 0x2a},
+ {0x03, 0xef, 0xbf, 0x0d},
+ {0x03, 0xef, 0xbf, 0x25},
+ {0x03, 0xef, 0xbd, 0x1a},
+ {0x03, 0xef, 0xbd, 0x26},
+ {0x01, 0xa0, 0x00, 0x00},
+ {0x03, 0xef, 0xbd, 0x25},
+ {0x03, 0xef, 0xbd, 0x23},
+ {0x03, 0xef, 0xbd, 0x2e},
+ {0x03, 0xef, 0xbe, 0x07},
+ {0x03, 0xef, 0xbe, 0x05},
+ {0x03, 0xef, 0xbd, 0x06},
+ {0x03, 0xef, 0xbd, 0x13},
+ {0x03, 0xef, 0xbd, 0x0b},
+ {0x03, 0xef, 0xbd, 0x16},
+ {0x03, 0xef, 0xbd, 0x0c},
+ {0x03, 0xef, 0xbd, 0x15},
+ {0x03, 0xef, 0xbd, 0x0d},
+ {0x03, 0xef, 0xbd, 0x1c},
+ {0x03, 0xef, 0xbd, 0x02},
+ {0x03, 0xef, 0xbd, 0x1f},
+ {0x03, 0xef, 0xbd, 0x1d},
+ {0x03, 0xef, 0xbd, 0x17},
+ {0x03, 0xef, 0xbd, 0x08},
+ {0x03, 0xef, 0xbd, 0x09},
+ {0x03, 0xef, 0xbd, 0x0e},
+ {0x03, 0xef, 0xbd, 0x04},
+ {0x03, 0xef, 0xbd, 0x05},
+ {0x03, 0xef, 0xbe, 0x3f},
+ {0x03, 0xef, 0xbe, 0x00},
+ {0x03, 0xef, 0xbd, 0x2c},
+ {0x03, 0xef, 0xbe, 0x06},
+ {0x03, 0xef, 0xbe, 0x0c},
+ {0x03, 0xef, 0xbe, 0x0f},
+ {0x03, 0xef, 0xbe, 0x0d},
+ {0x03, 0xef, 0xbe, 0x0b},
+ {0x03, 0xef, 0xbe, 0x19},
+ {0x03, 0xef, 0xbe, 0x15},
+ {0x03, 0xef, 0xbe, 0x11},
+ {0x03, 0xef, 0xbe, 0x31},
+ {0x03, 0xef, 0xbe, 0x33},
+ {0x03, 0xef, 0xbd, 0x0f},
+ {0x03, 0xef, 0xbe, 0x30},
+ {0x03, 0xef, 0xbe, 0x3e},
+ {0x03, 0xef, 0xbe, 0x32},
+ {0x03, 0xef, 0xbe, 0x36},
+ {0x03, 0xef, 0xbd, 0x14},
+ {0x03, 0xef, 0xbe, 0x2e},
+ {0x03, 0xef, 0xbd, 0x1e},
+ {0x03, 0xef, 0xbe, 0x10},
+ {0x03, 0xef, 0xbf, 0x13},
+ {0x03, 0xef, 0xbf, 0x15},
+ {0x03, 0xef, 0xbf, 0x17},
+ {0x03, 0xef, 0xbf, 0x1f},
+ {0x03, 0xef, 0xbf, 0x1d},
+ {0x03, 0xef, 0xbf, 0x1b},
+ {0x03, 0xef, 0xbf, 0x09},
+ {0x03, 0xef, 0xbf, 0x0b},
+ {0x03, 0xef, 0xbf, 0x37},
+ {0x03, 0xef, 0xbe, 0x04},
+ {0x01, 0xe0, 0x00, 0x00},
+ {0x03, 0xe2, 0xa6, 0x1a},
+ {0x03, 0xe2, 0xa6, 0x26},
+ {0x03, 0xe3, 0x80, 0x23},
+ {0x03, 0xe3, 0x80, 0x2e},
+ {0x03, 0xe3, 0x80, 0x25},
+ {0x03, 0xe3, 0x83, 0x1e},
+ {0x03, 0xe3, 0x83, 0x14},
+ {0x03, 0xe3, 0x82, 0x06},
+ {0x03, 0xe3, 0x82, 0x0b},
+ {0x03, 0xe3, 0x82, 0x0c},
+ {0x03, 0xe3, 0x82, 0x0d},
+ {0x03, 0xe3, 0x82, 0x02},
+ {0x03, 0xe3, 0x83, 0x0f},
+ {0x03, 0xe3, 0x83, 0x08},
+ {0x03, 0xe3, 0x83, 0x09},
+ {0x03, 0xe3, 0x83, 0x2c},
+ {0x03, 0xe3, 0x83, 0x0c},
+ {0x03, 0xe3, 0x82, 0x13},
+ {0x03, 0xe3, 0x82, 0x16},
+ {0x03, 0xe3, 0x82, 0x15},
+ {0x03, 0xe3, 0x82, 0x1c},
+ {0x03, 0xe3, 0x82, 0x1f},
+ {0x03, 0xe3, 0x82, 0x1d},
+ {0x03, 0xe3, 0x82, 0x1a},
+ {0x03, 0xe3, 0x82, 0x17},
+ {0x03, 0xe3, 0x82, 0x08},
+ {0x03, 0xe3, 0x82, 0x09},
+ {0x03, 0xe3, 0x82, 0x0e},
+ {0x03, 0xe3, 0x82, 0x04},
+ {0x03, 0xe3, 0x82, 0x05},
+ {0x03, 0xe3, 0x82, 0x3f},
+ {0x03, 0xe3, 0x83, 0x00},
+ {0x03, 0xe3, 0x83, 0x06},
+ {0x03, 0xe3, 0x83, 0x05},
+ {0x03, 0xe3, 0x83, 0x0d},
+ {0x03, 0xe3, 0x83, 0x0b},
+ {0x03, 0xe3, 0x83, 0x07},
+ {0x03, 0xe3, 0x83, 0x19},
+ {0x03, 0xe3, 0x83, 0x15},
+ {0x03, 0xe3, 0x83, 0x11},
+ {0x03, 0xe3, 0x83, 0x31},
+ {0x03, 0xe3, 0x83, 0x33},
+ {0x03, 0xe3, 0x83, 0x30},
+ {0x03, 0xe3, 0x83, 0x3e},
+ {0x03, 0xe3, 0x83, 0x32},
+ {0x03, 0xe3, 0x83, 0x36},
+ {0x03, 0xe3, 0x83, 0x2e},
+ {0x03, 0xe3, 0x82, 0x07},
+ {0x03, 0xe3, 0x85, 0x04},
+ {0x03, 0xe3, 0x84, 0x10},
+ {0x03, 0xe3, 0x85, 0x30},
+ {0x03, 0xe3, 0x85, 0x0d},
+ {0x03, 0xe3, 0x85, 0x13},
+ {0x03, 0xe3, 0x85, 0x15},
+ {0x03, 0xe3, 0x85, 0x17},
+ {0x03, 0xe3, 0x85, 0x1f},
+ {0x03, 0xe3, 0x85, 0x1d},
+ {0x03, 0xe3, 0x85, 0x1b},
+ {0x03, 0xe3, 0x85, 0x09},
+ {0x03, 0xe3, 0x85, 0x0f},
+ {0x03, 0xe3, 0x85, 0x0b},
+ {0x03, 0xe3, 0x85, 0x37},
+ {0x03, 0xe3, 0x85, 0x3b},
+ {0x03, 0xe3, 0x85, 0x39},
+ {0x03, 0xe3, 0x85, 0x3f},
+ {0x02, 0xc2, 0x02, 0x00},
+ {0x02, 0xc2, 0x0e, 0x00},
+ {0x02, 0xc2, 0x0c, 0x00},
+ {0x02, 0xc2, 0x00, 0x00},
+ {0x03, 0xe2, 0x82, 0x0f},
+ {0x03, 0xe2, 0x94, 0x2a},
+ {0x03, 0xe2, 0x86, 0x39},
+ {0x03, 0xe2, 0x86, 0x3b},
+ {0x03, 0xe2, 0x86, 0x3f},
+ {0x03, 0xe2, 0x96, 0x0d},
+ {0x03, 0xe2, 0x97, 0x25},
+}
+
+// Total table size 14680 bytes (14KiB)
diff --git a/libgo/go/golang_org/x/text/width/transform.go b/libgo/go/golang_org/x/text/width/transform.go
new file mode 100644
index 0000000000..04f1a3fc59
--- /dev/null
+++ b/libgo/go/golang_org/x/text/width/transform.go
@@ -0,0 +1,239 @@
+// 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 width
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+type foldTransform struct {
+ transform.NopResetter
+}
+
+func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
+ for n < len(src) {
+ if src[n] < utf8.RuneSelf {
+ // ASCII fast path.
+ for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
+ }
+ continue
+ }
+ v, size := trie.lookup(src[n:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ err = transform.ErrShortSrc
+ } else {
+ n = len(src)
+ }
+ break
+ }
+ if elem(v)&tagNeedsFold != 0 {
+ err = transform.ErrEndOfSpan
+ break
+ }
+ n += size
+ }
+ return n, err
+}
+
+func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for nSrc < len(src) {
+ if src[nSrc] < utf8.RuneSelf {
+ // ASCII fast path.
+ start, end := nSrc, len(src)
+ if d := len(dst) - nDst; d < end-start {
+ end = nSrc + d
+ }
+ for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
+ }
+ n := copy(dst[nDst:], src[start:nSrc])
+ if nDst += n; nDst == len(dst) {
+ nSrc = start + n
+ if nSrc == len(src) {
+ return nDst, nSrc, nil
+ }
+ if src[nSrc] < utf8.RuneSelf {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ }
+ continue
+ }
+ v, size := trie.lookup(src[nSrc:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ return nDst, nSrc, transform.ErrShortSrc
+ }
+ size = 1 // gobble 1 byte
+ }
+ if elem(v)&tagNeedsFold == 0 {
+ if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ nDst += size
+ } else {
+ data := inverseData[byte(v)]
+ if len(dst)-nDst < int(data[0]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ i := 1
+ for end := int(data[0]); i < end; i++ {
+ dst[nDst] = data[i]
+ nDst++
+ }
+ dst[nDst] = data[i] ^ src[nSrc+size-1]
+ nDst++
+ }
+ nSrc += size
+ }
+ return nDst, nSrc, nil
+}
+
+type narrowTransform struct {
+ transform.NopResetter
+}
+
+func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
+ for n < len(src) {
+ if src[n] < utf8.RuneSelf {
+ // ASCII fast path.
+ for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
+ }
+ continue
+ }
+ v, size := trie.lookup(src[n:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ err = transform.ErrShortSrc
+ } else {
+ n = len(src)
+ }
+ break
+ }
+ if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
+ } else {
+ err = transform.ErrEndOfSpan
+ break
+ }
+ n += size
+ }
+ return n, err
+}
+
+func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for nSrc < len(src) {
+ if src[nSrc] < utf8.RuneSelf {
+ // ASCII fast path.
+ start, end := nSrc, len(src)
+ if d := len(dst) - nDst; d < end-start {
+ end = nSrc + d
+ }
+ for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
+ }
+ n := copy(dst[nDst:], src[start:nSrc])
+ if nDst += n; nDst == len(dst) {
+ nSrc = start + n
+ if nSrc == len(src) {
+ return nDst, nSrc, nil
+ }
+ if src[nSrc] < utf8.RuneSelf {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ }
+ continue
+ }
+ v, size := trie.lookup(src[nSrc:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ return nDst, nSrc, transform.ErrShortSrc
+ }
+ size = 1 // gobble 1 byte
+ }
+ if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
+ if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ nDst += size
+ } else {
+ data := inverseData[byte(v)]
+ if len(dst)-nDst < int(data[0]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ i := 1
+ for end := int(data[0]); i < end; i++ {
+ dst[nDst] = data[i]
+ nDst++
+ }
+ dst[nDst] = data[i] ^ src[nSrc+size-1]
+ nDst++
+ }
+ nSrc += size
+ }
+ return nDst, nSrc, nil
+}
+
+type wideTransform struct {
+ transform.NopResetter
+}
+
+func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
+ for n < len(src) {
+ // TODO: Consider ASCII fast path. Special-casing ASCII handling can
+ // reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
+ // not enough to warrant the extra code and complexity.
+ v, size := trie.lookup(src[n:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ err = transform.ErrShortSrc
+ } else {
+ n = len(src)
+ }
+ break
+ }
+ if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
+ } else {
+ err = transform.ErrEndOfSpan
+ break
+ }
+ n += size
+ }
+ return n, err
+}
+
+func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for nSrc < len(src) {
+ // TODO: Consider ASCII fast path. Special-casing ASCII handling can
+ // reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
+ // not enough to warrant the extra code and complexity.
+ v, size := trie.lookup(src[nSrc:])
+ if size == 0 { // incomplete UTF-8 encoding
+ if !atEOF {
+ return nDst, nSrc, transform.ErrShortSrc
+ }
+ size = 1 // gobble 1 byte
+ }
+ if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
+ if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ nDst += size
+ } else {
+ data := inverseData[byte(v)]
+ if len(dst)-nDst < int(data[0]) {
+ return nDst, nSrc, transform.ErrShortDst
+ }
+ i := 1
+ for end := int(data[0]); i < end; i++ {
+ dst[nDst] = data[i]
+ nDst++
+ }
+ dst[nDst] = data[i] ^ src[nSrc+size-1]
+ nDst++
+ }
+ nSrc += size
+ }
+ return nDst, nSrc, nil
+}
diff --git a/libgo/go/golang_org/x/text/width/trieval.go b/libgo/go/golang_org/x/text/width/trieval.go
new file mode 100644
index 0000000000..0ecffb4c64
--- /dev/null
+++ b/libgo/go/golang_org/x/text/width/trieval.go
@@ -0,0 +1,30 @@
+// This file was generated by go generate; DO NOT EDIT
+
+package width
+
+// elem is an entry of the width trie. The high byte is used to encode the type
+// of the rune. The low byte is used to store the index to a mapping entry in
+// the inverseData array.
+type elem uint16
+
+const (
+ tagNeutral elem = iota << typeShift
+ tagAmbiguous
+ tagWide
+ tagNarrow
+ tagFullwidth
+ tagHalfwidth
+)
+
+const (
+ numTypeBits = 3
+ typeShift = 16 - numTypeBits
+
+ // tagNeedsFold is true for all fullwidth and halfwidth runes except for
+ // the Won sign U+20A9.
+ tagNeedsFold = 0x1000
+
+ // The Korean Won sign is halfwidth, but SHOULD NOT be mapped to a wide
+ // variant.
+ wonSign rune = 0x20A9
+)
diff --git a/libgo/go/golang_org/x/text/width/width.go b/libgo/go/golang_org/x/text/width/width.go
new file mode 100644
index 0000000000..27f55b8db7
--- /dev/null
+++ b/libgo/go/golang_org/x/text/width/width.go
@@ -0,0 +1,206 @@
+// 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.
+
+//go:generate stringer -type=Kind
+//go:generate go run gen.go gen_common.go gen_trieval.go
+
+// Package width provides functionality for handling different widths in text.
+//
+// Wide characters behave like ideographs; they tend to allow line breaks after
+// each character and remain upright in vertical text layout. Narrow characters
+// are kept together in words or runs that are rotated sideways in vertical text
+// layout.
+//
+// For more information, see http://unicode.org/reports/tr11/.
+package width // import "golang_org/x/text/width"
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+// TODO
+// 1) Reduce table size by compressing blocks.
+// 2) API proposition for computing display length
+// (approximation, fixed pitch only).
+// 3) Implement display length.
+
+// Kind indicates the type of width property as defined in http://unicode.org/reports/tr11/.
+type Kind int
+
+const (
+ // Neutral characters do not occur in legacy East Asian character sets.
+ Neutral Kind = iota
+
+ // EastAsianAmbiguous characters that can be sometimes wide and sometimes
+ // narrow and require additional information not contained in the character
+ // code to further resolve their width.
+ EastAsianAmbiguous
+
+ // EastAsianWide characters are wide in its usual form. They occur only in
+ // the context of East Asian typography. These runes may have explicit
+ // halfwidth counterparts.
+ EastAsianWide
+
+ // EastAsianNarrow characters are narrow in its usual form. They often have
+ // fullwidth counterparts.
+ EastAsianNarrow
+
+ // Note: there exist Narrow runes that do not have fullwidth or wide
+ // counterparts, despite what the definition says (e.g. U+27E6).
+
+ // EastAsianFullwidth characters have a compatibility decompositions of type
+ // wide that map to a narrow counterpart.
+ EastAsianFullwidth
+
+ // EastAsianHalfwidth characters have a compatibility decomposition of type
+ // narrow that map to a wide or ambiguous counterpart, plus U+20A9 â‚© WON
+ // SIGN.
+ EastAsianHalfwidth
+
+ // Note: there exist runes that have a halfwidth counterparts but that are
+ // classified as Ambiguous, rather than wide (e.g. U+2190).
+)
+
+// TODO: the generated tries need to return size 1 for invalid runes for the
+// width to be computed correctly (each byte should render width 1)
+
+var trie = newWidthTrie(0)
+
+// Lookup reports the Properties of the first rune in b and the number of bytes
+// of its UTF-8 encoding.
+func Lookup(b []byte) (p Properties, size int) {
+ v, sz := trie.lookup(b)
+ return Properties{elem(v), b[sz-1]}, sz
+}
+
+// LookupString reports the Properties of the first rune in s and the number of
+// bytes of its UTF-8 encoding.
+func LookupString(s string) (p Properties, size int) {
+ v, sz := trie.lookupString(s)
+ return Properties{elem(v), s[sz-1]}, sz
+}
+
+// LookupRune reports the Properties of rune r.
+func LookupRune(r rune) Properties {
+ var buf [4]byte
+ n := utf8.EncodeRune(buf[:], r)
+ v, _ := trie.lookup(buf[:n])
+ last := byte(r)
+ if r >= utf8.RuneSelf {
+ last = 0x80 + byte(r&0x3f)
+ }
+ return Properties{elem(v), last}
+}
+
+// Properties provides access to width properties of a rune.
+type Properties struct {
+ elem elem
+ last byte
+}
+
+func (e elem) kind() Kind {
+ return Kind(e >> typeShift)
+}
+
+// Kind returns the Kind of a rune as defined in Unicode TR #11.
+// See http://unicode.org/reports/tr11/ for more details.
+func (p Properties) Kind() Kind {
+ return p.elem.kind()
+}
+
+// Folded returns the folded variant of a rune or 0 if the rune is canonical.
+func (p Properties) Folded() rune {
+ if p.elem&tagNeedsFold != 0 {
+ buf := inverseData[byte(p.elem)]
+ buf[buf[0]] ^= p.last
+ r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+ return r
+ }
+ return 0
+}
+
+// Narrow returns the narrow variant of a rune or 0 if the rune is already
+// narrow or doesn't have a narrow variant.
+func (p Properties) Narrow() rune {
+ if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous) {
+ buf := inverseData[byte(p.elem)]
+ buf[buf[0]] ^= p.last
+ r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+ return r
+ }
+ return 0
+}
+
+// Wide returns the wide variant of a rune or 0 if the rune is already
+// wide or doesn't have a wide variant.
+func (p Properties) Wide() rune {
+ if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianHalfwidth || k == EastAsianNarrow) {
+ buf := inverseData[byte(p.elem)]
+ buf[buf[0]] ^= p.last
+ r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+ return r
+ }
+ return 0
+}
+
+// TODO for Properties:
+// - Add Fullwidth/Halfwidth or Inverted methods for computing variants
+// mapping.
+// - Add width information (including information on non-spacing runes).
+
+// Transformer implements the transform.Transformer interface.
+type Transformer struct {
+ t transform.SpanningTransformer
+}
+
+// Reset implements the transform.Transformer interface.
+func (t Transformer) Reset() { t.t.Reset() }
+
+// Transform implements the transform.Transformer interface.
+func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ return t.t.Transform(dst, src, atEOF)
+}
+
+// Span implements the transform.SpanningTransformer interface.
+func (t Transformer) Span(src []byte, atEOF bool) (n int, err error) {
+ return t.t.Span(src, atEOF)
+}
+
+// Bytes returns a new byte slice with the result of applying t to b.
+func (t Transformer) Bytes(b []byte) []byte {
+ b, _, _ = transform.Bytes(t, b)
+ return b
+}
+
+// String returns a string with the result of applying t to s.
+func (t Transformer) String(s string) string {
+ s, _, _ = transform.String(t, s)
+ return s
+}
+
+var (
+ // Fold is a transform that maps all runes to their canonical width.
+ //
+ // Note that the NFKC and NFKD transforms in golang.org/x/text/unicode/norm
+ // provide a more generic folding mechanism.
+ Fold Transformer = Transformer{foldTransform{}}
+
+ // Widen is a transform that maps runes to their wide variant, if
+ // available.
+ Widen Transformer = Transformer{wideTransform{}}
+
+ // Narrow is a transform that maps runes to their narrow variant, if
+ // available.
+ Narrow Transformer = Transformer{narrowTransform{}}
+)
+
+// TODO: Consider the following options:
+// - Treat Ambiguous runes that have a halfwidth counterpart as wide, or some
+// generalized variant of this.
+// - Consider a wide Won character to be the default width (or some generalized
+// variant of this).
+// - Filter the set of characters that gets converted (the preferred approach is
+// to allow applying filters to transforms).
diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go
index 0c733f751a..21d6a2e1dc 100644
--- a/libgo/go/hash/adler32/adler32.go
+++ b/libgo/go/hash/adler32/adler32.go
@@ -42,7 +42,7 @@ func New() hash.Hash32 {
func (d *digest) Size() int { return Size }
-func (d *digest) BlockSize() int { return 1 }
+func (d *digest) BlockSize() int { return 4 }
// Add p to the running checksum d.
func update(d digest, p []byte) digest {
@@ -52,6 +52,17 @@ func update(d digest, p []byte) digest {
if len(p) > nmax {
p, q = p[:nmax], p[nmax:]
}
+ for len(p) >= 4 {
+ s1 += uint32(p[0])
+ s2 += s1
+ s1 += uint32(p[1])
+ s2 += s1
+ s1 += uint32(p[2])
+ s2 += s1
+ s1 += uint32(p[3])
+ s2 += s1
+ p = p[4:]
+ }
for _, x := range p {
s1 += uint32(x)
s2 += s1
diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go
index dc5994885f..8aa91b17e9 100644
--- a/libgo/go/hash/crc32/crc32.go
+++ b/libgo/go/hash/crc32/crc32.go
@@ -40,69 +40,96 @@ const (
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint32
+// This file makes use of functions implemented in architecture-specific files.
+// The interface that they implement is as follows:
+//
+// // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE
+// // algorithm is available.
+// archAvailableIEEE() bool
+//
+// // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm.
+// // It can only be called if archAvailableIEEE() returns true.
+// archInitIEEE()
+//
+// // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if
+// // archInitIEEE() was previously called.
+// archUpdateIEEE(crc uint32, p []byte) uint32
+//
+// // archAvailableCastagnoli reports whether an architecture-specific
+// // CRC32-C algorithm is available.
+// archAvailableCastagnoli() bool
+//
+// // archInitCastagnoli initializes the architecture-specific CRC32-C
+// // algorithm. It can only be called if archAvailableCastagnoli() returns
+// // true.
+// archInitCastagnoli()
+//
+// // archUpdateCastagnoli updates the given CRC32-C. It can only be called
+// // if archInitCastagnoli() was previously called.
+// archUpdateCastagnoli(crc uint32, p []byte) uint32
+
// castagnoliTable points to a lazily initialized Table for the Castagnoli
// polynomial. MakeTable will always return this value when asked to make a
// Castagnoli table so we can compare against it to find when the caller is
// using this polynomial.
var castagnoliTable *Table
+var castagnoliTable8 *slicing8Table
+var castagnoliArchImpl bool
+var updateCastagnoli func(crc uint32, p []byte) uint32
var castagnoliOnce sync.Once
func castagnoliInit() {
- castagnoliTable = makeTable(Castagnoli)
+ castagnoliTable = simpleMakeTable(Castagnoli)
+ castagnoliArchImpl = archAvailableCastagnoli()
+
+ if castagnoliArchImpl {
+ archInitCastagnoli()
+ updateCastagnoli = archUpdateCastagnoli
+ } else {
+ // Initialize the slicing-by-8 table.
+ castagnoliTable8 = slicingMakeTable(Castagnoli)
+ updateCastagnoli = func(crc uint32, p []byte) uint32 {
+ return slicingUpdate(crc, castagnoliTable8, p)
+ }
+ }
}
// IEEETable is the table for the IEEE polynomial.
-var IEEETable = makeTable(IEEE)
-
-// slicing8Table is array of 8 Tables
-type slicing8Table [8]Table
+var IEEETable = simpleMakeTable(IEEE)
// ieeeTable8 is the slicing8Table for IEEE
var ieeeTable8 *slicing8Table
-var ieeeTable8Once sync.Once
+var ieeeArchImpl bool
+var updateIEEE func(crc uint32, p []byte) uint32
+var ieeeOnce sync.Once
+
+func ieeeInit() {
+ ieeeArchImpl = archAvailableIEEE()
+
+ if ieeeArchImpl {
+ archInitIEEE()
+ updateIEEE = archUpdateIEEE
+ } else {
+ // Initialize the slicing-by-8 table.
+ ieeeTable8 = slicingMakeTable(IEEE)
+ updateIEEE = func(crc uint32, p []byte) uint32 {
+ return slicingUpdate(crc, ieeeTable8, p)
+ }
+ }
+}
// MakeTable returns a Table constructed from the specified polynomial.
// The contents of this Table must not be modified.
func MakeTable(poly uint32) *Table {
switch poly {
case IEEE:
+ ieeeOnce.Do(ieeeInit)
return IEEETable
case Castagnoli:
castagnoliOnce.Do(castagnoliInit)
return castagnoliTable
}
- return makeTable(poly)
-}
-
-// makeTable returns the Table constructed from the specified polynomial.
-func makeTable(poly uint32) *Table {
- t := new(Table)
- for i := 0; i < 256; i++ {
- crc := uint32(i)
- for j := 0; j < 8; j++ {
- if crc&1 == 1 {
- crc = (crc >> 1) ^ poly
- } else {
- crc >>= 1
- }
- }
- t[i] = crc
- }
- return t
-}
-
-// makeTable8 returns slicing8Table constructed from the specified polynomial.
-func makeTable8(poly uint32) *slicing8Table {
- t := new(slicing8Table)
- t[0] = *makeTable(poly)
- for i := 0; i < 256; i++ {
- crc := t[0][i]
- for j := 1; j < 8; j++ {
- crc = t[0][crc&0xFF] ^ (crc >> 8)
- t[j][i] = crc
- }
- }
- return t
+ return simpleMakeTable(poly)
}
// digest represents the partial evaluation of a checksum.
@@ -114,7 +141,12 @@ type digest struct {
// New creates a new hash.Hash32 computing the CRC-32 checksum
// using the polynomial represented by the Table.
// Its Sum method will lay the value out in big-endian byte order.
-func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
+func New(tab *Table) hash.Hash32 {
+ if tab == IEEETable {
+ ieeeOnce.Do(ieeeInit)
+ }
+ return &digest{0, tab}
+}
// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
// using the IEEE polynomial.
@@ -127,41 +159,32 @@ func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { d.crc = 0 }
-func update(crc uint32, tab *Table, p []byte) uint32 {
- crc = ^crc
- for _, v := range p {
- crc = tab[byte(crc)^v] ^ (crc >> 8)
- }
- return ^crc
-}
-
-// updateSlicingBy8 updates CRC using Slicing-by-8
-func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
- crc = ^crc
- for len(p) > 8 {
- crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
- crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
- tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
- tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
- p = p[8:]
- }
- crc = ^crc
- return update(crc, &tab[0], p)
-}
-
// Update returns the result of adding the bytes in p to the crc.
func Update(crc uint32, tab *Table, p []byte) uint32 {
switch tab {
case castagnoliTable:
return updateCastagnoli(crc, p)
case IEEETable:
+ // Unfortunately, because IEEETable is exported, IEEE may be used without a
+ // call to MakeTable. We have to make sure it gets initialized in that case.
+ ieeeOnce.Do(ieeeInit)
return updateIEEE(crc, p)
+ default:
+ return simpleUpdate(crc, tab, p)
}
- return update(crc, tab, p)
}
func (d *digest) Write(p []byte) (n int, err error) {
- d.crc = Update(d.crc, d.tab, p)
+ switch d.tab {
+ case castagnoliTable:
+ d.crc = updateCastagnoli(d.crc, p)
+ case IEEETable:
+ // We only create digest objects through New() which takes care of
+ // initialization in this case.
+ d.crc = updateIEEE(d.crc, p)
+ default:
+ d.crc = simpleUpdate(d.crc, d.tab, p)
+ }
return len(p), nil
}
@@ -178,4 +201,7 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
// ChecksumIEEE returns the CRC-32 checksum of data
// using the IEEE polynomial.
-func ChecksumIEEE(data []byte) uint32 { return Update(0, IEEETable, data) }
+func ChecksumIEEE(data []byte) uint32 {
+ ieeeOnce.Do(ieeeInit)
+ return updateIEEE(0, data)
+}
diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64.go
index ab4e2b8c8c..72844f0037 100644
--- a/libgo/go/hash/crc32/crc32_amd64.go
+++ b/libgo/go/hash/crc32/crc32_amd64.go
@@ -2,8 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// AMD64-specific hardware-assisted CRC32 algorithms. See crc32.go for a
+// description of the interface that each architecture-specific file
+// implements.
+
+// +build ignore
+
package crc32
+import "unsafe"
+
// This file contains the code to call the SSE 4.2 version of the Castagnoli
// and IEEE CRC.
@@ -13,11 +21,20 @@ func haveSSE41() bool
func haveSSE42() bool
func haveCLMUL() bool
-// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE4.2 CRC32
// instruction.
//go:noescape
func castagnoliSSE42(crc uint32, p []byte) uint32
+// castagnoliSSE42Triple is defined in crc32_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+//go:noescape
+func castagnoliSSE42Triple(
+ crcA, crcB, crcC uint32,
+ a, b, c []byte,
+ rounds uint32,
+) (retA uint32, retB uint32, retC uint32)
+
// ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ
// instruction as well as SSE 4.1.
//go:noescape
@@ -26,31 +43,188 @@ func ieeeCLMUL(crc uint32, p []byte) uint32
var sse42 = haveSSE42()
var useFastIEEE = haveCLMUL() && haveSSE41()
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- if sse42 {
- return castagnoliSSE42(crc, p)
+const castagnoliK1 = 168
+const castagnoliK2 = 1344
+
+type sse42Table [4]Table
+
+var castagnoliSSE42TableK1 *sse42Table
+var castagnoliSSE42TableK2 *sse42Table
+
+func archAvailableCastagnoli() bool {
+ return sse42
+}
+
+func archInitCastagnoli() {
+ if !sse42 {
+ panic("arch-specific Castagnoli not available")
+ }
+ castagnoliSSE42TableK1 = new(sse42Table)
+ castagnoliSSE42TableK2 = new(sse42Table)
+ // See description in updateCastagnoli.
+ // t[0][i] = CRC(i000, O)
+ // t[1][i] = CRC(0i00, O)
+ // t[2][i] = CRC(00i0, O)
+ // t[3][i] = CRC(000i, O)
+ // where O is a sequence of K zeros.
+ var tmp [castagnoliK2]byte
+ for b := 0; b < 4; b++ {
+ for i := 0; i < 256; i++ {
+ val := uint32(i) << uint32(b*8)
+ castagnoliSSE42TableK1[b][i] = castagnoliSSE42(val, tmp[:castagnoliK1])
+ castagnoliSSE42TableK2[b][i] = castagnoliSSE42(val, tmp[:])
+ }
}
- return update(crc, castagnoliTable, p)
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- if useFastIEEE && len(p) >= 64 {
- left := len(p) & 15
- do := len(p) - left
- crc = ^ieeeCLMUL(^crc, p[:do])
- if left > 0 {
- crc = update(crc, IEEETable, p[do:])
+// castagnoliShift computes the CRC32-C of K1 or K2 zeroes (depending on the
+// table given) with the given initial crc value. This corresponds to
+// CRC(crc, O) in the description in updateCastagnoli.
+func castagnoliShift(table *sse42Table, crc uint32) uint32 {
+ return table[3][crc>>24] ^
+ table[2][(crc>>16)&0xFF] ^
+ table[1][(crc>>8)&0xFF] ^
+ table[0][crc&0xFF]
+}
+
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !sse42 {
+ panic("not available")
+ }
+
+ // This method is inspired from the algorithm in Intel's white paper:
+ // "Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction"
+ // The same strategy of splitting the buffer in three is used but the
+ // combining calculation is different; the complete derivation is explained
+ // below.
+ //
+ // -- The basic idea --
+ //
+ // The CRC32 instruction (available in SSE4.2) can process 8 bytes at a
+ // time. In recent Intel architectures the instruction takes 3 cycles;
+ // however the processor can pipeline up to three instructions if they
+ // don't depend on each other.
+ //
+ // Roughly this means that we can process three buffers in about the same
+ // time we can process one buffer.
+ //
+ // The idea is then to split the buffer in three, CRC the three pieces
+ // separately and then combine the results.
+ //
+ // Combining the results requires precomputed tables, so we must choose a
+ // fixed buffer length to optimize. The longer the length, the faster; but
+ // only buffers longer than this length will use the optimization. We choose
+ // two cutoffs and compute tables for both:
+ // - one around 512: 168*3=504
+ // - one around 4KB: 1344*3=4032
+ //
+ // -- The nitty gritty --
+ //
+ // Let CRC(I, X) be the non-inverted CRC32-C of the sequence X (with
+ // initial non-inverted CRC I). This function has the following properties:
+ // (a) CRC(I, AB) = CRC(CRC(I, A), B)
+ // (b) CRC(I, A xor B) = CRC(I, A) xor CRC(0, B)
+ //
+ // Say we want to compute CRC(I, ABC) where A, B, C are three sequences of
+ // K bytes each, where K is a fixed constant. Let O be the sequence of K zero
+ // bytes.
+ //
+ // CRC(I, ABC) = CRC(I, ABO xor C)
+ // = CRC(I, ABO) xor CRC(0, C)
+ // = CRC(CRC(I, AB), O) xor CRC(0, C)
+ // = CRC(CRC(I, AO xor B), O) xor CRC(0, C)
+ // = CRC(CRC(I, AO) xor CRC(0, B), O) xor CRC(0, C)
+ // = CRC(CRC(CRC(I, A), O) xor CRC(0, B), O) xor CRC(0, C)
+ //
+ // The castagnoliSSE42Triple function can compute CRC(I, A), CRC(0, B),
+ // and CRC(0, C) efficiently. We just need to find a way to quickly compute
+ // CRC(uvwx, O) given a 4-byte initial value uvwx. We can precompute these
+ // values; since we can't have a 32-bit table, we break it up into four
+ // 8-bit tables:
+ //
+ // CRC(uvwx, O) = CRC(u000, O) xor
+ // CRC(0v00, O) xor
+ // CRC(00w0, O) xor
+ // CRC(000x, O)
+ //
+ // We can compute tables corresponding to the four terms for all 8-bit
+ // values.
+
+ crc = ^crc
+
+ // If a buffer is long enough to use the optimization, process the first few
+ // bytes to align the buffer to an 8 byte boundary (if necessary).
+ if len(p) >= castagnoliK1*3 {
+ delta := int(uintptr(unsafe.Pointer(&p[0])) & 7)
+ if delta != 0 {
+ delta = 8 - delta
+ crc = castagnoliSSE42(crc, p[:delta])
+ p = p[delta:]
}
- return crc
}
- // only use slicing-by-8 when input is >= 4KB
- if len(p) >= 4096 {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+ // Process 3*K2 at a time.
+ for len(p) >= castagnoliK2*3 {
+ // Compute CRC(I, A), CRC(0, B), and CRC(0, C).
+ crcA, crcB, crcC := castagnoliSSE42Triple(
+ crc, 0, 0,
+ p, p[castagnoliK2:], p[castagnoliK2*2:],
+ castagnoliK2/24)
+
+ // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B)
+ crcAB := castagnoliShift(castagnoliSSE42TableK2, crcA) ^ crcB
+ // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C)
+ crc = castagnoliShift(castagnoliSSE42TableK2, crcAB) ^ crcC
+ p = p[castagnoliK2*3:]
+ }
+
+ // Process 3*K1 at a time.
+ for len(p) >= castagnoliK1*3 {
+ // Compute CRC(I, A), CRC(0, B), and CRC(0, C).
+ crcA, crcB, crcC := castagnoliSSE42Triple(
+ crc, 0, 0,
+ p, p[castagnoliK1:], p[castagnoliK1*2:],
+ castagnoliK1/24)
+
+ // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B)
+ crcAB := castagnoliShift(castagnoliSSE42TableK1, crcA) ^ crcB
+ // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C)
+ crc = castagnoliShift(castagnoliSSE42TableK1, crcAB) ^ crcC
+ p = p[castagnoliK1*3:]
}
- return update(crc, IEEETable, p)
+ // Use the simple implementation for what's left.
+ crc = castagnoliSSE42(crc, p)
+ return ^crc
+}
+
+func archAvailableIEEE() bool {
+ return useFastIEEE
+}
+
+var archIeeeTable8 *slicing8Table
+
+func archInitIEEE() {
+ if !useFastIEEE {
+ panic("not available")
+ }
+ // We still use slicing-by-8 for small buffers.
+ archIeeeTable8 = slicingMakeTable(IEEE)
+}
+
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+ if !useFastIEEE {
+ panic("not available")
+ }
+
+ if len(p) >= 64 {
+ left := len(p) & 15
+ do := len(p) - left
+ crc = ^ieeeCLMUL(^crc, p[:do])
+ p = p[do:]
+ }
+ if len(p) == 0 {
+ return crc
+ }
+ return slicingUpdate(crc, archIeeeTable8, p)
}
diff --git a/libgo/go/hash/crc32/crc32_amd64p32.go b/libgo/go/hash/crc32/crc32_amd64p32.go
index 067fbb162f..9d728fc8fe 100644
--- a/libgo/go/hash/crc32/crc32_amd64p32.go
+++ b/libgo/go/hash/crc32/crc32_amd64p32.go
@@ -7,32 +7,35 @@ package crc32
// This file contains the code to call the SSE 4.2 version of the Castagnoli
// CRC.
-// haveSSE42 is defined in crc_amd64p32.s and uses CPUID to test for SSE 4.2
+// haveSSE42 is defined in crc32_amd64p32.s and uses CPUID to test for SSE 4.2
// support.
func haveSSE42() bool
-// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// castagnoliSSE42 is defined in crc32_amd64p32.s and uses the SSE4.2 CRC32
// instruction.
//go:noescape
func castagnoliSSE42(crc uint32, p []byte) uint32
var sse42 = haveSSE42()
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- if sse42 {
- return castagnoliSSE42(crc, p)
- }
- return update(crc, castagnoliTable, p)
+func archAvailableCastagnoli() bool {
+ return sse42
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- // only use slicing-by-8 when input is >= 4KB
- if len(p) >= 4096 {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+func archInitCastagnoli() {
+ if !sse42 {
+ panic("not available")
}
+ // No initialization necessary.
+}
- return update(crc, IEEETable, p)
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !sse42 {
+ panic("not available")
+ }
+ return castagnoliSSE42(crc, p)
}
+
+func archAvailableIEEE() bool { return false }
+func archInitIEEE() { panic("not available") }
+func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") }
diff --git a/libgo/go/hash/crc32/crc32_generic.go b/libgo/go/hash/crc32/crc32_generic.go
index 8fc11a75db..abacbb663d 100644
--- a/libgo/go/hash/crc32/crc32_generic.go
+++ b/libgo/go/hash/crc32/crc32_generic.go
@@ -2,24 +2,88 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build 386 arm arm64 mips64 mips64le ppc64 ppc64le
+// This file contains CRC32 algorithms that are not specific to any architecture
+// and don't use hardware acceleration.
+//
+// The simple (and slow) CRC32 implementation only uses a 256*4 bytes table.
+//
+// The slicing-by-8 algorithm is a faster implementation that uses a bigger
+// table (8*256*4 bytes).
package crc32
-// The file contains the generic version of updateCastagnoli which just calls
-// the software implementation.
+// simpleMakeTable allocates and constructs a Table for the specified
+// polynomial. The table is suitable for use with the simple algorithm
+// (simpleUpdate).
+func simpleMakeTable(poly uint32) *Table {
+ t := new(Table)
+ simplePopulateTable(poly, t)
+ return t
+}
+
+// simplePopulateTable constructs a Table for the specified polynomial, suitable
+// for use with simpleUpdate.
+func simplePopulateTable(poly uint32, t *Table) {
+ for i := 0; i < 256; i++ {
+ crc := uint32(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+}
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- return update(crc, castagnoliTable, p)
+// simpleUpdate uses the simple algorithm to update the CRC, given a table that
+// was previously computed using simpleMakeTable.
+func simpleUpdate(crc uint32, tab *Table, p []byte) uint32 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- // only use slicing-by-8 when input is >= 4KB
- if len(p) >= 4096 {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+// Use slicing-by-8 when payload >= this value.
+const slicing8Cutoff = 16
+
+// slicing8Table is array of 8 Tables, used by the slicing-by-8 algorithm.
+type slicing8Table [8]Table
+
+// slicingMakeTable constructs a slicing8Table for the specified polynomial. The
+// table is suitable for use with the slicing-by-8 algorithm (slicingUpdate).
+func slicingMakeTable(poly uint32) *slicing8Table {
+ t := new(slicing8Table)
+ simplePopulateTable(poly, &t[0])
+ for i := 0; i < 256; i++ {
+ crc := t[0][i]
+ for j := 1; j < 8; j++ {
+ crc = t[0][crc&0xFF] ^ (crc >> 8)
+ t[j][i] = crc
+ }
+ }
+ return t
+}
+
+// slicingUpdate uses the slicing-by-8 algorithm to update the CRC, given a
+// table that was previously computed using slicingMakeTable.
+func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 {
+ if len(p) >= slicing8Cutoff {
+ crc = ^crc
+ for len(p) > 8 {
+ crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+ crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
+ tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
+ tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
+ p = p[8:]
+ }
+ crc = ^crc
+ }
+ if len(p) == 0 {
+ return crc
}
- return update(crc, IEEETable, p)
+ return simpleUpdate(crc, &tab[0], p)
}
diff --git a/libgo/go/hash/crc32/crc32_otherarch.go b/libgo/go/hash/crc32/crc32_otherarch.go
new file mode 100644
index 0000000000..09c3389ea7
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32_otherarch.go
@@ -0,0 +1,15 @@
+// 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.
+
+// -build !amd64,!amd64p32,!s390x
+
+package crc32
+
+func archAvailableIEEE() bool { return false }
+func archInitIEEE() { panic("not available") }
+func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") }
+
+func archAvailableCastagnoli() bool { return false }
+func archInitCastagnoli() { panic("not available") }
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 { panic("not available") }
diff --git a/libgo/go/hash/crc32/crc32_s390x.go b/libgo/go/hash/crc32/crc32_s390x.go
new file mode 100644
index 0000000000..8815c70470
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32_s390x.go
@@ -0,0 +1,91 @@
+// 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 crc32
+
+const (
+ vxMinLen = 64
+ vxAlignMask = 15 // align to 16 bytes
+)
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
+
+// vectorizedCastagnoli implements CRC32 using vector instructions.
+// It is defined in crc32_s390x.s.
+//go:noescape
+func vectorizedCastagnoli(crc uint32, p []byte) uint32
+
+// vectorizedIEEE implements CRC32 using vector instructions.
+// It is defined in crc32_s390x.s.
+//go:noescape
+func vectorizedIEEE(crc uint32, p []byte) uint32
+
+func archAvailableCastagnoli() bool {
+ return hasVX
+}
+
+var archCastagnoliTable8 *slicing8Table
+
+func archInitCastagnoli() {
+ if !hasVX {
+ panic("not available")
+ }
+ // We still use slicing-by-8 for small buffers.
+ archCastagnoliTable8 = slicingMakeTable(Castagnoli)
+}
+
+// archUpdateCastagnoli calculates the checksum of p using
+// vectorizedCastagnoli.
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !hasVX {
+ panic("not available")
+ }
+ // Use vectorized function if data length is above threshold.
+ if len(p) >= vxMinLen {
+ aligned := len(p) & ^vxAlignMask
+ crc = vectorizedCastagnoli(crc, p[:aligned])
+ p = p[aligned:]
+ }
+ if len(p) == 0 {
+ return crc
+ }
+ return slicingUpdate(crc, archCastagnoliTable8, p)
+}
+
+func archAvailableIEEE() bool {
+ return hasVX
+}
+
+var archIeeeTable8 *slicing8Table
+
+func archInitIEEE() {
+ if !hasVX {
+ panic("not available")
+ }
+ // We still use slicing-by-8 for small buffers.
+ archIeeeTable8 = slicingMakeTable(IEEE)
+}
+
+// archUpdateIEEE calculates the checksum of p using vectorizedIEEE.
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+ if !hasVX {
+ panic("not available")
+ }
+ // Use vectorized function if data length is above threshold.
+ if len(p) >= vxMinLen {
+ aligned := len(p) & ^vxAlignMask
+ crc = vectorizedIEEE(crc, p[:aligned])
+ p = p[aligned:]
+ }
+ if len(p) == 0 {
+ return crc
+ }
+ return slicingUpdate(crc, archIeeeTable8, p)
+}
diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go
index 1ca3ac2a27..1356734d50 100644
--- a/libgo/go/hash/crc32/crc32_test.go
+++ b/libgo/go/hash/crc32/crc32_test.go
@@ -5,7 +5,8 @@
package crc32
import (
- "io"
+ "hash"
+ "math/rand"
"testing"
)
@@ -48,82 +49,231 @@ var golden = []test{
{0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"},
}
-func TestGolden(t *testing.T) {
- castagnoliTab := MakeTable(Castagnoli)
+// testGoldenIEEE verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenIEEE(t *testing.T, crcFunc func(b []byte) uint32) {
+ for _, g := range golden {
+ if crc := crcFunc([]byte(g.in)); crc != g.ieee {
+ t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, crc, g.ieee)
+ }
+ }
+}
+// testGoldenCastagnoli verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenCastagnoli(t *testing.T, crcFunc func(b []byte) uint32) {
for _, g := range golden {
- ieee := NewIEEE()
- io.WriteString(ieee, g.in)
- s := ieee.Sum32()
- if s != g.ieee {
- t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+ if crc := crcFunc([]byte(g.in)); crc != g.castagnoli {
+ t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, crc, g.castagnoli)
}
+ }
+}
- castagnoli := New(castagnoliTab)
- io.WriteString(castagnoli, g.in)
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+// testCrossCheck generates random buffers of various lengths and verifies that
+// the two "update" functions return the same result.
+func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte) uint32) {
+ // The AMD64 implementation has some cutoffs at lengths 168*3=504 and
+ // 1344*3=4032. We should make sure lengths around these values are in the
+ // list.
+ lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 100, 128,
+ 500, 501, 502, 503, 504, 505, 512, 1000, 1024, 2000,
+ 4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
+ for _, length := range lengths {
+ p := make([]byte, length)
+ _, _ = rand.Read(p)
+ crcInit := uint32(rand.Int63())
+ crc1 := crcFunc1(crcInit, p)
+ crc2 := crcFunc2(crcInit, p)
+ if crc1 != crc2 {
+ t.Errorf("mismatch: 0x%x vs 0x%x (buffer length %d)", crc1, crc2, length)
}
+ }
+}
- if len(g.in) > 0 {
- // The SSE4.2 implementation of this has code to deal
- // with misaligned data so we ensure that we test that
- // too.
- castagnoli = New(castagnoliTab)
- io.WriteString(castagnoli, g.in[:1])
- io.WriteString(castagnoli, g.in[1:])
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
- }
+// TestSimple tests the simple generic algorithm.
+func TestSimple(t *testing.T) {
+ tab := simpleMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+
+ tab = simpleMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+}
+
+// TestSimple tests the slicing-by-8 algorithm.
+func TestSlicing(t *testing.T) {
+ tab := slicingMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ tab = slicingMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ // Cross-check various polys against the simple algorithm.
+ for _, poly := range []uint32{IEEE, Castagnoli, Koopman, 0xD5828281} {
+ t1 := simpleMakeTable(poly)
+ f1 := func(crc uint32, b []byte) uint32 {
+ return simpleUpdate(crc, t1, b)
+ }
+ t2 := slicingMakeTable(poly)
+ f2 := func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, t2, b)
}
+ testCrossCheck(t, f1, f2)
}
}
-func BenchmarkIEEECrc1KB(b *testing.B) {
- b.SetBytes(1024)
- data := make([]byte, 1024)
- for i := range data {
- data[i] = byte(i)
+func TestArchIEEE(t *testing.T) {
+ if !archAvailableIEEE() {
+ t.Skip("Arch-specific IEEE not available.")
}
- h := NewIEEE()
- in := make([]byte, 0, h.Size())
+ archInitIEEE()
+ slicingTable := slicingMakeTable(IEEE)
+ testCrossCheck(t, archUpdateIEEE, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
+}
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- h.Reset()
- h.Write(data)
- h.Sum(in)
+func TestArchCastagnoli(t *testing.T) {
+ if !archAvailableCastagnoli() {
+ t.Skip("Arch-specific Castagnoli not available.")
}
+ archInitCastagnoli()
+ slicingTable := slicingMakeTable(Castagnoli)
+ testCrossCheck(t, archUpdateCastagnoli, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
}
-func BenchmarkIEEECrc4KB(b *testing.B) {
- b.SetBytes(4096)
- data := make([]byte, 4096)
- for i := range data {
- data[i] = byte(i)
+func TestGolden(t *testing.T) {
+ testGoldenIEEE(t, ChecksumIEEE)
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ ieee := NewIEEE()
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ ieee.Write(b[:d])
+ ieee.Write(b[d:])
+ return ieee.Sum32()
+ })
}
- h := NewIEEE()
- in := make([]byte, 0, h.Size())
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- h.Reset()
- h.Write(data)
- h.Sum(in)
+ castagnoliTab := MakeTable(Castagnoli)
+ if castagnoliTab == nil {
+ t.Errorf("nil Castagnoli Table")
}
+
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ castagnoli.Write(b)
+ return castagnoli.Sum32()
+ })
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ castagnoli.Write(b[:d])
+ castagnoli.Write(b[d:])
+ return castagnoli.Sum32()
+ })
+ }
+}
+
+func BenchmarkIEEECrc40B(b *testing.B) {
+ benchmark(b, NewIEEE(), 40, 0)
+}
+
+func BenchmarkIEEECrc1KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 1<<10, 0)
+}
+
+func BenchmarkIEEECrc4KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 4<<10, 0)
+}
+
+func BenchmarkIEEECrc32KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 32<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc15B(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 15, 0)
+}
+
+func BenchmarkCastagnoliCrc15BMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 15, 1)
+}
+
+func BenchmarkCastagnoliCrc40B(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 40, 0)
+}
+
+func BenchmarkCastagnoliCrc40BMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 40, 1)
+}
+
+func BenchmarkCastagnoliCrc512(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 512, 0)
+}
+
+func BenchmarkCastagnoliCrc512Misaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 512, 1)
}
func BenchmarkCastagnoliCrc1KB(b *testing.B) {
- b.SetBytes(1024)
- data := make([]byte, 1024)
+ benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc1KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 1)
+}
+
+func BenchmarkCastagnoliCrc4KB(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc4KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 1)
+}
+
+func BenchmarkCastagnoliCrc32KB(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc32KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 1)
+}
+
+func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
+ b.SetBytes(n)
+ data := make([]byte, n+alignment)
+ data = data[alignment:]
for i := range data {
data[i] = byte(i)
}
- h := New(MakeTable(Castagnoli))
in := make([]byte, 0, h.Size())
+ // Warm up
+ h.Reset()
+ h.Write(data)
+ h.Sum(in)
+
b.ResetTimer()
for i := 0; i < b.N; i++ {
h.Reset()
diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go
index 54cc56055e..e939c2a06a 100644
--- a/libgo/go/hash/crc64/crc64.go
+++ b/libgo/go/hash/crc64/crc64.go
@@ -24,9 +24,25 @@ const (
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint64
+var (
+ slicing8TableISO = makeSlicingBy8Table(makeTable(ISO))
+ slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
+)
+
// MakeTable returns a Table constructed from the specified polynomial.
// The contents of this Table must not be modified.
func MakeTable(poly uint64) *Table {
+ switch poly {
+ case ISO:
+ return &slicing8TableISO[0]
+ case ECMA:
+ return &slicing8TableECMA[0]
+ default:
+ return makeTable(poly)
+ }
+}
+
+func makeTable(poly uint64) *Table {
t := new(Table)
for i := 0; i < 256; i++ {
crc := uint64(i)
@@ -42,6 +58,19 @@ func MakeTable(poly uint64) *Table {
return t
}
+func makeSlicingBy8Table(t *Table) *[8]Table {
+ var helperTable [8]Table
+ helperTable[0] = *t
+ for i := 0; i < 256; i++ {
+ crc := t[i]
+ for j := 1; j < 8; j++ {
+ crc = t[crc&0xff] ^ (crc >> 8)
+ helperTable[j][i] = crc
+ }
+ }
+ return &helperTable
+}
+
// digest represents the partial evaluation of a checksum.
type digest struct {
crc uint64
@@ -61,6 +90,35 @@ func (d *digest) Reset() { d.crc = 0 }
func update(crc uint64, tab *Table, p []byte) uint64 {
crc = ^crc
+ // Table comparison is somewhat expensive, so avoid it for small sizes
+ for len(p) >= 64 {
+ var helperTable *[8]Table
+ if *tab == slicing8TableECMA[0] {
+ helperTable = slicing8TableECMA
+ } else if *tab == slicing8TableISO[0] {
+ helperTable = slicing8TableISO
+ // For smaller sizes creating extended table takes too much time
+ } else if len(p) > 16384 {
+ helperTable = makeSlicingBy8Table(tab)
+ } else {
+ break
+ }
+ // Update using slicing-by-8
+ for len(p) > 8 {
+ crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
+ uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
+ crc = helperTable[7][crc&0xff] ^
+ helperTable[6][(crc>>8)&0xff] ^
+ helperTable[5][(crc>>16)&0xff] ^
+ helperTable[4][(crc>>24)&0xff] ^
+ helperTable[3][(crc>>32)&0xff] ^
+ helperTable[2][(crc>>40)&0xff] ^
+ helperTable[1][(crc>>48)&0xff] ^
+ helperTable[0][crc>>56]
+ p = p[8:]
+ }
+ }
+ // For reminders or small sizes
for _, v := range p {
crc = tab[byte(crc)^v] ^ (crc >> 8)
}
diff --git a/libgo/go/hash/crc64/crc64_test.go b/libgo/go/hash/crc64/crc64_test.go
index 81a87b56e3..480b150e13 100644
--- a/libgo/go/hash/crc64/crc64_test.go
+++ b/libgo/go/hash/crc64/crc64_test.go
@@ -10,66 +10,75 @@ import (
)
type test struct {
- out uint64
- in string
+ outISO uint64
+ outECMA uint64
+ in string
}
var golden = []test{
- {0x0, ""},
- {0x3420000000000000, "a"},
- {0x36c4200000000000, "ab"},
- {0x3776c42000000000, "abc"},
- {0x336776c420000000, "abcd"},
- {0x32d36776c4200000, "abcde"},
- {0x3002d36776c42000, "abcdef"},
- {0x31b002d36776c420, "abcdefg"},
- {0xe21b002d36776c4, "abcdefgh"},
- {0x8b6e21b002d36776, "abcdefghi"},
- {0x7f5b6e21b002d367, "abcdefghij"},
- {0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
- {0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
- {0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
- {0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- {0x3e05b21c7a4dc4da, "The days of the digital watch are numbered. -Tom Stoppard"},
- {0x5255866ad6ef28a6, "Nepal premier won't resign."},
- {0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
- {0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
- {0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- {0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- {0xf3553c65dacdadd2, "size: a.out: bad magic"},
- {0x9d5e034087a676b9, "The major problem is with sendmail. -Mark Horton"},
- {0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- {0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
- {0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
- {0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
- {0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
- {0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- {0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- {0xdb6efff26aa94946, "How can you write a big system without C++? -Paul Glick"},
+ {0x0, 0x0, ""},
+ {0x3420000000000000, 0x330284772e652b05, "a"},
+ {0x36c4200000000000, 0xbc6573200e84b046, "ab"},
+ {0x3776c42000000000, 0x2cd8094a1a277627, "abc"},
+ {0x336776c420000000, 0x3c9d28596e5960ba, "abcd"},
+ {0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde"},
+ {0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef"},
+ {0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg"},
+ {0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh"},
+ {0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi"},
+ {0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij"},
+ {0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old."},
+ {0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last."},
+ {0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole."},
+ {0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign."},
+ {0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program."},
+ {0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size: a.out: bad magic"},
+ {0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail. -Mark Horton"},
+ {0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you."},
+ {0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!"},
+ {0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++? -Paul Glick"},
+ {0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system."},
}
-var tab = MakeTable(ISO)
-
func TestGolden(t *testing.T) {
+ tabISO := MakeTable(ISO)
+ tabECMA := MakeTable(ECMA)
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := New(tab)
+ c := New(tabISO)
io.WriteString(c, g.in)
s := c.Sum64()
- if s != g.out {
- t.Errorf("crc64(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ if s != g.outISO {
+ t.Errorf("ISO crc64(%s) = 0x%x want 0x%x", g.in, s, g.outISO)
+ t.FailNow()
+ }
+ c = New(tabECMA)
+ io.WriteString(c, g.in)
+ s = c.Sum64()
+ if s != g.outECMA {
+ t.Errorf("ECMA crc64(%s) = 0x%x want 0x%x", g.in, s, g.outECMA)
t.FailNow()
}
}
}
-func BenchmarkCrc64KB(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(tab)
+ h := New(MakeTable(poly))
in := make([]byte, 0, h.Size())
b.ResetTimer()
@@ -79,3 +88,24 @@ func BenchmarkCrc64KB(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)
+ })
+}
diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go
index ab6fd1c7b4..8dd1f4ad2f 100644
--- a/libgo/go/html/escape.go
+++ b/libgo/go/html/escape.go
@@ -10,10 +10,6 @@ import (
"unicode/utf8"
)
-type writer interface {
- WriteString(string) (int, error)
-}
-
// These replacements permit compatibility with old numeric entities that
// assumed Windows-1252 encoding.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
@@ -185,7 +181,7 @@ func EscapeString(s string) string {
// UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a
// larger range of entities than EscapeString escapes. For example, "&aacute;"
-// unescapes to "á", as does "&#225;" and "&xE1;".
+// unescapes to "á", as does "&#225;" and "&#xE1;".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true.
func UnescapeString(s string) string {
diff --git a/libgo/go/html/template/clone_test.go b/libgo/go/html/template/clone_test.go
index d7c62fa399..b500715ac6 100644
--- a/libgo/go/html/template/clone_test.go
+++ b/libgo/go/html/template/clone_test.go
@@ -7,7 +7,9 @@ package template
import (
"bytes"
"errors"
+ "fmt"
"io/ioutil"
+ "sync"
"testing"
"text/template/parse"
)
@@ -194,3 +196,69 @@ func TestFuncMapWorksAfterClone(t *testing.T) {
t.Errorf("clone error message mismatch want %q got %q", wantErr, gotErr)
}
}
+
+// https://golang.org/issue/16101
+func TestTemplateCloneExecuteRace(t *testing.T) {
+ const (
+ input = `<title>{{block "a" .}}a{{end}}</title><body>{{block "b" .}}b{{end}}<body>`
+ overlay = `{{define "b"}}A{{end}}`
+ )
+ outer := Must(New("outer").Parse(input))
+ tmpl := Must(Must(outer.Clone()).Parse(overlay))
+
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ if err := tmpl.Execute(ioutil.Discard, "data"); err != nil {
+ panic(err)
+ }
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func TestTemplateCloneLookup(t *testing.T) {
+ // Template.escape makes an assumption that the template associated
+ // with t.Name() is t. Check that this holds.
+ tmpl := Must(New("x").Parse("a"))
+ tmpl = Must(tmpl.Clone())
+ if tmpl.Lookup(tmpl.Name()) != tmpl {
+ t.Error("after Clone, tmpl.Lookup(tmpl.Name()) != tmpl")
+ }
+}
+
+func TestCloneGrowth(t *testing.T) {
+ tmpl := Must(New("root").Parse(`<title>{{block "B". }}Arg{{end}}</title>`))
+ tmpl = Must(tmpl.Clone())
+ Must(tmpl.Parse(`{{define "B"}}Text{{end}}`))
+ for i := 0; i < 10; i++ {
+ tmpl.Execute(ioutil.Discard, nil)
+ }
+ if len(tmpl.DefinedTemplates()) > 200 {
+ t.Fatalf("too many templates: %v", len(tmpl.DefinedTemplates()))
+ }
+}
+
+// https://golang.org/issue/17735
+func TestCloneRedefinedName(t *testing.T) {
+ const base = `
+{{ define "a" -}}<title>{{ template "b" . -}}</title>{{ end -}}
+{{ define "b" }}{{ end -}}
+`
+ const page = `{{ template "a" . }}`
+
+ t1 := Must(New("a").Parse(base))
+
+ for i := 0; i < 2; i++ {
+ t2 := Must(t1.Clone())
+ t2 = Must(t2.New(fmt.Sprintf("%d", i)).Parse(page))
+ err := t2.Execute(ioutil.Discard, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go
index 3715ed5c93..2e14bd1231 100644
--- a/libgo/go/html/template/content.go
+++ b/libgo/go/html/template/content.go
@@ -18,16 +18,28 @@ type (
// 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
// See http://www.w3.org/TR/css3-syntax/#parsing and
// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
CSS string
// HTML encapsulates a known safe HTML document fragment.
// It should not be used for HTML from a third-party, or HTML with
// unclosed tags or comments. The outputs of a sound HTML sanitizer
// and a template escaped by this package are fine for use with HTML.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
HTML string
// HTMLAttr encapsulates an HTML attribute from a trusted source,
// for example, ` dir="ltr"`.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
HTMLAttr string
// JS encapsulates a known safe EcmaScript5 Expression, for example,
@@ -37,6 +49,15 @@ type (
// statement/expression ambiguity as when passing an expression like
// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
// valid Program with a very different meaning.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
+ //
+ // Using JS to include valid but untrusted JSON is not safe.
+ // A safe alternative is to parse the JSON with json.Unmarshal and then
+ // pass the resultant object into the template, where it will be
+ // converted to sanitized JSON when presented in a JavaScript context.
JS string
// JSStr encapsulates a sequence of characters meant to be embedded
@@ -46,6 +67,10 @@ type (
// | EscapeSequence
// Note that LineContinuations are not allowed.
// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
JSStr string
// URL encapsulates a known safe URL or URL substring (see RFC 3986).
@@ -53,6 +78,10 @@ type (
// from a trusted source should go in the page, but by default dynamic
// `javascript:` URLs are filtered out since they are a frequently
// exploited injection vector.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
URL string
)
diff --git a/libgo/go/html/template/content_test.go b/libgo/go/html/template/content_test.go
index e698328693..0b4365c83b 100644
--- a/libgo/go/html/template/content_test.go
+++ b/libgo/go/html/template/content_test.go
@@ -162,6 +162,47 @@ func TestTypedContent(t *testing.T) {
},
},
{
+ `<script type="text/javascript">alert("{{.}}")</script>`,
+ []string{
+ `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+ `a[href =~ \x22\/\/example.com\x22]#foo`,
+ `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+ ` dir=\x22ltr\x22`,
+ `c \x26\x26 alert(\x22Hello, World!\x22);`,
+ // Escape sequence not over-escaped.
+ `Hello, World \x26 O\x27Reilly\x21`,
+ `greeting=H%69\x26addressee=(World)`,
+ },
+ },
+ {
+ `<script type="text/javascript">alert({{.}})</script>`,
+ []string{
+ `"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
+ `"a[href =~ \"//example.com\"]#foo"`,
+ `"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
+ `" dir=\"ltr\""`,
+ // Not escaped.
+ `c && alert("Hello, World!");`,
+ // Escape sequence not over-escaped.
+ `"Hello, World & O'Reilly\x21"`,
+ `"greeting=H%69\u0026addressee=(World)"`,
+ },
+ },
+ {
+ // Not treated as JS. The output is same as for <div>{{.}}</div>
+ `<script type="text/template">{{.}}</script>`,
+ []string{
+ `&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
+ `a[href =~ &#34;//example.com&#34;]#foo`,
+ // Not escaped.
+ `Hello, <b>World</b> &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ `Hello, World &amp; O&#39;Reilly\x21`,
+ `greeting=H%69&amp;addressee=(World)`,
+ },
+ },
+ {
`<button onclick='alert("{{.}}")'>`,
[]string{
`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
diff --git a/libgo/go/html/template/context.go b/libgo/go/html/template/context.go
index c90fc1fda5..37a3faf88b 100644
--- a/libgo/go/html/template/context.go
+++ b/libgo/go/html/template/context.go
@@ -285,7 +285,8 @@ type element uint8
const (
// elementNone occurs outside a special tag or special element body.
elementNone element = iota
- // elementScript corresponds to the raw text <script> element.
+ // elementScript corresponds to the raw text <script> element
+ // with JS MIME type or no type attribute.
elementScript
// elementStyle corresponds to the raw text <style> element.
elementStyle
@@ -319,6 +320,8 @@ const (
attrNone attr = iota
// attrScript corresponds to an event handler attribute.
attrScript
+ // attrScriptType corresponds to the type attribute in script HTML element
+ attrScriptType
// attrStyle corresponds to the style attribute whose value is CSS.
attrStyle
// attrURL corresponds to an attribute whose value is a URL.
@@ -326,10 +329,11 @@ const (
)
var attrNames = [...]string{
- attrNone: "attrNone",
- attrScript: "attrScript",
- attrStyle: "attrStyle",
- attrURL: "attrURL",
+ attrNone: "attrNone",
+ attrScript: "attrScript",
+ attrScriptType: "attrScriptType",
+ attrStyle: "attrStyle",
+ attrURL: "attrURL",
}
func (a attr) String() string {
diff --git a/libgo/go/html/template/css.go b/libgo/go/html/template/css.go
index 318464835f..9154d8636d 100644
--- a/libgo/go/html/template/css.go
+++ b/libgo/go/html/template/css.go
@@ -243,13 +243,13 @@ func cssValueFilter(args ...interface{}) string {
return filterFailsafe
}
default:
- if c < 0x80 && isCSSNmchar(rune(c)) {
+ if c < utf8.RuneSelf && isCSSNmchar(rune(c)) {
id = append(id, c)
}
}
}
id = bytes.ToLower(id)
- if bytes.Index(id, expressionBytes) != -1 || bytes.Index(id, mozBindingBytes) != -1 {
+ if bytes.Contains(id, expressionBytes) || bytes.Contains(id, mozBindingBytes) {
return filterFailsafe
}
return string(b)
diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go
index 1827403aa3..cb89812743 100644
--- a/libgo/go/html/template/doc.go
+++ b/libgo/go/html/template/doc.go
@@ -129,7 +129,7 @@ then the template output is
<script>var pair = {"A": "foo", "B": "bar"};</script>
-See package json to understand how non-string content is marshalled for
+See package json to understand how non-string content is marshaled for
embedding in JavaScript contexts.
@@ -166,7 +166,7 @@ that would have been produced if {{.}} was a regular string.
Security Model
-http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
+https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
This package assumes that template authors are trusted, that Execute's data
parameter is not, and seeks to preserve the properties below in the face
diff --git a/libgo/go/html/template/error.go b/libgo/go/html/template/error.go
index 8f99e1b962..cbcaf92e4a 100644
--- a/libgo/go/html/template/error.go
+++ b/libgo/go/html/template/error.go
@@ -44,7 +44,7 @@ const (
// OK indicates the lack of an error.
OK ErrorCode = iota
- // ErrAmbigContext: "... appears in an ambiguous URL context"
+ // ErrAmbigContext: "... appears in an ambiguous context within a URL"
// Example:
// <a href="
// {{if .C}}
@@ -164,7 +164,7 @@ const (
// different context than an earlier pass, there is no single context.
// In the example, there is missing a quote, so it is not clear
// whether {{.}} is meant to be inside a JS string or in a JS value
- // context. The second iteration would produce something like
+ // context. The second iteration would produce something like
//
// <script>var x = ['firstValue,'secondValue]</script>
ErrRangeLoopReentry
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index 3c18340547..0e7d2be143 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -15,8 +15,8 @@ import (
// escapeTemplate rewrites the named template, which must be
// associated with t, to guarantee that the output of any of the named
-// templates is properly escaped. If no error is returned, then the named templates have
-// been modified. Otherwise the named templates have been rendered
+// templates is properly escaped. If no error is returned, then the named templates have
+// been modified. Otherwise the named templates have been rendered
// unusable.
func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
e := newEscaper(tmpl)
@@ -46,30 +46,30 @@ func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
// funcMap maps command names to functions that render their inputs safe.
var funcMap = template.FuncMap{
- "html_template_attrescaper": attrEscaper,
- "html_template_commentescaper": commentEscaper,
- "html_template_cssescaper": cssEscaper,
- "html_template_cssvaluefilter": cssValueFilter,
- "html_template_htmlnamefilter": htmlNameFilter,
- "html_template_htmlescaper": htmlEscaper,
- "html_template_jsregexpescaper": jsRegexpEscaper,
- "html_template_jsstrescaper": jsStrEscaper,
- "html_template_jsvalescaper": jsValEscaper,
- "html_template_nospaceescaper": htmlNospaceEscaper,
- "html_template_rcdataescaper": rcdataEscaper,
- "html_template_urlescaper": urlEscaper,
- "html_template_urlfilter": urlFilter,
- "html_template_urlnormalizer": urlNormalizer,
+ "_html_template_attrescaper": attrEscaper,
+ "_html_template_commentescaper": commentEscaper,
+ "_html_template_cssescaper": cssEscaper,
+ "_html_template_cssvaluefilter": cssValueFilter,
+ "_html_template_htmlnamefilter": htmlNameFilter,
+ "_html_template_htmlescaper": htmlEscaper,
+ "_html_template_jsregexpescaper": jsRegexpEscaper,
+ "_html_template_jsstrescaper": jsStrEscaper,
+ "_html_template_jsvalescaper": jsValEscaper,
+ "_html_template_nospaceescaper": htmlNospaceEscaper,
+ "_html_template_rcdataescaper": rcdataEscaper,
+ "_html_template_urlescaper": urlEscaper,
+ "_html_template_urlfilter": urlFilter,
+ "_html_template_urlnormalizer": urlNormalizer,
}
// equivEscapers matches contextual escapers to equivalent template builtins.
var equivEscapers = map[string]string{
- "html_template_attrescaper": "html",
- "html_template_htmlescaper": "html",
- "html_template_nospaceescaper": "html",
- "html_template_rcdataescaper": "html",
- "html_template_urlescaper": "urlquery",
- "html_template_urlnormalizer": "urlquery",
+ "_html_template_attrescaper": "html",
+ "_html_template_htmlescaper": "html",
+ "_html_template_nospaceescaper": "html",
+ "_html_template_rcdataescaper": "html",
+ "_html_template_urlescaper": "urlquery",
+ "_html_template_urlnormalizer": "urlquery",
}
// escaper collects type inferences about templates and changes needed to make
@@ -147,47 +147,47 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:
switch c.urlPart {
case urlPartNone:
- s = append(s, "html_template_urlfilter")
+ s = append(s, "_html_template_urlfilter")
fallthrough
case urlPartPreQuery:
switch c.state {
case stateCSSDqStr, stateCSSSqStr:
- s = append(s, "html_template_cssescaper")
+ s = append(s, "_html_template_cssescaper")
default:
- s = append(s, "html_template_urlnormalizer")
+ s = append(s, "_html_template_urlnormalizer")
}
case urlPartQueryOrFrag:
- s = append(s, "html_template_urlescaper")
+ s = append(s, "_html_template_urlescaper")
case urlPartUnknown:
return context{
state: stateError,
- err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous URL context", n),
+ err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous context within a URL", n),
}
default:
panic(c.urlPart.String())
}
case stateJS:
- s = append(s, "html_template_jsvalescaper")
+ s = append(s, "_html_template_jsvalescaper")
// A slash after a value starts a div operator.
c.jsCtx = jsCtxDivOp
case stateJSDqStr, stateJSSqStr:
- s = append(s, "html_template_jsstrescaper")
+ s = append(s, "_html_template_jsstrescaper")
case stateJSRegexp:
- s = append(s, "html_template_jsregexpescaper")
+ s = append(s, "_html_template_jsregexpescaper")
case stateCSS:
- s = append(s, "html_template_cssvaluefilter")
+ s = append(s, "_html_template_cssvaluefilter")
case stateText:
- s = append(s, "html_template_htmlescaper")
+ s = append(s, "_html_template_htmlescaper")
case stateRCDATA:
- s = append(s, "html_template_rcdataescaper")
+ s = append(s, "_html_template_rcdataescaper")
case stateAttr:
// Handled below in delim check.
case stateAttrName, stateTag:
c.state = stateAttrName
- s = append(s, "html_template_htmlnamefilter")
+ s = append(s, "_html_template_htmlnamefilter")
default:
if isComment(c.state) {
- s = append(s, "html_template_commentescaper")
+ s = append(s, "_html_template_commentescaper")
} else {
panic("unexpected state " + c.state.String())
}
@@ -196,9 +196,9 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case delimNone:
// No extra-escaping needed for raw text content.
case delimSpaceOrTagEnd:
- s = append(s, "html_template_nospaceescaper")
+ s = append(s, "_html_template_nospaceescaper")
default:
- s = append(s, "html_template_attrescaper")
+ s = append(s, "_html_template_attrescaper")
}
e.editActionNode(n, s)
return c
@@ -276,22 +276,22 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
// for all x.
var redundantFuncs = map[string]map[string]bool{
- "html_template_commentescaper": {
- "html_template_attrescaper": true,
- "html_template_nospaceescaper": true,
- "html_template_htmlescaper": true,
+ "_html_template_commentescaper": {
+ "_html_template_attrescaper": true,
+ "_html_template_nospaceescaper": true,
+ "_html_template_htmlescaper": true,
},
- "html_template_cssescaper": {
- "html_template_attrescaper": true,
+ "_html_template_cssescaper": {
+ "_html_template_attrescaper": true,
},
- "html_template_jsregexpescaper": {
- "html_template_attrescaper": true,
+ "_html_template_jsregexpescaper": {
+ "_html_template_attrescaper": true,
},
- "html_template_jsstrescaper": {
- "html_template_attrescaper": true,
+ "_html_template_jsstrescaper": {
+ "_html_template_attrescaper": true,
},
- "html_template_urlescaper": {
- "html_template_urlnormalizer": true,
+ "_html_template_urlescaper": {
+ "_html_template_urlnormalizer": true,
},
}
@@ -673,6 +673,8 @@ func contextAfterText(c context, s []byte) (context, int) {
return transitionFunc[c.state](c, s[:i])
}
+ // We are at the beginning of an attribute value.
+
i := bytes.IndexAny(s, delimEnds[c.delim])
if i == -1 {
i = len(s)
@@ -703,13 +705,21 @@ func contextAfterText(c context, s []byte) (context, int) {
}
return c, len(s)
}
+
+ element := c.element
+
+ // If this is a non-JS "type" attribute inside "script" tag, do not treat the contents as JS.
+ if c.state == stateAttr && c.element == elementScript && c.attr == attrScriptType && !isJSType(string(s[:i])) {
+ element = elementNone
+ }
+
if c.delim != delimSpaceOrTagEnd {
// Consume any quote.
i++
}
// On exiting an attribute, we discard all state information
// except the state and element.
- return context{state: stateTag, element: c.element}, i
+ return context{state: stateTag, element: element}, i
}
// editActionNode records a change to an action pipeline for later commit.
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index 707394e3b0..f6ace496e7 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -903,7 +903,7 @@ func TestErrors(t *testing.T) {
},
{
`<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`,
- "z:1:47: {{.H}} appears in an ambiguous URL context",
+ "z:1:47: {{.H}} appears in an ambiguous context within a URL",
},
{
`<a onclick="alert('Hello \`,
@@ -990,7 +990,7 @@ func TestErrors(t *testing.T) {
}
continue
}
- if strings.Index(got, test.err) == -1 {
+ if !strings.Contains(got, test.err) {
t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err)
continue
}
@@ -1365,6 +1365,10 @@ func TestEscapeText(t *testing.T) {
context{state: stateTag, element: elementScript},
},
{
+ `<script>`,
+ context{state: stateJS, jsCtx: jsCtxRegexp, element: elementScript},
+ },
+ {
`<script>foo`,
context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
},
@@ -1389,6 +1393,14 @@ func TestEscapeText(t *testing.T) {
context{state: stateText},
},
{
+ `<script type="text/template">`,
+ context{state: stateText},
+ },
+ {
+ `<script type="notjs">`,
+ context{state: stateText},
+ },
+ {
`<Script>`,
context{state: stateJS, element: elementScript},
},
diff --git a/libgo/go/html/template/examplefiles_test.go b/libgo/go/html/template/examplefiles_test.go
new file mode 100644
index 0000000000..ffca8d5a78
--- /dev/null
+++ b/libgo/go/html/template/examplefiles_test.go
@@ -0,0 +1,228 @@
+// 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 template_test
+
+import (
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "text/template"
+)
+
+// templateFile defines the contents of a template to be stored in a file, for testing.
+type templateFile struct {
+ name string
+ contents string
+}
+
+func createTestDir(files []templateFile) string {
+ dir, err := ioutil.TempDir("", "template")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, file := range files {
+ f, err := os.Create(filepath.Join(dir, file.name))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ _, err = io.WriteString(f, file.contents)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ return dir
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// Here we demonstrate loading a set of templates from a directory.
+func ExampleTemplate_glob() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T0.tmpl is a plain template file that just invokes T1.
+ {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
+ // T1.tmpl defines a template, T1 that invokes T2.
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ // T2.tmpl defines a template T2.
+ {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // T0.tmpl is the first name matched, so it becomes the starting template,
+ // the value returned by ParseGlob.
+ tmpl := template.Must(template.ParseGlob(pattern))
+
+ err := tmpl.Execute(os.Stdout, nil)
+ if err != nil {
+ log.Fatalf("template execution: %s", err)
+ }
+ // Output:
+ // T0 invokes T1: (T1 invokes T2: (This is T2))
+}
+
+// Here we demonstrate loading a set of templates from files in different directories
+func ExampleTemplate_parsefiles() {
+ // Here we create different temporary directories and populate them with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir1 := createTestDir([]templateFile{
+ // T1.tmpl is a plain template file that just invokes T2.
+ {"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`},
+ })
+
+ dir2 := createTestDir([]templateFile{
+ // T2.tmpl defines a template T2.
+ {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+ })
+
+ // Clean up after the test; another quirk of running as an example.
+ defer func(dirs ...string) {
+ for _, dir := range dirs {
+ os.RemoveAll(dir)
+ }
+ }(dir1, dir2)
+
+ // Here starts the example proper.
+ // Let's just parse only dir1/T0 and dir2/T2
+ paths := []string{
+ filepath.Join(dir1, "T1.tmpl"),
+ filepath.Join(dir2, "T2.tmpl"),
+ }
+ tmpl := template.Must(template.ParseFiles(paths...))
+
+ err := tmpl.Execute(os.Stdout, nil)
+ if err != nil {
+ log.Fatalf("template execution: %s", err)
+ }
+ // Output:
+ // T1 invokes T2: (This is T2)
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// This example demonstrates one way to share some templates
+// and use them in different contexts. In this variant we add multiple driver
+// templates by hand to an existing bundle of templates.
+func ExampleTemplate_helpers() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T1.tmpl defines a template, T1 that invokes T2.
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ // T2.tmpl defines a template T2.
+ {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // Load the helpers.
+ templates := template.Must(template.ParseGlob(pattern))
+ // Add one driver template to the bunch; we do this with an explicit template definition.
+ _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
+ if err != nil {
+ log.Fatal("parsing driver1: ", err)
+ }
+ // Add another driver template.
+ _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
+ if err != nil {
+ log.Fatal("parsing driver2: ", err)
+ }
+ // We load all the templates before execution. This package does not require
+ // that behavior but html/template's escaping does, so it's a good habit.
+ err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
+ if err != nil {
+ log.Fatalf("driver1 execution: %s", err)
+ }
+ err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
+ if err != nil {
+ log.Fatalf("driver2 execution: %s", err)
+ }
+ // Output:
+ // Driver 1 calls T1: (T1 invokes T2: (This is T2))
+ // Driver 2 calls T2: (This is T2)
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// This example demonstrates how to use one group of driver
+// templates with distinct sets of helper templates.
+func ExampleTemplate_share() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T0.tmpl is a plain template file that just invokes T1.
+ {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
+ // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // Load the drivers.
+ drivers := template.Must(template.ParseGlob(pattern))
+
+ // We must define an implementation of the T2 template. First we clone
+ // the drivers, then add a definition of T2 to the template name space.
+
+ // 1. Clone the helper set to create a new name space from which to run them.
+ first, err := drivers.Clone()
+ if err != nil {
+ log.Fatal("cloning helpers: ", err)
+ }
+ // 2. Define T2, version A, and parse it.
+ _, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
+ if err != nil {
+ log.Fatal("parsing T2: ", err)
+ }
+
+ // Now repeat the whole thing, using a different version of T2.
+ // 1. Clone the drivers.
+ second, err := drivers.Clone()
+ if err != nil {
+ log.Fatal("cloning drivers: ", err)
+ }
+ // 2. Define T2, version B, and parse it.
+ _, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
+ if err != nil {
+ log.Fatal("parsing T2: ", err)
+ }
+
+ // Execute the templates in the reverse order to verify the
+ // first is unaffected by the second.
+ err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
+ if err != nil {
+ log.Fatalf("second execution: %s", err)
+ }
+ err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
+ if err != nil {
+ log.Fatalf("first: execution: %s", err)
+ }
+
+ // Output:
+ // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
+ // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
+}
diff --git a/libgo/go/html/template/js.go b/libgo/go/html/template/js.go
index f6d166b311..6434fa3be6 100644
--- a/libgo/go/html/template/js.go
+++ b/libgo/go/html/template/js.go
@@ -162,14 +162,14 @@ func jsValEscaper(args ...interface{}) string {
// a division operator it is not turned into a line comment:
// x/{{y}}
// turning into
- // x//* error marshalling y:
+ // x//* error marshaling y:
// second line of error message */null
return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1))
}
// TODO: maybe post-process output to prevent it from containing
// "<!--", "-->", "<![CDATA[", "]]>", or "</script"
- // in case custom marshallers produce output containing those.
+ // in case custom marshalers produce output containing those.
// TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
if len(b) == 0 {
@@ -362,3 +362,43 @@ func isJSIdentPart(r rune) bool {
}
return false
}
+
+// isJSType returns true if the given MIME type should be considered JavaScript.
+//
+// It is used to determine whether a script tag with a type attribute is a javascript container.
+func isJSType(mimeType string) bool {
+ // per
+ // https://www.w3.org/TR/html5/scripting-1.html#attr-script-type
+ // https://tools.ietf.org/html/rfc7231#section-3.1.1
+ // https://tools.ietf.org/html/rfc4329#section-3
+ // https://www.ietf.org/rfc/rfc4627.txt
+
+ // discard parameters
+ if i := strings.Index(mimeType, ";"); i >= 0 {
+ mimeType = mimeType[:i]
+ }
+ mimeType = strings.TrimSpace(mimeType)
+ switch mimeType {
+ case
+ "application/ecmascript",
+ "application/javascript",
+ "application/json",
+ "application/x-ecmascript",
+ "application/x-javascript",
+ "text/ecmascript",
+ "text/javascript",
+ "text/javascript1.0",
+ "text/javascript1.1",
+ "text/javascript1.2",
+ "text/javascript1.3",
+ "text/javascript1.4",
+ "text/javascript1.5",
+ "text/jscript",
+ "text/livescript",
+ "text/x-ecmascript",
+ "text/x-javascript":
+ return true
+ default:
+ return false
+ }
+}
diff --git a/libgo/go/html/template/js_test.go b/libgo/go/html/template/js_test.go
index 7af7997de9..7484f60b54 100644
--- a/libgo/go/html/template/js_test.go
+++ b/libgo/go/html/template/js_test.go
@@ -332,6 +332,25 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
}
}
+func TestIsJsMimeType(t *testing.T) {
+ tests := []struct {
+ in string
+ out bool
+ }{
+ {"application/javascript;version=1.8", true},
+ {"application/javascript;version=1.8;foo=bar", true},
+ {"application/javascript/version=1.8", false},
+ {"text/javascript", true},
+ {"application/json", true},
+ }
+
+ for _, test := range tests {
+ if isJSType(test.in) != test.out {
+ t.Errorf("isJSType(%q) = %v, want %v", test.in, !test.out, test.out)
+ }
+ }
+}
+
func BenchmarkJSValEscaperWithNum(b *testing.B) {
for i := 0; i < b.N; i++ {
jsValEscaper(3.141592654)
diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go
index 96ab268a7f..b313a6b104 100644
--- a/libgo/go/html/template/template.go
+++ b/libgo/go/html/template/template.go
@@ -33,8 +33,9 @@ var escapeOK = fmt.Errorf("template escaped correctly")
// nameSpace is the data structure shared by all templates in an association.
type nameSpace struct {
- mu sync.Mutex
- set map[string]*Template
+ mu sync.Mutex
+ set map[string]*Template
+ escaped bool
}
// Templates returns a slice of the templates associated with t, including t
@@ -74,13 +75,28 @@ func (t *Template) Option(opt ...string) *Template {
return t
}
+// checkCanParse checks whether it is OK to parse templates.
+// If not, it returns an error.
+func (t *Template) checkCanParse() error {
+ if t == nil {
+ return nil
+ }
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.nameSpace.escaped {
+ return fmt.Errorf("html/template: cannot Parse after Execute")
+ }
+ return nil
+}
+
// escape escapes all associated templates.
func (t *Template) escape() error {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
+ t.nameSpace.escaped = true
if t.escapeErr == nil {
if t.Tree == nil {
- return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
+ return fmt.Errorf("template: %q is an incomplete or empty template", t.Name())
}
if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
return err
@@ -124,6 +140,7 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
+ t.nameSpace.escaped = true
tmpl = t.set[name]
if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
@@ -150,22 +167,27 @@ func (t *Template) DefinedTemplates() string {
return t.text.DefinedTemplates()
}
-// Parse parses a string into a template. Nested template definitions
-// will be associated with the top-level template t. Parse may be
-// called multiple times to parse definitions of templates to associate
-// with t. It is an error if a resulting template is non-empty (contains
-// content other than template definitions) and would replace a
-// non-empty template with the same name. (In multiple calls to Parse
-// with the same receiver template, only one call can contain text
-// other than space, comments, and template definitions.)
-func (t *Template) Parse(src string) (*Template, error) {
- t.nameSpace.mu.Lock()
- t.escapeErr = nil
- t.nameSpace.mu.Unlock()
- ret, err := t.text.Parse(src)
+// Parse parses text as a template body for t.
+// Named template definitions ({{define ...}} or {{block ...}} statements) in text
+// define additional templates associated with t and are removed from the
+// definition of t itself.
+//
+// Templates can be redefined in successive calls to Parse,
+// before the first use of Execute on t or any associated template.
+// A template definition with a body containing only white space and comments
+// is considered empty and will not replace an existing template's body.
+// This allows using Parse to add new named template definitions without
+// overwriting the main template body.
+func (t *Template) Parse(text string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
+ ret, err := t.text.Parse(text)
if err != nil {
return nil, err
}
+
// In general, all the named templates might have changed underfoot.
// Regardless, some new ones may have been defined.
// The template.Template set has been updated; update ours.
@@ -176,11 +198,7 @@ func (t *Template) Parse(src string) (*Template, error) {
tmpl := t.set[name]
if tmpl == nil {
tmpl = t.new(name)
- } else if tmpl.escapeErr != nil {
- return nil, fmt.Errorf("html/template: cannot redefine %q after it has executed", name)
}
- // Restore our record of this text/template to its unescaped original state.
- tmpl.escapeErr = nil
tmpl.text = v
tmpl.Tree = v.Tree
}
@@ -190,13 +208,14 @@ func (t *Template) Parse(src string) (*Template, error) {
// AddParseTree creates a new template with the name and parse tree
// and associates it with t.
//
-// It returns an error if t has already been executed.
+// It returns an error if t or any associated template has already been executed.
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
- if t.escapeErr != nil {
- return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name())
- }
text, err := t.text.AddParseTree(name, tree)
if err != nil {
return nil, err
@@ -252,7 +271,8 @@ func (t *Template) Clone() (*Template, error) {
ret.nameSpace,
}
}
- return ret, nil
+ // Return the template associated with the name of this template.
+ return ret.set[ret.Name()], nil
}
// New allocates a new HTML template with the given name.
@@ -346,6 +366,11 @@ func Must(t *Template, err error) *Template {
// the named files. The returned template's name will have the (base) name and
// (parsed) contents of the first file. There must be at least one file.
// If an error occurs, parsing stops and the returned *Template is nil.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
+// named "foo", while "a/foo" is unavailable.
func ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(nil, filenames...)
}
@@ -353,6 +378,11 @@ func ParseFiles(filenames ...string) (*Template, error) {
// ParseFiles parses the named files and associates the resulting templates with
// t. If an error occurs, parsing stops and the returned template is nil;
// otherwise it is t. There must be at least one file.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+//
+// ParseFiles returns an error if t or any associated template has already been executed.
func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(t, filenames...)
}
@@ -360,6 +390,10 @@ func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
// parseFiles is the helper for the method and function. If the argument
// template is nil, it is created from the first file.
func parseFiles(t *Template, filenames ...string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
if len(filenames) == 0 {
// Not really a problem, but be consistent.
return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
@@ -399,6 +433,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) {
// returned template will have the (base) name and (parsed) contents of the
// first file matched by the pattern. ParseGlob is equivalent to calling
// ParseFiles with the list of files matched by the pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func ParseGlob(pattern string) (*Template, error) {
return parseGlob(nil, pattern)
}
@@ -408,12 +445,20 @@ func ParseGlob(pattern string) (*Template, error) {
// processed by filepath.Glob and must match at least one file. ParseGlob is
// equivalent to calling t.ParseFiles with the list of files matched by the
// pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+//
+// ParseGlob returns an error if t or any associated template has already been executed.
func (t *Template) ParseGlob(pattern string) (*Template, error) {
return parseGlob(t, pattern)
}
// parseGlob is the implementation of the function and method ParseGlob.
func parseGlob(t *Template, pattern string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
filenames, err := filepath.Glob(pattern)
if err != nil {
return nil, err
diff --git a/libgo/go/html/template/template_test.go b/libgo/go/html/template/template_test.go
index 6f70d67de9..90c5a73ba7 100644
--- a/libgo/go/html/template/template_test.go
+++ b/libgo/go/html/template/template_test.go
@@ -1,7 +1,13 @@
-package template
+// 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 template_test
import (
"bytes"
+ . "html/template"
+ "strings"
"testing"
)
@@ -13,7 +19,7 @@ func TestTemplateClone(t *testing.T) {
t.Fatal(err)
}
if len(clone.Templates()) != len(orig.Templates()) {
- t.Fatalf("Invalid lenth of t.Clone().Templates()")
+ t.Fatalf("Invalid length of t.Clone().Templates()")
}
const want = "stuff"
@@ -27,3 +33,125 @@ func TestTemplateClone(t *testing.T) {
t.Fatalf("got %q; want %q", got, want)
}
}
+
+func TestRedefineNonEmptyAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `foo`)
+ c.mustExecute(c.root, nil, "foo")
+ c.mustNotParse(c.root, `bar`)
+}
+
+func TestRedefineEmptyAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, ``)
+ c.mustExecute(c.root, nil, "")
+ c.mustNotParse(c.root, `foo`)
+ c.mustExecute(c.root, nil, "")
+}
+
+func TestRedefineAfterNonExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{if .}}<{{template "X"}}>{{end}}{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.root, 0, "")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.root, 1, "&lt;foo>")
+}
+
+func TestRedefineAfterNamedExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `<{{template "X" .}}>{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.root, nil, "&lt;foo>")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.root, nil, "&lt;foo>")
+}
+
+func TestRedefineNestedByNameAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+}
+
+func TestRedefineNestedByTemplateAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+ c.mustNotParse(c.lookup("X"), `bar`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+}
+
+func TestRedefineSafety(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `<html><a href="{{template "X"}}">{{define "X"}}{{end}}`)
+ c.mustExecute(c.root, nil, `<html><a href="">`)
+ // Note: Every version of Go prior to Go 1.8 accepted the redefinition of "X"
+ // on the next line, but luckily kept it from being used in the outer template.
+ // Now we reject it, which makes clearer that we're not going to use it.
+ c.mustNotParse(c.root, `{{define "X"}}" bar="baz{{end}}`)
+ c.mustExecute(c.root, nil, `<html><a href="">`)
+}
+
+func TestRedefineTopUse(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{template "X"}}{{.}}{{define "X"}}{{end}}`)
+ c.mustExecute(c.root, 42, `42`)
+ c.mustNotParse(c.root, `{{define "X"}}<script>{{end}}`)
+ c.mustExecute(c.root, 42, `42`)
+}
+
+func TestRedefineOtherParsers(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, ``)
+ c.mustExecute(c.root, nil, ``)
+ if _, err := c.root.ParseFiles("no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("ParseFiles: %v\nwanted error about already having Executed", err)
+ }
+ if _, err := c.root.ParseGlob("*.no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("ParseGlob: %v\nwanted error about already having Executed", err)
+ }
+ if _, err := c.root.AddParseTree("t1", c.root.Tree); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("AddParseTree: %v\nwanted error about already having Executed", err)
+ }
+}
+
+type testCase struct {
+ t *testing.T
+ root *Template
+}
+
+func newTestCase(t *testing.T) *testCase {
+ return &testCase{
+ t: t,
+ root: New("root"),
+ }
+}
+
+func (c *testCase) lookup(name string) *Template {
+ return c.root.Lookup(name)
+}
+
+func (c *testCase) mustParse(t *Template, text string) {
+ _, err := t.Parse(text)
+ if err != nil {
+ c.t.Fatalf("parse: %v", err)
+ }
+}
+
+func (c *testCase) mustNotParse(t *Template, text string) {
+ _, err := t.Parse(text)
+ if err == nil {
+ c.t.Fatalf("parse: unexpected success")
+ }
+}
+
+func (c *testCase) mustExecute(t *Template, val interface{}, want string) {
+ var buf bytes.Buffer
+ err := t.Execute(&buf, val)
+ if err != nil {
+ c.t.Fatalf("execute: %v", err)
+ }
+ if buf.String() != want {
+ c.t.Fatalf("template output:\n%s\nwant:\n%s", buf.String(), want)
+ }
+}
diff --git a/libgo/go/html/template/transition.go b/libgo/go/html/template/transition.go
index aefe0355af..4a4716d782 100644
--- a/libgo/go/html/template/transition.go
+++ b/libgo/go/html/template/transition.go
@@ -105,14 +105,21 @@ func tTag(c context, s []byte) (context, int) {
err: errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
}, len(s)
}
- switch attrType(string(s[i:j])) {
- case contentTypeURL:
- attr = attrURL
- case contentTypeCSS:
- attr = attrStyle
- case contentTypeJS:
- attr = attrScript
+
+ attrName := string(s[i:j])
+ if c.element == elementScript && attrName == "type" {
+ attr = attrScriptType
+ } else {
+ switch attrType(attrName) {
+ case contentTypeURL:
+ attr = attrURL
+ case contentTypeCSS:
+ attr = attrStyle
+ case contentTypeJS:
+ attr = attrScript
+ }
}
+
if j == len(s) {
state = stateAttrName
} else {
@@ -149,10 +156,11 @@ func tAfterName(c context, s []byte) (context, int) {
}
var attrStartStates = [...]state{
- attrNone: stateAttr,
- attrScript: stateJS,
- attrStyle: stateCSS,
- attrURL: stateURL,
+ attrNone: stateAttr,
+ attrScript: stateJS,
+ attrScriptType: stateAttr,
+ attrStyle: stateCSS,
+ attrURL: stateURL,
}
// tBeforeValue is the context transition function for stateBeforeValue.
diff --git a/libgo/go/html/template/url.go b/libgo/go/html/template/url.go
index 2ca76bf389..02123b2ccc 100644
--- a/libgo/go/html/template/url.go
+++ b/libgo/go/html/template/url.go
@@ -17,7 +17,7 @@ func urlFilter(args ...interface{}) string {
if t == contentTypeURL {
return s
}
- if i := strings.IndexRune(s, ':'); i >= 0 && strings.IndexRune(s[:i], '/') < 0 {
+ if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
protocol := strings.ToLower(s[:i])
if protocol != "http" && protocol != "https" && protocol != "mailto" {
return "#" + filterFailsafe
@@ -32,7 +32,7 @@ func urlEscaper(args ...interface{}) string {
return urlProcessor(false, args...)
}
-// urlEscaper normalizes URL content so it can be embedded in a quote-delimited
+// urlNormalizer normalizes URL content so it can be embedded in a quote-delimited
// string or parenthesis delimited url(...).
// The normalizer does not encode all HTML specials. Specifically, it does not
// encode '&' so correct embedding in an HTML attribute requires escaping of
diff --git a/libgo/go/image/color/color.go b/libgo/go/image/color/color.go
index cae059b6da..0832c59729 100644
--- a/libgo/go/image/color/color.go
+++ b/libgo/go/image/color/color.go
@@ -147,7 +147,7 @@ type Model interface {
func ModelFunc(f func(Color) Color) Model {
// Note: using *modelFunc as the implementation
// means that callers can still use comparisons
- // like m == RGBAModel. This is not possible if
+ // like m == RGBAModel. This is not possible if
// we use the func value directly, because funcs
// are no longer comparable.
return &modelFunc{f}
@@ -246,8 +246,18 @@ func grayModel(c Color) Color {
return c
}
r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
- return Gray{uint8(y >> 8)}
+
+ // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
+ // as those given by the JFIF specification and used by func RGBToYCbCr in
+ // ycbcr.go.
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
+ //
+ // The 24 is 16 + 8. The 16 is the same as used in RGBToYCbCr. The 8 is
+ // because the return value is 8 bit color, not 16 bit color.
+ y := (19595*r + 38470*g + 7471*b + 1<<15) >> 24
+
+ return Gray{uint8(y)}
}
func gray16Model(c Color) Color {
@@ -255,7 +265,14 @@ func gray16Model(c Color) Color {
return c
}
r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
+
+ // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
+ // as those given by the JFIF specification and used by func RGBToYCbCr in
+ // ycbcr.go.
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
+ y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16
+
return Gray16{uint16(y)}
}
diff --git a/libgo/go/image/color/palette/gen.go b/libgo/go/image/color/palette/gen.go
index 2b5fdaaf2b..57718e6a0c 100644
--- a/libgo/go/image/color/palette/gen.go
+++ b/libgo/go/image/color/palette/gen.go
@@ -89,7 +89,7 @@ func printPlan9(w io.Writer) {
fmt.Fprintln(w, "// of continuous tones.")
fmt.Fprintln(w, "//")
fmt.Fprintln(w, "// This palette was used in the Plan 9 Operating System, described at")
- fmt.Fprintln(w, "// http://plan9.bell-labs.com/magic/man2html/6/color")
+ fmt.Fprintln(w, "// https://9p.io/magic/man2html/6/color")
fmt.Fprintln(w, "var Plan9 = []color.Color{")
for _, line := range lines {
fmt.Fprintln(w, line)
diff --git a/libgo/go/image/color/palette/palette.go b/libgo/go/image/color/palette/palette.go
index 0bf2c8e1aa..b695414520 100644
--- a/libgo/go/image/color/palette/palette.go
+++ b/libgo/go/image/color/palette/palette.go
@@ -19,7 +19,7 @@ import "image/color"
// of continuous tones.
//
// This palette was used in the Plan 9 Operating System, described at
-// http://plan9.bell-labs.com/magic/man2html/6/color
+// https://9p.io/magic/man2html/6/color
var Plan9 = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x44, 0xff},
diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go
index 904434f6a3..18d1a568aa 100644
--- a/libgo/go/image/color/ycbcr.go
+++ b/libgo/go/image/color/ycbcr.go
@@ -15,24 +15,42 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
r1 := int32(r)
g1 := int32(g)
b1 := int32(b)
+
+ // yy is in range [0,0xff].
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
- cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
- cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
- if yy < 0 {
- yy = 0
- } else if yy > 0xff {
- yy = 0xff
- }
- if cb < 0 {
- cb = 0
- } else if cb > 0xff {
- cb = 0xff
+
+ // The bit twiddling below is equivalent to
+ //
+ // cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ // if cb < 0 {
+ // cb = 0
+ // } else if cb > 0xff {
+ // cb = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute cr uses a similar pattern.
+ //
+ // Note that -11056 - 21712 + 32768 equals 0.
+ cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
+ if uint32(cb)&0xff000000 == 0 {
+ cb >>= 16
+ } else {
+ cb = ^(cb >> 31)
}
- if cr < 0 {
- cr = 0
- } else if cr > 0xff {
- cr = 0xff
+
+ // Note that 32768 - 27440 - 5328 equals 0.
+ cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
+ if uint32(cr)&0xff000000 == 0 {
+ cr >>= 16
+ } else {
+ cr = ^(cr >> 31)
}
+
return uint8(yy), uint8(cb), uint8(cr)
}
@@ -44,27 +62,44 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
// B = Y' + 1.77200*(Cb-128)
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(y) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(cb) - 128
cr1 := int32(cr) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 0xff {
- r = 0xff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 0xff {
- g = 0xff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 0xff {
- b = 0xff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
+
return uint8(r), uint8(g), uint8(b)
}
@@ -104,24 +139,39 @@ func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
+
return uint32(r), uint32(g), uint32(b), 0xffff
}
@@ -149,23 +199,37 @@ func (c NYCbCrA) RGBA() (uint32, uint32, uint32, uint32) {
yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
// The second part of this method applies the alpha.
@@ -220,10 +284,10 @@ func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
// CMYKToRGB converts a CMYK quadruple to an RGB triple.
func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
- w := uint32(0xffff - uint32(k)*0x101)
- r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff
- g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff
- b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff
+ w := 0xffff - uint32(k)*0x101
+ r := (0xffff - uint32(c)*0x101) * w / 0xffff
+ g := (0xffff - uint32(m)*0x101) * w / 0xffff
+ b := (0xffff - uint32(y)*0x101) * w / 0xffff
return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
}
@@ -239,11 +303,11 @@ func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
// This code is a copy of the CMYKToRGB function above, except that it
// returns values in the range [0, 0xffff] instead of [0, 0xff].
- w := uint32(0xffff - uint32(c.K)*0x101)
- r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff
- g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff
- b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff
- return uint32(r), uint32(g), uint32(b), 0xffff
+ w := 0xffff - uint32(c.K)*0x101
+ r := (0xffff - uint32(c.C)*0x101) * w / 0xffff
+ g := (0xffff - uint32(c.M)*0x101) * w / 0xffff
+ b := (0xffff - uint32(c.Y)*0x101) * w / 0xffff
+ return r, g, b, 0xffff
}
// CMYKModel is the Model for CMYK colors.
diff --git a/libgo/go/image/color/ycbcr_test.go b/libgo/go/image/color/ycbcr_test.go
index f5e7cbf335..85c1b984a6 100644
--- a/libgo/go/image/color/ycbcr_test.go
+++ b/libgo/go/image/color/ycbcr_test.go
@@ -171,3 +171,96 @@ func TestPalette(t *testing.T) {
t.Errorf("got %v, want %v", got, want)
}
}
+
+var sink8 uint8
+var sink32 uint32
+
+func BenchmarkYCbCrToRGB(b *testing.B) {
+ // YCbCrToRGB does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = YCbCrToRGB(0, 0, 0)
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = YCbCrToRGB(128, 128, 128)
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = YCbCrToRGB(255, 255, 255)
+ }
+ })
+}
+
+func BenchmarkRGBToYCbCr(b *testing.B) {
+ // RGBToYCbCr does saturating arithmetic.
+ // Different values can take different paths
+ // through the generated code.
+ b.Run("0", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = RGBToYCbCr(0, 0, 0)
+ }
+ })
+ b.Run("Cb", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = RGBToYCbCr(0, 0, 255)
+ }
+ })
+ b.Run("Cr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink8, sink8, sink8 = RGBToYCbCr(255, 0, 0)
+ }
+ })
+}
+
+func BenchmarkYCbCrToRGBA(b *testing.B) {
+ // RGB does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := YCbCr{0, 0, 0}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := YCbCr{128, 128, 128}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := YCbCr{255, 255, 255}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+}
+
+func BenchmarkNYCbCrAToRGBA(b *testing.B) {
+ // RGBA does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{0, 0, 0}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{128, 128, 128}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{255, 255, 255}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+}
diff --git a/libgo/go/image/decode_test.go b/libgo/go/image/decode_test.go
index d16ef8a1a4..85e235e729 100644
--- a/libgo/go/image/decode_test.go
+++ b/libgo/go/image/decode_test.go
@@ -36,6 +36,7 @@ var imageTests = []imageTest{
{"testdata/video-001.221212.png", "testdata/video-001.221212.jpeg", 8 << 8},
{"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8},
{"testdata/video-001.rgb.png", "testdata/video-001.rgb.jpeg", 8 << 8},
+ {"testdata/video-001.progressive.truncated.png", "testdata/video-001.progressive.truncated.jpeg", 8 << 8},
// Grayscale images.
{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
diff --git a/libgo/go/image/draw/bench_test.go b/libgo/go/image/draw/bench_test.go
index 7b89f95d11..a41d7e7dfb 100644
--- a/libgo/go/image/draw/bench_test.go
+++ b/libgo/go/image/draw/bench_test.go
@@ -74,7 +74,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
var src image.Image
switch scm {
case nil:
- src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
+ src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0x44}}
case color.CMYKModel:
src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go
index e47c48d961..a31dd427ce 100644
--- a/libgo/go/image/draw/draw.go
+++ b/libgo/go/image/draw/draw.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -116,7 +116,12 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil {
switch src0 := src.(type) {
case *image.Uniform:
- drawFillOver(dst0, r, src0)
+ sr, sg, sb, sa := src0.RGBA()
+ if sa == 0xffff {
+ drawFillSrc(dst0, r, sr, sg, sb, sa)
+ } else {
+ drawFillOver(dst0, r, sr, sg, sb, sa)
+ }
return
case *image.RGBA:
drawCopyOver(dst0, r, src0, sp)
@@ -150,7 +155,8 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil {
switch src0 := src.(type) {
case *image.Uniform:
- drawFillSrc(dst0, r, src0)
+ sr, sg, sb, sa := src0.RGBA()
+ drawFillSrc(dst0, r, sr, sg, sb, sa)
return
case *image.RGBA:
drawCopySrc(dst0, r, src0, sp)
@@ -232,8 +238,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
}
}
-func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
- sr, sg, sb, sa := src.RGBA()
+func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
@@ -255,8 +260,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
}
}
-func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
- sr, sg, sb, sa := src.RGBA()
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
sr8 := uint8(sr >> 8)
sg8 := uint8(sg >> 8)
sb8 := uint8(sb >> 8)
@@ -634,10 +638,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
if !floydSteinberg {
continue
}
- er -= int32(palette[bestIndex][0])
- eg -= int32(palette[bestIndex][1])
- eb -= int32(palette[bestIndex][2])
- ea -= int32(palette[bestIndex][3])
+ er -= palette[bestIndex][0]
+ eg -= palette[bestIndex][1]
+ eb -= palette[bestIndex][2]
+ ea -= palette[bestIndex][3]
} else {
out.R = uint16(er)
diff --git a/libgo/go/image/draw/example_test.go b/libgo/go/image/draw/example_test.go
new file mode 100644
index 0000000000..d381c1c67f
--- /dev/null
+++ b/libgo/go/image/draw/example_test.go
@@ -0,0 +1,50 @@
+// 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 draw_test
+
+import (
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "math"
+)
+
+func ExampleDrawer_floydSteinberg() {
+ const width = 130
+ const height = 50
+
+ im := image.NewGray(image.Rectangle{Max: image.Point{X: width, Y: height}})
+ for x := 0; x < width; x++ {
+ for y := 0; y < height; y++ {
+ dist := math.Sqrt(math.Pow(float64(x-width/2), 2)/3+math.Pow(float64(y-height/2), 2)) / (height / 1.5) * 255
+ var gray uint8
+ if dist > 255 {
+ gray = 255
+ } else {
+ gray = uint8(dist)
+ }
+ im.SetGray(x, y, color.Gray{Y: 255 - gray})
+ }
+ }
+ pi := image.NewPaletted(im.Bounds(), []color.Color{
+ color.Gray{Y: 255},
+ color.Gray{Y: 160},
+ color.Gray{Y: 70},
+ color.Gray{Y: 35},
+ color.Gray{Y: 0},
+ })
+
+ draw.FloydSteinberg.Draw(pi, im.Bounds(), im, image.ZP)
+ shade := []string{" ", "â–‘", "â–’", "â–“", "â–ˆ"}
+ for i, p := range pi.Pix {
+ fmt.Print(shade[p])
+ if (i+1)%width == 0 {
+ fmt.Print("\n")
+ }
+ }
+}
diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go
index 6a133124ad..e61112817b 100644
--- a/libgo/go/image/gif/reader.go
+++ b/libgo/go/image/gif/reader.go
@@ -63,6 +63,22 @@ const (
eApplication = 0xFF // Application
)
+func readFull(r io.Reader, b []byte) error {
+ _, err := io.ReadFull(r, b)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
+
+func readByte(r io.ByteReader) (byte, error) {
+ b, err := r.ReadByte()
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return b, err
+}
+
// decoder is the type used to decode a GIF file.
type decoder struct {
r reader
@@ -96,7 +112,7 @@ type decoder struct {
// blockReader parses the block structure of GIF image data, which
// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
// reader given to the LZW decoder, which is thus immune to the
-// blocking. After the LZW decoder completes, there will be a 0-byte
+// blocking. After the LZW decoder completes, there will be a 0-byte
// block remaining (0, ()), which is consumed when checking that the
// blockReader is exhausted.
type blockReader struct {
@@ -124,7 +140,7 @@ func (b *blockReader) Read(p []byte) (int, error) {
return 0, b.err
}
b.slice = b.tmp[:blockLen]
- if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
+ if b.err = readFull(b.r, b.slice); b.err != nil {
return 0, b.err
}
}
@@ -151,9 +167,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
for {
- c, err := d.r.ReadByte()
+ c, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading frames: %v", err)
}
switch c {
case sExtension:
@@ -178,16 +194,29 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
m.Palette = d.globalColorTable
}
- if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+ if d.hasTransparentIndex {
if !useLocalColorTable {
// Clone the global color table.
m.Palette = append(color.Palette(nil), d.globalColorTable...)
}
- m.Palette[d.transparentIndex] = color.RGBA{}
+ if ti := int(d.transparentIndex); ti < len(m.Palette) {
+ m.Palette[ti] = color.RGBA{}
+ } else {
+ // The transparentIndex is out of range, which is an error
+ // according to the spec, but Firefox and Google Chrome
+ // seem OK with this, so we enlarge the palette with
+ // transparent colors. See golang.org/issue/15059.
+ p := make(color.Palette, ti+1)
+ copy(p, m.Palette)
+ for i := len(m.Palette); i < len(p); i++ {
+ p[i] = color.RGBA{}
+ }
+ m.Palette = p
+ }
}
- litWidth, err := d.r.ReadByte()
+ litWidth, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
if litWidth < 2 || litWidth > 8 {
return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
@@ -196,9 +225,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
br := &blockReader{r: d.r}
lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth))
defer lzwr.Close()
- if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
+ if err = readFull(lzwr, m.Pix); err != nil {
if err != io.ErrUnexpectedEOF {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errNotEnough
}
@@ -210,18 +239,18 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
// for an image". In practice, though, giflib (a widely used C
// library) does not enforce this, so we also accept lzwr returning
// io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF
- // before the LZW decoder saw an explict end code), provided that
+ // before the LZW decoder saw an explicit end code), provided that
// the io.ReadFull call above successfully read len(m.Pix) bytes.
// See https://golang.org/issue/9856 for an example GIF.
if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errTooMuch
}
if n, err := br.Read(d.tmp[:1]); n != 0 || err != io.EOF {
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errTooMuch
}
@@ -251,7 +280,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
case sTrailer:
if len(d.image) == 0 {
- return io.ErrUnexpectedEOF
+ return fmt.Errorf("gif: missing image data")
}
return nil
@@ -262,13 +291,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
func (d *decoder) readHeaderAndScreenDescriptor() error {
- _, err := io.ReadFull(d.r, d.tmp[:13])
+ err := readFull(d.r, d.tmp[:13])
if err != nil {
- return err
+ return fmt.Errorf("gif: reading header: %v", err)
}
d.vers = string(d.tmp[:6])
if d.vers != "GIF87a" && d.vers != "GIF89a" {
- return fmt.Errorf("gif: can't recognize format %s", d.vers)
+ return fmt.Errorf("gif: can't recognize format %q", d.vers)
}
d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
@@ -285,9 +314,9 @@ func (d *decoder) readHeaderAndScreenDescriptor() error {
func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
n := 1 << (1 + uint(fields&fColorTableBitsMask))
- _, err := io.ReadFull(d.r, d.tmp[:3*n])
+ err := readFull(d.r, d.tmp[:3*n])
if err != nil {
- return nil, fmt.Errorf("gif: short read on color table: %s", err)
+ return nil, fmt.Errorf("gif: reading color table: %s", err)
}
j, p := 0, make(color.Palette, n)
for i := range p {
@@ -298,9 +327,9 @@ func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
}
func (d *decoder) readExtension() error {
- extension, err := d.r.ReadByte()
+ extension, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading extension: %v", err)
}
size := 0
switch extension {
@@ -311,9 +340,9 @@ func (d *decoder) readExtension() error {
case eComment:
// nothing to do but read the data.
case eApplication:
- b, err := d.r.ReadByte()
+ b, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading extension: %v", err)
}
// The spec requires size be 11, but Adobe sometimes uses 10.
size = int(b)
@@ -321,8 +350,8 @@ func (d *decoder) readExtension() error {
return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
}
if size > 0 {
- if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
- return err
+ if err := readFull(d.r, d.tmp[:size]); err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
}
}
@@ -330,8 +359,11 @@ func (d *decoder) readExtension() error {
// this extension defines a loop count.
if extension == eApplication && string(d.tmp[:size]) == "NETSCAPE2.0" {
n, err := d.readBlock()
- if n == 0 || err != nil {
- return err
+ if err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
+ }
+ if n == 0 {
+ return nil
}
if n == 3 && d.tmp[0] == 1 {
d.loopCount = int(d.tmp[1]) | int(d.tmp[2])<<8
@@ -339,16 +371,22 @@ func (d *decoder) readExtension() error {
}
for {
n, err := d.readBlock()
- if n == 0 || err != nil {
- return err
+ if err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
+ }
+ if n == 0 {
+ return nil
}
}
}
func (d *decoder) readGraphicControl() error {
- if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
+ if err := readFull(d.r, d.tmp[:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
+ if d.tmp[0] != 4 {
+ return fmt.Errorf("gif: invalid graphic control extension block size: %d", d.tmp[0])
+ }
flags := d.tmp[1]
d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
@@ -356,11 +394,14 @@ func (d *decoder) readGraphicControl() error {
d.transparentIndex = d.tmp[4]
d.hasTransparentIndex = true
}
+ if d.tmp[5] != 0 {
+ return fmt.Errorf("gif: invalid graphic control extension block terminator: %d", d.tmp[5])
+ }
return nil
}
func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
- if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
+ if err := readFull(d.r, d.tmp[:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
}
left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -380,11 +421,14 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
}
func (d *decoder) readBlock() (int, error) {
- n, err := d.r.ReadByte()
+ n, err := readByte(d.r)
if n == 0 || err != nil {
return 0, err
}
- return io.ReadFull(d.r, d.tmp[:n])
+ if err := readFull(d.r, d.tmp[:n]); err != nil {
+ return 0, err
+ }
+ return int(n), nil
}
// interlaceScan defines the ordering for a pass of the interlace algorithm.
diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go
index c294195b6f..1267ba06a9 100644
--- a/libgo/go/image/gif/reader_test.go
+++ b/libgo/go/image/gif/reader_test.go
@@ -10,6 +10,7 @@ import (
"image"
"image/color"
"reflect"
+ "strings"
"testing"
)
@@ -22,12 +23,16 @@ const (
trailerStr = "\x3b"
)
-// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
-func lzwEncode(n int) []byte {
+// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
+func lzwEncode(in []byte) []byte {
b := &bytes.Buffer{}
w := lzw.NewWriter(b, lzw.LSB, 2)
- w.Write(make([]byte, n))
- w.Close()
+ if _, err := w.Write(in); err != nil {
+ panic(err)
+ }
+ if err := w.Close(); err != nil {
+ panic(err)
+ }
return b.Bytes()
}
@@ -53,7 +58,7 @@ func TestDecode(t *testing.T) {
// byte, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
if tc.nPix > 0 {
- enc := lzwEncode(tc.nPix)
+ enc := lzwEncode(make([]byte, tc.nPix))
if len(enc) > 0xff {
t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
continue
@@ -97,13 +102,13 @@ func TestTransparentIndex(t *testing.T) {
for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
if transparentIndex < 2 {
// Write the graphic control for the transparent index.
- b.WriteString("\x21\xf9\x00\x01\x00\x00")
+ b.WriteString("\x21\xf9\x04\x01\x00\x00")
b.WriteByte(byte(transparentIndex))
b.WriteByte(0)
}
// Write an image with bounds 2x1, as per TestDecode.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
- enc := lzwEncode(2)
+ enc := lzwEncode([]byte{0x00, 0x00})
if len(enc) > 0xff {
t.Fatalf("compressed length %d is too large", len(enc))
}
@@ -196,21 +201,13 @@ func TestNoPalette(t *testing.T) {
b.WriteString(headerStr[:len(headerStr)-3])
b.WriteString("\x00\x00\x00") // No global palette.
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels: neither is in range, because there is no palette.
- pix := []byte{0, 3}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{0x00, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
@@ -226,21 +223,13 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
b.WriteString(headerStr)
b.WriteString(paletteStr)
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels; some pvals trigger the expected error.
- pix := []byte{pval, pval}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{pval, pval})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
@@ -254,6 +243,36 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
}
}
+func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
+ b := &bytes.Buffer{}
+
+ // Manufacture a GIF with a 2 color palette.
+ b.WriteString(headerStr)
+ b.WriteString(paletteStr)
+
+ // Graphic Control Extension: transparency, transparent color index = 3.
+ //
+ // This index, 3, is out of range of the global palette and there is no
+ // local palette in the subsequent image descriptor. This is an error
+ // according to the spec, but Firefox and Google Chrome seem OK with this.
+ //
+ // See golang.org/issue/15059.
+ b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
+
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
+ b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+
+ // Encode the pixels.
+ enc := lzwEncode([]byte{0x03, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ b.WriteByte(0x00) // An empty block signifies the end of the image data.
+
+ b.WriteString(trailerStr)
+
+ try(t, b.Bytes(), "")
+}
+
func TestLoopCount(t *testing.T) {
data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
@@ -274,3 +293,19 @@ func TestLoopCount(t *testing.T) {
t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
}
}
+
+func TestUnexpectedEOF(t *testing.T) {
+ for i := len(testGIF) - 1; i >= 0; i-- {
+ _, err := Decode(bytes.NewReader(testGIF[:i]))
+ if err == errNotEnough {
+ continue
+ }
+ text := ""
+ if err != nil {
+ text = err.Error()
+ }
+ if !strings.HasPrefix(text, "gif:") || !strings.HasSuffix(text, ": unexpected EOF") {
+ t.Errorf("Decode(testGIF[:%d]) = %v, want gif: ...: unexpected EOF", i, err)
+ }
+ }
+}
diff --git a/libgo/go/image/internal/imageutil/gen.go b/libgo/go/image/internal/imageutil/gen.go
index fc1e707f0f..6792b28a45 100644
--- a/libgo/go/image/internal/imageutil/gen.go
+++ b/libgo/go/image/internal/imageutil/gen.go
@@ -95,32 +95,51 @@ const sratioCase = `
%s
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
`
diff --git a/libgo/go/image/internal/imageutil/impl.go b/libgo/go/image/internal/imageutil/impl.go
index fd7826d4a9..3696b08e41 100644
--- a/libgo/go/image/internal/imageutil/impl.go
+++ b/libgo/go/image/internal/imageutil/impl.go
@@ -44,32 +44,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -83,32 +101,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
ci := ciBase + sx/2
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -122,32 +158,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
ci := ciBase + sx/2
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -160,32 +214,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index adf97abbd1..c5834219a3 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -641,6 +641,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
return nil, err
}
}
+
+ if d.progressive {
+ if err := d.reconstructProgressiveImage(); err != nil {
+ return nil, err
+ }
+ }
if d.img1 != nil {
return d.img1, nil
}
diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go
index 99734c01af..e1104d27c2 100644
--- a/libgo/go/image/jpeg/scan.go
+++ b/libgo/go/image/jpeg/scan.go
@@ -173,7 +173,6 @@ func (d *decoder) processSOS(n int) error {
compIndex := scan[i].compIndex
hi := d.comp[compIndex].h
vi := d.comp[compIndex].v
- qt := &d.quant[d.comp[compIndex].tq]
for j := 0; j < hi*vi; j++ {
// The blocks are traversed one MCU at a time. For 4:2:0 chroma
// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
@@ -286,55 +285,19 @@ func (d *decoder) processSOS(n int) error {
}
if d.progressive {
- if zigEnd != blockSize-1 || al != 0 {
- // We haven't completely decoded this 8x8 block. Save the coefficients.
- d.progCoeffs[compIndex][by*mxx*hi+bx] = b
- // At this point, we could execute the rest of the loop body to dequantize and
- // perform the inverse DCT, to save early stages of a progressive image to the
- // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
- // the jpeg.Decode function does not return until the entire image is decoded,
- // so we "continue" here to avoid wasted computation.
- continue
- }
- }
-
- // Dequantize, perform the inverse DCT and store the block to the image.
- for zig := 0; zig < blockSize; zig++ {
- b[unzig[zig]] *= qt[zig]
+ // Save the coefficients.
+ d.progCoeffs[compIndex][by*mxx*hi+bx] = b
+ // At this point, we could call reconstructBlock to dequantize and perform the
+ // inverse DCT, to save early stages of a progressive image to the *image.YCbCr
+ // buffers (the whole point of progressive encoding), but in Go, the jpeg.Decode
+ // function does not return until the entire image is decoded, so we "continue"
+ // here to avoid wasted computation. Instead, reconstructBlock is called on each
+ // accumulated block by the reconstructProgressiveImage method after all of the
+ // SOS markers are processed.
+ continue
}
- idct(&b)
- dst, stride := []byte(nil), 0
- if d.nComp == 1 {
- dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
- } else {
- switch compIndex {
- case 0:
- dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
- case 1:
- dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
- case 2:
- dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
- case 3:
- dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
- default:
- return UnsupportedError("too many components")
- }
- }
- // Level shift by +128, clip to [0, 255], and write to dst.
- for y := 0; y < 8; y++ {
- y8 := y * 8
- yStride := y * stride
- for x := 0; x < 8; x++ {
- c := b[y8+x]
- if c < -128 {
- c = 0
- } else if c > 127 {
- c = 255
- } else {
- c += 128
- }
- dst[yStride+x] = uint8(c)
- }
+ if err := d.reconstructBlock(&b, bx, by, int(compIndex)); err != nil {
+ return err
}
} // for j
} // for i
@@ -470,3 +433,70 @@ func (d *decoder) refineNonZeroes(b *block, zig, zigEnd, nz, delta int32) (int32
}
return zig, nil
}
+
+func (d *decoder) reconstructProgressiveImage() error {
+ // The h0, mxx, by and bx variables have the same meaning as in the
+ // processSOS method.
+ h0 := d.comp[0].h
+ mxx := (d.width + 8*h0 - 1) / (8 * h0)
+ for i := 0; i < d.nComp; i++ {
+ if d.progCoeffs[i] == nil {
+ continue
+ }
+ v := 8 * d.comp[0].v / d.comp[i].v
+ h := 8 * d.comp[0].h / d.comp[i].h
+ stride := mxx * d.comp[i].h
+ for by := 0; by*v < d.height; by++ {
+ for bx := 0; bx*h < d.width; bx++ {
+ if err := d.reconstructBlock(&d.progCoeffs[i][by*stride+bx], bx, by, i); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// reconstructBlock dequantizes, performs the inverse DCT and stores the block
+// to the image.
+func (d *decoder) reconstructBlock(b *block, bx, by, compIndex int) error {
+ qt := &d.quant[d.comp[compIndex].tq]
+ for zig := 0; zig < blockSize; zig++ {
+ b[unzig[zig]] *= qt[zig]
+ }
+ idct(b)
+ dst, stride := []byte(nil), 0
+ if d.nComp == 1 {
+ dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
+ } else {
+ switch compIndex {
+ case 0:
+ dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
+ case 1:
+ dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
+ case 2:
+ dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
+ case 3:
+ dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
+ default:
+ return UnsupportedError("too many components")
+ }
+ }
+ // Level shift by +128, clip to [0, 255], and write to dst.
+ for y := 0; y < 8; y++ {
+ y8 := y * 8
+ yStride := y * stride
+ for x := 0; x < 8; x++ {
+ c := b[y8+x]
+ if c < -128 {
+ c = 0
+ } else if c > 127 {
+ c = 255
+ } else {
+ c += 128
+ }
+ dst[yStride+x] = uint8(c)
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/image/png/example_test.go b/libgo/go/image/png/example_test.go
new file mode 100644
index 0000000000..2a03be5a1a
--- /dev/null
+++ b/libgo/go/image/png/example_test.go
@@ -0,0 +1,79 @@
+// 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 png_test
+
+import (
+ "encoding/base64"
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+const gopher = `iVBORw0KGgoAAAANSUhEUgAAAEsAAAA8CAAAAAALAhhPAAAFfUlEQVRYw62XeWwUVRzHf2+OPbo9d7tsWyiyaZti6eWGAhISoIGKECEKCAiJJkYTiUgTMYSIosYYBBIUIxoSPIINEBDi2VhwkQrVsj1ESgu9doHWdrul7ba73WNm3vOPtsseM9MdwvvrzTs+8/t95ze/33sI5BqiabU6m9En8oNjduLnAEDLUsQXFF8tQ5oxK3vmnNmDSMtrncks9Hhtt/qeWZapHb1ha3UqYSWVl2ZmpWgaXMXGohQAvmeop3bjTRtv6SgaK/Pb9/bFzUrYslbFAmHPp+3WhAYdr+7GN/YnpN46Opv55VDsJkoEpMrY/vO2BIYQ6LLvm0ThY3MzDzzeSJeeWNyTkgnIE5ePKsvKlcg/0T9QMzXalwXMlj54z4c0rh/mzEfr+FgWEz2w6uk8dkzFAgcARAgNp1ZYef8bH2AgvuStbc2/i6CiWGj98y2tw2l4FAXKkQBIf+exyRnteY83LfEwDQAYCoK+P6bxkZm/0966LxcAAILHB56kgD95PPxltuYcMtFTWw/FKkY/6Opf3GGd9ZF+Qp6mzJxzuRSractOmJrH1u8XTvWFHINNkLQLMR+XHXvfPPHw967raE1xxwtA36IMRfkAAG29/7mLuQcb2WOnsJReZGfpiHsSBX81cvMKywYZHhX5hFPtOqPGWZCXnhWGAu6lX91ElKXSalcLXu3UaOXVay57ZSe5f6Gpx7J2MXAsi7EqSp09b/MirKSyJfnfEEgeDjl8FgDAfvewP03zZ+AJ0m9aFRM8eEHBDRKjfcreDXnZdQuAxXpT2NRJ7xl3UkLBhuVGU16gZiGOgZmrSbRdqkILuL/yYoSXHHkl9KXgqNu3PB8oRg0geC5vFmLjad6mUyTKLmF3OtraWDIfACyXqmephaDABawfpi6tqqBZytfQMqOz6S09iWXhktrRaB8Xz4Yi/8gyABDm5NVe6qq/3VzPrcjELWrebVuyY2T7ar4zQyybUCtsQ5Es1FGaZVrRVQwAgHGW2ZCRZshI5bGQi7HesyE972pOSeMM0dSktlzxRdrlqb3Osa6CCS8IJoQQQgBAbTAa5l5epO34rJszibJI8rxLfGzcp1dRosutGeb2VDNgqYrwTiPNsLxXiPi3dz7LiS1WBRBDBOnqEjyy3aQb+/bLiJzz9dIkscVBBLxMfSEac7kO4Fpkngi0ruNBeSOal+u8jgOuqPz12nryMLCniEjtOOOmpt+KEIqsEdocJjYXwrh9OZqWJQyPCTo67LNS/TdxLAv6R5ZNK9npEjbYdT33gRo4o5oTqR34R+OmaSzDBWsAIPhuRcgyoteNi9gF0KzNYWVItPf2TLoXEg+7isNC7uJkgo1iQWOfRSP9NR11RtbZZ3OMG/VhL6jvx+J1m87+RCfJChAtEBQkSBX2PnSiihc/Twh3j0h7qdYQAoRVsRGmq7HU2QRbaxVGa1D6nIOqaIWRjyRZpHMQKWKpZM5feA+lzC4ZFultV8S6T0mzQGhQohi5I8iw+CsqBSxhFMuwyLgSwbghGb0AiIKkSDmGZVmJSiKihsiyOAUs70UkywooYP0bii9GdH4sfr1UNysd3fUyLLMQN+rsmo3grHl9VNJHbbwxoa47Vw5gupIqrZcjPh9R4Nye3nRDk199V+aetmvVtDRE8/+cbgAAgMIWGb3UA0MGLE9SCbWX670TDy1y98c3D27eppUjsZ6fql3jcd5rUe7+ZIlLNQny3Rd+E5Tct3WVhTM5RBCEdiEK0b6B+/ca2gYU393nFj/n1AygRQxPIUA043M42u85+z2SnssKrPl8Mx76NL3E6eXc3be7OD+H4WHbJkKI8AU8irbITQjZ+0hQcPEgId/Fn/pl9crKH02+5o2b9T/eMx7pKoskYgAAAABJRU5ErkJggg==`
+
+// gopherPNG creates an io.Reader by decoding the base64 encoded image data string in the gopher constant.
+func gopherPNG() io.Reader { return base64.NewDecoder(base64.StdEncoding, strings.NewReader(gopher)) }
+
+func ExampleDecode() {
+ // This example uses png.Decode which can only decode PNG images.
+ // Consider using the general image.Decode as it can sniff and decode any registered image format.
+ img, err := png.Decode(gopherPNG())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ levels := []string{" ", "â–‘", "â–’", "â–“", "â–ˆ"}
+
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
+ c := color.GrayModel.Convert(img.At(x, y)).(color.Gray)
+ level := c.Y / 51 // 51 * 5 = 255
+ if level == 5 {
+ level--
+ }
+ fmt.Print(levels[level])
+ }
+ fmt.Print("\n")
+ }
+}
+
+func ExampleEncode() {
+ const width, height = 256, 256
+
+ // Create a colored image of the given width and height.
+ img := image.NewNRGBA(image.Rect(0, 0, width, height))
+
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ img.Set(x, y, color.NRGBA{
+ R: uint8((x + y) & 255),
+ G: uint8((x + y) << 1 & 255),
+ B: uint8((x + y) << 2 & 255),
+ A: 255,
+ })
+ }
+ }
+
+ f, err := os.Create("image.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := png.Encode(f, img); err != nil {
+ f.Close()
+ log.Fatal(err)
+ }
+
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index 9e6f985f7e..8299df5673 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -113,6 +113,11 @@ type decoder struct {
idatLength uint32
tmp [3 * 256]byte
interlace int
+
+ // useTransparent and transparent are used for grayscale and truecolor
+ // transparency, as opposed to palette transparency.
+ useTransparent bool
+ transparent [6]byte
}
// A FormatError reports that the input is not a valid PNG.
@@ -252,20 +257,51 @@ func (d *decoder) parsePLTE(length uint32) error {
}
func (d *decoder) parsetRNS(length uint32) error {
- if length > 256 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
switch d.cb {
- case cbG8, cbG16:
- return UnsupportedError("grayscale transparency")
+ case cbG1, cbG2, cbG4, cbG8, cbG16:
+ if length != 2 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ switch d.cb {
+ case cbG1:
+ d.transparent[1] *= 0xff
+ case cbG2:
+ d.transparent[1] *= 0x55
+ case cbG4:
+ d.transparent[1] *= 0x11
+ }
+ d.useTransparent = true
+
case cbTC8, cbTC16:
- return UnsupportedError("truecolor transparency")
+ if length != 6 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ d.useTransparent = true
+
case cbP1, cbP2, cbP4, cbP8:
+ if length > 256 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
if len(d.palette) < n {
d.palette = d.palette[:n]
}
@@ -273,7 +309,8 @@ func (d *decoder) parsetRNS(length uint32) error {
rgba := d.palette[i].(color.RGBA)
d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
- case cbGA8, cbGA16, cbTCA8, cbTCA16:
+
+ default:
return FormatError("tRNS, color type mismatch")
}
return d.verifyChecksum()
@@ -366,7 +403,7 @@ func (d *decoder) decode() (image.Image, error) {
// readImagePass reads a single image pass, sized according to the pass number.
func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
- var bitsPerPixel int = 0
+ bitsPerPixel := 0
pixOffset := 0
var (
gray *image.Gray
@@ -394,16 +431,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
bitsPerPixel = d.depth
- gray = image.NewGray(image.Rect(0, 0, width, height))
- img = gray
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ gray = image.NewGray(image.Rect(0, 0, width, height))
+ img = gray
+ }
case cbGA8:
bitsPerPixel = 16
nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
case cbTC8:
bitsPerPixel = 24
- rgba = image.NewRGBA(image.Rect(0, 0, width, height))
- img = rgba
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ rgba = image.NewRGBA(image.Rect(0, 0, width, height))
+ img = rgba
+ }
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
@@ -414,16 +461,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
img = nrgba
case cbG16:
bitsPerPixel = 16
- gray16 = image.NewGray16(image.Rect(0, 0, width, height))
- img = gray16
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ gray16 = image.NewGray16(image.Rect(0, 0, width, height))
+ img = gray16
+ }
case cbGA16:
bitsPerPixel = 32
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
case cbTC16:
bitsPerPixel = 48
- rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
- img = rgba64
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
+ img = rgba64
+ }
case cbTCA16:
bitsPerPixel = 64
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
@@ -483,30 +540,83 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
// Convert from bytes to colors.
switch d.cb {
case cbG1:
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
- b <<= 1
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ ycol := (b >> 7) * 0xff
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 1
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
+ b <<= 1
+ }
}
}
case cbG2:
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
- b <<= 2
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ ycol := (b >> 6) * 0x55
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 2
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
+ b <<= 2
+ }
}
}
case cbG4:
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
- b <<= 4
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ ycol := (b >> 4) * 0x11
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 4
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
+ b <<= 4
+ }
}
}
case cbG8:
+ if d.useTransparent {
+ // Match error from Go 1.7 and earlier.
+ // Go 1.9 will decode this properly.
+ return nil, chunkOrderError
+ }
copy(gray.Pix[pixOffset:], cdat)
pixOffset += gray.Stride
case cbGA8:
@@ -515,16 +625,37 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
- pix, i, j := rgba.Pix, pixOffset, 0
- for x := 0; x < width; x++ {
- pix[i+0] = cdat[j+0]
- pix[i+1] = cdat[j+1]
- pix[i+2] = cdat[j+2]
- pix[i+3] = 0xff
- i += 4
- j += 3
+ if d.useTransparent {
+ pix, i, j := nrgba.Pix, pixOffset, 0
+ tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5]
+ for x := 0; x < width; x++ {
+ r := cdat[j+0]
+ g := cdat[j+1]
+ b := cdat[j+2]
+ a := uint8(0xff)
+ if r == tr && g == tg && b == tb {
+ a = 0x00
+ }
+ pix[i+0] = r
+ pix[i+1] = g
+ pix[i+2] = b
+ pix[i+3] = a
+ i += 4
+ j += 3
+ }
+ pixOffset += nrgba.Stride
+ } else {
+ pix, i, j := rgba.Pix, pixOffset, 0
+ for x := 0; x < width; x++ {
+ pix[i+0] = cdat[j+0]
+ pix[i+1] = cdat[j+1]
+ pix[i+2] = cdat[j+2]
+ pix[i+3] = 0xff
+ i += 4
+ j += 3
+ }
+ pixOffset += rgba.Stride
}
- pixOffset += rgba.Stride
case cbP1:
for x := 0; x < width; x += 8 {
b := cdat[x/8]
@@ -575,9 +706,21 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
copy(nrgba.Pix[pixOffset:], cdat)
pixOffset += nrgba.Stride
case cbG16:
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.SetGray16(x, y, color.Gray16{ycol})
+ if d.useTransparent {
+ ty := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ acol := uint16(0xffff)
+ if ycol == ty {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ gray16.SetGray16(x, y, color.Gray16{ycol})
+ }
}
case cbGA16:
for x := 0; x < width; x++ {
@@ -586,11 +729,27 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
- gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
- bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ if d.useTransparent {
+ tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3])
+ tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5])
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ acol := uint16(0xffff)
+ if rcol == tr && gcol == tg && bcol == tb {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ }
}
case cbTCA16:
for x := 0; x < width; x++ {
@@ -709,7 +868,11 @@ func (d *decoder) parseChunk() error {
d.stage = dsSeenPLTE
return d.parsePLTE(length)
case "tRNS":
- if d.stage != dsSeenPLTE {
+ if cbPaletted(d.cb) {
+ if d.stage != dsSeenPLTE {
+ return chunkOrderError
+ }
+ } else if d.stage != dsSeenIHDR {
return chunkOrderError
}
d.stage = dsSeentRNS
@@ -717,6 +880,13 @@ func (d *decoder) parseChunk() error {
case "IDAT":
if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
return chunkOrderError
+ } else if d.stage == dsSeenIDAT {
+ // Ignore trailing zero-length or garbage IDAT chunks.
+ //
+ // This does not affect valid PNG images that contain multiple IDAT
+ // chunks, since the first call to parseIDAT below will consume all
+ // consecutive IDAT chunks required for decoding the image.
+ break
}
d.stage = dsSeenIDAT
return d.parseIDAT(length)
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index f058f6b227..503b5dc567 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -39,6 +39,21 @@ var filenames = []string{
"basn4a16",
"basn6a08",
"basn6a16",
+ "ftbbn0g01",
+ "ftbbn0g02",
+ "ftbbn0g04",
+ "ftbbn2c16",
+ "ftbbn3p08",
+ "ftbgn2c16",
+ "ftbgn3p08",
+ "ftbrn2c08",
+ "ftbwn0g16",
+ "ftbwn3p08",
+ "ftbyn3p08",
+ "ftp0n0g08",
+ "ftp0n2c08",
+ "ftp0n3p08",
+ "ftp1n3p08",
}
var filenamesPaletted = []string{
@@ -64,6 +79,50 @@ func readPNG(filename string) (image.Image, error) {
return Decode(f)
}
+// fakebKGDs maps from filenames to fake bKGD chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakebKGDs = map[string]string{
+ "ftbbn0g01": "bKGD {gray: 0;}\n",
+ "ftbbn0g02": "bKGD {gray: 0;}\n",
+ "ftbbn0g04": "bKGD {gray: 0;}\n",
+ "ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
+ "ftbbn3p08": "bKGD {index: 245}\n",
+ "ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
+ "ftbgn3p08": "bKGD {index: 245}\n",
+ "ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
+ "ftbwn0g16": "bKGD {gray: 65535;}\n",
+ "ftbwn3p08": "bKGD {index: 0}\n",
+ "ftbyn3p08": "bKGD {index: 245}\n",
+}
+
+// fakegAMAs maps from filenames to fake gAMA chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakegAMAs = map[string]string{
+ "ftbbn0g01": "",
+ "ftbbn0g02": "gAMA {0.45455}\n",
+}
+
+// fakeIHDRUsings maps from filenames to fake IHDR "using" lines for our
+// approximation to the sng command-line tool. The PNG model is that
+// transparency (in the tRNS chunk) is separate to the color/grayscale/palette
+// color model (in the IHDR chunk). The Go model is that the concrete
+// image.Image type returned by png.Decode, such as image.RGBA (with all pixels
+// having 100% alpha) or image.NRGBA, encapsulates whether or not the image has
+// transparency. This map is a hack to work around the fact that the Go model
+// can't otherwise discriminate PNG's "IHDR says color (with no alpha) but tRNS
+// says alpha" and "IHDR says color with alpha".
+var fakeIHDRUsings = map[string]string{
+ "ftbbn0g01": " using grayscale;\n",
+ "ftbbn0g02": " using grayscale;\n",
+ "ftbbn0g04": " using grayscale;\n",
+ "ftbbn2c16": " using color;\n",
+ "ftbgn2c16": " using color;\n",
+ "ftbrn2c08": " using color;\n",
+ "ftbwn0g16": " using grayscale;\n",
+}
+
// An approximation of the sng command-line tool.
func sng(w io.WriteCloser, filename string, png image.Image) {
defer w.Close()
@@ -95,25 +154,35 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// Write the filename and IHDR.
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
- switch {
- case cm == color.RGBAModel, cm == color.RGBA64Model:
- io.WriteString(w, " using color;\n")
- case cm == color.NRGBAModel, cm == color.NRGBA64Model:
- io.WriteString(w, " using color alpha;\n")
- case cm == color.GrayModel, cm == color.Gray16Model:
- io.WriteString(w, " using grayscale;\n")
- case cpm != nil:
- io.WriteString(w, " using color palette;\n")
- default:
- io.WriteString(w, "unknown PNG decoder color model\n")
+ if s, ok := fakeIHDRUsings[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ switch {
+ case cm == color.RGBAModel, cm == color.RGBA64Model:
+ io.WriteString(w, " using color;\n")
+ case cm == color.NRGBAModel, cm == color.NRGBA64Model:
+ io.WriteString(w, " using color alpha;\n")
+ case cm == color.GrayModel, cm == color.Gray16Model:
+ io.WriteString(w, " using grayscale;\n")
+ case cpm != nil:
+ io.WriteString(w, " using color palette;\n")
+ default:
+ io.WriteString(w, "unknown PNG decoder color model\n")
+ }
}
io.WriteString(w, "}\n")
- // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
- // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
- io.WriteString(w, "gAMA {1.0000}\n")
+ // We fake a gAMA chunk. The test files have a gAMA chunk but the go PNG
+ // parser ignores it (the PNG spec section 11.3 says "Ancillary chunks may
+ // be ignored by a decoder").
+ if s, ok := fakegAMAs[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ io.WriteString(w, "gAMA {1.0000}\n")
+ }
// Write the PLTE and tRNS (if applicable).
+ useTransparent := false
if cpm != nil {
lastAlpha := -1
io.WriteString(w, "PLTE {\n")
@@ -133,6 +202,9 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
}
io.WriteString(w, "}\n")
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
if lastAlpha != -1 {
io.WriteString(w, "tRNS {\n")
for i := 0; i <= lastAlpha; i++ {
@@ -142,6 +214,42 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
}
io.WriteString(w, "}\n")
}
+ } else if strings.HasPrefix(filename, "ft") {
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
+ // We fake a tRNS chunk. The test files' grayscale and truecolor
+ // transparent images all have their top left corner transparent.
+ switch c := png.At(0, 0).(type) {
+ case color.NRGBA:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ // The standard image package doesn't have a "gray with
+ // alpha" type. Instead, we use an image.NRGBA.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ case color.NRGBA64:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbwn0g16":
+ // The standard image package doesn't have a "gray16 with
+ // alpha" type. Instead, we use an image.NRGBA64.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ }
}
// Write the IMAGE.
@@ -171,12 +279,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
case cm == color.NRGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba := png.At(x, y).(color.NRGBA)
- fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ fmt.Fprintf(w, "%02x", nrgba.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
+ } else {
+ fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ }
+ }
}
case cm == color.NRGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba64 := png.At(x, y).(color.NRGBA64)
- fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ switch filename {
+ case "ftbwn0g16":
+ fmt.Fprintf(w, "%04x ", nrgba64.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
+ } else {
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
+ }
}
case cpm != nil:
var b, c int
@@ -256,8 +382,23 @@ func TestReader(t *testing.T) {
}
ps := pb.Text()
ss := sb.Text()
+
+ // Newer versions of the sng command line tool append an optional
+ // color name to the RGB tuple. For example:
+ // # rgb = (0xff,0xff,0xff) grey100
+ // # rgb = (0x00,0x00,0xff) blue1
+ // instead of the older version's plainer:
+ // # rgb = (0xff,0xff,0xff)
+ // # rgb = (0x00,0x00,0xff)
+ // We strip any such name.
+ if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
+ if i := strings.LastIndex(ss, ") "); i >= 0 {
+ ss = ss[:i+1]
+ }
+ }
+
if ps != ss {
- t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+ t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
break
}
}
@@ -350,6 +491,33 @@ func TestIncompleteIDATOnRowBoundary(t *testing.T) {
}
}
+func TestTrailingIDATChunks(t *testing.T) {
+ // The following is a valid 1x1 PNG image containing color.Gray{255} and
+ // a trailing zero-length IDAT chunk (see PNG specification section 12.9):
+ const (
+ ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55"
+ idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd"
+ idatZero = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e"
+ iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+ )
+ _, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend))
+ if err != nil {
+ t.Fatalf("decoding valid image: %v", err)
+ }
+
+ // Non-zero-length trailing IDAT chunks should be ignored (recoverable error).
+ // The following chunk contains a single pixel with color.Gray{0}.
+ const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+
+ img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend))
+ if err != nil {
+ t.Fatalf("trailing IDAT not ignored: %v", err)
+ }
+ if img.At(0, 0) == (color.Gray{0}) {
+ t.Fatal("decoded image from trailing IDAT chunk")
+ }
+}
+
func TestMultipletRNSChunks(t *testing.T) {
/*
The following is a valid 1x1 paletted PNG image with a 1-element palette
@@ -461,3 +629,13 @@ func BenchmarkDecodeRGB(b *testing.B) {
func BenchmarkDecodeInterlacing(b *testing.B) {
benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4)
}
+
+func TestIssue19553(t *testing.T) {
+ var buf = []byte{
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88, 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac, 0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11, 0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05, 0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b, 0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31, 0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1, 0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+ }
+ _, err := Decode(bytes.NewReader(buf))
+ if err != chunkOrderError {
+ t.Errorf("Decode: expected chunkOrderError for transparent gray8, got %v", err)
+ }
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/README b/libgo/go/image/png/testdata/pngsuite/README
index c0f78bde87..01d1d896d6 100644
--- a/libgo/go/image/png/testdata/pngsuite/README
+++ b/libgo/go/image/png/testdata/pngsuite/README
@@ -1,21 +1,20 @@
The *.png and README.original files in this directory are copied from
-libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+libpng.org, specifically contrib/pngsuite/* in libpng 1.6.26.
+
README.original gives the following license for those files:
Permission to use, copy, and distribute these images for any purpose
and without fee is hereby granted.
-
-The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact
-not part of pngsuite but were created from files in pngsuite. Their non-power-
-of-two sizes makes them useful for testing bit-depths smaller than a byte.
+The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact not
+part of pngsuite but were created from files in pngsuite. Their non-power-of-2
+sizes makes them useful for testing bit-depths smaller than a byte.
basn3a08.png was generated from basn6a08.png using the pngnq tool, which
converted it to the 8-bit paletted image with alpha values in tRNS chunk.
-The *.sng files in this directory were generated from the *.png files
-by the sng command-line tool and some hand editing. The files
-basn0g0{1,2,4}.sng were actually generated by first converting the PNG
-to a bitdepth of 8 and then running sng on them. basn4a08.sng was generated
-by from a 16-bit rgba version of basn4a08.png rather than the original
-gray + alpha.
+The *.sng files in this directory were generated from the *.png files by the
+sng command-line tool and some hand editing. The files basn0g0{1,2,4}.sng and
+ftbbn0g0{1,2,4}.sng were actually generated by first converting the PNG to a
+bitdepth of 8 and then running sng on them. basn4a08.sng was generated from a
+16-bit rgba version of basn4a08.png rather than the original gray + alpha.
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.png b/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.png
new file mode 100644
index 0000000000..ba746ffb2f
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.sng b/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.sng
new file mode 100644
index 0000000000..c5347a4149
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g01.sng
@@ -0,0 +1,44 @@
+#SNG: from ftbbn0g01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+bKGD {gray: 0;}
+tRNS {
+ gray: 0;
+}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+00ffffffffffffff000000000000000000000000000000000000000000000000
+00ffffffffffffffff0000000000000000000000000000000000000000000000
+00ffffffffffffffffff00000000000000000000000000000000000000000000
+00ffffff0000ffffffff00000000000000000000000000000000000000000000
+00ffffff000000ffffff00000000000000000000000000000000000000000000
+00ffffff000000ffffff00ffffff000000ffffff000000000000000000000000
+00ffffff00ffffffffff00ffffff000000ffffff000000000000000000000000
+00ffffffffffffffffff00ffffffff0000ffffff000000000000000000000000
+00ffffffffffffffff0000ffffffff0000ffffff000000000000000000000000
+00ffffffffff0000000000ffffffffff00ffffff000000000000000000000000
+00ffffff00000000000000ffffffffff00ffffff0000000000ffffffffff0000
+00ffffff00000000000000ffffffffffffffffff000000ffffffffffffffff00
+00ffffff00000000000000ffffffffffffffffff000000ffffffffffffffff00
+00ffffff00000000000000ffffffffffffffffff0000ffffffffff00ffffff00
+0000000000000000000000ffffff00ffffffffff0000ffffffff000000000000
+0000000000000000000000ffffff00ffffffffff0000ffffff00000000000000
+0000000000000000000000ffffff0000ffffffff0000ffffff0000ffffff0000
+0000000000000000000000ffffff000000ffffff0000ffffff00ffffffffff00
+0000000000000000000000ffffff000000ffffff0000ffffff0000ffffffff00
+00000000000000000000000000000000000000000000ffffff00000000ffff00
+00000000000000000000000000000000000000000000ffffffff0000ffffff00
+00000000000000000000000000000000000000000000ffffffffffffffffff00
+0000000000000000000000000000000000000000000000ffffffffffffffff00
+000000000000000000000000000000000000000000000000ffffffffffff0000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.png b/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.png
new file mode 100644
index 0000000000..3d83bd6900
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.sng b/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.sng
new file mode 100644
index 0000000000..9686a6a2ee
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g02.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn0g02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {0.45455}
+bKGD {gray: 0;}
+tRNS {
+ gray: 0;
+}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaa000000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaaaa0000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000
+00aaaaaa0000aaaaaaaa00000000000000000000000000000000000000000000
+00aaaaaa000000aaaaaa00000000000000000000000000000000000000000000
+00aaaaaa000000aaaaaa00aaaaaa000000aaaaaa000000000000000000000000
+00aaaaaa00aaaaaaaaaa00aaaaaa000000aaaaaa000000000000000000000000
+00aaaaaaaaaaaaaaaaaa00aaaaaaaa0000aaaaaa000000000000000000000000
+00aaaaaaaaaaaaaaaa0000aaaaaaaa0000aaaaaa000000000000000000000000
+00aaaaaaaaaa0000000000aaaaaaaaaa00aaaaaa000000000000000000000000
+00aaaaaa00000000000000aaaaaaaaaa00aaaaaa0000000000aaaaaaaaaa0000
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa000000aaaaaaaaaaaaaaaa00
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa000000aaaaaaaaaaaaaaaa00
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa0000aaaaaaaaaa00aaaaaa00
+0000000000000000000000aaaaaa00aaaaaaaaaa0000aaaaaaaa000000000000
+0000000000000000000000aaaaaa00aaaaaaaaaa0000aaaaaa00000000000000
+0000000000000000000000aaaaaa0000aaaaaaaa0000aaaaaa0000aaaaaa0000
+0000000000000000000000aaaaaa000000aaaaaa0000aaaaaa00aaaaaaaaaa00
+0000000000000000000000aaaaaa000000aaaaaa0000aaaaaa0000aaaaaaaa00
+00000000000000000000000000000000000000000000aaaaaa00000000aaaa00
+00000000000000000000000000000000000000000000aaaaaaaa0000aaaaaa00
+00000000000000000000000000000000000000000000aaaaaaaaaaaaaaaaaa00
+0000000000000000000000000000000000000000000000aaaaaaaaaaaaaaaa00
+000000000000000000000000000000000000000000000000aaaaaaaaaaaa0000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.png b/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.png
new file mode 100644
index 0000000000..39a7050d27
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.sng b/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.sng
new file mode 100644
index 0000000000..518ba6c2ca
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn0g04.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn0g04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+bKGD {gray: 0;}
+tRNS {
+ gray: 255;
+}
+IMAGE {
+ pixels hex
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffddcceeffffffffffffffffffffffffffffff
+ffffffffffffffffffffffeebb776655446699ddffffffffffffffffffffffff
+ffffffffffffffffeebb886666553322222222335599ccffffffffffffffffff
+ffffffffffeecc997766554433333322334422112222336699ccffffffffffff
+ffffffcc997777664433333333444433334444332233335566777799cceeffff
+ffffcc777777775533333344556655444444444444332266777777776699ffff
+ffffdd8888887766444466777777777766555555445566777777775555bbffff
+ffffee8888888888777777777777777777777777777777777766555544eeffff
+ffffff8866667788998888777777777777777777777777665555444455ffffff
+ffffff8866778888999999998877777777777777777755331111334488ffffff
+ffffff99667788889999999999998877777777776655221111111133aaffffff
+ffffff99666688888899997777999999887766555533221111001122ddffffff
+ffffffaa666677888899886666669999997755554422111122111144ffffffff
+ffffffbb666666888888777755669999997755552222113344223377ffffffff
+ffffffcc666655778877777755779999996655332211334422111199ffffffff
+ffffffdd6666446688557777557799999966552222113311111111ccffffffff
+ffffffee6666555588666677557799999966442211222211111122eeffffffff
+ffffffff6666555577775577557799999955332211332211111155ffffffffff
+ffffffff6666665566775577557799999955331111443311111188ffffffffff
+ffffffff88666655667755665577999988552211114433111111ccffffffffff
+ffffffffffaa66666666666655779999885522111133111122bbffffffffffff
+ffffffffffffcc6666666666557788998855221111111122ccffffffffffffff
+ffffffffffffffee886666665577888877553311111133ddffffffffffffffff
+ffffffffffffffffffaa666655778888775544221144eeffffffffffffffffff
+ffffffffffffffffffffcc77557788886655553377ffffffffffffffffffffff
+ffffffffffffffffffffffee9988888866555599ffffffffffffffffffffffff
+ffffffffffffffffffffffffffbb88886655bbffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffdd8866ccffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffeeddffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.png b/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.png
new file mode 100644
index 0000000000..dd3168e5c8
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.sng b/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.sng
new file mode 100644
index 0000000000..76989fa9ee
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn2c16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 0; green: 0; blue: 65535;}
+tRNS {
+ red: 65535; green: 65535; blue: 65535;
+}
+IMAGE {
+ pixels hex
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e3e3e3e3e3e3 c9c9c9c9c9c9 f1f1f1f1f1f1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e8e8e8e8e8e8 b5b5b5b5b5b5 7e7e7e7e7e7e 656565656565 6e6e52525252 7e7e2e2e2e2e a6a643434343 c7c790909090 ebebdddddddd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff eeeeeeeeeeee bfbfbfbfbfbf 898989898989 676767676767 6b6b5d5d5d5d 7a7a39393939 8a8a12121212 8d8d00010000 858500000000 777700000000 848400000000 9a9a01010101 a2a22d2d2d2d bfbf7d7d7d7d ddddd0d0d0d0 fcfcfcfcfcfc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f2f2f2f2f2f2 c4c4c4c4c4c4 959595959595 727272727272 6f6f6b6b6b6b 777744444444 87871e1e1e1e 959501010101 9f9f00010000 919100000000 808000010000 72720c0c0c0c 61612d2d2d2d 53530e0e0e0e 505000000000 595900010000 858500000000 929206060606 7a7a66666666 a0a0a0a0a0a0 cfcfcfcfcfcf f8f8f8f8f8f8 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f7f7f7f7f7f7 cacacacacaca 9a9a9a9a9a9a 767676767676 737373737373 7c7c5d5d5d5d 87872e2e2e2e 939307070707 9e9e00010000 a9a900000000 b0b000000000 c9c900000000 cfcf00000000 b9b900010000 a2a201010101 8c8c19191919 85852a2a2a2a 7f7f13131313 818100010000 969600000000 8f8f00000000 6b6b53535353 6e6e6e6e6e6e 737373737373 767676767676 9b9b9b9b9b9b c4c4c4c4c4c4 eeeeeeeeeeee ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff cccccccccccc 7f7f7f7f7f7f 767676767676 757575757575 757575757575 96962f2f2f2f b8b800010000 b4b400000000 b6b600010000 adad0c0c0c0c 94943a3a3a3a 929250505050 b9b923232323 d6d602020202 e2e200010000 efef00000000 e7e700000000 dada00000000 cfcf00010000 baba00000000 7d7d01010101 6f6f6b6b6b6b 757575757575 757575757575 757575757575 757575757575 6a6a6a6a6a6a 9a9a9a9a9a9a ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff dcdcdcdcdcdc 858585858585 888888888888 848484848484 7b7b7b7b7b7b 858554545454 b7b713131313 a9a91d1d1d1d 8d8d4f4f4f4f 787875757575 777777777777 777777777777 777777777777 81816b6b6b6b aaaa41414141 d6d620202020 ecec10101010 e9e90c0c0c0c d0d012121212 a5a528282828 7b7b58585858 777777777777 777777777777 777777777777 707070707070 5c5c5c5c5c5c 525252525252 bdbdbdbdbdbd ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff eaeaeaeaeaea 848484848484 818181818181 858588888585 8e8e8e8e8e8e 898989898989 7f7f7f7f7f7f 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 767676767676 636363636363 545454545454 505050505050 4c4c4c4c4c4c e6e6e6e6e6e6 ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f8f8f8f8f8f8 7f7f84847f7f 252597972525 0404a5a50404 3939a4a43939 8b8b94948b8b 939393939393 8f8f8f8f8f8f 838383838383 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7a7a7a7a7a7a 7a7a7a7a7a7a 797979797979 6a6a6a6a6a6a 575757575757 505050505050 4c4c4c4c4c4c 494949494949 595959595959 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 8a8a8a8a8a8a 0101b3b30101 0000c6c60001 0000f2f20000 5959b6b65959 929292929292 959595959595 979797979797 949494949494 878787878787 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 717171717171 5a5a5a5a6060 282828288585 040404049393 0c0c0c0c7878 282828285858 464646464a4a 828282828282 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 929292929292 0c0cabab0c0c 0000bdbd0001 0000f4f40000 2020dddd2020 919191919191 949494949494 979797979797 999999999999 9b9b9b9b9b9b 999999999999 8b8b8b8b8b8b 7f7f7f7f7f7f 7e7e7e7e7e7e 7e7e7e7e7e7e 7d7d7d7d7d7d 777777777777 626262626262 535353536060 12121212bebe 00010000cccc 000000009292 000000016969 000000006767 2a2a2a2a5555 acacacacacac ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 949494949494 1616a1a11616 0000b4b40001 0000e2e20000 0000f4f40000 7676a2a27676 939393939393 8d8d97978d8d 46469e9e4646 4646a7a74646 8e8e9e9e8e8e 9e9e9e9e9e9e 9c9c9c9c9c9c 8e8e8e8e8e8e 7e7e7e7e7e7e 6a6a6a6a6a6a 5a5a5a5a5a5a 575757575a5a 18181818cdcd 00010000f0f0 00000000a0a0 020202026060 010101013d3d 000100006161 1d1d1d1d5959 d6d6d6d6d6d6 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff a4a4a4a4a4a4 212198982121 0000aaaa0001 0000c8c80000 0000f4f40000 3b3bcaca3b3b 929292929292 4a4aacac4a4a 0001bcbc0000 0000a9a90000 2f2f9a9a2f2f 9d9d9d9d9d9d 9f9f9f9f9f9f a0a0a0a0a0a0 7a7a7a7a7a7a 5a5a5a5a5a5a 595959595959 31313131a1a1 00010000ffff 00000000c6c6 030303035b5b 191919192424 0c0c0c0c1515 0c0c0c0c5555 3b3b3b3b5353 fbfbfbfbfbfb ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff b6b6b6b6b6b6 2b2b8f8f2b2b 0000a2a20001 0000adad0000 0000ebeb0000 0707eded0707 898995958989 4343a7a74343 0001c9c90000 000099990000 383895953838 9c9c9c9c9c9c 9e9e9e9e9e9e 9f9f9f9f9f9f 747474747474 595959595959 505050506767 05050505f5f5 00010000f0f0 030303037070 383838384646 484848484848 161616163939 2b2b2b2b5555 727272727272 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff c7c7c7c7c7c7 343486863434 0000b1b10001 00008d8d0000 0000d2d20000 0000f3f30000 4c4c9b9b4c4c 3b3b9e9e3b3b 0001c7c70000 000098980000 3d3d94943d3d 9b9b9b9b9b9b 9d9d9d9d9d9d 9e9e9e9e9e9e 6e6e6e6e6e6e 595959595959 2b2b2b2badad 00000001ffff 00000000a6a6 252525255959 434343434f4f 161616167e7e 000000019f9f 010101018e8e 9c9c9c9ca1a1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff d8d8d8d8d8d8 3e3e7d7d3e3e 0000b1b10001 00007b7b0000 0000b8b80000 0000f1f10000 17178b8b1717 3b3b9c9c3b3b 0001c6c60000 000097970000 3d3d93933d3d 9a9a9a9a9a9a 9b9b9b9b9b9b 9d9d9d9d9d9d 676767676767 575757575959 09090909eeee 00000001f0f0 040404046b6b 333333335a5a 070707079090 000000009e9e 000000017c7c 0d0d0d0d5d5d c7c7c7c7c7c7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff eaeaeaeaeaea 474774744747 0000adad0001 000085850000 090998980909 0000dcdc0000 0000a7a70000 232398982323 0001c3c30000 000096960000 3f3f92923f3f 989898989898 9a9a9a9a9a9a 9c9c9c9c9c9c 616161616161 424242427f7f 00010000ffff 00000001b9b9 1a1a1a1a5d5d 161616164949 000000007b7b 000000006b6b 000000016b6b 1c1c1c1c5656 f4f4f4f4f4f4 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc 50506c6c5050 0000a9a90001 000095950000 2d2d77772d2d 0000c1c10000 0000c5c50000 010193930101 0001c1c10000 000090900000 4b4b91914b4b 979797979797 999999999999 9a9a9a9a9a9a 5a5a5a5a5a5a 2b2b2b2ba4a4 00010000f6f6 000000018686 2f2f2f2f5353 191919193030 020202026363 000000007373 000000019b9b 4d4d4d4d7070 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 686873736868 0000a4a40001 0000a4a40000 3e3e65653e3e 1414a5a51414 0000d4d40000 00008b8b0001 0000bfbf0000 00008e8e0000 4a4a90904a4a 959595959595 979797979797 969696969696 575757575757 1a1a1a1ab5b5 00010000dede 000000016868 3f3f3f3f4b4b 2b2b2b2b2b2b 0c0c0c0c6d6d 00000000b3b3 000000016b6b 868686869292 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 8c8c8c8c8c8c 05059e9e0505 0001b0b00000 343466663434 404085854040 0000caca0000 000097970001 0000bcbc0000 00008c8c0000 49498e8e4949 939393939393 959595959595 8f8f8f8f8f8f 565656565656 0f0f0f0fb7b7 00010000b9b9 030303036666 474747474747 2f2f2f2f6464 00010000a2a2 000000009d9d 090909095858 c5c5c5c5c5c5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff fafafafafafa 9090b0b09090 343485853434 616164646161 63636a6a6363 0606afaf0606 0000aeae0001 0000b9b90000 00008b8b0000 53538d8d5353 919191919191 939393939393 898989898989 555555555555 0a0a0a0aa8a8 000100009d9d 070707076363 343434345c5c 040404049b9b 00010000b1b1 1a1a1a1a4d4d b5b5b5b5bbbb ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d0d0d0d0d0d0 6d6d6d6d6d6d 656565656565 2d2d8f8f2d2d 0000b2b20001 0000b6b60000 000089890000 55558b8b5555 8f8f8f8f8f8f 919191919191 818181818181 555555555555 151515157e7e 000100008484 010101016565 010101018484 000100009191 1c1c1c1c6e6e cecececed0d0 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ecececececec 868686868686 585870705858 0000afaf0001 0000b3b30000 000088880000 535389895353 8d8d8d8d8d8d 8f8f8f8f8f8f 7a7a7a7a7a7a 545454545454 2c2c2c2c4949 020202026b6b 000000016464 000000006363 292929297474 dfdfdfdfe5e5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc aaaaaaaaaaaa 212198982121 0001b0b00000 000086860000 575787875757 8b8b8b8b8b8b 8d8d8d8d8d8d 747474747474 535353535353 3d3d3d3d3d3d 1a1a1a1a2323 0d0d0d0d4343 474747477272 ededededefef ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d1d1d6d6d1d1 38389b9b3838 2d2d77772d2d 7d7d81817d7d 888888888888 8b8b8b8b8b8b 6d6d6d6d6d6d 525252525252 4f4f4f4f4f4f 373737373737 777777777777 fafafafafafa ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff efefefefefef a0a0a0a0a0a0 838383838383 868686868686 888888888888 676767676767 515151515151 505050505050 a0a0a0a0a0a0 fdfdfdfdfdfd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fefefefefefe c0c0c0c0c0c0 858585858585 868686868686 616161616161 525252525252 b7b7b7b7b7b7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff dededededede 909090909090 656565656565 cccccccccccc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f5f5f5f5f5f5 e3e3e3e3e3e3 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.png b/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.png
new file mode 100644
index 0000000000..0ede3574db
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.sng
new file mode 100644
index 0000000000..429d99b417
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbbn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbbn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ ( 0, 0, 0) # rgb = (0x00,0x00,0x00) grey0
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.png b/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.png
new file mode 100644
index 0000000000..85cec395c0
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.sng b/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.sng
new file mode 100644
index 0000000000..0f5621dc06
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbgn2c16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbgn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 0; green: 65535; blue: 0;}
+tRNS {
+ red: 65535; green: 65535; blue: 65535;
+}
+IMAGE {
+ pixels hex
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e3e3e3e3e3e3 c9c9c9c9c9c9 f1f1f1f1f1f1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e8e8e8e8e8e8 b5b5b5b5b5b5 7e7e7e7e7e7e 656565656565 6e6e52525252 7e7e2e2e2e2e a6a643434343 c7c790909090 ebebdddddddd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff eeeeeeeeeeee bfbfbfbfbfbf 898989898989 676767676767 6b6b5d5d5d5d 7a7a39393939 8a8a12121212 8d8d00010000 858500000000 777700000000 848400000000 9a9a01010101 a2a22d2d2d2d bfbf7d7d7d7d ddddd0d0d0d0 fcfcfcfcfcfc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f2f2f2f2f2f2 c4c4c4c4c4c4 959595959595 727272727272 6f6f6b6b6b6b 777744444444 87871e1e1e1e 959501010101 9f9f00010000 919100000000 808000010000 72720c0c0c0c 61612d2d2d2d 53530e0e0e0e 505000000000 595900010000 858500000000 929206060606 7a7a66666666 a0a0a0a0a0a0 cfcfcfcfcfcf f8f8f8f8f8f8 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f7f7f7f7f7f7 cacacacacaca 9a9a9a9a9a9a 767676767676 737373737373 7c7c5d5d5d5d 87872e2e2e2e 939307070707 9e9e00010000 a9a900000000 b0b000000000 c9c900000000 cfcf00000000 b9b900010000 a2a201010101 8c8c19191919 85852a2a2a2a 7f7f13131313 818100010000 969600000000 8f8f00000000 6b6b53535353 6e6e6e6e6e6e 737373737373 767676767676 9b9b9b9b9b9b c4c4c4c4c4c4 eeeeeeeeeeee ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff cccccccccccc 7f7f7f7f7f7f 767676767676 757575757575 757575757575 96962f2f2f2f b8b800010000 b4b400000000 b6b600010000 adad0c0c0c0c 94943a3a3a3a 929250505050 b9b923232323 d6d602020202 e2e200010000 efef00000000 e7e700000000 dada00000000 cfcf00010000 baba00000000 7d7d01010101 6f6f6b6b6b6b 757575757575 757575757575 757575757575 757575757575 6a6a6a6a6a6a 9a9a9a9a9a9a ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff dcdcdcdcdcdc 858585858585 888888888888 848484848484 7b7b7b7b7b7b 858554545454 b7b713131313 a9a91d1d1d1d 8d8d4f4f4f4f 787875757575 777777777777 777777777777 777777777777 81816b6b6b6b aaaa41414141 d6d620202020 ecec10101010 e9e90c0c0c0c d0d012121212 a5a528282828 7b7b58585858 777777777777 777777777777 777777777777 707070707070 5c5c5c5c5c5c 525252525252 bdbdbdbdbdbd ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff eaeaeaeaeaea 848484848484 818181818181 858588888585 8e8e8e8e8e8e 898989898989 7f7f7f7f7f7f 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 767676767676 636363636363 545454545454 505050505050 4c4c4c4c4c4c e6e6e6e6e6e6 ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f8f8f8f8f8f8 7f7f84847f7f 252597972525 0404a5a50404 3939a4a43939 8b8b94948b8b 939393939393 8f8f8f8f8f8f 838383838383 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7a7a7a7a7a7a 7a7a7a7a7a7a 797979797979 6a6a6a6a6a6a 575757575757 505050505050 4c4c4c4c4c4c 494949494949 595959595959 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 8a8a8a8a8a8a 0101b3b30101 0000c6c60001 0000f2f20000 5959b6b65959 929292929292 959595959595 979797979797 949494949494 878787878787 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 717171717171 5a5a5a5a6060 282828288585 040404049393 0c0c0c0c7878 282828285858 464646464a4a 828282828282 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 929292929292 0c0cabab0c0c 0000bdbd0001 0000f4f40000 2020dddd2020 919191919191 949494949494 979797979797 999999999999 9b9b9b9b9b9b 999999999999 8b8b8b8b8b8b 7f7f7f7f7f7f 7e7e7e7e7e7e 7e7e7e7e7e7e 7d7d7d7d7d7d 777777777777 626262626262 535353536060 12121212bebe 00010000cccc 000000009292 000000016969 000000006767 2a2a2a2a5555 acacacacacac ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 949494949494 1616a1a11616 0000b4b40001 0000e2e20000 0000f4f40000 7676a2a27676 939393939393 8d8d97978d8d 46469e9e4646 4646a7a74646 8e8e9e9e8e8e 9e9e9e9e9e9e 9c9c9c9c9c9c 8e8e8e8e8e8e 7e7e7e7e7e7e 6a6a6a6a6a6a 5a5a5a5a5a5a 575757575a5a 18181818cdcd 00010000f0f0 00000000a0a0 020202026060 010101013d3d 000100006161 1d1d1d1d5959 d6d6d6d6d6d6 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff a4a4a4a4a4a4 212198982121 0000aaaa0001 0000c8c80000 0000f4f40000 3b3bcaca3b3b 929292929292 4a4aacac4a4a 0001bcbc0000 0000a9a90000 2f2f9a9a2f2f 9d9d9d9d9d9d 9f9f9f9f9f9f a0a0a0a0a0a0 7a7a7a7a7a7a 5a5a5a5a5a5a 595959595959 31313131a1a1 00010000ffff 00000000c6c6 030303035b5b 191919192424 0c0c0c0c1515 0c0c0c0c5555 3b3b3b3b5353 fbfbfbfbfbfb ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff b6b6b6b6b6b6 2b2b8f8f2b2b 0000a2a20001 0000adad0000 0000ebeb0000 0707eded0707 898995958989 4343a7a74343 0001c9c90000 000099990000 383895953838 9c9c9c9c9c9c 9e9e9e9e9e9e 9f9f9f9f9f9f 747474747474 595959595959 505050506767 05050505f5f5 00010000f0f0 030303037070 383838384646 484848484848 161616163939 2b2b2b2b5555 727272727272 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff c7c7c7c7c7c7 343486863434 0000b1b10001 00008d8d0000 0000d2d20000 0000f3f30000 4c4c9b9b4c4c 3b3b9e9e3b3b 0001c7c70000 000098980000 3d3d94943d3d 9b9b9b9b9b9b 9d9d9d9d9d9d 9e9e9e9e9e9e 6e6e6e6e6e6e 595959595959 2b2b2b2badad 00000001ffff 00000000a6a6 252525255959 434343434f4f 161616167e7e 000000019f9f 010101018e8e 9c9c9c9ca1a1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff d8d8d8d8d8d8 3e3e7d7d3e3e 0000b1b10001 00007b7b0000 0000b8b80000 0000f1f10000 17178b8b1717 3b3b9c9c3b3b 0001c6c60000 000097970000 3d3d93933d3d 9a9a9a9a9a9a 9b9b9b9b9b9b 9d9d9d9d9d9d 676767676767 575757575959 09090909eeee 00000001f0f0 040404046b6b 333333335a5a 070707079090 000000009e9e 000000017c7c 0d0d0d0d5d5d c7c7c7c7c7c7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff eaeaeaeaeaea 474774744747 0000adad0001 000085850000 090998980909 0000dcdc0000 0000a7a70000 232398982323 0001c3c30000 000096960000 3f3f92923f3f 989898989898 9a9a9a9a9a9a 9c9c9c9c9c9c 616161616161 424242427f7f 00010000ffff 00000001b9b9 1a1a1a1a5d5d 161616164949 000000007b7b 000000006b6b 000000016b6b 1c1c1c1c5656 f4f4f4f4f4f4 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc 50506c6c5050 0000a9a90001 000095950000 2d2d77772d2d 0000c1c10000 0000c5c50000 010193930101 0001c1c10000 000090900000 4b4b91914b4b 979797979797 999999999999 9a9a9a9a9a9a 5a5a5a5a5a5a 2b2b2b2ba4a4 00010000f6f6 000000018686 2f2f2f2f5353 191919193030 020202026363 000000007373 000000019b9b 4d4d4d4d7070 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 686873736868 0000a4a40001 0000a4a40000 3e3e65653e3e 1414a5a51414 0000d4d40000 00008b8b0001 0000bfbf0000 00008e8e0000 4a4a90904a4a 959595959595 979797979797 969696969696 575757575757 1a1a1a1ab5b5 00010000dede 000000016868 3f3f3f3f4b4b 2b2b2b2b2b2b 0c0c0c0c6d6d 00000000b3b3 000000016b6b 868686869292 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 8c8c8c8c8c8c 05059e9e0505 0001b0b00000 343466663434 404085854040 0000caca0000 000097970001 0000bcbc0000 00008c8c0000 49498e8e4949 939393939393 959595959595 8f8f8f8f8f8f 565656565656 0f0f0f0fb7b7 00010000b9b9 030303036666 474747474747 2f2f2f2f6464 00010000a2a2 000000009d9d 090909095858 c5c5c5c5c5c5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff fafafafafafa 9090b0b09090 343485853434 616164646161 63636a6a6363 0606afaf0606 0000aeae0001 0000b9b90000 00008b8b0000 53538d8d5353 919191919191 939393939393 898989898989 555555555555 0a0a0a0aa8a8 000100009d9d 070707076363 343434345c5c 040404049b9b 00010000b1b1 1a1a1a1a4d4d b5b5b5b5bbbb ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d0d0d0d0d0d0 6d6d6d6d6d6d 656565656565 2d2d8f8f2d2d 0000b2b20001 0000b6b60000 000089890000 55558b8b5555 8f8f8f8f8f8f 919191919191 818181818181 555555555555 151515157e7e 000100008484 010101016565 010101018484 000100009191 1c1c1c1c6e6e cecececed0d0 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ecececececec 868686868686 585870705858 0000afaf0001 0000b3b30000 000088880000 535389895353 8d8d8d8d8d8d 8f8f8f8f8f8f 7a7a7a7a7a7a 545454545454 2c2c2c2c4949 020202026b6b 000000016464 000000006363 292929297474 dfdfdfdfe5e5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc aaaaaaaaaaaa 212198982121 0001b0b00000 000086860000 575787875757 8b8b8b8b8b8b 8d8d8d8d8d8d 747474747474 535353535353 3d3d3d3d3d3d 1a1a1a1a2323 0d0d0d0d4343 474747477272 ededededefef ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d1d1d6d6d1d1 38389b9b3838 2d2d77772d2d 7d7d81817d7d 888888888888 8b8b8b8b8b8b 6d6d6d6d6d6d 525252525252 4f4f4f4f4f4f 373737373737 777777777777 fafafafafafa ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff efefefefefef a0a0a0a0a0a0 838383838383 868686868686 888888888888 676767676767 515151515151 505050505050 a0a0a0a0a0a0 fdfdfdfdfdfd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fefefefefefe c0c0c0c0c0c0 858585858585 868686868686 616161616161 525252525252 b7b7b7b7b7b7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff dededededede 909090909090 656565656565 cccccccccccc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f5f5f5f5f5f5 e3e3e3e3e3e3 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.png b/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.png
new file mode 100644
index 0000000000..8cf2e6fb6a
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.sng
new file mode 100644
index 0000000000..0e3b7bd77d
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbgn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbgn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ (170,170,170) # rgb = (0xaa,0xaa,0xaa)
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.png b/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.png
new file mode 100644
index 0000000000..5cca0d6210
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.sng b/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.sng
new file mode 100644
index 0000000000..9569bdaf78
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbrn2c08.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbrn2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 255; green: 0; blue: 0;}
+tRNS {
+ red: 255; green: 255; blue: 255;
+}
+IMAGE {
+ pixels hex
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e3e3e3 c9c9c9 f1f1f1 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee ffffff ffffff
+ffffff ffffff cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a ffffff ffffff
+ffffff ffffff dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd ffffff ffffff
+ffffff ffffff eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 ffffff ffffff
+ffffff ffffff f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 ffffff ffffff ffffff
+ffffff ffffff ffffff 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 ffffff ffffff ffffff
+ffffff ffffff ffffff 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac ffffff ffffff ffffff
+ffffff ffffff ffffff 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 ffffff ffffff ffffff
+ffffff ffffff ffffff a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb ffffff ffffff ffffff
+ffffff ffffff ffffff b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff dedede 909090 656565 cccccc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff f5f5f5 e3e3e3 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.png b/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.png
new file mode 100644
index 0000000000..99bdeed2b3
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.sng b/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.sng
new file mode 100644
index 0000000000..3fca307274
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbwn0g16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbwn0g16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale;
+}
+gAMA {1.0000}
+bKGD {gray: 65535;}
+tRNS {
+ gray: 65535;
+}
+IMAGE {
+ pixels hex
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff e3e3 c9c9 f1f1 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff e8e8 b5b5 7e7e 6565 5ab9 462f 60f8 a111 e210 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff eeee bfbf 8989 6767 6190 4cba 3614 2a50 27e9 23b5 279c 2eea 5049 914b d4b7 fcfc ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff f2f2 c4c4 9595 7272 6c9e 5392 3da0 2d6a 2fb7 2b83 2669 2aa7 3cc7 22c2 1801 1ab5 27e9 3008 6c66 a0a0 cfcf f8f8 ffff ffff ffff ffff ffff
+ffff ffff f7f7 caca 9a9a 7676 7373 66aa 48e3 3109 2f6a 32b6 34d0 3c50 3e1d 3784 3151 3b9b 4578 337b 26b6 2d03 2ae9 5a87 6e6e 7373 7676 9b9b c4c4 eeee ffff ffff
+ffff ffff cccc 7f7f 7676 7575 7575 4e17 3737 3603 369d 3c5c 553c 641e 5026 419f 43d1 47b7 4551 416a 3e1e 37d0 2636 6c9e 7575 7575 7575 7575 6a6a 9a9a ffff ffff
+ffff ffff dcdc 8585 8888 8484 7b7b 6308 4449 471f 61ea 765b 7777 7777 7777 7205 60c3 56bd 5214 4e5d 4b15 4daa 62d9 7777 7777 7777 7070 5c5c 5252 bdbd ffff ffff
+ffff ffff eaea 8484 8181 8749 8e8e 8989 7f7f 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7676 6363 5454 5050 4c4c e6e6 ffff ffff
+ffff ffff f8f8 8271 6847 62d4 783c 90d8 9393 8f8f 8383 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7a7a 7a7a 7979 6a6a 5757 5050 4c4c 4949 5959 ffff ffff ffff
+ffff ffff ffff 8a8a 69d4 749a 8e83 901d 9292 9595 9797 9494 8787 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7171 5b0b 32d9 1474 1876 2dac 46bc 8282 ffff ffff ffff
+ffff ffff ffff 9292 69ae 6f4d 8fb1 8f6d 9191 9494 9797 9999 9b9b 9999 8b8b 7f7f 7e7e 7e7e 7d7d 7777 6262 54d2 25d7 1773 10c8 0c12 0bd7 2f1b acac ffff ffff ffff
+ffff ffff ffff 9494 67f1 6a00 8517 8fb1 905f 9393 9371 7a19 7f65 97fa 9e9e 9c9c 8e8e 7e7e 6a6a 5a5a 57af 2ce6 1b97 1264 0cd0 07e7 0b27 2403 d6d6 ffff ffff ffff
+ffff ffff ffff a4a4 6735 641d 75c7 8fb1 8f71 9292 8400 6eb6 6386 6e32 9d9d 9f9f a0a0 7a7a 5a5a 5959 3e11 1d50 16c2 0d21 1a5d 0d15 1470 3dfd fbfb ffff ffff ffff
+ffff ffff ffff b6b6 660f 5f67 65e1 8a64 8e79 909a 7e27 765e 5a1a 6efc 9c9c 9e9e 9f9f 7474 5959 52f5 209b 1b97 0f8a 39d4 4848 1a1c 2fff 7272 ffff ffff ffff ffff
+ffff ffff ffff c7c7 647e 683c 5309 7bab 8f1a 7ad2 7588 7531 5983 7079 9b9b 9d9d 9e9e 6e6e 5959 3a1c 1d50 1315 2b1f 44a4 220a 1247 1136 9d2f ffff ffff ffff ffff
+ffff ffff ffff d8d8 6358 683c 486f 6c5b 8dec 5b67 745a 749a 58ec 6fe2 9a9a 9b9b 9d9d 6767 5792 235c 1b97 0fdb 37af 16c6 1229 0e41 163f c7c7 ffff ffff ffff ffff
+ffff ffff ffff eaea 61c7 65e1 4e53 5d3f 818e 6258 6809 72d6 5855 7020 9898 9a9a 9c9c 6161 4945 1d50 1544 21ce 1bf3 0e23 0c4d 0c4d 22c7 f4f4 ffff ffff ffff ffff
+ffff ffff ffff fcfc 60cd 6386 57bf 58c1 71a8 7403 56fb 71a8 54cd 7484 9797 9999 9a9a 5a5a 3914 1c47 0f68 3352 1bbe 0d28 0d38 11d2 5153 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff 6ee2 6094 6094 5535 6978 7cd8 51db 707a 539f 7383 9595 9797 9696 5757 2beb 1985 0bf5 40a0 2b2b 1732 1493 0c4d 87e7 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff 8c8c 5f1f 67a5 51a6 68e2 76f5 58ec 6eb6 5272 71eb 9393 9595 8f8f 5656 225f 1544 0e64 4747 3547 129f 120c 121e c5c5 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff fafa a368 63e7 6325 6782 698c 6678 6cf2 51db 757b 9191 9393 8989 5555 1c33 120c 119a 38cd 155f 1459 1ff7 b666 ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff d0d0 6d6d 6565 66e3 68d3 6b2e 50ae 7522 8f8f 9191 8181 5555 2127 0f2d 0c80 1010 10ab 2589 cf09 ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ecec 8686 667a 670e 6969 5017 7320 8d8d 8f8f 7a7a 5454 2f81 0e14 0b7f 0b61 31c8 e090 ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff fcfc aaaa 6735 67a5 4ee9 739b 8b8b 8d8d 7474 5353 3d3d 1b23 1342 4c38 ee28 ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff d4c3 7285 58c1 7fd8 8888 8b8b 6d6d 5252 4f4f 3737 7777 fafa ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff efef a0a0 8383 8686 8888 6767 5151 5050 a0a0 fdfd ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff fefe c0c0 8585 8686 6161 5252 b7b7 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff dede 9090 6565 cccc ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff f5f5 e3e3 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.png b/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.png
new file mode 100644
index 0000000000..eacab7a144
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.sng
new file mode 100644
index 0000000000..7b5aff60d4
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbwn3p08.sng
@@ -0,0 +1,291 @@
+#SNG: from ftbwn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+bKGD {index: 0}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.png b/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.png
new file mode 100644
index 0000000000..656db0989a
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.sng
new file mode 100644
index 0000000000..5d61987330
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftbyn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbyn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ (255,255, 0) # rgb = (0xff,0xff,0x00) yellow1
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.png b/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.png
new file mode 100644
index 0000000000..333465fcdc
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.sng b/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.sng
new file mode 100644
index 0000000000..c8abd33893
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n0g08.sng
@@ -0,0 +1,41 @@
+#SNG: from ftp0n0g08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7fe3c9f17f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7fe8b57e655a4661a1e17f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7feebf8967614d362a2824282f5091d4fc7f7f7f7f7f7f7f7f
+7f7f7f7f7ff2c495726c533e2e302c272b3d23181b28306ca0cff87f7f7f7f7f
+7f7ff7ca9a76736649313033353c3e38313c4533272d2b5a6e73769bc4ee7f7f
+7f7fcc7f7675754e3736373c55645042444845423e38266c757575756a9a7f7f
+7f7fdc8588847b6344476276777777726157524e4b4e63777777705c52bd7f7f
+7f7fea8481878e897f797979797979797979797979797979766354504ce67f7f
+7f7ff88268627890938f837b7b7b7b7b7b7b7b7b7a7a796a57504c49597f7f7f
+7f7f7f8a69748e8f92959794877c7c7c7c7c7c7c7c715b3314182d46827f7f7f
+7f7f7f92696f8f8f919497999b998b7f7e7e7d7762542517110c0c2fac7f7f7f
+7f7f7f946769848f9093937a7f979e9c8e7e6a5a572d1b120d080b24d67f7f7f
+7f7f7fa46764758f8f92836e636e9d9fa07a5a593e1d160d1a0d143efb7f7f7f
+7f7f7fb6665f658a8e907e765a6e9c9e9f745953201b0f3a481a30727f7f7f7f
+7f7f7fc76468537b8e7a757559709b9d9e6e593a1d132b442212119d7f7f7f7f
+7f7f7fd86368486c8d5b7474586f9a9b9d6757231b103717120e16c77f7f7f7f
+7f7f7fea61654e5d816268725870989a9c61491d15221c0e0c0c23f47f7f7f7f
+7f7f7ffc6063575871735771547497999a5a391c0f331c0d0d12517f7f7f7f7f
+7f7f7f7f6e606055697c51705373959796572c190c402b17140c877f7f7f7f7f
+7f7f7f7f8c5f67516876586e527193958f5622150e4735121212c57f7f7f7f7f
+7f7f7f7ffaa363636769666c5175919389551c121139151420b67f7f7f7f7f7f
+7f7f7f7f7f7fd06d6566686b50758f918155210f0c101025ce7f7f7f7f7f7f7f
+7f7f7f7f7f7f7fec8666676950738d8f7a542f0e0b0b31e07f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7ffcaa67674f738b8d74533d1b134ced7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7fd472587f888b6d524f3777fa7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7fefa0838688675150a0fd7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7ffec085866152b77f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7fde9065cc7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7ff5e37f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.png b/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.png
new file mode 100644
index 0000000000..fc6e42cb42
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.sng b/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.sng
new file mode 100644
index 0000000000..d41c7eb36c
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n2c08.sng
@@ -0,0 +1,41 @@
+#SNG: from ftp0n2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e3e3e3 c9c9c9 f1f1f1 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee 7f7f7f 7f7f7f
+7f7f7f 7f7f7f cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a 7f7f7f 7f7f7f
+7f7f7f 7f7f7f dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd 7f7f7f 7f7f7f
+7f7f7f 7f7f7f eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 7f7f7f 7f7f7f
+7f7f7f 7f7f7f f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f dedede 909090 656565 cccccc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f5f5f5 e3e3e3 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.png b/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.png
new file mode 100644
index 0000000000..69a69e5872
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.sng
new file mode 100644
index 0000000000..f1f8448d00
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp0n3p08.sng
@@ -0,0 +1,288 @@
+#SNG: from ftp0n3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+IMAGE {
+ pixels hex
+2323232323232323232323232323232323232323232323232323232323232323
+2323232323232323232323232323232323232323232323232323232323232323
+2323232323232323232323232323e0ea66232323232323232323232323232323
+2323232323232323232323de02a336e43903f4f0232323232323232323232323
+232323232323232369ef1a358680062eb017b0ab7af459502323232323232323
+2323232323667c0ea9cc803979937917a03a878787b0e2ae8ae75c2323232323
+23235cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c692323
+23237823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e2323
+2323e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef2323
+23236c9f229d981a23282828282828282828282828282828a7b445c3c8de2323
+23235ca249d63d140f139f272727272727272727a5a528af44c3c8ce43232323
+2323239a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1232323
+232323965b58b53811940d0b090b1823a3a3252ab4d24c269957571088232323
+232323946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877232323
+23232388c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950232323
+23232302bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a923232323
+2323237b47636ec441b23d4edb3f09078bac4315f340ec855a82995f23232323
+23232359bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b23232323
+2323236cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086023232323
+23232350bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e62323232323
+23232323add6d6bf61c16f566eb20e0d924475bd578572001e6d342323232323
+2323232316d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b2323232323
+23232323550c47b3365bd45d6f33110f1a4575cbf2c0521e0802232323232323
+232323232323e7ac36be625e7031131122455a0a2f0a9900e723232323232323
+232323232323236a9e37d36270331613a545f181e53032e82323232323232323
+23232323232323235088c5d371311816a8464b7374ee89232323232323232323
+2323232323232323232377b654a29b18acc24a722a5523232323232323232323
+2323232323232323232323d78a9f9e9b3548c38ac92323232323232323232323
+232323232323232323232323c6ef1f9e3cc20223232323232323232323232323
+2323232323232323232323232323e89736782323232323232323232323232323
+23232323232323232323232323232360e0232323232323232323232323232323
+2323232323232323232323232323232323232323232323232323232323232323
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.png b/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.png
new file mode 100644
index 0000000000..a6c9f35a86
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.sng b/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.sng
new file mode 100644
index 0000000000..2d179e2e99
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/ftp1n3p08.sng
@@ -0,0 +1,290 @@
+#SNG: from ftp1n3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
index df23270ee9..dd87d81629 100644
--- a/libgo/go/image/png/writer.go
+++ b/libgo/go/image/png/writer.go
@@ -420,8 +420,11 @@ func writeImage(w io.Writer, m image.Image, cb int, level int) error {
}
// Apply the filter.
+ // Skip filter for NoCompression and paletted images (cbP8) as
+ // "filters are rarely useful on palette images" and will result
+ // in larger files (see http://www.libpng.org/pub/png/book/chapter09.html).
f := ftNone
- if level != zlib.NoCompression {
+ if level != zlib.NoCompression && cb != cbP8 {
f = filter(&cr, pr, bpp)
}
diff --git a/libgo/go/image/testdata/video-001.progressive.truncated.jpeg b/libgo/go/image/testdata/video-001.progressive.truncated.jpeg
new file mode 100644
index 0000000000..b5be8bc763
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.progressive.truncated.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.progressive.truncated.png b/libgo/go/image/testdata/video-001.progressive.truncated.png
new file mode 100644
index 0000000000..baf1981226
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.progressive.truncated.png
Binary files differ
diff --git a/libgo/go/index/suffixarray/example_test.go b/libgo/go/index/suffixarray/example_test.go
new file mode 100644
index 0000000000..a23a58026b
--- /dev/null
+++ b/libgo/go/index/suffixarray/example_test.go
@@ -0,0 +1,24 @@
+// 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 suffixarray_test
+
+import (
+ "fmt"
+ "index/suffixarray"
+)
+
+func ExampleIndex_Lookup() {
+ index := suffixarray.New([]byte("banana"))
+ offsets := index.Lookup([]byte("ana"), -1)
+ for _, off := range offsets {
+ fmt.Println(off)
+ }
+
+ // Unordered output:
+ // 1
+ // 3
+}
diff --git a/libgo/go/internal/nettrace/nettrace.go b/libgo/go/internal/nettrace/nettrace.go
new file mode 100644
index 0000000000..de3254df58
--- /dev/null
+++ b/libgo/go/internal/nettrace/nettrace.go
@@ -0,0 +1,45 @@
+// 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 nettrace contains internal hooks for tracing activity in
+// the net package. This package is purely internal for use by the
+// net/http/httptrace package and has no stable API exposed to end
+// users.
+package nettrace
+
+// TraceKey is a context.Context Value key. Its associated value should
+// be a *Trace struct.
+type TraceKey struct{}
+
+// LookupIPAltResolverKey is a context.Context Value key used by tests to
+// specify an alternate resolver func.
+// It is not exposed to outsider users. (But see issue 12503)
+// The value should be the same type as lookupIP:
+// func lookupIP(ctx context.Context, host string) ([]IPAddr, error)
+type LookupIPAltResolverKey struct{}
+
+// Trace contains a set of hooks for tracing events within
+// the net package. Any specific hook may be nil.
+type Trace struct {
+ // DNSStart is called with the hostname of a DNS lookup
+ // before it begins.
+ DNSStart func(name string)
+
+ // DNSDone is called after a DNS lookup completes (or fails).
+ // The coalesced parameter is whether singleflight de-dupped
+ // the call. The addrs are of type net.IPAddr but can't
+ // actually be for circular dependency reasons.
+ DNSDone func(netIPs []interface{}, coalesced bool, err error)
+
+ // 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, excluding
+ // Dials made during DNS lookups. It may also be called multiple
+ // times, like ConnectStart.
+ ConnectDone func(network, addr string, err error)
+}
diff --git a/libgo/go/internal/pprof/profile/encode.go b/libgo/go/internal/pprof/profile/encode.go
new file mode 100644
index 0000000000..6b879a84ac
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/encode.go
@@ -0,0 +1,470 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package profile
+
+import (
+ "errors"
+ "fmt"
+ "sort"
+)
+
+func (p *Profile) decoder() []decoder {
+ return profileDecoder
+}
+
+// preEncode populates the unexported fields to be used by encode
+// (with suffix X) from the corresponding exported fields. The
+// exported fields are cleared up to facilitate testing.
+func (p *Profile) preEncode() {
+ strings := make(map[string]int)
+ addString(strings, "")
+
+ for _, st := range p.SampleType {
+ st.typeX = addString(strings, st.Type)
+ st.unitX = addString(strings, st.Unit)
+ }
+
+ for _, s := range p.Sample {
+ s.labelX = nil
+ var keys []string
+ for k := range s.Label {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ vs := s.Label[k]
+ for _, v := range vs {
+ s.labelX = append(s.labelX,
+ Label{
+ keyX: addString(strings, k),
+ strX: addString(strings, v),
+ },
+ )
+ }
+ }
+ var numKeys []string
+ for k := range s.NumLabel {
+ numKeys = append(numKeys, k)
+ }
+ sort.Strings(numKeys)
+ for _, k := range numKeys {
+ vs := s.NumLabel[k]
+ for _, v := range vs {
+ s.labelX = append(s.labelX,
+ Label{
+ keyX: addString(strings, k),
+ numX: v,
+ },
+ )
+ }
+ }
+ s.locationIDX = nil
+ for _, l := range s.Location {
+ s.locationIDX = append(s.locationIDX, l.ID)
+ }
+ }
+
+ for _, m := range p.Mapping {
+ m.fileX = addString(strings, m.File)
+ m.buildIDX = addString(strings, m.BuildID)
+ }
+
+ for _, l := range p.Location {
+ for i, ln := range l.Line {
+ if ln.Function != nil {
+ l.Line[i].functionIDX = ln.Function.ID
+ } else {
+ l.Line[i].functionIDX = 0
+ }
+ }
+ if l.Mapping != nil {
+ l.mappingIDX = l.Mapping.ID
+ } else {
+ l.mappingIDX = 0
+ }
+ }
+ for _, f := range p.Function {
+ f.nameX = addString(strings, f.Name)
+ f.systemNameX = addString(strings, f.SystemName)
+ f.filenameX = addString(strings, f.Filename)
+ }
+
+ p.dropFramesX = addString(strings, p.DropFrames)
+ p.keepFramesX = addString(strings, p.KeepFrames)
+
+ if pt := p.PeriodType; pt != nil {
+ pt.typeX = addString(strings, pt.Type)
+ pt.unitX = addString(strings, pt.Unit)
+ }
+
+ p.stringTable = make([]string, len(strings))
+ for s, i := range strings {
+ p.stringTable[i] = s
+ }
+}
+
+func (p *Profile) encode(b *buffer) {
+ for _, x := range p.SampleType {
+ encodeMessage(b, 1, x)
+ }
+ for _, x := range p.Sample {
+ encodeMessage(b, 2, x)
+ }
+ for _, x := range p.Mapping {
+ encodeMessage(b, 3, x)
+ }
+ for _, x := range p.Location {
+ encodeMessage(b, 4, x)
+ }
+ for _, x := range p.Function {
+ encodeMessage(b, 5, x)
+ }
+ encodeStrings(b, 6, p.stringTable)
+ encodeInt64Opt(b, 7, p.dropFramesX)
+ encodeInt64Opt(b, 8, p.keepFramesX)
+ encodeInt64Opt(b, 9, p.TimeNanos)
+ encodeInt64Opt(b, 10, p.DurationNanos)
+ if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
+ encodeMessage(b, 11, p.PeriodType)
+ }
+ encodeInt64Opt(b, 12, p.Period)
+}
+
+var profileDecoder = []decoder{
+ nil, // 0
+ // repeated ValueType sample_type = 1
+ func(b *buffer, m message) error {
+ x := new(ValueType)
+ pp := m.(*Profile)
+ pp.SampleType = append(pp.SampleType, x)
+ return decodeMessage(b, x)
+ },
+ // repeated Sample sample = 2
+ func(b *buffer, m message) error {
+ x := new(Sample)
+ pp := m.(*Profile)
+ pp.Sample = append(pp.Sample, x)
+ return decodeMessage(b, x)
+ },
+ // repeated Mapping mapping = 3
+ func(b *buffer, m message) error {
+ x := new(Mapping)
+ pp := m.(*Profile)
+ pp.Mapping = append(pp.Mapping, x)
+ return decodeMessage(b, x)
+ },
+ // repeated Location location = 4
+ func(b *buffer, m message) error {
+ x := new(Location)
+ pp := m.(*Profile)
+ pp.Location = append(pp.Location, x)
+ return decodeMessage(b, x)
+ },
+ // repeated Function function = 5
+ func(b *buffer, m message) error {
+ x := new(Function)
+ pp := m.(*Profile)
+ pp.Function = append(pp.Function, x)
+ return decodeMessage(b, x)
+ },
+ // repeated string string_table = 6
+ func(b *buffer, m message) error {
+ err := decodeStrings(b, &m.(*Profile).stringTable)
+ if err != nil {
+ return err
+ }
+ if *&m.(*Profile).stringTable[0] != "" {
+ return errors.New("string_table[0] must be ''")
+ }
+ return nil
+ },
+ // repeated int64 drop_frames = 7
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
+ // repeated int64 keep_frames = 8
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
+ // repeated int64 time_nanos = 9
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
+ // repeated int64 duration_nanos = 10
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
+ // optional string period_type = 11
+ func(b *buffer, m message) error {
+ x := new(ValueType)
+ pp := m.(*Profile)
+ pp.PeriodType = x
+ return decodeMessage(b, x)
+ },
+ // repeated int64 period = 12
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
+}
+
+// postDecode takes the unexported fields populated by decode (with
+// suffix X) and populates the corresponding exported fields.
+// The unexported fields are cleared up to facilitate testing.
+func (p *Profile) postDecode() error {
+ var err error
+
+ mappings := make(map[uint64]*Mapping)
+ for _, m := range p.Mapping {
+ m.File, err = getString(p.stringTable, &m.fileX, err)
+ m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
+ mappings[m.ID] = m
+ }
+
+ functions := make(map[uint64]*Function)
+ for _, f := range p.Function {
+ f.Name, err = getString(p.stringTable, &f.nameX, err)
+ f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
+ f.Filename, err = getString(p.stringTable, &f.filenameX, err)
+ functions[f.ID] = f
+ }
+
+ locations := make(map[uint64]*Location)
+ for _, l := range p.Location {
+ l.Mapping = mappings[l.mappingIDX]
+ l.mappingIDX = 0
+ for i, ln := range l.Line {
+ if id := ln.functionIDX; id != 0 {
+ l.Line[i].Function = functions[id]
+ if l.Line[i].Function == nil {
+ return fmt.Errorf("Function ID %d not found", id)
+ }
+ l.Line[i].functionIDX = 0
+ }
+ }
+ locations[l.ID] = l
+ }
+
+ for _, st := range p.SampleType {
+ st.Type, err = getString(p.stringTable, &st.typeX, err)
+ st.Unit, err = getString(p.stringTable, &st.unitX, err)
+ }
+
+ for _, s := range p.Sample {
+ labels := make(map[string][]string)
+ numLabels := make(map[string][]int64)
+ for _, l := range s.labelX {
+ var key, value string
+ key, err = getString(p.stringTable, &l.keyX, err)
+ if l.strX != 0 {
+ value, err = getString(p.stringTable, &l.strX, err)
+ labels[key] = append(labels[key], value)
+ } else {
+ numLabels[key] = append(numLabels[key], l.numX)
+ }
+ }
+ if len(labels) > 0 {
+ s.Label = labels
+ }
+ if len(numLabels) > 0 {
+ s.NumLabel = numLabels
+ }
+ s.Location = nil
+ for _, lid := range s.locationIDX {
+ s.Location = append(s.Location, locations[lid])
+ }
+ s.locationIDX = nil
+ }
+
+ p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
+ p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
+
+ if pt := p.PeriodType; pt == nil {
+ p.PeriodType = &ValueType{}
+ }
+
+ if pt := p.PeriodType; pt != nil {
+ pt.Type, err = getString(p.stringTable, &pt.typeX, err)
+ pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
+ }
+ p.stringTable = nil
+ return nil
+}
+
+func (p *ValueType) decoder() []decoder {
+ return valueTypeDecoder
+}
+
+func (p *ValueType) encode(b *buffer) {
+ encodeInt64Opt(b, 1, p.typeX)
+ encodeInt64Opt(b, 2, p.unitX)
+}
+
+var valueTypeDecoder = []decoder{
+ nil, // 0
+ // optional int64 type = 1
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
+ // optional int64 unit = 2
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
+}
+
+func (p *Sample) decoder() []decoder {
+ return sampleDecoder
+}
+
+func (p *Sample) encode(b *buffer) {
+ encodeUint64s(b, 1, p.locationIDX)
+ for _, x := range p.Value {
+ encodeInt64(b, 2, x)
+ }
+ for _, x := range p.labelX {
+ encodeMessage(b, 3, x)
+ }
+}
+
+var sampleDecoder = []decoder{
+ nil, // 0
+ // repeated uint64 location = 1
+ func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
+ // repeated int64 value = 2
+ func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
+ // repeated Label label = 3
+ func(b *buffer, m message) error {
+ s := m.(*Sample)
+ n := len(s.labelX)
+ s.labelX = append(s.labelX, Label{})
+ return decodeMessage(b, &s.labelX[n])
+ },
+}
+
+func (p Label) decoder() []decoder {
+ return labelDecoder
+}
+
+func (p Label) encode(b *buffer) {
+ encodeInt64Opt(b, 1, p.keyX)
+ encodeInt64Opt(b, 2, p.strX)
+ encodeInt64Opt(b, 3, p.numX)
+}
+
+var labelDecoder = []decoder{
+ nil, // 0
+ // optional int64 key = 1
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
+ // optional int64 str = 2
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
+ // optional int64 num = 3
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
+}
+
+func (p *Mapping) decoder() []decoder {
+ return mappingDecoder
+}
+
+func (p *Mapping) encode(b *buffer) {
+ encodeUint64Opt(b, 1, p.ID)
+ encodeUint64Opt(b, 2, p.Start)
+ encodeUint64Opt(b, 3, p.Limit)
+ encodeUint64Opt(b, 4, p.Offset)
+ encodeInt64Opt(b, 5, p.fileX)
+ encodeInt64Opt(b, 6, p.buildIDX)
+ encodeBoolOpt(b, 7, p.HasFunctions)
+ encodeBoolOpt(b, 8, p.HasFilenames)
+ encodeBoolOpt(b, 9, p.HasLineNumbers)
+ encodeBoolOpt(b, 10, p.HasInlineFrames)
+}
+
+var mappingDecoder = []decoder{
+ nil, // 0
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) }, // optional uint64 id = 1
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) }, // optional uint64 memory_offset = 2
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) }, // optional uint64 memory_limit = 3
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) }, // optional uint64 file_offset = 4
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) }, // optional int64 filename = 5
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) }, // optional int64 build_id = 6
+ func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) }, // optional bool has_functions = 7
+ func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) }, // optional bool has_filenames = 8
+ func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) }, // optional bool has_line_numbers = 9
+ func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
+}
+
+func (p *Location) decoder() []decoder {
+ return locationDecoder
+}
+
+func (p *Location) encode(b *buffer) {
+ encodeUint64Opt(b, 1, p.ID)
+ encodeUint64Opt(b, 2, p.mappingIDX)
+ encodeUint64Opt(b, 3, p.Address)
+ for i := range p.Line {
+ encodeMessage(b, 4, &p.Line[i])
+ }
+}
+
+var locationDecoder = []decoder{
+ nil, // 0
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) }, // optional uint64 id = 1;
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) }, // optional uint64 address = 3;
+ func(b *buffer, m message) error { // repeated Line line = 4
+ pp := m.(*Location)
+ n := len(pp.Line)
+ pp.Line = append(pp.Line, Line{})
+ return decodeMessage(b, &pp.Line[n])
+ },
+}
+
+func (p *Line) decoder() []decoder {
+ return lineDecoder
+}
+
+func (p *Line) encode(b *buffer) {
+ encodeUint64Opt(b, 1, p.functionIDX)
+ encodeInt64Opt(b, 2, p.Line)
+}
+
+var lineDecoder = []decoder{
+ nil, // 0
+ // optional uint64 function_id = 1
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
+ // optional int64 line = 2
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
+}
+
+func (p *Function) decoder() []decoder {
+ return functionDecoder
+}
+
+func (p *Function) encode(b *buffer) {
+ encodeUint64Opt(b, 1, p.ID)
+ encodeInt64Opt(b, 2, p.nameX)
+ encodeInt64Opt(b, 3, p.systemNameX)
+ encodeInt64Opt(b, 4, p.filenameX)
+ encodeInt64Opt(b, 5, p.StartLine)
+}
+
+var functionDecoder = []decoder{
+ nil, // 0
+ // optional uint64 id = 1
+ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
+ // optional int64 function_name = 2
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
+ // optional int64 function_system_name = 3
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
+ // repeated int64 filename = 4
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
+ // optional int64 start_line = 5
+ func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
+}
+
+func addString(strings map[string]int, s string) int64 {
+ i, ok := strings[s]
+ if !ok {
+ i = len(strings)
+ strings[s] = i
+ }
+ return int64(i)
+}
+
+func getString(strings []string, strng *int64, err error) (string, error) {
+ if err != nil {
+ return "", err
+ }
+ s := int(*strng)
+ if s < 0 || s >= len(strings) {
+ return "", errMalformed
+ }
+ *strng = 0
+ return strings[s], nil
+}
diff --git a/libgo/go/internal/pprof/profile/filter.go b/libgo/go/internal/pprof/profile/filter.go
new file mode 100644
index 0000000000..1baa096a49
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/filter.go
@@ -0,0 +1,158 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implements methods to filter samples from profiles.
+
+package profile
+
+import "regexp"
+
+// FilterSamplesByName filters the samples in a profile and only keeps
+// samples where at least one frame matches focus but none match ignore.
+// Returns true is the corresponding regexp matched at least one sample.
+func (p *Profile) FilterSamplesByName(focus, ignore, hide *regexp.Regexp) (fm, im, hm bool) {
+ focusOrIgnore := make(map[uint64]bool)
+ hidden := make(map[uint64]bool)
+ for _, l := range p.Location {
+ if ignore != nil && l.matchesName(ignore) {
+ im = true
+ focusOrIgnore[l.ID] = false
+ } else if focus == nil || l.matchesName(focus) {
+ fm = true
+ focusOrIgnore[l.ID] = true
+ }
+ if hide != nil && l.matchesName(hide) {
+ hm = true
+ l.Line = l.unmatchedLines(hide)
+ if len(l.Line) == 0 {
+ hidden[l.ID] = true
+ }
+ }
+ }
+
+ s := make([]*Sample, 0, len(p.Sample))
+ for _, sample := range p.Sample {
+ if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
+ if len(hidden) > 0 {
+ var locs []*Location
+ for _, loc := range sample.Location {
+ if !hidden[loc.ID] {
+ locs = append(locs, loc)
+ }
+ }
+ if len(locs) == 0 {
+ // Remove sample with no locations (by not adding it to s).
+ continue
+ }
+ sample.Location = locs
+ }
+ s = append(s, sample)
+ }
+ }
+ p.Sample = s
+
+ return
+}
+
+// matchesName returns whether the function name or file in the
+// location matches the regular expression.
+func (loc *Location) matchesName(re *regexp.Regexp) bool {
+ for _, ln := range loc.Line {
+ if fn := ln.Function; fn != nil {
+ if re.MatchString(fn.Name) {
+ return true
+ }
+ if re.MatchString(fn.Filename) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// unmatchedLines returns the lines in the location that do not match
+// the regular expression.
+func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
+ var lines []Line
+ for _, ln := range loc.Line {
+ if fn := ln.Function; fn != nil {
+ if re.MatchString(fn.Name) {
+ continue
+ }
+ if re.MatchString(fn.Filename) {
+ continue
+ }
+ }
+ lines = append(lines, ln)
+ }
+ return lines
+}
+
+// focusedAndNotIgnored looks up a slice of ids against a map of
+// focused/ignored locations. The map only contains locations that are
+// explicitly focused or ignored. Returns whether there is at least
+// one focused location but no ignored locations.
+func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
+ var f bool
+ for _, loc := range locs {
+ if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
+ if focus {
+ // Found focused location. Must keep searching in case there
+ // is an ignored one as well.
+ f = true
+ } else {
+ // Found ignored location. Can return false right away.
+ return false
+ }
+ }
+ }
+ return f
+}
+
+// TagMatch selects tags for filtering
+type TagMatch func(key, val string, nval int64) bool
+
+// FilterSamplesByTag removes all samples from the profile, except
+// those that match focus and do not match the ignore regular
+// expression.
+func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
+ samples := make([]*Sample, 0, len(p.Sample))
+ for _, s := range p.Sample {
+ focused, ignored := focusedSample(s, focus, ignore)
+ fm = fm || focused
+ im = im || ignored
+ if focused && !ignored {
+ samples = append(samples, s)
+ }
+ }
+ p.Sample = samples
+ return
+}
+
+// focusedTag checks a sample against focus and ignore regexps.
+// Returns whether the focus/ignore regexps match any tags
+func focusedSample(s *Sample, focus, ignore TagMatch) (fm, im bool) {
+ fm = focus == nil
+ for key, vals := range s.Label {
+ for _, val := range vals {
+ if ignore != nil && ignore(key, val, 0) {
+ im = true
+ }
+ if !fm && focus(key, val, 0) {
+ fm = true
+ }
+ }
+ }
+ for key, vals := range s.NumLabel {
+ for _, val := range vals {
+ if ignore != nil && ignore(key, "", val) {
+ im = true
+ }
+ if !fm && focus(key, "", val) {
+ fm = true
+ }
+ }
+ }
+ return fm, im
+}
diff --git a/libgo/go/internal/pprof/profile/legacy_profile.go b/libgo/go/internal/pprof/profile/legacy_profile.go
new file mode 100644
index 0000000000..d69f8deee7
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/legacy_profile.go
@@ -0,0 +1,1266 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements parsers to convert legacy profiles into the
+// profile.proto format.
+
+package profile
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
+ countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
+
+ heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
+ heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
+
+ contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
+
+ hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
+
+ growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
+
+ fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
+
+ threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
+ threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
+
+ procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
+
+ briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
+
+ // LegacyHeapAllocated instructs the heapz parsers to use the
+ // allocated memory stats instead of the default in-use memory. Note
+ // that tcmalloc doesn't provide all allocated memory, only in-use
+ // stats.
+ LegacyHeapAllocated bool
+)
+
+func isSpaceOrComment(line string) bool {
+ trimmed := strings.TrimSpace(line)
+ return len(trimmed) == 0 || trimmed[0] == '#'
+}
+
+// parseGoCount parses a Go count profile (e.g., threadcreate or
+// goroutine) and returns a new Profile.
+func parseGoCount(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ var line string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ line, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(line) {
+ break
+ }
+ }
+
+ m := countStartRE.FindStringSubmatch(line)
+ if m == nil {
+ return nil, errUnrecognized
+ }
+ profileType := m[1]
+ p := &Profile{
+ PeriodType: &ValueType{Type: profileType, Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
+ }
+ locations := make(map[uint64]*Location)
+ for {
+ line, err = r.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return nil, err
+ }
+ if isSpaceOrComment(line) {
+ continue
+ }
+ if strings.HasPrefix(line, "---") {
+ break
+ }
+ m := countRE.FindStringSubmatch(line)
+ if m == nil {
+ return nil, errMalformed
+ }
+ n, err := strconv.ParseInt(m[1], 0, 64)
+ if err != nil {
+ return nil, errMalformed
+ }
+ fields := strings.Fields(m[2])
+ locs := make([]*Location, 0, len(fields))
+ for _, stk := range fields {
+ addr, err := strconv.ParseUint(stk, 0, 64)
+ if err != nil {
+ return nil, errMalformed
+ }
+ // Adjust all frames by -1 to land on the call instruction.
+ addr--
+ loc := locations[addr]
+ if loc == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ locations[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ locs = append(locs, loc)
+ }
+ p.Sample = append(p.Sample, &Sample{
+ Location: locs,
+ Value: []int64{n},
+ })
+ }
+
+ if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// remapLocationIDs ensures there is a location for each address
+// referenced by a sample, and remaps the samples to point to the new
+// location ids.
+func (p *Profile) remapLocationIDs() {
+ seen := make(map[*Location]bool, len(p.Location))
+ var locs []*Location
+
+ for _, s := range p.Sample {
+ for _, l := range s.Location {
+ if seen[l] {
+ continue
+ }
+ l.ID = uint64(len(locs) + 1)
+ locs = append(locs, l)
+ seen[l] = true
+ }
+ }
+ p.Location = locs
+}
+
+func (p *Profile) remapFunctionIDs() {
+ seen := make(map[*Function]bool, len(p.Function))
+ var fns []*Function
+
+ for _, l := range p.Location {
+ for _, ln := range l.Line {
+ fn := ln.Function
+ if fn == nil || seen[fn] {
+ continue
+ }
+ fn.ID = uint64(len(fns) + 1)
+ fns = append(fns, fn)
+ seen[fn] = true
+ }
+ }
+ p.Function = fns
+}
+
+// remapMappingIDs matches location addresses with existing mappings
+// and updates them appropriately. This is O(N*M), if this ever shows
+// up as a bottleneck, evaluate sorting the mappings and doing a
+// binary search, which would make it O(N*log(M)).
+func (p *Profile) remapMappingIDs() {
+ if len(p.Mapping) == 0 {
+ return
+ }
+
+ // Some profile handlers will incorrectly set regions for the main
+ // executable if its section is remapped. Fix them through heuristics.
+
+ // Remove the initial mapping if named '/anon_hugepage' and has a
+ // consecutive adjacent mapping.
+ if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
+ if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
+ p.Mapping = p.Mapping[1:]
+ }
+ }
+
+ // Subtract the offset from the start of the main mapping if it
+ // ends up at a recognizable start address.
+ const expectedStart = 0x400000
+ if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
+ m.Start = expectedStart
+ m.Offset = 0
+ }
+
+ for _, l := range p.Location {
+ if a := l.Address; a != 0 {
+ for _, m := range p.Mapping {
+ if m.Start <= a && a < m.Limit {
+ l.Mapping = m
+ break
+ }
+ }
+ }
+ }
+
+ // Reset all mapping IDs.
+ for i, m := range p.Mapping {
+ m.ID = uint64(i + 1)
+ }
+}
+
+var cpuInts = []func([]byte) (uint64, []byte){
+ get32l,
+ get32b,
+ get64l,
+ get64b,
+}
+
+func get32l(b []byte) (uint64, []byte) {
+ if len(b) < 4 {
+ return 0, nil
+ }
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
+}
+
+func get32b(b []byte) (uint64, []byte) {
+ if len(b) < 4 {
+ return 0, nil
+ }
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
+}
+
+func get64l(b []byte) (uint64, []byte) {
+ if len(b) < 8 {
+ return 0, nil
+ }
+ 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, b[8:]
+}
+
+func get64b(b []byte) (uint64, []byte) {
+ if len(b) < 8 {
+ return 0, nil
+ }
+ 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, b[8:]
+}
+
+// ParseTracebacks parses a set of tracebacks and returns a newly
+// populated profile. It will accept any text file and generate a
+// Profile out of it with any hex addresses it can identify, including
+// a process map if it can recognize one. Each sample will include a
+// tag "source" with the addresses recognized in string format.
+func ParseTracebacks(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ p := &Profile{
+ PeriodType: &ValueType{Type: "trace", Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{
+ {Type: "trace", Unit: "count"},
+ },
+ }
+
+ var sources []string
+ var sloc []*Location
+
+ locs := make(map[uint64]*Location)
+ for {
+ l, err := r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if sectionTrigger(l) == memoryMapSection {
+ break
+ }
+ if s, addrs := extractHexAddresses(l); len(s) > 0 {
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ sources = append(sources, s...)
+ } else {
+ if len(sources) > 0 || len(sloc) > 0 {
+ addTracebackSample(sloc, sources, p)
+ sloc, sources = nil, nil
+ }
+ }
+ }
+
+ // Add final sample to save any leftover data.
+ if len(sources) > 0 || len(sloc) > 0 {
+ addTracebackSample(sloc, sources, p)
+ }
+
+ if err := p.ParseMemoryMap(r); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+func addTracebackSample(l []*Location, s []string, p *Profile) {
+ p.Sample = append(p.Sample,
+ &Sample{
+ Value: []int64{1},
+ Location: l,
+ Label: map[string][]string{"source": s},
+ })
+}
+
+// parseCPU parses a profilez legacy profile and returns a newly
+// populated Profile.
+//
+// The general format for profilez samples is a sequence of words in
+// binary format. The first words are a header with the following data:
+// 1st word -- 0
+// 2nd word -- 3
+// 3rd word -- 0 if a c++ application, 1 if a java application.
+// 4th word -- Sampling period (in microseconds).
+// 5th word -- Padding.
+func parseCPU(b []byte) (*Profile, error) {
+ var parse func([]byte) (uint64, []byte)
+ var n1, n2, n3, n4, n5 uint64
+ for _, parse = range cpuInts {
+ var tmp []byte
+ n1, tmp = parse(b)
+ n2, tmp = parse(tmp)
+ n3, tmp = parse(tmp)
+ n4, tmp = parse(tmp)
+ n5, tmp = parse(tmp)
+
+ if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
+ b = tmp
+ return cpuProfile(b, int64(n4), parse)
+ }
+ }
+ return nil, errUnrecognized
+}
+
+// cpuProfile returns a new Profile from C++ profilez data.
+// b is the profile bytes after the header, period is the profiling
+// period, and parse is a function to parse 8-byte chunks from the
+// profile in its native endianness.
+func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
+ p := &Profile{
+ Period: period * 1000,
+ PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
+ SampleType: []*ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "nanoseconds"},
+ },
+ }
+ var err error
+ if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
+ return nil, err
+ }
+
+ // If all samples have the same second-to-the-bottom frame, it
+ // strongly suggests that it is an uninteresting artifact of
+ // measurement -- a stack frame pushed by the signal handler. The
+ // bottom frame is always correct as it is picked up from the signal
+ // structure, not the stack. Check if this is the case and if so,
+ // remove.
+ if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
+ allSame := true
+ id1 := p.Sample[0].Location[1].Address
+ for _, s := range p.Sample {
+ if len(s.Location) < 2 || id1 != s.Location[1].Address {
+ allSame = false
+ break
+ }
+ }
+ if allSame {
+ for _, s := range p.Sample {
+ s.Location = append(s.Location[:1], s.Location[2:]...)
+ }
+ }
+ }
+
+ if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// parseCPUSamples parses a collection of profilez samples from a
+// profile.
+//
+// profilez samples are a repeated sequence of stack frames of the
+// form:
+// 1st word -- The number of times this stack was encountered.
+// 2nd word -- The size of the stack (StackSize).
+// 3rd word -- The first address on the stack.
+// ...
+// StackSize + 2 -- The last address on the stack
+// The last stack trace is of the form:
+// 1st word -- 0
+// 2nd word -- 1
+// 3rd word -- 0
+//
+// Addresses from stack traces may point to the next instruction after
+// each call. Optionally adjust by -1 to land somewhere on the actual
+// call (except for the leaf, which is not a call).
+func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
+ locs := make(map[uint64]*Location)
+ for len(b) > 0 {
+ var count, nstk uint64
+ count, b = parse(b)
+ nstk, b = parse(b)
+ if b == nil || nstk > uint64(len(b)/4) {
+ return nil, nil, errUnrecognized
+ }
+ var sloc []*Location
+ addrs := make([]uint64, nstk)
+ for i := 0; i < int(nstk); i++ {
+ addrs[i], b = parse(b)
+ }
+
+ if count == 0 && nstk == 1 && addrs[0] == 0 {
+ // End of data marker
+ break
+ }
+ for i, addr := range addrs {
+ if adjust && i > 0 {
+ addr--
+ }
+ loc := locs[addr]
+ if loc == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ locs[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ sloc = append(sloc, loc)
+ }
+ p.Sample = append(p.Sample,
+ &Sample{
+ Value: []int64{int64(count), int64(count) * p.Period},
+ Location: sloc,
+ })
+ }
+ // Reached the end without finding the EOD marker.
+ return b, locs, nil
+}
+
+// parseHeap parses a heapz legacy or a growthz profile and
+// returns a newly populated Profile.
+func parseHeap(b []byte) (p *Profile, err error) {
+ r := bytes.NewBuffer(b)
+ l, err := r.ReadString('\n')
+ if err != nil {
+ return nil, errUnrecognized
+ }
+
+ sampling := ""
+
+ if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
+ }
+
+ var period int64
+ if len(header[6]) > 0 {
+ if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+
+ switch header[5] {
+ case "heapz_v2", "heap_v2":
+ sampling, p.Period = "v2", period
+ case "heapprofile":
+ sampling, p.Period = "", 1
+ case "heap":
+ sampling, p.Period = "v2", period/2
+ default:
+ return nil, errUnrecognized
+ }
+ } else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
+ Period: 1,
+ }
+ } else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "allocations", Unit: "count"},
+ Period: 1,
+ }
+ } else {
+ return nil, errUnrecognized
+ }
+
+ if LegacyHeapAllocated {
+ for _, st := range p.SampleType {
+ st.Type = "alloc_" + st.Type
+ }
+ } else {
+ for _, st := range p.SampleType {
+ st.Type = "inuse_" + st.Type
+ }
+ }
+
+ locs := make(map[uint64]*Location)
+ for {
+ l, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if l == "" {
+ break
+ }
+ }
+
+ if isSpaceOrComment(l) {
+ continue
+ }
+ l = strings.TrimSpace(l)
+
+ if sectionTrigger(l) != unrecognizedSection {
+ break
+ }
+
+ value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
+ if err != nil {
+ return nil, err
+ }
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ p.Sample = append(p.Sample, &Sample{
+ Value: value,
+ Location: sloc,
+ NumLabel: map[string][]int64{"bytes": {blocksize}},
+ })
+ }
+
+ if err = parseAdditionalSections(l, r, p); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// parseHeapSample parses a single row from a heap profile into a new Sample.
+func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
+ sampleData := heapSampleRE.FindStringSubmatch(line)
+ if len(sampleData) != 6 {
+ return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
+ }
+
+ // Use first two values by default; tcmalloc sampling generates the
+ // same value for both, only the older heap-profile collect separate
+ // stats for in-use and allocated objects.
+ valueIndex := 1
+ if LegacyHeapAllocated {
+ valueIndex = 3
+ }
+
+ var v1, v2 int64
+ if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
+ return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+ if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
+ return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+
+ if v1 == 0 {
+ if v2 != 0 {
+ return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
+ }
+ } else {
+ blocksize = v2 / v1
+ if sampling == "v2" {
+ v1, v2 = scaleHeapSample(v1, v2, rate)
+ }
+ }
+
+ value = []int64{v1, v2}
+ addrs = parseHexAddresses(sampleData[5])
+
+ return value, blocksize, addrs, nil
+}
+
+// extractHexAddresses extracts hex numbers from a string and returns
+// them, together with their numeric value, in a slice.
+func extractHexAddresses(s string) ([]string, []uint64) {
+ hexStrings := hexNumberRE.FindAllString(s, -1)
+ var ids []uint64
+ for _, s := range hexStrings {
+ if id, err := strconv.ParseUint(s, 0, 64); err == nil {
+ ids = append(ids, id)
+ } else {
+ // Do not expect any parsing failures due to the regexp matching.
+ panic("failed to parse hex value:" + s)
+ }
+ }
+ return hexStrings, ids
+}
+
+// parseHexAddresses parses hex numbers from a string and returns them
+// in a slice.
+func parseHexAddresses(s string) []uint64 {
+ _, ids := extractHexAddresses(s)
+ return ids
+}
+
+// scaleHeapSample adjusts the data from a heapz Sample to
+// account for its probability of appearing in the collected
+// data. heapz profiles are a sampling of the memory allocations
+// requests in a program. We estimate the unsampled value by dividing
+// each collected sample by its probability of appearing in the
+// profile. heapz v2 profiles rely on a poisson process to determine
+// which samples to collect, based on the desired average collection
+// rate R. The probability of a sample of size S to appear in that
+// profile is 1-exp(-S/R).
+func scaleHeapSample(count, size, rate int64) (int64, int64) {
+ if count == 0 || size == 0 {
+ return 0, 0
+ }
+
+ if rate <= 1 {
+ // if rate==1 all samples were collected so no adjustment is needed.
+ // if rate<1 treat as unknown and skip scaling.
+ return count, size
+ }
+
+ avgSize := float64(size) / float64(count)
+ scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
+
+ return int64(float64(count) * scale), int64(float64(size) * scale)
+}
+
+// parseContention parses a mutex or contention profile. There are 2 cases:
+// "--- contentionz " for legacy C++ profiles (and backwards compatibility)
+// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime.
+// This code converts the text output from runtime into a *Profile. (In the future
+// the runtime might write a serialized Profile directly making this unnecessary.)
+func parseContention(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+ var l string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ l, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(l) {
+ break
+ }
+ }
+
+ if strings.HasPrefix(l, "--- contentionz ") {
+ return parseCppContention(r)
+ } else if strings.HasPrefix(l, "--- mutex:") {
+ return parseCppContention(r)
+ } else if strings.HasPrefix(l, "--- contention:") {
+ return parseCppContention(r)
+ }
+ return nil, errUnrecognized
+}
+
+// parseCppContention parses the output from synchronization_profiling.cc
+// for backward compatibility, and the compatible (non-debug) block profile
+// output from the Go runtime.
+func parseCppContention(r *bytes.Buffer) (*Profile, error) {
+ p := &Profile{
+ PeriodType: &ValueType{Type: "contentions", Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{
+ {Type: "contentions", Unit: "count"},
+ {Type: "delay", Unit: "nanoseconds"},
+ },
+ }
+
+ var cpuHz int64
+ var l string
+ var err error
+ // Parse text of the form "attribute = value" before the samples.
+ const delimiter = "="
+ for {
+ l, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if l == "" {
+ break
+ }
+ }
+ if isSpaceOrComment(l) {
+ continue
+ }
+
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if strings.HasPrefix(l, "---") {
+ break
+ }
+
+ attr := strings.SplitN(l, delimiter, 2)
+ if len(attr) != 2 {
+ break
+ }
+ key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
+ var err error
+ switch key {
+ case "cycles/second":
+ if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ case "sampling period":
+ if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ case "ms since reset":
+ ms, err := strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return nil, errUnrecognized
+ }
+ p.DurationNanos = ms * 1000 * 1000
+ case "format":
+ // CPP contentionz profiles don't have format.
+ return nil, errUnrecognized
+ case "resolution":
+ // CPP contentionz profiles don't have resolution.
+ return nil, errUnrecognized
+ case "discarded samples":
+ default:
+ return nil, errUnrecognized
+ }
+ }
+
+ locs := make(map[uint64]*Location)
+ for {
+ if !isSpaceOrComment(l) {
+ if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
+ break
+ }
+ value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
+ if err != nil {
+ return nil, err
+ }
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+ p.Sample = append(p.Sample, &Sample{
+ Value: value,
+ Location: sloc,
+ })
+ }
+
+ if l, err = r.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ }
+
+ if err = parseAdditionalSections(l, r, p); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// parseContentionSample parses a single row from a contention profile
+// into a new Sample.
+func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
+ sampleData := contentionSampleRE.FindStringSubmatch(line)
+ if sampleData == nil {
+ return value, addrs, errUnrecognized
+ }
+
+ v1, err := strconv.ParseInt(sampleData[1], 10, 64)
+ if err != nil {
+ return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+ v2, err := strconv.ParseInt(sampleData[2], 10, 64)
+ if err != nil {
+ return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+
+ // Unsample values if period and cpuHz are available.
+ // - Delays are scaled to cycles and then to nanoseconds.
+ // - Contentions are scaled to cycles.
+ if period > 0 {
+ if cpuHz > 0 {
+ cpuGHz := float64(cpuHz) / 1e9
+ v1 = int64(float64(v1) * float64(period) / cpuGHz)
+ }
+ v2 = v2 * period
+ }
+
+ value = []int64{v2, v1}
+ addrs = parseHexAddresses(sampleData[3])
+
+ return value, addrs, nil
+}
+
+// parseThread parses a Threadz profile and returns a new Profile.
+func parseThread(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ var line string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ line, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(line) {
+ break
+ }
+ }
+
+ if m := threadzStartRE.FindStringSubmatch(line); m != nil {
+ // Advance over initial comments until first stack trace.
+ for {
+ line, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if line == "" {
+ break
+ }
+ }
+ if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
+ break
+ }
+ }
+ } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+ return nil, errUnrecognized
+ }
+
+ p := &Profile{
+ SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
+ PeriodType: &ValueType{Type: "thread", Unit: "count"},
+ Period: 1,
+ }
+
+ locs := make(map[uint64]*Location)
+ // Recognize each thread and populate profile samples.
+ for sectionTrigger(line) == unrecognizedSection {
+ if strings.HasPrefix(line, "---- no stack trace for") {
+ line = ""
+ break
+ }
+ if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+ return nil, errUnrecognized
+ }
+
+ var addrs []uint64
+ line, addrs, err = parseThreadSample(r)
+ if err != nil {
+ return nil, errUnrecognized
+ }
+ if len(addrs) == 0 {
+ // We got a --same as previous threads--. Bump counters.
+ if len(p.Sample) > 0 {
+ s := p.Sample[len(p.Sample)-1]
+ s.Value[0]++
+ }
+ continue
+ }
+
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ p.Sample = append(p.Sample, &Sample{
+ Value: []int64{1},
+ Location: sloc,
+ })
+ }
+
+ if err = parseAdditionalSections(line, r, p); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// parseThreadSample parses a symbolized or unsymbolized stack trace.
+// Returns the first line after the traceback, the sample (or nil if
+// it hits a 'same-as-previous' marker) and an error.
+func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
+ var l string
+ sameAsPrevious := false
+ for {
+ if l, err = b.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return "", nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if strings.HasPrefix(l, "---") {
+ break
+ }
+ if strings.Contains(l, "same as previous thread") {
+ sameAsPrevious = true
+ continue
+ }
+
+ addrs = append(addrs, parseHexAddresses(l)...)
+ }
+
+ if sameAsPrevious {
+ return l, nil, nil
+ }
+ return l, addrs, nil
+}
+
+// parseAdditionalSections parses any additional sections in the
+// profile, ignoring any unrecognized sections.
+func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
+ for {
+ if sectionTrigger(l) == memoryMapSection {
+ break
+ }
+ // Ignore any unrecognized sections.
+ if l, err := b.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return err
+ }
+ if l == "" {
+ break
+ }
+ }
+ }
+ return p.ParseMemoryMap(b)
+}
+
+// ParseMemoryMap parses a memory map in the format of
+// /proc/self/maps, and overrides the mappings in the current profile.
+// It renumbers the samples and locations in the profile correspondingly.
+func (p *Profile) ParseMemoryMap(rd io.Reader) error {
+ b := bufio.NewReader(rd)
+
+ var attrs []string
+ var r *strings.Replacer
+ const delimiter = "="
+ for {
+ l, err := b.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if r != nil {
+ l = r.Replace(l)
+ }
+ m, err := parseMappingEntry(l)
+ if err != nil {
+ if err == errUnrecognized {
+ // Recognize assignments of the form: attr=value, and replace
+ // $attr with value on subsequent mappings.
+ if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
+ attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
+ r = strings.NewReplacer(attrs...)
+ }
+ // Ignore any unrecognized entries
+ continue
+ }
+ return err
+ }
+ if m == nil || (m.File == "" && len(p.Mapping) != 0) {
+ // In some cases the first entry may include the address range
+ // but not the name of the file. It should be followed by
+ // another entry with the name.
+ continue
+ }
+ if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
+ // Update the name if this is the entry following that empty one.
+ p.Mapping[0].File = m.File
+ continue
+ }
+ p.Mapping = append(p.Mapping, m)
+ }
+ p.remapLocationIDs()
+ p.remapFunctionIDs()
+ p.remapMappingIDs()
+ return nil
+}
+
+func parseMappingEntry(l string) (*Mapping, error) {
+ mapping := &Mapping{}
+ var err error
+ if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
+ if !strings.Contains(me[3], "x") {
+ // Skip non-executable entries.
+ return nil, nil
+ }
+ if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if me[4] != "" {
+ if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+ mapping.File = me[8]
+ return mapping, nil
+ }
+
+ if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
+ if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ mapping.File = me[3]
+ if me[5] != "" {
+ if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+ return mapping, nil
+ }
+
+ return nil, errUnrecognized
+}
+
+type sectionType int
+
+const (
+ unrecognizedSection sectionType = iota
+ memoryMapSection
+)
+
+var memoryMapTriggers = []string{
+ "--- Memory map: ---",
+ "MAPPED_LIBRARIES:",
+}
+
+func sectionTrigger(line string) sectionType {
+ for _, trigger := range memoryMapTriggers {
+ if strings.Contains(line, trigger) {
+ return memoryMapSection
+ }
+ }
+ return unrecognizedSection
+}
+
+func (p *Profile) addLegacyFrameInfo() {
+ switch {
+ case isProfileType(p, heapzSampleTypes) ||
+ isProfileType(p, heapzInUseSampleTypes) ||
+ isProfileType(p, heapzAllocSampleTypes):
+ p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
+ case isProfileType(p, contentionzSampleTypes):
+ p.DropFrames, p.KeepFrames = lockRxStr, ""
+ default:
+ p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
+ }
+}
+
+var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
+var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
+var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
+var contentionzSampleTypes = []string{"contentions", "delay"}
+
+func isProfileType(p *Profile, t []string) bool {
+ st := p.SampleType
+ if len(st) != len(t) {
+ return false
+ }
+
+ for i := range st {
+ if st[i].Type != t[i] {
+ return false
+ }
+ }
+ return true
+}
+
+var allocRxStr = strings.Join([]string{
+ // POSIX entry points.
+ `calloc`,
+ `cfree`,
+ `malloc`,
+ `free`,
+ `memalign`,
+ `do_memalign`,
+ `(__)?posix_memalign`,
+ `pvalloc`,
+ `valloc`,
+ `realloc`,
+
+ // TC malloc.
+ `tcmalloc::.*`,
+ `tc_calloc`,
+ `tc_cfree`,
+ `tc_malloc`,
+ `tc_free`,
+ `tc_memalign`,
+ `tc_posix_memalign`,
+ `tc_pvalloc`,
+ `tc_valloc`,
+ `tc_realloc`,
+ `tc_new`,
+ `tc_delete`,
+ `tc_newarray`,
+ `tc_deletearray`,
+ `tc_new_nothrow`,
+ `tc_newarray_nothrow`,
+
+ // Memory-allocation routines on OS X.
+ `malloc_zone_malloc`,
+ `malloc_zone_calloc`,
+ `malloc_zone_valloc`,
+ `malloc_zone_realloc`,
+ `malloc_zone_memalign`,
+ `malloc_zone_free`,
+
+ // Go runtime
+ `runtime\..*`,
+
+ // Other misc. memory allocation routines
+ `BaseArena::.*`,
+ `(::)?do_malloc_no_errno`,
+ `(::)?do_malloc_pages`,
+ `(::)?do_malloc`,
+ `DoSampledAllocation`,
+ `MallocedMemBlock::MallocedMemBlock`,
+ `_M_allocate`,
+ `__builtin_(vec_)?delete`,
+ `__builtin_(vec_)?new`,
+ `__gnu_cxx::new_allocator::allocate`,
+ `__libc_malloc`,
+ `__malloc_alloc_template::allocate`,
+ `allocate`,
+ `cpp_alloc`,
+ `operator new(\[\])?`,
+ `simple_alloc::allocate`,
+}, `|`)
+
+var allocSkipRxStr = strings.Join([]string{
+ // Preserve Go runtime frames that appear in the middle/bottom of
+ // the stack.
+ `runtime\.panic`,
+ `runtime\.reflectcall`,
+ `runtime\.call[0-9]*`,
+}, `|`)
+
+var cpuProfilerRxStr = strings.Join([]string{
+ `ProfileData::Add`,
+ `ProfileData::prof_handler`,
+ `CpuProfiler::prof_handler`,
+ `__pthread_sighandler`,
+ `__restore`,
+}, `|`)
+
+var lockRxStr = strings.Join([]string{
+ `RecordLockProfileData`,
+ `(base::)?RecordLockProfileData.*`,
+ `(base::)?SubmitMutexProfileData.*`,
+ `(base::)?SubmitSpinLockProfileData.*`,
+ `(Mutex::)?AwaitCommon.*`,
+ `(Mutex::)?Unlock.*`,
+ `(Mutex::)?UnlockSlow.*`,
+ `(Mutex::)?ReaderUnlock.*`,
+ `(MutexLock::)?~MutexLock.*`,
+ `(SpinLock::)?Unlock.*`,
+ `(SpinLock::)?SlowUnlock.*`,
+ `(SpinLockHolder::)?~SpinLockHolder.*`,
+}, `|`)
diff --git a/libgo/go/internal/pprof/profile/profile.go b/libgo/go/internal/pprof/profile/profile.go
new file mode 100644
index 0000000000..28e713d7be
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/profile.go
@@ -0,0 +1,572 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package profile provides a representation of profile.proto and
+// methods to encode/decode profiles in this format.
+package profile
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "regexp"
+ "strings"
+ "time"
+)
+
+// Profile is an in-memory representation of profile.proto.
+type Profile struct {
+ SampleType []*ValueType
+ Sample []*Sample
+ Mapping []*Mapping
+ Location []*Location
+ Function []*Function
+
+ DropFrames string
+ KeepFrames string
+
+ TimeNanos int64
+ DurationNanos int64
+ PeriodType *ValueType
+ Period int64
+
+ dropFramesX int64
+ keepFramesX int64
+ stringTable []string
+}
+
+// ValueType corresponds to Profile.ValueType
+type ValueType struct {
+ Type string // cpu, wall, inuse_space, etc
+ Unit string // seconds, nanoseconds, bytes, etc
+
+ typeX int64
+ unitX int64
+}
+
+// Sample corresponds to Profile.Sample
+type Sample struct {
+ Location []*Location
+ Value []int64
+ Label map[string][]string
+ NumLabel map[string][]int64
+
+ locationIDX []uint64
+ labelX []Label
+}
+
+// Label corresponds to Profile.Label
+type Label struct {
+ keyX int64
+ // Exactly one of the two following values must be set
+ strX int64
+ numX int64 // Integer value for this label
+}
+
+// Mapping corresponds to Profile.Mapping
+type Mapping struct {
+ ID uint64
+ Start uint64
+ Limit uint64
+ Offset uint64
+ File string
+ BuildID string
+ HasFunctions bool
+ HasFilenames bool
+ HasLineNumbers bool
+ HasInlineFrames bool
+
+ fileX int64
+ buildIDX int64
+}
+
+// Location corresponds to Profile.Location
+type Location struct {
+ ID uint64
+ Mapping *Mapping
+ Address uint64
+ Line []Line
+
+ mappingIDX uint64
+}
+
+// Line corresponds to Profile.Line
+type Line struct {
+ Function *Function
+ Line int64
+
+ functionIDX uint64
+}
+
+// Function corresponds to Profile.Function
+type Function struct {
+ ID uint64
+ Name string
+ SystemName string
+ Filename string
+ StartLine int64
+
+ nameX int64
+ systemNameX int64
+ filenameX int64
+}
+
+// Parse parses a profile and checks for its validity. The input
+// may be a gzip-compressed encoded protobuf or one of many legacy
+// profile formats which may be unsupported in the future.
+func Parse(r io.Reader) (*Profile, error) {
+ orig, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+
+ var p *Profile
+ if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
+ gz, err := gzip.NewReader(bytes.NewBuffer(orig))
+ if err != nil {
+ return nil, fmt.Errorf("decompressing profile: %v", err)
+ }
+ data, err := ioutil.ReadAll(gz)
+ if err != nil {
+ return nil, fmt.Errorf("decompressing profile: %v", err)
+ }
+ orig = data
+ }
+ if p, err = parseUncompressed(orig); err != nil {
+ if p, err = parseLegacy(orig); err != nil {
+ return nil, fmt.Errorf("parsing profile: %v", err)
+ }
+ }
+
+ if err := p.CheckValid(); err != nil {
+ return nil, fmt.Errorf("malformed profile: %v", err)
+ }
+ return p, nil
+}
+
+var errUnrecognized = fmt.Errorf("unrecognized profile format")
+var errMalformed = fmt.Errorf("malformed profile format")
+
+func parseLegacy(data []byte) (*Profile, error) {
+ parsers := []func([]byte) (*Profile, error){
+ parseCPU,
+ parseHeap,
+ parseGoCount, // goroutine, threadcreate
+ parseThread,
+ parseContention,
+ }
+
+ for _, parser := range parsers {
+ p, err := parser(data)
+ if err == nil {
+ p.setMain()
+ p.addLegacyFrameInfo()
+ return p, nil
+ }
+ if err != errUnrecognized {
+ return nil, err
+ }
+ }
+ return nil, errUnrecognized
+}
+
+func parseUncompressed(data []byte) (*Profile, error) {
+ p := &Profile{}
+ if err := unmarshal(data, p); err != nil {
+ return nil, err
+ }
+
+ if err := p.postDecode(); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
+
+// setMain scans Mapping entries and guesses which entry is main
+// because legacy profiles don't obey the convention of putting main
+// first.
+func (p *Profile) setMain() {
+ for i := 0; i < len(p.Mapping); i++ {
+ file := strings.TrimSpace(strings.Replace(p.Mapping[i].File, "(deleted)", "", -1))
+ if len(file) == 0 {
+ continue
+ }
+ if len(libRx.FindStringSubmatch(file)) > 0 {
+ continue
+ }
+ if strings.HasPrefix(file, "[") {
+ continue
+ }
+ // Swap what we guess is main to position 0.
+ tmp := p.Mapping[i]
+ p.Mapping[i] = p.Mapping[0]
+ p.Mapping[0] = tmp
+ break
+ }
+}
+
+// Write writes the profile as a gzip-compressed marshaled protobuf.
+func (p *Profile) Write(w io.Writer) error {
+ p.preEncode()
+ b := marshal(p)
+ zw := gzip.NewWriter(w)
+ defer zw.Close()
+ _, err := zw.Write(b)
+ return err
+}
+
+// CheckValid tests whether the profile is valid. Checks include, but are
+// not limited to:
+// - len(Profile.Sample[n].value) == len(Profile.value_unit)
+// - Sample.id has a corresponding Profile.Location
+func (p *Profile) CheckValid() error {
+ // Check that sample values are consistent
+ sampleLen := len(p.SampleType)
+ if sampleLen == 0 && len(p.Sample) != 0 {
+ return fmt.Errorf("missing sample type information")
+ }
+ for _, s := range p.Sample {
+ if len(s.Value) != sampleLen {
+ return fmt.Errorf("mismatch: sample has: %d values vs. %d types", len(s.Value), len(p.SampleType))
+ }
+ }
+
+ // Check that all mappings/locations/functions are in the tables
+ // Check that there are no duplicate ids
+ mappings := make(map[uint64]*Mapping, len(p.Mapping))
+ for _, m := range p.Mapping {
+ if m.ID == 0 {
+ return fmt.Errorf("found mapping with reserved ID=0")
+ }
+ if mappings[m.ID] != nil {
+ return fmt.Errorf("multiple mappings with same id: %d", m.ID)
+ }
+ mappings[m.ID] = m
+ }
+ functions := make(map[uint64]*Function, len(p.Function))
+ for _, f := range p.Function {
+ if f.ID == 0 {
+ return fmt.Errorf("found function with reserved ID=0")
+ }
+ if functions[f.ID] != nil {
+ return fmt.Errorf("multiple functions with same id: %d", f.ID)
+ }
+ functions[f.ID] = f
+ }
+ locations := make(map[uint64]*Location, len(p.Location))
+ for _, l := range p.Location {
+ if l.ID == 0 {
+ return fmt.Errorf("found location with reserved id=0")
+ }
+ if locations[l.ID] != nil {
+ return fmt.Errorf("multiple locations with same id: %d", l.ID)
+ }
+ locations[l.ID] = l
+ if m := l.Mapping; m != nil {
+ if m.ID == 0 || mappings[m.ID] != m {
+ return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
+ }
+ }
+ for _, ln := range l.Line {
+ if f := ln.Function; f != nil {
+ if f.ID == 0 || functions[f.ID] != f {
+ return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// Aggregate merges the locations in the profile into equivalence
+// classes preserving the request attributes. It also updates the
+// samples to point to the merged locations.
+func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
+ for _, m := range p.Mapping {
+ m.HasInlineFrames = m.HasInlineFrames && inlineFrame
+ m.HasFunctions = m.HasFunctions && function
+ m.HasFilenames = m.HasFilenames && filename
+ m.HasLineNumbers = m.HasLineNumbers && linenumber
+ }
+
+ // Aggregate functions
+ if !function || !filename {
+ for _, f := range p.Function {
+ if !function {
+ f.Name = ""
+ f.SystemName = ""
+ }
+ if !filename {
+ f.Filename = ""
+ }
+ }
+ }
+
+ // Aggregate locations
+ if !inlineFrame || !address || !linenumber {
+ for _, l := range p.Location {
+ if !inlineFrame && len(l.Line) > 1 {
+ l.Line = l.Line[len(l.Line)-1:]
+ }
+ if !linenumber {
+ for i := range l.Line {
+ l.Line[i].Line = 0
+ }
+ }
+ if !address {
+ l.Address = 0
+ }
+ }
+ }
+
+ return p.CheckValid()
+}
+
+// Print dumps a text representation of a profile. Intended mainly
+// for debugging purposes.
+func (p *Profile) String() string {
+
+ ss := make([]string, 0, len(p.Sample)+len(p.Mapping)+len(p.Location))
+ if pt := p.PeriodType; pt != nil {
+ ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
+ }
+ ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
+ if p.TimeNanos != 0 {
+ ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
+ }
+ if p.DurationNanos != 0 {
+ ss = append(ss, fmt.Sprintf("Duration: %v", time.Duration(p.DurationNanos)))
+ }
+
+ ss = append(ss, "Samples:")
+ var sh1 string
+ for _, s := range p.SampleType {
+ sh1 = sh1 + fmt.Sprintf("%s/%s ", s.Type, s.Unit)
+ }
+ ss = append(ss, strings.TrimSpace(sh1))
+ for _, s := range p.Sample {
+ var sv string
+ for _, v := range s.Value {
+ sv = fmt.Sprintf("%s %10d", sv, v)
+ }
+ sv = sv + ": "
+ for _, l := range s.Location {
+ sv = sv + fmt.Sprintf("%d ", l.ID)
+ }
+ ss = append(ss, sv)
+ const labelHeader = " "
+ if len(s.Label) > 0 {
+ ls := labelHeader
+ for k, v := range s.Label {
+ ls = ls + fmt.Sprintf("%s:%v ", k, v)
+ }
+ ss = append(ss, ls)
+ }
+ if len(s.NumLabel) > 0 {
+ ls := labelHeader
+ for k, v := range s.NumLabel {
+ ls = ls + fmt.Sprintf("%s:%v ", k, v)
+ }
+ ss = append(ss, ls)
+ }
+ }
+
+ ss = append(ss, "Locations")
+ for _, l := range p.Location {
+ locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
+ if m := l.Mapping; m != nil {
+ locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
+ }
+ if len(l.Line) == 0 {
+ ss = append(ss, locStr)
+ }
+ for li := range l.Line {
+ lnStr := "??"
+ if fn := l.Line[li].Function; fn != nil {
+ lnStr = fmt.Sprintf("%s %s:%d s=%d",
+ fn.Name,
+ fn.Filename,
+ l.Line[li].Line,
+ fn.StartLine)
+ if fn.Name != fn.SystemName {
+ lnStr = lnStr + "(" + fn.SystemName + ")"
+ }
+ }
+ ss = append(ss, locStr+lnStr)
+ // Do not print location details past the first line
+ locStr = " "
+ }
+ }
+
+ ss = append(ss, "Mappings")
+ for _, m := range p.Mapping {
+ bits := ""
+ if m.HasFunctions {
+ bits = bits + "[FN]"
+ }
+ if m.HasFilenames {
+ bits = bits + "[FL]"
+ }
+ if m.HasLineNumbers {
+ bits = bits + "[LN]"
+ }
+ if m.HasInlineFrames {
+ bits = bits + "[IN]"
+ }
+ ss = append(ss, fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
+ m.ID,
+ m.Start, m.Limit, m.Offset,
+ m.File,
+ m.BuildID,
+ bits))
+ }
+
+ return strings.Join(ss, "\n") + "\n"
+}
+
+// Merge adds profile p adjusted by ratio r into profile p. Profiles
+// must be compatible (same Type and SampleType).
+// TODO(rsilvera): consider normalizing the profiles based on the
+// total samples collected.
+func (p *Profile) Merge(pb *Profile, r float64) error {
+ if err := p.Compatible(pb); err != nil {
+ return err
+ }
+
+ pb = pb.Copy()
+
+ // Keep the largest of the two periods.
+ if pb.Period > p.Period {
+ p.Period = pb.Period
+ }
+
+ p.DurationNanos += pb.DurationNanos
+
+ p.Mapping = append(p.Mapping, pb.Mapping...)
+ for i, m := range p.Mapping {
+ m.ID = uint64(i + 1)
+ }
+ p.Location = append(p.Location, pb.Location...)
+ for i, l := range p.Location {
+ l.ID = uint64(i + 1)
+ }
+ p.Function = append(p.Function, pb.Function...)
+ for i, f := range p.Function {
+ f.ID = uint64(i + 1)
+ }
+
+ if r != 1.0 {
+ for _, s := range pb.Sample {
+ for i, v := range s.Value {
+ s.Value[i] = int64((float64(v) * r))
+ }
+ }
+ }
+ p.Sample = append(p.Sample, pb.Sample...)
+ return p.CheckValid()
+}
+
+// Compatible determines if two profiles can be compared/merged.
+// returns nil if the profiles are compatible; otherwise an error with
+// details on the incompatibility.
+func (p *Profile) Compatible(pb *Profile) error {
+ if !compatibleValueTypes(p.PeriodType, pb.PeriodType) {
+ return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
+ }
+
+ if len(p.SampleType) != len(pb.SampleType) {
+ return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
+ }
+
+ for i := range p.SampleType {
+ if !compatibleValueTypes(p.SampleType[i], pb.SampleType[i]) {
+ return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
+ }
+ }
+
+ return nil
+}
+
+// HasFunctions determines if all locations in this profile have
+// symbolized function information.
+func (p *Profile) HasFunctions() bool {
+ for _, l := range p.Location {
+ if l.Mapping == nil || !l.Mapping.HasFunctions {
+ return false
+ }
+ }
+ return true
+}
+
+// HasFileLines determines if all locations in this profile have
+// symbolized file and line number information.
+func (p *Profile) HasFileLines() bool {
+ for _, l := range p.Location {
+ if l.Mapping == nil || (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
+ return false
+ }
+ }
+ return true
+}
+
+func compatibleValueTypes(v1, v2 *ValueType) bool {
+ if v1 == nil || v2 == nil {
+ return true // No grounds to disqualify.
+ }
+ return v1.Type == v2.Type && v1.Unit == v2.Unit
+}
+
+// Copy makes a fully independent copy of a profile.
+func (p *Profile) Copy() *Profile {
+ p.preEncode()
+ b := marshal(p)
+
+ pp := &Profile{}
+ if err := unmarshal(b, pp); err != nil {
+ panic(err)
+ }
+ if err := pp.postDecode(); err != nil {
+ panic(err)
+ }
+
+ return pp
+}
+
+// Demangler maps symbol names to a human-readable form. This may
+// include C++ demangling and additional simplification. Names that
+// are not demangled may be missing from the resulting map.
+type Demangler func(name []string) (map[string]string, error)
+
+// Demangle attempts to demangle and optionally simplify any function
+// names referenced in the profile. It works on a best-effort basis:
+// it will silently preserve the original names in case of any errors.
+func (p *Profile) Demangle(d Demangler) error {
+ // Collect names to demangle.
+ var names []string
+ for _, fn := range p.Function {
+ names = append(names, fn.SystemName)
+ }
+
+ // Update profile with demangled names.
+ demangled, err := d(names)
+ if err != nil {
+ return err
+ }
+ for _, fn := range p.Function {
+ if dd, ok := demangled[fn.SystemName]; ok {
+ fn.Name = dd
+ }
+ }
+ return nil
+}
+
+// Empty returns true if the profile contains no samples.
+func (p *Profile) Empty() bool {
+ return len(p.Sample) == 0
+}
diff --git a/libgo/go/internal/pprof/profile/profile_test.go b/libgo/go/internal/pprof/profile/profile_test.go
new file mode 100644
index 0000000000..e1963f3351
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/profile_test.go
@@ -0,0 +1,79 @@
+// 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 profile
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestEmptyProfile(t *testing.T) {
+ var buf bytes.Buffer
+ p, err := Parse(&buf)
+ if err != nil {
+ t.Error("Want no error, got", err)
+ }
+ if p == nil {
+ t.Fatal("Want a valid profile, got <nil>")
+ }
+ if !p.Empty() {
+ t.Errorf("Profile should be empty, got %#v", p)
+ }
+}
+
+func TestParseContention(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ wantErr bool
+ }{
+ {
+ name: "valid",
+ in: `--- mutex:
+cycles/second=3491920901
+sampling period=1
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
+34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
+`,
+ },
+ {
+ name: "valid with comment",
+ in: `--- mutex:
+cycles/second=3491920901
+sampling period=1
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
+# 0x45e850 sync.(*Mutex).Unlock+0x80 /go/src/sync/mutex.go:126
+# 0x45f763 sync.(*RWMutex).Unlock+0x83 /go/src/sync/rwmutex.go:125
+# 0x4a2be0 main.main.func3+0x70 /go/src/internal/pprof/profile/a_binary.go:58
+
+34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
+# 0x45e850 sync.(*Mutex).Unlock+0x80 /go/src/sync/mutex.go:126
+# 0x45f763 sync.(*RWMutex).Unlock+0x83 /go/src/sync/rwmutex.go:125
+# 0x4a2b16 main.main.func2+0xd6 /go/src/internal/pprof/profile/a_binary.go:48
+`,
+ },
+ {
+ name: "empty",
+ in: `--- mutex:`,
+ wantErr: true,
+ },
+ {
+ name: "invalid header",
+ in: `--- channel:
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31`,
+ wantErr: true,
+ },
+ }
+ for _, tc := range tests {
+ _, err := parseContention([]byte(tc.in))
+ if tc.wantErr && err == nil {
+ t.Errorf("parseContention(%q) succeeded unexpectedly", tc.name)
+ }
+ if !tc.wantErr && err != nil {
+ t.Errorf("parseContention(%q) failed unexpectedly: %v", tc.name, err)
+ }
+ }
+
+}
diff --git a/libgo/go/internal/pprof/profile/proto.go b/libgo/go/internal/pprof/profile/proto.go
new file mode 100644
index 0000000000..11d7f9ff9b
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/proto.go
@@ -0,0 +1,360 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is a simple protocol buffer encoder and decoder.
+//
+// A protocol message must implement the message interface:
+// decoder() []decoder
+// encode(*buffer)
+//
+// The decode method returns a slice indexed by field number that gives the
+// function to decode that field.
+// The encode method encodes its receiver into the given buffer.
+//
+// The two methods are simple enough to be implemented by hand rather than
+// by using a protocol compiler.
+//
+// See profile.go for examples of messages implementing this interface.
+//
+// There is no support for groups, message sets, or "has" bits.
+
+package profile
+
+import "errors"
+
+type buffer struct {
+ field int
+ typ int
+ u64 uint64
+ data []byte
+ tmp [16]byte
+}
+
+type decoder func(*buffer, message) error
+
+type message interface {
+ decoder() []decoder
+ encode(*buffer)
+}
+
+func marshal(m message) []byte {
+ var b buffer
+ m.encode(&b)
+ return b.data
+}
+
+func encodeVarint(b *buffer, x uint64) {
+ for x >= 128 {
+ b.data = append(b.data, byte(x)|0x80)
+ x >>= 7
+ }
+ b.data = append(b.data, byte(x))
+}
+
+func encodeLength(b *buffer, tag int, len int) {
+ encodeVarint(b, uint64(tag)<<3|2)
+ encodeVarint(b, uint64(len))
+}
+
+func encodeUint64(b *buffer, tag int, x uint64) {
+ // append varint to b.data
+ encodeVarint(b, uint64(tag)<<3|0)
+ encodeVarint(b, x)
+}
+
+func encodeUint64s(b *buffer, tag int, x []uint64) {
+ if len(x) > 2 {
+ // Use packed encoding
+ n1 := len(b.data)
+ for _, u := range x {
+ encodeVarint(b, u)
+ }
+ n2 := len(b.data)
+ encodeLength(b, tag, n2-n1)
+ n3 := len(b.data)
+ copy(b.tmp[:], b.data[n2:n3])
+ copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+ copy(b.data[n1:], b.tmp[:n3-n2])
+ return
+ }
+ for _, u := range x {
+ encodeUint64(b, tag, u)
+ }
+}
+
+func encodeUint64Opt(b *buffer, tag int, x uint64) {
+ if x == 0 {
+ return
+ }
+ encodeUint64(b, tag, x)
+}
+
+func encodeInt64(b *buffer, tag int, x int64) {
+ u := uint64(x)
+ encodeUint64(b, tag, u)
+}
+
+func encodeInt64Opt(b *buffer, tag int, x int64) {
+ if x == 0 {
+ return
+ }
+ encodeInt64(b, tag, x)
+}
+
+func encodeInt64s(b *buffer, tag int, x []int64) {
+ if len(x) > 2 {
+ // Use packed encoding
+ n1 := len(b.data)
+ for _, u := range x {
+ encodeVarint(b, uint64(u))
+ }
+ n2 := len(b.data)
+ encodeLength(b, tag, n2-n1)
+ n3 := len(b.data)
+ copy(b.tmp[:], b.data[n2:n3])
+ copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+ copy(b.data[n1:], b.tmp[:n3-n2])
+ return
+ }
+ for _, u := range x {
+ encodeInt64(b, tag, u)
+ }
+}
+
+func encodeString(b *buffer, tag int, x string) {
+ encodeLength(b, tag, len(x))
+ b.data = append(b.data, x...)
+}
+
+func encodeStrings(b *buffer, tag int, x []string) {
+ for _, s := range x {
+ encodeString(b, tag, s)
+ }
+}
+
+func encodeStringOpt(b *buffer, tag int, x string) {
+ if x == "" {
+ return
+ }
+ encodeString(b, tag, x)
+}
+
+func encodeBool(b *buffer, tag int, x bool) {
+ if x {
+ encodeUint64(b, tag, 1)
+ } else {
+ encodeUint64(b, tag, 0)
+ }
+}
+
+func encodeBoolOpt(b *buffer, tag int, x bool) {
+ if x == false {
+ return
+ }
+ encodeBool(b, tag, x)
+}
+
+func encodeMessage(b *buffer, tag int, m message) {
+ n1 := len(b.data)
+ m.encode(b)
+ n2 := len(b.data)
+ encodeLength(b, tag, n2-n1)
+ n3 := len(b.data)
+ copy(b.tmp[:], b.data[n2:n3])
+ copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+ copy(b.data[n1:], b.tmp[:n3-n2])
+}
+
+func unmarshal(data []byte, m message) (err error) {
+ b := buffer{data: data, typ: 2}
+ return decodeMessage(&b, m)
+}
+
+func le64(p []byte) uint64 {
+ return 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
+}
+
+func le32(p []byte) uint32 {
+ return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+}
+
+func decodeVarint(data []byte) (uint64, []byte, error) {
+ var i int
+ var u uint64
+ for i = 0; ; i++ {
+ if i >= 10 || i >= len(data) {
+ return 0, nil, errors.New("bad varint")
+ }
+ u |= uint64(data[i]&0x7F) << uint(7*i)
+ if data[i]&0x80 == 0 {
+ return u, data[i+1:], nil
+ }
+ }
+}
+
+func decodeField(b *buffer, data []byte) ([]byte, error) {
+ x, data, err := decodeVarint(data)
+ if err != nil {
+ return nil, err
+ }
+ b.field = int(x >> 3)
+ b.typ = int(x & 7)
+ b.data = nil
+ b.u64 = 0
+ switch b.typ {
+ case 0:
+ b.u64, data, err = decodeVarint(data)
+ if err != nil {
+ return nil, err
+ }
+ case 1:
+ if len(data) < 8 {
+ return nil, errors.New("not enough data")
+ }
+ b.u64 = le64(data[:8])
+ data = data[8:]
+ case 2:
+ var n uint64
+ n, data, err = decodeVarint(data)
+ if err != nil {
+ return nil, err
+ }
+ if n > uint64(len(data)) {
+ return nil, errors.New("too much data")
+ }
+ b.data = data[:n]
+ data = data[n:]
+ case 5:
+ if len(data) < 4 {
+ return nil, errors.New("not enough data")
+ }
+ b.u64 = uint64(le32(data[:4]))
+ data = data[4:]
+ default:
+ return nil, errors.New("unknown type: " + string(b.typ))
+ }
+
+ return data, nil
+}
+
+func checkType(b *buffer, typ int) error {
+ if b.typ != typ {
+ return errors.New("type mismatch")
+ }
+ return nil
+}
+
+func decodeMessage(b *buffer, m message) error {
+ if err := checkType(b, 2); err != nil {
+ return err
+ }
+ dec := m.decoder()
+ data := b.data
+ for len(data) > 0 {
+ // pull varint field# + type
+ var err error
+ data, err = decodeField(b, data)
+ if err != nil {
+ return err
+ }
+ if b.field >= len(dec) || dec[b.field] == nil {
+ continue
+ }
+ if err := dec[b.field](b, m); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func decodeInt64(b *buffer, x *int64) error {
+ if err := checkType(b, 0); err != nil {
+ return err
+ }
+ *x = int64(b.u64)
+ return nil
+}
+
+func decodeInt64s(b *buffer, x *[]int64) error {
+ if b.typ == 2 {
+ // Packed encoding
+ data := b.data
+ for len(data) > 0 {
+ var u uint64
+ var err error
+
+ if u, data, err = decodeVarint(data); err != nil {
+ return err
+ }
+ *x = append(*x, int64(u))
+ }
+ return nil
+ }
+ var i int64
+ if err := decodeInt64(b, &i); err != nil {
+ return err
+ }
+ *x = append(*x, i)
+ return nil
+}
+
+func decodeUint64(b *buffer, x *uint64) error {
+ if err := checkType(b, 0); err != nil {
+ return err
+ }
+ *x = b.u64
+ return nil
+}
+
+func decodeUint64s(b *buffer, x *[]uint64) error {
+ if b.typ == 2 {
+ data := b.data
+ // Packed encoding
+ for len(data) > 0 {
+ var u uint64
+ var err error
+
+ if u, data, err = decodeVarint(data); err != nil {
+ return err
+ }
+ *x = append(*x, u)
+ }
+ return nil
+ }
+ var u uint64
+ if err := decodeUint64(b, &u); err != nil {
+ return err
+ }
+ *x = append(*x, u)
+ return nil
+}
+
+func decodeString(b *buffer, x *string) error {
+ if err := checkType(b, 2); err != nil {
+ return err
+ }
+ *x = string(b.data)
+ return nil
+}
+
+func decodeStrings(b *buffer, x *[]string) error {
+ var s string
+ if err := decodeString(b, &s); err != nil {
+ return err
+ }
+ *x = append(*x, s)
+ return nil
+}
+
+func decodeBool(b *buffer, x *bool) error {
+ if err := checkType(b, 0); err != nil {
+ return err
+ }
+ if int64(b.u64) == 0 {
+ *x = false
+ } else {
+ *x = true
+ }
+ return nil
+}
diff --git a/libgo/go/internal/pprof/profile/proto_test.go b/libgo/go/internal/pprof/profile/proto_test.go
new file mode 100644
index 0000000000..c2613fc375
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/proto_test.go
@@ -0,0 +1,67 @@
+package profile
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestPackedEncoding(t *testing.T) {
+
+ type testcase struct {
+ uint64s []uint64
+ int64s []int64
+ encoded []byte
+ }
+ for i, tc := range []testcase{
+ {
+ []uint64{0, 1, 10, 100, 1000, 10000},
+ []int64{1000, 0, 1000},
+ []byte{10, 8, 0, 1, 10, 100, 232, 7, 144, 78, 18, 5, 232, 7, 0, 232, 7},
+ },
+ {
+ []uint64{10000},
+ nil,
+ []byte{8, 144, 78},
+ },
+ {
+ nil,
+ []int64{-10000},
+ []byte{16, 240, 177, 255, 255, 255, 255, 255, 255, 255, 1},
+ },
+ } {
+ source := &packedInts{tc.uint64s, tc.int64s}
+ if got, want := marshal(source), tc.encoded; !reflect.DeepEqual(got, want) {
+ t.Errorf("failed encode %d, got %v, want %v", i, got, want)
+ }
+
+ dest := new(packedInts)
+ if err := unmarshal(tc.encoded, dest); err != nil {
+ t.Errorf("failed decode %d: %v", i, err)
+ continue
+ }
+ if got, want := dest.uint64s, tc.uint64s; !reflect.DeepEqual(got, want) {
+ t.Errorf("failed decode uint64s %d, got %v, want %v", i, got, want)
+ }
+ if got, want := dest.int64s, tc.int64s; !reflect.DeepEqual(got, want) {
+ t.Errorf("failed decode int64s %d, got %v, want %v", i, got, want)
+ }
+ }
+}
+
+type packedInts struct {
+ uint64s []uint64
+ int64s []int64
+}
+
+func (u *packedInts) decoder() []decoder {
+ return []decoder{
+ nil,
+ func(b *buffer, m message) error { return decodeUint64s(b, &m.(*packedInts).uint64s) },
+ func(b *buffer, m message) error { return decodeInt64s(b, &m.(*packedInts).int64s) },
+ }
+}
+
+func (u *packedInts) encode(b *buffer) {
+ encodeUint64s(b, 1, u.uint64s)
+ encodeInt64s(b, 2, u.int64s)
+}
diff --git a/libgo/go/internal/pprof/profile/prune.go b/libgo/go/internal/pprof/profile/prune.go
new file mode 100644
index 0000000000..1924fada7a
--- /dev/null
+++ b/libgo/go/internal/pprof/profile/prune.go
@@ -0,0 +1,97 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implements methods to remove frames from profiles.
+
+package profile
+
+import (
+ "fmt"
+ "regexp"
+)
+
+// Prune removes all nodes beneath a node matching dropRx, and not
+// matching keepRx. If the root node of a Sample matches, the sample
+// will have an empty stack.
+func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
+ prune := make(map[uint64]bool)
+ pruneBeneath := make(map[uint64]bool)
+
+ for _, loc := range p.Location {
+ var i int
+ for i = len(loc.Line) - 1; i >= 0; i-- {
+ if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
+ funcName := fn.Name
+ // Account for leading '.' on the PPC ELF v1 ABI.
+ if funcName[0] == '.' {
+ funcName = funcName[1:]
+ }
+ if dropRx.MatchString(funcName) {
+ if keepRx == nil || !keepRx.MatchString(funcName) {
+ break
+ }
+ }
+ }
+ }
+
+ if i >= 0 {
+ // Found matching entry to prune.
+ pruneBeneath[loc.ID] = true
+
+ // Remove the matching location.
+ if i == len(loc.Line)-1 {
+ // Matched the top entry: prune the whole location.
+ prune[loc.ID] = true
+ } else {
+ loc.Line = loc.Line[i+1:]
+ }
+ }
+ }
+
+ // Prune locs from each Sample
+ for _, sample := range p.Sample {
+ // Scan from the root to the leaves to find the prune location.
+ // Do not prune frames before the first user frame, to avoid
+ // pruning everything.
+ foundUser := false
+ for i := len(sample.Location) - 1; i >= 0; i-- {
+ id := sample.Location[i].ID
+ if !prune[id] && !pruneBeneath[id] {
+ foundUser = true
+ continue
+ }
+ if !foundUser {
+ continue
+ }
+ if prune[id] {
+ sample.Location = sample.Location[i+1:]
+ break
+ }
+ if pruneBeneath[id] {
+ sample.Location = sample.Location[i:]
+ break
+ }
+ }
+ }
+}
+
+// RemoveUninteresting prunes and elides profiles using built-in
+// tables of uninteresting function names.
+func (p *Profile) RemoveUninteresting() error {
+ var keep, drop *regexp.Regexp
+ var err error
+
+ if p.DropFrames != "" {
+ if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
+ return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
+ }
+ if p.KeepFrames != "" {
+ if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
+ return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
+ }
+ }
+ p.Prune(drop, keep)
+ }
+ return nil
+}
diff --git a/libgo/go/internal/race/doc.go b/libgo/go/internal/race/doc.go
index d6a2243eb8..8fa44ce6f1 100644
--- a/libgo/go/internal/race/doc.go
+++ b/libgo/go/internal/race/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/internal/race/norace.go b/libgo/go/internal/race/norace.go
index d9049eb1eb..d83c0165b2 100644
--- a/libgo/go/internal/race/norace.go
+++ b/libgo/go/internal/race/norace.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -38,3 +38,5 @@ func ReadRange(addr unsafe.Pointer, len int) {
func WriteRange(addr unsafe.Pointer, len int) {
}
+
+func Errors() int { return 0 }
diff --git a/libgo/go/internal/race/race.go b/libgo/go/internal/race/race.go
index cb0e773c44..2e7d97beaa 100644
--- a/libgo/go/internal/race/race.go
+++ b/libgo/go/internal/race/race.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -48,3 +48,7 @@ func ReadRange(addr unsafe.Pointer, len int) {
func WriteRange(addr unsafe.Pointer, len int) {
runtime.RaceWriteRange(addr, len)
}
+
+func Errors() int {
+ return runtime.RaceErrors()
+}
diff --git a/libgo/go/internal/singleflight/singleflight.go b/libgo/go/internal/singleflight/singleflight.go
index f4cb2d670d..de81ac87b9 100644
--- a/libgo/go/internal/singleflight/singleflight.go
+++ b/libgo/go/internal/singleflight/singleflight.go
@@ -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.
diff --git a/libgo/go/internal/singleflight/singleflight_test.go b/libgo/go/internal/singleflight/singleflight_test.go
index c0ec0240c7..5e6f1b328e 100644
--- a/libgo/go/internal/singleflight/singleflight_test.go
+++ b/libgo/go/internal/singleflight/singleflight_test.go
@@ -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.
diff --git a/libgo/go/internal/syscall/unix/getentropy_openbsd.go b/libgo/go/internal/syscall/unix/getentropy_openbsd.go
new file mode 100644
index 0000000000..d5caa8095a
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getentropy_openbsd.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// getentropy(2)'s syscall number, from /usr/src/sys/kern/syscalls.master
+const entropyTrap uintptr = 7
+
+// GetEntropy calls the OpenBSD getentropy system call.
+func GetEntropy(p []byte) error {
+ _, _, errno := syscall.Syscall(entropyTrap,
+ uintptr(unsafe.Pointer(&p[0])),
+ uintptr(len(p)),
+ 0)
+ if errno != 0 {
+ return errno
+ }
+ return nil
+}
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux.go b/libgo/go/internal/syscall/unix/getrandom_linux.go
index e07557a93b..0d0d4f115c 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_386.go b/libgo/go/internal/syscall/unix/getrandom_linux_386.go
index 48c69b4585..a583896e68 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_386.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_386.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
const randomTrap uintptr = 355
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_alpha.go b/libgo/go/internal/syscall/unix/getrandom_linux_alpha.go
new file mode 100644
index 0000000000..9587b5aa4c
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_alpha.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 511
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go b/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go
index 7175e36e31..cff0eb6f05 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
const randomTrap uintptr = 318
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_arm.go b/libgo/go/internal/syscall/unix/getrandom_linux_arm.go
index c4d6f43d56..92e2492cd0 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_arm.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_arm.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
const randomTrap uintptr = 384
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go
index 0e632dc27a..8425800b6d 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,4 +6,11 @@
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+//
+// This file is named "generic" because at a certain point Linux
+// started standardizing on system call numbers across
+// architectures. So far this means only arm64 uses the standard
+// numbers.
const randomTrap uintptr = 278
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_ia64.go b/libgo/go/internal/syscall/unix/getrandom_linux_ia64.go
new file mode 100644
index 0000000000..d20ba238fc
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_ia64.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 1339
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_m68k.go b/libgo/go/internal/syscall/unix/getrandom_linux_m68k.go
new file mode 100644
index 0000000000..5559d30d33
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_m68k.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 352
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go b/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go
index 8531db68b0..02fd1a0642 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go
@@ -1,9 +1,11 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 mips64 mips64le
+// +build mips64 mips64le mipsn64 mipso64
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
const randomTrap uintptr = 5313
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_mipsn32.go b/libgo/go/internal/syscall/unix/getrandom_linux_mipsn32.go
new file mode 100644
index 0000000000..8f481fa58d
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_mipsn32.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mipsn32
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 6317
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_mipso32.go b/libgo/go/internal/syscall/unix/getrandom_linux_mipso32.go
new file mode 100644
index 0000000000..612d00b4af
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_mipso32.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mipso32
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 4353
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_mipsx.go b/libgo/go/internal/syscall/unix/getrandom_linux_mipsx.go
new file mode 100644
index 0000000000..af7b7229b1
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_mipsx.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 4353
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go b/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go
index 6edaba2f14..a7d0bd9f73 100644
--- a/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go
@@ -1,9 +1,11 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build ppc64 ppc64le
+// +build ppc ppc64 ppc64le
package unix
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
const randomTrap uintptr = 359
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_s390.go b/libgo/go/internal/syscall/unix/getrandom_linux_s390.go
new file mode 100644
index 0000000000..e3bc4ee355
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_s390.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 349
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_s390x.go b/libgo/go/internal/syscall/unix/getrandom_linux_s390x.go
new file mode 100644
index 0000000000..e3bc4ee355
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_s390x.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 349
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_sparcx.go b/libgo/go/internal/syscall/unix/getrandom_linux_sparcx.go
new file mode 100644
index 0000000000..4874ec1bd8
--- /dev/null
+++ b/libgo/go/internal/syscall/unix/getrandom_linux_sparcx.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build sparc sparc64
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 347
diff --git a/libgo/go/internal/syscall/windows/mksyscall.go b/libgo/go/internal/syscall/windows/mksyscall.go
new file mode 100644
index 0000000000..91fa2b3b81
--- /dev/null
+++ b/libgo/go/internal/syscall/windows/mksyscall.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
diff --git a/libgo/go/internal/syscall/windows/registry/mksyscall.go b/libgo/go/internal/syscall/windows/registry/mksyscall.go
new file mode 100644
index 0000000000..077215351e
--- /dev/null
+++ b/libgo/go/internal/syscall/windows/registry/mksyscall.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package registry
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
diff --git a/libgo/go/internal/syscall/windows/registry/registry_test.go b/libgo/go/internal/syscall/windows/registry/registry_test.go
index a63c42022d..56069d7684 100644
--- a/libgo/go/internal/syscall/windows/registry/registry_test.go
+++ b/libgo/go/internal/syscall/windows/registry/registry_test.go
@@ -213,7 +213,7 @@ func enumerateValues(t *testing.T, k registry.Key) {
}
}
for n, v := range haveNames {
- t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+ t.Errorf("value %s (%v) is found while enumerating, but has not been created", n, v)
}
}
@@ -335,7 +335,7 @@ func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
// read data with short buffer
gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
if err == nil {
- t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1)
+ t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1)
return
}
if err != registry.ErrShortBuffer {
diff --git a/libgo/go/internal/syscall/windows/registry/syscall.go b/libgo/go/internal/syscall/windows/registry/syscall.go
index 02d985cec9..a6525dac5d 100644
--- a/libgo/go/internal/syscall/windows/registry/syscall.go
+++ b/libgo/go/internal/syscall/windows/registry/syscall.go
@@ -8,8 +8,6 @@ package registry
import "syscall"
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall.go
-
const (
_REG_OPTION_NON_VOLATILE = 0
diff --git a/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go b/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go
index 7e473d4e1d..a3a1f5fc8f 100644
--- a/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go
+++ b/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go
@@ -2,12 +2,39 @@
package registry
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+ "internal/syscall/windows/sysdll"
+ "syscall"
+ "unsafe"
+)
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
@@ -74,7 +101,7 @@ func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32,
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
diff --git a/libgo/go/internal/syscall/windows/reparse_windows.go b/libgo/go/internal/syscall/windows/reparse_windows.go
new file mode 100644
index 0000000000..7c6ad8fb7e
--- /dev/null
+++ b/libgo/go/internal/syscall/windows/reparse_windows.go
@@ -0,0 +1,64 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+const (
+ FSCTL_SET_REPARSE_POINT = 0x000900A4
+ IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
+
+ SYMLINK_FLAG_RELATIVE = 1
+)
+
+// These structures are described
+// in https://msdn.microsoft.com/en-us/library/cc232007.aspx
+// and https://msdn.microsoft.com/en-us/library/cc232006.aspx.
+
+// REPARSE_DATA_BUFFER_HEADER is a common part of REPARSE_DATA_BUFFER structure.
+type REPARSE_DATA_BUFFER_HEADER struct {
+ ReparseTag uint32
+ // The size, in bytes, of the reparse data that follows
+ // the common portion of the REPARSE_DATA_BUFFER element.
+ // This value is the length of the data starting at the
+ // SubstituteNameOffset field.
+ ReparseDataLength uint16
+ Reserved uint16
+}
+
+type SymbolicLinkReparseBuffer struct {
+ // The integer that contains the offset, in bytes,
+ // of the substitute name string in the PathBuffer array,
+ // computed as an offset from byte 0 of PathBuffer. Note that
+ // this offset must be divided by 2 to get the array index.
+ SubstituteNameOffset uint16
+ // The integer that contains the length, in bytes, of the
+ // substitute name string. If this string is null-terminated,
+ // SubstituteNameLength does not include the Unicode null character.
+ SubstituteNameLength uint16
+ // PrintNameOffset is similar to SubstituteNameOffset.
+ PrintNameOffset uint16
+ // PrintNameLength is similar to SubstituteNameLength.
+ PrintNameLength uint16
+ // Flags specifies whether the substitute name is a full path name or
+ // a path name relative to the directory containing the symbolic link.
+ Flags uint32
+ PathBuffer [1]uint16
+}
+
+type MountPointReparseBuffer struct {
+ // The integer that contains the offset, in bytes,
+ // of the substitute name string in the PathBuffer array,
+ // computed as an offset from byte 0 of PathBuffer. Note that
+ // this offset must be divided by 2 to get the array index.
+ SubstituteNameOffset uint16
+ // The integer that contains the length, in bytes, of the
+ // substitute name string. If this string is null-terminated,
+ // SubstituteNameLength does not include the Unicode null character.
+ SubstituteNameLength uint16
+ // PrintNameOffset is similar to SubstituteNameOffset.
+ PrintNameOffset uint16
+ // PrintNameLength is similar to SubstituteNameLength.
+ PrintNameLength uint16
+ PathBuffer [1]uint16
+}
diff --git a/libgo/go/internal/syscall/windows/security_windows.go b/libgo/go/internal/syscall/windows/security_windows.go
new file mode 100644
index 0000000000..2c145e160f
--- /dev/null
+++ b/libgo/go/internal/syscall/windows/security_windows.go
@@ -0,0 +1,57 @@
+// 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 windows
+
+import (
+ "syscall"
+)
+
+const (
+ SecurityAnonymous = 0
+ SecurityIdentification = 1
+ SecurityImpersonation = 2
+ SecurityDelegation = 3
+)
+
+//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
+//sys RevertToSelf() (err error) = advapi32.RevertToSelf
+
+const (
+ TOKEN_ADJUST_PRIVILEGES = 0x0020
+ SE_PRIVILEGE_ENABLED = 0x00000002
+)
+
+type LUID struct {
+ LowPart uint32
+ HighPart int32
+}
+
+type LUID_AND_ATTRIBUTES struct {
+ Luid LUID
+ Attributes uint32
+}
+
+type TOKEN_PRIVILEGES struct {
+ PrivilegeCount uint32
+ Privileges [1]LUID_AND_ATTRIBUTES
+}
+
+//sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
+//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
+//sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
+
+func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
+ ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
+ if ret == 0 {
+ // AdjustTokenPrivileges call failed
+ return err
+ }
+ // AdjustTokenPrivileges call succeeded
+ if err == syscall.EINVAL {
+ // GetLastError returned ERROR_SUCCESS
+ return nil
+ }
+ return err
+}
diff --git a/libgo/go/internal/syscall/windows/syscall_windows.go b/libgo/go/internal/syscall/windows/syscall_windows.go
index e6a3f238d8..ec08a5a92c 100644
--- a/libgo/go/internal/syscall/windows/syscall_windows.go
+++ b/libgo/go/internal/syscall/windows/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,7 +6,10 @@ package windows
import "syscall"
-//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall_windows.go
+const (
+ ERROR_SHARING_VIOLATION syscall.Errno = 32
+ ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113
+)
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
@@ -107,6 +110,7 @@ const (
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
+//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
const (
ComputerNameNetBIOS = 0
@@ -139,5 +143,25 @@ func Rename(oldpath, newpath string) error {
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
}
+const MB_ERR_INVALID_CHARS = 8
+
//sys GetACP() (acp uint32) = kernel32.GetACP
+//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
+//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread
+
+const STYPE_DISKTREE = 0x00
+
+type SHARE_INFO_2 struct {
+ Netname *uint16
+ Type uint32
+ Remark *uint16
+ Permissions uint32
+ MaxUses uint32
+ CurrentUses uint32
+ Path *uint16
+ Passwd *uint16
+}
+
+//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd
+//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel
diff --git a/libgo/go/internal/syscall/windows/zsyscall_windows.go b/libgo/go/internal/syscall/windows/zsyscall_windows.go
index d599258976..7a2ffeeffa 100644
--- a/libgo/go/internal/syscall/windows/zsyscall_windows.go
+++ b/libgo/go/internal/syscall/windows/zsyscall_windows.go
@@ -2,21 +2,60 @@
package windows
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+ "internal/syscall/windows/sysdll"
+ "syscall"
+ "unsafe"
+)
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
+ modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
+ modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
- procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
- procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
- procMoveFileExW = modkernel32.NewProc("MoveFileExW")
- procGetACP = modkernel32.NewProc("GetACP")
- procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+ procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
+ procMoveFileExW = modkernel32.NewProc("MoveFileExW")
+ procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
+ procGetACP = modkernel32.NewProc("GetACP")
+ procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
+ procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
+ procNetShareDel = modnetapi32.NewProc("NetShareDel")
+ procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
+ procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
+ procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
+ procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
+ procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
)
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
@@ -31,7 +70,7 @@ func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
@@ -43,7 +82,20 @@ func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
@@ -57,12 +109,120 @@ func GetACP() (acp uint32) {
return
}
+func GetConsoleCP() (ccp uint32) {
+ r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0)
+ ccp = uint32(r0)
+ return
+}
+
func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) {
r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar))
nwrite = int32(r0)
if nwrite == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCurrentThread() (pseudoHandle syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
+ pseudoHandle = syscall.Handle(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) {
+ r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0)
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) {
+ r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved))
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func ImpersonateSelf(impersonationlevel uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func RevertToSelf() (err error) {
+ r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) {
+ var _p0 uint32
+ if openasself {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) {
+ r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) {
+ var _p0 uint32
+ if disableAllPrivileges {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen)))
+ ret = uint32(r0)
+ if true {
+ if e1 != 0 {
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
diff --git a/libgo/go/internal/testenv/testenv.go b/libgo/go/internal/testenv/testenv.go
index 10719084bb..71a692b367 100644
--- a/libgo/go/internal/testenv/testenv.go
+++ b/libgo/go/internal/testenv/testenv.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -11,8 +11,13 @@
package testenv
import (
+ "errors"
+ "flag"
"os"
+ "os/exec"
+ "path/filepath"
"runtime"
+ "strconv"
"strings"
"testing"
)
@@ -65,6 +70,39 @@ func MustHaveGoRun(t *testing.T) {
}
}
+// GoToolPath reports the path to the Go tool.
+// It is a convenience wrapper around GoTool.
+// If the tool is unavailable GoToolPath calls t.Skip.
+// If the tool should be available and isn't, GoToolPath calls t.Fatal.
+func GoToolPath(t *testing.T) string {
+ MustHaveGoBuild(t)
+ path, err := GoTool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return path
+}
+
+// GoTool reports the path to the Go tool.
+func GoTool() (string, error) {
+ if !HasGoBuild() {
+ return "", errors.New("platform cannot run go tool")
+ }
+ var exeSuffix string
+ if runtime.GOOS == "windows" {
+ exeSuffix = ".exe"
+ }
+ path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
+ if _, err := os.Stat(path); err == nil {
+ return path, nil
+ }
+ goBin, err := exec.LookPath("go" + exeSuffix)
+ if err != nil {
+ return "", errors.New("cannot find go tool: " + err.Error())
+ }
+ return goBin, nil
+}
+
// HasExec reports whether the current system can start new processes
// using os.StartProcess or (more commonly) exec.Command.
func HasExec() bool {
@@ -102,3 +140,57 @@ func MustHaveExternalNetwork(t *testing.T) {
t.Skipf("skipping test: no external network in -short mode")
}
}
+
+var haveCGO bool
+
+// MustHaveCGO calls t.Skip if cgo is not available.
+func MustHaveCGO(t *testing.T) {
+ if !haveCGO {
+ t.Skipf("skipping test: no cgo")
+ }
+}
+
+// HasSymlink reports whether the current system can use os.Symlink.
+func HasSymlink() bool {
+ ok, _ := hasSymlink()
+ return ok
+}
+
+// MustHaveSymlink reports whether the current system can use os.Symlink.
+// If not, MustHaveSymlink calls t.Skip with an explanation.
+func MustHaveSymlink(t *testing.T) {
+ ok, reason := hasSymlink()
+ if !ok {
+ t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
+ }
+}
+
+// HasLink reports whether the current system can use os.Link.
+func HasLink() bool {
+ // From Android release M (Marshmallow), hard linking files is blocked
+ // and an attempt to call link() on a file will return EACCES.
+ // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
+ return runtime.GOOS != "plan9" && runtime.GOOS != "android"
+}
+
+// MustHaveLink reports whether the current system can use os.Link.
+// If not, MustHaveLink calls t.Skip with an explanation.
+func MustHaveLink(t *testing.T) {
+ if !HasLink() {
+ t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+}
+
+var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
+
+func SkipFlaky(t *testing.T, issue int) {
+ if !*flaky {
+ t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
+ }
+}
+
+func SkipFlakyNet(t *testing.T) {
+ if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
+ t.Skip("skipping test on builder known to have frequent network failures")
+ }
+}
diff --git a/libgo/go/internal/testenv/testenv_cgo.go b/libgo/go/internal/testenv/testenv_cgo.go
new file mode 100644
index 0000000000..e3d4d16b33
--- /dev/null
+++ b/libgo/go/internal/testenv/testenv_cgo.go
@@ -0,0 +1,11 @@
+// Copyright 2017 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 cgo
+
+package testenv
+
+func init() {
+ haveCGO = true
+}
diff --git a/libgo/go/internal/testenv/testenv_notwin.go b/libgo/go/internal/testenv/testenv_notwin.go
new file mode 100644
index 0000000000..d8ce6cd385
--- /dev/null
+++ b/libgo/go/internal/testenv/testenv_notwin.go
@@ -0,0 +1,20 @@
+// 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 !windows
+
+package testenv
+
+import (
+ "runtime"
+)
+
+func hasSymlink() (ok bool, reason string) {
+ switch runtime.GOOS {
+ case "android", "nacl", "plan9":
+ return false, ""
+ }
+
+ return true, ""
+}
diff --git a/libgo/go/internal/testenv/testenv_windows.go b/libgo/go/internal/testenv/testenv_windows.go
new file mode 100644
index 0000000000..e593f64711
--- /dev/null
+++ b/libgo/go/internal/testenv/testenv_windows.go
@@ -0,0 +1,49 @@
+// 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 testenv
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sync"
+ "syscall"
+)
+
+var symlinkOnce sync.Once
+var winSymlinkErr error
+
+func initWinHasSymlink() {
+ tmpdir, err := ioutil.TempDir("", "symtest")
+ if err != nil {
+ panic("failed to create temp directory: " + err.Error())
+ }
+ defer os.RemoveAll(tmpdir)
+
+ err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
+ if err != nil {
+ err = err.(*os.LinkError).Err
+ switch err {
+ case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
+ winSymlinkErr = err
+ }
+ }
+ os.Remove("target")
+}
+
+func hasSymlink() (ok bool, reason string) {
+ symlinkOnce.Do(initWinHasSymlink)
+
+ switch winSymlinkErr {
+ case nil:
+ return true, ""
+ case syscall.EWINDOWS:
+ return false, ": symlinks are not supported on your version of Windows"
+ case syscall.ERROR_PRIVILEGE_NOT_HELD:
+ return false, ": you don't have enough privileges to create symlinks"
+ }
+
+ return false, ""
+}
diff --git a/libgo/go/internal/trace/goroutines.go b/libgo/go/internal/trace/goroutines.go
index f8673e20bc..923a157416 100644
--- a/libgo/go/internal/trace/goroutines.go
+++ b/libgo/go/internal/trace/goroutines.go
@@ -48,7 +48,7 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
g.blockSchedTime = ev.Ts
gs[g.ID] = g
- case EvGoStart:
+ case EvGoStart, EvGoStartLabel:
g := gs[ev.G]
if g.PC == 0 {
g.PC = ev.Stk[0].PC
@@ -83,6 +83,10 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
g := gs[ev.G]
g.ExecTime += ev.Ts - g.lastStartTime
g.blockNetTime = ev.Ts
+ case EvGoBlockGC:
+ g := gs[ev.G]
+ g.ExecTime += ev.Ts - g.lastStartTime
+ g.blockGCTime = ev.Ts
case EvGoUnblock:
g := gs[ev.Args[0]]
if g.blockNetTime != 0 {
diff --git a/libgo/go/internal/trace/mkcanned.bash b/libgo/go/internal/trace/mkcanned.bash
new file mode 100644
index 0000000000..78c5572065
--- /dev/null
+++ b/libgo/go/internal/trace/mkcanned.bash
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2016 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# mkcanned.bash creates canned traces for the trace test suite using
+# the current Go version.
+
+set -e
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <label>" >&2
+ exit 1
+fi
+
+go test -run ClientServerParallel4 -trace "testdata/http_$1_good" net/http
+go test -run 'TraceStress$|TraceStressStartStop$' runtime/trace -savetraces
+mv ../../runtime/trace/TestTraceStress.trace "testdata/stress_$1_good"
+mv ../../runtime/trace/TestTraceStressStartStop.trace "testdata/stress_start_stop_$1_good"
diff --git a/libgo/go/internal/trace/order.go b/libgo/go/internal/trace/order.go
new file mode 100644
index 0000000000..36ed58d675
--- /dev/null
+++ b/libgo/go/internal/trace/order.go
@@ -0,0 +1,279 @@
+// 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 trace
+
+import (
+ "fmt"
+ "sort"
+)
+
+type eventBatch struct {
+ events []*Event
+ selected bool
+}
+
+type orderEvent struct {
+ ev *Event
+ batch int
+ g uint64
+ init gState
+ next gState
+}
+
+type gStatus int
+
+type gState struct {
+ seq uint64
+ status gStatus
+}
+
+const (
+ gDead gStatus = iota
+ gRunnable
+ gRunning
+ gWaiting
+
+ unordered = ^uint64(0)
+ garbage = ^uint64(0) - 1
+ noseq = ^uint64(0)
+ seqinc = ^uint64(0) - 1
+)
+
+// order1007 merges a set of per-P event batches into a single, consistent stream.
+// The high level idea is as follows. Events within an individual batch are in
+// correct order, because they are emitted by a single P. So we need to produce
+// a correct interleaving of the batches. To do this we take first unmerged event
+// from each batch (frontier). Then choose subset that is "ready" to be merged,
+// that is, events for which all dependencies are already merged. Then we choose
+// event with the lowest timestamp from the subset, merge it and repeat.
+// This approach ensures that we form a consistent stream even if timestamps are
+// incorrect (condition observed on some machines).
+func order1007(m map[int][]*Event) (events []*Event, err error) {
+ pending := 0
+ var batches []*eventBatch
+ for _, v := range m {
+ pending += len(v)
+ batches = append(batches, &eventBatch{v, false})
+ }
+ gs := make(map[uint64]gState)
+ var frontier []orderEvent
+ for ; pending != 0; pending-- {
+ for i, b := range batches {
+ if b.selected || len(b.events) == 0 {
+ continue
+ }
+ ev := b.events[0]
+ g, init, next := stateTransition(ev)
+ if !transitionReady(g, gs[g], init) {
+ continue
+ }
+ frontier = append(frontier, orderEvent{ev, i, g, init, next})
+ b.events = b.events[1:]
+ b.selected = true
+ // Get rid of "Local" events, they are intended merely for ordering.
+ switch ev.Type {
+ case EvGoStartLocal:
+ ev.Type = EvGoStart
+ case EvGoUnblockLocal:
+ ev.Type = EvGoUnblock
+ case EvGoSysExitLocal:
+ ev.Type = EvGoSysExit
+ }
+ }
+ if len(frontier) == 0 {
+ return nil, fmt.Errorf("no consistent ordering of events possible")
+ }
+ sort.Sort(orderEventList(frontier))
+ f := frontier[0]
+ frontier[0] = frontier[len(frontier)-1]
+ frontier = frontier[:len(frontier)-1]
+ events = append(events, f.ev)
+ transition(gs, f.g, f.init, f.next)
+ if !batches[f.batch].selected {
+ panic("frontier batch is not selected")
+ }
+ batches[f.batch].selected = false
+ }
+
+ // At this point we have a consistent stream of events.
+ // Make sure time stamps respect the ordering.
+ // The tests will skip (not fail) the test case if they see this error.
+ if !sort.IsSorted(eventList(events)) {
+ return nil, ErrTimeOrder
+ }
+
+ // The last part is giving correct timestamps to EvGoSysExit events.
+ // The problem with EvGoSysExit is that actual syscall exit timestamp (ev.Args[2])
+ // is potentially acquired long before event emission. So far we've used
+ // timestamp of event emission (ev.Ts).
+ // We could not set ev.Ts = ev.Args[2] earlier, because it would produce
+ // seemingly broken timestamps (misplaced event).
+ // We also can't simply update the timestamp and resort events, because
+ // if timestamps are broken we will misplace the event and later report
+ // logically broken trace (instead of reporting broken timestamps).
+ lastSysBlock := make(map[uint64]int64)
+ for _, ev := range events {
+ switch ev.Type {
+ case EvGoSysBlock, EvGoInSyscall:
+ lastSysBlock[ev.G] = ev.Ts
+ case EvGoSysExit:
+ ts := int64(ev.Args[2])
+ if ts == 0 {
+ continue
+ }
+ block := lastSysBlock[ev.G]
+ if block == 0 {
+ return nil, fmt.Errorf("stray syscall exit")
+ }
+ if ts < block {
+ return nil, ErrTimeOrder
+ }
+ ev.Ts = ts
+ }
+ }
+ sort.Stable(eventList(events))
+
+ return
+}
+
+// stateTransition returns goroutine state (sequence and status) when the event
+// becomes ready for merging (init) and the goroutine state after the event (next).
+func stateTransition(ev *Event) (g uint64, init, next gState) {
+ switch ev.Type {
+ case EvGoCreate:
+ g = ev.Args[0]
+ init = gState{0, gDead}
+ next = gState{1, gRunnable}
+ case EvGoWaiting, EvGoInSyscall:
+ g = ev.G
+ init = gState{1, gRunnable}
+ next = gState{2, gWaiting}
+ case EvGoStart, EvGoStartLabel:
+ g = ev.G
+ init = gState{ev.Args[1], gRunnable}
+ next = gState{ev.Args[1] + 1, gRunning}
+ case EvGoStartLocal:
+ // noseq means that this event is ready for merging as soon as
+ // frontier reaches it (EvGoStartLocal is emitted on the same P
+ // as the corresponding EvGoCreate/EvGoUnblock, and thus the latter
+ // is already merged).
+ // seqinc is a stub for cases when event increments g sequence,
+ // but since we don't know current seq we also don't know next seq.
+ g = ev.G
+ init = gState{noseq, gRunnable}
+ next = gState{seqinc, gRunning}
+ case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
+ EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep,
+ EvGoSysBlock, EvGoBlockGC:
+ g = ev.G
+ init = gState{noseq, gRunning}
+ next = gState{noseq, gWaiting}
+ case EvGoSched, EvGoPreempt:
+ g = ev.G
+ init = gState{noseq, gRunning}
+ next = gState{noseq, gRunnable}
+ case EvGoUnblock, EvGoSysExit:
+ g = ev.Args[0]
+ init = gState{ev.Args[1], gWaiting}
+ next = gState{ev.Args[1] + 1, gRunnable}
+ case EvGoUnblockLocal, EvGoSysExitLocal:
+ g = ev.Args[0]
+ init = gState{noseq, gWaiting}
+ next = gState{seqinc, gRunnable}
+ case EvGCStart:
+ g = garbage
+ init = gState{ev.Args[0], gDead}
+ next = gState{ev.Args[0] + 1, gDead}
+ default:
+ // no ordering requirements
+ g = unordered
+ }
+ return
+}
+
+func transitionReady(g uint64, curr, init gState) bool {
+ return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status
+}
+
+func transition(gs map[uint64]gState, g uint64, init, next gState) {
+ if g == unordered {
+ return
+ }
+ curr := gs[g]
+ if !transitionReady(g, curr, init) {
+ panic("event sequences are broken")
+ }
+ switch next.seq {
+ case noseq:
+ next.seq = curr.seq
+ case seqinc:
+ next.seq = curr.seq + 1
+ }
+ gs[g] = next
+}
+
+// order1005 merges a set of per-P event batches into a single, consistent stream.
+func order1005(m map[int][]*Event) (events []*Event, err error) {
+ for _, batch := range m {
+ events = append(events, batch...)
+ }
+ for _, ev := range events {
+ if ev.Type == EvGoSysExit {
+ // EvGoSysExit emission is delayed until the thread has a P.
+ // Give it the real sequence number and time stamp.
+ ev.seq = int64(ev.Args[1])
+ if ev.Args[2] != 0 {
+ ev.Ts = int64(ev.Args[2])
+ }
+ }
+ }
+ sort.Sort(eventSeqList(events))
+ if !sort.IsSorted(eventList(events)) {
+ return nil, ErrTimeOrder
+ }
+ return
+}
+
+type orderEventList []orderEvent
+
+func (l orderEventList) Len() int {
+ return len(l)
+}
+
+func (l orderEventList) Less(i, j int) bool {
+ return l[i].ev.Ts < l[j].ev.Ts
+}
+
+func (l orderEventList) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
+
+type eventList []*Event
+
+func (l eventList) Len() int {
+ return len(l)
+}
+
+func (l eventList) Less(i, j int) bool {
+ return l[i].Ts < l[j].Ts
+}
+
+func (l eventList) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
+
+type eventSeqList []*Event
+
+func (l eventSeqList) Len() int {
+ return len(l)
+}
+
+func (l eventSeqList) Less(i, j int) bool {
+ return l[i].seq < l[j].seq
+}
+
+func (l eventSeqList) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
diff --git a/libgo/go/internal/trace/parser.go b/libgo/go/internal/trace/parser.go
index 11f9aba616..efa85409a2 100644
--- a/libgo/go/internal/trace/parser.go
+++ b/libgo/go/internal/trace/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -9,30 +9,32 @@ import (
"bytes"
"fmt"
"io"
+ "math/rand"
"os"
"os/exec"
- "sort"
"strconv"
"strings"
+ _ "unsafe"
)
// Event describes one event in the trace.
type Event struct {
Off int // offset in input file (for debugging and error reporting)
Type byte // one of Ev*
- Seq int64 // sequence number
+ seq int64 // sequence number
Ts int64 // timestamp in nanoseconds
P int // P on which the event happened (can be one of TimerP, NetpollP, SyscallP)
G uint64 // G on which the event happened
StkID uint64 // unique stack ID
Stk []*Frame // stack trace (can be empty)
Args [3]uint64 // event-type-specific arguments
+ SArgs []string // event-type-specific string args
// linked event (can be nil), depends on event type:
// for GCStart: the GCStop
// for GCScanStart: the GCScanDone
// for GCSweepStart: the GCSweepDone
// for GoCreate: first GoStart of the created goroutine
- // for GoStart: the associated GoEnd, GoBlock or other blocking event
+ // for GoStart/GoStartLabel: the associated GoEnd, GoBlock or other blocking event
// for GoSched/GoPreempt: the next GoStart
// for GoBlock and other blocking events: the unblock event
// for GoUnblock: the associated GoStart
@@ -55,27 +57,52 @@ const (
TimerP // depicts timer unblocks
NetpollP // depicts network unblocks
SyscallP // depicts returns from syscalls
+ GCP // depicts GC state
)
// Parse parses, post-processes and verifies the trace.
-func Parse(r io.Reader) ([]*Event, error) {
- rawEvents, err := readTrace(r)
+func Parse(r io.Reader, bin string) ([]*Event, error) {
+ ver, events, err := parse(r, bin)
if err != nil {
return nil, err
}
- events, err := parseEvents(rawEvents)
+ if ver < 1007 && bin == "" {
+ return nil, fmt.Errorf("for traces produced by go 1.6 or below, the binary argument must be provided")
+ }
+ return events, nil
+}
+
+// parse parses, post-processes and verifies the trace. It returns the
+// trace version and the list of events.
+func parse(r io.Reader, bin string) (int, []*Event, error) {
+ ver, rawEvents, strings, err := readTrace(r)
if err != nil {
- return nil, err
+ return 0, nil, err
+ }
+ events, stacks, err := parseEvents(ver, rawEvents, strings)
+ if err != nil {
+ return 0, nil, err
}
events, err = removeFutile(events)
if err != nil {
- return nil, err
+ return 0, nil, err
}
- err = postProcessTrace(events)
+ err = postProcessTrace(ver, events)
if err != nil {
- return nil, err
+ return 0, nil, err
}
- return events, nil
+ // Attach stack traces.
+ for _, ev := range events {
+ if ev.StkID != 0 {
+ ev.Stk = stacks[ev.StkID]
+ }
+ }
+ if ver < 1007 && bin != "" {
+ if err := symbolize(events, bin); err != nil {
+ return 0, nil, err
+ }
+ }
+ return ver, events, nil
}
// rawEvent is a helper type used during parsing.
@@ -87,107 +114,189 @@ type rawEvent struct {
// readTrace does wire-format parsing and verification.
// It does not care about specific event types and argument meaning.
-func readTrace(r io.Reader) ([]rawEvent, error) {
+func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]string, err error) {
// Read and validate trace header.
var buf [16]byte
- off, err := r.Read(buf[:])
- if off != 16 || err != nil {
- return nil, fmt.Errorf("failed to read header: read %v, err %v", off, err)
+ off, err := io.ReadFull(r, buf[:])
+ if err != nil {
+ err = fmt.Errorf("failed to read header: read %v, err %v", off, err)
+ return
}
- if bytes.Compare(buf[:], []byte("go 1.5 trace\x00\x00\x00\x00")) != 0 {
- return nil, fmt.Errorf("not a trace file")
+ ver, err = parseHeader(buf[:])
+ if err != nil {
+ return
+ }
+ switch ver {
+ case 1005, 1007, 1008:
+ // Note: When adding a new version, add canned traces
+ // from the old version to the test suite using mkcanned.bash.
+ break
+ default:
+ err = fmt.Errorf("unsupported trace file version %v.%v (update Go toolchain) %v", ver/1000, ver%1000, ver)
+ return
}
// Read events.
- var events []rawEvent
+ strings = make(map[uint64]string)
for {
// Read event type and number of arguments (1 byte).
off0 := off
- n, err := r.Read(buf[:1])
+ var n int
+ n, err = r.Read(buf[:1])
if err == io.EOF {
+ err = nil
break
}
if err != nil || n != 1 {
- return nil, fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+ err = fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+ return
}
off += n
typ := buf[0] << 2 >> 2
- narg := buf[0] >> 6
+ narg := buf[0]>>6 + 1
+ inlineArgs := byte(4)
+ if ver < 1007 {
+ narg++
+ inlineArgs++
+ }
+ if typ == EvNone || typ >= EvCount || EventDescriptions[typ].minVersion > ver {
+ err = fmt.Errorf("unknown event type %v at offset 0x%x", typ, off0)
+ return
+ }
+ if typ == EvString {
+ // String dictionary entry [ID, length, string].
+ var id uint64
+ id, off, err = readVal(r, off)
+ if err != nil {
+ return
+ }
+ if id == 0 {
+ err = fmt.Errorf("string at offset %d has invalid id 0", off)
+ return
+ }
+ if strings[id] != "" {
+ err = fmt.Errorf("string at offset %d has duplicate id %v", off, id)
+ return
+ }
+ var ln uint64
+ ln, off, err = readVal(r, off)
+ if err != nil {
+ return
+ }
+ if ln == 0 {
+ err = fmt.Errorf("string at offset %d has invalid length 0", off)
+ return
+ }
+ if ln > 1e6 {
+ err = fmt.Errorf("string at offset %d has too large length %v", off, ln)
+ return
+ }
+ buf := make([]byte, ln)
+ var n int
+ n, err = io.ReadFull(r, buf)
+ if err != nil {
+ err = fmt.Errorf("failed to read trace at offset %d: read %v, want %v, error %v", off, n, ln, err)
+ return
+ }
+ off += n
+ strings[id] = string(buf)
+ continue
+ }
ev := rawEvent{typ: typ, off: off0}
- if narg < 3 {
- for i := 0; i < int(narg)+2; i++ { // sequence number and time stamp are present but not counted in narg
+ if narg < inlineArgs {
+ for i := 0; i < int(narg); i++ {
var v uint64
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
ev.args = append(ev.args, v)
}
} else {
- // If narg == 3, the first value is length of the event in bytes.
+ // More than inlineArgs args, the first value is length of the event in bytes.
var v uint64
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
evLen := v
off1 := off
for evLen > uint64(off-off1) {
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
ev.args = append(ev.args, v)
}
if evLen != uint64(off-off1) {
- return nil, fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+ err = fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+ return
}
}
events = append(events, ev)
}
- return events, nil
+ return
+}
+
+// parseHeader parses trace header of the form "go 1.7 trace\x00\x00\x00\x00"
+// and returns parsed version as 1007.
+func parseHeader(buf []byte) (int, error) {
+ if len(buf) != 16 {
+ return 0, fmt.Errorf("bad header length")
+ }
+ if buf[0] != 'g' || buf[1] != 'o' || buf[2] != ' ' ||
+ buf[3] < '1' || buf[3] > '9' ||
+ buf[4] != '.' ||
+ buf[5] < '1' || buf[5] > '9' {
+ return 0, fmt.Errorf("not a trace file")
+ }
+ ver := int(buf[5] - '0')
+ i := 0
+ for ; buf[6+i] >= '0' && buf[6+i] <= '9' && i < 2; i++ {
+ ver = ver*10 + int(buf[6+i]-'0')
+ }
+ ver += int(buf[3]-'0') * 1000
+ if !bytes.Equal(buf[6+i:], []byte(" trace\x00\x00\x00\x00")[:10-i]) {
+ return 0, fmt.Errorf("not a trace file")
+ }
+ return ver, nil
}
// Parse events transforms raw events into events.
// It does analyze and verify per-event-type arguments.
-func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
+func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (events []*Event, stacks map[uint64][]*Frame, err error) {
var ticksPerSec, lastSeq, lastTs int64
var lastG, timerGoid uint64
var lastP int
lastGs := make(map[int]uint64) // last goroutine running on P
- stacks := make(map[uint64][]*Frame)
+ stacks = make(map[uint64][]*Frame)
+ batches := make(map[int][]*Event) // events by P
for _, raw := range rawEvents {
- if raw.typ == EvNone || raw.typ >= EvCount {
- err = fmt.Errorf("unknown event type %v at offset 0x%x", raw.typ, raw.off)
- return
- }
desc := EventDescriptions[raw.typ]
if desc.Name == "" {
err = fmt.Errorf("missing description for event type %v", raw.typ)
return
}
- if raw.typ != EvStack {
- narg := len(desc.Args)
- if desc.Stack {
- narg++
- }
- if raw.typ != EvBatch && raw.typ != EvFrequency && raw.typ != EvTimerGoroutine {
- narg++ // sequence number
- narg++ // timestamp
- }
- if len(raw.args) != narg {
- err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
- desc.Name, raw.off, narg, len(raw.args))
- return
- }
+ narg := argNum(raw, ver)
+ if len(raw.args) != narg {
+ err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
+ desc.Name, raw.off, narg, len(raw.args))
+ return
}
switch raw.typ {
case EvBatch:
lastGs[lastP] = lastG
lastP = int(raw.args[0])
lastG = lastGs[lastP]
- lastSeq = int64(raw.args[1])
- lastTs = int64(raw.args[2])
+ if ver < 1007 {
+ lastSeq = int64(raw.args[1])
+ lastTs = int64(raw.args[2])
+ } else {
+ lastTs = int64(raw.args[1])
+ }
case EvFrequency:
ticksPerSec = int64(raw.args[0])
if ticksPerSec <= 0 {
@@ -211,81 +320,110 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
raw.off, size)
return
}
- if uint64(len(raw.args)) != size+2 {
+ want := 2 + 4*size
+ if ver < 1007 {
+ want = 2 + size
+ }
+ if uint64(len(raw.args)) != want {
err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want %v, got %v",
- raw.off, size+2, len(raw.args))
+ raw.off, want, len(raw.args))
return
}
id := raw.args[0]
if id != 0 && size > 0 {
stk := make([]*Frame, size)
for i := 0; i < int(size); i++ {
- stk[i] = &Frame{PC: raw.args[i+2]}
+ if ver < 1007 {
+ stk[i] = &Frame{PC: raw.args[2+i]}
+ } else {
+ pc := raw.args[2+i*4+0]
+ fn := raw.args[2+i*4+1]
+ file := raw.args[2+i*4+2]
+ line := raw.args[2+i*4+3]
+ stk[i] = &Frame{PC: pc, Fn: strings[fn], File: strings[file], Line: int(line)}
+ }
}
stacks[id] = stk
}
default:
e := &Event{Off: raw.off, Type: raw.typ, P: lastP, G: lastG}
- e.Seq = lastSeq + int64(raw.args[0])
- e.Ts = lastTs + int64(raw.args[1])
- lastSeq = e.Seq
- lastTs = e.Ts
- for i := range desc.Args {
- e.Args[i] = raw.args[i+2]
+ var argOffset int
+ if ver < 1007 {
+ e.seq = lastSeq + int64(raw.args[0])
+ e.Ts = lastTs + int64(raw.args[1])
+ lastSeq = e.seq
+ argOffset = 2
+ } else {
+ e.Ts = lastTs + int64(raw.args[0])
+ argOffset = 1
}
- if desc.Stack {
- e.StkID = raw.args[len(desc.Args)+2]
+ lastTs = e.Ts
+ for i := argOffset; i < narg; i++ {
+ if i == narg-1 && desc.Stack {
+ e.StkID = raw.args[i]
+ } else {
+ e.Args[i-argOffset] = raw.args[i]
+ }
}
switch raw.typ {
- case EvGoStart:
+ case EvGoStart, EvGoStartLocal, EvGoStartLabel:
lastG = e.Args[0]
e.G = lastG
+ if raw.typ == EvGoStartLabel {
+ e.SArgs = []string{strings[e.Args[2]]}
+ }
case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
e.G = 0
case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt,
EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
- EvGoSysBlock:
+ EvGoSysBlock, EvGoBlockGC:
lastG = 0
- case EvGoSysExit:
- // EvGoSysExit emission is delayed until the thread has a P.
- // Give it the real sequence number and time stamp.
- e.Seq = int64(e.Args[1])
- if e.Args[2] != 0 {
- e.Ts = int64(e.Args[2])
- }
+ case EvGoSysExit, EvGoWaiting, EvGoInSyscall:
+ e.G = e.Args[0]
}
- events = append(events, e)
+ batches[lastP] = append(batches[lastP], e)
}
}
- if len(events) == 0 {
+ if len(batches) == 0 {
err = fmt.Errorf("trace is empty")
return
}
-
- // Attach stack traces.
- for _, ev := range events {
- if ev.StkID != 0 {
- ev.Stk = stacks[ev.StkID]
- }
- }
-
- // Sort by sequence number and translate cpu ticks to real time.
- sort.Sort(eventList(events))
if ticksPerSec == 0 {
err = fmt.Errorf("no EvFrequency event")
return
}
+ if BreakTimestampsForTesting {
+ var batchArr [][]*Event
+ for _, batch := range batches {
+ batchArr = append(batchArr, batch)
+ }
+ for i := 0; i < 5; i++ {
+ batch := batchArr[rand.Intn(len(batchArr))]
+ batch[rand.Intn(len(batch))].Ts += int64(rand.Intn(2000) - 1000)
+ }
+ }
+ if ver < 1007 {
+ events, err = order1005(batches)
+ } else {
+ events, err = order1007(batches)
+ }
+ if err != nil {
+ return
+ }
+
+ // Translate cpu ticks to real time.
minTs := events[0].Ts
+ // Use floating point to avoid integer overflows.
+ freq := 1e9 / float64(ticksPerSec)
for _, ev := range events {
- ev.Ts = (ev.Ts - minTs) * 1e9 / ticksPerSec
+ ev.Ts = int64(float64(ev.Ts-minTs) * freq)
// Move timers and syscalls to separate fake Ps.
if timerGoid != 0 && ev.G == timerGoid && ev.Type == EvGoUnblock {
ev.P = TimerP
}
if ev.Type == EvGoSysExit {
ev.P = SyscallP
- ev.G = ev.Args[0]
}
}
@@ -355,7 +493,7 @@ var ErrTimeOrder = fmt.Errorf("time stamps out of order")
// The resulting trace is guaranteed to be consistent
// (for example, a P does not run two Gs at the same time, or a G is indeed
// blocked before an unblock event).
-func postProcessTrace(events []*Event) error {
+func postProcessTrace(ver int, events []*Event) error {
const (
gDead = iota
gRunnable
@@ -417,6 +555,8 @@ func postProcessTrace(events []*Event) error {
return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
}
evGC = ev
+ // Attribute this to the global GC state.
+ ev.P = GCP
case EvGCDone:
if evGC == nil {
return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.Off, ev.Ts)
@@ -446,19 +586,17 @@ func postProcessTrace(events []*Event) error {
p.evSweep.Link = ev
p.evSweep = nil
case EvGoWaiting:
- g1 := gs[ev.Args[0]]
- if g1.state != gRunnable {
- return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+ if g.state != gRunnable {
+ return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
- g1.state = gWaiting
- gs[ev.Args[0]] = g1
+ g.state = gWaiting
+ g.ev = ev
case EvGoInSyscall:
- g1 := gs[ev.Args[0]]
- if g1.state != gRunnable {
- return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+ if g.state != gRunnable {
+ return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
- g1.state = gWaiting
- gs[ev.Args[0]] = g1
+ g.state = gWaiting
+ g.ev = ev
case EvGoCreate:
if err := checkRunning(p, g, ev, true); err != nil {
return err
@@ -467,7 +605,7 @@ func postProcessTrace(events []*Event) error {
return fmt.Errorf("g %v already exists (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
}
gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, evCreate: ev}
- case EvGoStart:
+ case EvGoStart, EvGoStartLabel:
if g.state != gRunnable {
return fmt.Errorf("g %v is not runnable before start (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
@@ -478,8 +616,12 @@ func postProcessTrace(events []*Event) error {
g.evStart = ev
p.g = ev.G
if g.evCreate != nil {
- // +1 because symbolizer expects return pc.
- ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+ if ver < 1007 {
+ // +1 because symbolizer expects return pc.
+ ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+ } else {
+ ev.StkID = g.evCreate.Args[1]
+ }
g.evCreate = nil
}
@@ -547,7 +689,7 @@ func postProcessTrace(events []*Event) error {
g.state = gRunnable
g.ev = ev
case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
- EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet:
+ EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoBlockGC:
if err := checkRunning(p, g, ev, false); err != nil {
return err
}
@@ -565,23 +707,11 @@ func postProcessTrace(events []*Event) error {
// TODO(dvyukov): restore stacks for EvGoStart events.
// TODO(dvyukov): test that all EvGoStart events has non-nil Link.
- // Last, after all the other consistency checks,
- // make sure time stamps respect sequence numbers.
- // The tests will skip (not fail) the test case if they see this error,
- // so check everything else that could possibly be wrong first.
- lastTs := int64(0)
- for _, ev := range events {
- if ev.Ts < lastTs {
- return ErrTimeOrder
- }
- lastTs = ev.Ts
- }
-
return nil
}
-// symbolizeTrace attaches func/file/line info to stack traces.
-func Symbolize(events []*Event, bin string) error {
+// symbolize attaches func/file/line info to stack traces.
+func symbolize(events []*Event, bin string) error {
// First, collect and dedup all pcs.
pcs := make(map[uint64]*Frame)
for _, ev := range events {
@@ -672,57 +802,81 @@ func readVal(r io.Reader, off0 int) (v uint64, off int, err error) {
return 0, 0, fmt.Errorf("bad value at offset 0x%x", off0)
}
-type eventList []*Event
-
-func (l eventList) Len() int {
- return len(l)
-}
-
-func (l eventList) Less(i, j int) bool {
- return l[i].Seq < l[j].Seq
+// Print dumps events to stdout. For debugging.
+func Print(events []*Event) {
+ for _, ev := range events {
+ PrintEvent(ev)
+ }
}
-func (l eventList) Swap(i, j int) {
- l[i], l[j] = l[j], l[i]
+// PrintEvent dumps the event to stdout. For debugging.
+func PrintEvent(ev *Event) {
+ desc := EventDescriptions[ev.Type]
+ fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
+ for i, a := range desc.Args {
+ fmt.Printf(" %v=%v", a, ev.Args[i])
+ }
+ fmt.Printf("\n")
}
-// Print dumps events to stdout. For debugging.
-func Print(events []*Event) {
- for _, ev := range events {
- desc := EventDescriptions[ev.Type]
- fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
- for i, a := range desc.Args {
- fmt.Printf(" %v=%v", a, ev.Args[i])
+// argNum returns total number of args for the event accounting for timestamps,
+// sequence numbers and differences between trace format versions.
+func argNum(raw rawEvent, ver int) int {
+ desc := EventDescriptions[raw.typ]
+ if raw.typ == EvStack {
+ return len(raw.args)
+ }
+ narg := len(desc.Args)
+ if desc.Stack {
+ narg++
+ }
+ switch raw.typ {
+ case EvBatch, EvFrequency, EvTimerGoroutine:
+ if ver < 1007 {
+ narg++ // there was an unused arg before 1.7
+ }
+ case EvGCStart, EvGoStart, EvGoUnblock:
+ if ver < 1007 {
+ narg-- // 1.7 added an additional seq arg
+ }
+ fallthrough
+ default:
+ narg++ // timestamp
+ if ver < 1007 {
+ narg++ // sequence
}
- fmt.Printf("\n")
}
+ return narg
}
+// BreakTimestampsForTesting causes the parser to randomly alter timestamps (for testing of broken cputicks).
+var BreakTimestampsForTesting bool
+
// Event types in the trace.
// Verbatim copy from src/runtime/trace.go.
const (
EvNone = 0 // unused
EvBatch = 1 // start of per-P batch of events [pid, timestamp]
EvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)]
- EvStack = 3 // stack [stack id, number of PCs, array of PCs]
+ EvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
EvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
EvProcStart = 5 // start of P [timestamp, thread id]
EvProcStop = 6 // stop of P [timestamp]
- EvGCStart = 7 // GC start [timestamp, stack id]
+ EvGCStart = 7 // GC start [timestamp, seq, stack id]
EvGCDone = 8 // GC done [timestamp]
- EvGCScanStart = 9 // GC scan start [timestamp]
- EvGCScanDone = 10 // GC scan done [timestamp]
+ EvGCScanStart = 9 // GC mark termination start [timestamp]
+ EvGCScanDone = 10 // GC mark termination done [timestamp]
EvGCSweepStart = 11 // GC sweep start [timestamp, stack id]
EvGCSweepDone = 12 // GC sweep done [timestamp]
- EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
- EvGoStart = 14 // goroutine starts running [timestamp, goroutine id]
+ EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+ EvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq]
EvGoEnd = 15 // goroutine ends [timestamp]
EvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack]
EvGoSched = 17 // goroutine calls Gosched [timestamp, stack]
EvGoPreempt = 18 // goroutine is preempted [timestamp, stack]
EvGoSleep = 19 // goroutine calls Sleep [timestamp, stack]
EvGoBlock = 20 // goroutine blocks [timestamp, stack]
- EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+ EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack]
EvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack]
EvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack]
EvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack]
@@ -730,57 +884,70 @@ const (
EvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack]
EvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack]
EvGoSysCall = 28 // syscall enter [timestamp, stack]
- EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, real timestamp]
+ EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
EvGoSysBlock = 30 // syscall blocks [timestamp]
- EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
- EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
- EvHeapAlloc = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+ EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+ EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
+ EvHeapAlloc = 33 // memstats.heap_live change [timestamp, heap_alloc]
EvNextGC = 34 // memstats.next_gc change [timestamp, next_gc]
EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
EvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
- EvCount = 37
+ EvString = 37 // string dictionary entry [ID, length, string]
+ EvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+ EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+ EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+ EvGoStartLabel = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
+ EvGoBlockGC = 42 // goroutine blocks on GC assist [timestamp, stack]
+ EvCount = 43
)
var EventDescriptions = [EvCount]struct {
- Name string
- Stack bool
- Args []string
+ Name string
+ minVersion int
+ Stack bool
+ Args []string
}{
- EvNone: {"None", false, []string{}},
- EvBatch: {"Batch", false, []string{"p", "seq", "ticks"}},
- EvFrequency: {"Frequency", false, []string{"freq", "unused"}},
- EvStack: {"Stack", false, []string{"id", "siz"}},
- EvGomaxprocs: {"Gomaxprocs", true, []string{"procs"}},
- EvProcStart: {"ProcStart", false, []string{"thread"}},
- EvProcStop: {"ProcStop", false, []string{}},
- EvGCStart: {"GCStart", true, []string{}},
- EvGCDone: {"GCDone", false, []string{}},
- EvGCScanStart: {"GCScanStart", false, []string{}},
- EvGCScanDone: {"GCScanDone", false, []string{}},
- EvGCSweepStart: {"GCSweepStart", true, []string{}},
- EvGCSweepDone: {"GCSweepDone", false, []string{}},
- EvGoCreate: {"GoCreate", true, []string{"g", "pc"}},
- EvGoStart: {"GoStart", false, []string{"g"}},
- EvGoEnd: {"GoEnd", false, []string{}},
- EvGoStop: {"GoStop", true, []string{}},
- EvGoSched: {"GoSched", true, []string{}},
- EvGoPreempt: {"GoPreempt", true, []string{}},
- EvGoSleep: {"GoSleep", true, []string{}},
- EvGoBlock: {"GoBlock", true, []string{}},
- EvGoUnblock: {"GoUnblock", true, []string{"g"}},
- EvGoBlockSend: {"GoBlockSend", true, []string{}},
- EvGoBlockRecv: {"GoBlockRecv", true, []string{}},
- EvGoBlockSelect: {"GoBlockSelect", true, []string{}},
- EvGoBlockSync: {"GoBlockSync", true, []string{}},
- EvGoBlockCond: {"GoBlockCond", true, []string{}},
- EvGoBlockNet: {"GoBlockNet", true, []string{}},
- EvGoSysCall: {"GoSysCall", true, []string{}},
- EvGoSysExit: {"GoSysExit", false, []string{"g", "seq", "ts"}},
- EvGoSysBlock: {"GoSysBlock", false, []string{}},
- EvGoWaiting: {"GoWaiting", false, []string{"g"}},
- EvGoInSyscall: {"GoInSyscall", false, []string{"g"}},
- EvHeapAlloc: {"HeapAlloc", false, []string{"mem"}},
- EvNextGC: {"NextGC", false, []string{"mem"}},
- EvTimerGoroutine: {"TimerGoroutine", false, []string{"g", "unused"}},
- EvFutileWakeup: {"FutileWakeup", false, []string{}},
+ EvNone: {"None", 1005, false, []string{}},
+ EvBatch: {"Batch", 1005, false, []string{"p", "ticks"}}, // in 1.5 format it was {"p", "seq", "ticks"}
+ EvFrequency: {"Frequency", 1005, false, []string{"freq"}}, // in 1.5 format it was {"freq", "unused"}
+ EvStack: {"Stack", 1005, false, []string{"id", "siz"}},
+ EvGomaxprocs: {"Gomaxprocs", 1005, true, []string{"procs"}},
+ EvProcStart: {"ProcStart", 1005, false, []string{"thread"}},
+ EvProcStop: {"ProcStop", 1005, false, []string{}},
+ EvGCStart: {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
+ EvGCDone: {"GCDone", 1005, false, []string{}},
+ EvGCScanStart: {"GCScanStart", 1005, false, []string{}},
+ EvGCScanDone: {"GCScanDone", 1005, false, []string{}},
+ EvGCSweepStart: {"GCSweepStart", 1005, true, []string{}},
+ EvGCSweepDone: {"GCSweepDone", 1005, false, []string{}},
+ EvGoCreate: {"GoCreate", 1005, true, []string{"g", "stack"}},
+ EvGoStart: {"GoStart", 1005, false, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+ EvGoEnd: {"GoEnd", 1005, false, []string{}},
+ EvGoStop: {"GoStop", 1005, true, []string{}},
+ EvGoSched: {"GoSched", 1005, true, []string{}},
+ EvGoPreempt: {"GoPreempt", 1005, true, []string{}},
+ EvGoSleep: {"GoSleep", 1005, true, []string{}},
+ EvGoBlock: {"GoBlock", 1005, true, []string{}},
+ EvGoUnblock: {"GoUnblock", 1005, true, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+ EvGoBlockSend: {"GoBlockSend", 1005, true, []string{}},
+ EvGoBlockRecv: {"GoBlockRecv", 1005, true, []string{}},
+ EvGoBlockSelect: {"GoBlockSelect", 1005, true, []string{}},
+ EvGoBlockSync: {"GoBlockSync", 1005, true, []string{}},
+ EvGoBlockCond: {"GoBlockCond", 1005, true, []string{}},
+ EvGoBlockNet: {"GoBlockNet", 1005, true, []string{}},
+ EvGoSysCall: {"GoSysCall", 1005, true, []string{}},
+ EvGoSysExit: {"GoSysExit", 1005, false, []string{"g", "seq", "ts"}},
+ EvGoSysBlock: {"GoSysBlock", 1005, false, []string{}},
+ EvGoWaiting: {"GoWaiting", 1005, false, []string{"g"}},
+ EvGoInSyscall: {"GoInSyscall", 1005, false, []string{"g"}},
+ EvHeapAlloc: {"HeapAlloc", 1005, false, []string{"mem"}},
+ EvNextGC: {"NextGC", 1005, false, []string{"mem"}},
+ EvTimerGoroutine: {"TimerGoroutine", 1005, false, []string{"g"}}, // in 1.5 format it was {"g", "unused"}
+ EvFutileWakeup: {"FutileWakeup", 1005, false, []string{}},
+ EvString: {"String", 1007, false, []string{}},
+ EvGoStartLocal: {"GoStartLocal", 1007, false, []string{"g"}},
+ EvGoUnblockLocal: {"GoUnblockLocal", 1007, true, []string{"g"}},
+ EvGoSysExitLocal: {"GoSysExitLocal", 1007, false, []string{"g", "ts"}},
+ EvGoStartLabel: {"GoStartLabel", 1008, false, []string{"g", "seq", "label"}},
+ EvGoBlockGC: {"GoBlockGC", 1008, true, []string{}},
}
diff --git a/libgo/go/internal/trace/parser_test.go b/libgo/go/internal/trace/parser_test.go
index fecefc4053..d6f580aed5 100644
--- a/libgo/go/internal/trace/parser_test.go
+++ b/libgo/go/internal/trace/parser_test.go
@@ -5,6 +5,9 @@
package trace
import (
+ "bytes"
+ "io/ioutil"
+ "path/filepath"
"strings"
"testing"
)
@@ -22,9 +25,78 @@ func TestCorruptedInputs(t *testing.T) {
"go 1.5 trace\x00\x00\x00\x00\xc3\x0200",
}
for _, data := range tests {
- events, err := Parse(strings.NewReader(data))
+ events, err := Parse(strings.NewReader(data), "")
if err == nil || events != nil {
- t.Fatalf("no error on input: %q\n", data)
+ t.Fatalf("no error on input: %q", data)
}
}
}
+
+func TestParseCanned(t *testing.T) {
+ files, err := ioutil.ReadDir("./testdata")
+ if err != nil {
+ t.Fatalf("failed to read ./testdata: %v", err)
+ }
+ for _, f := range files {
+ data, err := ioutil.ReadFile(filepath.Join("./testdata", f.Name()))
+ if err != nil {
+ t.Fatalf("failed to read input file: %v", err)
+ }
+ // Instead of Parse that requires a proper binary name for old traces,
+ // we use 'parse' that omits symbol lookup if an empty string is given.
+ _, _, err = parse(bytes.NewReader(data), "")
+ switch {
+ case strings.HasSuffix(f.Name(), "_good"):
+ if err != nil {
+ t.Errorf("failed to parse good trace %v: %v", f.Name(), err)
+ }
+ case strings.HasSuffix(f.Name(), "_unordered"):
+ if err != ErrTimeOrder {
+ t.Errorf("unordered trace is not detected %v: %v", f.Name(), err)
+ }
+ default:
+ t.Errorf("unknown input file suffix: %v", f.Name())
+ }
+ }
+}
+
+func TestParseVersion(t *testing.T) {
+ tests := map[string]int{
+ "go 1.5 trace\x00\x00\x00\x00": 1005,
+ "go 1.7 trace\x00\x00\x00\x00": 1007,
+ "go 1.10 trace\x00\x00\x00": 1010,
+ "go 1.25 trace\x00\x00\x00": 1025,
+ "go 1.234 trace\x00\x00": 1234,
+ "go 1.2345 trace\x00": -1,
+ "go 0.0 trace\x00\x00\x00\x00": -1,
+ "go a.b trace\x00\x00\x00\x00": -1,
+ }
+ for header, ver := range tests {
+ ver1, err := parseHeader([]byte(header))
+ if ver == -1 {
+ if err == nil {
+ t.Fatalf("no error on input: %q, version %v", header, ver1)
+ }
+ } else {
+ if err != nil {
+ t.Fatalf("failed to parse: %q (%v)", header, err)
+ }
+ if ver != ver1 {
+ t.Fatalf("wrong version: %v, want %v, input: %q", ver1, ver, header)
+ }
+ }
+ }
+}
+
+func TestTimestampOverflow(t *testing.T) {
+ // Test that parser correctly handles large timestamps (long tracing).
+ w := NewWriter()
+ w.Emit(EvBatch, 0, 0)
+ w.Emit(EvFrequency, 1e9)
+ for ts := uint64(1); ts < 1e16; ts *= 2 {
+ w.Emit(EvGoCreate, ts, ts, 0, 0)
+ }
+ if _, err := Parse(w, ""); err != nil {
+ t.Fatalf("failed to parse: %v", err)
+ }
+}
diff --git a/libgo/go/internal/trace/testdata/http_1_5_good b/libgo/go/internal/trace/testdata/http_1_5_good
new file mode 100644
index 0000000000..0736cae674
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/http_1_5_good
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/http_1_7_good b/libgo/go/internal/trace/testdata/http_1_7_good
new file mode 100644
index 0000000000..b0e318e9a4
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/http_1_7_good
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/stress_1_5_good b/libgo/go/internal/trace/testdata/stress_1_5_good
new file mode 100644
index 0000000000..c5055ebd19
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/stress_1_5_good
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/stress_1_5_unordered b/libgo/go/internal/trace/testdata/stress_1_5_unordered
new file mode 100644
index 0000000000..11f7d745ca
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/stress_1_5_unordered
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/stress_1_7_good b/libgo/go/internal/trace/testdata/stress_1_7_good
new file mode 100644
index 0000000000..b4d927de34
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/stress_1_7_good
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/stress_start_stop_1_5_good b/libgo/go/internal/trace/testdata/stress_start_stop_1_5_good
new file mode 100644
index 0000000000..72a887b844
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/stress_start_stop_1_5_good
Binary files differ
diff --git a/libgo/go/internal/trace/testdata/stress_start_stop_1_7_good b/libgo/go/internal/trace/testdata/stress_start_stop_1_7_good
new file mode 100644
index 0000000000..c23ed7dc08
--- /dev/null
+++ b/libgo/go/internal/trace/testdata/stress_start_stop_1_7_good
Binary files differ
diff --git a/libgo/go/internal/trace/writer.go b/libgo/go/internal/trace/writer.go
new file mode 100644
index 0000000000..a481f50a7e
--- /dev/null
+++ b/libgo/go/internal/trace/writer.go
@@ -0,0 +1,45 @@
+package trace
+
+import "bytes"
+
+// Writer is a test trace writer.
+type Writer struct {
+ bytes.Buffer
+}
+
+func NewWriter() *Writer {
+ w := new(Writer)
+ w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
+ return w
+}
+
+// Emit writes an event record to the trace.
+// See Event types for valid types and required arguments.
+func (w *Writer) Emit(typ byte, args ...uint64) {
+ nargs := byte(len(args)) - 1
+ if nargs > 3 {
+ nargs = 3
+ }
+ buf := []byte{typ | nargs<<6}
+ if nargs == 3 {
+ buf = append(buf, 0)
+ }
+ for _, a := range args {
+ buf = appendVarint(buf, a)
+ }
+ if nargs == 3 {
+ buf[1] = byte(len(buf) - 2)
+ }
+ n, err := w.Write(buf)
+ if n != len(buf) || err != nil {
+ panic("failed to write")
+ }
+}
+
+func appendVarint(buf []byte, v uint64) []byte {
+ for ; v >= 0x80; v >>= 7 {
+ buf = append(buf, 0x80|byte(v))
+ }
+ buf = append(buf, byte(v))
+ return buf
+}
diff --git a/libgo/go/io/example_test.go b/libgo/go/io/example_test.go
index 412dfb3b92..bf16de8fe2 100644
--- a/libgo/go/io/example_test.go
+++ b/libgo/go/io/example_test.go
@@ -189,7 +189,7 @@ func ExampleSectionReader_Seek() {
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
- if _, err := s.Seek(10, 0); err != nil {
+ if _, err := s.Seek(10, io.SeekStart); err != nil {
log.Fatal(err)
}
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
index 8e7855c665..9e4b86594d 100644
--- a/libgo/go/io/io.go
+++ b/libgo/go/io/io.go
@@ -16,6 +16,13 @@ import (
"errors"
)
+// Seek whence values.
+const (
+ SeekStart = 0 // seek relative to the origin of the file
+ SeekCurrent = 1 // seek relative to the current offset
+ SeekEnd = 2 // seek relative to the end
+)
+
// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite = errors.New("short write")
@@ -41,23 +48,23 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error")
// Reader is the interface that wraps the basic Read method.
//
-// Read reads up to len(p) bytes into p. It returns the number of bytes
-// read (0 <= n <= len(p)) and any error encountered. Even if Read
+// Read reads up to len(p) bytes into p. It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
//
// When Read encounters an error or end-of-file condition after
// successfully reading n > 0 bytes, it returns the number of
-// bytes read. It may return the (non-nil) error from the same call
+// bytes read. It may return the (non-nil) error from the same call
// or return the error (and n == 0) from a subsequent call.
// An instance of this general case is that a Reader returning
// a non-zero number of bytes at the end of the input stream may
-// return either err == EOF or err == nil. The next Read should
+// return either err == EOF or err == nil. The next Read should
// return 0, EOF.
//
// Callers should always process the n > 0 bytes returned before
-// considering the error err. Doing so correctly handles I/O errors
+// considering the error err. Doing so correctly handles I/O errors
// that happen after reading some bytes and also both of the
// allowed EOF behaviors.
//
@@ -95,10 +102,12 @@ type Closer interface {
// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
-// interpreted according to whence: 0 means relative to the start of
-// the file, 1 means relative to the current offset, and 2 means
-// relative to the end. Seek returns the new offset relative to the
-// start of the file and an error, if any.
+// interpreted according to whence:
+// SeekStart means relative to the start of the file,
+// SeekCurrent means relative to the current offset, and
+// SeekEnd means relative to the end.
+// Seek returns the new offset relative to the start of the
+// file and an error, if any.
//
// Seeking to an offset before the start of the file is an error.
// Seeking to any positive offset is legal, but the behavior of subsequent
@@ -176,15 +185,15 @@ type WriterTo interface {
// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
-// underlying input source. It returns the number of bytes
+// underlying input source. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
// When ReadAt returns n < len(p), it returns a non-nil error
-// explaining why more bytes were not returned. In this respect,
+// explaining why more bytes were not returned. In this respect,
// ReadAt is stricter than Read.
//
// Even if ReadAt returns n < len(p), it may use all of p as scratch
-// space during the call. If some data is available but not len(p) bytes,
+// space during the call. If some data is available but not len(p) bytes,
// ReadAt blocks until either all the data is available or an error occurs.
// In this respect ReadAt is different from Read.
//
@@ -206,7 +215,7 @@ type ReaderAt interface {
// WriterAt is the interface that wraps the basic WriteAt method.
//
// WriteAt writes len(p) bytes from p to the underlying data stream
-// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
+// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
//
@@ -226,7 +235,7 @@ type WriterAt interface {
//
// ReadByte reads and returns the next byte from the input.
type ByteReader interface {
- ReadByte() (c byte, err error)
+ ReadByte() (byte, error)
}
// ByteScanner is the interface that adds the UnreadByte method to the
@@ -274,6 +283,7 @@ type stringWriter interface {
// WriteString writes the contents of the string s to w, which accepts a slice of bytes.
// If w implements a WriteString method, it is invoked directly.
+// Otherwise, w.Write is called exactly once.
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
@@ -335,7 +345,7 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
}
// Copy copies from src to dst until either EOF is reached
-// on src or an error occurs. It returns the number of bytes
+// on src or an error occurs. It returns the number of bytes
// copied and the first error encountered while copying, if any.
//
// A successful Copy returns err == nil, not err == EOF.
@@ -392,11 +402,10 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
break
}
}
- if er == EOF {
- break
- }
if er != nil {
- err = er
+ if er != EOF {
+ err = er
+ }
break
}
}
@@ -411,6 +420,7 @@ func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
// A LimitedReader reads from R but limits the amount of
// data returned to just N bytes. Each call to Read
// updates N to reflect the new amount remaining.
+// Read returns EOF when N <= 0 or when the underlying R returns EOF.
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
@@ -462,11 +472,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 {
@@ -497,7 +507,7 @@ func (s *SectionReader) Size() int64 { return s.limit - s.base }
// TeeReader returns a Reader that writes to w what it reads from r.
// All reads from r performed through it are matched with
-// corresponding writes to w. There is no internal buffering -
+// corresponding writes to w. There is no internal buffering -
// the write must complete before the read completes.
// Any error encountered while writing is reported as a read error.
func TeeReader(r Reader, w Writer) Reader {
diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go
index e892574b0b..877e8392e2 100644
--- a/libgo/go/io/io_test.go
+++ b/libgo/go/io/io_test.go
@@ -347,7 +347,7 @@ func TestSectionReader_Seek(t *testing.T) {
br := bytes.NewReader([]byte("foo"))
sr := NewSectionReader(br, 0, int64(len("foo")))
- for whence := 0; whence <= 2; whence++ {
+ for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} {
for offset := int64(-3); offset <= 4; offset++ {
brOff, brErr := br.Seek(offset, whence)
srOff, srErr := sr.Seek(offset, whence)
@@ -359,7 +359,7 @@ func TestSectionReader_Seek(t *testing.T) {
}
// And verify we can just seek past the end and get an EOF
- got, err := sr.Seek(100, 0)
+ got, err := sr.Seek(100, SeekStart)
if err != nil || got != 100 {
t.Errorf("Seek = %v, %v; want 100, nil", got, err)
}
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
index e90a33f99b..f0da616830 100644
--- a/libgo/go/io/ioutil/ioutil.go
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -63,8 +63,8 @@ func ReadFile(filename string) ([]byte, error) {
}
}
// As initial capacity for readAll, use n + a little extra in case Size is zero,
- // and to avoid another allocation after Read has filled the buffer. The readAll
- // call will read into its allocated internal buffer cheaply. If the size was
+ // and to avoid another allocation after Read has filled the buffer. The readAll
+ // call will read into its allocated internal buffer cheaply. If the size was
// wrong, we'll either waste some space off the end or reallocate as needed, but
// in the overwhelmingly common case we'll get it just right.
return readAll(f, n+bytes.MinRead)
@@ -88,13 +88,6 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error {
return err
}
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
@@ -107,7 +100,7 @@ func ReadDir(dirname string) ([]os.FileInfo, error) {
if err != nil {
return nil, err
}
- sort.Sort(byName(list))
+ sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
return list, nil
}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
index 61d4a7ad37..e5e315cfb7 100644
--- a/libgo/go/io/ioutil/tempfile.go
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -41,8 +41,8 @@ func nextSuffix() string {
// If dir is the empty string, TempFile uses the default directory
// for temporary files (see os.TempDir).
// Multiple programs calling TempFile simultaneously
-// will not choose the same file. The caller can use f.Name()
-// to find the pathname of the file. It is the caller's responsibility
+// will not choose the same file. The caller can use f.Name()
+// to find the pathname of the file. It is the caller's responsibility
// to remove the file when no longer needed.
func TempFile(dir, prefix string) (f *os.File, err error) {
if dir == "" {
@@ -68,10 +68,10 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
// TempDir creates a new temporary directory in the directory dir
// with a name beginning with prefix and returns the path of the
-// new directory. If dir is the empty string, TempDir uses the
+// new directory. If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
-// will not choose the same directory. It is the caller's responsibility
+// will not choose the same directory. It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, prefix string) (name string, err error) {
if dir == "" {
@@ -90,6 +90,11 @@ func TempDir(dir, prefix string) (name string, err error) {
}
continue
}
+ if os.IsNotExist(err) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ return "", err
+ }
+ }
if err == nil {
name = try
}
diff --git a/libgo/go/io/ioutil/tempfile_test.go b/libgo/go/io/ioutil/tempfile_test.go
index d2a132a110..6a70aedc32 100644
--- a/libgo/go/io/ioutil/tempfile_test.go
+++ b/libgo/go/io/ioutil/tempfile_test.go
@@ -51,3 +51,19 @@ func TestTempDir(t *testing.T) {
}
}
}
+
+// test that we return a nice error message if the dir argument to TempDir doesn't
+// exist (or that it's empty and os.TempDir doesn't exist)
+func TestTempDir_BadDir(t *testing.T) {
+ dir, err := TempDir("", "TestTempDir_BadDir")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ badDir := filepath.Join(dir, "not-exist")
+ _, err = TempDir(badDir, "foo")
+ if pe, ok := err.(*os.PathError); !ok || !os.IsNotExist(err) || pe.Path != badDir {
+ t.Errorf("TempDir error = %#v; want PathError for path %q satisifying os.IsNotExist", err, badDir)
+ }
+}
diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go
index 16860aa361..d784846862 100644
--- a/libgo/go/io/multi.go
+++ b/libgo/go/io/multi.go
@@ -4,28 +4,45 @@
package io
+type eofReader struct{}
+
+func (eofReader) Read([]byte) (int, error) {
+ return 0, EOF
+}
+
type multiReader struct {
readers []Reader
}
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 err == EOF {
+ // Use eofReader instead of nil to avoid nil panic
+ // after performing flatten (Issue 18232).
+ mr.readers[0] = eofReader{} // permit earlier GC
+ mr.readers = mr.readers[1:]
+ }
if n > 0 || err != EOF {
- if err == EOF {
- // Don't return EOF yet. There may be more bytes
- // in the remaining readers.
+ if err == EOF && len(mr.readers) > 0 {
+ // Don't return EOF yet. More readers remain.
err = nil
}
return
}
- mr.readers = mr.readers[1:]
}
return 0, EOF
}
// MultiReader returns a Reader that's the logical concatenation of
-// the provided input readers. They're read sequentially. Once all
+// the provided input readers. They're read sequentially. Once all
// inputs have returned EOF, Read will return EOF. If any of the readers
// return a non-nil, non-EOF error, Read will return that error.
func MultiReader(readers ...Reader) Reader {
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
index c5d1b9530e..70f2a48e9e 100644
--- a/libgo/go/io/multi_test.go
+++ b/libgo/go/io/multi_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -7,11 +7,14 @@ package io_test
import (
"bytes"
"crypto/sha1"
+ "errors"
"fmt"
. "io"
"io/ioutil"
+ "runtime"
"strings"
"testing"
+ "time"
)
func TestMultiReader(t *testing.T) {
@@ -165,3 +168,128 @@ 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)
+ }
+}
+
+// byteAndEOFReader is a Reader which reads one byte (the underlying
+// byte) and io.EOF at once in its Read call.
+type byteAndEOFReader byte
+
+func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ // Read(0 bytes) is useless. We expect no such useless
+ // calls in this test.
+ panic("unexpected call")
+ }
+ p[0] = byte(b)
+ return 1, EOF
+}
+
+// This used to yield bytes forever; issue 16795.
+func TestMultiReaderSingleByteWithEOF(t *testing.T) {
+ got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10))
+ if err != nil {
+ t.Fatal(err)
+ }
+ const want = "ab"
+ if string(got) != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+// Test that a reader returning (n, EOF) at the end of an MultiReader
+// chain continues to return EOF on its final read, rather than
+// yielding a (0, EOF).
+func TestMultiReaderFinalEOF(t *testing.T) {
+ r := MultiReader(bytes.NewReader(nil), byteAndEOFReader('a'))
+ buf := make([]byte, 2)
+ n, err := r.Read(buf)
+ if n != 1 || err != EOF {
+ t.Errorf("got %v, %v; want 1, EOF", n, err)
+ }
+}
+
+func TestMultiReaderFreesExhaustedReaders(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping finalizer test on gccgo with conservative GC")
+ }
+
+ var mr Reader
+ closed := make(chan struct{})
+ {
+ buf1 := bytes.NewReader([]byte("foo"))
+ buf2 := bytes.NewReader([]byte("bar"))
+ mr = MultiReader(buf1, buf2)
+ runtime.SetFinalizer(buf1, func(*bytes.Reader) {
+ close(closed)
+ })
+ }
+
+ buf := make([]byte, 4)
+ if n, err := ReadFull(mr, buf); err != nil || string(buf) != "foob" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 3, "foo", nil`, n, buf[:n], err)
+ }
+
+ runtime.GC()
+ select {
+ case <-closed:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for collection of buf1")
+ }
+
+ if n, err := ReadFull(mr, buf[:2]); err != nil || string(buf[:2]) != "ar" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n, buf[:n], err)
+ }
+}
+
+func TestInterleavedMultiReader(t *testing.T) {
+ r1 := strings.NewReader("123")
+ r2 := strings.NewReader("45678")
+
+ mr1 := MultiReader(r1, r2)
+ mr2 := MultiReader(mr1)
+
+ buf := make([]byte, 4)
+
+ // Have mr2 use mr1's []Readers.
+ // Consume r1 (and clear it for GC to handle) and consume part of r2.
+ n, err := ReadFull(mr2, buf)
+ if got := string(buf[:n]); got != "1234" || err != nil {
+ t.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got, err)
+ }
+
+ // Consume the rest of r2 via mr1.
+ // This should not panic even though mr2 cleared r1.
+ n, err = ReadFull(mr1, buf)
+ if got := string(buf[:n]); got != "5678" || err != nil {
+ t.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got, err)
+ }
+}
diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go
index 179515e78d..b6e7755f64 100644
--- a/libgo/go/io/pipe.go
+++ b/libgo/go/io/pipe.go
@@ -15,11 +15,6 @@ import (
// ErrClosedPipe is the error used for read or write operations on a closed pipe.
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
-type pipeResult struct {
- n int
- err error
-}
-
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
type pipe struct {
rl sync.Mutex // gates readers one at a time
@@ -90,6 +85,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
}
if p.werr != nil {
err = ErrClosedPipe
+ break
}
p.wwait.Wait()
}
@@ -153,7 +149,7 @@ type PipeWriter struct {
}
// Write implements the standard Write interface:
-// it writes data to the pipe, blocking until readers
+// it writes data to the pipe, blocking until one or more readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is ErrClosedPipe.
@@ -180,11 +176,17 @@ func (w *PipeWriter) CloseWithError(err error) error {
// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
-// Reads on one end are matched with writes on the other,
-// copying data directly between the two; there is no internal buffering.
-// It is safe to call Read and Write in parallel with each other or with
-// Close. Close will complete once pending I/O is done. Parallel calls to
-// Read, and parallel calls to Write, are also safe:
+//
+// Reads and Writes on the pipe are matched one to one
+// except when multiple Reads are needed to consume a single Write.
+// That is, each Write to the PipeWriter blocks until it has satisfied
+// one or more Reads from the PipeReader that fully consume
+// the written data.
+// The data is copied directly from the Write to the corresponding
+// Read (or Reads); there is no internal buffering.
+//
+// It is safe to call Read and Write in parallel with each other or with Close.
+// Parallel calls to Read and parallel calls to Write are also safe:
// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := new(pipe)
diff --git a/libgo/go/io/pipe_test.go b/libgo/go/io/pipe_test.go
index b16e653069..95930e86a4 100644
--- a/libgo/go/io/pipe_test.go
+++ b/libgo/go/io/pipe_test.go
@@ -247,6 +247,18 @@ func TestPipeWriteClose(t *testing.T) {
}
}
+// Test close on Write side during Write.
+func TestPipeWriteClose2(t *testing.T) {
+ c := make(chan int, 1)
+ _, w := Pipe()
+ go delayClose(t, w, c, pipeTest{})
+ n, err := w.Write(make([]byte, 64))
+ <-c
+ if n != 0 || err != ErrClosedPipe {
+ t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
+ }
+}
+
func TestWriteEmpty(t *testing.T) {
r, w := Pipe()
go func() {
diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go
index 4cfe550300..58b8788be4 100644
--- a/libgo/go/log/log.go
+++ b/libgo/go/log/log.go
@@ -8,6 +8,8 @@
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
+// Every log message is output on a separate line: if the message being
+// printed does not end in a newline, the logger will add one.
// The Fatal functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log
@@ -42,8 +44,8 @@ const (
)
// A Logger represents an active logging object that generates lines of
-// output to an io.Writer. Each logging operation makes a single call to
-// the Writer's Write method. A Logger can be used simultaneously from
+// output to an io.Writer. Each logging operation makes a single call to
+// the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
mu sync.Mutex // ensures atomic writes; protects the following fields
@@ -53,7 +55,7 @@ type Logger struct {
buf []byte // for accumulating text to write
}
-// New creates a new Logger. The out variable sets the
+// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
@@ -134,10 +136,10 @@ func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
}
}
-// Output writes the output for a logging event. The string s contains
+// Output writes the output for a logging event. The string s contains
// the text to print after the prefix specified by the flags of the
-// Logger. A newline is appended if the last character of s is not
-// already a newline. Calldepth is used to recover the PC and is
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is used to recover the PC and is
// provided for generality, although at the moment on all pre-defined
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) error {
@@ -334,10 +336,10 @@ func Panicln(v ...interface{}) {
panic(s)
}
-// Output writes the output for a logging event. The string s contains
+// Output writes the output for a logging event. The string s contains
// the text to print after the prefix specified by the flags of the
-// Logger. A newline is appended if the last character of s is not
-// already a newline. Calldepth is the count of the number of
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is the count of the number of
// frames to skip when computing the file name and line number
// if Llongfile or Lshortfile is set; a value of 1 will print the details
// for the caller of Output.
diff --git a/libgo/go/log/syslog/doc.go b/libgo/go/log/syslog/doc.go
index dfcc2dde34..5458523249 100644
--- a/libgo/go/log/syslog/doc.go
+++ b/libgo/go/log/syslog/doc.go
@@ -10,7 +10,7 @@
// the syslog client will attempt to reconnect to the server
// and write again.
//
-// The syslog package is frozen and not accepting new features.
+// The syslog package is frozen and is not accepting new features.
// Some external packages provide more functionality. See:
//
// https://godoc.org/?q=syslog
diff --git a/libgo/go/log/syslog/example_test.go b/libgo/go/log/syslog/example_test.go
new file mode 100644
index 0000000000..0513b26da1
--- /dev/null
+++ b/libgo/go/log/syslog/example_test.go
@@ -0,0 +1,24 @@
+// 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
+// +build !windows,!nacl,!plan9
+
+package syslog_test
+
+import (
+ "fmt"
+ "log"
+ "log/syslog"
+)
+
+func ExampleDial() {
+ sysLog, err := syslog.Dial("tcp", "localhost:1234",
+ syslog.LOG_WARNING|syslog.LOG_DAEMON, "demotag")
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Fprintf(sysLog, "This is a daemon warning with demotag.")
+ sysLog.Emerg("And this is a daemon emergency with demotag.")
+}
diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go
index 4bf447626f..df9ffb8e33 100644
--- a/libgo/go/log/syslog/syslog.go
+++ b/libgo/go/log/syslog/syslog.go
@@ -85,8 +85,8 @@ type Writer struct {
}
// This interface and the separate syslog_unix.go file exist for
-// Solaris support as implemented by gccgo. On Solaris you can not
-// simply open a TCP connection to the syslog daemon. The gccgo
+// Solaris support as implemented by gccgo. On Solaris you cannot
+// simply open a TCP connection to the syslog daemon. The gccgo
// sources have a syslog_solaris.go file that implements unixSyslog to
// return a type that satisfies this interface and simply calls the C
// library syslog function.
@@ -100,18 +100,20 @@ type netConn struct {
conn net.Conn
}
-// New establishes a new connection to the system log daemon. Each
+// New establishes a new connection to the system log daemon. Each
// write to the returned writer sends a log message with the given
// priority and prefix.
-func New(priority Priority, tag string) (w *Writer, err error) {
+func New(priority Priority, tag string) (*Writer, error) {
return Dial("", "", priority, tag)
}
// Dial establishes a connection to a log daemon by connecting to
-// address raddr on the specified network. Each write to the returned
+// address raddr on the specified network. Each write to the returned
// writer sends a log message with the given facility, severity and
// tag.
// If network is empty, Dial will connect to the local syslog server.
+// Otherwise, see the documentation for net.Dial for valid values
+// of network and raddr.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
return nil, errors.New("log/syslog: invalid priority")
@@ -187,57 +189,57 @@ func (w *Writer) Close() error {
// Emerg logs a message with severity LOG_EMERG, ignoring the severity
// passed to New.
-func (w *Writer) Emerg(m string) (err error) {
- _, err = w.writeAndRetry(LOG_EMERG, m)
+func (w *Writer) Emerg(m string) error {
+ _, err := w.writeAndRetry(LOG_EMERG, m)
return err
}
// Alert logs a message with severity LOG_ALERT, ignoring the severity
// passed to New.
-func (w *Writer) Alert(m string) (err error) {
- _, err = w.writeAndRetry(LOG_ALERT, m)
+func (w *Writer) Alert(m string) error {
+ _, err := w.writeAndRetry(LOG_ALERT, m)
return err
}
// Crit logs a message with severity LOG_CRIT, ignoring the severity
// passed to New.
-func (w *Writer) Crit(m string) (err error) {
- _, err = w.writeAndRetry(LOG_CRIT, m)
+func (w *Writer) Crit(m string) error {
+ _, err := w.writeAndRetry(LOG_CRIT, m)
return err
}
// Err logs a message with severity LOG_ERR, ignoring the severity
// passed to New.
-func (w *Writer) Err(m string) (err error) {
- _, err = w.writeAndRetry(LOG_ERR, m)
+func (w *Writer) Err(m string) error {
+ _, err := w.writeAndRetry(LOG_ERR, m)
return err
}
// Warning logs a message with severity LOG_WARNING, ignoring the
// severity passed to New.
-func (w *Writer) Warning(m string) (err error) {
- _, err = w.writeAndRetry(LOG_WARNING, m)
+func (w *Writer) Warning(m string) error {
+ _, err := w.writeAndRetry(LOG_WARNING, m)
return err
}
// Notice logs a message with severity LOG_NOTICE, ignoring the
// severity passed to New.
-func (w *Writer) Notice(m string) (err error) {
- _, err = w.writeAndRetry(LOG_NOTICE, m)
+func (w *Writer) Notice(m string) error {
+ _, err := w.writeAndRetry(LOG_NOTICE, m)
return err
}
// Info logs a message with severity LOG_INFO, ignoring the severity
// passed to New.
-func (w *Writer) Info(m string) (err error) {
- _, err = w.writeAndRetry(LOG_INFO, m)
+func (w *Writer) Info(m string) error {
+ _, err := w.writeAndRetry(LOG_INFO, m)
return err
}
// Debug logs a message with severity LOG_DEBUG, ignoring the severity
// passed to New.
-func (w *Writer) Debug(m string) (err error) {
- _, err = w.writeAndRetry(LOG_DEBUG, m)
+func (w *Writer) Debug(m string) error {
+ _, err := w.writeAndRetry(LOG_DEBUG, m)
return err
}
diff --git a/libgo/go/log/syslog/syslog_libc.go b/libgo/go/log/syslog/syslog_libc.go
index cf370eff9d..48963b4350 100644
--- a/libgo/go/log/syslog/syslog_libc.go
+++ b/libgo/go/log/syslog/syslog_libc.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build solaris irix
+
// gccgo specific implementation of syslog for Solaris. Solaris uses
// STREAMS to communicate with syslogd. That is enough of a pain that
// we just call the libc function.
diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go
index 52363f9f7c..1263be6d78 100644
--- a/libgo/go/log/syslog/syslog_test.go
+++ b/libgo/go/log/syslog/syslog_test.go
@@ -134,6 +134,7 @@ func startServer(n, la string, done chan<- string) (addr string, sock io.Closer,
}
func TestWithSimulated(t *testing.T) {
+ t.Parallel()
msg := "Test 123"
var transport []string
for _, n := range []string{"unix", "unixgram", "udp", "tcp"} {
@@ -262,6 +263,7 @@ func check(t *testing.T, in, out string) {
}
func TestWrite(t *testing.T) {
+ t.Parallel()
tests := []struct {
pri Priority
pre string
@@ -367,7 +369,8 @@ func TestConcurrentReconnect(t *testing.T) {
defer wg.Done()
w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag")
if err != nil {
- t.Fatalf("syslog.Dial() failed: %v", err)
+ t.Errorf("syslog.Dial() failed: %v", err)
+ return
}
defer w.Close()
for i := 0; i < M; i++ {
diff --git a/libgo/go/log/syslog/syslog_unix.go b/libgo/go/log/syslog/syslog_unix.go
index 1cdabec692..356b98d18e 100644
--- a/libgo/go/log/syslog/syslog_unix.go
+++ b/libgo/go/log/syslog/syslog_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows,!nacl,!plan9
+// +build !windows,!nacl,!plan9,!solaris,!irix
package syslog
diff --git a/libgo/go/math/acosh.go b/libgo/go/math/acosh.go
index e394008b07..dce21b2350 100644
--- a/libgo/go/math/acosh.go
+++ b/libgo/go/math/acosh.go
@@ -6,7 +6,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go
index 968a7b1837..3d8cd7223d 100644
--- a/libgo/go/math/all_test.go
+++ b/libgo/go/math/all_test.go
@@ -1165,21 +1165,88 @@ var frexpSC = []fi{
{NaN(), 0},
}
-var vfgammaSC = []float64{
- Inf(-1),
- -3,
- Copysign(0, -1),
- 0,
- Inf(1),
- NaN(),
-}
-var gammaSC = []float64{
- NaN(),
- NaN(),
- Inf(-1),
- Inf(1),
- Inf(1),
- NaN(),
+var vfgamma = [][2]float64{
+ {Inf(1), Inf(1)},
+ {Inf(-1), NaN()},
+ {0, Inf(1)},
+ {Copysign(0, -1), Inf(-1)},
+ {NaN(), NaN()},
+ {-1, NaN()},
+ {-2, NaN()},
+ {-3, NaN()},
+ {-1e16, NaN()},
+ {-1e300, NaN()},
+ {1.7e308, Inf(1)},
+
+ // Test inputs inspired by Python test suite.
+ // Outputs computed at high precision by PARI/GP.
+ // If recomputing table entries, be careful to use
+ // high-precision (%.1000g) formatting of the float64 inputs.
+ // For example, -2.0000000000000004 is the float64 with exact value
+ // -2.00000000000000044408920985626161695, and
+ // gamma(-2.0000000000000004) = -1249999999999999.5386078562728167651513, while
+ // gamma(-2.00000000000000044408920985626161695) = -1125899906826907.2044875028130093136826.
+ // Thus the table lists -1.1258999068426235e+15 as the answer.
+ {0.5, 1.772453850905516},
+ {1.5, 0.886226925452758},
+ {2.5, 1.329340388179137},
+ {3.5, 3.3233509704478426},
+ {-0.5, -3.544907701811032},
+ {-1.5, 2.363271801207355},
+ {-2.5, -0.9453087204829419},
+ {-3.5, 0.2700882058522691},
+ {0.1, 9.51350769866873},
+ {0.01, 99.4325851191506},
+ {1e-08, 9.999999942278434e+07},
+ {1e-16, 1e+16},
+ {0.001, 999.4237724845955},
+ {1e-16, 1e+16},
+ {1e-308, 1e+308},
+ {5.6e-309, 1.7857142857142864e+308},
+ {5.5e-309, Inf(1)},
+ {1e-309, Inf(1)},
+ {1e-323, Inf(1)},
+ {5e-324, Inf(1)},
+ {-0.1, -10.686287021193193},
+ {-0.01, -100.58719796441078},
+ {-1e-08, -1.0000000057721567e+08},
+ {-1e-16, -1e+16},
+ {-0.001, -1000.5782056293586},
+ {-1e-16, -1e+16},
+ {-1e-308, -1e+308},
+ {-5.6e-309, -1.7857142857142864e+308},
+ {-5.5e-309, Inf(-1)},
+ {-1e-309, Inf(-1)},
+ {-1e-323, Inf(-1)},
+ {-5e-324, Inf(-1)},
+ {-0.9999999999999999, -9.007199254740992e+15},
+ {-1.0000000000000002, 4.5035996273704955e+15},
+ {-1.9999999999999998, 2.2517998136852485e+15},
+ {-2.0000000000000004, -1.1258999068426235e+15},
+ {-100.00000000000001, -7.540083334883109e-145},
+ {-99.99999999999999, 7.540083334884096e-145},
+ {17, 2.0922789888e+13},
+ {171, 7.257415615307999e+306},
+ {171.6, 1.5858969096672565e+308},
+ {171.624, 1.7942117599248104e+308},
+ {171.625, Inf(1)},
+ {172, Inf(1)},
+ {2000, Inf(1)},
+ {-100.5, -3.3536908198076787e-159},
+ {-160.5, -5.255546447007829e-286},
+ {-170.5, -3.3127395215386074e-308},
+ {-171.5, 1.9316265431712e-310},
+ {-176.5, -1.196e-321},
+ {-177.5, 5e-324},
+ {-178.5, Copysign(0, -1)},
+ {-179.5, 0},
+ {-201.0001, 0},
+ {-202.9999, Copysign(0, -1)},
+ {-1000.5, Copysign(0, -1)},
+ {-1.0000000003e+09, Copysign(0, -1)},
+ {-4.5035996273704955e+15, 0},
+ {-63.349078729022985, 4.177797167776188e-88},
+ {-127.45117632943295, 1.183111089623681e-214},
}
var vfhypotSC = [][2]float64{
@@ -1225,12 +1292,6 @@ var hypotSC = []float64{
NaN(),
}
-var vfilogbSC = []float64{
- Inf(-1),
- 0,
- Inf(1),
- NaN(),
-}
var ilogbSC = []int{
MaxInt32,
MinInt32,
@@ -1741,6 +1802,12 @@ var logbBC = []float64{
}
func tolerance(a, b, e float64) bool {
+ // Multiplying by e here can underflow denormal values to zero.
+ // Check a==b so that at least if a and b are small and identical
+ // we say they match.
+ if a == b {
+ return true
+ }
d := a - b
if d < 0 {
d = -d
@@ -1756,7 +1823,6 @@ func tolerance(a, b, e float64) bool {
}
return d < e
}
-func kindaclose(a, b float64) bool { return tolerance(a, b, 1e-8) }
func close(a, b float64) bool { return tolerance(a, b, 1e-14) }
func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
@@ -1981,7 +2047,7 @@ func TestExp(t *testing.T) {
func testExp(t *testing.T, Exp func(float64) float64, name string) {
for i := 0; i < len(vf); i++ {
- if f := Exp(vf[i]); !close(exp[i], f) {
+ if f := Exp(vf[i]); !veryclose(exp[i], f) {
t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
}
}
@@ -2154,9 +2220,18 @@ func TestGamma(t *testing.T) {
t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
}
}
- for i := 0; i < len(vfgammaSC); i++ {
- if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
- t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
+ for _, g := range vfgamma {
+ f := Gamma(g[0])
+ var ok bool
+ if IsNaN(g[1]) || IsInf(g[1], 0) || g[1] == 0 || f == 0 {
+ ok = alike(g[1], f)
+ } else if g[0] > -50 && g[0] <= 171 {
+ ok = veryclose(g[1], f)
+ } else {
+ ok = close(g[1], f)
+ }
+ if !ok {
+ t.Errorf("Gamma(%g) = %g, want %g", g[0], f, g[1])
}
}
}
@@ -3007,27 +3082,36 @@ func BenchmarkSinh(b *testing.B) {
var Global float64
-func BenchmarkSqrt(b *testing.B) {
+func BenchmarkSqrtIndirect(b *testing.B) {
x, y := 0.0, 10.0
+ f := Sqrt
for i := 0; i < b.N; i++ {
- x += Sqrt(y)
+ x += f(y)
}
Global = x
}
-func BenchmarkSqrtIndirect(b *testing.B) {
- x, y := 0.0, 10.0
+func BenchmarkSqrtLatency(b *testing.B) {
+ x := 10.0
+ for i := 0; i < b.N; i++ {
+ x = Sqrt(x)
+ }
+ Global = x
+}
+
+func BenchmarkSqrtIndirectLatency(b *testing.B) {
+ x := 10.0
f := Sqrt
for i := 0; i < b.N; i++ {
- x += f(y)
+ x = f(x)
}
Global = x
}
-func BenchmarkSqrtGo(b *testing.B) {
- x, y := 0.0, 10.0
+func BenchmarkSqrtGoLatency(b *testing.B) {
+ x := 10.0
for i := 0; i < b.N; i++ {
- x += SqrtGo(y)
+ x = SqrtGo(x)
}
Global = x
}
diff --git a/libgo/go/math/arith_s390x.go b/libgo/go/math/arith_s390x.go
new file mode 100644
index 0000000000..937f25faac
--- /dev/null
+++ b/libgo/go/math/arith_s390x.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package math
+
+func log10TrampolineSetup(x float64) float64
+func log10Asm(x float64) float64
+
+func cosTrampolineSetup(x float64) float64
+func cosAsm(x float64) float64
+
+func coshTrampolineSetup(x float64) float64
+func coshAsm(x float64) float64
+
+func sinTrampolineSetup(x float64) float64
+func sinAsm(x float64) float64
+
+func sinhTrampolineSetup(x float64) float64
+func sinhAsm(x float64) float64
+
+func tanhTrampolineSetup(x float64) float64
+func tanhAsm(x float64) float64
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
diff --git a/libgo/go/math/arith_s390x_test.go b/libgo/go/math/arith_s390x_test.go
new file mode 100644
index 0000000000..fd3e8ca428
--- /dev/null
+++ b/libgo/go/math/arith_s390x_test.go
@@ -0,0 +1,146 @@
+// 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
+
+// Tests whether the non vector routines are working, even when the tests are run on a
+// vector-capable machine.
+package math_test
+
+import (
+ . "math"
+ "testing"
+)
+
+func TestCosNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := CosNoVec(vf[i]); !veryclose(cos[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vfcosSC); i++ {
+ if f := CosNoVec(vfcosSC[i]); !alike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
+ }
+ }
+}
+
+func TestCoshNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := CoshNoVec(vf[i]); !close(cosh[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vfcoshSC); i++ {
+ if f := CoshNoVec(vfcoshSC[i]); !alike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
+ }
+ }
+}
+func TestSinNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := SinNoVec(vf[i]); !veryclose(sin[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := SinNoVec(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+}
+
+func TestSinhNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := SinhNoVec(vf[i]); !close(sinh[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vfsinhSC); i++ {
+ if f := SinhNoVec(vfsinhSC[i]); !alike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+
+// Check that math functions of high angle values
+// return accurate results. [Since (vf[i] + large) - large != vf[i],
+// testing for Trig(vf[i] + large) == Trig(vf[i]), where large is
+// a multiple of 2*Pi, is misleading.]
+func TestLargeCosNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := cosLarge[i]
+ f2 := CosNoVec(vf[i] + large)
+ if !close(f1, f2) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSinNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := sinLarge[i]
+ f2 := SinNoVec(vf[i] + large)
+ if !close(f1, f2) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestTanhNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := TanhNoVec(vf[i]); !veryclose(tanh[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vftanhSC); i++ {
+ if f := TanhNoVec(vftanhSC[i]); !alike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
+ }
+ }
+
+}
+
+func TestLog10Novec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ a := Abs(vf[i])
+ if f := Log10NoVec(a); !veryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
+ }
+ }
+ if f := Log10NoVec(E); f != Log10E {
+ t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log10NoVec(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
diff --git a/libgo/go/math/asinh.go b/libgo/go/math/asinh.go
index ff2de0215f..3b793b0cea 100644
--- a/libgo/go/math/asinh.go
+++ b/libgo/go/math/asinh.go
@@ -6,7 +6,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/atanh.go b/libgo/go/math/atanh.go
index 113d5c103c..d59a8474fc 100644
--- a/libgo/go/math/atanh.go
+++ b/libgo/go/math/atanh.go
@@ -6,7 +6,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/big/arith_decl.go b/libgo/go/math/big/arith_decl.go
index 1707aa4e20..553883394f 100644
--- a/libgo/go/math/big/arith_decl.go
+++ b/libgo/go/math/big/arith_decl.go
@@ -1,7 +1,8 @@
-// Copyright 2010 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.
+// +build ignore
// +build !math_big_pure_go
package big
diff --git a/libgo/go/math/big/arith_decl_pure.go b/libgo/go/math/big/arith_decl_pure.go
index e760a3816b..5c04414b06 100644
--- a/libgo/go/math/big/arith_decl_pure.go
+++ b/libgo/go/math/big/arith_decl_pure.go
@@ -1,8 +1,8 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 math_big_pure_go
+// -build math_big_pure_go
package big
diff --git a/libgo/go/math/big/arith_decl_s390x.go b/libgo/go/math/big/arith_decl_s390x.go
new file mode 100644
index 0000000000..3936d3faad
--- /dev/null
+++ b/libgo/go/math/big/arith_decl_s390x.go
@@ -0,0 +1,24 @@
+// 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
+// +build !math_big_pure_go
+
+package big
+
+func addVV_check(z, x, y []Word) (c Word)
+func addVV_vec(z, x, y []Word) (c Word)
+func addVV_novec(z, x, y []Word) (c Word)
+func subVV_check(z, x, y []Word) (c Word)
+func subVV_vec(z, x, y []Word) (c Word)
+func subVV_novec(z, x, y []Word) (c Word)
+func addVW_check(z, x []Word, y Word) (c Word)
+func addVW_vec(z, x []Word, y Word) (c Word)
+func addVW_novec(z, x []Word, y Word) (c Word)
+func subVW_check(z, x []Word, y Word) (c Word)
+func subVW_vec(z, x []Word, y Word) (c Word)
+func subVW_novec(z, x []Word, y Word) (c Word)
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
diff --git a/libgo/go/math/big/arith_s390x_test.go b/libgo/go/math/big/arith_s390x_test.go
new file mode 100644
index 0000000000..ee127a4fc9
--- /dev/null
+++ b/libgo/go/math/big/arith_s390x_test.go
@@ -0,0 +1,45 @@
+// 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
+// +build s390x !math_big_pure_go
+
+package big
+
+import (
+ "testing"
+)
+
+// Tests whether the non vector routines are working, even when the tests are run on a
+// vector-capable machine
+
+func TestFunVVnovec(t *testing.T) {
+ if hasVX == true {
+ for _, a := range sumVV {
+ arg := a
+ testFunVV(t, "addVV_novec", addVV_novec, arg)
+
+ arg = argVV{a.z, a.y, a.x, a.c}
+ testFunVV(t, "addVV_novec symmetric", addVV_novec, arg)
+
+ arg = argVV{a.x, a.z, a.y, a.c}
+ testFunVV(t, "subVV_novec", subVV_novec, arg)
+
+ arg = argVV{a.y, a.z, a.x, a.c}
+ testFunVV(t, "subVV_novec symmetric", subVV_novec, arg)
+ }
+ }
+}
+
+func TestFunVWnovec(t *testing.T) {
+ if hasVX == true {
+ for _, a := range sumVW {
+ arg := a
+ testFunVW(t, "addVW_novec", addVW_novec, arg)
+
+ arg = argVW{a.x, a.z, a.y, a.c}
+ testFunVW(t, "subVW_novec", subVW_novec, arg)
+ }
+ }
+}
diff --git a/libgo/go/math/big/arith_test.go b/libgo/go/math/big/arith_test.go
index f46a494f17..f2b3083000 100644
--- a/libgo/go/math/big/arith_test.go
+++ b/libgo/go/math/big/arith_test.go
@@ -5,10 +5,15 @@
package big
import (
+ "fmt"
+ "internal/testenv"
"math/rand"
+ "strings"
"testing"
)
+var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
+
type funWW func(x, y, c Word) (z1, z0 Word)
type argWW struct {
x, y, c, z1, z0 Word
@@ -118,28 +123,25 @@ 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 {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
+ 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
@@ -158,21 +160,6 @@ var sumVW = []argVW{
{nat{585}, nat{314}, 271, 0},
}
-var prodVW = []argVW{
- {},
- {nat{0}, nat{0}, 0, 0},
- {nat{0}, nat{_M}, 0, 0},
- {nat{0}, nat{0}, _M, 0},
- {nat{1}, nat{1}, 1, 0},
- {nat{22793}, nat{991}, 23, 0},
- {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
- {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
- {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
- {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
- {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
- {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
-}
-
var lshVW = []argVW{
{},
{nat{0}, nat{0}, 0, 0},
@@ -251,28 +238,23 @@ 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 {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
+ 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
@@ -397,28 +379,23 @@ 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 {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
+ 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
@@ -435,23 +412,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) }
diff --git a/libgo/go/math/big/decimal.go b/libgo/go/math/big/decimal.go
index 2c0c9daebc..2dfa032c77 100644
--- a/libgo/go/math/big/decimal.go
+++ b/libgo/go/math/big/decimal.go
@@ -125,11 +125,12 @@ func shr(x *decimal, s uint) {
// read a digit, write a digit
w := 0 // write index
+ mask := Word(1)<<s - 1
for r < len(x.mant) {
ch := Word(x.mant[r])
r++
d := n >> s
- n -= d << s
+ n &= mask // n -= d << s
x.mant[w] = byte(d + '0')
w++
n = n*10 + ch - '0'
@@ -138,7 +139,7 @@ func shr(x *decimal, s uint) {
// write extra digits that still fit
for n > 0 && w < len(x.mant) {
d := n >> s
- n -= d << s
+ n &= mask
x.mant[w] = byte(d + '0')
w++
n = n * 10
@@ -148,7 +149,7 @@ func shr(x *decimal, s uint) {
// append additional digits that didn't fit
for n > 0 {
d := n >> s
- n -= d << s
+ n &= mask
x.mant = append(x.mant, byte(d+'0'))
n = n * 10
}
diff --git a/libgo/go/math/big/decimal_test.go b/libgo/go/math/big/decimal_test.go
index 15bdb181e7..424811e15a 100644
--- a/libgo/go/math/big/decimal_test.go
+++ b/libgo/go/math/big/decimal_test.go
@@ -4,7 +4,10 @@
package big
-import "testing"
+import (
+ "fmt"
+ "testing"
+)
func TestDecimalString(t *testing.T) {
for _, test := range []struct {
@@ -105,12 +108,27 @@ func TestDecimalRounding(t *testing.T) {
}
}
+var sink string
+
func BenchmarkDecimalConversion(b *testing.B) {
for i := 0; i < b.N; i++ {
for shift := -100; shift <= +100; shift++ {
var d decimal
d.init(natOne, shift)
- d.String()
+ sink = d.String()
}
}
}
+
+func BenchmarkFloatString(b *testing.B) {
+ x := new(Float)
+ for _, prec := range []uint{1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ sink = x.String()
+ }
+ })
+ }
+}
diff --git a/libgo/go/math/big/doc.go b/libgo/go/math/big/doc.go
index a3c23751ba..65ed019b74 100644
--- a/libgo/go/math/big/doc.go
+++ b/libgo/go/math/big/doc.go
@@ -31,7 +31,7 @@ setters, for instance:
var z1 Int
z1.SetUint64(123) // z1 := 123
- z2 := new(Rat).SetFloat64(1.2) // z2 := 6/5
+ z2 := new(Rat).SetFloat64(1.25) // z2 := 5/4
z3 := new(Float).SetInt(z1) // z3 := 123.0
Setters, numeric operations and predicates are represented as methods of
diff --git a/libgo/go/math/big/float.go b/libgo/go/math/big/float.go
index b1c748c9a5..aabd7b4477 100644
--- a/libgo/go/math/big/float.go
+++ b/libgo/go/math/big/float.go
@@ -392,15 +392,13 @@ func (z *Float) round(sbit uint) {
// m > 0 implies z.prec > 0 (checked by validate)
m := uint32(len(z.mant)) // present mantissa length in words
- bits := m * _W // present mantissa bits
+ bits := m * _W // present mantissa bits; bits > 0
if bits <= z.prec {
// mantissa fits => nothing to do
return
}
// bits > z.prec
- n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
-
// Rounding is based on two bits: the rounding bit (rbit) and the
// sticky bit (sbit). The rbit is the bit immediately before the
// z.prec leading mantissa bits (the "0.5"). The sbit is set if any
@@ -415,111 +413,77 @@ func (z *Float) round(sbit uint) {
// bits > z.prec: mantissa too large => round
r := uint(bits - z.prec - 1) // rounding bit position; r >= 0
- rbit := z.mant.bit(r) // rounding bit
+ rbit := z.mant.bit(r) & 1 // rounding bit; be safe and ensure it's a single bit
if sbit == 0 {
+ // TODO(gri) if rbit != 0 we don't need to compute sbit for some rounding modes (optimization)
sbit = z.mant.sticky(r)
}
- if debugFloat && sbit&^1 != 0 {
- panic(fmt.Sprintf("invalid sbit %#x", sbit))
- }
-
- // convert ToXInf rounding modes
- mode := z.mode
- switch mode {
- case ToNegativeInf:
- mode = ToZero
- if z.neg {
- mode = AwayFromZero
- }
- case ToPositiveInf:
- mode = AwayFromZero
- if z.neg {
- mode = ToZero
- }
- }
+ sbit &= 1 // be safe and ensure it's a single bit
// cut off extra words
+ n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
if m > n {
copy(z.mant, z.mant[m-n:]) // move n last words to front
z.mant = z.mant[:n]
}
- // determine number of trailing zero bits t
- t := n*_W - z.prec // 0 <= t < _W
- lsb := Word(1) << t
-
- // make rounding decision
- // TODO(gri) This can be simplified (see Bits.round in bits_test.go).
- switch mode {
- case ToZero:
- // nothing to do
- case ToNearestEven, ToNearestAway:
- if rbit == 0 {
- // rounding bits == 0b0x
- mode = ToZero
- } else if sbit == 1 {
- // rounding bits == 0b11
- mode = AwayFromZero
- }
- case AwayFromZero:
- if rbit|sbit == 0 {
- mode = ToZero
- }
- default:
- // ToXInf modes have been converted to ToZero or AwayFromZero
- panic("unreachable")
- }
-
- // round and determine accuracy
- switch mode {
- case ToZero:
- if rbit|sbit != 0 {
- z.acc = Below
+ // determine number of trailing zero bits (ntz) and compute lsb mask of mantissa's least-significant word
+ ntz := n*_W - z.prec // 0 <= ntz < _W
+ lsb := Word(1) << ntz
+
+ // round if result is inexact
+ if rbit|sbit != 0 {
+ // Make rounding decision: The result mantissa is truncated ("rounded down")
+ // by default. Decide if we need to increment, or "round up", the (unsigned)
+ // mantissa.
+ inc := false
+ switch z.mode {
+ case ToNegativeInf:
+ inc = z.neg
+ case ToZero:
+ // nothing to do
+ case ToNearestEven:
+ inc = rbit != 0 && (sbit != 0 || z.mant[0]&lsb != 0)
+ case ToNearestAway:
+ inc = rbit != 0
+ case AwayFromZero:
+ inc = true
+ case ToPositiveInf:
+ inc = !z.neg
+ default:
+ panic("unreachable")
}
- case ToNearestEven, ToNearestAway:
- if debugFloat && rbit != 1 {
- panic("internal error in rounding")
- }
- if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 {
- z.acc = Below
- break
- }
- // mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0
- fallthrough
-
- case AwayFromZero:
- // add 1 to mantissa
- if addVW(z.mant, z.mant, lsb) != 0 {
- // overflow => shift mantissa right by 1 and add msb
- shrVU(z.mant, z.mant, 1)
- z.mant[n-1] |= 1 << (_W - 1)
- // adjust exponent
- if z.exp < MaxExp {
+ // A positive result (!z.neg) is Above the exact result if we increment,
+ // and it's Below if we truncate (Exact results require no rounding).
+ // For a negative result (z.neg) it is exactly the opposite.
+ z.acc = makeAcc(inc != z.neg)
+
+ if inc {
+ // add 1 to mantissa
+ if addVW(z.mant, z.mant, lsb) != 0 {
+ // mantissa overflow => adjust exponent
+ if z.exp >= MaxExp {
+ // exponent overflow
+ z.form = inf
+ return
+ }
z.exp++
- } else {
- // exponent overflow
- z.acc = makeAcc(!z.neg)
- z.form = inf
- return
+ // adjust mantissa: divide by 2 to compensate for exponent adjustment
+ shrVU(z.mant, z.mant, 1)
+ // set msb == carry == 1 from the mantissa overflow above
+ const msb = 1 << (_W - 1)
+ z.mant[n-1] |= msb
}
}
- z.acc = Above
}
// zero out trailing bits in least-significant word
z.mant[0] &^= lsb - 1
- // update accuracy
- if z.acc != Exact && z.neg {
- z.acc = -z.acc
- }
-
if debugFloat {
z.validate()
}
-
- return
}
func (z *Float) setBits64(neg bool, x uint64) *Float {
@@ -874,21 +838,43 @@ func (x *Float) Float32() (float32, Accuracy) {
emax = bias // 127 largest unbiased exponent (normal)
)
- // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
- e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
- p := mbits + 1 // precision of normal float
+ // Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float32 mantissa.
+ e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
- // If the exponent is too small, we may have a denormal number
- // in which case we have fewer mantissa bits available: reduce
- // precision accordingly.
+ // Compute precision p for float32 mantissa.
+ // If the exponent is too small, we have a denormal number before
+ // rounding and fewer than p mantissa bits of precision available
+ // (the exponent remains fixed but the mantissa gets shifted right).
+ p := mbits + 1 // precision of normal float
if e < emin {
- p -= emin - int(e)
- // Make sure we have at least 1 bit so that we don't
- // lose numbers rounded up to the smallest denormal.
- if p < 1 {
- p = 1
+ // recompute precision
+ p = mbits + 1 - emin + int(e)
+ // If p == 0, the mantissa of x is shifted so much to the right
+ // that its msb falls immediately to the right of the float32
+ // mantissa space. In other words, if the smallest denormal is
+ // considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+ // If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+ // If m == 0.5, it is rounded down to even, i.e., 0.0.
+ // If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+ if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+ // underflow to ±0
+ if x.neg {
+ var z float32
+ return -z, Above
+ }
+ return 0.0, Below
+ }
+ // otherwise, round up
+ // We handle p == 0 explicitly because it's easy and because
+ // Float.round doesn't support rounding to 0 bits of precision.
+ if p == 0 {
+ if x.neg {
+ return -math.SmallestNonzeroFloat32, Below
+ }
+ return math.SmallestNonzeroFloat32, Above
}
}
+ // p > 0
// round
var r Float
@@ -898,12 +884,8 @@ func (x *Float) Float32() (float32, Accuracy) {
// Rounding may have caused r to overflow to ±Inf
// (rounding never causes underflows to 0).
- if r.form == inf {
- e = emax + 1 // cause overflow below
- }
-
- // If the exponent is too large, overflow to ±Inf.
- if e > emax {
+ // If the exponent is too large, also overflow to ±Inf.
+ if r.form == inf || e > emax {
// overflow
if x.neg {
return float32(math.Inf(-1)), Below
@@ -921,17 +903,12 @@ func (x *Float) Float32() (float32, Accuracy) {
// Rounding may have caused a denormal number to
// become normal. Check again.
if e < emin {
- // denormal number
- if e < dmin {
- // underflow to ±0
- if x.neg {
- var z float32
- return -z, Above
- }
- return 0.0, Below
- }
- // bexp = 0
- mant = msb32(r.mant) >> (fbits - r.prec)
+ // denormal number: recompute precision
+ // Since rounding may have at best increased precision
+ // and we have eliminated p <= 0 early, we know p > 0.
+ // bexp == 0 for denormals
+ p = mbits + 1 - emin + int(e)
+ mant = msb32(r.mant) >> uint(fbits-p)
} else {
// normal number: emin <= e <= emax
bexp = uint32(e+bias) << mbits
@@ -981,21 +958,43 @@ func (x *Float) Float64() (float64, Accuracy) {
emax = bias // 1023 largest unbiased exponent (normal)
)
- // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
- e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
- p := mbits + 1 // precision of normal float
+ // Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float64 mantissa.
+ e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
- // If the exponent is too small, we may have a denormal number
- // in which case we have fewer mantissa bits available: reduce
- // precision accordingly.
+ // Compute precision p for float64 mantissa.
+ // If the exponent is too small, we have a denormal number before
+ // rounding and fewer than p mantissa bits of precision available
+ // (the exponent remains fixed but the mantissa gets shifted right).
+ p := mbits + 1 // precision of normal float
if e < emin {
- p -= emin - int(e)
- // Make sure we have at least 1 bit so that we don't
- // lose numbers rounded up to the smallest denormal.
- if p < 1 {
- p = 1
+ // recompute precision
+ p = mbits + 1 - emin + int(e)
+ // If p == 0, the mantissa of x is shifted so much to the right
+ // that its msb falls immediately to the right of the float64
+ // mantissa space. In other words, if the smallest denormal is
+ // considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+ // If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+ // If m == 0.5, it is rounded down to even, i.e., 0.0.
+ // If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+ if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+ // underflow to ±0
+ if x.neg {
+ var z float64
+ return -z, Above
+ }
+ return 0.0, Below
+ }
+ // otherwise, round up
+ // We handle p == 0 explicitly because it's easy and because
+ // Float.round doesn't support rounding to 0 bits of precision.
+ if p == 0 {
+ if x.neg {
+ return -math.SmallestNonzeroFloat64, Below
+ }
+ return math.SmallestNonzeroFloat64, Above
}
}
+ // p > 0
// round
var r Float
@@ -1005,12 +1004,8 @@ func (x *Float) Float64() (float64, Accuracy) {
// Rounding may have caused r to overflow to ±Inf
// (rounding never causes underflows to 0).
- if r.form == inf {
- e = emax + 1 // cause overflow below
- }
-
- // If the exponent is too large, overflow to ±Inf.
- if e > emax {
+ // If the exponent is too large, also overflow to ±Inf.
+ if r.form == inf || e > emax {
// overflow
if x.neg {
return math.Inf(-1), Below
@@ -1028,17 +1023,12 @@ func (x *Float) Float64() (float64, Accuracy) {
// Rounding may have caused a denormal number to
// become normal. Check again.
if e < emin {
- // denormal number
- if e < dmin {
- // underflow to ±0
- if x.neg {
- var z float64
- return -z, Above
- }
- return 0.0, Below
- }
- // bexp = 0
- mant = msb64(r.mant) >> (fbits - r.prec)
+ // denormal number: recompute precision
+ // Since rounding may have at best increased precision
+ // and we have eliminated p <= 0 early, we know p > 0.
+ // bexp == 0 for denormals
+ p = mbits + 1 - emin + int(e)
+ mant = msb64(r.mant) >> uint(fbits-p)
} else {
// normal number: emin <= e <= emax
bexp = uint64(e+bias) << mbits
@@ -1220,20 +1210,30 @@ func (z *Float) uadd(x, y *Float) {
ex := int64(x.exp) - int64(len(x.mant))*_W
ey := int64(y.exp) - int64(len(y.mant))*_W
+ al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
+
// TODO(gri) having a combined add-and-shift primitive
// could make this code significantly faster
switch {
case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = z.mant.add(x.mant, t)
+ if al {
+ t := nat(nil).shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.add(x.mant, t)
+ } else {
+ z.mant = z.mant.shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.add(x.mant, z.mant)
+ }
default:
// ex == ey, no shift needed
z.mant = z.mant.add(x.mant, y.mant)
case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = z.mant.add(t, y.mant)
+ if al {
+ t := nat(nil).shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.add(t, y.mant)
+ } else {
+ z.mant = z.mant.shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.add(z.mant, y.mant)
+ }
ex = ey
}
// len(z.mant) > 0
@@ -1257,18 +1257,28 @@ func (z *Float) usub(x, y *Float) {
ex := int64(x.exp) - int64(len(x.mant))*_W
ey := int64(y.exp) - int64(len(y.mant))*_W
+ al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
+
switch {
case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = t.sub(x.mant, t)
+ if al {
+ t := nat(nil).shl(y.mant, uint(ey-ex))
+ z.mant = t.sub(x.mant, t)
+ } else {
+ z.mant = z.mant.shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.sub(x.mant, z.mant)
+ }
default:
// ex == ey, no shift needed
z.mant = z.mant.sub(x.mant, y.mant)
case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = t.sub(t, y.mant)
+ if al {
+ t := nat(nil).shl(x.mant, uint(ex-ey))
+ z.mant = t.sub(t, y.mant)
+ } else {
+ z.mant = z.mant.shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.sub(z.mant, y.mant)
+ }
ex = ey
}
@@ -1427,7 +1437,7 @@ func (z *Float) Add(x, y *Float) *Float {
}
if x.form == finite && y.form == finite {
- // x + y (commom case)
+ // x + y (common case)
z.neg = x.neg
if x.neg == y.neg {
// x + y == x + y
diff --git a/libgo/go/math/big/float_test.go b/libgo/go/math/big/float_test.go
index d3b214b631..7d4bd312c9 100644
--- a/libgo/go/math/big/float_test.go
+++ b/libgo/go/math/big/float_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "flag"
"fmt"
"math"
"strconv"
@@ -829,7 +830,7 @@ func TestFloatFloat32(t *testing.T) {
}{
{"0", 0, Exact},
- // underflow
+ // underflow to zero
{"1e-1000", 0, Below},
{"0x0.000002p-127", 0, Below},
{"0x.0000010p-126", 0, Below},
@@ -843,6 +844,46 @@ func TestFloatFloat32(t *testing.T) {
{"1p-149", math.SmallestNonzeroFloat32, Exact},
{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
+ // special denormal cases (see issues 14553, 14651)
+ {"0x0.0000001p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+ {"0x0.0000008p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+ {"0x0.0000010p-126", math.Float32frombits(0x00000000), Below}, // rounded down to even
+ {"0x0.0000011p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+ {"0x0.0000018p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+
+ {"0x1.0000000p-149", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+ {"0x0.0000020p-126", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+ {"0x0.fffffe0p-126", math.Float32frombits(0x007fffff), Exact}, // largest denormal
+ {"0x1.0000000p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
+
+ {"0x0.8p-149", math.Float32frombits(0x000000000), Below}, // rounded down to even
+ {"0x0.9p-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+ {"0x0.ap-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+ {"0x0.bp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+ {"0x0.cp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+
+ {"0x1.0p-149", math.Float32frombits(0x000000001), Exact}, // smallest denormal
+ {"0x1.7p-149", math.Float32frombits(0x000000001), Below},
+ {"0x1.8p-149", math.Float32frombits(0x000000002), Above},
+ {"0x1.9p-149", math.Float32frombits(0x000000002), Above},
+
+ {"0x2.0p-149", math.Float32frombits(0x000000002), Exact},
+ {"0x2.8p-149", math.Float32frombits(0x000000002), Below}, // rounded down to even
+ {"0x2.9p-149", math.Float32frombits(0x000000003), Above},
+
+ {"0x3.0p-149", math.Float32frombits(0x000000003), Exact},
+ {"0x3.7p-149", math.Float32frombits(0x000000003), Below},
+ {"0x3.8p-149", math.Float32frombits(0x000000004), Above}, // rounded up to even
+
+ {"0x4.0p-149", math.Float32frombits(0x000000004), Exact},
+ {"0x4.8p-149", math.Float32frombits(0x000000004), Below}, // rounded down to even
+ {"0x4.9p-149", math.Float32frombits(0x000000005), Above},
+
+ // specific case from issue 14553
+ {"0x7.7p-149", math.Float32frombits(0x000000007), Below},
+ {"0x7.8p-149", math.Float32frombits(0x000000008), Above},
+ {"0x7.9p-149", math.Float32frombits(0x000000008), Above},
+
// normals
{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
{"1p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
@@ -881,7 +922,7 @@ func TestFloatFloat32(t *testing.T) {
x := makeFloat(tx)
out, acc := x.Float32()
if !alike32(out, tout) || acc != tacc {
- t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
+ t.Errorf("%s: got %g (%#08x, %s); want %g (%#08x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
}
// test that x.SetFloat64(float64(f)).Float32() == f
@@ -903,18 +944,48 @@ func TestFloatFloat64(t *testing.T) {
}{
{"0", 0, Exact},
- // underflow
+ // underflow to zero
{"1e-1000", 0, Below},
{"0x0.0000000000001p-1023", 0, Below},
{"0x0.00000000000008p-1022", 0, Below},
// denormals
{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
- {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal
+ {"0x0.00000000000010p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal
{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
{"1p-1074", math.SmallestNonzeroFloat64, Exact},
{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
+ // special denormal cases (see issues 14553, 14651)
+ {"0x0.00000000000001p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+ {"0x0.00000000000004p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+ {"0x0.00000000000008p-1022", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+ {"0x0.00000000000009p-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+ {"0x0.0000000000000ap-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+ {"0x0.8p-1074", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+ {"0x0.9p-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+ {"0x0.ap-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+ {"0x0.bp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+ {"0x0.cp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+ {"0x1.0p-1074", math.Float64frombits(0x00000000000000001), Exact},
+ {"0x1.7p-1074", math.Float64frombits(0x00000000000000001), Below},
+ {"0x1.8p-1074", math.Float64frombits(0x00000000000000002), Above},
+ {"0x1.9p-1074", math.Float64frombits(0x00000000000000002), Above},
+
+ {"0x2.0p-1074", math.Float64frombits(0x00000000000000002), Exact},
+ {"0x2.8p-1074", math.Float64frombits(0x00000000000000002), Below}, // rounded down to even
+ {"0x2.9p-1074", math.Float64frombits(0x00000000000000003), Above},
+
+ {"0x3.0p-1074", math.Float64frombits(0x00000000000000003), Exact},
+ {"0x3.7p-1074", math.Float64frombits(0x00000000000000003), Below},
+ {"0x3.8p-1074", math.Float64frombits(0x00000000000000004), Above}, // rounded up to even
+
+ {"0x4.0p-1074", math.Float64frombits(0x00000000000000004), Exact},
+ {"0x4.8p-1074", math.Float64frombits(0x00000000000000004), Below}, // rounded down to even
+ {"0x4.9p-1074", math.Float64frombits(0x00000000000000005), Above},
+
// normals
{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
{"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, // smallest normal
@@ -958,7 +1029,7 @@ func TestFloatFloat64(t *testing.T) {
x := makeFloat(tx)
out, acc := x.Float64()
if !alike64(out, tout) || acc != tacc {
- t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
+ t.Errorf("%s: got %g (%#016x, %s); want %g (%#016x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
}
// test that x.SetFloat64(f).Float64() == f
@@ -1425,12 +1496,14 @@ func TestFloatQuo(t *testing.T) {
}
}
+var long = flag.Bool("long", false, "run very long tests")
+
// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
// it serves as a smoke test for basic correctness of division.
func TestFloatQuoSmoke(t *testing.T) {
- n := 1000
- if testing.Short() {
- n = 10
+ n := 10
+ if *long {
+ n = 1000
}
const dprec = 3 // max. precision variation
@@ -1692,3 +1765,41 @@ func TestFloatCmpSpecialValues(t *testing.T) {
}
}
}
+
+func BenchmarkFloatAdd(b *testing.B) {
+ x := new(Float)
+ y := new(Float)
+ z := new(Float)
+
+ for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ y.SetPrec(prec).SetRat(NewRat(1, 6))
+ z.SetPrec(prec)
+
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ z.Add(x, y)
+ }
+ })
+ }
+}
+
+func BenchmarkFloatSub(b *testing.B) {
+ x := new(Float)
+ y := new(Float)
+ z := new(Float)
+
+ for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ y.SetPrec(prec).SetRat(NewRat(1, 6))
+ z.SetPrec(prec)
+
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ z.Sub(x, y)
+ }
+ })
+ }
+}
diff --git a/libgo/go/math/big/floatconv.go b/libgo/go/math/big/floatconv.go
index 37d5c06a6f..95d1bf84e2 100644
--- a/libgo/go/math/big/floatconv.go
+++ b/libgo/go/math/big/floatconv.go
@@ -12,9 +12,13 @@ import (
"strings"
)
+var floatZero Float
+
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s must be a floating-point number of the same format as accepted
-// by Parse, with base argument 0.
+// by Parse, with base argument 0. The entire string (not just a prefix) must
+// be valid for success. If the operation failed, the value of z is undefined
+// but the returned value is nil.
func (z *Float) SetString(s string) (*Float, bool) {
if f, _, err := z.Parse(s, 0); err == nil {
return f, true
@@ -85,7 +89,7 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
if fcount < 0 {
// The mantissa has a "decimal" point ddd.dddd; and
// -fcount is the number of digits to the right of '.'.
- // Adjust relevant exponent accodingly.
+ // Adjust relevant exponent accordingly.
d := int64(fcount)
switch b {
case 10:
@@ -212,17 +216,18 @@ func (z *Float) pow5(n uint64) *Float {
//
// It sets z to the (possibly rounded) value of the corresponding floating-
// point value, and returns z, the actual base b, and an error err, if any.
+// The entire string (not just a prefix) must be consumed for success.
// If z's precision is 0, it is changed to 64 before rounding takes effect.
// The number must be of the form:
//
// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
// sign = "+" | "-" .
-// prefix = "0" ( "x" | "X" | "b" | "B" ) .
+// prefix = "0" ( "x" | "X" | "b" | "B" ) .
// mantissa = digits | digits "." [ digits ] | "." digits .
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
// digits = digit { digit } .
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
-// infinity = [ sign ] ( "inf" | "Inf" ) .
+// infinity = [ sign ] ( "inf" | "Inf" ) .
//
// The base argument must be 0, 2, 10, or 16. Providing an invalid base
// argument will lead to a run-time panic.
@@ -273,3 +278,16 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
}
+
+var _ fmt.Scanner = &floatZero // *Float must implement fmt.Scanner
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts formats whose verbs are supported by
+// fmt.Scan for floating point values, which are:
+// 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
+// Scan doesn't handle ±Inf.
+func (z *Float) Scan(s fmt.ScanState, ch rune) error {
+ s.SkipSpace()
+ _, _, err := z.scan(byteReader{s}, 0)
+ return err
+}
diff --git a/libgo/go/math/big/floatconv_test.go b/libgo/go/math/big/floatconv_test.go
index b6f9993608..edcb2eb105 100644
--- a/libgo/go/math/big/floatconv_test.go
+++ b/libgo/go/math/big/floatconv_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "bytes"
"fmt"
"math"
"strconv"
@@ -290,6 +291,11 @@ func TestFloat64Text(t *testing.T) {
// Issue 2625.
{383260575764816448, 'f', 0, "383260575764816448"},
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+
+ // Issue 15918.
+ {1, 'f', -10, "1"},
+ {1, 'f', -11, "1"},
+ {1, 'f', -12, "1"},
} {
// The test cases are from the strconv package which tests float64 values.
// When formatting values with prec = -1 (shortest representation),
@@ -660,3 +666,54 @@ func BenchmarkParseFloatLargeExp(b *testing.B) {
}
}
}
+
+func TestFloatScan(t *testing.T) {
+ var floatScanTests = []struct {
+ input string
+ format string
+ output string
+ remaining int
+ wantErr bool
+ }{
+ 0: {"10.0", "%f", "10", 0, false},
+ 1: {"23.98+2.0", "%v", "23.98", 4, false},
+ 2: {"-1+1", "%v", "-1", 2, false},
+ 3: {" 00000", "%v", "0", 0, false},
+ 4: {"-123456p-78", "%b", "-4.084816388e-19", 0, false},
+ 5: {"+123", "%b", "123", 0, false},
+ 6: {"-1.234e+56", "%e", "-1.234e+56", 0, false},
+ 7: {"-1.234E-56", "%E", "-1.234e-56", 0, false},
+ 8: {"-1.234e+567", "%g", "-1.234e+567", 0, false},
+ 9: {"+1234567891011.234", "%G", "1.234567891e+12", 0, false},
+
+ // Scan doesn't handle ±Inf.
+ 10: {"Inf", "%v", "", 3, true},
+ 11: {"-Inf", "%v", "", 3, true},
+ 12: {"-Inf", "%v", "", 3, true},
+ }
+
+ var buf bytes.Buffer
+ for i, test := range floatScanTests {
+ x := new(Float)
+ buf.Reset()
+ buf.WriteString(test.input)
+ _, err := fmt.Fscanf(&buf, test.format, x)
+ if test.wantErr {
+ if err == nil {
+ t.Errorf("#%d want non-nil err", i)
+ }
+ continue
+ }
+
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err)
+ }
+
+ if x.String() != test.output {
+ t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+ }
+ if buf.Len() != test.remaining {
+ t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+ }
+ }
+}
diff --git a/libgo/go/math/big/floatexample_test.go b/libgo/go/math/big/floatexample_test.go
index 05bce613a8..8645c44f10 100644
--- a/libgo/go/math/big/floatexample_test.go
+++ b/libgo/go/math/big/floatexample_test.go
@@ -13,7 +13,7 @@ import (
)
func ExampleFloat_Add() {
- // Operating on numbers of different precision.
+ // Operate on numbers of different precision.
var x, y, z big.Float
x.SetInt64(1000) // x is automatically set to 64bit precision
y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
@@ -28,8 +28,8 @@ func ExampleFloat_Add() {
// z = 1002.718282 (0x.faadf854p+10, prec = 32, acc = Below)
}
-func Example_Shift() {
- // Implementing Float "shift" by modifying the (binary) exponents directly.
+func ExampleFloat_shift() {
+ // Implement Float "shift" by modifying the (binary) exponents directly.
for s := -5; s <= 5; s++ {
x := big.NewFloat(0.5)
x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
diff --git a/libgo/go/math/big/floatmarsh.go b/libgo/go/math/big/floatmarsh.go
index 44987ee03a..d1c1dab069 100644
--- a/libgo/go/math/big/floatmarsh.go
+++ b/libgo/go/math/big/floatmarsh.go
@@ -6,7 +6,94 @@
package big
-import "fmt"
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const floatGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+// The Float value and all its attributes (precision,
+// rounding mode, accuracy) are marshaled.
+func (x *Float) GobEncode() ([]byte, error) {
+ if x == nil {
+ return nil, nil
+ }
+
+ // determine max. space (bytes) required for encoding
+ sz := 1 + 1 + 4 // version + mode|acc|form|neg (3+2+2+1bit) + prec
+ n := 0 // number of mantissa words
+ if x.form == finite {
+ // add space for mantissa and exponent
+ n = int((x.prec + (_W - 1)) / _W) // required mantissa length in words for given precision
+ // actual mantissa slice could be shorter (trailing 0's) or longer (unused bits):
+ // - if shorter, only encode the words present
+ // - if longer, cut off unused words when encoding in bytes
+ // (in practice, this should never happen since rounding
+ // takes care of it, but be safe and do it always)
+ if len(x.mant) < n {
+ n = len(x.mant)
+ }
+ // len(x.mant) >= n
+ sz += 4 + n*_S // exp + mant
+ }
+ buf := make([]byte, sz)
+
+ buf[0] = floatGobVersion
+ b := byte(x.mode&7)<<5 | byte((x.acc+1)&3)<<3 | byte(x.form&3)<<1
+ if x.neg {
+ b |= 1
+ }
+ buf[1] = b
+ binary.BigEndian.PutUint32(buf[2:], x.prec)
+
+ if x.form == finite {
+ binary.BigEndian.PutUint32(buf[6:], uint32(x.exp))
+ x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words
+ }
+
+ return buf, nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+// The result is rounded per the precision and rounding mode of
+// z unless z's precision is 0, in which case z is set exactly
+// to the decoded value.
+func (z *Float) GobDecode(buf []byte) error {
+ if len(buf) == 0 {
+ // Other side sent a nil or default value.
+ *z = Float{}
+ return nil
+ }
+
+ if buf[0] != floatGobVersion {
+ return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0])
+ }
+
+ oldPrec := z.prec
+ oldMode := z.mode
+
+ b := buf[1]
+ z.mode = RoundingMode((b >> 5) & 7)
+ z.acc = Accuracy((b>>3)&3) - 1
+ z.form = form((b >> 1) & 3)
+ z.neg = b&1 != 0
+ z.prec = binary.BigEndian.Uint32(buf[2:])
+
+ if z.form == finite {
+ z.exp = int32(binary.BigEndian.Uint32(buf[6:]))
+ z.mant = z.mant.setBytes(buf[10:])
+ }
+
+ if oldPrec != 0 {
+ z.mode = oldMode
+ z.SetPrec(uint(oldPrec))
+ }
+
+ return nil
+}
// MarshalText implements the encoding.TextMarshaler interface.
// Only the Float value is marshaled (in full precision), other
diff --git a/libgo/go/math/big/floatmarsh_test.go b/libgo/go/math/big/floatmarsh_test.go
index d7ef2fca68..5bd906ddae 100644
--- a/libgo/go/math/big/floatmarsh_test.go
+++ b/libgo/go/math/big/floatmarsh_test.go
@@ -5,7 +5,10 @@
package big
import (
+ "bytes"
+ "encoding/gob"
"encoding/json"
+ "io"
"testing"
)
@@ -23,6 +26,85 @@ var floatVals = []string{
"Inf",
}
+func TestFloatGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for _, test := range floatVals {
+ for _, sign := range []string{"", "+", "-"} {
+ for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
+ for _, mode := range []RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToNegativeInf, ToPositiveInf} {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ x := sign + test
+
+ var tx Float
+ _, _, err := tx.SetPrec(prec).SetMode(mode).Parse(x, 0)
+ if err != nil {
+ t.Errorf("parsing of %s (%dbits, %v) failed (invalid test case): %v", x, prec, mode, err)
+ continue
+ }
+
+ // If tx was set to prec == 0, tx.Parse(x, 0) assumes precision 64. Correct it.
+ if prec == 0 {
+ tx.SetPrec(0)
+ }
+
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("encoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
+ continue
+ }
+
+ var rx Float
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("decoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
+ continue
+ }
+
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("transmission of %s failed: got %s want %s", x, rx.String(), tx.String())
+ continue
+ }
+
+ if rx.Prec() != prec {
+ t.Errorf("transmission of %s's prec failed: got %d want %d", x, rx.Prec(), prec)
+ }
+
+ if rx.Mode() != mode {
+ t.Errorf("transmission of %s's mode failed: got %s want %s", x, rx.Mode(), mode)
+ }
+
+ if rx.Acc() != tx.Acc() {
+ t.Errorf("transmission of %s's accuracy failed: got %s want %s", x, rx.Acc(), tx.Acc())
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestFloatCorruptGob(t *testing.T) {
+ var buf bytes.Buffer
+ tx := NewFloat(4 / 3).SetPrec(1000).SetMode(ToPositiveInf)
+ if err := gob.NewEncoder(&buf).Encode(tx); err != nil {
+ t.Fatal(err)
+ }
+ b := buf.Bytes()
+
+ var rx Float
+ if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := gob.NewDecoder(bytes.NewReader(b[:10])).Decode(&rx); err != io.ErrUnexpectedEOF {
+ t.Errorf("got %v want EOF", err)
+ }
+
+ b[1] = 0
+ if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err == nil {
+ t.Fatal("got nil want version error")
+ }
+}
+
func TestFloatJSONEncoding(t *testing.T) {
for _, test := range floatVals {
for _, sign := range []string{"", "+", "-"} {
diff --git a/libgo/go/math/big/ftoa.go b/libgo/go/math/big/ftoa.go
index c5cdb5eb70..d2a85886c7 100644
--- a/libgo/go/math/big/ftoa.go
+++ b/libgo/go/math/big/ftoa.go
@@ -41,8 +41,11 @@ import (
// x.Prec() mantissa bits.
// The prec value is ignored for the 'b' or 'p' format.
func (x *Float) Text(format byte, prec int) string {
- const extra = 10 // TODO(gri) determine a good/better value here
- return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+ cap := 10 // TODO(gri) determine a good/better value here
+ if prec > 0 {
+ cap += prec
+ }
+ return string(x.Append(make([]byte, 0, cap), format, prec))
}
// String formats x like x.Text('g', 10).
@@ -333,9 +336,9 @@ func (x *Float) fmtB(buf []byte) []byte {
return strconv.AppendInt(buf, e, 10)
}
-// fmtP appends the string of x in the format 0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
-// ad returns the extended buffer.
+// fmtP appends the string of x in the format "0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or "0" if x is zero,
+// and returns the extended buffer.
// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
// The sign of x is ignored, and x must not be an Inf.
func (x *Float) fmtP(buf []byte) []byte {
@@ -373,13 +376,14 @@ func min(x, y int) int {
return y
}
+var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
+
// Format implements fmt.Formatter. It accepts all the regular
-// formats for floating-point numbers ('e', 'E', 'f', 'F', 'g',
-// 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the
-// interpretation of 'b' and 'p'. The 'v' format is handled like
-// 'g'.
+// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
+// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
+// interpretation of 'p'. The 'v' format is handled like 'g'.
// Format also supports specification of the minimum precision
-// in digits, the output field width, as well as the format verbs
+// in digits, the output field width, as well as the format flags
// '+' and ' ' for sign control, '0' for space or zero padding,
// and '-' for left or right justification. See the fmt package
// for details.
diff --git a/libgo/go/math/big/gcd_test.go b/libgo/go/math/big/gcd_test.go
index c0b9f58300..3cca2ecd0c 100644
--- a/libgo/go/math/big/gcd_test.go
+++ b/libgo/go/math/big/gcd_test.go
@@ -20,13 +20,30 @@ func randInt(r *rand.Rand, size uint) *Int {
}
func runGCD(b *testing.B, aSize, bSize uint) {
+ if isRaceBuilder && (aSize > 1000 || bSize > 1000) {
+ b.Skip("skipping on race builder")
+ }
+ b.Run("WithoutXY", func(b *testing.B) {
+ runGCDExt(b, aSize, bSize, false)
+ })
+ b.Run("WithXY", func(b *testing.B) {
+ runGCDExt(b, aSize, bSize, true)
+ })
+}
+
+func runGCDExt(b *testing.B, aSize, bSize uint, calcXY bool) {
b.StopTimer()
var r = rand.New(rand.NewSource(1234))
aa := randInt(r, aSize)
bb := randInt(r, bSize)
+ var x, y *Int
+ if calcXY {
+ x = new(Int)
+ y = new(Int)
+ }
b.StartTimer()
for i := 0; i < b.N; i++ {
- new(Int).GCD(nil, nil, aa, bb)
+ new(Int).GCD(x, y, aa, bb)
}
}
diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go
index 67ab7042ff..1d8dabce12 100644
--- a/libgo/go/math/big/int.go
+++ b/libgo/go/math/big/int.go
@@ -361,7 +361,8 @@ func (x *Int) Uint64() uint64 {
}
// SetString sets z to the value of s, interpreted in the given base,
-// and returns z and a boolean indicating success. If SetString fails,
+// and returns z and a boolean indicating success. The entire string
+// (not just a prefix) must be valid for success. If SetString fails,
// the value of z is undefined but the returned value is nil.
//
// The base argument must be 0 or a value between 2 and MaxBase. If the base
@@ -371,12 +372,11 @@ func (x *Int) Uint64() uint64 {
//
func (z *Int) SetString(s string, base int) (*Int, bool) {
r := strings.NewReader(s)
- _, _, err := z.scan(r, base)
- if err != nil {
+ if _, _, err := z.scan(r, base); err != nil {
return nil, false
}
- _, err = r.ReadByte()
- if err != io.EOF {
+ // entire string must have been consumed
+ if _, err := r.ReadByte(); err != io.EOF {
return nil, false
}
return z, true // err == io.EOF => scan consumed all of s
@@ -404,8 +404,11 @@ func (x *Int) BitLen() int {
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
-// See Knuth, volume 2, section 4.6.3.
+//
+// Modular exponentation of inputs of a particular size is not a
+// cryptographically constant-time operation.
func (z *Int) Exp(x, y, m *Int) *Int {
+ // See Knuth, volume 2, section 4.6.3.
var yWords nat
if !y.neg {
yWords = y.abs
@@ -459,11 +462,11 @@ func (z *Int) GCD(x, y, a, b *Int) *Int {
q := new(Int)
temp := new(Int)
+ r := new(Int)
for len(B.abs) > 0 {
- r := new(Int)
q, r = q.QuoRem(A, B, r)
- A, B = B, r
+ A, B, r = B, r, A
temp.Set(X)
X.Mul(X, q)
@@ -550,19 +553,6 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
return z.Lsh(u, k)
}
-// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼â¿.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (x *Int) ProbablyPrime(n int) bool {
- if n <= 0 {
- panic("non-positive n for ProbablyPrime")
- }
- return !x.neg && x.abs.probablyPrime(n)
-}
-
// Rand sets z to a pseudo-random number in [0, n) and returns z.
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
z.neg = false
@@ -577,6 +567,11 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
// and returns z. If g and n are not relatively prime, the result is undefined.
func (z *Int) ModInverse(g, n *Int) *Int {
+ if g.neg {
+ // GCD expects parameters a and b to be > 0.
+ var g2 Int
+ g = g2.Mod(g, n)
+ }
var d Int
d.GCD(z, nil, g, n)
// x and y are such that g*x + n*y = d. Since g and n are
@@ -932,3 +927,14 @@ func (z *Int) Not(x *Int) *Int {
z.neg = true // z cannot be zero if x is positive
return z
}
+
+// Sqrt sets z to ⌊√x⌋, the largest integer such that z² ≤ x, and returns z.
+// It panics if x is negative.
+func (z *Int) Sqrt(x *Int) *Int {
+ if x.neg {
+ panic("square root of negative number")
+ }
+ z.neg = false
+ z.abs = z.abs.sqrt(x.abs)
+ return z
+}
diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go
index 45a3765d3e..b8e0778ca3 100644
--- a/libgo/go/math/big/int_test.go
+++ b/libgo/go/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/hex"
"fmt"
"math/rand"
+ "strings"
"testing"
"testing/quick"
)
@@ -478,6 +479,18 @@ func TestQuoStepD6(t *testing.T) {
}
}
+func BenchmarkQuoRem(b *testing.B) {
+ x, _ := new(Int).SetString("153980389784927331788354528594524332344709972855165340650588877572729725338415474372475094155672066328274535240275856844648695200875763869073572078279316458648124537905600131008790701752441155668003033945258023841165089852359980273279085783159654751552359397986180318708491098942831252291841441726305535546071", 0)
+ y, _ := new(Int).SetString("7746362281539803897849273317883545285945243323447099728551653406505888775727297253384154743724750941556720663282745352402758568446486952008757638690735720782793164586481245379056001310087907017524411556680030339452580238411650898523599802732790857831596547515523593979861803187084910989428312522918414417263055355460715745539358014631136245887418412633787074173796862711588221766398229333338511838891484974940633857861775630560092874987828057333663969469797013996401149696897591265769095952887917296740109742927689053276850469671231961384715398038978492733178835452859452433234470997285516534065058887757272972533841547437247509415567206632827453524027585684464869520087576386907357207827931645864812453790560013100879070175244115566800303394525802384116508985235998027327908578315965475155235939798618031870849109894283125229184144172630553554607112725169432413343763989564437170644270643461665184965150423819594083121075825", 0)
+ q := new(Int)
+ r := new(Int)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ q.QuoRem(y, x, r)
+ }
+}
+
var bitLenTests = []struct {
in string
out int
@@ -572,6 +585,19 @@ var expTests = []struct {
{"0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0"},
{"0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0"},
{"0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0"},
+
+ {
+ "2",
+ "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+ "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", // odd
+ "0x6AADD3E3E424D5B713FCAA8D8945B1E055166132038C57BBD2D51C833F0C5EA2007A2324CE514F8E8C2F008A2F36F44005A4039CB55830986F734C93DAF0EB4BAB54A6A8C7081864F44346E9BC6F0A3EB9F2C0146A00C6A05187D0C101E1F2D038CDB70CB5E9E05A2D188AB6CBB46286624D4415E7D4DBFAD3BCC6009D915C406EED38F468B940F41E6BEDC0430DD78E6F19A7DA3A27498A4181E24D738B0072D8F6ADB8C9809A5B033A09785814FD9919F6EF9F83EEA519BEC593855C4C10CBEEC582D4AE0792158823B0275E6AEC35242740468FAF3D5C60FD1E376362B6322F78B7ED0CA1C5BBCD2B49734A56C0967A1D01A100932C837B91D592CE08ABFF",
+ },
+ {
+ "2",
+ "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+ "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF72", // even
+ "0x7858794B5897C29F4ED0B40913416AB6C48588484E6A45F2ED3E26C941D878E923575AAC434EE2750E6439A6976F9BB4D64CEDB2A53CE8D04DD48CADCDF8E46F22747C6B81C6CEA86C0D873FBF7CEF262BAAC43A522BD7F32F3CDAC52B9337C77B3DCFB3DB3EDD80476331E82F4B1DF8EFDC1220C92656DFC9197BDC1877804E28D928A2A284B8DED506CBA304435C9D0133C246C98A7D890D1DE60CBC53A024361DA83A9B8775019083D22AC6820ED7C3C68F8E801DD4EC779EE0A05C6EB682EF9840D285B838369BA7E148FA27691D524FAEAF7C6ECE2A4B99A294B9F2C241857B5B90CC8BFFCFCF18DFA7D676131D5CD3855A5A3E8EBFA0CDFADB4D198B4A",
+ },
}
func TestExp(t *testing.T) {
@@ -614,6 +640,26 @@ func TestExp(t *testing.T) {
}
}
+func BenchmarkExp(b *testing.B) {
+ x, _ := new(Int).SetString("11001289118363089646017359372117963499250546375269047542777928006103246876688756735760905680604646624353196869572752623285140408755420374049317646428185270079555372763503115646054602867593662923894140940837479507194934267532831694565516466765025434902348314525627418515646588160955862839022051353653052947073136084780742729727874803457643848197499548297570026926927502505634297079527299004267769780768565695459945235586892627059178884998772989397505061206395455591503771677500931269477503508150175717121828518985901959919560700853226255420793148986854391552859459511723547532575574664944815966793196961286234040892865", 0)
+ y, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF72", 0)
+ n, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 0)
+ out := new(Int)
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, y, n)
+ }
+}
+
+func BenchmarkExp2(b *testing.B) {
+ x, _ := new(Int).SetString("2", 0)
+ y, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF72", 0)
+ n, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 0)
+ out := new(Int)
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, y, n)
+ }
+}
+
func checkGcd(aBytes, bBytes []byte) bool {
x := new(Int)
y := new(Int)
@@ -715,85 +761,6 @@ func TestGcd(t *testing.T) {
}
}
-var primes = []string{
- "2",
- "3",
- "5",
- "7",
- "11",
-
- "13756265695458089029",
- "13496181268022124907",
- "10953742525620032441",
- "17908251027575790097",
-
- // https://golang.org/issue/638
- "18699199384836356663",
-
- "98920366548084643601728869055592650835572950932266967461790948584315647051443",
- "94560208308847015747498523884063394671606671904944666360068158221458669711639",
-
- // http://primes.utm.edu/lists/small/small3.html
- "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
- "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
- "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
- "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
-
- // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
- "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
- "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
- "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
- "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
- "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
-}
-
-var composites = []string{
- "0",
- "1",
- "21284175091214687912771199898307297748211672914763848041968395774954376176754",
- "6084766654921918907427900243509372380954290099172559290432744450051395395951",
- "84594350493221918389213352992032324280367711247940675652888030554255915464401",
- "82793403787388584738507275144194252681",
-}
-
-func TestProbablyPrime(t *testing.T) {
- nreps := 20
- if testing.Short() {
- nreps = 1
- }
- for i, s := range primes {
- p, _ := new(Int).SetString(s, 10)
- if !p.ProbablyPrime(nreps) {
- t.Errorf("#%d prime found to be non-prime (%s)", i, s)
- }
- }
-
- for i, s := range composites {
- c, _ := new(Int).SetString(s, 10)
- if c.ProbablyPrime(nreps) {
- t.Errorf("#%d composite found to be prime (%s)", i, s)
- }
- if testing.Short() {
- break
- }
- }
-
- // check that ProbablyPrime panics if n <= 0
- c := NewInt(11) // a prime
- for _, n := range []int{-1, 0, 1} {
- func() {
- defer func() {
- if n <= 0 && recover() == nil {
- t.Fatalf("expected panic from ProbablyPrime(%d)", n)
- }
- }()
- if !c.ProbablyPrime(n) {
- t.Fatalf("%v should be a prime", c)
- }
- }()
- }
-}
-
type intShiftTest struct {
in string
shift uint
@@ -1229,6 +1196,9 @@ func BenchmarkModSqrt224_3Mod4(b *testing.B) {
}
func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
+ if isRaceBuilder {
+ b.Skip("skipping on race builder")
+ }
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
@@ -1238,6 +1208,9 @@ func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
}
func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
+ if isRaceBuilder {
+ b.Skip("skipping on race builder")
+ }
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
@@ -1303,6 +1276,7 @@ var modInverseTests = []struct {
}{
{"1234567", "458948883992"},
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+ {"-10", "13"}, // issue #16984
}
func TestModInverse(t *testing.T) {
@@ -1480,3 +1454,44 @@ func TestIssue2607(t *testing.T) {
n := NewInt(10)
n.Rand(rand.New(rand.NewSource(9)), n)
}
+
+func TestSqrt(t *testing.T) {
+ root := 0
+ r := new(Int)
+ for i := 0; i < 10000; i++ {
+ if (root+1)*(root+1) <= i {
+ root++
+ }
+ n := NewInt(int64(i))
+ r.SetInt64(-2)
+ r.Sqrt(n)
+ if r.Cmp(NewInt(int64(root))) != 0 {
+ t.Errorf("Sqrt(%v) = %v, want %v", n, r, root)
+ }
+ }
+
+ for i := 0; i < 1000; i += 10 {
+ n, _ := new(Int).SetString("1"+strings.Repeat("0", i), 10)
+ r := new(Int).Sqrt(n)
+ root, _ := new(Int).SetString("1"+strings.Repeat("0", i/2), 10)
+ if r.Cmp(root) != 0 {
+ t.Errorf("Sqrt(1e%d) = %v, want 1e%d", i, r, i/2)
+ }
+ }
+
+ // Test aliasing.
+ r.SetInt64(100)
+ r.Sqrt(r)
+ if r.Int64() != 10 {
+ t.Errorf("Sqrt(100) = %v, want 10 (aliased output)", r.Int64())
+ }
+}
+
+func BenchmarkSqrt(b *testing.B) {
+ n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
+ b.ResetTimer()
+ t := new(Int)
+ for i := 0; i < b.N; i++ {
+ t.Sqrt(n)
+ }
+}
diff --git a/libgo/go/math/big/intconv.go b/libgo/go/math/big/intconv.go
index 56a75f87ae..91a62ce04e 100644
--- a/libgo/go/math/big/intconv.go
+++ b/libgo/go/math/big/intconv.go
@@ -52,16 +52,18 @@ func writeMultiple(s fmt.State, text string, count int) {
}
}
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
-// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+var _ fmt.Formatter = intOne // *Int must implement fmt.Formatter
+
+// Format implements fmt.Formatter. It accepts the formats
+// 'b' (binary), 'o' (octal), 'd' (decimal), 'x' (lowercase
+// hexadecimal), and 'X' (uppercase hexadecimal).
// Also supported are the full suite of package fmt's format
-// verbs for integral types, including '+', '-', and ' '
-// for sign control, '#' for leading zero in octal and for
-// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
-// respectively, specification of minimum digits precision,
-// output field width, space or zero padding, and left or
-// right justification.
+// flags for integral types, including '+' and ' ' for sign
+// control, '#' for leading zero in octal and for hexadecimal,
+// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
+// specification of minimum digits precision, output field
+// width, space or zero padding, and '-' for left or right
+// justification.
//
func (x *Int) Format(s fmt.State, ch rune) {
// determine base
@@ -223,6 +225,8 @@ func (r byteReader) UnreadByte() error {
return r.UnreadRune()
}
+var _ fmt.Scanner = intOne // *Int must implement fmt.Scanner
+
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
diff --git a/libgo/go/math/big/intmarsh.go b/libgo/go/math/big/intmarsh.go
index 4ff57b6464..ee1e4143ed 100644
--- a/libgo/go/math/big/intmarsh.go
+++ b/libgo/go/math/big/intmarsh.go
@@ -59,7 +59,7 @@ func (z *Int) UnmarshalText(text []byte) error {
return nil
}
-// The JSON marshallers are only here for API backward compatibility
+// The JSON marshalers are only here for API backward compatibility
// (programs that explicitly look for these two methods). JSON works
// fine with the TextMarshaler only.
@@ -70,5 +70,9 @@ func (x *Int) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
func (z *Int) UnmarshalJSON(text []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(text) == "null" {
+ return nil
+ }
return z.UnmarshalText(text)
}
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index 79cf6e07f7..9b1a626c4c 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -8,7 +8,10 @@
package big
-import "math/rand"
+import (
+ "math/rand"
+ "sync"
+)
// An unsigned integer x of the form
//
@@ -539,6 +542,26 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
return
}
+// getNat returns a *nat of len n. The contents may not be zero.
+// The pool holds *nat to avoid allocation when converting to interface{}.
+func getNat(n int) *nat {
+ var z *nat
+ if v := natPool.Get(); v != nil {
+ z = v.(*nat)
+ }
+ if z == nil {
+ z = new(nat)
+ }
+ *z = z.make(n)
+ return z
+}
+
+func putNat(x *nat) {
+ natPool.Put(x)
+}
+
+var natPool sync.Pool
+
// q = (uIn-r)/v, with 0 <= r < y
// Uses z as storage for q, and u as storage for r if possible.
// See Knuth, Volume 2, section 4.3.1, Algorithm D.
@@ -557,7 +580,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
}
q = z.make(m + 1)
- qhatv := make(nat, n+1)
+ qhatvp := getNat(n + 1)
+ qhatv := *qhatvp
if alias(u, uIn) || alias(u, v) {
u = nil // u is an alias for uIn or v - cannot reuse
}
@@ -565,35 +589,40 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
u.clear() // TODO(gri) no need to clear if we allocated a new u
// D1.
+ var v1p *nat
shift := nlz(v[n-1])
if shift > 0 {
// do not modify v, it may be used by another goroutine simultaneously
- v1 := make(nat, n)
+ v1p = getNat(n)
+ v1 := *v1p
shlVU(v1, v, shift)
v = v1
}
u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
// D2.
+ vn1 := v[n-1]
for j := m; j >= 0; j-- {
// D3.
qhat := Word(_M)
- if u[j+n] != v[n-1] {
+ if ujn := u[j+n]; ujn != vn1 {
var rhat Word
- qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+ qhat, rhat = divWW(ujn, u[j+n-1], vn1)
// x1 | x2 = q̂v_{n-2}
- x1, x2 := mulWW(qhat, v[n-2])
+ vn2 := v[n-2]
+ x1, x2 := mulWW(qhat, vn2)
// test if q̂v_{n-2} > br̂ + u_{j+n-2}
- for greaterThan(x1, x2, rhat, u[j+n-2]) {
+ ujn2 := u[j+n-2]
+ for greaterThan(x1, x2, rhat, ujn2) {
qhat--
prevRhat := rhat
- rhat += v[n-1]
+ rhat += vn1
// v[n-1] >= 0, so this tests for overflow.
if rhat < prevRhat {
break
}
- x1, x2 = mulWW(qhat, v[n-2])
+ x1, x2 = mulWW(qhat, vn2)
}
}
@@ -609,6 +638,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
q[j] = qhat
}
+ if v1p != nil {
+ putNat(v1p)
+ }
+ putNat(qhatvp)
q = q.norm()
shrVU(u, u, shift)
@@ -627,14 +660,14 @@ func (x nat) bitLen() int {
const deBruijn32 = 0x077CB531
-var deBruijn32Lookup = []byte{
+var deBruijn32Lookup = [...]byte{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
}
const deBruijn64 = 0x03f79d71b4ca8b09
-var deBruijn64Lookup = []byte{
+var deBruijn64Lookup = [...]byte{
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
@@ -647,7 +680,7 @@ func trailingZeroBits(x Word) uint {
// x & -x leaves only the right-most bit set in the word. Let k be the
// index of that bit. Since only a single bit is set, the value is two
// to the power of k. Multiplying by a power of two is equivalent to
- // left shifting, in this case by k bits. The de Bruijn constant is
+ // left shifting, in this case by k bits. The de Bruijn constant is
// such that all six bit, consecutive substrings are distinct.
// Therefore, if we have a left shifted version of this constant we can
// find by how many bits it was shifted by looking at which six bit
@@ -927,7 +960,7 @@ func (z nat) expNN(x, y, m nat) nat {
// (x^2...x^15) but then reduces the number of multiply-reduces by a
// third. Even for a 32-bit exponent, this reduces the number of
// operations. Uses Montgomery method for odd moduli.
- if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+ if x.cmp(natOne) > 0 && len(y) > 1 && len(m) > 0 {
if m[0]&1 == 1 {
return z.expNNMontgomery(x, y, m)
}
@@ -1018,7 +1051,7 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
for j := 0; j < _W; j += n {
if i != len(y)-1 || j != 0 {
// Unrolled loop for significant performance
- // gain. Use go test -bench=".*" in crypto/rsa
+ // gain. Use go test -bench=".*" in crypto/rsa
// to check performance before making changes.
zz = zz.mul(z, z)
zz, z = z, zz
@@ -1146,96 +1179,6 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
return zz.norm()
}
-// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼â¿.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (n nat) probablyPrime(reps int) bool {
- if len(n) == 0 {
- return false
- }
-
- if len(n) == 1 {
- if n[0] < 2 {
- return false
- }
-
- if n[0]%2 == 0 {
- return n[0] == 2
- }
-
- // We have to exclude these cases because we reject all
- // multiples of these numbers below.
- switch n[0] {
- case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
- return true
- }
- }
-
- if n[0]&1 == 0 {
- return false // n is even
- }
-
- const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
- const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
-
- var r Word
- switch _W {
- case 32:
- r = n.modW(primesProduct32)
- case 64:
- r = n.modW(primesProduct64 & _M)
- default:
- panic("Unknown word size")
- }
-
- if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
- r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
- return false
- }
-
- if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
- r%43 == 0 || r%47 == 0 || r%53 == 0) {
- return false
- }
-
- nm1 := nat(nil).sub(n, natOne)
- // determine q, k such that nm1 = q << k
- k := nm1.trailingZeroBits()
- q := nat(nil).shr(nm1, k)
-
- nm3 := nat(nil).sub(nm1, natTwo)
- rand := rand.New(rand.NewSource(int64(n[0])))
-
- var x, y, quotient nat
- nm3Len := nm3.bitLen()
-
-NextRandom:
- for i := 0; i < reps; i++ {
- x = x.random(rand, nm3, nm3Len)
- x = x.add(x, natTwo)
- y = y.expNN(x, q, n)
- if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
- continue
- }
- for j := uint(1); j < k; j++ {
- y = y.mul(y, y)
- quotient, y = quotient.div(y, y, n)
- if y.cmp(nm1) == 0 {
- continue NextRandom
- }
- if y.cmp(natOne) == 0 {
- return false
- }
- }
- return false
- }
-
- return true
-}
-
// bytes writes the value of z into buf using big-endian encoding.
// len(buf) must be >= len(z)*_S. The value of z is encoded in the
// slice buf[i:]. The number i of unused bytes at the beginning of
@@ -1280,3 +1223,37 @@ func (z nat) setBytes(buf []byte) nat {
return z.norm()
}
+
+// sqrt sets z = ⌊√x⌋
+func (z nat) sqrt(x nat) nat {
+ if x.cmp(natOne) <= 0 {
+ return z.set(x)
+ }
+ if alias(z, x) {
+ z = nil
+ }
+
+ // Start with value known to be too large and repeat "z = ⌊(z + ⌊x/z⌋)/2⌋" until it stops getting smaller.
+ // See Brent and Zimmermann, Modern Computer Arithmetic, Algorithm 1.13 (SqrtInt).
+ // https://members.loria.fr/PZimmermann/mca/pub226.html
+ // If x is one less than a perfect square, the sequence oscillates between the correct z and z+1;
+ // otherwise it converges to the correct z and stays there.
+ var z1, z2 nat
+ z1 = z
+ z1 = z1.setUint64(1)
+ z1 = z1.shl(z1, uint(x.bitLen()/2+1)) // must be ≥ √x
+ for n := 0; ; n++ {
+ z2, _ = z2.div(nil, x, z1)
+ z2 = z2.add(z2, z1)
+ z2 = z2.shr(z2, 1)
+ if z2.cmp(z1) >= 0 {
+ // z1 is answer.
+ // Figure out whether z1 or z2 is currently aliased to z by looking at loop count.
+ if n&1 == 0 {
+ return z1
+ }
+ return z.set(z1)
+ }
+ z1, z2 = z2, z1
+ }
+}
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index 563ccb3052..ebb2985654 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "fmt"
"runtime"
"strings"
"testing"
@@ -509,24 +510,20 @@ func TestExpNN(t *testing.T) {
}
}
-func ExpHelper(b *testing.B, x, y Word) {
- var z nat
- for i := 0; i < b.N; i++ {
- z.expWW(x, y)
+func BenchmarkExp3Power(b *testing.B) {
+ const x = 3
+ for _, y := range []Word{
+ 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000,
+ } {
+ b.Run(fmt.Sprintf("%#x", y), func(b *testing.B) {
+ var z nat
+ for i := 0; i < b.N; i++ {
+ z.expWW(x, y)
+ }
+ })
}
}
-func BenchmarkExp3Power0x10(b *testing.B) { ExpHelper(b, 3, 0x10) }
-func BenchmarkExp3Power0x40(b *testing.B) { ExpHelper(b, 3, 0x40) }
-func BenchmarkExp3Power0x100(b *testing.B) { ExpHelper(b, 3, 0x100) }
-func BenchmarkExp3Power0x400(b *testing.B) { ExpHelper(b, 3, 0x400) }
-func BenchmarkExp3Power0x1000(b *testing.B) { ExpHelper(b, 3, 0x1000) }
-func BenchmarkExp3Power0x4000(b *testing.B) { ExpHelper(b, 3, 0x4000) }
-func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
-func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
-func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
-func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
-
func fibo(n int) nat {
switch n {
case 0:
diff --git a/libgo/go/math/big/natconv.go b/libgo/go/math/big/natconv.go
index d2ce667fb6..44547842c1 100644
--- a/libgo/go/math/big/natconv.go
+++ b/libgo/go/math/big/natconv.go
@@ -302,7 +302,7 @@ func (x nat) itoa(neg bool, base int) []byte {
}
} else {
- bb, ndigits := maxPow(Word(b))
+ bb, ndigits := maxPow(b)
// construct table of successive squares of bb*leafSize to use in subdivisions
// result (table != nil) <=> (len(x) > leafSize > 0)
@@ -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
}
}
diff --git a/libgo/go/math/big/natconv_test.go b/libgo/go/math/big/natconv_test.go
index 028e5a858e..bdb60e68e0 100644
--- a/libgo/go/math/big/natconv_test.go
+++ b/libgo/go/math/big/natconv_test.go
@@ -6,6 +6,7 @@ package big
import (
"bytes"
+ "fmt"
"io"
"strings"
"testing"
@@ -273,102 +274,64 @@ 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} {
+ if isRaceBuilder && y > 1000 {
+ continue
+ }
+ 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} {
+ if isRaceBuilder && y > 1000 {
+ continue
+ }
+ 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
diff --git a/libgo/go/math/big/prime.go b/libgo/go/math/big/prime.go
new file mode 100644
index 0000000000..3e9690e55e
--- /dev/null
+++ b/libgo/go/math/big/prime.go
@@ -0,0 +1,320 @@
+// 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 big
+
+import "math/rand"
+
+// ProbablyPrime reports whether x is probably prime,
+// applying the Miller-Rabin test with n pseudorandomly chosen bases
+// as well as a Baillie-PSW test.
+//
+// If x is prime, ProbablyPrime returns true.
+// If x is chosen randomly and not prime, ProbablyPrime probably returns false.
+// The probability of returning true for a randomly chosen non-prime is at most ¼â¿.
+//
+// ProbablyPrime is 100% accurate for inputs less than 2â¶â´.
+// See Menezes et al., Handbook of Applied Cryptography, 1997, pp. 145-149,
+// and FIPS 186-4 Appendix F for further discussion of the error probabilities.
+//
+// ProbablyPrime is not suitable for judging primes that an adversary may
+// have crafted to fool the test.
+//
+// As of Go 1.8, ProbablyPrime(0) is allowed and applies only a Baillie-PSW test.
+// Before Go 1.8, ProbablyPrime applied only the Miller-Rabin tests, and ProbablyPrime(0) panicked.
+func (x *Int) ProbablyPrime(n int) bool {
+ // Note regarding the doc comment above:
+ // It would be more precise to say that the Baillie-PSW test uses the
+ // extra strong Lucas test as its Lucas test, but since no one knows
+ // how to tell any of the Lucas tests apart inside a Baillie-PSW test
+ // (they all work equally well empirically), that detail need not be
+ // documented or implicitly guaranteed.
+ // The comment does avoid saying "the" Baillie-PSW test
+ // because of this general ambiguity.
+
+ if n < 0 {
+ panic("negative n for ProbablyPrime")
+ }
+ if x.neg || len(x.abs) == 0 {
+ return false
+ }
+
+ // primeBitMask records the primes < 64.
+ const primeBitMask uint64 = 1<<2 | 1<<3 | 1<<5 | 1<<7 |
+ 1<<11 | 1<<13 | 1<<17 | 1<<19 | 1<<23 | 1<<29 | 1<<31 |
+ 1<<37 | 1<<41 | 1<<43 | 1<<47 | 1<<53 | 1<<59 | 1<<61
+
+ w := x.abs[0]
+ if len(x.abs) == 1 && w < 64 {
+ return primeBitMask&(1<<w) != 0
+ }
+
+ if w&1 == 0 {
+ return false // n is even
+ }
+
+ const primesA = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37
+ const primesB = 29 * 31 * 41 * 43 * 47 * 53
+
+ var rA, rB uint32
+ switch _W {
+ case 32:
+ rA = uint32(x.abs.modW(primesA))
+ rB = uint32(x.abs.modW(primesB))
+ case 64:
+ r := x.abs.modW((primesA * primesB) & _M)
+ rA = uint32(r % primesA)
+ rB = uint32(r % primesB)
+ default:
+ panic("math/big: invalid word size")
+ }
+
+ if rA%3 == 0 || rA%5 == 0 || rA%7 == 0 || rA%11 == 0 || rA%13 == 0 || rA%17 == 0 || rA%19 == 0 || rA%23 == 0 || rA%37 == 0 ||
+ rB%29 == 0 || rB%31 == 0 || rB%41 == 0 || rB%43 == 0 || rB%47 == 0 || rB%53 == 0 {
+ return false
+ }
+
+ return x.abs.probablyPrimeMillerRabin(n+1, true) && x.abs.probablyPrimeLucas()
+}
+
+// probablyPrimeMillerRabin reports whether n passes reps rounds of the
+// Miller-Rabin primality test, using pseudo-randomly chosen bases.
+// If force2 is true, one of the rounds is forced to use base 2.
+// See Handbook of Applied Cryptography, p. 139, Algorithm 4.24.
+// The number n is known to be non-zero.
+func (n nat) probablyPrimeMillerRabin(reps int, force2 bool) bool {
+ nm1 := nat(nil).sub(n, natOne)
+ // determine q, k such that nm1 = q << k
+ k := nm1.trailingZeroBits()
+ q := nat(nil).shr(nm1, k)
+
+ nm3 := nat(nil).sub(nm1, natTwo)
+ rand := rand.New(rand.NewSource(int64(n[0])))
+
+ var x, y, quotient nat
+ nm3Len := nm3.bitLen()
+
+NextRandom:
+ for i := 0; i < reps; i++ {
+ if i == reps-1 && force2 {
+ x = x.set(natTwo)
+ } else {
+ x = x.random(rand, nm3, nm3Len)
+ x = x.add(x, natTwo)
+ }
+ y = y.expNN(x, q, n)
+ if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+ continue
+ }
+ for j := uint(1); j < k; j++ {
+ y = y.mul(y, y)
+ quotient, y = quotient.div(y, y, n)
+ if y.cmp(nm1) == 0 {
+ continue NextRandom
+ }
+ if y.cmp(natOne) == 0 {
+ return false
+ }
+ }
+ return false
+ }
+
+ return true
+}
+
+// probablyPrimeLucas reports whether n passes the "almost extra strong" Lucas probable prime test,
+// using Baillie-OEIS parameter selection. This corresponds to "AESLPSP" on Jacobsen's tables (link below).
+// The combination of this test and a Miller-Rabin/Fermat test with base 2 gives a Baillie-PSW test.
+//
+// References:
+//
+// Baillie and Wagstaff, "Lucas Pseudoprimes", Mathematics of Computation 35(152),
+// October 1980, pp. 1391-1417, especially page 1401.
+// http://www.ams.org/journals/mcom/1980-35-152/S0025-5718-1980-0583518-6/S0025-5718-1980-0583518-6.pdf
+//
+// Grantham, "Frobenius Pseudoprimes", Mathematics of Computation 70(234),
+// March 2000, pp. 873-891.
+// http://www.ams.org/journals/mcom/2001-70-234/S0025-5718-00-01197-2/S0025-5718-00-01197-2.pdf
+//
+// Baillie, "Extra strong Lucas pseudoprimes", OEIS A217719, https://oeis.org/A217719.
+//
+// Jacobsen, "Pseudoprime Statistics, Tables, and Data", http://ntheory.org/pseudoprimes.html.
+//
+// Nicely, "The Baillie-PSW Primality Test", http://www.trnicely.net/misc/bpsw.html.
+// (Note that Nicely's definition of the "extra strong" test gives the wrong Jacobi condition,
+// as pointed out by Jacobsen.)
+//
+// Crandall and Pomerance, Prime Numbers: A Computational Perspective, 2nd ed.
+// Springer, 2005.
+func (n nat) probablyPrimeLucas() bool {
+ // Discard 0, 1.
+ if len(n) == 0 || n.cmp(natOne) == 0 {
+ return false
+ }
+ // Two is the only even prime.
+ // Already checked by caller, but here to allow testing in isolation.
+ if n[0]&1 == 0 {
+ return n.cmp(natTwo) == 0
+ }
+
+ // Baillie-OEIS "method C" for choosing D, P, Q,
+ // as in https://oeis.org/A217719/a217719.txt:
+ // try increasing P ≥ 3 such that D = P² - 4 (so Q = 1)
+ // until Jacobi(D, n) = -1.
+ // The search is expected to succeed for non-square n after just a few trials.
+ // After more than expected failures, check whether n is square
+ // (which would cause Jacobi(D, n) = 1 for all D not dividing n).
+ p := Word(3)
+ d := nat{1}
+ t1 := nat(nil) // temp
+ intD := &Int{abs: d}
+ intN := &Int{abs: n}
+ for ; ; p++ {
+ if p > 10000 {
+ // This is widely believed to be impossible.
+ // If we get a report, we'll want the exact number n.
+ panic("math/big: internal error: cannot find (D/n) = -1 for " + intN.String())
+ }
+ d[0] = p*p - 4
+ j := Jacobi(intD, intN)
+ if j == -1 {
+ break
+ }
+ if j == 0 {
+ // d = p²-4 = (p-2)(p+2).
+ // If (d/n) == 0 then d shares a prime factor with n.
+ // Since the loop proceeds in increasing p and starts with p-2==1,
+ // the shared prime factor must be p+2.
+ // If p+2 == n, then n is prime; otherwise p+2 is a proper factor of n.
+ return len(n) == 1 && n[0] == p+2
+ }
+ if p == 40 {
+ // We'll never find (d/n) = -1 if n is a square.
+ // If n is a non-square we expect to find a d in just a few attempts on average.
+ // After 40 attempts, take a moment to check if n is indeed a square.
+ t1 = t1.sqrt(n)
+ t1 = t1.mul(t1, t1)
+ if t1.cmp(n) == 0 {
+ return false
+ }
+ }
+ }
+
+ // Grantham definition of "extra strong Lucas pseudoprime", after Thm 2.3 on p. 876
+ // (D, P, Q above have become Δ, b, 1):
+ //
+ // Let U_n = U_n(b, 1), V_n = V_n(b, 1), and Δ = b²-4.
+ // An extra strong Lucas pseudoprime to base b is a composite n = 2^r s + Jacobi(Δ, n),
+ // where s is odd and gcd(n, 2*Δ) = 1, such that either (i) U_s ≡ 0 mod n and V_s ≡ ±2 mod n,
+ // or (ii) V_{2^t s} ≡ 0 mod n for some 0 ≤ t < r-1.
+ //
+ // We know gcd(n, Δ) = 1 or else we'd have found Jacobi(d, n) == 0 above.
+ // We know gcd(n, 2) = 1 because n is odd.
+ //
+ // Arrange s = (n - Jacobi(Δ, n)) / 2^r = (n+1) / 2^r.
+ s := nat(nil).add(n, natOne)
+ r := int(s.trailingZeroBits())
+ s = s.shr(s, uint(r))
+ nm2 := nat(nil).sub(n, natTwo) // n-2
+
+ // We apply the "almost extra strong" test, which checks the above conditions
+ // except for U_s ≡ 0 mod n, which allows us to avoid computing any U_k values.
+ // Jacobsen points out that maybe we should just do the full extra strong test:
+ // "It is also possible to recover U_n using Crandall and Pomerance equation 3.13:
+ // U_n = D^-1 (2V_{n+1} - PV_n) allowing us to run the full extra-strong test
+ // at the cost of a single modular inversion. This computation is easy and fast in GMP,
+ // so we can get the full extra-strong test at essentially the same performance as the
+ // almost extra strong test."
+
+ // Compute Lucas sequence V_s(b, 1), where:
+ //
+ // V(0) = 2
+ // V(1) = P
+ // V(k) = P V(k-1) - Q V(k-2).
+ //
+ // (Remember that due to method C above, P = b, Q = 1.)
+ //
+ // In general V(k) = α^k + β^k, where α and β are roots of x² - Px + Q.
+ // Crandall and Pomerance (p.147) observe that for 0 ≤ j ≤ k,
+ //
+ // V(j+k) = V(j)V(k) - V(k-j).
+ //
+ // So in particular, to quickly double the subscript:
+ //
+ // V(2k) = V(k)² - 2
+ // V(2k+1) = V(k) V(k+1) - P
+ //
+ // We can therefore start with k=0 and build up to k=s in logâ‚‚(s) steps.
+ natP := nat(nil).setWord(p)
+ vk := nat(nil).setWord(2)
+ vk1 := nat(nil).setWord(p)
+ t2 := nat(nil) // temp
+ for i := int(s.bitLen()); i >= 0; i-- {
+ if s.bit(uint(i)) != 0 {
+ // k' = 2k+1
+ // V(k') = V(2k+1) = V(k) V(k+1) - P.
+ t1 = t1.mul(vk, vk1)
+ t1 = t1.add(t1, n)
+ t1 = t1.sub(t1, natP)
+ t2, vk = t2.div(vk, t1, n)
+ // V(k'+1) = V(2k+2) = V(k+1)² - 2.
+ t1 = t1.mul(vk1, vk1)
+ t1 = t1.add(t1, nm2)
+ t2, vk1 = t2.div(vk1, t1, n)
+ } else {
+ // k' = 2k
+ // V(k'+1) = V(2k+1) = V(k) V(k+1) - P.
+ t1 = t1.mul(vk, vk1)
+ t1 = t1.add(t1, n)
+ t1 = t1.sub(t1, natP)
+ t2, vk1 = t2.div(vk1, t1, n)
+ // V(k') = V(2k) = V(k)² - 2
+ t1 = t1.mul(vk, vk)
+ t1 = t1.add(t1, nm2)
+ t2, vk = t2.div(vk, t1, n)
+ }
+ }
+
+ // Now k=s, so vk = V(s). Check V(s) ≡ ±2 (mod n).
+ if vk.cmp(natTwo) == 0 || vk.cmp(nm2) == 0 {
+ // Check U(s) ≡ 0.
+ // As suggested by Jacobsen, apply Crandall and Pomerance equation 3.13:
+ //
+ // U(k) = Dâ»Â¹ (2 V(k+1) - P V(k))
+ //
+ // Since we are checking for U(k) == 0 it suffices to check 2 V(k+1) == P V(k) mod n,
+ // or P V(k) - 2 V(k+1) == 0 mod n.
+ t1 := t1.mul(vk, natP)
+ t2 := t2.shl(vk1, 1)
+ if t1.cmp(t2) < 0 {
+ t1, t2 = t2, t1
+ }
+ t1 = t1.sub(t1, t2)
+ t3 := vk1 // steal vk1, no longer needed below
+ vk1 = nil
+ _ = vk1
+ t2, t3 = t2.div(t3, t1, n)
+ if len(t3) == 0 {
+ return true
+ }
+ }
+
+ // Check V(2^t s) ≡ 0 mod n for some 0 ≤ t < r-1.
+ for t := 0; t < r-1; t++ {
+ if len(vk) == 0 { // vk == 0
+ return true
+ }
+ // Optimization: V(k) = 2 is a fixed point for V(k') = V(k)² - 2,
+ // so if V(k) = 2, we can stop: we will never find a future V(k) == 0.
+ if len(vk) == 1 && vk[0] == 2 { // vk == 2
+ return false
+ }
+ // k' = 2k
+ // V(k') = V(2k) = V(k)² - 2
+ t1 = t1.mul(vk, vk)
+ t1 = t1.sub(t1, natTwo)
+ t2, vk = t2.div(vk, t1, n)
+ }
+ return false
+}
diff --git a/libgo/go/math/big/prime_test.go b/libgo/go/math/big/prime_test.go
new file mode 100644
index 0000000000..a2d3d18f8f
--- /dev/null
+++ b/libgo/go/math/big/prime_test.go
@@ -0,0 +1,214 @@
+// 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 big
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+var primes = []string{
+ "2",
+ "3",
+ "5",
+ "7",
+ "11",
+
+ "13756265695458089029",
+ "13496181268022124907",
+ "10953742525620032441",
+ "17908251027575790097",
+
+ // https://golang.org/issue/638
+ "18699199384836356663",
+
+ "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+ "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+ // http://primes.utm.edu/lists/small/small3.html
+ "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+ "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+ "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+ // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+ "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
+ "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
+ "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
+ "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
+ "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
+}
+
+var composites = []string{
+ "0",
+ "1",
+ "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+ "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+ "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+ "82793403787388584738507275144194252681",
+
+ // Arnault, "Rabin-Miller Primality Test: Composite Numbers Which Pass It",
+ // Mathematics of Computation, 64(209) (January 1995), pp. 335-361.
+ "1195068768795265792518361315725116351898245581", // strong pseudoprime to prime bases 2 through 29
+ // strong pseudoprime to all prime bases up to 200
+ `
+ 80383745745363949125707961434194210813883768828755814583748891752229
+ 74273765333652186502336163960045457915042023603208766569966760987284
+ 0439654082329287387918508691668573282677617710293896977394701670823
+ 0428687109997439976544144845341155872450633409279022275296229414984
+ 2306881685404326457534018329786111298960644845216191652872597534901`,
+
+ // Extra-strong Lucas pseudoprimes. https://oeis.org/A217719
+ "989",
+ "3239",
+ "5777",
+ "10877",
+ "27971",
+ "29681",
+ "30739",
+ "31631",
+ "39059",
+ "72389",
+ "73919",
+ "75077",
+ "100127",
+ "113573",
+ "125249",
+ "137549",
+ "137801",
+ "153931",
+ "155819",
+ "161027",
+ "162133",
+ "189419",
+ "218321",
+ "231703",
+ "249331",
+ "370229",
+ "429479",
+ "430127",
+ "459191",
+ "473891",
+ "480689",
+ "600059",
+ "621781",
+ "632249",
+ "635627",
+
+ "3673744903",
+ "3281593591",
+ "2385076987",
+ "2738053141",
+ "2009621503",
+ "1502682721",
+ "255866131",
+ "117987841",
+ "587861",
+
+ "6368689",
+ "8725753",
+ "80579735209",
+ "105919633",
+}
+
+func cutSpace(r rune) rune {
+ if unicode.IsSpace(r) {
+ return -1
+ }
+ return r
+}
+
+func TestProbablyPrime(t *testing.T) {
+ nreps := 20
+ if testing.Short() {
+ nreps = 3
+ }
+ for i, s := range primes {
+ p, _ := new(Int).SetString(s, 10)
+ if !p.ProbablyPrime(nreps) || !p.ProbablyPrime(1) || !p.ProbablyPrime(0) {
+ t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+ }
+ }
+
+ for i, s := range composites {
+ s = strings.Map(cutSpace, s)
+ c, _ := new(Int).SetString(s, 10)
+ if c.ProbablyPrime(nreps) || c.ProbablyPrime(1) || c.ProbablyPrime(0) {
+ t.Errorf("#%d composite found to be prime (%s)", i, s)
+ }
+ }
+
+ // check that ProbablyPrime panics if n <= 0
+ c := NewInt(11) // a prime
+ for _, n := range []int{-1, 0, 1} {
+ func() {
+ defer func() {
+ if n < 0 && recover() == nil {
+ t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+ }
+ }()
+ if !c.ProbablyPrime(n) {
+ t.Fatalf("%v should be a prime", c)
+ }
+ }()
+ }
+}
+
+func BenchmarkProbablyPrime(b *testing.B) {
+ p, _ := new(Int).SetString("203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", 10)
+ for _, n := range []int{0, 1, 5, 10, 20} {
+ b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.ProbablyPrime(n)
+ }
+ })
+ }
+
+ b.Run("Lucas", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.abs.probablyPrimeLucas()
+ }
+ })
+ b.Run("MillerRabinBase2", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.abs.probablyPrimeMillerRabin(1, true)
+ }
+ })
+}
+
+func TestMillerRabinPseudoprimes(t *testing.T) {
+ testPseudoprimes(t, "probablyPrimeMillerRabin",
+ func(n nat) bool { return n.probablyPrimeMillerRabin(1, true) && !n.probablyPrimeLucas() },
+ // https://oeis.org/A001262
+ []int{2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141, 52633, 65281, 74665, 80581, 85489, 88357, 90751})
+}
+
+func TestLucasPseudoprimes(t *testing.T) {
+ testPseudoprimes(t, "probablyPrimeLucas",
+ func(n nat) bool { return n.probablyPrimeLucas() && !n.probablyPrimeMillerRabin(1, true) },
+ // https://oeis.org/A217719
+ []int{989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077})
+}
+
+func testPseudoprimes(t *testing.T, name string, cond func(nat) bool, want []int) {
+ n := nat{1}
+ for i := 3; i < 100000; i += 2 {
+ n[0] = Word(i)
+ pseudo := cond(n)
+ if pseudo && (len(want) == 0 || i != want[0]) {
+ t.Errorf("%s(%v, base=2) = %v, want false", name, i)
+ } else if !pseudo && len(want) >= 1 && i == want[0] {
+ t.Errorf("%s(%v, base=2) = false, want true", name, i)
+ }
+ if len(want) > 0 && i == want[0] {
+ want = want[1:]
+ }
+ }
+ if len(want) > 0 {
+ t.Fatalf("forgot to test %v", want)
+ }
+}
diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go
index 2cd9ed0938..56ce33d882 100644
--- a/libgo/go/math/big/rat.go
+++ b/libgo/go/math/big/rat.go
@@ -63,7 +63,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
// quotToFloat32 returns the non-negative float32 value
// nearest to the quotient a/b, using round-to-even in
-// halfway cases. It does not mutate its arguments.
+// halfway cases. It does not mutate its arguments.
// Preconditions: b is non-zero; a and b have no common factors.
func quotToFloat32(a, b nat) (f float32, exact bool) {
const (
@@ -161,7 +161,7 @@ func quotToFloat32(a, b nat) (f float32, exact bool) {
// quotToFloat64 returns the non-negative float64 value
// nearest to the quotient a/b, using round-to-even in
-// halfway cases. It does not mutate its arguments.
+// halfway cases. It does not mutate its arguments.
// Preconditions: b is non-zero; a and b have no common factors.
func quotToFloat64(a, b nat) (f float64, exact bool) {
const (
diff --git a/libgo/go/math/big/rat_test.go b/libgo/go/math/big/rat_test.go
index 3a06fca3c3..afda68658f 100644
--- a/libgo/go/math/big/rat_test.go
+++ b/libgo/go/math/big/rat_test.go
@@ -382,9 +382,9 @@ func TestFloat32Distribution(t *testing.T) {
9,
11,
}
- var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
- if testing.Short() {
- winc, einc = 5, 15 // quick test (~60ms on x86-64)
+ var winc, einc = uint64(5), 15 // quick test (~60ms on x86-64)
+ if *long {
+ winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
}
for _, sign := range "+-" {
@@ -430,9 +430,9 @@ func TestFloat64Distribution(t *testing.T) {
9,
11,
}
- var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
- if testing.Short() {
- winc, einc = 10, 500 // quick test (~12ms on x86-64)
+ var winc, einc = uint64(10), 500 // quick test (~12ms on x86-64)
+ if *long {
+ winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
}
for _, sign := range "+-" {
diff --git a/libgo/go/math/big/ratconv.go b/libgo/go/math/big/ratconv.go
index 4566ff4e39..a6a401c857 100644
--- a/libgo/go/math/big/ratconv.go
+++ b/libgo/go/math/big/ratconv.go
@@ -15,9 +15,12 @@ import (
)
func ratTok(ch rune) bool {
- return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+ return strings.ContainsRune("+-/0123456789.eE", ch)
}
+var ratZero Rat
+var _ fmt.Scanner = &ratZero // *Rat must implement fmt.Scanner
+
// Scan is a support routine for fmt.Scanner. It accepts the formats
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
@@ -25,7 +28,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
if err != nil {
return err
}
- if strings.IndexRune("efgEFGv", ch) < 0 {
+ if !strings.ContainsRune("efgEFGv", ch) {
return errors.New("Rat.Scan: invalid verb")
}
if _, ok := z.SetString(string(tok)); !ok {
@@ -36,8 +39,9 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s can be given as a fraction "a/b" or as a floating-point number
-// optionally followed by an exponent. If the operation failed, the value of
-// z is undefined but the returned value is nil.
+// optionally followed by an exponent. The entire string (not just a prefix)
+// must be valid for success. If the operation failed, the value of z is un-
+// defined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
return nil, false
@@ -49,9 +53,13 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if _, ok := z.a.SetString(s[:sep], 0); !ok {
return nil, false
}
- s = s[sep+1:]
+ r := strings.NewReader(s[sep+1:])
var err error
- if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+ if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil {
+ return nil, false
+ }
+ // entire string must have been consumed
+ if _, err = r.ReadByte(); err != io.EOF {
return nil, false
}
if len(z.b.abs) == 0 {
@@ -88,6 +96,12 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
return nil, false
}
+ // special-case 0 (see also issue #16176)
+ if len(z.a.abs) == 0 {
+ return z, true
+ }
+ // len(z.a.abs) > 0
+
// correct exponent
if ecorr < 0 {
exp += int64(ecorr)
@@ -178,7 +192,7 @@ func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err err
}
break // i > 0
}
- digits = append(digits, byte(ch))
+ digits = append(digits, ch)
}
// i > 0 => we have at least one digit
diff --git a/libgo/go/math/big/ratconv_test.go b/libgo/go/math/big/ratconv_test.go
index da2fdab4ca..56ac8d7aa3 100644
--- a/libgo/go/math/big/ratconv_test.go
+++ b/libgo/go/math/big/ratconv_test.go
@@ -48,7 +48,12 @@ var setStringTests = []StringTest{
{"53/70893980658822810696", "53/70893980658822810696", true},
{"106/141787961317645621392", "53/70893980658822810696", true},
{"204211327800791583.81095", "4084226556015831676219/20000", true},
+ {"0e9999999999", "0", true}, // issue #16176
{in: "1/0"},
+ {in: "4/3/2"}, // issue 17001
+ {in: "4/3/"},
+ {in: "4/3."},
+ {in: "4/"},
}
// These are not supported by fmt.Fscanf.
@@ -58,6 +63,7 @@ var setStringTests2 = []StringTest{
{"-010.", "-10", true},
{"0x10/0x20", "1/2", true},
{"0b1000/3", "8/3", true},
+ {in: "4/3x"},
// TODO(gri) add more tests
}
@@ -137,8 +143,8 @@ func TestFloatString(t *testing.T) {
}
}
-// Test inputs to Rat.SetString. The prefix "long:" causes the test
-// to be skipped in --test.short mode. (The threshold is about 500us.)
+// Test inputs to Rat.SetString. The prefix "long:" causes the test
+// to be skipped except in -long mode. (The threshold is about 500us.)
var float64inputs = []string{
// Constants plundered from strconv/testfp.txt.
@@ -344,7 +350,7 @@ func isFinite(f float64) bool {
func TestFloat32SpecialCases(t *testing.T) {
for _, input := range float64inputs {
if strings.HasPrefix(input, "long:") {
- if testing.Short() {
+ if !*long {
continue
}
input = input[len("long:"):]
@@ -400,7 +406,7 @@ func TestFloat32SpecialCases(t *testing.T) {
func TestFloat64SpecialCases(t *testing.T) {
for _, input := range float64inputs {
if strings.HasPrefix(input, "long:") {
- if testing.Short() {
+ if !*long {
continue
}
input = input[len("long:"):]
diff --git a/libgo/go/math/cmplx/cmath_test.go b/libgo/go/math/cmplx/cmath_test.go
index 18d9be8194..7a5c485a31 100644
--- a/libgo/go/math/cmplx/cmath_test.go
+++ b/libgo/go/math/cmplx/cmath_test.go
@@ -9,6 +9,9 @@ import (
"testing"
)
+// The higher-precision values in vc26 were used to derive the
+// input arguments vc (see also comment below). For reference
+// only (do not delete).
var vc26 = []complex128{
(4.97901192488367350108546816 + 7.73887247457810456552351752i),
(7.73887247457810456552351752 - 0.27688005719200159404635997i),
@@ -21,6 +24,7 @@ var vc26 = []complex128{
(1.82530809168085506044576505 - 8.68592476857560136238589621i),
(-8.68592476857560136238589621 + 4.97901192488367350108546816i),
}
+
var vc = []complex128{
(4.9790119248836735e+00 + 7.7388724745781045e+00i),
(7.7388724745781045e+00 - 2.7688005719200159e-01i),
@@ -448,8 +452,7 @@ func tolerance(a, b, e float64) bool {
}
return d < e
}
-func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
-func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
func alike(a, b float64) bool {
switch {
case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b):
@@ -756,6 +759,14 @@ func TestTanh(t *testing.T) {
}
}
+// See issue 17577
+func TestInfiniteLoopIntanSeries(t *testing.T) {
+ want := Inf()
+ if got := Cot(0); got != want {
+ t.Errorf("Cot(0): got %g, want %g", got, want)
+ }
+}
+
func BenchmarkAbs(b *testing.B) {
for i := 0; i < b.N; i++ {
Abs(complex(2.5, 3.5))
diff --git a/libgo/go/math/cmplx/example_test.go b/libgo/go/math/cmplx/example_test.go
new file mode 100644
index 0000000000..be87cff5ef
--- /dev/null
+++ b/libgo/go/math/cmplx/example_test.go
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package cmplx_test
+
+import (
+ "fmt"
+ "math"
+ "math/cmplx"
+)
+
+func ExampleAbs() {
+ fmt.Printf("%.1f", cmplx.Abs(3+4i))
+ // Output: 5.0
+}
+
+// ExampleExp computes Euler's identity.
+func ExampleExp() {
+ fmt.Printf("%.1f", cmplx.Exp(1i*math.Pi)+1)
+ // Output: (0.0+0.0i)
+}
+
+func ExamplePolar() {
+ r, theta := cmplx.Polar(2i)
+ fmt.Printf("r: %.1f, θ: %.1f*π", r, theta/math.Pi)
+ // Output: r: 2.0, θ: 0.5*π
+}
diff --git a/libgo/go/math/cmplx/sqrt.go b/libgo/go/math/cmplx/sqrt.go
index 276be07ae9..72f81e907c 100644
--- a/libgo/go/math/cmplx/sqrt.go
+++ b/libgo/go/math/cmplx/sqrt.go
@@ -43,7 +43,7 @@ import "math"
// Cancelation error in r-x or r+x is avoided by using the
// identity 2 Re w Im w = y.
//
-// Note that -w is also a square root of z. The root chosen
+// Note that -w is also a square root of z. The root chosen
// is always in the right half plane and Im w has the same sign as y.
//
// ACCURACY:
diff --git a/libgo/go/math/cmplx/tan.go b/libgo/go/math/cmplx/tan.go
index 9485315d8d..2990552155 100644
--- a/libgo/go/math/cmplx/tan.go
+++ b/libgo/go/math/cmplx/tan.go
@@ -120,9 +120,9 @@ func tanSeries(z complex128) float64 {
rn := 0.0
d := 0.0
for {
- rn += 1
+ rn++
f *= rn
- rn += 1
+ rn++
f *= rn
x2 *= x
y2 *= y
@@ -130,16 +130,18 @@ func tanSeries(z complex128) float64 {
t /= f
d += t
- rn += 1
+ rn++
f *= rn
- rn += 1
+ rn++
f *= rn
x2 *= x
y2 *= y
t = y2 - x2
t /= f
d += t
- if math.Abs(t/d) <= MACHEP {
+ if !(math.Abs(t/d) > MACHEP) {
+ // Caution: Use ! and > instead of <= for correct behavior if t/d is NaN.
+ // See issue 17577.
break
}
}
diff --git a/libgo/go/math/erf.go b/libgo/go/math/erf.go
index 4cd80f80c3..8ddd5f9809 100644
--- a/libgo/go/math/erf.go
+++ b/libgo/go/math/erf.go
@@ -10,7 +10,7 @@ package math
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/s_erf.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/exp.go b/libgo/go/math/exp.go
index 51330c21dc..cbc955d01e 100644
--- a/libgo/go/math/exp.go
+++ b/libgo/go/math/exp.go
@@ -21,7 +21,7 @@ func Exp(x float64) float64 {
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go
index b4dcdc52a2..a0a62d10c9 100644
--- a/libgo/go/math/expm1.go
+++ b/libgo/go/math/expm1.go
@@ -6,7 +6,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -235,7 +235,7 @@ func expm1(x float64) float64 {
}
t := Float64frombits(uint64(0x3ff-k) << 52) // 2**-k
y := x - (e + t)
- y += 1
+ y++
y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
return y
}
diff --git a/libgo/go/math/export_s390x_test.go b/libgo/go/math/export_s390x_test.go
new file mode 100644
index 0000000000..2e7f584dc3
--- /dev/null
+++ b/libgo/go/math/export_s390x_test.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package math
+
+// Export internal functions and variable for testing.
+var Log10NoVec = log10
+var CosNoVec = cos
+var CoshNoVec = cosh
+var SinNoVec = sin
+var SinhNoVec = sinh
+var TanhNoVec = tanh
+var HasVX = hasVX
diff --git a/libgo/go/math/export_test.go b/libgo/go/math/export_test.go
index 02992d70e8..368308e1e5 100644
--- a/libgo/go/math/export_test.go
+++ b/libgo/go/math/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/math/floor_asm.go b/libgo/go/math/floor_asm.go
index 28e56a5d51..9a2487af3e 100644
--- a/libgo/go/math/floor_asm.go
+++ b/libgo/go/math/floor_asm.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 amd64p32
+// +build ignore
+// -build amd64 amd64p32
package math
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
index 164f54f332..cc9e869496 100644
--- a/libgo/go/math/gamma.go
+++ b/libgo/go/math/gamma.go
@@ -21,7 +21,7 @@ package math
//
// DESCRIPTION:
//
-// Returns gamma function of the argument. The result is
+// Returns gamma function of the argument. The result is
// correctly signed, and the sign (+1 or -1) is also
// returned in a global (extern) variable named signgam.
// This variable is also filled in by the logarithmic gamma
@@ -91,23 +91,31 @@ var _gamS = [...]float64{
}
// Gamma function computed by Stirling's formula.
-// The polynomial is valid for 33 <= x <= 172.
-func stirling(x float64) float64 {
+// The pair of results must be multiplied together to get the actual answer.
+// The multiplication is left to the caller so that, if careful, the caller can avoid
+// infinity for 172 <= x <= 180.
+// The polynomial is valid for 33 <= x <= 172; larger values are only used
+// in reciprocal and produce denormalized floats. The lower precision there
+// masks any imprecision in the polynomial.
+func stirling(x float64) (float64, float64) {
+ if x > 200 {
+ return Inf(1), 1
+ }
const (
SqrtTwoPi = 2.506628274631000502417
MaxStirling = 143.01608
)
w := 1 / x
w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
- y := Exp(x)
+ y1 := Exp(x)
+ y2 := 1.0
if x > MaxStirling { // avoid Pow() overflow
v := Pow(x, 0.5*x-0.25)
- y = v * (v / y)
+ y1, y2 = v, v/y1
} else {
- y = Pow(x, x-0.5) / y
+ y1 = Pow(x, x-0.5) / y1
}
- y = SqrtTwoPi * y * w
- return y
+ return y1, SqrtTwoPi * w * y2
}
// Gamma returns the Gamma function of x.
@@ -125,22 +133,26 @@ func Gamma(x float64) float64 {
switch {
case isNegInt(x) || IsInf(x, -1) || IsNaN(x):
return NaN()
+ case IsInf(x, 1):
+ return Inf(1)
case x == 0:
if Signbit(x) {
return Inf(-1)
}
return Inf(1)
- case x < -170.5674972726612 || x > 171.61447887182298:
- return Inf(1)
}
q := Abs(x)
p := Floor(q)
if q > 33 {
if x >= 0 {
- return stirling(x)
+ y1, y2 := stirling(x)
+ return y1 * y2
}
+ // Note: x is negative but (checked above) not a negative integer,
+ // so x must be small enough to be in range for conversion to int64.
+ // If |x| were >= 2â¶Â³ it would have to be an integer.
signgam := 1
- if ip := int(p); ip&1 == 0 {
+ if ip := int64(p); ip&1 == 0 {
signgam = -1
}
z := q - p
@@ -152,7 +164,14 @@ func Gamma(x float64) float64 {
if z == 0 {
return Inf(signgam)
}
- z = Pi / (Abs(z) * stirling(q))
+ sq1, sq2 := stirling(q)
+ absz := Abs(z)
+ d := absz * sq1 * sq2
+ if IsInf(d, 0) {
+ z = Pi / absz / sq1 / sq2
+ } else {
+ z = Pi / d
+ }
return float64(signgam) * z
}
diff --git a/libgo/go/math/j0.go b/libgo/go/math/j0.go
index de7738880e..fe26791175 100644
--- a/libgo/go/math/j0.go
+++ b/libgo/go/math/j0.go
@@ -10,7 +10,7 @@ package math
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/e_j0.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -305,20 +305,20 @@ var p0S2 = [5]float64{
}
func pzero(x float64) float64 {
- var p [6]float64
- var q [5]float64
+ var p *[6]float64
+ var q *[5]float64
if x >= 8 {
- p = p0R8
- q = p0S8
+ p = &p0R8
+ q = &p0S8
} else if x >= 4.5454 {
- p = p0R5
- q = p0S5
+ p = &p0R5
+ q = &p0S5
} else if x >= 2.8571 {
- p = p0R3
- q = p0S3
+ p = &p0R3
+ q = &p0S3
} else if x >= 2 {
- p = p0R2
- q = p0S2
+ p = &p0R2
+ q = &p0S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
@@ -408,19 +408,19 @@ var q0S2 = [6]float64{
}
func qzero(x float64) float64 {
- var p, q [6]float64
+ var p, q *[6]float64
if x >= 8 {
- p = q0R8
- q = q0S8
+ p = &q0R8
+ q = &q0S8
} else if x >= 4.5454 {
- p = q0R5
- q = q0S5
+ p = &q0R5
+ q = &q0S5
} else if x >= 2.8571 {
- p = q0R3
- q = q0S3
+ p = &q0R3
+ q = &q0S3
} else if x >= 2 {
- p = q0R2
- q = q0S2
+ p = &q0R2
+ q = &q0S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
diff --git a/libgo/go/math/j1.go b/libgo/go/math/j1.go
index c537a72eb2..f1adcb6f41 100644
--- a/libgo/go/math/j1.go
+++ b/libgo/go/math/j1.go
@@ -10,7 +10,7 @@ package math
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/e_j1.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -298,20 +298,20 @@ var p1S2 = [5]float64{
}
func pone(x float64) float64 {
- var p [6]float64
- var q [5]float64
+ var p *[6]float64
+ var q *[5]float64
if x >= 8 {
- p = p1R8
- q = p1S8
+ p = &p1R8
+ q = &p1S8
} else if x >= 4.5454 {
- p = p1R5
- q = p1S5
+ p = &p1R5
+ q = &p1S5
} else if x >= 2.8571 {
- p = p1R3
- q = p1S3
+ p = &p1R3
+ q = &p1S3
} else if x >= 2 {
- p = p1R2
- q = p1S2
+ p = &p1R2
+ q = &p1S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
@@ -401,19 +401,19 @@ var q1S2 = [6]float64{
}
func qone(x float64) float64 {
- var p, q [6]float64
+ var p, q *[6]float64
if x >= 8 {
- p = q1R8
- q = q1S8
+ p = &q1R8
+ q = &q1S8
} else if x >= 4.5454 {
- p = q1R5
- q = q1S5
+ p = &q1R5
+ q = &q1S5
} else if x >= 2.8571 {
- p = q1R3
- q = q1S3
+ p = &q1R3
+ q = &q1S3
} else if x >= 2 {
- p = q1R2
- q = q1S2
+ p = &q1R2
+ q = &q1S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
diff --git a/libgo/go/math/jn.go b/libgo/go/math/jn.go
index ffb8a00f50..342278257a 100644
--- a/libgo/go/math/jn.go
+++ b/libgo/go/math/jn.go
@@ -10,7 +10,7 @@ package math
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/e_jn.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -174,7 +174,7 @@ func Jn(n int, x float64) float64 {
q1 := w*z - 1
k := 1
for q1 < 1e9 {
- k += 1
+ k++
z += h
q0, q1 = q1, z*q1-q0
}
diff --git a/libgo/go/math/lgamma.go b/libgo/go/math/lgamma.go
index 6a02c412d9..19ac3ffafc 100644
--- a/libgo/go/math/lgamma.go
+++ b/libgo/go/math/lgamma.go
@@ -10,7 +10,7 @@ package math
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/log.go b/libgo/go/math/log.go
index 60b57552d8..cf242e86fd 100644
--- a/libgo/go/math/log.go
+++ b/libgo/go/math/log.go
@@ -10,7 +10,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
-// and came with this notice. The go code is a simpler
+// and came with this notice. The go code is a simpler
// version of the original C.
//
// ====================================================
diff --git a/libgo/go/math/log1p.go b/libgo/go/math/log1p.go
index c8daaaa1c9..ef1c7defeb 100644
--- a/libgo/go/math/log1p.go
+++ b/libgo/go/math/log1p.go
@@ -6,7 +6,7 @@ package math
// The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
-// and came with this notice. The go code is a simplified
+// and came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -173,7 +173,7 @@ func log1p(x float64) float64 {
if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
} else {
- k += 1
+ k++
u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
iu = (0x0010000000000000 - iu) >> 2
}
@@ -185,10 +185,9 @@ func log1p(x float64) float64 {
if f == 0 {
if k == 0 {
return 0
- } else {
- c += float64(k) * Ln2Lo
- return float64(k)*Ln2Hi + c
}
+ c += float64(k) * Ln2Lo
+ return float64(k)*Ln2Hi + c
}
R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
if k == 0 {
diff --git a/libgo/go/math/modf.go b/libgo/go/math/modf.go
index 5d2f489b70..b59d4b7fd5 100644
--- a/libgo/go/math/modf.go
+++ b/libgo/go/math/modf.go
@@ -5,7 +5,7 @@
package math
// Modf returns integer and fractional floating-point numbers
-// that sum to f. Both values have the same sign as f.
+// that sum to f. Both values have the same sign as f.
//
// Special cases are:
// Modf(±Inf) = ±Inf, NaN
diff --git a/libgo/go/math/rand/gen_cooked.go b/libgo/go/math/rand/gen_cooked.go
new file mode 100644
index 0000000000..567b7a8d14
--- /dev/null
+++ b/libgo/go/math/rand/gen_cooked.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program computes the value of rng_cooked in rng.go,
+// which is used for seeding all instances of rand.Source.
+// a 64bit and a 63bit version of the array is printed to
+// the standard output.
+
+package main
+
+import "fmt"
+
+const (
+ length = 607
+ tap = 273
+ mask = (1 << 63) - 1
+ a = 48271
+ m = (1 << 31) - 1
+ q = 44488
+ r = 3399
+)
+
+var (
+ rngVec [length]int64
+ rngTap, rngFeed int
+)
+
+func seedrand(x int32) int32 {
+ hi := x / q
+ lo := x % q
+ x = a*lo - r*hi
+ if x < 0 {
+ x += m
+ }
+ return x
+}
+
+func srand(seed int32) {
+ rngTap = 0
+ rngFeed = length - tap
+ seed %= m
+ if seed < 0 {
+ seed += m
+ } else if seed == 0 {
+ seed = 89482311
+ }
+ x := seed
+ for i := -20; i < length; i++ {
+ x = seedrand(x)
+ if i >= 0 {
+ var u int64
+ u = int64(x) << 20
+ x = seedrand(x)
+ u ^= int64(x) << 10
+ x = seedrand(x)
+ u ^= int64(x)
+ rngVec[i] = u
+ }
+ }
+}
+
+func vrand() int64 {
+ rngTap--
+ if rngTap < 0 {
+ rngTap += length
+ }
+ rngFeed--
+ if rngFeed < 0 {
+ rngFeed += length
+ }
+ x := (rngVec[rngFeed] + rngVec[rngTap])
+ rngVec[rngFeed] = x
+ return x
+}
+
+func main() {
+ srand(1)
+ for i := uint64(0); i < 7.8e12; i++ {
+ vrand()
+ }
+ fmt.Printf("rngVec after 7.8e12 calls to vrand:\n%#v\n", rngVec)
+ for i := range rngVec {
+ rngVec[i] &= mask
+ }
+ fmt.Printf("lower 63bit of rngVec after 7.8e12 calls to vrand:\n%#v\n", rngVec)
+}
diff --git a/libgo/go/math/rand/race_test.go b/libgo/go/math/rand/race_test.go
new file mode 100644
index 0000000000..186c7169d8
--- /dev/null
+++ b/libgo/go/math/rand/race_test.go
@@ -0,0 +1,48 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "sync"
+ "testing"
+)
+
+// TestConcurrent exercises the rand API concurrently, triggering situations
+// where the race detector is likely to detect issues.
+func TestConcurrent(t *testing.T) {
+ const (
+ numRoutines = 10
+ numCycles = 10
+ )
+ var wg sync.WaitGroup
+ defer wg.Wait()
+ wg.Add(numRoutines)
+ for i := 0; i < numRoutines; i++ {
+ go func(i int) {
+ defer wg.Done()
+ buf := make([]byte, 997)
+ for j := 0; j < numCycles; j++ {
+ var seed int64
+ seed += int64(ExpFloat64())
+ seed += int64(Float32())
+ seed += int64(Float64())
+ seed += int64(Intn(Int()))
+ seed += int64(Int31n(Int31()))
+ seed += int64(Int63n(Int63()))
+ seed += int64(NormFloat64())
+ seed += int64(Uint32())
+ seed += int64(Uint64())
+ for _, p := range Perm(10) {
+ seed += int64(p)
+ }
+ Read(buf)
+ for _, b := range buf {
+ seed += int64(b)
+ }
+ Seed(int64(i*j) * seed)
+ }
+ }(i)
+ }
+}
diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go
index d693bfb52f..9fe1cbd61e 100644
--- a/libgo/go/math/rand/rand.go
+++ b/libgo/go/math/rand/rand.go
@@ -23,7 +23,20 @@ type Source interface {
Seed(seed int64)
}
+// A Source64 is a Source that can also generate
+// uniformly-distributed pseudo-random uint64 values in
+// the range [0, 1<<64) directly.
+// If a Rand r's underlying Source s implements Source64,
+// then r.Uint64 returns the result of one call to s.Uint64
+// instead of making two calls to s.Int63.
+type Source64 interface {
+ Source
+ Uint64() uint64
+}
+
// NewSource returns a new pseudo-random Source seeded with the given value.
+// Unlike the default Source used by top-level functions, this source is not
+// safe for concurrent use by multiple goroutines.
func NewSource(seed int64) Source {
var rng rngSource
rng.Seed(seed)
@@ -33,14 +46,36 @@ func NewSource(seed int64) Source {
// A Rand is a source of random numbers.
type Rand struct {
src Source
+ s64 Source64 // non-nil if src is source64
+
+ // readVal contains remainder of 63-bit integer used for bytes
+ // generation during most recent Read call.
+ // It is saved so next Read call can start where the previous
+ // one finished.
+ readVal int64
+ // readPos indicates the number of low-order bytes of readVal
+ // that are still valid.
+ readPos int8
}
// New returns a new Rand that uses random values from src
// to generate other random values.
-func New(src Source) *Rand { return &Rand{src} }
+func New(src Source) *Rand {
+ s64, _ := src.(Source64)
+ return &Rand{src: src, s64: s64}
+}
// Seed uses the provided seed value to initialize the generator to a deterministic state.
-func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
+// Seed should not be called concurrently with any other Rand method.
+func (r *Rand) Seed(seed int64) {
+ if lk, ok := r.src.(*lockedSource); ok {
+ lk.seedPos(seed, &r.readPos)
+ return
+ }
+
+ r.src.Seed(seed)
+ r.readPos = 0
+}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
func (r *Rand) Int63() int64 { return r.src.Int63() }
@@ -48,6 +83,14 @@ func (r *Rand) Int63() int64 { return r.src.Int63() }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
+// Uint64 returns a pseudo-random 64-bit value as a uint64.
+func (r *Rand) Uint64() uint64 {
+ if r.s64 != nil {
+ return r.s64.Uint64()
+ }
+ return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
+}
+
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
@@ -160,26 +203,42 @@ func (r *Rand) Perm(n int) []int {
// Read generates len(p) random bytes and writes them into p. It
// always returns len(p) and a nil error.
+// Read should not be called concurrently with any other Rand method.
func (r *Rand) Read(p []byte) (n int, err error) {
- for i := 0; i < len(p); i += 7 {
- val := r.src.Int63()
- for j := 0; i+j < len(p) && j < 7; j++ {
- p[i+j] = byte(val)
- val >>= 8
+ if lk, ok := r.src.(*lockedSource); ok {
+ return lk.read(p, &r.readVal, &r.readPos)
+ }
+ return read(p, r.Int63, &r.readVal, &r.readPos)
+}
+
+func read(p []byte, int63 func() int64, readVal *int64, readPos *int8) (n int, err error) {
+ pos := *readPos
+ val := *readVal
+ for n = 0; n < len(p); n++ {
+ if pos == 0 {
+ val = int63()
+ pos = 7
}
+ p[n] = byte(val)
+ val >>= 8
+ pos--
}
- return len(p), nil
+ *readPos = pos
+ *readVal = val
+ return
}
/*
* Top-level convenience functions
*/
-var globalRand = New(&lockedSource{src: NewSource(1)})
+var globalRand = New(&lockedSource{src: NewSource(1).(Source64)})
// 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). Seed values that have the same remainder when
+// divided by 2^31-1 generate the same pseudo-random sequence.
+// Seed, unlike the Rand.Seed method, is safe for concurrent use.
func Seed(seed int64) { globalRand.Seed(seed) }
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
@@ -190,6 +249,10 @@ func Int63() int64 { return globalRand.Int63() }
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }
+// Uint64 returns a pseudo-random 64-bit value as a uint64
+// from the default Source.
+func Uint64() uint64 { return globalRand.Uint64() }
+
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand.Int31() }
@@ -226,6 +289,7 @@ func Perm(n int) []int { return globalRand.Perm(n) }
// Read generates len(p) random bytes from the default Source and
// writes them into p. It always returns len(p) and a nil error.
+// Read, unlike the Rand.Read method, is safe for concurrent use.
func Read(p []byte) (n int, err error) { return globalRand.Read(p) }
// NormFloat64 returns a normally distributed float64 in the range
@@ -251,7 +315,7 @@ func ExpFloat64() float64 { return globalRand.ExpFloat64() }
type lockedSource struct {
lk sync.Mutex
- src Source
+ src Source64
}
func (r *lockedSource) Int63() (n int64) {
@@ -261,8 +325,31 @@ func (r *lockedSource) Int63() (n int64) {
return
}
+func (r *lockedSource) Uint64() (n uint64) {
+ r.lk.Lock()
+ n = r.src.Uint64()
+ r.lk.Unlock()
+ return
+}
+
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
r.lk.Unlock()
}
+
+// seedPos implements Seed for a lockedSource without a race condiiton.
+func (r *lockedSource) seedPos(seed int64, readPos *int8) {
+ r.lk.Lock()
+ r.src.Seed(seed)
+ *readPos = 0
+ r.lk.Unlock()
+}
+
+// read implements Read for a lockedSource without a race condition.
+func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
+ r.lk.Lock()
+ n, err = read(p, r.src.Int63, readVal, readPos)
+ r.lk.Unlock()
+ return
+}
diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go
index 8d68335fdd..bf509e06be 100644
--- a/libgo/go/math/rand/rand_test.go
+++ b/libgo/go/math/rand/rand_test.go
@@ -5,13 +5,16 @@
package rand
import (
+ "bytes"
"errors"
"fmt"
"internal/testenv"
+ "io"
"math"
"os"
"runtime"
"testing"
+ "testing/iotest"
)
const (
@@ -325,13 +328,26 @@ func TestExpTables(t *testing.T) {
}
}
+func hasSlowFloatingPoint() bool {
+ switch runtime.GOARCH {
+ case "arm":
+ return os.Getenv("GOARM") == "5"
+ case "mips", "mipsle", "mips64", "mips64le":
+ // Be conservative and assume that all mips boards
+ // have emulated floating point.
+ // TODO: detect what it actually has.
+ return true
+ }
+ return false
+}
+
func TestFloat32(t *testing.T) {
// For issue 6721, the problem came after 7533753 calls, so check 10e6.
num := int(10e6)
// But do the full amount only on builders (not locally).
// But ARM5 floating point emulation is slow (Issue 10749), so
// do less for that builder:
- if testing.Short() && (testenv.Builder() == "" || runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5") {
+ if testing.Short() && (testenv.Builder() == "" || hasSlowFloatingPoint()) {
num /= 100 // 1.72 seconds instead of 172 seconds
}
@@ -373,7 +389,7 @@ func testReadUniformity(t *testing.T, n int, seed int64) {
checkSampleDistribution(t, samples, expected)
}
-func TestRead(t *testing.T) {
+func TestReadUniformity(t *testing.T) {
testBufferSizes := []int{
2, 4, 7, 64, 1024, 1 << 16, 1 << 20,
}
@@ -394,7 +410,42 @@ func TestReadEmpty(t *testing.T) {
if n != 0 {
t.Errorf("Read into empty buffer returned unexpected n of %d", n)
}
+}
+
+func TestReadByOneByte(t *testing.T) {
+ r := New(NewSource(1))
+ b1 := make([]byte, 100)
+ _, err := io.ReadFull(iotest.OneByteReader(r), b1)
+ if err != nil {
+ t.Errorf("read by one byte: %v", err)
+ }
+ r = New(NewSource(1))
+ b2 := make([]byte, 100)
+ _, err = r.Read(b2)
+ if err != nil {
+ t.Errorf("read: %v", err)
+ }
+ if !bytes.Equal(b1, b2) {
+ t.Errorf("read by one byte vs single read:\n%x\n%x", b1, b2)
+ }
+}
+func TestReadSeedReset(t *testing.T) {
+ r := New(NewSource(42))
+ b1 := make([]byte, 128)
+ _, err := r.Read(b1)
+ if err != nil {
+ t.Errorf("read: %v", err)
+ }
+ r.Seed(42)
+ b2 := make([]byte, 128)
+ _, err = r.Read(b2)
+ if err != nil {
+ t.Errorf("read: %v", err)
+ }
+ if !bytes.Equal(b1, b2) {
+ t.Errorf("mismatch after re-seed:\n%x\n%x", b1, b2)
+ }
}
// Benchmarks
diff --git a/libgo/go/math/rand/regress_test.go b/libgo/go/math/rand/regress_test.go
index 9ae5357447..e31e6c5af0 100644
--- a/libgo/go/math/rand/regress_test.go
+++ b/libgo/go/math/rand/regress_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -342,25 +342,25 @@ var regressGolden = []interface{}{
[]int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9)
[]int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
[]byte{0x1}, // Read([0])
- []byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b}, // Read([0 0 0 0 0 0 0])
- []byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62}, // Read([0 0 0 0 0 0 0 0])
- []byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48}, // Read([0 0 0 0 0 0 0 0 0])
- []byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0])
- []byte{0x51}, // Read([0])
- []byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0])
- []byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44}, // Read([0 0 0 0 0 0 0 0])
- []byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52}, // Read([0 0 0 0 0 0 0 0 0])
- []byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0])
- []byte{0xc7}, // Read([0])
- []byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c}, // Read([0 0 0 0 0 0 0])
- []byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc}, // Read([0 0 0 0 0 0 0 0])
- []byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4}, // Read([0 0 0 0 0 0 0 0 0])
- []byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0])
- []byte{0xaa}, // Read([0])
- []byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6}, // Read([0 0 0 0 0 0 0])
- []byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f}, // Read([0 0 0 0 0 0 0 0])
- []byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce}, // Read([0 0 0 0 0 0 0 0 0])
- []byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0])
+ []byte{0x94, 0xfd, 0xc2, 0xfa, 0x2f, 0xfc, 0xc0}, // Read([0 0 0 0 0 0 0])
+ []byte{0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b, 0x73, 0xc8}, // Read([0 0 0 0 0 0 0 0])
+ []byte{0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62, 0xa5, 0xee, 0xe8}, // Read([0 0 0 0 0 0 0 0 0])
+ []byte{0x2a, 0xbd, 0xf4, 0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd}, // Read([0 0 0 0 0 0 0 0 0 0])
+ []byte{0xaf}, // Read([0])
+ []byte{0x48, 0xa7, 0x9e, 0xe0, 0xb1, 0xd, 0x39}, // Read([0 0 0 0 0 0 0])
+ []byte{0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89}, // Read([0 0 0 0 0 0 0 0])
+ []byte{0x2e, 0xe2, 0x85, 0xec, 0xe1, 0x51, 0x14, 0x55, 0x78}, // Read([0 0 0 0 0 0 0 0 0])
+ []byte{0x8, 0x75, 0xd6, 0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0 0 0 0])
+ []byte{0xf8}, // Read([0])
+ []byte{0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44}, // Read([0 0 0 0 0 0 0])
+ []byte{0xc6, 0xb1, 0xf8, 0x3b, 0x8e, 0x88, 0x3b, 0xbf}, // Read([0 0 0 0 0 0 0 0])
+ []byte{0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52, 0xc7, 0x42}, // Read([0 0 0 0 0 0 0 0 0])
+ []byte{0x9c, 0x32, 0xf3, 0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6}, // Read([0 0 0 0 0 0 0 0 0 0])
+ []byte{0x59}, // Read([0])
+ []byte{0xc1, 0x8f, 0xd, 0xce, 0xcc, 0x77, 0xc7}, // Read([0 0 0 0 0 0 0])
+ []byte{0x5e, 0x7a, 0x81, 0xbf, 0xde, 0x27, 0x5f, 0x67}, // Read([0 0 0 0 0 0 0 0])
+ []byte{0xcf, 0xe2, 0x42, 0xcf, 0x3c, 0xc3, 0x54, 0xf3, 0xed}, // Read([0 0 0 0 0 0 0 0 0])
+ []byte{0xe2, 0xd6, 0xbe, 0xcc, 0x4e, 0xa3, 0xae, 0x5e, 0x88, 0x52}, // Read([0 0 0 0 0 0 0 0 0 0])
uint32(4059586549), // Uint32()
uint32(1052117029), // Uint32()
uint32(2817310706), // Uint32()
@@ -381,4 +381,24 @@ var regressGolden = []interface{}{
uint32(75079301), // Uint32()
uint32(3380456901), // Uint32()
uint32(3433369789), // Uint32()
+ uint64(8717895732742165505), // Uint64()
+ uint64(2259404117704393152), // Uint64()
+ uint64(6050128673802995827), // Uint64()
+ uint64(9724605487393973602), // Uint64()
+ uint64(12613765599614152010), // Uint64()
+ uint64(11893357769247901871), // Uint64()
+ uint64(1774932891286980153), // Uint64()
+ uint64(15267744271532198264), // Uint64()
+ uint64(17498302081433670737), // Uint64()
+ uint64(1543572285742637646), // Uint64()
+ uint64(11885104867954719224), // Uint64()
+ uint64(17548432336275752516), // Uint64()
+ uint64(7837839688282259259), // Uint64()
+ uint64(2518412263346885298), // Uint64()
+ uint64(5617773211005988520), // Uint64()
+ uint64(11562935753659892057), // Uint64()
+ uint64(16368296284793757383), // Uint64()
+ uint64(161231572858529631), // Uint64()
+ uint64(16482847956365694147), // Uint64()
+ uint64(16596477517051940556), // Uint64()
}
diff --git a/libgo/go/math/rand/rng.go b/libgo/go/math/rand/rng.go
index 947c49f0f2..f922417cdc 100644
--- a/libgo/go/math/rand/rng.go
+++ b/libgo/go/math/rand/rng.go
@@ -23,161 +23,159 @@ const (
)
var (
- // cooked random numbers
- // the state of the rng
- // after 780e10 iterations
+ // Used for seeding. See gen_cooked.go for details.
rng_cooked [_LEN]int64 = [...]int64{
- 5041579894721019882, 4646389086726545243, 1395769623340756751, 5333664234075297259,
- 2875692520355975054, 9033628115061424579, 7143218595135194537, 4812947590706362721,
- 7937252194349799378, 5307299880338848416, 8209348851763925077, 2115741599318814044,
- 4593015457530856296, 8140875735541888011, 3319429241265089026, 8619815648190321034,
- 1727074043483619500, 113108499721038619, 4569519971459345583, 5062833859075314731,
- 2387618771259064424, 2716131344356686112, 6559392774825876886, 7650093201692370310,
- 7684323884043752161, 257867835996031390, 6593456519409015164, 271327514973697897,
- 2789386447340118284, 1065192797246149621, 3344507881999356393, 4459797941780066633,
- 7465081662728599889, 1014950805555097187, 4449440729345990775, 3481109366438502643,
+ -4181792142133755926, -4576982950128230565, 1395769623340756751, 5333664234075297259,
+ -6347679516498800754, 9033628115061424579, 7143218595135194537, 4812947590706362721,
+ 7937252194349799378, 5307299880338848416, 8209348851763925077, -7107630437535961764,
+ 4593015457530856296, 8140875735541888011, -5903942795589686782, -603556388664454774,
+ -7496297993371156308, 113108499721038619, 4569519971459345583, -4160538177779461077,
+ -6835753265595711384, -6507240692498089696, 6559392774825876886, 7650093201692370310,
+ 7684323884043752161, -8965504200858744418, -2629915517445760644, 271327514973697897,
+ -6433985589514657524, 1065192797246149621, 3344507881999356393, -4763574095074709175,
+ 7465081662728599889, 1014950805555097187, -4773931307508785033, -5742262670416273165,
2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
- 4523597184512354423, 10530508058128498, 8633833783282346118, 2625309929628791628,
- 8660405965245884302, 10162832508971942, 6540714680961817391, 7031802312784620857,
- 6240911277345944669, 831864355460801054, 8004434137542152891, 2116287251661052151,
+ -4699774852342421385, 10530508058128498, -589538253572429690, -6598062107225984180,
+ 8660405965245884302, 10162832508971942, -2682657355892958417, 7031802312784620857,
+ 6240911277345944669, 831864355460801054, -1218937899312622917, 2116287251661052151,
2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
- 457351505131524928, 342195045928179354, 2847771682816600509, 2068020115986376518,
- 4368649989588021065, 887231587095185257, 5563591506886576496, 6816225200251950296,
- 5616972787034086048, 8471809303394836566, 1686575021641186857, 4045484338074262002,
- 4244156215201778923, 7848217333783577387, 5632136521049761902, 833283142057835272,
- 9029726508369077193, 3243583134664087292, 4316371101804477087, 8937849979965997980,
- 6446940406810434101, 1679342092332374735, 6050638460742422078, 6993520719509581582,
- 7640877852514293609, 5881353426285907985, 812786550756860885, 4541845584483343330,
- 2725470216277009086, 4980675660146853729, 5210769080603236061, 8894283318990530821,
- 6326442804750084282, 1495812843684243920, 7069751578799128019, 7370257291860230865,
- 6756929275356942261, 4706794511633873654, 7824520467827898663, 8549875090542453214,
- 33650829478596156, 1328918435751322643, 7297902601803624459, 1011190183918857495,
- 2238025036817854944, 5147159997473910359, 896512091560522982, 2659470849286379941,
- 6097729358393448602, 1731725986304753684, 4106255841983812711, 8327155210721535508,
- 8477511620686074402, 5803876044675762232, 8435417780860221662, 5988852856651071244,
- 4715837297103951910, 7566171971264485114, 505808562678895611, 5070098180695063370,
- 842110666775871513, 572156825025677802, 1791881013492340891, 3393267094866038768,
- 3778721850472236509, 2352769483186201278, 1292459583847367458, 8897907043675088419,
- 5781809037144163536, 2733958794029492513, 5092019688680754699, 8996124554772526841,
- 4234737173186232084, 5027558287275472836, 4635198586344772304, 8687338893267139351,
- 5907508150730407386, 784756255473944452, 972392927514829904, 5422057694808175112,
- 5158420642969283891, 9048531678558643225, 2407211146698877100, 7583282216521099569,
- 3940796514530962282, 3341174631045206375, 3095313889586102949, 7405321895688238710,
- 5832080132947175283, 7890064875145919662, 8184139210799583195, 1149859861409226130,
- 1464597243840211302, 4641648007187991873, 3516491885471466898, 956288521791657692,
+ 457351505131524928, -8881176990926596454, -6375600354038175299, -7155351920868399290,
+ 4368649989588021065, 887231587095185257, -3659780529968199312, -2407146836602825512,
+ 5616972787034086048, -751562733459939242, 1686575021641186857, -5177887698780513806,
+ -4979215821652996885, -1375154703071198421, 5632136521049761902, -8390088894796940536,
+ -193645528485698615, -5979788902190688516, -4907000935050298721, -285522056888777828,
+ -2776431630044341707, 1679342092332374735, 6050638460742422078, -2229851317345194226,
+ -1582494184340482199, 5881353426285907985, 812786550756860885, 4541845584483343330,
+ -6497901820577766722, 4980675660146853729, -4012602956251539747, -329088717864244987,
+ -2896929232104691526, 1495812843684243920, -2153620458055647789, 7370257291860230865,
+ -2466442761497833547, 4706794511633873654, -1398851569026877145, 8549875090542453214,
+ -9189721207376179652, -7894453601103453165, 7297902601803624459, 1011190183918857495,
+ -6985347000036920864, 5147159997473910359, -8326859945294252826, 2659470849286379941,
+ 6097729358393448602, -7491646050550022124, -5117116194870963097, -896216826133240300,
+ -745860416168701406, 5803876044675762232, -787954255994554146, -3234519180203704564,
+ -4507534739750823898, -1657200065590290694, 505808562678895611, -4153273856159712438,
+ -8381261370078904295, 572156825025677802, 1791881013492340891, 3393267094866038768,
+ -5444650186382539299, 2352769483186201278, -7930912453007408350, -325464993179687389,
+ -3441562999710612272, -6489413242825283295, 5092019688680754699, -227247482082248967,
+ 4234737173186232084, 5027558287275472836, 4635198586344772304, -536033143587636457,
+ 5907508150730407386, -8438615781380831356, 972392927514829904, -3801314342046600696,
+ -4064951393885491917, -174840358296132583, 2407211146698877100, -1640089820333676239,
+ 3940796514530962282, -5882197405809569433, 3095313889586102949, -1818050141166537098,
+ 5832080132947175283, 7890064875145919662, 8184139210799583195, -8073512175445549678,
+ -7758774793014564506, -4581724029666783935, 3516491885471466898, -8267083515063118116,
6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
- 3350107529868390359, 6116438694366558490, 2107701075971293812, 1803294065921269267,
- 2469478054175558874, 7368243281019965984, 3791908367843677526, 185046971116456637,
- 2257095756513439648, 7217693971077460129, 909049953079504259, 7196649268545224266,
- 5637660345400869599, 3955544945427965183, 8057528650917418961, 4139268440301127643,
- 6621926588513568059, 1373361136802681441, 6527366231383600011, 3507654575162700890,
- 9202058512774729859, 1954818376891585542, 6640380907130175705, 8299563319178235687,
- 3901867355218954373, 7046310742295574065, 6847195391333990232, 1572638100518868053,
- 8850422670118399721, 3631909142291992901, 5158881091950831288, 2882958317343121593,
- 4763258931815816403, 6280052734341785344, 4243789408204964850, 2043464728020827976,
- 6545300466022085465, 4562580375758598164, 5495451168795427352, 1738312861590151095,
- 553004618757816492, 6895160632757959823, 8233623922264685171, 7139506338801360852,
- 8550891222387991669, 5535668688139305547, 2430933853350256242, 5401941257863201076,
- 8159640039107728799, 6157493831600770366, 7632066283658143750, 6308328381617103346,
+ -5873264506986385449, 6116438694366558490, 2107701075971293812, -7420077970933506541,
+ 2469478054175558874, -1855128755834809824, -5431463669011098282, -9038325065738319171,
+ -6966276280341336160, 7217693971077460129, -8314322083775271549, 7196649268545224266,
+ -3585711691453906209, -5267827091426810625, 8057528650917418961, -5084103596553648165,
+ -2601445448341207749, -7850010900052094367, 6527366231383600011, 3507654575162700890,
+ 9202058512774729859, 1954818376891585542, -2582991129724600103, 8299563319178235687,
+ -5321504681635821435, 7046310742295574065, -2376176645520785576, -7650733936335907755,
+ 8850422670118399721, 3631909142291992901, 5158881091950831288, -6340413719511654215,
+ 4763258931815816403, 6280052734341785344, -4979582628649810958, 2043464728020827976,
+ -2678071570832690343, 4562580375758598164, 5495451168795427352, -7485059175264624713,
+ 553004618757816492, 6895160632757959823, -989748114590090637, 7139506338801360852,
+ -672480814466784139, 5535668688139305547, 2430933853350256242, -3821430778991574732,
+ -1063731997747047009, -3065878205254005442, 7632066283658143750, 6308328381617103346,
3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
- 4079788377417136100, 8090302575944624335, 2945117363431356361, 864324395848741045,
- 3009039260312620700, 8430027460082534031, 401084700045993341, 7254622446438694921,
- 4707864159563588614, 5640248530963493951, 5982507712689997893, 3315098242282210105,
- 5503847578771918426, 3941971367175193882, 8118566580304798074, 3839261274019871296,
- 7062410411742090847, 741381002980207668, 6027994129690250817, 2497829994150063930,
- 6251390334426228834, 1368930247903518833, 8809096399316380241, 6492004350391900708,
- 2462145737463489636, 404828418920299174, 4153026434231690595, 261785715255475940,
- 5464715384600071357, 592710404378763017, 6764129236657751224, 8513655718539357449,
- 5820343663801914208, 385298524683789911, 5224135003438199467, 6303131641338802145,
- 7150122561309371392, 368107899140673753, 3115186834558311558, 2915636353584281051,
+ -5143583659437639708, 8090302575944624335, 2945117363431356361, -8359047641006034763,
+ 3009039260312620700, -793344576772241777, 401084700045993341, -1968749590416080887,
+ 4707864159563588614, -3583123505891281857, -3240864324164777915, -5908273794572565703,
+ -3719524458082857382, -5281400669679581926, 8118566580304798074, 3839261274019871296,
+ 7062410411742090847, -8481991033874568140, 6027994129690250817, -6725542042704711878,
+ -2971981702428546974, -7854441788951256975, 8809096399316380241, 6492004350391900708,
+ 2462145737463489636, -8818543617934476634, -5070345602623085213, -8961586321599299868,
+ -3758656652254704451, -8630661632476012791, 6764129236657751224, -709716318315418359,
+ -3403028373052861600, -8838073512170985897, -3999237033416576341, -2920240395515973663,
+ -2073249475545404416, 368107899140673753, -6108185202296464250, -6307735683270494757,
4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
- 4654329375432538231, 8930667561363381602, 5374373436876319273, 7623042350483453954,
- 7725442901813263321, 9186225467561587250, 4091027289597503355, 2357631606492579800,
- 2530936820058611833, 1636551876240043639, 5564664674334965799, 1452244145334316253,
- 2061642381019690829, 1279580266495294036, 9108481583171221009, 6023278686734049809,
- 5007630032676973346, 2153168792952589781, 6720334534964750538, 6041546491134794105,
- 3433922409283786309, 2285479922797300912, 3110614940896576130, 6366559590722842893,
- 5418791419666136509, 7163298419643543757, 4891138053923696990, 580618510277907015,
- 1684034065251686769, 4429514767357295841, 330346578555450005, 1119637995812174675,
- 7177515271653460134, 4589042248470800257, 7693288629059004563, 143607045258444228,
- 246994305896273627, 866417324803099287, 6473547110565816071, 3092379936208876896,
- 2058427839513754051, 5133784708526867938, 8785882556301281247, 6149332666841167611,
- 8585842181454472135, 6137678347805511274, 2070447184436970006, 5708223427705576541,
- 5999657892458244504, 4358391411789012426, 325123008708389849, 6837621693887290924,
- 4843721905315627004, 6010651222149276415, 5398352198963874652, 4602025990114250980,
- 1044646352569048800, 9106614159853161675, 829256115228593269, 4919284369102997000,
- 2681532557646850893, 3681559472488511871, 5307999518958214035, 6334130388442829274,
- 2658708232916537604, 1163313865052186287, 581945337509520675, 3648778920718647903,
- 4423673246306544414, 1620799783996955743, 220828013409515943, 8150384699999389761,
- 4287360518296753003, 4590000184845883843, 5513660857261085186, 6964829100392774275,
- 478991688350776035, 8746140185685648781, 228500091334420247, 1356187007457302238,
- 3019253992034194581, 3152601605678500003, 430152752706002213, 5559581553696971176,
- 4916432985369275664, 663574931734554391, 3420773838927732076, 2868348622579915573,
- 1999319134044418520, 3328689518636282723, 2587672709781371173, 1517255313529399333,
- 3092343956317362483, 3662252519007064108, 972445599196498113, 7664865435875959367,
- 1708913533482282562, 6917817162668868494, 3217629022545312900, 2570043027221707107,
- 8739788839543624613, 2488075924621352812, 4694002395387436668, 4559628481798514356,
+ 4654329375432538231, -292704475491394206, -3848998599978456535, 7623042350483453954,
+ 7725442901813263321, 9186225467561587250, -5132344747257272453, -6865740430362196008,
+ 2530936820058611833, 1636551876240043639, -3658707362519810009, 1452244145334316253,
+ -7161729655835084979, -7943791770359481772, 9108481583171221009, -3200093350120725999,
+ 5007630032676973346, 2153168792952589781, 6720334534964750538, -3181825545719981703,
+ 3433922409283786309, 2285479922797300912, 3110614940896576130, -2856812446131932915,
+ -3804580617188639299, 7163298419643543757, 4891138053923696990, 580618510277907015,
+ 1684034065251686769, 4429514767357295841, -8893025458299325803, -8103734041042601133,
+ 7177515271653460134, 4589042248470800257, -1530083407795771245, 143607045258444228,
+ 246994305896273627, -8356954712051676521, 6473547110565816071, 3092379936208876896,
+ 2058427839513754051, -4089587328327907870, 8785882556301281247, -3074039370013608197,
+ -637529855400303673, 6137678347805511274, -7152924852417805802, 5708223427705576541,
+ -3223714144396531304, 4358391411789012426, 325123008708389849, 6837621693887290924,
+ 4843721905315627004, -3212720814705499393, -3825019837890901156, 4602025990114250980,
+ 1044646352569048800, 9106614159853161675, -8394115921626182539, -4304087667751778808,
+ 2681532557646850893, 3681559472488511871, -3915372517896561773, -2889241648411946534,
+ -6564663803938238204, -8060058171802589521, 581945337509520675, 3648778920718647903,
+ -4799698790548231394, -7602572252857820065, 220828013409515943, -1072987336855386047,
+ 4287360518296753003, -4633371852008891965, 5513660857261085186, -2258542936462001533,
+ -8744380348503999773, 8746140185685648781, 228500091334420247, 1356187007457302238,
+ 3019253992034194581, 3152601605678500003, -8793219284148773595, 5559581553696971176,
+ 4916432985369275664, -8559797105120221417, -5802598197927043732, 2868348622579915573,
+ -7224052902810357288, -5894682518218493085, 2587672709781371173, -7706116723325376475,
+ 3092343956317362483, -5561119517847711700, 972445599196498113, -1558506600978816441,
+ 1708913533482282562, -2305554874185907314, -6005743014309462908, -6653329009633068701,
+ -483583197311151195, 2488075924621352812, -4529369641467339140, -4663743555056261452,
2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
- 628141331766346752, 4571950817186770476, 1472811188152235408, 7596648026010355826,
- 6091219417754424743, 7834161864828164065, 7103445518877254909, 4390861237357459201,
- 4442653864240571734, 8903482404847331368, 622261699494173647, 6037261250297213248,
- 504404948065709118, 7275215526217113061, 1011176780856001400, 2194750105623461063,
- 2623071828615234808, 5157313728073836108, 3738405111966602044, 2539767524076729570,
- 2467284396349269342, 5256026990536851868, 7841086888628396109, 6640857538655893162,
- 1202087339038317498, 2113514992440715978, 7534350895342931403, 4925284734898484745,
- 5145623771477493805, 8225140880134972332, 2719520354384050532, 9132346697815513771,
- 4332154495710163773, 7137789594094346916, 6994721091344268833, 6667228574869048934,
- 655440045726677499, 59934747298466858, 6124974028078036405, 8957774780655365418,
- 2332206071942466437, 1701056712286369627, 3154897383618636503, 1637766181387607527,
- 2460521277767576533, 197309393502684135, 643677854385267315, 2543179307861934850,
- 4350769010207485119, 4754652089410667672, 2015595502641514512, 7999059458976458608,
- 4287946071480840813, 8362686366770308971, 6486469209321732151, 3617727845841796026,
- 7554353525834302244, 4450022655153542367, 1605195740213535749, 5327014565305508387,
- 4626575813550328320, 2692222020597705149, 241045573717249868, 5098046974627094010,
- 7916882295460730264, 884817090297530579, 5329160409530630596, 7790979528857726136,
- 4955070238059373407, 4918537275422674302, 3008076183950404629, 3007769226071157901,
- 2470346235617803020, 8928702772696731736, 7856187920214445904, 4474874585391974885,
- 7900176660600710914, 2140571127916226672, 2425445057265199971, 2486055153341847830,
- 4186670094382025798, 1883939007446035042, 8808666044074867985, 3734134241178479257,
- 4065968871360089196, 6953124200385847784, 1305686814738899057, 1637739099014457647,
- 3656125660947993209, 3966759634633167020, 3106378204088556331, 6328899822778449810,
- 4565385105440252958, 1979884289539493806, 2331793186920865425, 3783206694208922581,
- 8464961209802336085, 2843963751609577687, 3030678195484896323, 4793717574095772604,
+ 628141331766346752, -4651421219668005332, -7750560848702540400, 7596648026010355826,
+ -3132152619100351065, 7834161864828164065, 7103445518877254909, 4390861237357459201,
+ -4780718172614204074, -319889632007444440, 622261699494173647, -3186110786557562560,
+ -8718967088789066690, -1948156510637662747, -8212195255998774408, -7028621931231314745,
+ 2623071828615234808, -4066058308780939700, -5484966924888173764, -6683604512778046238,
+ -6756087640505506466, 5256026990536851868, 7841086888628396109, 6640857538655893162,
+ -8021284697816458310, -7109857044414059830, -1689021141511844405, -4298087301956291063,
+ -4077748265377282003, -998231156719803476, 2719520354384050532, 9132346697815513771,
+ 4332154495710163773, -2085582442760428892, 6994721091344268833, -2556143461985726874,
+ -8567931991128098309, 59934747298466858, -3098398008776739403, -265597256199410390,
+ 2332206071942466437, -7522315324568406181, 3154897383618636503, -7585605855467168281,
+ -6762850759087199275, 197309393502684135, -8579694182469508493, 2543179307861934850,
+ 4350769010207485119, -4468719947444108136, -7207776534213261296, -1224312577878317200,
+ 4287946071480840813, 8362686366770308971, 6486469209321732151, -5605644191012979782,
+ -1669018511020473564, 4450022655153542367, -7618176296641240059, -3896357471549267421,
+ -4596796223304447488, -6531150016257070659, -8982326463137525940, -4125325062227681798,
+ -1306489741394045544, -8338554946557245229, 5329160409530630596, 7790979528857726136,
+ 4955070238059373407, -4304834761432101506, -6215295852904371179, 3007769226071157901,
+ -6753025801236972788, 8928702772696731736, 7856187920214445904, -4748497451462800923,
+ 7900176660600710914, -7082800908938549136, -6797926979589575837, -6737316883512927978,
+ 4186670094382025798, 1883939007446035042, -414705992779907823, 3734134241178479257,
+ 4065968871360089196, 6953124200385847784, -7917685222115876751, -7585632937840318161,
+ -5567246375906782599, -5256612402221608788, 3106378204088556331, -2894472214076325998,
+ 4565385105440252958, 1979884289539493806, -6891578849933910383, 3783206694208922581,
+ 8464961209802336085, 2843963751609577687, 3030678195484896323, -4429654462759003204,
4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
- 1042662272908816815, 5557303057122568958, 2647678726283249984, 2144477441549833761,
- 5806352215355387087, 7117771003473903623, 5916597177708541638, 462597715452321361,
- 8833658097025758785, 5970273481425315300, 563813119381731307, 2768349550652697015,
- 1598828206250873866, 5206393647403558110, 6235043485709261823, 3152217402014639496,
- 8469693267274066490, 125672920241807416, 5311079624024060938, 6663754932310491587,
- 8736848295048751716, 4488039774992061878, 5923302823487327109, 140891791083103236,
- 7414942793393574290, 7990420780896957397, 4317817392807076702, 3625184369705367340,
- 2740722765288122703, 5743100009702758344, 5997898640509039159, 8854493341352484163,
- 5242208035432907801, 701338899890987198, 7609280429197514109, 3020985755112334161,
- 6651322707055512866, 2635195723621160615, 5144520864246028816, 1035086515727829828,
- 1567242097116389047, 8172389260191636581, 6337820351429292273, 2163012566996458925,
- 2743190902890262681, 1906367633221323427, 6011544915663598137, 5932255307352610768,
- 2241128460406315459, 895504896216695588, 3094483003111372717, 4583857460292963101,
- 9079887171656594975, 8839289181930711403, 5762740387243057873, 4225072055348026230,
- 1838220598389033063, 3801620336801580414, 8823526620080073856, 1776617605585100335,
- 7899055018877642622, 5421679761463003041, 5521102963086275121, 4248279443559365898,
- 8735487530905098534, 1760527091573692978, 7142485049657745894, 8222656872927218123,
- 4969531564923704323, 3394475942196872480, 6424174453260338141, 359248545074932887,
- 3273651282831730598, 6797106199797138596, 3030918217665093212, 145600834617314036,
- 6036575856065626233, 740416251634527158, 7080427635449935582, 6951781370868335478,
- 399922722363687927, 294902314447253185, 7844950936339178523, 880320858634709042,
- 6192655680808675579, 411604686384710388, 9026808440365124461, 6440783557497587732,
+ 1042662272908816815, -3666068979732206850, 2647678726283249984, 2144477441549833761,
+ -3417019821499388721, -2105601033380872185, 5916597177708541638, -8760774321402454447,
+ 8833658097025758785, 5970273481425315300, 563813119381731307, -6455022486202078793,
+ 1598828206250873866, -4016978389451217698, -2988328551145513985, -6071154634840136312,
+ 8469693267274066490, 125672920241807416, -3912292412830714870, -2559617104544284221,
+ -486523741806024092, -4735332261862713930, 5923302823487327109, -9082480245771672572,
+ -1808429243461201518, 7990420780896957397, 4317817392807076702, 3625184369705367340,
+ -6482649271566653105, -3480272027152017464, -3225473396345736649, -368878695502291645,
+ -3981164001421868007, -8522033136963788610, 7609280429197514109, 3020985755112334161,
+ -2572049329799262942, 2635195723621160615, 5144520864246028816, -8188285521126945980,
+ 1567242097116389047, 8172389260191636581, -2885551685425483535, -7060359469858316883,
+ -6480181133964513127, -7317004403633452381, 6011544915663598137, 5932255307352610768,
+ 2241128460406315459, -8327867140638080220, 3094483003111372717, 4583857460292963101,
+ 9079887171656594975, -384082854924064405, -3460631649611717935, 4225072055348026230,
+ -7385151438465742745, 3801620336801580414, -399845416774701952, -7446754431269675473,
+ 7899055018877642622, 5421679761463003041, 5521102963086275121, -4975092593295409910,
+ 8735487530905098534, -7462844945281082830, -2080886987197029914, -1000715163927557685,
+ -4253840471931071485, -5828896094657903328, 6424174453260338141, 359248545074932887,
+ -5949720754023045210, -2426265837057637212, 3030918217665093212, -9077771202237461772,
+ -3186796180789149575, 740416251634527158, -2142944401404840226, 6951781370868335478,
+ 399922722363687927, -8928469722407522623, -1378421100515597285, -8343051178220066766,
+ -3030716356046100229, -8811767350470065420, 9026808440365124461, 6440783557497587732,
4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
- 1907224908052289603, 7381039757301768559, 6157238513393239656, 7749994231914157575,
+ -7316147128802486205, 7381039757301768559, 6157238513393239656, -1473377804940618233,
8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
- 7169176924412769570, 7942066497793203302, 1357759729055557688, 2278447439451174845,
- 3625338785743880657, 6477479539006708521, 8976185375579272206, 5511371554711836120,
+ 7169176924412769570, -1281305539061572506, -7865612307799218120, 2278447439451174845,
+ 3625338785743880657, 6477479539006708521, 8976185375579272206, -3712000482142939688,
1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
- 6346751753565857109, 241159987320630307, 3095793449658682053, 8978332846736310159,
- 2902794662273147216, 7208698530190629697, 7276901792339343736, 1732385229314443140,
- 4133292154170828382, 2918308698224194548, 1519461397937144458, 5293934712616591764,
- 4922828954023452664, 2879211533496425641, 5896236396443472108, 8465043815351752425,
- 7329020396871624740, 8915471717014488588, 2944902635677463047, 7052079073493465134,
+ 6346751753565857109, -8982212049534145501, -6127578587196093755, -245039190118465649,
+ -6320577374581628592, 7208698530190629697, 7276901792339343736, -7490986807540332668,
+ 4133292154170828382, 2918308698224194548, -7703910638917631350, -3929437324238184044,
+ -4300543082831323144, -6344160503358350167, 5896236396443472108, -758328221503023383,
+ -1894351639983151068, -307900319840287220, -6278469401177312761, -2171292963361310674,
8382142935188824023, 9103922860780351547, 4152330101494654406,
}
)
@@ -223,13 +221,18 @@ func (rng *rngSource) Seed(seed int64) {
x = seedrand(x)
u ^= int64(x)
u ^= rng_cooked[i]
- rng.vec[i] = u & _MASK
+ rng.vec[i] = u
}
}
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
func (rng *rngSource) Int63() int64 {
+ return int64(rng.Uint64() & _MASK)
+}
+
+// Uint64 returns a non-negative pseudo-random 64-bit integer as an uint64.
+func (rng *rngSource) Uint64() uint64 {
rng.tap--
if rng.tap < 0 {
rng.tap += _LEN
@@ -240,7 +243,7 @@ func (rng *rngSource) Int63() int64 {
rng.feed += _LEN
}
- x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK
+ x := rng.vec[rng.feed] + rng.vec[rng.tap]
rng.vec[rng.feed] = x
- return x
+ return uint64(x)
}
diff --git a/libgo/go/math/remainder.go b/libgo/go/math/remainder.go
index 98bb04dc79..c6a4c7d741 100644
--- a/libgo/go/math/remainder.go
+++ b/libgo/go/math/remainder.go
@@ -6,7 +6,7 @@ package math
// The original C code and the comment below are from
// FreeBSD's /usr/src/lib/msun/src/e_remainder.c and came
-// with this notice. The go code is a simplified version of
+// with this notice. The go code is a simplified version of
// the original C.
//
// ====================================================
diff --git a/libgo/go/math/sin.go b/libgo/go/math/sin.go
index 1c5491f6dc..75579ab4ed 100644
--- a/libgo/go/math/sin.go
+++ b/libgo/go/math/sin.go
@@ -146,8 +146,8 @@ func cos(x float64) float64 {
// map zeros to origin
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
if j > 3 {
@@ -212,8 +212,8 @@ func sin(x float64) float64 {
// map zeros to origin
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
diff --git a/libgo/go/math/sincos.go b/libgo/go/math/sincos.go
index b3a2f8a861..89db81e7fa 100644
--- a/libgo/go/math/sincos.go
+++ b/libgo/go/math/sincos.go
@@ -42,8 +42,8 @@ func sincos(x float64) (sin, cos float64) {
y := float64(j) // integer part of x/(Pi/4), as float
if j&1 == 1 { // map zeros to origin
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
if j > 3 { // reflect in x axis
diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go
index 86c0452347..c65c32e8a0 100644
--- a/libgo/go/math/sqrt.go
+++ b/libgo/go/math/sqrt.go
@@ -13,7 +13,7 @@ func Sqrt(x float64) float64 {
// The original C code and the long comment below are
// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
-// came with this notice. The go code is a simplified
+// came with this notice. The go code is a simplified
// version of the original C.
//
// ====================================================
@@ -86,7 +86,7 @@ func Sqrt(x float64) float64 {
// equal to huge for some floating point number "huge" and "tiny".
//
//
-// Notes: Rounding mode detection omitted. The constants "mask", "shift",
+// Notes: Rounding mode detection omitted. The constants "mask", "shift",
// and "bias" are found in src/math/bits.go
// Sqrt returns the square root of x.
@@ -148,7 +148,3 @@ func sqrt(x float64) float64 {
ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return Float64frombits(ix)
}
-
-func sqrtC(f float64, r *float64) {
- *r = sqrt(f)
-}
diff --git a/libgo/go/math/tan.go b/libgo/go/math/tan.go
index e544b276b5..f5230d3f1f 100644
--- a/libgo/go/math/tan.go
+++ b/libgo/go/math/tan.go
@@ -114,8 +114,8 @@ func tan(x float64) float64 {
/* map zeros and singularities to origin */
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
z := ((x - y*PI4A) - y*PI4B) - y*PI4C
diff --git a/libgo/go/mime/encodedword.go b/libgo/go/mime/encodedword.go
index db4b5f4510..c3ca4bacd1 100644
--- a/libgo/go/mime/encodedword.go
+++ b/libgo/go/mime/encodedword.go
@@ -16,7 +16,7 @@ import (
"unicode/utf8"
)
-// A WordEncoder is a RFC 2047 encoded-word encoder.
+// A WordEncoder is an RFC 2047 encoded-word encoder.
type WordEncoder byte
const (
@@ -71,7 +71,7 @@ const (
maxEncodedWordLen = 75
// maxContentLen is how much content can be encoded, ignoring the header and
// 2-byte footer.
- maxContentLen = maxEncodedWordLen - len("=?UTF-8?") - len("?=")
+ maxContentLen = maxEncodedWordLen - len("=?UTF-8?q?") - len("?=")
)
var maxBase64Len = base64.StdEncoding.DecodedLen(maxContentLen)
@@ -89,7 +89,7 @@ func (e WordEncoder) bEncode(buf *bytes.Buffer, charset, s string) {
var currentLen, last, runeLen int
for i := 0; i < len(s); i += runeLen {
- // Multi-byte characters must not be split accross encoded-words.
+ // Multi-byte characters must not be split across encoded-words.
// See RFC 2047, section 5.3.
_, runeLen = utf8.DecodeRuneInString(s[i:])
@@ -119,7 +119,7 @@ func (e WordEncoder) qEncode(buf *bytes.Buffer, charset, s string) {
var currentLen, runeLen int
for i := 0; i < len(s); i += runeLen {
b := s[i]
- // Multi-byte characters must not be split accross encoded-words.
+ // Multi-byte characters must not be split across encoded-words.
// See RFC 2047, section 5.3.
var encLen int
if b >= ' ' && b <= '~' && b != '=' && b != '?' && b != '_' {
diff --git a/libgo/go/mime/encodedword_test.go b/libgo/go/mime/encodedword_test.go
index 5fcd7a06dd..b7ca4d05e3 100644
--- a/libgo/go/mime/encodedword_test.go
+++ b/libgo/go/mime/encodedword_test.go
@@ -31,10 +31,8 @@ func TestEncodeWord(t *testing.T) {
{QEncoding, utf8, strings.Repeat("é", 11), "=?utf-8?q?" + strings.Repeat("=C3=A9", 10) + "?= =?utf-8?q?=C3=A9?="},
{QEncoding, iso88591, strings.Repeat("\xe9", 22), "=?iso-8859-1?q?" + strings.Repeat("=E9", 22) + "?="},
{QEncoding, utf8, strings.Repeat("\x80", 22), "=?utf-8?q?" + strings.Repeat("=80", 21) + "?= =?utf-8?q?=80?="},
- {BEncoding, utf8, strings.Repeat("é", 24), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?="},
- {BEncoding, utf8, strings.Repeat("é", 27), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?= =?utf-8?b?w6nDqcOp?="},
{BEncoding, iso88591, strings.Repeat("\xe9", 45), "=?iso-8859-1?b?" + strings.Repeat("6enp", 15) + "?="},
- {BEncoding, utf8, strings.Repeat("\x80", 51), "=?utf-8?b?" + strings.Repeat("gICA", 16) + "?= =?utf-8?b?gICA?="},
+ {BEncoding, utf8, strings.Repeat("\x80", 48), "=?utf-8?b?" + strings.Repeat("gICA", 15) + "?= =?utf-8?b?gICA?="},
}
for _, test := range tests {
@@ -44,6 +42,37 @@ func TestEncodeWord(t *testing.T) {
}
}
+func TestEncodedWordLength(t *testing.T) {
+ tests := []struct {
+ enc WordEncoder
+ src string
+ }{
+ {QEncoding, strings.Repeat("à", 30)},
+ {QEncoding, strings.Repeat("é", 60)},
+ {BEncoding, strings.Repeat("ï", 25)},
+ {BEncoding, strings.Repeat("ô", 37)},
+ {BEncoding, strings.Repeat("\x80", 50)},
+ {QEncoding, "{$firstname} Bienvendio a Apostolica, aquà inicia el camino de tu"},
+ }
+
+ for _, test := range tests {
+ s := test.enc.Encode("utf-8", test.src)
+ wordLen := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == ' ' {
+ wordLen = 0
+ continue
+ }
+
+ wordLen++
+ if wordLen > maxEncodedWordLen {
+ t.Errorf("Encode(%q) has more than %d characters: %q",
+ test.src, maxEncodedWordLen, s)
+ }
+ }
+ }
+}
+
func TestDecodeWord(t *testing.T) {
tests := []struct {
src, exp string
@@ -203,6 +232,6 @@ func BenchmarkQDecodeHeader(b *testing.B) {
dec := new(WordDecoder)
for i := 0; i < b.N; i++ {
- dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+ dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
}
}
diff --git a/libgo/go/mime/grammar.go b/libgo/go/mime/grammar.go
index 31b66e8f03..6a6f71dbd4 100644
--- a/libgo/go/mime/grammar.go
+++ b/libgo/go/mime/grammar.go
@@ -11,7 +11,7 @@ import (
// isTSpecial reports whether rune is in 'tspecials' as defined by RFC
// 1521 and RFC 2045.
func isTSpecial(r rune) bool {
- return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1
+ return strings.ContainsRune(`()<>@,;:\"/[]?=`, r)
}
// isTokenChar reports whether rune is in 'token' as defined by RFC
diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go
index efee65bb00..75cc90310f 100644
--- a/libgo/go/mime/mediatype.go
+++ b/libgo/go/mime/mediatype.go
@@ -221,7 +221,7 @@ func isNotTokenChar(r rune) bool {
// consumeToken consumes a token from the beginning of provided
// string, per RFC 2045 section 5.1 (referenced from 2183), and return
-// the token consumed and the rest of the string. Returns ("", v) on
+// the token consumed and the rest of the string. Returns ("", v) on
// failure to consume at least one character.
func consumeToken(v string) (token, rest string) {
notPos := strings.IndexFunc(v, isNotTokenChar)
@@ -237,7 +237,7 @@ func consumeToken(v string) (token, rest string) {
// consumeValue consumes a "value" per RFC 2045, where a value is
// either a 'token' or a 'quoted-string'. On success, consumeValue
// returns the value consumed (and de-quoted/escaped, if a
-// quoted-string) and the rest of the string. On failure, returns
+// quoted-string) and the rest of the string. On failure, returns
// ("", v).
func consumeValue(v string) (value, rest string) {
if v == "" {
@@ -248,24 +248,33 @@ func consumeValue(v string) (value, rest string) {
}
// parse a quoted-string
- rest = v[1:] // consume the leading quote
buffer := new(bytes.Buffer)
- var nextIsLiteral bool
- for idx, r := range rest {
- switch {
- case nextIsLiteral:
- buffer.WriteRune(r)
- nextIsLiteral = false
- case r == '"':
- return buffer.String(), rest[idx+1:]
- case r == '\\':
- nextIsLiteral = true
- case r != '\r' && r != '\n':
- buffer.WriteRune(r)
- default:
+ for i := 1; i < len(v); i++ {
+ r := v[i]
+ if r == '"' {
+ return buffer.String(), v[i+1:]
+ }
+ // When MSIE sends a full file path (in "intranet mode"), it does not
+ // escape backslashes: "C:\dev\go\foo.txt", not "C:\\dev\\go\\foo.txt".
+ //
+ // No known MIME generators emit unnecessary backslash escapes
+ // for simple token characters like numbers and letters.
+ //
+ // If we see an unnecessary backslash escape, assume it is from MSIE
+ // and intended as a literal backslash. This makes Go servers deal better
+ // with MSIE without affecting the way they handle conforming MIME
+ // generators.
+ if r == '\\' && i+1 < len(v) && !isTokenChar(rune(v[i+1])) {
+ buffer.WriteByte(v[i+1])
+ i++
+ continue
+ }
+ if r == '\r' || r == '\n' {
return "", v
}
+ buffer.WriteByte(v[i])
}
+ // Did not find end quote.
return "", v
}
diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go
index 9afa55825f..c5fc906d6a 100644
--- a/libgo/go/mime/mediatype_test.go
+++ b/libgo/go/mime/mediatype_test.go
@@ -138,10 +138,11 @@ func TestParseMediaType(t *testing.T) {
m("title", "This is even more ***fun*** isn't it!")},
// Tests from http://greenbytes.de/tech/tc2231/
+ // Note: Backslash escape handling is a bit loose, like MSIE.
// TODO(bradfitz): add the rest of the tests from that site.
{`attachment; filename="f\oo.html"`,
"attachment",
- m("filename", "foo.html")},
+ m("filename", "f\\oo.html")},
{`attachment; filename="\"quoting\" tested.html"`,
"attachment",
m("filename", `"quoting" tested.html`)},
@@ -165,7 +166,7 @@ func TestParseMediaType(t *testing.T) {
m("filename", "foo-%41.html")},
{`attachment; filename="foo-%\41.html"`,
"attachment",
- m("filename", "foo-%41.html")},
+ m("filename", "foo-%\\41.html")},
{`filename=foo.html`,
"", m()},
{`x=y; filename=foo.html`,
@@ -220,18 +221,21 @@ func TestParseMediaType(t *testing.T) {
// Empty string used to be mishandled.
{`foo; bar=""`, "foo", m("bar", "")},
+
+ // Microsoft browers in intranet mode do not think they need to escape \ in file name.
+ {`form-data; name="file"; filename="C:\dev\go\robots.txt"`, "form-data", m("name", "file", "filename", `C:\dev\go\robots.txt`)},
}
for _, test := range tests {
mt, params, err := ParseMediaType(test.in)
if err != nil {
if test.t != "" {
- t.Errorf("for input %q, unexpected error: %v", test.in, err)
+ t.Errorf("for input %#q, unexpected error: %v", test.in, err)
continue
}
continue
}
if g, e := mt, test.t; g != e {
- t.Errorf("for input %q, expected type %q, got %q",
+ t.Errorf("for input %#q, expected type %q, got %q",
test.in, e, g)
continue
}
@@ -239,7 +243,7 @@ func TestParseMediaType(t *testing.T) {
continue
}
if !reflect.DeepEqual(params, test.p) {
- t.Errorf("for input %q, wrong params.\n"+
+ t.Errorf("for input %#q, wrong params.\n"+
"expected: %#v\n"+
" got: %#v",
test.in, test.p, params)
diff --git a/libgo/go/mime/multipart/formdata.go b/libgo/go/mime/multipart/formdata.go
index eee53fc8dd..c9e3188c33 100644
--- a/libgo/go/mime/multipart/formdata.go
+++ b/libgo/go/mime/multipart/formdata.go
@@ -20,7 +20,11 @@ import (
// a Content-Disposition of "form-data".
// It stores up to maxMemory bytes of the file parts in memory
// and the remainder on disk in temporary files.
-func (r *Reader) ReadForm(maxMemory int64) (f *Form, err error) {
+func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
+ return r.readForm(maxMemory)
+}
+
+func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
defer func() {
if err != nil {
@@ -75,8 +79,10 @@ func (r *Reader) ReadForm(maxMemory int64) (f *Form, err error) {
if err != nil {
return nil, err
}
- defer file.Close()
_, err = io.Copy(file, io.MultiReader(&b, p))
+ if cerr := file.Close(); err == nil {
+ err = cerr
+ }
if err != nil {
os.Remove(file.Name())
return nil, err
diff --git a/libgo/go/mime/multipart/formdata_test.go b/libgo/go/mime/multipart/formdata_test.go
index 6e2388bafe..1deca0b94d 100644
--- a/libgo/go/mime/multipart/formdata_test.go
+++ b/libgo/go/mime/multipart/formdata_test.go
@@ -88,3 +88,39 @@ Content-Disposition: form-data; name="textb"
` + textbValue + `
--MyBoundary--
`
+
+func TestReadForm_NoReadAfterEOF(t *testing.T) {
+ maxMemory := int64(32) << 20
+ boundary := `---------------------------8d345eef0d38dc9`
+ body := `
+-----------------------------8d345eef0d38dc9
+Content-Disposition: form-data; name="version"
+
+171
+-----------------------------8d345eef0d38dc9--`
+
+ mr := NewReader(&failOnReadAfterErrorReader{t: t, r: strings.NewReader(body)}, boundary)
+
+ f, err := mr.ReadForm(maxMemory)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Got: %#v", f)
+}
+
+// failOnReadAfterErrorReader is an io.Reader wrapping r.
+// It fails t if any Read is called after a failing Read.
+type failOnReadAfterErrorReader struct {
+ t *testing.T
+ r io.Reader
+ sawErr error
+}
+
+func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
+ if r.sawErr != nil {
+ r.t.Fatalf("unexpected Read on Reader after previous read saw error %v", r.sawErr)
+ }
+ n, err = r.r.Read(p)
+ r.sawErr = err
+ return
+}
diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go
index 3b746a5e15..1954808176 100644
--- a/libgo/go/mime/multipart/multipart.go
+++ b/libgo/go/mime/multipart/multipart.go
@@ -42,9 +42,7 @@ type Part struct {
// during Read calls.
Header textproto.MIMEHeader
- buffer *bytes.Buffer
- mr *Reader
- bytesRead int
+ mr *Reader
disposition string
dispositionParams map[string]string
@@ -53,6 +51,11 @@ type Part struct {
// wrapper around such a reader, decoding the
// Content-Transfer-Encoding
r io.Reader
+
+ n int // known data bytes waiting in mr.bufReader
+ total int64 // total data bytes read already
+ err error // error to return when n == 0
+ readErr error // read error observed from mr.bufReader
}
// FormName returns the name parameter if p has a Content-Disposition
@@ -96,7 +99,7 @@ func (p *Part) parseContentDisposition() {
func NewReader(r io.Reader, boundary string) *Reader {
b := []byte("\r\n--" + boundary + "--")
return &Reader{
- bufReader: bufio.NewReaderSize(r, peekBufferSize),
+ bufReader: bufio.NewReaderSize(&stickyErrorReader{r: r}, peekBufferSize),
nl: b[:2],
nlDashBoundary: b[:len(b)-2],
dashBoundaryDash: b[2:],
@@ -104,11 +107,28 @@ func NewReader(r io.Reader, boundary string) *Reader {
}
}
+// stickyErrorReader is an io.Reader which never calls Read on its
+// underlying Reader once an error has been seen. (the io.Reader
+// interface's contract promises nothing about the return values of
+// Read calls after an error, yet this package does do multiple Reads
+// after error)
+type stickyErrorReader struct {
+ r io.Reader
+ err error
+}
+
+func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+ n, r.err = r.r.Read(p)
+ return n, r.err
+}
+
func newPart(mr *Reader) (*Part, error) {
bp := &Part{
Header: make(map[string][]string),
mr: mr,
- buffer: new(bytes.Buffer),
}
if err := bp.populateHeaders(); err != nil {
return nil, err
@@ -143,65 +163,118 @@ type partReader struct {
p *Part
}
-func (pr partReader) Read(d []byte) (n int, err error) {
+func (pr partReader) Read(d []byte) (int, error) {
p := pr.p
- defer func() {
- p.bytesRead += n
- }()
- if p.buffer.Len() >= len(d) {
- // Internal buffer of unconsumed data is large enough for
- // the read request. No need to parse more at the moment.
- return p.buffer.Read(d)
+ br := p.mr.bufReader
+
+ // Read into buffer until we identify some data to return,
+ // or we find a reason to stop (boundary or read error).
+ for p.n == 0 && p.err == nil {
+ peek, _ := br.Peek(br.Buffered())
+ p.n, p.err = scanUntilBoundary(peek, p.mr.dashBoundary, p.mr.nlDashBoundary, p.total, p.readErr)
+ if p.n == 0 && p.err == nil {
+ // Force buffered I/O to read more into buffer.
+ _, p.readErr = br.Peek(len(peek) + 1)
+ if p.readErr == io.EOF {
+ p.readErr = io.ErrUnexpectedEOF
+ }
+ }
}
- peek, err := p.mr.bufReader.Peek(peekBufferSize) // TODO(bradfitz): add buffer size accessor
-
- // Look for an immediate empty part without a leading \r\n
- // before the boundary separator. Some MIME code makes empty
- // parts like this. Most browsers, however, write the \r\n
- // before the subsequent boundary even for empty parts and
- // won't hit this path.
- if p.bytesRead == 0 && p.mr.peekBufferIsEmptyPart(peek) {
- return 0, io.EOF
+
+ // Read out from "data to return" part of buffer.
+ if p.n == 0 {
+ return 0, p.err
}
- unexpectedEOF := err == io.EOF
- if err != nil && !unexpectedEOF {
- return 0, fmt.Errorf("multipart: Part Read: %v", err)
+ n := len(d)
+ if n > p.n {
+ n = p.n
}
- if peek == nil {
- panic("nil peek buf")
+ n, _ = br.Read(d[:n])
+ p.total += int64(n)
+ p.n -= n
+ if p.n == 0 {
+ return n, p.err
}
- // Search the peek buffer for "\r\n--boundary". If found,
- // consume everything up to the boundary. If not, consume only
- // as much of the peek buffer as cannot hold the boundary
- // string.
- nCopy := 0
- foundBoundary := false
- if idx, isEnd := p.mr.peekBufferSeparatorIndex(peek); idx != -1 {
- nCopy = idx
- foundBoundary = isEnd
- if !isEnd && nCopy == 0 {
- nCopy = 1 // make some progress.
+ return n, nil
+}
+
+// scanUntilBoundary scans buf to identify how much of it can be safely
+// returned as part of the Part body.
+// dashBoundary is "--boundary".
+// nlDashBoundary is "\r\n--boundary" or "\n--boundary", depending on what mode we are in.
+// The comments below (and the name) assume "\n--boundary", but either is accepted.
+// total is the number of bytes read out so far. If total == 0, then a leading "--boundary" is recognized.
+// readErr is the read error, if any, that followed reading the bytes in buf.
+// scanUntilBoundary returns the number of data bytes from buf that can be
+// returned as part of the Part body and also the error to return (if any)
+// once those data bytes are done.
+func scanUntilBoundary(buf, dashBoundary, nlDashBoundary []byte, total int64, readErr error) (int, error) {
+ if total == 0 {
+ // At beginning of body, allow dashBoundary.
+ if bytes.HasPrefix(buf, dashBoundary) {
+ switch matchAfterPrefix(buf, dashBoundary, readErr) {
+ case -1:
+ return len(dashBoundary), nil
+ case 0:
+ return 0, nil
+ case +1:
+ return 0, io.EOF
+ }
+ }
+ if bytes.HasPrefix(dashBoundary, buf) {
+ return 0, readErr
}
- } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
- nCopy = safeCount
- } else if unexpectedEOF {
- // If we've run out of peek buffer and the boundary
- // wasn't found (and can't possibly fit), we must have
- // hit the end of the file unexpectedly.
- return 0, io.ErrUnexpectedEOF
}
- if nCopy > 0 {
- if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
- return 0, err
+
+ // Search for "\n--boundary".
+ if i := bytes.Index(buf, nlDashBoundary); i >= 0 {
+ switch matchAfterPrefix(buf[i:], nlDashBoundary, readErr) {
+ case -1:
+ return i + len(nlDashBoundary), nil
+ case 0:
+ return i, nil
+ case +1:
+ return i, io.EOF
+ }
+ }
+ if bytes.HasPrefix(nlDashBoundary, buf) {
+ return 0, readErr
+ }
+
+ // Otherwise, anything up to the final \n is not part of the boundary
+ // and so must be part of the body.
+ // Also if the section from the final \n onward is not a prefix of the boundary,
+ // it too must be part of the body.
+ i := bytes.LastIndexByte(buf, nlDashBoundary[0])
+ if i >= 0 && bytes.HasPrefix(nlDashBoundary, buf[i:]) {
+ return i, nil
+ }
+ return len(buf), readErr
+}
+
+// matchAfterPrefix checks whether buf should be considered to match the boundary.
+// The prefix is "--boundary" or "\r\n--boundary" or "\n--boundary",
+// and the caller has verified already that bytes.HasPrefix(buf, prefix) is true.
+//
+// matchAfterPrefix returns +1 if the buffer does match the boundary,
+// meaning the prefix is followed by a dash, space, tab, cr, nl, or end of input.
+// It returns -1 if the buffer definitely does NOT match the boundary,
+// meaning the prefix is followed by some other character.
+// For example, "--foobar" does not match "--foo".
+// It returns 0 more input needs to be read to make the decision,
+// meaning that len(buf) == len(prefix) and readErr == nil.
+func matchAfterPrefix(buf, prefix []byte, readErr error) int {
+ if len(buf) == len(prefix) {
+ if readErr != nil {
+ return +1
}
+ return 0
}
- n, err = p.buffer.Read(d)
- if err == io.EOF && !foundBoundary {
- // If the boundary hasn't been reached there's more to
- // read, so don't pass through an EOF from the buffer
- err = nil
+ c := buf[len(prefix)]
+ if c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '-' {
+ return +1
}
- return
+ return -1
}
func (p *Part) Close() error {
@@ -210,7 +283,7 @@ func (p *Part) Close() error {
}
// Reader is an iterator over parts in a MIME multipart body.
-// Reader's underlying parser consumes its input as needed. Seeking
+// Reader's underlying parser consumes its input as needed. Seeking
// isn't supported.
type Reader struct {
bufReader *bufio.Reader
@@ -310,7 +383,7 @@ func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
rest = skipLWSPChar(rest)
// On the first part, see our lines are ending in \n instead of \r\n
- // and switch into that mode if so. This is a violation of the spec,
+ // and switch into that mode if so. This is a violation of the spec,
// but occurs in practice.
if mr.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
mr.nl = mr.nl[1:]
@@ -319,64 +392,6 @@ func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
return bytes.Equal(rest, mr.nl)
}
-// peekBufferIsEmptyPart reports whether the provided peek-ahead
-// buffer represents an empty part. It is called only if we've not
-// already read any bytes in this part and checks for the case of MIME
-// software not writing the \r\n on empty parts. Some does, some
-// doesn't.
-//
-// This checks that what follows the "--boundary" is actually the end
-// ("--boundary--" with optional whitespace) or optional whitespace
-// and then a newline, so we don't catch "--boundaryFAKE", in which
-// case the whole line is part of the data.
-func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
- // End of parts case.
- // Test whether peek matches `^--boundary--[ \t]*(?:\r\n|$)`
- if bytes.HasPrefix(peek, mr.dashBoundaryDash) {
- rest := peek[len(mr.dashBoundaryDash):]
- rest = skipLWSPChar(rest)
- return bytes.HasPrefix(rest, mr.nl) || len(rest) == 0
- }
- if !bytes.HasPrefix(peek, mr.dashBoundary) {
- return false
- }
- // Test whether rest matches `^[ \t]*\r\n`)
- rest := peek[len(mr.dashBoundary):]
- rest = skipLWSPChar(rest)
- return bytes.HasPrefix(rest, mr.nl)
-}
-
-// peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in
-// peek and whether it is a real boundary (and not a prefix of an
-// unrelated separator). To be the end, the peek buffer must contain a
-// newline after the boundary or contain the ending boundary (--separator--).
-func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) {
- idx = bytes.Index(peek, mr.nlDashBoundary)
- if idx == -1 {
- return
- }
-
- peek = peek[idx+len(mr.nlDashBoundary):]
- if len(peek) == 0 || len(peek) == 1 && peek[0] == '-' {
- return idx, false
- }
- if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' {
- return idx, true
- }
- peek = skipLWSPChar(peek)
- // Don't have a complete line after the peek.
- if bytes.IndexByte(peek, '\n') == -1 {
- return idx, false
- }
- if len(peek) > 0 && peek[0] == '\n' {
- return idx, true
- }
- if len(peek) > 1 && peek[0] == '\r' && peek[1] == '\n' {
- return idx, true
- }
- return idx, false
-}
-
// skipLWSPChar returns b with leading spaces and tabs removed.
// RFC 822 defines:
// LWSP-char = SPACE / HTAB
diff --git a/libgo/go/mime/multipart/multipart_test.go b/libgo/go/mime/multipart/multipart_test.go
index d06bb4159a..7fbee90ac3 100644
--- a/libgo/go/mime/multipart/multipart_test.go
+++ b/libgo/go/mime/multipart/multipart_test.go
@@ -125,6 +125,7 @@ func TestMultipartSlowInput(t *testing.T) {
}
func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
+ t.Parallel()
reader := NewReader(r, "MyBoundary")
buf := new(bytes.Buffer)
@@ -323,6 +324,73 @@ func (s *slowReader) Read(p []byte) (int, error) {
return s.r.Read(p[:1])
}
+type sentinelReader struct {
+ // done is closed when this reader is read from.
+ done chan struct{}
+}
+
+func (s *sentinelReader) Read([]byte) (int, error) {
+ if s.done != nil {
+ close(s.done)
+ s.done = nil
+ }
+ return 0, io.EOF
+}
+
+// TestMultipartStreamReadahead tests that PartReader does not block
+// on reading past the end of a part, ensuring that it can be used on
+// a stream like multipart/x-mixed-replace. See golang.org/issue/15431
+func TestMultipartStreamReadahead(t *testing.T) {
+ testBody1 := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo-bar: baz
+
+Body
+--MyBoundary
+`
+ testBody2 := `foo-bar: bop
+
+Body 2
+--MyBoundary--
+`
+ done1 := make(chan struct{})
+ reader := NewReader(
+ io.MultiReader(
+ strings.NewReader(testBody1),
+ &sentinelReader{done1},
+ strings.NewReader(testBody2)),
+ "MyBoundary")
+
+ var i int
+ readPart := func(hdr textproto.MIMEHeader, body string) {
+ part, err := reader.NextPart()
+ if part == nil || err != nil {
+ t.Fatalf("Part %d: NextPart failed: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(part.Header, hdr) {
+ t.Errorf("Part %d: part.Header = %v, want %v", i, part.Header, hdr)
+ }
+ data, err := ioutil.ReadAll(part)
+ expectEq(t, body, string(data), fmt.Sprintf("Part %d body", i))
+ if err != nil {
+ t.Fatalf("Part %d: ReadAll failed: %v", i, err)
+ }
+ i++
+ }
+
+ readPart(textproto.MIMEHeader{"Foo-Bar": {"baz"}}, "Body")
+
+ select {
+ case <-done1:
+ t.Errorf("Reader read past second boundary")
+ default:
+ }
+
+ readPart(textproto.MIMEHeader{"Foo-Bar": {"bop"}}, "Body 2")
+}
+
func TestLineContinuation(t *testing.T) {
// This body, extracted from an email, contains headers that span multiple
// lines.
@@ -446,8 +514,8 @@ type parseTest struct {
var parseTests = []parseTest{
// Actual body from App Engine on a blob upload. The final part (the
// Content-Type: message/external-body) is what App Engine replaces
- // the uploaded file with. The other form fields (prefixed with
- // "other" in their form-data name) are unchanged. A bug was
+ // the uploaded file with. The other form fields (prefixed with
+ // "other" in their form-data name) are unchanged. A bug was
// reported with blob uploads failing when the other fields were
// empty. This was the MIME POST body that previously failed.
{
@@ -755,6 +823,7 @@ func partsFromReader(r *Reader) ([]headerBody, error) {
}
func TestParseAllSizes(t *testing.T) {
+ t.Parallel()
const maxSize = 5 << 10
var buf bytes.Buffer
body := strings.Repeat("a", maxSize)
diff --git a/libgo/go/mime/multipart/writer.go b/libgo/go/mime/multipart/writer.go
index 80960939d6..f82756d551 100644
--- a/libgo/go/mime/multipart/writer.go
+++ b/libgo/go/mime/multipart/writer.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"net/textproto"
+ "sort"
"strings"
)
@@ -94,10 +95,14 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
} else {
fmt.Fprintf(&b, "--%s\r\n", w.boundary)
}
- // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
- // and clean, like http.Header.Write(w) does.
- for k, vv := range header {
- for _, v := range vv {
+
+ keys := make([]string, 0, len(header))
+ for k := range header {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ for _, v := range header[k] {
fmt.Fprintf(&b, "%s: %s\r\n", k, v)
}
}
diff --git a/libgo/go/mime/multipart/writer_test.go b/libgo/go/mime/multipart/writer_test.go
index ba00c97ece..9670c660a4 100644
--- a/libgo/go/mime/multipart/writer_test.go
+++ b/libgo/go/mime/multipart/writer_test.go
@@ -7,6 +7,7 @@ package multipart
import (
"bytes"
"io/ioutil"
+ "net/textproto"
"strings"
"testing"
)
@@ -126,3 +127,32 @@ func TestWriterBoundaryGoroutines(t *testing.T) {
w.Boundary()
<-done
}
+
+func TestSortedHeader(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(&buf)
+ if err := w.SetBoundary("MIMEBOUNDARY"); err != nil {
+ t.Fatalf("Error setting mime boundary: %v", err)
+ }
+
+ header := textproto.MIMEHeader{
+ "A": {"2"},
+ "B": {"5", "7", "6"},
+ "C": {"4"},
+ "M": {"3"},
+ "Z": {"1"},
+ }
+
+ part, err := w.CreatePart(header)
+ if err != nil {
+ t.Fatalf("Unable to create part: %v", err)
+ }
+ part.Write([]byte("foo"))
+
+ w.Close()
+
+ want := "--MIMEBOUNDARY\r\nA: 2\r\nB: 5\r\nB: 7\r\nB: 6\r\nC: 4\r\nM: 3\r\nZ: 1\r\n\r\nfoo\r\n--MIMEBOUNDARY--\r\n"
+ if want != buf.String() {
+ t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want)
+ }
+}
diff --git a/libgo/go/mime/quotedprintable/example_test.go b/libgo/go/mime/quotedprintable/example_test.go
new file mode 100644
index 0000000000..0593b04935
--- /dev/null
+++ b/libgo/go/mime/quotedprintable/example_test.go
@@ -0,0 +1,39 @@
+// 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 quotedprintable_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "mime/quotedprintable"
+ "os"
+ "strings"
+)
+
+func ExampleNewReader() {
+ for _, s := range []string{
+ `=48=65=6C=6C=6F=2C=20=47=6F=70=68=65=72=73=21`,
+ `invalid escape: <b style="font-size: 200%">hello</b>`,
+ "Hello, Gophers! This symbol will be unescaped: =3D and this will be written in =\r\none line.",
+ } {
+ b, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(s)))
+ fmt.Printf("%s %v\n", b, err)
+ }
+ // Output:
+ // Hello, Gophers! <nil>
+ // invalid escape: <b style="font-size: 200%">hello</b> <nil>
+ // Hello, Gophers! This symbol will be unescaped: = and this will be written in one line. <nil>
+}
+
+func ExampleNewWriter() {
+ w := quotedprintable.NewWriter(os.Stdout)
+ w.Write([]byte("These symbols will be escaped: = \t"))
+ w.Close()
+
+ // Output:
+ // These symbols will be escaped: =3D =09
+}
diff --git a/libgo/go/mime/quotedprintable/reader.go b/libgo/go/mime/quotedprintable/reader.go
index 3bd6833da5..b142240343 100644
--- a/libgo/go/mime/quotedprintable/reader.go
+++ b/libgo/go/mime/quotedprintable/reader.go
@@ -74,6 +74,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
// with other broken QP encoders & decoders.
+ // 3. it accepts soft line-break (=) at end of message (issue 15486); i.e.
+ // the final byte read from the underlying reader is allowed to be '=',
+ // and it will be silently ignored.
+ // 4. it takes = as literal = if not followed by two hex digits
+ // but not at end of line (issue 13219).
for len(p) > 0 {
if len(r.line) == 0 {
if r.rerr != nil {
@@ -89,7 +94,8 @@ func (r *Reader) Read(p []byte) (n int, err error) {
if bytes.HasSuffix(r.line, softSuffix) {
rightStripped := wholeLine[len(r.line):]
r.line = r.line[:len(r.line)-1]
- if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
+ if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) &&
+ !(len(rightStripped) == 0 && len(r.line) > 0 && r.rerr == io.EOF) {
r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
}
} else if hasLF {
@@ -107,6 +113,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
case b == '=':
b, err = readHexByte(r.line[1:])
if err != nil {
+ if len(r.line) >= 2 && r.line[1] != '\r' && r.line[1] != '\n' {
+ // Take the = as a literal =.
+ b = '='
+ break
+ }
return n, err
}
r.line = r.line[2:] // 2 of the 3; other 1 is done below
diff --git a/libgo/go/mime/quotedprintable/reader_test.go b/libgo/go/mime/quotedprintable/reader_test.go
index e77b2610ec..ca016f969a 100644
--- a/libgo/go/mime/quotedprintable/reader_test.go
+++ b/libgo/go/mime/quotedprintable/reader_test.go
@@ -30,7 +30,7 @@ func TestReader(t *testing.T) {
{in: "foo bar=3d", want: "foo bar="}, // lax.
{in: "foo bar=\n", want: "foo bar"},
{in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
- {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
+ {in: "foo bar=0", want: "foo bar=0"}, // lax
{in: "foo bar=0D=0A", want: "foo bar\r\n"},
{in: " A B \r\n C ", want: " A B\r\n C"},
{in: " A B =\r\n C ", want: " A B C"},
@@ -58,6 +58,9 @@ func TestReader(t *testing.T) {
{in: "foo=\nbar", want: "foobar"},
{in: "foo=\rbar", want: "foo", err: "quotedprintable: invalid hex byte 0x0d"},
{in: "foo=\r\r\r \nbar", want: "foo", err: `quotedprintable: invalid bytes after =: "\r\r\r \n"`},
+ // Issue 15486, accept trailing soft line-break at end of input.
+ {in: "foo=", want: "foo"},
+ {in: "=", want: "", err: `quotedprintable: invalid bytes after =: ""`},
// Example from RFC 2045:
{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
@@ -191,13 +194,10 @@ func TestExhaustive(t *testing.T) {
}
sort.Strings(outcomes)
got := strings.Join(outcomes, "\n")
- want := `OK: 21576
-invalid bytes after =: 3397
-quotedprintable: invalid hex byte 0x0a: 1400
-quotedprintable: invalid hex byte 0x0d: 2700
-quotedprintable: invalid hex byte 0x20: 2490
-quotedprintable: invalid hex byte 0x3d: 440
-unexpected EOF: 3122`
+ want := `OK: 28934
+invalid bytes after =: 3949
+quotedprintable: invalid hex byte 0x0d: 2048
+unexpected EOF: 194`
if got != want {
t.Errorf("Got:\n%s\nWant:\n%s", got, want)
}
diff --git a/libgo/go/mime/testdata/test.types.plan9 b/libgo/go/mime/testdata/test.types.plan9
new file mode 100644
index 0000000000..19dbf41cce
--- /dev/null
+++ b/libgo/go/mime/testdata/test.types.plan9
@@ -0,0 +1,8 @@
+# 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.
+
+
+ # mime package test
+.t1 application test - y # Simple test
+.t2 text test - y # Text test
diff --git a/libgo/go/mime/type_plan9.go b/libgo/go/mime/type_plan9.go
index c3ba186e7c..14ff973405 100644
--- a/libgo/go/mime/type_plan9.go
+++ b/libgo/go/mime/type_plan9.go
@@ -21,7 +21,7 @@ func initMimePlan9() {
}
var typeFiles = []string{
- "/sys/lib/mimetypes",
+ "/sys/lib/mimetype",
}
func initMimeForTests() map[string]string {
diff --git a/libgo/go/net/addrselect.go b/libgo/go/net/addrselect.go
index 58ab7d706c..1ab9fc5326 100644
--- a/libgo/go/net/addrselect.go
+++ b/libgo/go/net/addrselect.go
@@ -188,33 +188,17 @@ func (s *byRFC6724) Less(i, j int) bool {
// Rule 9: Use longest matching prefix.
// When DA and DB belong to the same address family (both are IPv6 or
- // both are IPv4): If CommonPrefixLen(Source(DA), DA) >
+ // both are IPv4 [but see below]): If CommonPrefixLen(Source(DA), DA) >
// CommonPrefixLen(Source(DB), DB), then prefer DA. Similarly, if
// CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
// then prefer DB.
- da4 := DA.To4() != nil
- db4 := DB.To4() != nil
- if da4 == db4 {
+ //
+ // However, applying this rule to IPv4 addresses causes
+ // problems (see issues 13283 and 18518), so limit to IPv6.
+ if DA.To4() == nil && DB.To4() == nil {
commonA := commonPrefixLen(SourceDA, DA)
commonB := commonPrefixLen(SourceDB, DB)
- // CommonPrefixLen doesn't really make sense for IPv4, and even
- // causes problems for common load balancing practices
- // (e.g., https://golang.org/issue/13283). Glibc instead only
- // uses CommonPrefixLen for IPv4 when the source and destination
- // addresses are on the same subnet, but that requires extra
- // work to find the netmask for our source addresses. As a
- // simpler heuristic, we limit its use to when the source and
- // destination belong to the same special purpose block.
- if da4 {
- if !sameIPv4SpecialPurposeBlock(SourceDA, DA) {
- commonA = 0
- }
- if !sameIPv4SpecialPurposeBlock(SourceDB, DB) {
- commonB = 0
- }
- }
-
if commonA > commonB {
return preferDA
}
@@ -404,28 +388,3 @@ func commonPrefixLen(a, b IP) (cpl int) {
}
return
}
-
-// sameIPv4SpecialPurposeBlock reports whether a and b belong to the same
-// address block reserved by the IANA IPv4 Special-Purpose Address Registry:
-// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
-func sameIPv4SpecialPurposeBlock(a, b IP) bool {
- a, b = a.To4(), b.To4()
- if a == nil || b == nil || a[0] != b[0] {
- return false
- }
- // IANA defines more special-purpose blocks, but these are the only
- // ones likely to be relevant to typical Go systems.
- switch a[0] {
- case 10: // 10.0.0.0/8: Private-Use
- return true
- case 127: // 127.0.0.0/8: Loopback
- return true
- case 169: // 169.254.0.0/16: Link Local
- return a[1] == 254 && b[1] == 254
- case 172: // 172.16.0.0/12: Private-Use
- return a[1]&0xf0 == 16 && b[1]&0xf0 == 16
- case 192: // 192.168.0.0/16: Private-Use
- return a[1] == 168 && b[1] == 168
- }
- return false
-}
diff --git a/libgo/go/net/addrselect_test.go b/libgo/go/net/addrselect_test.go
index 80aa4eb195..d6e0e63c3b 100644
--- a/libgo/go/net/addrselect_test.go
+++ b/libgo/go/net/addrselect_test.go
@@ -117,27 +117,6 @@ func TestSortByRFC6724(t *testing.T) {
},
reverse: false,
},
-
- // Prefer longer common prefixes, but only for IPv4 address
- // pairs in the same special-purpose block.
- {
- in: []IPAddr{
- {IP: ParseIP("1.2.3.4")},
- {IP: ParseIP("10.55.0.1")},
- {IP: ParseIP("10.66.0.1")},
- },
- srcs: []IP{
- ParseIP("1.2.3.5"),
- ParseIP("10.66.1.2"),
- ParseIP("10.66.1.2"),
- },
- want: []IPAddr{
- {IP: ParseIP("10.66.0.1")},
- {IP: ParseIP("10.55.0.1")},
- {IP: ParseIP("1.2.3.4")},
- },
- reverse: true,
- },
}
for i, tt := range tests {
inCopy := make([]IPAddr, len(tt.in))
@@ -268,67 +247,3 @@ func TestRFC6724CommonPrefixLength(t *testing.T) {
}
}
-
-func mustParseCIDRs(t *testing.T, blocks ...string) []*IPNet {
- res := make([]*IPNet, len(blocks))
- for i, block := range blocks {
- var err error
- _, res[i], err = ParseCIDR(block)
- if err != nil {
- t.Fatalf("ParseCIDR(%s) failed: %v", block, err)
- }
- }
- return res
-}
-
-func TestSameIPv4SpecialPurposeBlock(t *testing.T) {
- blocks := mustParseCIDRs(t,
- "10.0.0.0/8",
- "127.0.0.0/8",
- "169.254.0.0/16",
- "172.16.0.0/12",
- "192.168.0.0/16",
- )
-
- addrs := []struct {
- ip IP
- block int // index or -1
- }{
- {IP{1, 2, 3, 4}, -1},
- {IP{2, 3, 4, 5}, -1},
- {IP{10, 2, 3, 4}, 0},
- {IP{10, 6, 7, 8}, 0},
- {IP{127, 0, 0, 1}, 1},
- {IP{127, 255, 255, 255}, 1},
- {IP{169, 254, 77, 99}, 2},
- {IP{169, 254, 44, 22}, 2},
- {IP{169, 255, 0, 1}, -1},
- {IP{172, 15, 5, 6}, -1},
- {IP{172, 16, 32, 41}, 3},
- {IP{172, 31, 128, 9}, 3},
- {IP{172, 32, 88, 100}, -1},
- {IP{192, 168, 1, 1}, 4},
- {IP{192, 168, 128, 42}, 4},
- {IP{192, 169, 1, 1}, -1},
- }
-
- for i, addr := range addrs {
- for j, block := range blocks {
- got := block.Contains(addr.ip)
- want := addr.block == j
- if got != want {
- t.Errorf("%d/%d. %s.Contains(%s): got %v, want %v", i, j, block, addr.ip, got, want)
- }
- }
- }
-
- for i, addr1 := range addrs {
- for j, addr2 := range addrs {
- got := sameIPv4SpecialPurposeBlock(addr1.ip, addr2.ip)
- want := addr1.block >= 0 && addr1.block == addr2.block
- if got != want {
- t.Errorf("%d/%d. sameIPv4SpecialPurposeBlock(%s, %s): got %v, want %v", i, j, addr1.ip, addr2.ip, got, want)
- }
- }
- }
-}
diff --git a/libgo/go/net/cgo_android.go b/libgo/go/net/cgo_android.go
index fe9925b840..ab0368d14b 100644
--- a/libgo/go/net/cgo_android.go
+++ b/libgo/go/net/cgo_android.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go
index ae1054b39a..c1adf20cd9 100644
--- a/libgo/go/net/cgo_bsd.go
+++ b/libgo/go/net/cgo_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/cgo_linux.go b/libgo/go/net/cgo_linux.go
index baf207257f..36bac3439f 100644
--- a/libgo/go/net/cgo_linux.go
+++ b/libgo/go/net/cgo_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/cgo_netbsd.go b/libgo/go/net/cgo_netbsd.go
index 8a16871906..1ce0139237 100644
--- a/libgo/go/net/cgo_netbsd.go
+++ b/libgo/go/net/cgo_netbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/cgo_openbsd.go b/libgo/go/net/cgo_openbsd.go
index 183091366c..4610246561 100644
--- a/libgo/go/net/cgo_openbsd.go
+++ b/libgo/go/net/cgo_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/cgo_solaris.go b/libgo/go/net/cgo_solaris.go
index 05811c6c25..bd1e8f3ae8 100644
--- a/libgo/go/net/cgo_solaris.go
+++ b/libgo/go/net/cgo_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go
index b86ff7daf1..51259722ae 100644
--- a/libgo/go/net/cgo_stub.go
+++ b/libgo/go/net/cgo_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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
}
diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go
index f634323ed8..a90aaa904e 100644
--- a/libgo/go/net/cgo_unix.go
+++ b/libgo/go/net/cgo_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -18,6 +18,7 @@ package net
*/
import (
+ "context"
"syscall"
"unsafe"
)
@@ -51,18 +52,31 @@ func (eai addrinfoErrno) Error() string { return bytePtrToString(libc_gai_stre
func (eai addrinfoErrno) Temporary() bool { return eai == syscall.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 syscall.Addrinfo
switch network {
case "": // no hints
@@ -83,11 +97,35 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
hints.Ai_family = syscall.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
+ }
+}
- s := syscall.StringBytePtr(service)
+func cgoLookupServicePort(hints *syscall.Addrinfo, network, service string) (port int, err error) {
+ s, err := syscall.BytePtrFromString(service)
+ if err != nil {
+ return 0, err
+ }
+ // Lowercase the service name in the memory passed to C.
+ for i := 0; i < len(service); i++ {
+ bp := (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(s)) + uintptr(i)))
+ *bp = lowerASCII(*bp)
+ }
var res *syscall.Addrinfo
syscall.Entersyscall()
- gerrno := libc_getaddrinfo(nil, s, &hints, &res)
+ gerrno := libc_getaddrinfo(nil, s, hints, &res)
syscall.Exitsyscall()
if gerrno != 0 {
switch gerrno {
@@ -100,7 +138,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 libc_freeaddrinfo(res)
@@ -109,17 +147,22 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
case syscall.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 syscall.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 cgoPortLookup(result chan<- portLookupResult, hints *syscall.Addrinfo, network, service string) {
+ port, err := cgoLookupServicePort(hints, network, service)
+ result <- portLookupResult{port, err}
}
-func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
+func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) {
acquireThread()
defer releaseThread()
@@ -152,7 +195,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 libc_freeaddrinfo(res)
@@ -181,17 +224,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:
@@ -207,10 +275,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 {
@@ -223,9 +288,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 *syscall.RawSockaddr, salen syscall.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)
@@ -242,16 +324,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 *syscall.RawSockaddr, salen syscall.Socklen_t) {
+ names, err := cgoLookupAddrPTR(addr, sa, salen)
+ result <- reverseLookupResult{names, err}
}
func cgoSockaddr(ip IP, zone string) (*syscall.RawSockaddr, syscall.Socklen_t) {
diff --git a/libgo/go/net/cgo_unix_test.go b/libgo/go/net/cgo_unix_test.go
index 4d5ab23fd3..e861c7aa1f 100644
--- a/libgo/go/net/cgo_unix_test.go
+++ b/libgo/go/net/cgo_unix_test.go
@@ -7,18 +7,76 @@
package net
-import "testing"
+import (
+ "context"
+ "testing"
+)
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(host); err != nil {
+}
+
+func TestCgoLookupIPWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupIP(ctx, "localhost")
+ if !ok {
+ t.Errorf("cgoLookupIP must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPort(t *testing.T) {
+ ctx := context.Background()
+ _, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+ if !ok {
+ t.Errorf("cgoLookupPort must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPortWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+ if !ok {
+ t.Errorf("cgoLookupPort must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPTR(t *testing.T) {
+ ctx := context.Background()
+ _, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+ if !ok {
+ t.Errorf("cgoLookupPTR must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPTRWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+ if !ok {
+ t.Errorf("cgoLookupPTR must not be a placeholder")
+ }
+ if err != nil {
t.Error(err)
}
}
diff --git a/libgo/go/net/conf.go b/libgo/go/net/conf.go
index ddaa978f4f..c10aafe63a 100644
--- a/libgo/go/net/conf.go
+++ b/libgo/go/net/conf.go
@@ -124,16 +124,17 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
}()
}
+ fallbackOrder := hostLookupCgo
if c.netGo {
- return hostLookupFilesDNS
+ fallbackOrder = hostLookupFilesDNS
}
if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
- return hostLookupCgo
+ return fallbackOrder
}
if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
// Don't deal with special form hostnames with backslashes
// or '%'.
- return hostLookupCgo
+ return fallbackOrder
}
// OpenBSD is unique and doesn't use nsswitch.conf.
@@ -154,7 +155,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
return hostLookupDNSFiles
}
if len(lookup) < 1 || len(lookup) > 2 {
- return hostLookupCgo
+ return fallbackOrder
}
switch lookup[0] {
case "bind":
@@ -162,7 +163,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
if lookup[1] == "file" {
return hostLookupDNSFiles
}
- return hostLookupCgo
+ return fallbackOrder
}
return hostLookupDNS
case "file":
@@ -170,26 +171,24 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
if lookup[1] == "bind" {
return hostLookupFilesDNS
}
- return hostLookupCgo
+ return fallbackOrder
}
return hostLookupFiles
default:
- return hostLookupCgo
+ return fallbackOrder
}
}
- hasDot := byteIndex(hostname, '.') != -1
-
// Canonicalize the hostname by removing any trailing dot.
if stringsHasSuffix(hostname, ".") {
hostname = hostname[:len(hostname)-1]
}
if stringsHasSuffixFold(hostname, ".local") {
- // Per RFC 6762, the ".local" TLD is special. And
+ // Per RFC 6762, the ".local" TLD is special. And
// because Go's native resolver doesn't do mDNS or
// similar local resolution mechanisms, assume that
// libc might (via Avahi, etc) and use cgo.
- return hostLookupCgo
+ return fallbackOrder
}
nss := c.nss
@@ -199,7 +198,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
if c.goos == "solaris" {
// illumos defaults to "nis [NOTFOUND=return] files"
- return hostLookupCgo
+ return fallbackOrder
}
if c.goos == "linux" {
// glibc says the default is "dns [!UNAVAIL=return] files"
@@ -212,21 +211,25 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
// We failed to parse or open nsswitch.conf, so
// conservatively assume we should use cgo if it's
// available.
- return hostLookupCgo
+ return fallbackOrder
}
var mdnsSource, filesSource, dnsSource bool
var first string
for _, src := range srcs {
if src.source == "myhostname" {
- if hasDot {
- continue
+ if isLocalhost(hostname) || isGateway(hostname) {
+ return fallbackOrder
}
- return hostLookupCgo
+ hn, err := getHostname()
+ if err != nil || stringsEqualFold(hostname, hn) {
+ return fallbackOrder
+ }
+ continue
}
if src.source == "files" || src.source == "dns" {
if !src.standardCriteria() {
- return hostLookupCgo // non-standard; let libc deal with it.
+ return fallbackOrder // non-standard; let libc deal with it.
}
if src.source == "files" {
filesSource = true
@@ -246,14 +249,14 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
continue
}
// Some source we don't know how to deal with.
- return hostLookupCgo
+ return fallbackOrder
}
// We don't parse mdns.allow files. They're rare. If one
// exists, it might list other TLDs (besides .local) or even
// '*', so just let libc deal with it.
if mdnsSource && c.hasMDNSAllow {
- return hostLookupCgo
+ return fallbackOrder
}
// Cases where Go can handle it without cgo and C thread
@@ -272,7 +275,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
}
// Something weird. Let libc deal with it.
- return hostLookupCgo
+ return fallbackOrder
}
// goDebugNetDNS parses the value of the GODEBUG "netdns" value.
@@ -292,7 +295,7 @@ func goDebugNetDNS() (dnsMode string, debugLevel int) {
return
}
if '0' <= s[0] && s[0] <= '9' {
- debugLevel, _, _ = dtoi(s, 0)
+ debugLevel, _, _ = dtoi(s)
} else {
dnsMode = s
}
@@ -305,3 +308,15 @@ func goDebugNetDNS() (dnsMode string, debugLevel int) {
parsePart(goDebug)
return
}
+
+// isLocalhost reports whether h should be considered a "localhost"
+// name for the myhostname NSS module.
+func isLocalhost(h string) bool {
+ return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
+}
+
+// isGateway reports whether h should be considered a "gateway"
+// name for the myhostname NSS module.
+func isGateway(h string) bool {
+ return stringsEqualFold(h, "gateway")
+}
diff --git a/libgo/go/net/conf_netcgo.go b/libgo/go/net/conf_netcgo.go
index b66bae3710..abc33cee47 100644
--- a/libgo/go/net/conf_netcgo.go
+++ b/libgo/go/net/conf_netcgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/net/conf_test.go b/libgo/go/net/conf_test.go
index 86904bffde..17d03f4b5f 100644
--- a/libgo/go/net/conf_test.go
+++ b/libgo/go/net/conf_test.go
@@ -13,8 +13,9 @@ import (
)
type nssHostTest struct {
- host string
- want hostLookupOrder
+ host string
+ localhost string
+ want hostLookupOrder
}
func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) }
@@ -32,7 +33,6 @@ func TestConfHostLookupOrder(t *testing.T) {
tests := []struct {
name string
c *conf
- goos string
hostTests []nssHostTest
}{
{
@@ -43,8 +43,30 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"foo.local", hostLookupCgo},
- {"google.com", hostLookupCgo},
+ {"foo.local", "myhostname", hostLookupCgo},
+ {"google.com", "myhostname", hostLookupCgo},
+ },
+ },
+ {
+ name: "netgo_dns_before_files",
+ c: &conf{
+ netGo: true,
+ nss: nssStr("hosts: dns files"),
+ resolv: defaultResolvConf,
+ },
+ hostTests: []nssHostTest{
+ {"x.com", "myhostname", hostLookupDNSFiles},
+ },
+ },
+ {
+ name: "netgo_fallback_on_cgo",
+ c: &conf{
+ netGo: true,
+ nss: nssStr("hosts: dns files something_custom"),
+ resolv: defaultResolvConf,
+ },
+ hostTests: []nssHostTest{
+ {"x.com", "myhostname", hostLookupFilesDNS},
},
},
{
@@ -54,11 +76,11 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"foo.local", hostLookupCgo},
- {"foo.local.", hostLookupCgo},
- {"foo.LOCAL", hostLookupCgo},
- {"foo.LOCAL.", hostLookupCgo},
- {"google.com", hostLookupFilesDNS},
+ {"foo.local", "myhostname", hostLookupCgo},
+ {"foo.local.", "myhostname", hostLookupCgo},
+ {"foo.LOCAL", "myhostname", hostLookupCgo},
+ {"foo.LOCAL.", "myhostname", hostLookupCgo},
+ {"google.com", "myhostname", hostLookupFilesDNS},
},
},
{
@@ -68,7 +90,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: nssStr("foo: bar"),
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
},
// On OpenBSD, no resolv.conf means no DNS.
{
@@ -77,7 +99,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
},
{
name: "solaris_no_nsswitch",
@@ -86,7 +108,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_bind_file",
@@ -95,8 +117,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: &dnsConfig{lookup: []string{"bind", "file"}},
},
hostTests: []nssHostTest{
- {"google.com", hostLookupDNSFiles},
- {"foo.local", hostLookupDNSFiles},
+ {"google.com", "myhostname", hostLookupDNSFiles},
+ {"foo.local", "myhostname", hostLookupDNSFiles},
},
},
{
@@ -105,7 +127,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "bind"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
},
{
name: "openbsd_lookup_bind",
@@ -113,7 +135,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"bind"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNS}},
},
{
name: "openbsd_lookup_file",
@@ -121,7 +143,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
},
{
name: "openbsd_lookup_yp",
@@ -129,7 +151,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_two",
@@ -137,7 +159,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "foo"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_empty",
@@ -145,7 +167,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: nil},
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}},
},
// glibc lacking an nsswitch.conf, per
// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html
@@ -156,7 +178,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}},
},
{
name: "files_mdns_dns",
@@ -165,8 +187,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -176,9 +198,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNS},
- {"x\\.com", hostLookupCgo}, // punt on weird glibc escape
- {"foo.com%en0", hostLookupCgo}, // and IPv6 zones
+ {"x.com", "myhostname", hostLookupDNS},
+ {"x\\.com", "myhostname", hostLookupCgo}, // punt on weird glibc escape
+ {"foo.com%en0", "myhostname", hostLookupCgo}, // and IPv6 zones
},
},
{
@@ -189,8 +211,8 @@ func TestConfHostLookupOrder(t *testing.T) {
hasMDNSAllow: true,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -200,9 +222,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"x", hostLookupFilesDNS},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"x", "myhostname", hostLookupFilesDNS},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -212,9 +234,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNSFiles},
- {"x", hostLookupDNSFiles},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupDNSFiles},
+ {"x", "myhostname", hostLookupDNSFiles},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -224,7 +246,7 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
},
},
{
@@ -234,8 +256,23 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"somehostname", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"myhostname", "myhostname", hostLookupCgo},
+ {"myHostname", "myhostname", hostLookupCgo},
+ {"myhostname.dot", "myhostname.dot", hostLookupCgo},
+ {"myHostname.dot", "myhostname.dot", hostLookupCgo},
+ {"gateway", "myhostname", hostLookupCgo},
+ {"Gateway", "myhostname", hostLookupCgo},
+ {"localhost", "myhostname", hostLookupCgo},
+ {"Localhost", "myhostname", hostLookupCgo},
+ {"anything.localhost", "myhostname", hostLookupCgo},
+ {"Anything.localhost", "myhostname", hostLookupCgo},
+ {"localhost.localdomain", "myhostname", hostLookupCgo},
+ {"Localhost.Localdomain", "myhostname", hostLookupCgo},
+ {"anything.localhost.localdomain", "myhostname", hostLookupCgo},
+ {"Anything.Localhost.Localdomain", "myhostname", hostLookupCgo},
+ {"somehostname", "myhostname", hostLookupFilesDNS},
+ {"", "myhostname", hostLookupFilesDNS}, // Issue 13623
},
},
{
@@ -245,8 +282,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"somehostname", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"somehostname", "myhostname", hostLookupFilesDNS},
+ {"myhostname", "myhostname", hostLookupCgo},
},
},
// Debian Squeeze is just "dns,files", but lists all
@@ -260,8 +298,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNSFiles},
- {"somehostname", hostLookupDNSFiles},
+ {"x.com", "myhostname", hostLookupDNSFiles},
+ {"somehostname", "myhostname", hostLookupDNSFiles},
},
},
{
@@ -270,7 +308,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: nssStr("foo: bar"),
resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
// Android should always use cgo.
{
@@ -281,12 +319,18 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
},
},
}
+
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+
for _, tt := range tests {
for _, ht := range tt.hostTests {
+ getHostname = func() (string, error) { return ht.localhost, nil }
+
gotOrder := tt.c.hostLookupOrder(ht.host)
if gotOrder != ht.want {
t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want)
diff --git a/libgo/go/net/conn_test.go b/libgo/go/net/conn_test.go
index 6995c110f2..16cf69ee16 100644
--- a/libgo/go/net/conn_test.go
+++ b/libgo/go/net/conn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -43,7 +43,7 @@ func TestConnAndListener(t *testing.T) {
t.Fatal(err)
}
defer c.Close()
- if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+ if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
}
c.SetDeadline(time.Now().Add(someTimeout))
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 193776fe41..50bba5a49e 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -1,11 +1,12 @@
-// Copyright 2010 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 net
import (
- "errors"
+ "context"
+ "internal/nettrace"
"time"
)
@@ -58,24 +59,47 @@ type Dialer struct {
// that do not support keep-alives ignore this field.
KeepAlive time.Duration
+ // Resolver optionally specifies an alternate resolver to use.
+ Resolver *Resolver
+
// Cancel is an optional channel whose closure indicates that
// the dial should be canceled. Not all types of dials support
// cancelation.
+ //
+ // Deprecated: Use DialContext instead.
Cancel <-chan struct{}
}
-// Return either now+Timeout or Deadline, whichever comes first.
-// Or zero, if neither is set.
-func (d *Dialer) deadline(now time.Time) time.Time {
- if d.Timeout == 0 {
- return d.Deadline
+func minNonzeroTime(a, b time.Time) time.Time {
+ if a.IsZero() {
+ return b
}
- timeoutDeadline := now.Add(d.Timeout)
- if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
- return timeoutDeadline
- } else {
- return d.Deadline
+ if b.IsZero() || a.Before(b) {
+ return a
+ }
+ return b
+}
+
+// deadline returns the earliest of:
+// - now+Timeout
+// - d.Deadline
+// - the context's deadline
+// Or zero, if none of Timeout, Deadline, or context's deadline is set.
+func (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Time) {
+ if d.Timeout != 0 { // including negative, for historical reasons
+ earliest = now.Add(d.Timeout)
+ }
+ if d, ok := ctx.Deadline(); ok {
+ earliest = minNonzeroTime(earliest, d)
+ }
+ return minNonzeroTime(earliest, d.Deadline)
+}
+
+func (d *Dialer) resolver() *Resolver {
+ if d.Resolver != nil {
+ return d.Resolver
}
+ return DefaultResolver
}
// partialDeadline returns the deadline to use for a single address,
@@ -110,7 +134,7 @@ func (d *Dialer) fallbackDelay() time.Duration {
}
}
-func parseNetwork(net string) (afnet string, proto int, err error) {
+func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err error) {
i := last(net, ':')
if i < 0 { // no colon
switch net {
@@ -127,9 +151,9 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
switch afnet {
case "ip", "ip4", "ip6":
protostr := net[i+1:]
- proto, i, ok := dtoi(protostr, 0)
+ proto, i, ok := dtoi(protostr)
if !ok || i != len(protostr) {
- proto, err = lookupProtocol(protostr)
+ proto, err = lookupProtocol(ctx, protostr)
if err != nil {
return "", 0, err
}
@@ -139,8 +163,11 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
return "", 0, UnknownNetworkError(net)
}
-func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
- afnet, _, err := parseNetwork(net)
+// resolveAddrList resolves addr using hint and returns a list of
+// addresses. The result contains at least one address when error is
+// nil.
+func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
+ afnet, _, err := parseNetwork(ctx, network)
if err != nil {
return nil, err
}
@@ -153,9 +180,59 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
if err != nil {
return nil, err
}
+ if op == "dial" && hint != nil && addr.Network() != hint.Network() {
+ return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
+ }
return addrList{addr}, nil
}
- return internetAddrList(afnet, addr, deadline)
+ addrs, err := r.internetAddrList(ctx, afnet, addr)
+ if err != nil || op != "dial" || hint == nil {
+ return addrs, err
+ }
+ var (
+ tcp *TCPAddr
+ udp *UDPAddr
+ ip *IPAddr
+ wildcard bool
+ )
+ switch hint := hint.(type) {
+ case *TCPAddr:
+ tcp = hint
+ wildcard = tcp.isWildcard()
+ case *UDPAddr:
+ udp = hint
+ wildcard = udp.isWildcard()
+ case *IPAddr:
+ ip = hint
+ wildcard = ip.isWildcard()
+ }
+ naddrs := addrs[:0]
+ for _, addr := range addrs {
+ if addr.Network() != hint.Network() {
+ return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
+ }
+ switch addr := addr.(type) {
+ case *TCPAddr:
+ if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(tcp.IP) {
+ continue
+ }
+ naddrs = append(naddrs, addr)
+ case *UDPAddr:
+ if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(udp.IP) {
+ continue
+ }
+ naddrs = append(naddrs, addr)
+ case *IPAddr:
+ if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(ip.IP) {
+ continue
+ }
+ naddrs = append(naddrs, addr)
+ }
+ }
+ if len(naddrs) == 0 {
+ return nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: hint.String()}
+ }
+ return naddrs, nil
}
// Dial connects to the address on the named network.
@@ -173,8 +250,8 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
// 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")
@@ -184,10 +261,13 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
// 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.
+//
+// If the host is resolved to multiple addresses,
+// Dial will try each address in order until one succeeds.
func Dial(network, address string) (Conn, error) {
var d Dialer
return d.Dial(network, address)
@@ -200,11 +280,10 @@ func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
return d.Dial(network, address)
}
-// dialContext holds common state for all dial operations.
-type dialContext struct {
+// dialParam contains a Dial's parameters and configuration.
+type dialParam struct {
Dialer
network, address string
- finalDeadline time.Time
}
// Dial connects to the address on the named network.
@@ -212,17 +291,70 @@ type dialContext struct {
// See func Dial for a description of the network and address
// parameters.
func (d *Dialer) Dial(network, address string) (Conn, error) {
- finalDeadline := d.deadline(time.Now())
- addrs, err := resolveAddrList("dial", network, address, finalDeadline)
+ return d.DialContext(context.Background(), network, address)
+}
+
+// DialContext connects to the address on the named network using
+// the provided context.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// When using TCP, and the host in the address parameter resolves to multiple
+// network addresses, any dial timeout (from d.Timeout or ctx) is spread
+// over each consecutive dial, such that each is given an appropriate
+// fraction of the time to connect.
+// For example, if a host has 4 IP addresses and the timeout is 1 minute,
+// the connect to each single address will be given 15 seconds to complete
+// before trying the next one.
+//
+// See func Dial for a description of the network and address
+// parameters.
+func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
+ if ctx == nil {
+ panic("nil context")
+ }
+ deadline := d.deadline(ctx, time.Now())
+ if !deadline.IsZero() {
+ if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
+ subCtx, cancel := context.WithDeadline(ctx, deadline)
+ defer cancel()
+ ctx = subCtx
+ }
+ }
+ if oldCancel := d.Cancel; oldCancel != nil {
+ subCtx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ go func() {
+ select {
+ case <-oldCancel:
+ cancel()
+ case <-subCtx.Done():
+ }
+ }()
+ ctx = subCtx
+ }
+
+ // 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 := d.resolver().resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
}
- ctx := &dialContext{
- Dialer: *d,
- network: network,
- address: address,
- finalDeadline: finalDeadline,
+ dp := &dialParam{
+ Dialer: *d,
+ network: network,
+ address: address,
}
var primaries, fallbacks addrList
@@ -233,116 +365,128 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
}
var c Conn
- if len(fallbacks) == 0 {
- // dialParallel can accept an empty fallbacks list,
- // but this shortcut avoids the goroutine/channel overhead.
- c, err = dialSerial(ctx, primaries, nil)
+ if len(fallbacks) > 0 {
+ c, err = dialParallel(ctx, dp, primaries, fallbacks)
} else {
- c, err = dialParallel(ctx, primaries, fallbacks)
+ c, err = dialSerial(ctx, dp, primaries)
+ }
+ if err != nil {
+ return nil, err
}
- if d.KeepAlive > 0 && err == nil {
- if tc, ok := c.(*TCPConn); ok {
- setKeepAlive(tc.fd, true)
- setKeepAlivePeriod(tc.fd, d.KeepAlive)
- testHookSetKeepAlive()
- }
+ if tc, ok := c.(*TCPConn); ok && d.KeepAlive > 0 {
+ setKeepAlive(tc.fd, true)
+ setKeepAlivePeriod(tc.fd, d.KeepAlive)
+ testHookSetKeepAlive()
}
- return c, err
+ return c, nil
}
// dialParallel races two copies of dialSerial, giving the first a
// head start. It returns the first established connection and
// closes the others. Otherwise it returns an error from the first
// primary address.
-func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) {
- results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup
- cancel := make(chan struct{})
- defer close(cancel)
-
- // Spawn the primary racer.
- go dialSerialAsync(ctx, primaries, nil, cancel, results)
-
- // Spawn the fallback racer.
- fallbackTimer := time.NewTimer(ctx.fallbackDelay())
- go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results)
-
- var primaryErr error
- for nracers := 2; nracers > 0; nracers-- {
- res := <-results
- // If we're still waiting for a connection, then hasten the delay.
- // Otherwise, disable the Timer and let cancel take over.
- if fallbackTimer.Stop() && res.error != nil {
- fallbackTimer.Reset(0)
- }
- if res.error == nil {
- return res.Conn, nil
- }
- if res.primary {
- primaryErr = res.error
- }
+func dialParallel(ctx context.Context, dp *dialParam, primaries, fallbacks addrList) (Conn, error) {
+ if len(fallbacks) == 0 {
+ return dialSerial(ctx, dp, primaries)
}
- return nil, primaryErr
-}
-type dialResult struct {
- Conn
- error
- primary bool
-}
+ returned := make(chan struct{})
+ defer close(returned)
+
+ type dialResult struct {
+ Conn
+ error
+ primary bool
+ done bool
+ }
+ results := make(chan dialResult) // unbuffered
-// dialSerialAsync runs dialSerial after some delay, and returns the
-// resulting connection through a channel. When racing two connections,
-// the primary goroutine uses a nil timer to omit the delay.
-func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <-chan struct{}, results chan<- dialResult) {
- if timer != nil {
- // We're in the fallback goroutine; sleep before connecting.
+ startRacer := func(ctx context.Context, primary bool) {
+ ras := primaries
+ if !primary {
+ ras = fallbacks
+ }
+ c, err := dialSerial(ctx, dp, ras)
select {
- case <-timer.C:
- case <-cancel:
- return
+ case results <- dialResult{Conn: c, error: err, primary: primary, done: true}:
+ case <-returned:
+ if c != nil {
+ c.Close()
+ }
}
}
- c, err := dialSerial(ctx, ras, cancel)
- select {
- case results <- dialResult{c, err, timer == nil}:
- // We won the race.
- case <-cancel:
- // The other goroutine won the race.
- if c != nil {
- c.Close()
+
+ var primary, fallback dialResult
+
+ // Start the main racer.
+ primaryCtx, primaryCancel := context.WithCancel(ctx)
+ defer primaryCancel()
+ go startRacer(primaryCtx, true)
+
+ // Start the timer for the fallback racer.
+ fallbackTimer := time.NewTimer(dp.fallbackDelay())
+ defer fallbackTimer.Stop()
+
+ for {
+ select {
+ case <-fallbackTimer.C:
+ fallbackCtx, fallbackCancel := context.WithCancel(ctx)
+ defer fallbackCancel()
+ go startRacer(fallbackCtx, false)
+
+ case res := <-results:
+ if res.error == nil {
+ return res.Conn, nil
+ }
+ if res.primary {
+ primary = res
+ } else {
+ fallback = res
+ }
+ if primary.done && fallback.done {
+ return nil, primary.error
+ }
+ if res.primary && fallbackTimer.Stop() {
+ // If we were able to stop the timer, that means it
+ // was running (hadn't yet started the fallback), but
+ // we just got an error on the primary path, so start
+ // the fallback immediately (in 0 nanoseconds).
+ fallbackTimer.Reset(0)
+ }
}
}
}
// dialSerial connects to a list of addresses in sequence, returning
// either the first successful connection, or the first error.
-func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, error) {
+func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (Conn, error) {
var firstErr error // The error from the first address is most relevant.
for i, ra := range ras {
select {
- case <-cancel:
- return nil, &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: errCanceled}
+ case <-ctx.Done():
+ return nil, &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())}
default:
}
- partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i)
+ deadline, _ := ctx.Deadline()
+ partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i)
if err != nil {
// Ran out of time.
if firstErr == nil {
- firstErr = &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: err}
+ firstErr = &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: err}
}
break
}
-
- // dialTCP does not support cancelation (see golang.org/issue/11225),
- // so if cancel fires, we'll continue trying to connect until the next
- // timeout, or return a spurious connection for the caller to close.
- dialer := func(d time.Time) (Conn, error) {
- return dialSingle(ctx, ra, d)
+ dialCtx := ctx
+ if partialDeadline.Before(deadline) {
+ var cancel context.CancelFunc
+ dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
+ defer cancel()
}
- c, err := dial(ctx.network, ra, dialer, partialDeadline)
+
+ c, err := dialSingle(dialCtx, dp, ra)
if err == nil {
return c, nil
}
@@ -352,37 +496,43 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e
}
if firstErr == nil {
- firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress}
+ firstErr = &OpError{Op: "dial", Net: dp.network, Source: nil, Addr: nil, Err: errMissingAddress}
}
return nil, firstErr
}
// dialSingle attempts to establish and returns a single connection to
-// the destination address. This must be called through the OS-specific
-// dial function, because some OSes don't implement the deadline feature.
-func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) {
- la := ctx.LocalAddr
- if la != nil && la.Network() != ra.Network() {
- return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
+// the destination address.
+func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) {
+ trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
+ if trace != nil {
+ raStr := ra.String()
+ if trace.ConnectStart != nil {
+ trace.ConnectStart(dp.network, raStr)
+ }
+ if trace.ConnectDone != nil {
+ defer func() { trace.ConnectDone(dp.network, raStr, err) }()
+ }
}
+ la := dp.LocalAddr
switch ra := ra.(type) {
case *TCPAddr:
la, _ := la.(*TCPAddr)
- c, err = testHookDialTCP(ctx.network, la, ra, deadline, ctx.Cancel)
+ c, err = dialTCP(ctx, dp.network, la, ra)
case *UDPAddr:
la, _ := la.(*UDPAddr)
- c, err = dialUDP(ctx.network, la, ra, deadline)
+ c, err = dialUDP(ctx, dp.network, la, ra)
case *IPAddr:
la, _ := la.(*IPAddr)
- c, err = dialIP(ctx.network, la, ra, deadline)
+ c, err = dialIP(ctx, dp.network, la, ra)
case *UnixAddr:
la, _ := la.(*UnixAddr)
- c, err = dialUnix(ctx.network, la, ra, deadline)
+ c, err = dialUnix(ctx, dp.network, la, ra)
default:
- return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}}
+ return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: dp.address}}
}
if err != nil {
- return nil, err // c is non-nil interface containing nil pointer
+ return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: err} // c is non-nil interface containing nil pointer
}
return c, nil
}
@@ -394,8 +544,11 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
// If host is omitted, as in ":8080", Listen listens on all available interfaces
// instead of just the interface with the given host address.
// See Dial for more details about address syntax.
+//
+// Listening on a hostname is not recommended because this creates a socket
+// for at most one of its IP addresses.
func Listen(net, laddr string) (Listener, error) {
- addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+ addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", net, laddr, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
}
@@ -421,8 +574,11 @@ func Listen(net, laddr string) (Listener, error) {
// If host is omitted, as in ":8080", ListenPacket listens on all available interfaces
// instead of just the interface with the given host address.
// See Dial for the syntax of laddr.
+//
+// Listening on a hostname is not recommended because this creates a socket
+// for at most one of its IP addresses.
func ListenPacket(net, laddr string) (PacketConn, error) {
- addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+ addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", net, laddr, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
}
diff --git a/libgo/go/net/dial_gen.go b/libgo/go/net/dial_gen.go
deleted file mode 100644
index a628f71483..0000000000
--- a/libgo/go/net/dial_gen.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows plan9
-
-package net
-
-import "time"
-
-// dialChannel is the simple pure-Go implementation of dial, still
-// used on operating systems where the deadline hasn't been pushed
-// down into the pollserver. (Plan 9 and some old versions of Windows)
-func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
- if deadline.IsZero() {
- return dialer(noDeadline)
- }
- timeout := deadline.Sub(time.Now())
- if timeout <= 0 {
- return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
- }
- t := time.NewTimer(timeout)
- defer t.Stop()
- type racer struct {
- Conn
- error
- }
- ch := make(chan racer, 1)
- go func() {
- testHookDialChannel()
- c, err := dialer(noDeadline)
- ch <- racer{c, err}
- }()
- select {
- case <-t.C:
- return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
- case racer := <-ch:
- return racer.Conn, racer.error
- }
-}
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
index 2311b10824..9919d72ce3 100644
--- a/libgo/go/net/dial_test.go
+++ b/libgo/go/net/dial_test.go
@@ -5,6 +5,8 @@
package net
import (
+ "bufio"
+ "context"
"internal/testenv"
"io"
"net/internal/socktest"
@@ -23,13 +25,12 @@ var prohibitionaryDialArgTests = []struct {
}
func TestProhibitionaryDialArg(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
if !supportsIPv4map {
t.Skip("mapping ipv4 address inside ipv6 address not supported")
}
@@ -54,56 +55,29 @@ func TestProhibitionaryDialArg(t *testing.T) {
}
}
-func TestSelfConnect(t *testing.T) {
- if runtime.GOOS == "windows" {
- // TODO(brainman): do not know why it hangs.
- t.Skip("known-broken test on windows")
+func TestDialLocal(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
}
-
- // Test that Dial does not honor self-connects.
- // See the comment in DialTCP.
-
- // Find a port that would be used as a local address.
- l, err := Listen("tcp", "127.0.0.1:0")
+ defer ln.Close()
+ _, port, err := SplitHostPort(ln.Addr().String())
if err != nil {
t.Fatal(err)
}
- c, err := Dial("tcp", l.Addr().String())
+ c, err := Dial("tcp", JoinHostPort("", port))
if err != nil {
t.Fatal(err)
}
- addr := c.LocalAddr().String()
c.Close()
- l.Close()
-
- // Try to connect to that address repeatedly.
- n := 100000
- if testing.Short() {
- n = 1000
- }
- switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
- // Non-Linux systems take a long time to figure
- // out that there is nothing listening on localhost.
- n = 100
- }
- for i := 0; i < n; i++ {
- c, err := DialTimeout("tcp", addr, time.Millisecond)
- if err == nil {
- if c.LocalAddr().String() == addr {
- t.Errorf("#%d: Dial %q self-connect", i, addr)
- } else {
- t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
- }
- c.Close()
- }
- }
}
func TestDialTimeoutFDLeak(t *testing.T) {
switch runtime.GOOS {
case "plan9":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+ case "openbsd":
+ testenv.SkipFlaky(t, 15157)
}
const T = 100 * time.Millisecond
@@ -130,17 +104,14 @@ func TestDialTimeoutFDLeak(t *testing.T) {
// socktest.Switch.
// It may happen when the Dial call bumps against TCP
// simultaneous open. See selfConnect in tcpsock_posix.go.
- defer func() {
- sw.Set(socktest.FilterClose, nil)
- forceCloseSockets()
- }()
+ defer func() { sw.Set(socktest.FilterClose, nil) }()
var mu sync.Mutex
var attempts int
sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
mu.Lock()
attempts++
mu.Unlock()
- return nil, errTimedout
+ return nil, nil
})
const N = 100
@@ -171,11 +142,19 @@ 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 }()
testHookLookupIP = lookupLocalhost
@@ -188,24 +167,19 @@ 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)
}
- defer dss.teardown()
if err := dss.buildup(handler); err != nil {
+ dss.teardown()
t.Fatal(err)
}
- before := sw.Sockets()
- const T = 100 * time.Millisecond
const N = 10
var wg sync.WaitGroup
wg.Add(N)
- d := &Dialer{DualStack: true, Timeout: T}
+ d := &Dialer{DualStack: true, Timeout: 100*time.Millisecond + closedPortDelay}
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
@@ -218,7 +192,7 @@ func TestDialerDualStackFDLeak(t *testing.T) {
}()
}
wg.Wait()
- time.Sleep(2 * T) // wait for the dial racers to stop
+ dss.teardown()
after := sw.Sockets()
if len(after) != len(before) {
t.Errorf("got %d; want %d", len(after), len(before))
@@ -229,18 +203,18 @@ func TestDialerDualStackFDLeak(t *testing.T) {
// expected to hang until the timeout elapses. These addresses are reserved
// for benchmarking by RFC 6890.
const (
- slowDst4 = "192.18.0.254"
- slowDst6 = "2001:2::254"
- slowTimeout = 1 * time.Second
+ slowDst4 = "198.18.0.254"
+ slowDst6 = "2001:2::254"
)
// In some environments, the slow IPs may be explicitly unreachable, and fail
// more quickly than expected. This test hook prevents dialTCP from returning
// before the deadline.
-func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
- c, err := dialTCP(net, laddr, raddr, deadline, cancel)
+func slowDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ c, err := doDialTCP(ctx, net, laddr, raddr)
if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
- time.Sleep(deadline.Sub(time.Now()))
+ // Wait for the deadline, or indefinitely if none exists.
+ <-ctx.Done()
}
return c, err
}
@@ -278,9 +252,8 @@ func dialClosedPort() (actual, expected time.Duration) {
}
func TestDialParallel(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
@@ -294,7 +267,7 @@ func TestDialParallel(t *testing.T) {
const fallbackDelay = 200 * time.Millisecond
// Some cases will run quickly when "connection refused" is fast,
- // or trigger the fallbackDelay on Windows. This value holds the
+ // or trigger the fallbackDelay on Windows. This value holds the
// lesser of the two delays.
var closedPortOrFallbackDelay time.Duration
if closedPortDelay < fallbackDelay {
@@ -369,10 +342,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)
}
@@ -389,17 +359,15 @@ func TestDialParallel(t *testing.T) {
fallbacks := makeAddrs(tt.fallbacks, dss.port)
d := Dialer{
FallbackDelay: fallbackDelay,
- Timeout: slowTimeout,
- }
- ctx := &dialContext{
- Dialer: d,
- network: "tcp",
- address: "?",
- finalDeadline: d.deadline(time.Now()),
}
startTime := time.Now()
- c, err := dialParallel(ctx, primaries, fallbacks)
- elapsed := time.Now().Sub(startTime)
+ dp := &dialParam{
+ Dialer: d,
+ network: "tcp",
+ address: "?",
+ }
+ c, err := dialParallel(context.Background(), dp, primaries, fallbacks)
+ elapsed := time.Since(startTime)
if c != nil {
c.Close()
@@ -418,12 +386,30 @@ func TestDialParallel(t *testing.T) {
} else if !(elapsed <= expectElapsedMax) {
t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
}
+
+ // Repeat each case, ensuring that it can be canceled quickly.
+ ctx, cancel := context.WithCancel(context.Background())
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ time.Sleep(5 * time.Millisecond)
+ cancel()
+ wg.Done()
+ }()
+ startTime = time.Now()
+ c, err = dialParallel(ctx, dp, primaries, fallbacks)
+ if c != nil {
+ c.Close()
+ }
+ elapsed = time.Now().Sub(startTime)
+ if elapsed > 100*time.Millisecond {
+ t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed)
+ }
+ wg.Wait()
}
- // Wait for any slowDst4/slowDst6 connections to timeout.
- time.Sleep(slowTimeout * 3 / 2)
}
-func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+func lookupSlowFast(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
switch host {
case "slow6loopback4":
// Returns a slow IPv6 address, and a local IPv4 address.
@@ -432,14 +418,13 @@ func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, e
{IP: ParseIP("127.0.0.1")},
}, nil
default:
- return fn(host)
+ return fn(ctx, host)
}
}
func TestDialerFallbackDelay(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
@@ -463,8 +448,6 @@ func TestDialerFallbackDelay(t *testing.T) {
{true, 200 * time.Millisecond, 200 * time.Millisecond},
// The default is 300ms.
{true, 0, 300 * time.Millisecond},
- // This case is last, in order to wait for hanging slowDst6 connections.
- {false, 0, slowTimeout},
}
handler := func(dss *dualStackServer, ln Listener) {
@@ -476,9 +459,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)
}
@@ -488,7 +469,7 @@ func TestDialerFallbackDelay(t *testing.T) {
}
for i, tt := range testCases {
- d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
+ d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
startTime := time.Now()
c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
@@ -509,46 +490,78 @@ func TestDialerFallbackDelay(t *testing.T) {
}
}
-func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932")
+func TestDialParallelSpuriousConnection(t *testing.T) {
+ if !supportsIPv4 || !supportsIPv6 {
+ t.Skip("both IPv4 and IPv6 are required")
}
- ln, err := newLocalListener("tcp")
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ handler := func(dss *dualStackServer, ln Listener) {
+ // Accept one connection per address.
+ c, err := ln.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ // The client should close itself, without sending data.
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
+ var b [1]byte
+ if _, err := c.Read(b[:]); err != io.EOF {
+ t.Errorf("got %v; want %v", err, io.EOF)
+ }
+ c.Close()
+ wg.Done()
+ }
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
- defer ln.Close()
+ defer dss.teardown()
+ if err := dss.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
+
+ const fallbackDelay = 100 * time.Millisecond
+
+ origTestHookDialTCP := testHookDialTCP
+ defer func() { testHookDialTCP = origTestHookDialTCP }()
+ testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation.
+ // This forces dialParallel to juggle two successful connections.
+ time.Sleep(fallbackDelay * 2)
- d := Dialer{}
- ctx := &dialContext{
- Dialer: d,
- network: "tcp",
- address: "?",
- finalDeadline: d.deadline(time.Now()),
+ // Now ignore the provided context (which will be canceled) and use a
+ // different one to make sure this completes with a valid connection,
+ // which we hope to be closed below:
+ return doDialTCP(context.Background(), net, laddr, raddr)
}
- results := make(chan dialResult)
- cancel := make(chan struct{})
+ d := Dialer{
+ FallbackDelay: fallbackDelay,
+ }
+ dp := &dialParam{
+ Dialer: d,
+ network: "tcp",
+ address: "?",
+ }
- // Spawn a connection in the background.
- go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
+ makeAddr := func(ip string) addrList {
+ addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
+ if err != nil {
+ t.Fatal(err)
+ }
+ return addrList{addr}
+ }
- // Receive it at the server.
- c, err := ln.Accept()
+ // dialParallel returns one connection (and closes the other.)
+ c, err := dialParallel(context.Background(), dp, makeAddr("127.0.0.1"), makeAddr("::1"))
if err != nil {
t.Fatal(err)
}
- defer c.Close()
-
- // Tell dialSerialAsync that someone else won the race.
- close(cancel)
+ c.Close()
- // The connection should close itself, without sending data.
- c.SetReadDeadline(time.Now().Add(1 * time.Second))
- var b [1]byte
- if _, err := c.Read(b[:]); err != io.EOF {
- t.Errorf("got %v; want %v", err, io.EOF)
- }
+ // The server should've seen both connections.
+ wg.Wait()
}
func TestDialerPartialDeadline(t *testing.T) {
@@ -587,44 +600,125 @@ func TestDialerPartialDeadline(t *testing.T) {
}
func TestDialerLocalAddr(t *testing.T) {
- ch := make(chan error, 1)
- handler := func(ls *localServer, ln Listener) {
- c, err := ln.Accept()
- if err != nil {
- ch <- err
- return
- }
- defer c.Close()
- ch <- nil
- }
- ls, err := newLocalServer("tcp")
- if err != nil {
- t.Fatal(err)
+ if !supportsIPv4 || !supportsIPv6 {
+ t.Skip("both IPv4 and IPv6 are required")
}
- defer ls.teardown()
- if err := ls.buildup(handler); err != nil {
- t.Fatal(err)
+
+ 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 {
+ tests = append(tests, test{
+ "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
+ })
+ } else {
+ tests = append(tests, test{
+ "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
+ })
}
- laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
- if err != nil {
- t.Fatal(err)
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
+ handler := func(ls *localServer, ln Listener) {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ c.Close()
+ }
}
- laddr.Port = 0
- d := &Dialer{LocalAddr: laddr}
- c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
- if err != nil {
- t.Fatal(err)
+ var err error
+ var lss [2]*localServer
+ for i, network := range []string{"tcp4", "tcp6"} {
+ lss[i], err = newLocalServer(network)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer lss[i].teardown()
+ if err := lss[i].buildup(handler); err != nil {
+ t.Fatal(err)
+ }
}
- defer c.Close()
- c.Read(make([]byte, 1))
- err = <-ch
- if err != nil {
- t.Error(err)
+
+ for _, tt := range tests {
+ d := &Dialer{LocalAddr: tt.laddr}
+ var addr string
+ ip := ParseIP(tt.raddr)
+ if ip.To4() != nil {
+ addr = lss[0].Listener.Addr().String()
+ }
+ if ip.To16() != nil && ip.To4() == nil {
+ addr = lss[1].Listener.Addr().String()
+ }
+ c, err := d.Dial(tt.network, addr)
+ if err == nil && tt.error != nil || err != nil && tt.error == nil {
+ t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
+ }
+ if err != nil {
+ if perr := parseDialError(err); perr != nil {
+ t.Error(perr)
+ }
+ continue
+ }
+ c.Close()
}
}
func TestDialerDualStack(t *testing.T) {
+ // This test is known to be flaky. Don't frighten regular
+ // users about it; only fail on the build dashboard.
+ if testenv.Builder() == "" {
+ testenv.SkipFlaky(t, 13324)
+ }
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
@@ -649,10 +743,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)
}
@@ -677,7 +768,6 @@ func TestDialerDualStack(t *testing.T) {
c.Close()
}
}
- time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
}
func TestDialerKeepAlive(t *testing.T) {
@@ -719,14 +809,16 @@ func TestDialerKeepAlive(t *testing.T) {
}
func TestDialCancel(t *testing.T) {
- if runtime.GOOS == "plan9" || runtime.GOOS == "nacl" {
- // plan9 is not implemented and nacl doesn't have
- // external network access.
- t.Skipf("skipping on %s", runtime.GOOS)
+ switch testenv.Builder() {
+ case "linux-arm64-buildlet":
+ t.Skip("skipping on linux-arm64-buildlet; incompatible network config? issue 15191")
+ case "":
+ testenv.MustHaveExternalNetwork(t)
}
- onGoBuildFarm := testenv.Builder() != ""
- if testing.Short() && !onGoBuildFarm {
- t.Skip("skipping in short mode")
+
+ if runtime.GOOS == "nacl" {
+ // nacl doesn't have external network access.
+ t.Skipf("skipping on %s", runtime.GOOS)
}
blackholeIPPort := JoinHostPort(slowDst4, "1234")
@@ -781,3 +873,84 @@ func TestDialCancel(t *testing.T) {
}
}
}
+
+func TestCancelAfterDial(t *testing.T) {
+ if testing.Short() {
+ t.Skip("avoiding time.Sleep")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ defer func() {
+ ln.Close()
+ wg.Wait()
+ }()
+
+ // Echo back the first line of each incoming connection.
+ go func() {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ break
+ }
+ rb := bufio.NewReader(c)
+ line, err := rb.ReadString('\n')
+ if err != nil {
+ t.Error(err)
+ c.Close()
+ continue
+ }
+ if _, err := c.Write([]byte(line)); err != nil {
+ t.Error(err)
+ }
+ c.Close()
+ }
+ wg.Done()
+ }()
+
+ try := func() {
+ cancel := make(chan struct{})
+ d := &Dialer{Cancel: cancel}
+ c, err := d.Dial("tcp", ln.Addr().String())
+
+ // Immediately after dialing, request cancelation and sleep.
+ // Before Issue 15078 was fixed, this would cause subsequent operations
+ // to fail with an i/o timeout roughly 50% of the time.
+ close(cancel)
+ time.Sleep(10 * time.Millisecond)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ // Send some data to confirm that the connection is still alive.
+ const message = "echo!\n"
+ if _, err := c.Write([]byte(message)); err != nil {
+ t.Fatal(err)
+ }
+
+ // The server should echo the line, and close the connection.
+ rb := bufio.NewReader(c)
+ line, err := rb.ReadString('\n')
+ if err != nil {
+ t.Fatal(err)
+ }
+ if line != message {
+ t.Errorf("got %q; want %q", line, message)
+ }
+ if _, err := rb.ReadByte(); err != io.EOF {
+ t.Errorf("got %v; want %v", err, io.EOF)
+ }
+ }
+
+ // This bug manifested about 50% of the time, so try it a few times.
+ for i := 0; i < 10; i++ {
+ try()
+ }
+}
diff --git a/libgo/go/net/dial_unix_test.go b/libgo/go/net/dial_unix_test.go
new file mode 100644
index 0000000000..4705254728
--- /dev/null
+++ b/libgo/go/net/dial_unix_test.go
@@ -0,0 +1,108 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+ "context"
+ "syscall"
+ "testing"
+ "time"
+)
+
+// Issue 16523
+func TestDialContextCancelRace(t *testing.T) {
+ oldConnectFunc := connectFunc
+ oldGetsockoptIntFunc := getsockoptIntFunc
+ oldTestHookCanceledDial := testHookCanceledDial
+ defer func() {
+ connectFunc = oldConnectFunc
+ getsockoptIntFunc = oldGetsockoptIntFunc
+ testHookCanceledDial = oldTestHookCanceledDial
+ }()
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ listenerDone := make(chan struct{})
+ go func() {
+ defer close(listenerDone)
+ c, err := ln.Accept()
+ if err == nil {
+ c.Close()
+ }
+ }()
+ defer func() { <-listenerDone }()
+ defer ln.Close()
+
+ sawCancel := make(chan bool, 1)
+ testHookCanceledDial = func() {
+ sawCancel <- true
+ }
+
+ ctx, cancelCtx := context.WithCancel(context.Background())
+
+ connectFunc = func(fd int, addr syscall.Sockaddr) error {
+ err := oldConnectFunc(fd, addr)
+ t.Logf("connect(%d, addr) = %v", fd, err)
+ if err == nil {
+ // On some operating systems, localhost
+ // connects _sometimes_ succeed immediately.
+ // Prevent that, so we exercise the code path
+ // we're interested in testing. This seems
+ // harmless. It makes FreeBSD 10.10 work when
+ // run with many iterations. It failed about
+ // half the time previously.
+ return syscall.EINPROGRESS
+ }
+ return err
+ }
+
+ getsockoptIntFunc = func(fd, level, opt int) (val int, err error) {
+ val, err = oldGetsockoptIntFunc(fd, level, opt)
+ t.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd, level, opt, val, err)
+ if level == syscall.SOL_SOCKET && opt == syscall.SO_ERROR && err == nil && val == 0 {
+ t.Logf("canceling context")
+
+ // Cancel the context at just the moment which
+ // caused the race in issue 16523.
+ cancelCtx()
+
+ // And wait for the "interrupter" goroutine to
+ // cancel the dial by messing with its write
+ // timeout before returning.
+ select {
+ case <-sawCancel:
+ t.Logf("saw cancel")
+ case <-time.After(5 * time.Second):
+ t.Errorf("didn't see cancel after 5 seconds")
+ }
+ }
+ return
+ }
+
+ var d Dialer
+ c, err := d.DialContext(ctx, "tcp", ln.Addr().String())
+ if err == nil {
+ c.Close()
+ t.Fatal("unexpected successful dial; want context canceled error")
+ }
+
+ select {
+ case <-ctx.Done():
+ case <-time.After(5 * time.Second):
+ t.Fatal("expected context to be canceled")
+ }
+
+ oe, ok := err.(*OpError)
+ if !ok || oe.Op != "dial" {
+ t.Fatalf("Dial error = %#v; want dial *OpError", err)
+ }
+ if oe.Err != ctx.Err() {
+ t.Errorf("DialContext = (%v, %v); want OpError with error %v", c, err, ctx.Err())
+ }
+}
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index 5dc2a0368c..2ab5639d62 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -45,7 +45,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs
}
if dns.rcode != dnsRcodeSuccess {
// None of the error codes make sense
- // for the query we sent. If we didn't get
+ // for the query we sent. If we didn't get
// a name error and we didn't get success,
// the server is behaving incorrectly or
// having temporary trouble.
@@ -113,12 +113,20 @@ func equalASCIILabel(x, y string) bool {
return true
}
+// isDomainName checks if a string is a presentation-format domain name
+// (currently restricted to hostname-compatible "preferred name" LDH labels and
+// SRV-like "underscore labels"; see golang.org/issue/12421).
func isDomainName(s string) bool {
// See RFC 1035, RFC 3696.
- if len(s) == 0 {
- return false
- }
- if len(s) > 255 {
+ // Presentation format has dots before every label except the first, and the
+ // terminal empty label is optional here because we assume fully-qualified
+ // (absolute) input. We must therefore reserve space for the first and last
+ // labels' length octets in wire format, where they are necessary and the
+ // maximum total length is 255.
+ // So our _effective_ maximum is 253, but 254 is not rejected if the last
+ // character is a dot.
+ l := len(s)
+ if l == 0 || l > 254 || l == 254 && s[l-1] != '.' {
return false
}
@@ -161,7 +169,7 @@ func isDomainName(s string) bool {
return ok
}
-// absDomainName returns an absoulte domain name which ends with a
+// absDomainName returns an absolute domain name which ends with a
// trailing dot to match pure Go reverse resolver and all other lookup
// routines.
// See golang.org/issue/12189.
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
index 17188f0024..4dd4e16b0f 100644
--- a/libgo/go/net/dnsclient_unix.go
+++ b/libgo/go/net/dnsclient_unix.go
@@ -16,6 +16,7 @@
package net
import (
+ "context"
"errors"
"io"
"math/rand"
@@ -26,10 +27,10 @@ import (
// A dnsDialer provides dialing suitable for DNS queries.
type dnsDialer interface {
- dialDNS(string, string) (dnsConn, error)
+ dialDNS(ctx context.Context, network, addr string) (dnsConn, error)
}
-var testHookDNSDialer = func(d time.Duration) dnsDialer { return &Dialer{Timeout: d} }
+var testHookDNSDialer = func() dnsDialer { return &Dialer{} }
// A dnsConn represents a DNS transport endpoint.
type dnsConn interface {
@@ -37,46 +38,67 @@ type dnsConn interface {
SetDeadline(time.Time) error
- // readDNSResponse reads a DNS response message from the DNS
- // transport endpoint and returns the received DNS response
- // message.
- readDNSResponse() (*dnsMsg, error)
+ // dnsRoundTrip executes a single DNS transaction, returning a
+ // DNS response message for the provided DNS query message.
+ dnsRoundTrip(query *dnsMsg) (*dnsMsg, error)
+}
- // writeDNSQuery writes a DNS query message to the DNS
- // connection endpoint.
- writeDNSQuery(*dnsMsg) error
+func (c *UDPConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) {
+ return dnsRoundTripUDP(c, query)
}
-func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
- b := make([]byte, 512) // see RFC 1035
- n, err := c.Read(b)
- if err != nil {
+// dnsRoundTripUDP implements the dnsRoundTrip interface for RFC 1035's
+// "UDP usage" transport mechanism. c should be a packet-oriented connection,
+// such as a *UDPConn.
+func dnsRoundTripUDP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
+ b, ok := query.Pack()
+ if !ok {
+ return nil, errors.New("cannot marshal DNS message")
+ }
+ if _, err := c.Write(b); err != nil {
return nil, err
}
- msg := &dnsMsg{}
- if !msg.Unpack(b[:n]) {
- return nil, errors.New("cannot unmarshal DNS message")
+
+ b = make([]byte, 512) // see RFC 1035
+ for {
+ n, err := c.Read(b)
+ if err != nil {
+ return nil, err
+ }
+ resp := &dnsMsg{}
+ if !resp.Unpack(b[:n]) || !resp.IsResponseTo(query) {
+ // Ignore invalid responses as they may be malicious
+ // forgery attempts. Instead continue waiting until
+ // timeout. See golang.org/issue/13281.
+ continue
+ }
+ return resp, nil
}
- return msg, nil
}
-func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
- b, ok := msg.Pack()
+func (c *TCPConn) dnsRoundTrip(out *dnsMsg) (*dnsMsg, error) {
+ return dnsRoundTripTCP(c, out)
+}
+
+// dnsRoundTripTCP implements the dnsRoundTrip interface for RFC 1035's
+// "TCP usage" transport mechanism. c should be a stream-oriented connection,
+// such as a *TCPConn.
+func dnsRoundTripTCP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
+ b, ok := query.Pack()
if !ok {
- return errors.New("cannot marshal DNS message")
+ return nil, errors.New("cannot marshal DNS message")
}
+ l := len(b)
+ b = append([]byte{byte(l >> 8), byte(l)}, b...)
if _, err := c.Write(b); err != nil {
- return err
+ return nil, err
}
- return nil
-}
-func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
- b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
+ b = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
if _, err := io.ReadFull(c, b[:2]); err != nil {
return nil, err
}
- l := int(b[0])<<8 | int(b[1])
+ l = int(b[0])<<8 | int(b[1])
if l > len(b) {
b = make([]byte, l)
}
@@ -84,27 +106,17 @@ func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
if err != nil {
return nil, err
}
- msg := &dnsMsg{}
- if !msg.Unpack(b[:n]) {
+ resp := &dnsMsg{}
+ if !resp.Unpack(b[:n]) {
return nil, errors.New("cannot unmarshal DNS message")
}
- return msg, nil
-}
-
-func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
- b, ok := msg.Pack()
- if !ok {
- return errors.New("cannot marshal DNS message")
- }
- l := uint16(len(b))
- b = append([]byte{byte(l >> 8), byte(l)}, b...)
- if _, err := c.Write(b); err != nil {
- return err
+ if !resp.IsResponseTo(query) {
+ return nil, errors.New("invalid DNS response")
}
- return nil
+ return resp, nil
}
-func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
+func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, error) {
switch network {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
default:
@@ -113,11 +125,11 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
// Calling Dial here is scary -- we have to be sure not to
// dial a name that will require a DNS lookup, or Dial will
// call back here to translate it. The DNS config parser has
- // already checked that all the cfg.servers[i] are IP
+ // already checked that all the cfg.servers are IP
// addresses, which Dial will use without a DNS lookup.
- c, err := d.Dial(network, server)
+ c, err := d.DialContext(ctx, network, server)
if err != nil {
- return nil, err
+ return nil, mapErr(err)
}
switch network {
case "tcp", "tcp4", "tcp6":
@@ -129,8 +141,8 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
}
// exchange sends a query on the connection and hopes for a response.
-func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
- d := testHookDNSDialer(timeout)
+func exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
+ d := testHookDNSDialer()
out := dnsMsg{
dnsMsgHdr: dnsMsgHdr{
recursion_desired: true,
@@ -140,24 +152,24 @@ func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg
},
}
for _, network := range []string{"udp", "tcp"} {
- c, err := d.dialDNS(network, server)
+ // TODO(mdempsky): Refactor so defers from UDP-based
+ // exchanges happen before TCP-based exchange.
+
+ ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
+ defer cancel()
+
+ c, err := d.dialDNS(ctx, network, server)
if err != nil {
return nil, err
}
defer c.Close()
- if timeout > 0 {
- c.SetDeadline(time.Now().Add(timeout))
+ if d, ok := ctx.Deadline(); ok && !d.IsZero() {
+ c.SetDeadline(d)
}
out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
- if err := c.writeDNSQuery(&out); err != nil {
- return nil, err
- }
- in, err := c.readDNSResponse()
+ in, err := c.dnsRoundTrip(&out)
if err != nil {
- return nil, err
- }
- if in.id != out.id {
- return nil, errors.New("DNS message ID mismatch")
+ return nil, mapErr(err)
}
if in.truncated { // see RFC 5966
continue
@@ -169,16 +181,16 @@ func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg
// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Err: "no DNS servers", Name: name}
- }
- timeout := time.Duration(cfg.timeout) * time.Second
+func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
var lastErr error
+ serverOffset := cfg.serverOffset()
+ sLen := uint32(len(cfg.servers))
+
for i := 0; i < cfg.attempts; i++ {
- for _, server := range cfg.servers {
- server = JoinHostPort(server, "53")
- msg, err := exchange(server, name, qtype, timeout)
+ for j := uint32(0); j < sLen; j++ {
+ server := cfg.servers[(serverOffset+j)%sLen]
+
+ msg, err := exchange(ctx, server, name, qtype, cfg.timeout)
if err != nil {
lastErr = &DNSError{
Err: err.Error(),
@@ -190,6 +202,12 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
}
continue
}
+ // libresolv continues to the next server when it receives
+ // an invalid referral response. See golang.org/issue/15434.
+ if msg.rcode == dnsRcodeSuccess && !msg.authoritative && !msg.recursion_available && len(msg.answer) == 0 && len(msg.extra) == 0 {
+ lastErr = &DNSError{Err: "lame referral", Name: name, Server: server}
+ continue
+ }
cname, rrs, err := answer(name, server, msg, qtype)
// If answer errored for rcodes dnsRcodeSuccess or dnsRcodeNameError,
// it means the response in msg was not useful and trying another
@@ -229,7 +247,6 @@ type resolverConfig struct {
// time to recheck resolv.conf.
ch chan struct{} // guards lastChecked and modTime
lastChecked time.Time // last time resolv.conf was checked
- modTime time.Time // time of resolv.conf modification
mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
@@ -239,16 +256,12 @@ var resolvConf resolverConfig
// init initializes conf and is only called via conf.initOnce.
func (conf *resolverConfig) init() {
- // Set dnsConfig, modTime, and lastChecked so we don't parse
+ // Set dnsConfig and lastChecked so we don't parse
// resolv.conf twice the first time.
conf.dnsConfig = systemConf().resolv
if conf.dnsConfig == nil {
conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
}
-
- if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
- conf.modTime = fi.ModTime()
- }
conf.lastChecked = time.Now()
// Prepare ch so that only one update of resolverConfig may
@@ -274,17 +287,12 @@ func (conf *resolverConfig) tryUpdate(name string) {
}
conf.lastChecked = now
+ var mtime time.Time
if fi, err := os.Stat(name); err == nil {
- if fi.ModTime().Equal(conf.modTime) {
- return
- }
- conf.modTime = fi.ModTime()
- } else {
- // If modTime wasn't set prior, assume nothing has changed.
- if conf.modTime.IsZero() {
- return
- }
- conf.modTime = time.Time{}
+ mtime = fi.ModTime()
+ }
+ if mtime.Equal(conf.dnsConfig.mtime) {
+ return
}
dnsConf := dnsReadConfig(name)
@@ -306,16 +314,21 @@ func (conf *resolverConfig) releaseSema() {
<-conf.ch
}
-func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
+func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
if !isDomainName(name) {
- return "", nil, &DNSError{Err: "invalid domain name", Name: name}
+ // We used to use "invalid domain name" as the error,
+ // but that is a detail of the specific lookup mechanism.
+ // Other lookups might allow broader name syntax
+ // (for example Multicast DNS allows UTF-8; see RFC 6762).
+ // For consistency with libc resolvers, report no such host.
+ return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
}
resolvConf.tryUpdate("/etc/resolv.conf")
resolvConf.mu.RLock()
conf := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
for _, fqdn := range conf.nameList(name) {
- cname, rrs, err = tryOneName(conf, fqdn, qtype)
+ cname, rrs, err = tryOneName(ctx, conf, fqdn, qtype)
if err == nil {
break
}
@@ -329,30 +342,57 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
return
}
+// avoidDNS reports whether this is a hostname for which we should not
+// use DNS. Currently this includes only .onion, per RFC 7686. See
+// golang.org/issue/13705. Does not cover .local names (RFC 6762),
+// see golang.org/issue/16739.
+func avoidDNS(name string) bool {
+ if name == "" {
+ return true
+ }
+ if name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+ return stringsHasSuffixFold(name, ".onion")
+}
+
// nameList returns a list of names for sequential DNS queries.
func (conf *dnsConfig) nameList(name string) []string {
+ if avoidDNS(name) {
+ return nil
+ }
+
+ // Check name length (see isDomainName).
+ l := len(name)
+ rooted := l > 0 && name[l-1] == '.'
+ if l > 254 || l == 254 && rooted {
+ return nil
+ }
+
// If name is rooted (trailing dot), try only that name.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
if rooted {
return []string{name}
}
+
+ hasNdots := count(name, '.') >= conf.ndots
+ name += "."
+ l++
+
// Build list of search choices.
names := make([]string, 0, 1+len(conf.search))
// If name has enough dots, try unsuffixed first.
- if count(name, '.') >= conf.ndots {
- names = append(names, name+".")
+ if hasNdots {
+ names = append(names, name)
}
- // Try suffixes.
+ // Try suffixes that are not too long (see isDomainName).
for _, suffix := range conf.search {
- suffixed := name + "." + suffix
- if suffixed[len(suffixed)-1] != '.' {
- suffixed += "."
+ if l+len(suffix) <= 254 {
+ names = append(names, name+suffix)
}
- names = append(names, suffixed)
}
// Try unsuffixed, if not tried first above.
- if count(name, '.') < conf.ndots {
- names = append(names, name+".")
+ if !hasNdots {
+ names = append(names, name)
}
return names
}
@@ -392,11 +432,11 @@ func (o hostLookupOrder) String() string {
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
-func goLookupHost(name string) (addrs []string, err error) {
- return goLookupHostOrder(name, hostLookupFilesDNS)
+func goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
+ return goLookupHostOrder(ctx, name, hostLookupFilesDNS)
}
-func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
+func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
if order == hostLookupFilesDNS || order == hostLookupFiles {
// Use entries from /etc/hosts if they match.
addrs = lookupStaticHost(name)
@@ -404,7 +444,7 @@ func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err
return
}
}
- ips, err := goLookupIPOrder(name, order)
+ ips, _, err := goLookupIPCNAMEOrder(ctx, name, order)
if err != nil {
return
}
@@ -430,27 +470,30 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
// goLookupIP is the native Go implementation of LookupIP.
// The libc versions are in cgo_*.go.
-func goLookupIP(name string) (addrs []IPAddr, err error) {
- return goLookupIPOrder(name, hostLookupFilesDNS)
+func goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ order := systemConf().hostLookupOrder(host)
+ addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+ return
}
-func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
+func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) {
if order == hostLookupFilesDNS || order == hostLookupFiles {
addrs = goLookupIPFiles(name)
if len(addrs) > 0 || order == hostLookupFiles {
- return addrs, nil
+ return addrs, name, nil
}
}
if !isDomainName(name) {
- return nil, &DNSError{Err: "invalid domain name", Name: name}
+ // See comment in func lookup above about use of errNoSuchHost.
+ return nil, "", &DNSError{Err: errNoSuchHost.Error(), Name: name}
}
resolvConf.tryUpdate("/etc/resolv.conf")
resolvConf.mu.RLock()
conf := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
type racer struct {
- fqdn string
- rrs []dnsRR
+ cname string
+ rrs []dnsRR
error
}
lane := make(chan racer, 1)
@@ -459,20 +502,23 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
for _, fqdn := range conf.nameList(name) {
for _, qtype := range qtypes {
go func(qtype uint16) {
- _, rrs, err := tryOneName(conf, fqdn, qtype)
- lane <- racer{fqdn, rrs, err}
+ cname, rrs, err := tryOneName(ctx, conf, fqdn, qtype)
+ lane <- racer{cname, rrs, err}
}(qtype)
}
for range qtypes {
racer := <-lane
if racer.error != nil {
// Prefer error for original name.
- if lastErr == nil || racer.fqdn == name+"." {
+ if lastErr == nil || fqdn == name+"." {
lastErr = racer.error
}
continue
}
addrs = append(addrs, addrRecordList(racer.rrs)...)
+ if cname == "" {
+ cname = racer.cname
+ }
}
if len(addrs) > 0 {
break
@@ -490,24 +536,16 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
addrs = goLookupIPFiles(name)
}
if len(addrs) == 0 && lastErr != nil {
- return nil, lastErr
+ return nil, "", lastErr
}
}
- return addrs, nil
+ return addrs, cname, nil
}
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(name string) (cname string, err error) {
- _, rrs, err := lookup(name, dnsTypeCNAME)
- if err != nil {
- return
- }
- cname = rrs[0].(*dnsRR_CNAME).Cname
+// goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
+func goLookupCNAME(ctx context.Context, host string) (cname string, err error) {
+ order := systemConf().hostLookupOrder(host)
+ _, cname, err = goLookupIPCNAMEOrder(ctx, host, order)
return
}
@@ -516,7 +554,7 @@ func goLookupCNAME(name string) (cname string, err error) {
// only if cgoLookupPTR is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of depending
// on our lookup code, so that Go and C get the same answers.
-func goLookupPTR(addr string) ([]string, error) {
+func goLookupPTR(ctx context.Context, addr string) ([]string, error) {
names := lookupStaticAddr(addr)
if len(names) > 0 {
return names, nil
@@ -525,7 +563,7 @@ func goLookupPTR(addr string) ([]string, error) {
if err != nil {
return nil, err
}
- _, rrs, err := lookup(arpa, dnsTypePTR)
+ _, rrs, err := lookup(ctx, arpa, dnsTypePTR)
if err != nil {
return nil, err
}
diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go
index 934f25b2c9..85267bbddc 100644
--- a/libgo/go/net/dnsclient_unix_test.go
+++ b/libgo/go/net/dnsclient_unix_test.go
@@ -7,7 +7,9 @@
package net
import (
+ "context"
"fmt"
+ "internal/testenv"
"io/ioutil"
"os"
"path"
@@ -18,6 +20,9 @@ import (
"time"
)
+// Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
+const TestAddr uint32 = 0xc0000201
+
var dnsTransportFallbackTests = []struct {
server string
name string
@@ -32,13 +37,12 @@ var dnsTransportFallbackTests = []struct {
}
func TestDNSTransportFallback(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
for _, tt := range dnsTransportFallbackTests {
- timeout := time.Duration(tt.timeout) * time.Second
- msg, err := exchange(tt.server, tt.name, tt.qtype, timeout)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ msg, err := exchange(ctx, tt.server, tt.name, tt.qtype, time.Second)
if err != nil {
t.Error(err)
continue
@@ -67,20 +71,20 @@ var specialDomainNameTests = []struct {
// Name resolution APIs and libraries should recognize the
// followings as special and should not send any queries.
- // Though, we test those names here for verifying nagative
+ // Though, we test those names here for verifying negative
// answers at DNS query-response interaction level.
{"localhost.", dnsTypeALL, dnsRcodeNameError},
{"invalid.", dnsTypeALL, dnsRcodeNameError},
}
func TestSpecialDomainName(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
server := "8.8.8.8:53"
for _, tt := range specialDomainNameTests {
- msg, err := exchange(server, tt.name, tt.qtype, 3*time.Second)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ msg, err := exchange(ctx, server, tt.name, tt.qtype, 3*time.Second)
if err != nil {
t.Error(err)
continue
@@ -94,6 +98,58 @@ func TestSpecialDomainName(t *testing.T) {
}
}
+// Issue 13705: don't try to resolve onion addresses, etc
+func TestAvoidDNSName(t *testing.T) {
+ tests := []struct {
+ name string
+ avoid bool
+ }{
+ {"foo.com", false},
+ {"foo.com.", false},
+
+ {"foo.onion.", true},
+ {"foo.onion", true},
+ {"foo.ONION", true},
+ {"foo.ONION.", true},
+
+ // But do resolve *.local address; Issue 16739
+ {"foo.local.", false},
+ {"foo.local", false},
+ {"foo.LOCAL", false},
+ {"foo.LOCAL.", false},
+
+ {"", true}, // will be rejected earlier too
+
+ // Without stuff before onion/local, they're fine to
+ // use DNS. With a search path,
+ // "onion.vegegtables.com" can use DNS. Without a
+ // search path (or with a trailing dot), the queries
+ // are just kinda useless, but don't reveal anything
+ // private.
+ {"local", false},
+ {"onion", false},
+ {"local.", false},
+ {"onion.", false},
+ }
+ for _, tt := range tests {
+ got := avoidDNS(tt.name)
+ if got != tt.avoid {
+ t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
+ }
+ }
+}
+
+// Issue 13705: don't try to resolve onion addresses, etc
+func TestLookupTorOnion(t *testing.T) {
+ addrs, err := goLookupIP(context.Background(), "foo.onion")
+ if len(addrs) > 0 {
+ t.Errorf("unexpected addresses: %v", addrs)
+ }
+ if err != nil {
+ t.Fatalf("lookup = %v; want nil", err)
+ }
+}
+
type resolvConfTest struct {
dir string
path string
@@ -124,20 +180,20 @@ func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
return err
}
f.Close()
- if err := conf.forceUpdate(conf.path); err != nil {
+ if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil {
return err
}
return nil
}
-func (conf *resolvConfTest) forceUpdate(name string) error {
+func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
dnsConf := dnsReadConfig(name)
conf.mu.Lock()
conf.dnsConfig = dnsConf
conf.mu.Unlock()
for i := 0; i < 5; i++ {
if conf.tryAcquireSema() {
- conf.lastChecked = time.Time{}
+ conf.lastChecked = lastChecked
conf.releaseSema()
return nil
}
@@ -153,7 +209,7 @@ func (conf *resolvConfTest) servers() []string {
}
func (conf *resolvConfTest) teardown() error {
- err := conf.forceUpdate("/etc/resolv.conf")
+ err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
os.RemoveAll(conf.dir)
return err
}
@@ -166,7 +222,7 @@ var updateResolvConfTests = []struct {
{
name: "golang.org",
lines: []string{"nameserver 8.8.8.8"},
- servers: []string{"8.8.8.8"},
+ servers: []string{"8.8.8.8:53"},
},
{
name: "",
@@ -176,14 +232,12 @@ var updateResolvConfTests = []struct {
{
name: "www.example.com",
lines: []string{"nameserver 8.8.4.4"},
- servers: []string{"8.8.4.4"},
+ servers: []string{"8.8.4.4:53"},
},
}
func TestUpdateResolvConf(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
conf, err := newResolvConfTest()
if err != nil {
@@ -203,7 +257,7 @@ func TestUpdateResolvConf(t *testing.T) {
for j := 0; j < N; j++ {
go func(name string) {
defer wg.Done()
- ips, err := goLookupIP(name)
+ ips, err := goLookupIP(context.Background(), name)
if err != nil {
t.Error(err)
return
@@ -338,9 +392,7 @@ var goLookupIPWithResolverConfigTests = []struct {
}
func TestGoLookupIPWithResolverConfig(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
conf, err := newResolvConfTest()
if err != nil {
@@ -353,10 +405,15 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
t.Error(err)
continue
}
- conf.tryUpdate(conf.path)
- addrs, err := goLookupIP(tt.name)
+ addrs, err := goLookupIP(context.Background(), tt.name)
if err != nil {
- if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
+ // This test uses external network connectivity.
+ // We need to take care with errors on both
+ // DNS message exchange layer and DNS
+ // transport layer because goLookupIP may fail
+ // when the IP connectivity on node under test
+ // gets lost during its run.
+ if err, ok := err.(*DNSError); !ok || tt.error != nil && (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
t.Errorf("got %v; want %v", err, tt.error)
}
continue
@@ -380,9 +437,7 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
// Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
// Add a config that simulates no dns servers being available.
conf, err := newResolvConfTest()
@@ -392,7 +447,6 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
if err := conf.writeAndUpdate([]string{}); err != nil {
t.Fatal(err)
}
- conf.tryUpdate(conf.path)
// Redirect host file lookups.
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
testHookHostsPath = "testdata/hosts"
@@ -400,15 +454,15 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
name := fmt.Sprintf("order %v", order)
- // First ensure that we get an error when contacting a non-existant host.
- _, err := goLookupIPOrder("notarealhost", order)
+ // First ensure that we get an error when contacting a non-existent host.
+ _, _, err := goLookupIPCNAMEOrder(context.Background(), "notarealhost", order)
if err == nil {
t.Errorf("%s: expected error while looking up name not in hosts file", name)
continue
}
// Now check that we get an address when the name appears in the hosts file.
- addrs, err := goLookupIPOrder("thor", order) // entry is in "testdata/hosts"
+ addrs, _, err := goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
if err != nil {
t.Errorf("%s: expected to successfully lookup host entry", name)
continue
@@ -444,10 +498,10 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
t.Fatal(err)
}
- d := &fakeDNSConn{}
- testHookDNSDialer = func(time.Duration) dnsDialer { return d }
+ d := &fakeDNSDialer{}
+ testHookDNSDialer = func() dnsDialer { return d }
- d.rh = func(q *dnsMsg) (*dnsMsg, error) {
+ d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
r := &dnsMsg{
dnsMsgHdr: dnsMsgHdr{
id: q.id,
@@ -464,7 +518,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
return r, nil
}
- _, err = goLookupIP(fqdn)
+ _, err = goLookupIP(context.Background(), fqdn)
if err == nil {
t.Fatal("expected an error")
}
@@ -475,19 +529,84 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
}
}
+// Issue 15434. If a name server gives a lame referral, continue to the next.
+func TestIgnoreLameReferrals(t *testing.T) {
+ origTestHookDNSDialer := testHookDNSDialer
+ defer func() { testHookDNSDialer = origTestHookDNSDialer }()
+
+ conf, err := newResolvConfTest()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conf.teardown()
+
+ if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
+ "nameserver 192.0.2.2"}); err != nil {
+ t.Fatal(err)
+ }
+
+ d := &fakeDNSDialer{}
+ testHookDNSDialer = func() dnsDialer { return d }
+
+ d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+ t.Log(s, q)
+ r := &dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ id: q.id,
+ response: true,
+ },
+ question: q.question,
+ }
+
+ if s == "192.0.2.2:53" {
+ r.recursion_available = true
+ if q.question[0].Qtype == dnsTypeA {
+ r.answer = []dnsRR{
+ &dnsRR_A{
+ Hdr: dnsRR_Header{
+ Name: q.question[0].Name,
+ Rrtype: dnsTypeA,
+ Class: dnsClassINET,
+ Rdlength: 4,
+ },
+ A: TestAddr,
+ },
+ }
+ }
+ }
+
+ return r, nil
+ }
+
+ addrs, err := goLookupIP(context.Background(), "www.golang.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if got := len(addrs); got != 1 {
+ t.Fatalf("got %d addresses, want 1", got)
+ }
+
+ if got, want := addrs[0].String(), "192.0.2.1"; got != want {
+ t.Fatalf("got address %v, want %v", got, want)
+ }
+}
+
func BenchmarkGoLookupIP(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
+ ctx := context.Background()
for i := 0; i < b.N; i++ {
- goLookupIP("www.example.com")
+ goLookupIP(ctx, "www.example.com")
}
}
func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
+ ctx := context.Background()
for i := 0; i < b.N; i++ {
- goLookupIP("some.nonexistent")
+ goLookupIP(ctx, "some.nonexistent")
}
}
@@ -507,42 +626,237 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
if err := conf.writeAndUpdate(lines); err != nil {
b.Fatal(err)
}
+ ctx := context.Background()
for i := 0; i < b.N; i++ {
- goLookupIP("www.example.com")
+ goLookupIP(ctx, "www.example.com")
}
}
-type fakeDNSConn struct {
- // last query
- qmu sync.Mutex // guards q
- q *dnsMsg
+type fakeDNSDialer struct {
// reply handler
- rh func(*dnsMsg) (*dnsMsg, error)
+ rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
}
-func (f *fakeDNSConn) dialDNS(n, s string) (dnsConn, error) {
- return f, nil
+func (f *fakeDNSDialer) dialDNS(_ context.Context, n, s string) (dnsConn, error) {
+ return &fakeDNSConn{f.rh, s, time.Time{}}, nil
+}
+
+type fakeDNSConn struct {
+ rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
+ s string
+ t time.Time
}
func (f *fakeDNSConn) Close() error {
return nil
}
-func (f *fakeDNSConn) SetDeadline(time.Time) error {
+func (f *fakeDNSConn) SetDeadline(t time.Time) error {
+ f.t = t
return nil
}
-func (f *fakeDNSConn) writeDNSQuery(q *dnsMsg) error {
- f.qmu.Lock()
- defer f.qmu.Unlock()
- f.q = q
- return nil
+func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) {
+ return f.rh(f.s, q, f.t)
}
-func (f *fakeDNSConn) readDNSResponse() (*dnsMsg, error) {
- f.qmu.Lock()
- q := f.q
- f.qmu.Unlock()
- return f.rh(q)
+// UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
+func TestIgnoreDNSForgeries(t *testing.T) {
+ c, s := Pipe()
+ go func() {
+ b := make([]byte, 512)
+ n, err := s.Read(b)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ msg := &dnsMsg{}
+ if !msg.Unpack(b[:n]) {
+ t.Error("invalid DNS query")
+ return
+ }
+
+ s.Write([]byte("garbage DNS response packet"))
+
+ msg.response = true
+ msg.id++ // make invalid ID
+ b, ok := msg.Pack()
+ if !ok {
+ t.Error("failed to pack DNS response")
+ return
+ }
+ s.Write(b)
+
+ msg.id-- // restore original ID
+ msg.answer = []dnsRR{
+ &dnsRR_A{
+ Hdr: dnsRR_Header{
+ Name: "www.example.com.",
+ Rrtype: dnsTypeA,
+ Class: dnsClassINET,
+ Rdlength: 4,
+ },
+ A: TestAddr,
+ },
+ }
+
+ b, ok = msg.Pack()
+ if !ok {
+ t.Error("failed to pack DNS response")
+ return
+ }
+ s.Write(b)
+ }()
+
+ msg := &dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ },
+ },
+ }
+
+ resp, err := dnsRoundTripUDP(c, msg)
+ if err != nil {
+ t.Fatalf("dnsRoundTripUDP failed: %v", err)
+ }
+
+ if got := resp.answer[0].(*dnsRR_A).A; got != TestAddr {
+ t.Errorf("got address %v, want %v", got, TestAddr)
+ }
+}
+
+// Issue 16865. If a name server times out, continue to the next.
+func TestRetryTimeout(t *testing.T) {
+ origTestHookDNSDialer := testHookDNSDialer
+ defer func() { testHookDNSDialer = origTestHookDNSDialer }()
+
+ conf, err := newResolvConfTest()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conf.teardown()
+
+ testConf := []string{
+ "nameserver 192.0.2.1", // the one that will timeout
+ "nameserver 192.0.2.2",
+ }
+ if err := conf.writeAndUpdate(testConf); err != nil {
+ t.Fatal(err)
+ }
+
+ d := &fakeDNSDialer{}
+ testHookDNSDialer = func() dnsDialer { return d }
+
+ var deadline0 time.Time
+
+ d.rh = func(s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
+ t.Log(s, q, deadline)
+
+ if deadline.IsZero() {
+ t.Error("zero deadline")
+ }
+
+ if s == "192.0.2.1:53" {
+ deadline0 = deadline
+ time.Sleep(10 * time.Millisecond)
+ return nil, errTimeout
+ }
+
+ if deadline == deadline0 {
+ t.Error("deadline didn't change")
+ }
+
+ return mockTXTResponse(q), nil
+ }
+
+ _, err = LookupTXT("www.golang.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if deadline0.IsZero() {
+ t.Error("deadline0 still zero", deadline0)
+ }
+}
+
+func TestRotate(t *testing.T) {
+ // without rotation, always uses the first server
+ testRotate(t, false, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.1:53", "192.0.2.1:53"})
+
+ // with rotation, rotates through back to first
+ testRotate(t, true, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.2:53", "192.0.2.1:53"})
+}
+
+func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
+ origTestHookDNSDialer := testHookDNSDialer
+ defer func() { testHookDNSDialer = origTestHookDNSDialer }()
+
+ conf, err := newResolvConfTest()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conf.teardown()
+
+ var confLines []string
+ for _, ns := range nameservers {
+ confLines = append(confLines, "nameserver "+ns)
+ }
+ if rotate {
+ confLines = append(confLines, "options rotate")
+ }
+
+ if err := conf.writeAndUpdate(confLines); err != nil {
+ t.Fatal(err)
+ }
+
+ d := &fakeDNSDialer{}
+ testHookDNSDialer = func() dnsDialer { return d }
+
+ var usedServers []string
+ d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+ usedServers = append(usedServers, s)
+ return mockTXTResponse(q), nil
+ }
+
+ // len(nameservers) + 1 to allow rotation to get back to start
+ for i := 0; i < len(nameservers)+1; i++ {
+ if _, err := LookupTXT("www.golang.org"); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ if !reflect.DeepEqual(usedServers, wantServers) {
+ t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
+ }
+}
+
+func mockTXTResponse(q *dnsMsg) *dnsMsg {
+ r := &dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ id: q.id,
+ response: true,
+ recursion_available: true,
+ },
+ question: q.question,
+ answer: []dnsRR{
+ &dnsRR_TXT{
+ Hdr: dnsRR_Header{
+ Name: q.question[0].Name,
+ Rrtype: dnsTypeTXT,
+ Class: dnsClassINET,
+ },
+ Txt: "ok",
+ },
+ },
+ }
+
+ return r
}
diff --git a/libgo/go/net/dnsconfig_unix.go b/libgo/go/net/dnsconfig_unix.go
index 6073fdb6d8..9c8108d11c 100644
--- a/libgo/go/net/dnsconfig_unix.go
+++ b/libgo/go/net/dnsconfig_unix.go
@@ -8,36 +8,54 @@
package net
-var defaultNS = []string{"127.0.0.1", "::1"}
+import (
+ "os"
+ "sync/atomic"
+ "time"
+)
+
+var (
+ defaultNS = []string{"127.0.0.1:53", "[::1]:53"}
+ getHostname = os.Hostname // variable for testing
+)
type dnsConfig struct {
- servers []string // servers to use
- search []string // suffixes to append to local name
- ndots int // number of dots in name to trigger absolute lookup
- timeout int // seconds before giving up on packet
- attempts int // lost packets before giving up on server
- rotate bool // round robin among servers
- unknownOpt bool // anything unknown was encountered
- lookup []string // OpenBSD top-level database "lookup" order
- err error // any error that occurs during open of resolv.conf
+ servers []string // server addresses (in host:port form) to use
+ search []string // rooted suffixes to append to local name
+ ndots int // number of dots in name to trigger absolute lookup
+ timeout time.Duration // wait before giving up on a query, including retries
+ attempts int // lost packets before giving up on server
+ rotate bool // round robin among servers
+ unknownOpt bool // anything unknown was encountered
+ lookup []string // OpenBSD top-level database "lookup" order
+ err error // any error that occurs during open of resolv.conf
+ mtime time.Time // time of resolv.conf modification
+ soffset uint32 // used by serverOffset
}
// See resolv.conf(5) on a Linux machine.
-// TODO(rsc): Supposed to call uname() and chop the beginning
-// of the host name to get the default search domain.
func dnsReadConfig(filename string) *dnsConfig {
conf := &dnsConfig{
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
}
file, err := open(filename)
if err != nil {
conf.servers = defaultNS
+ conf.search = dnsDefaultSearch()
conf.err = err
return conf
}
defer file.close()
+ if fi, err := file.file.Stat(); err == nil {
+ conf.mtime = fi.ModTime()
+ } else {
+ conf.servers = defaultNS
+ conf.search = dnsDefaultSearch()
+ conf.err = err
+ return conf
+ }
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
// comment.
@@ -51,43 +69,45 @@ func dnsReadConfig(filename string) *dnsConfig {
case "nameserver": // add one name server
if len(f) > 1 && len(conf.servers) < 3 { // small, but the standard limit
// One more check: make sure server name is
- // just an IP address. Otherwise we need DNS
+ // just an IP address. Otherwise we need DNS
// to look it up.
if parseIPv4(f[1]) != nil {
- conf.servers = append(conf.servers, f[1])
+ conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
} else if ip, _ := parseIPv6(f[1], true); ip != nil {
- conf.servers = append(conf.servers, f[1])
+ conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
}
}
case "domain": // set search path to just this domain
if len(f) > 1 {
- conf.search = []string{f[1]}
+ conf.search = []string{ensureRooted(f[1])}
}
case "search": // set search path to given servers
conf.search = make([]string, len(f)-1)
for i := 0; i < len(conf.search); i++ {
- conf.search[i] = f[i+1]
+ conf.search[i] = ensureRooted(f[i+1])
}
case "options": // magic options
for _, s := range f[1:] {
switch {
case hasPrefix(s, "ndots:"):
- n, _, _ := dtoi(s, 6)
- if n < 1 {
- n = 1
+ n, _, _ := dtoi(s[6:])
+ if n < 0 {
+ n = 0
+ } else if n > 15 {
+ n = 15
}
conf.ndots = n
case hasPrefix(s, "timeout:"):
- n, _, _ := dtoi(s, 8)
+ n, _, _ := dtoi(s[8:])
if n < 1 {
n = 1
}
- conf.timeout = n
+ conf.timeout = time.Duration(n) * time.Second
case hasPrefix(s, "attempts:"):
- n, _, _ := dtoi(s, 9)
+ n, _, _ := dtoi(s[9:])
if n < 1 {
n = 1
}
@@ -112,9 +132,42 @@ func dnsReadConfig(filename string) *dnsConfig {
if len(conf.servers) == 0 {
conf.servers = defaultNS
}
+ if len(conf.search) == 0 {
+ conf.search = dnsDefaultSearch()
+ }
return conf
}
+// serverOffset returns an offset that can be used to determine
+// indices of servers in c.servers when making queries.
+// When the rotate option is enabled, this offset increases.
+// Otherwise it is always 0.
+func (c *dnsConfig) serverOffset() uint32 {
+ if c.rotate {
+ return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start
+ }
+ return 0
+}
+
+func dnsDefaultSearch() []string {
+ hn, err := getHostname()
+ if err != nil {
+ // best effort
+ return nil
+ }
+ if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 {
+ return []string{ensureRooted(hn[i+1:])}
+ }
+ return nil
+}
+
func hasPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
}
+
+func ensureRooted(s string) string {
+ if len(s) > 0 && s[len(s)-1] == '.' {
+ return s
+ }
+ return s + "."
+}
diff --git a/libgo/go/net/dnsconfig_unix_test.go b/libgo/go/net/dnsconfig_unix_test.go
index c8eed61890..37bdeb04c8 100644
--- a/libgo/go/net/dnsconfig_unix_test.go
+++ b/libgo/go/net/dnsconfig_unix_test.go
@@ -7,9 +7,12 @@
package net
import (
+ "errors"
"os"
"reflect"
+ "strings"
"testing"
+ "time"
)
var dnsReadConfigTests = []struct {
@@ -19,10 +22,10 @@ var dnsReadConfigTests = []struct {
{
name: "testdata/resolv.conf",
want: &dnsConfig{
- servers: []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
- search: []string{"localdomain"},
+ servers: []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
+ search: []string{"localdomain."},
ndots: 5,
- timeout: 10,
+ timeout: 10 * time.Second,
attempts: 3,
rotate: true,
unknownOpt: true, // the "options attempts 3" line
@@ -31,20 +34,20 @@ var dnsReadConfigTests = []struct {
{
name: "testdata/domain-resolv.conf",
want: &dnsConfig{
- servers: []string{"8.8.8.8"},
- search: []string{"localdomain"},
+ servers: []string{"8.8.8.8:53"},
+ search: []string{"localdomain."},
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
},
},
{
name: "testdata/search-resolv.conf",
want: &dnsConfig{
- servers: []string{"8.8.8.8"},
- search: []string{"test", "invalid"},
+ servers: []string{"8.8.8.8:53"},
+ search: []string{"test.", "invalid."},
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
},
},
@@ -53,29 +56,65 @@ var dnsReadConfigTests = []struct {
want: &dnsConfig{
servers: defaultNS,
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
+ name: "testdata/invalid-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 0,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
+ name: "testdata/large-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 15,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
+ name: "testdata/negative-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 0,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
},
},
{
name: "testdata/openbsd-resolv.conf",
want: &dnsConfig{
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
lookup: []string{"file", "bind"},
- servers: []string{"169.254.169.254", "10.240.0.1"},
+ servers: []string{"169.254.169.254:53", "10.240.0.1:53"},
search: []string{"c.symbolic-datum-552.internal."},
},
},
}
func TestDNSReadConfig(t *testing.T) {
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+ getHostname = func() (string, error) { return "host.domain.local", nil }
+
for _, tt := range dnsReadConfigTests {
conf := dnsReadConfig(tt.name)
if conf.err != nil {
t.Fatal(conf.err)
}
+ conf.mtime = time.Time{}
if !reflect.DeepEqual(conf, tt.want) {
t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
}
@@ -83,6 +122,10 @@ func TestDNSReadConfig(t *testing.T) {
}
func TestDNSReadMissingFile(t *testing.T) {
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+ getHostname = func() (string, error) { return "host.domain.local", nil }
+
conf := dnsReadConfig("a-nonexistent-file")
if !os.IsNotExist(conf.err) {
t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist)
@@ -91,10 +134,106 @@ func TestDNSReadMissingFile(t *testing.T) {
want := &dnsConfig{
servers: defaultNS,
ndots: 1,
- timeout: 5,
+ timeout: 5 * time.Second,
attempts: 2,
+ search: []string{"domain.local."},
}
if !reflect.DeepEqual(conf, want) {
t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
}
}
+
+var dnsDefaultSearchTests = []struct {
+ name string
+ err error
+ want []string
+}{
+ {
+ name: "host.long.domain.local",
+ want: []string{"long.domain.local."},
+ },
+ {
+ name: "host.local",
+ want: []string{"local."},
+ },
+ {
+ name: "host",
+ want: nil,
+ },
+ {
+ name: "host.domain.local",
+ err: errors.New("errored"),
+ want: nil,
+ },
+ {
+ // ensures we don't return []string{""}
+ // which causes duplicate lookups
+ name: "foo.",
+ want: nil,
+ },
+}
+
+func TestDNSDefaultSearch(t *testing.T) {
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+
+ for _, tt := range dnsDefaultSearchTests {
+ getHostname = func() (string, error) { return tt.name, tt.err }
+ got := dnsDefaultSearch()
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want)
+ }
+ }
+}
+
+func TestDNSNameLength(t *testing.T) {
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+ getHostname = func() (string, error) { return "host.domain.local", nil }
+
+ var char63 = ""
+ for i := 0; i < 63; i++ {
+ char63 += "a"
+ }
+ longDomain := strings.Repeat(char63+".", 5) + "example"
+
+ for _, tt := range dnsReadConfigTests {
+ conf := dnsReadConfig(tt.name)
+ if conf.err != nil {
+ t.Fatal(conf.err)
+ }
+
+ var shortestSuffix int
+ for _, suffix := range tt.want.search {
+ if shortestSuffix == 0 || len(suffix) < shortestSuffix {
+ shortestSuffix = len(suffix)
+ }
+ }
+
+ // Test a name that will be maximally long when prefixing the shortest
+ // suffix (accounting for the intervening dot).
+ longName := longDomain[len(longDomain)-254+1+shortestSuffix:]
+ if longName[0] == '.' || longName[1] == '.' {
+ longName = "aa." + longName[3:]
+ }
+ for _, fqdn := range conf.nameList(longName) {
+ if len(fqdn) > 254 {
+ t.Errorf("got %d; want less than or equal to 254", len(fqdn))
+ }
+ }
+
+ // Now test a name that's too long for suffixing.
+ unsuffixable := "a." + longName[1:]
+ unsuffixableResults := conf.nameList(unsuffixable)
+ if len(unsuffixableResults) != 1 {
+ t.Errorf("suffixed names %v; want []", unsuffixableResults[1:])
+ }
+
+ // Now test a name that's too long for DNS.
+ tooLong := "a." + longDomain
+ tooLongResults := conf.nameList(tooLong)
+ if tooLongResults != nil {
+ t.Errorf("suffixed names %v; want nil", tooLongResults)
+ }
+ }
+}
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
index 93078fe849..8f6c7b6350 100644
--- a/libgo/go/net/dnsmsg.go
+++ b/libgo/go/net/dnsmsg.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DNS packet assembly. See RFC 1035.
+// DNS packet assembly. See RFC 1035.
//
// This is intended to support name resolution during Dial.
// It doesn't have to be blazing fast.
@@ -18,7 +18,7 @@
// generic pack/unpack routines.
//
// TODO(rsc): There are enough names defined in this file that they're all
-// prefixed with dns. Perhaps put this in its own package later.
+// prefixed with dns. Perhaps put this in its own package later.
package net
@@ -69,7 +69,7 @@ const (
)
// A dnsStruct describes how to iterate over its fields to emulate
-// reflective marshalling.
+// reflective marshaling.
type dnsStruct interface {
// Walk iterates over fields of a structure and calls f
// with a reference to that field, the name of the field
@@ -109,7 +109,7 @@ const (
// DNS queries.
type dnsQuestion struct {
- Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
+ Name string
Qtype uint16
Qclass uint16
}
@@ -124,7 +124,7 @@ func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
// There are many types of messages,
// but they all share the same header.
type dnsRR_Header struct {
- Name string `net:"domain-name"`
+ Name string
Rrtype uint16
Class uint16
Ttl uint32
@@ -152,7 +152,7 @@ type dnsRR interface {
type dnsRR_CNAME struct {
Hdr dnsRR_Header
- Cname string `net:"domain-name"`
+ Cname string
}
func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
@@ -163,77 +163,10 @@ func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
}
-type dnsRR_HINFO struct {
- Hdr dnsRR_Header
- Cpu string
- Os string
-}
-
-func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
- return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
-}
-
-type dnsRR_MB struct {
- Hdr dnsRR_Header
- Mb string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MB) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
- return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
-}
-
-type dnsRR_MG struct {
- Hdr dnsRR_Header
- Mg string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MG) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
- return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
-}
-
-type dnsRR_MINFO struct {
- Hdr dnsRR_Header
- Rmail string `net:"domain-name"`
- Email string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
- return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
-}
-
-type dnsRR_MR struct {
- Hdr dnsRR_Header
- Mr string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MR) Header() *dnsRR_Header {
- return &rr.Hdr
-}
-
-func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
- return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
-}
-
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
- Mx string `net:"domain-name"`
+ Mx string
}
func (rr *dnsRR_MX) Header() *dnsRR_Header {
@@ -246,7 +179,7 @@ func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
type dnsRR_NS struct {
Hdr dnsRR_Header
- Ns string `net:"domain-name"`
+ Ns string
}
func (rr *dnsRR_NS) Header() *dnsRR_Header {
@@ -259,7 +192,7 @@ func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
type dnsRR_PTR struct {
Hdr dnsRR_Header
- Ptr string `net:"domain-name"`
+ Ptr string
}
func (rr *dnsRR_PTR) Header() *dnsRR_Header {
@@ -272,8 +205,8 @@ func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
type dnsRR_SOA struct {
Hdr dnsRR_Header
- Ns string `net:"domain-name"`
- Mbox string `net:"domain-name"`
+ Ns string
+ Mbox string
Serial uint32
Refresh uint32
Retry uint32
@@ -315,7 +248,7 @@ func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
if !f(&txt, "Txt", "") {
return false
}
- // more bytes than rr.Hdr.Rdlength said there woudld be
+ // more bytes than rr.Hdr.Rdlength said there would be
if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
return false
}
@@ -330,7 +263,7 @@ type dnsRR_SRV struct {
Priority uint16
Weight uint16
Port uint16
- Target string `net:"domain-name"`
+ Target string
}
func (rr *dnsRR_SRV) Header() *dnsRR_Header {
@@ -347,7 +280,7 @@ func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
type dnsRR_A struct {
Hdr dnsRR_Header
- A uint32 `net:"ipv4"`
+ A uint32
}
func (rr *dnsRR_A) Header() *dnsRR_Header {
@@ -360,7 +293,7 @@ func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
type dnsRR_AAAA struct {
Hdr dnsRR_Header
- AAAA [16]byte `net:"ipv6"`
+ AAAA [16]byte
}
func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
@@ -376,17 +309,12 @@ func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
// All the packers and unpackers take a (msg []byte, off int)
// and return (off1 int, ok bool). If they return ok==false, they
// also return off1==len(msg), so that the next unpacker will
-// also fail. This lets us avoid checks of ok until the end of a
+// also fail. This lets us avoid checks of ok until the end of a
// packing sequence.
// Map of constructors for each RR wire type.
var rr_mk = map[int]func() dnsRR{
dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
- dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
- dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
- dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
- dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
- dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
@@ -399,13 +327,20 @@ var rr_mk = map[int]func() dnsRR{
// Pack a domain name s into msg[off:].
// Domain names are a sequence of counted strings
-// split at the dots. They end with a zero-length string.
+// split at the dots. They end with a zero-length string.
func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
// Add trailing dot to canonicalize name.
if n := len(s); n == 0 || s[n-1] != '.' {
s += "."
}
+ // Allow root domain.
+ if s == "." {
+ msg[off] = 0
+ off++
+ return off, true
+ }
+
// Each dot ends a segment of the name.
// We trade each dot byte for a length byte.
// There is also a trailing zero.
@@ -422,8 +357,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
if i-begin >= 1<<6 { // top two bits of length must be clear
return len(msg), false
}
+ if i-begin == 0 {
+ return len(msg), false
+ }
+
msg[off] = byte(i - begin)
off++
+
for j := begin; j < i; j++ {
msg[off] = s[j]
off++
@@ -440,8 +380,8 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
// In addition to the simple sequences of counted strings above,
// domain names are allowed to refer to strings elsewhere in the
// packet, to avoid repeating common suffixes when returning
-// many entries in a single domain. The pointers are marked
-// by a length byte with the top two bits set. Ignoring those
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
// two bits, that byte and the next give a 14 bit offset from msg[0]
// where we should pick up the trail.
// Note that if we jump elsewhere in the packet,
@@ -494,6 +434,9 @@ Loop:
return "", len(msg), false
}
}
+ if len(s) == 0 {
+ s = "."
+ }
if ptr == 0 {
off1 = off
}
@@ -803,20 +746,32 @@ func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
// Pack it in: header and then the pieces.
off := 0
off, ok = packStruct(&dh, msg, off)
+ if !ok {
+ return nil, false
+ }
for i := 0; i < len(question); i++ {
off, ok = packStruct(&question[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(answer); i++ {
off, ok = packRR(answer[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(ns); i++ {
off, ok = packRR(ns[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(extra); i++ {
off, ok = packRR(extra[i], msg, off)
- }
- if !ok {
- return nil, false
+ if !ok {
+ return nil, false
+ }
}
return msg[0:off], true
}
@@ -848,6 +803,9 @@ func (dns *dnsMsg) Unpack(msg []byte) bool {
for i := 0; i < len(dns.question); i++ {
off, ok = unpackStruct(&dns.question[i], msg, off)
+ if !ok {
+ return false
+ }
}
for i := 0; i < int(dh.Ancount); i++ {
rec, off, ok = unpackRR(msg, off)
@@ -904,3 +862,23 @@ func (dns *dnsMsg) String() string {
}
return s
}
+
+// IsResponseTo reports whether m is an acceptable response to query.
+func (m *dnsMsg) IsResponseTo(query *dnsMsg) bool {
+ if !m.response {
+ return false
+ }
+ if m.id != query.id {
+ return false
+ }
+ if len(m.question) != len(query.question) {
+ return false
+ }
+ for i, q := range m.question {
+ q2 := query.question[i]
+ if !equalASCIILabel(q.Name, q2.Name) || q.Qtype != q2.Qtype || q.Qclass != q2.Qclass {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go
index 1078d77ceb..2a25a21d4c 100644
--- a/libgo/go/net/dnsmsg_test.go
+++ b/libgo/go/net/dnsmsg_test.go
@@ -10,6 +10,103 @@ import (
"testing"
)
+func TestStructPackUnpack(t *testing.T) {
+ want := dnsQuestion{
+ Name: ".",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ }
+ buf := make([]byte, 50)
+ n, ok := packStruct(&want, buf, 0)
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ buf = buf[:n]
+ got := dnsQuestion{}
+ n, ok = unpackStruct(&got, buf, 0)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if n != len(buf) {
+ t.Errorf("unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
+func TestDomainNamePackUnpack(t *testing.T) {
+ tests := []struct {
+ in string
+ want string
+ ok bool
+ }{
+ {"", ".", true},
+ {".", ".", true},
+ {"google..com", "", false},
+ {"google.com", "google.com.", true},
+ {"google..com.", "", false},
+ {"google.com.", "google.com.", true},
+ {".google.com.", "", false},
+ {"www..google.com.", "", false},
+ {"www.google.com.", "www.google.com.", true},
+ }
+
+ for _, test := range tests {
+ buf := make([]byte, 30)
+ n, ok := packDomainName(test.in, buf, 0)
+ if ok != test.ok {
+ t.Errorf("packing of %s: got ok = %t, want = %t", test.in, ok, test.ok)
+ continue
+ }
+ if !test.ok {
+ continue
+ }
+ buf = buf[:n]
+ got, n, ok := unpackDomainName(buf, 0)
+ if !ok {
+ t.Errorf("unpacking for %s failed", test.in)
+ continue
+ }
+ if n != len(buf) {
+ t.Errorf(
+ "unpacked different amount than packed for %s: got n = %d, want = %d",
+ test.in,
+ n,
+ len(buf),
+ )
+ }
+ if got != test.want {
+ t.Errorf("unpacking packing of %s: got = %s, want = %s", test.in, got, test.want)
+ }
+ }
+}
+
+func TestDNSPackUnpack(t *testing.T) {
+ want := dnsMsg{
+ question: []dnsQuestion{{
+ Name: ".",
+ Qtype: dnsTypeAAAA,
+ Qclass: dnsClassINET,
+ }},
+ answer: []dnsRR{},
+ ns: []dnsRR{},
+ extra: []dnsRR{},
+ }
+ b, ok := want.Pack()
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ var got dnsMsg
+ ok = got.Unpack(b)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
func TestDNSParseSRVReply(t *testing.T) {
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {
@@ -20,7 +117,7 @@ func TestDNSParseSRVReply(t *testing.T) {
if !ok {
t.Fatal("unpacking packet failed")
}
- msg.String() // exercise this code path
+ _ = msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -68,7 +165,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
if !ok {
t.Fatal("unpacking packet failed")
}
- msg.String() // exercise this code path
+ _ = msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -183,6 +280,124 @@ func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
}
}
+func TestIsResponseTo(t *testing.T) {
+ // Sample DNS query.
+ query := dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ },
+ },
+ }
+
+ resp := query
+ resp.response = true
+ if !resp.IsResponseTo(&query) {
+ t.Error("got false, want true")
+ }
+
+ badResponses := []dnsMsg{
+ // Different ID.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 43,
+ response: true,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ },
+ },
+ },
+
+ // Different query name.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ response: true,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.google.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ },
+ },
+ },
+
+ // Different query type.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ response: true,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeAAAA,
+ Qclass: dnsClassINET,
+ },
+ },
+ },
+
+ // Different query class.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ response: true,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassCSNET,
+ },
+ },
+ },
+
+ // No questions.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ response: true,
+ },
+ },
+
+ // Extra questions.
+ {
+ dnsMsgHdr: dnsMsgHdr{
+ id: 42,
+ response: true,
+ },
+ question: []dnsQuestion{
+ {
+ Name: "www.example.com.",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ },
+ {
+ Name: "www.golang.org.",
+ Qtype: dnsTypeAAAA,
+ Qclass: dnsClassINET,
+ },
+ },
+ },
+ }
+
+ for i := range badResponses {
+ if badResponses[i].IsResponseTo(&query) {
+ t.Errorf("%v: got true, want false", i)
+ }
+ }
+}
+
// Valid DNS SRV reply
const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
index be07dc6a16..e0f786dec8 100644
--- a/libgo/go/net/dnsname_test.go
+++ b/libgo/go/net/dnsname_test.go
@@ -15,7 +15,7 @@ type dnsNameTest struct {
}
var dnsNameTests = []dnsNameTest{
- // RFC2181, section 11.
+ // RFC 2181, section 11.
{"_xmpp-server._tcp.google.com", true},
{"foo.com", true},
{"1foo.com", true},
@@ -32,14 +32,12 @@ var dnsNameTests = []dnsNameTest{
func emitDNSNameTest(ch chan<- dnsNameTest) {
defer close(ch)
- var char59 = ""
var char63 = ""
- var char64 = ""
- for i := 0; i < 59; i++ {
- char59 += "a"
+ for i := 0; i < 63; i++ {
+ char63 += "a"
}
- char63 = char59 + "aaaa"
- char64 = char63 + "a"
+ char64 := char63 + "a"
+ longDomain := strings.Repeat(char63+".", 5) + "example"
for _, tc := range dnsNameTests {
ch <- tc
@@ -47,14 +45,15 @@ func emitDNSNameTest(ch chan<- dnsNameTest) {
ch <- dnsNameTest{char63 + ".com", true}
ch <- dnsNameTest{char64 + ".com", false}
- // 255 char name is fine:
- ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." +
- char63 + ".com",
- true}
- // 256 char name is bad:
- ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." +
- char63 + ".com",
- false}
+
+ // Remember: wire format is two octets longer than presentation
+ // (length octets for the first and [root] last labels).
+ // 253 is fine:
+ ch <- dnsNameTest{longDomain[len(longDomain)-253:], true}
+ // A terminal dot doesn't contribute to length:
+ ch <- dnsNameTest{longDomain[len(longDomain)-253:] + ".", true}
+ // 254 is bad:
+ ch <- dnsNameTest{longDomain[len(longDomain)-254:], false}
}
func TestDNSName(t *testing.T) {
diff --git a/libgo/go/net/error_plan9_test.go b/libgo/go/net/error_plan9_test.go
index 495ea96534..d7c7f1487f 100644
--- a/libgo/go/net/error_plan9_test.go
+++ b/libgo/go/net/error_plan9_test.go
@@ -9,6 +9,8 @@ import "syscall"
var (
errTimedout = syscall.ETIMEDOUT
errOpNotSupported = syscall.EPLAN9
+
+ abortedConnRequestErrors []error
)
func isPlatformError(err error) bool {
diff --git a/libgo/go/net/error_posix_test.go b/libgo/go/net/error_posix_test.go
index 981cc837ba..b411a378df 100644
--- a/libgo/go/net/error_posix_test.go
+++ b/libgo/go/net/error_posix_test.go
@@ -12,16 +12,6 @@ import (
"testing"
)
-var (
- errTimedout = syscall.ETIMEDOUT
- errOpNotSupported = syscall.EOPNOTSUPP
-)
-
-func isPlatformError(err error) bool {
- _, ok := err.(syscall.Errno)
- return ok
-}
-
func TestSpuriousENOTAVAIL(t *testing.T) {
for _, tt := range []struct {
error
diff --git a/libgo/go/net/error_test.go b/libgo/go/net/error_test.go
index 1aab14c449..c23da49fad 100644
--- a/libgo/go/net/error_test.go
+++ b/libgo/go/net/error_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "context"
"fmt"
"io"
"io/ioutil"
@@ -91,9 +92,13 @@ second:
case *os.SyscallError:
nestedErr = err.Err
goto third
+ case *os.PathError: // for Plan 9
+ nestedErr = err.Err
+ goto third
}
switch nestedErr {
- case errCanceled, errClosing, errMissingAddress:
+ case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress,
+ context.DeadlineExceeded, context.Canceled:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -135,7 +140,7 @@ func TestDialError(t *testing.T) {
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
- testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+ testHookLookupIP = func(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
}
sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
@@ -203,6 +208,62 @@ func TestProtocolDialError(t *testing.T) {
}
}
+func TestDialAddrError(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("not supported on %s", runtime.GOOS)
+ }
+ if !supportsIPv4 || !supportsIPv6 {
+ t.Skip("both IPv4 and IPv6 are required")
+ }
+
+ for _, tt := range []struct {
+ network string
+ lit string
+ addr *TCPAddr
+ }{
+ {"tcp4", "::1", nil},
+ {"tcp4", "", &TCPAddr{IP: IPv6loopback}},
+ // We don't test the {"tcp6", "byte sequence", nil}
+ // case for now because there is no easy way to
+ // control name resolution.
+ {"tcp6", "", &TCPAddr{IP: IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}},
+ } {
+ var err error
+ var c Conn
+ var op string
+ if tt.lit != "" {
+ c, err = Dial(tt.network, JoinHostPort(tt.lit, "0"))
+ op = fmt.Sprintf("Dial(%q, %q)", tt.network, JoinHostPort(tt.lit, "0"))
+ } else {
+ c, err = DialTCP(tt.network, nil, tt.addr)
+ op = fmt.Sprintf("DialTCP(%q, %q)", tt.network, tt.addr)
+ }
+ if err == nil {
+ c.Close()
+ t.Errorf("%s succeeded, want error", op)
+ continue
+ }
+ if perr := parseDialError(err); perr != nil {
+ t.Errorf("%s: %v", op, perr)
+ continue
+ }
+ operr := err.(*OpError).Err
+ aerr, ok := operr.(*AddrError)
+ if !ok {
+ t.Errorf("%s: %v is %T, want *AddrError", op, err, operr)
+ continue
+ }
+ want := tt.lit
+ if tt.lit == "" {
+ want = tt.addr.IP.String()
+ }
+ if aerr.Addr != want {
+ t.Errorf("%s: %v, error Addr=%q, want %q", op, err, aerr.Addr, want)
+ }
+ }
+}
+
var listenErrorTests = []struct {
network, address string
}{
@@ -228,7 +289,7 @@ func TestListenError(t *testing.T) {
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
- testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+ testHookLookupIP = func(_ context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
}
sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
@@ -288,7 +349,7 @@ func TestListenPacketError(t *testing.T) {
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
- testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+ testHookLookupIP = func(_ context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
}
@@ -413,7 +474,7 @@ second:
goto third
}
switch nestedErr {
- case errCanceled, errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+ case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -465,6 +526,10 @@ third:
if isPlatformError(nestedErr) {
return nil
}
+ switch nestedErr {
+ case os.ErrClosed: // for Plan 9
+ return nil
+ }
return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
}
@@ -543,6 +608,9 @@ second:
case *os.SyscallError:
nestedErr = err.Err
goto third
+ case *os.PathError: // for Plan 9
+ nestedErr = err.Err
+ goto third
}
switch nestedErr {
case errClosing, errTimeout:
@@ -703,3 +771,17 @@ func TestFileError(t *testing.T) {
ln.Close()
}
}
+
+func parseLookupPortError(nestedErr error) error {
+ if nestedErr == nil {
+ return nil
+ }
+
+ switch nestedErr.(type) {
+ case *AddrError, *DNSError:
+ return nil
+ case *os.PathError: // for Plan 9
+ return nil
+ }
+ return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+}
diff --git a/libgo/go/net/error_unix_test.go b/libgo/go/net/error_unix_test.go
new file mode 100644
index 0000000000..9ce9e12c5e
--- /dev/null
+++ b/libgo/go/net/error_unix_test.go
@@ -0,0 +1,34 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+var (
+ errTimedout = syscall.ETIMEDOUT
+ errOpNotSupported = syscall.EOPNOTSUPP
+
+ abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go
+)
+
+func isPlatformError(err error) bool {
+ _, ok := err.(syscall.Errno)
+ return ok
+}
+
+func samePlatformError(err, want error) bool {
+ if op, ok := err.(*OpError); ok {
+ err = op.Err
+ }
+ if sys, ok := err.(*os.SyscallError); ok {
+ err = sys.Err
+ }
+ return err == want
+}
diff --git a/libgo/go/net/error_windows_test.go b/libgo/go/net/error_windows_test.go
new file mode 100644
index 0000000000..834a9de441
--- /dev/null
+++ b/libgo/go/net/error_windows_test.go
@@ -0,0 +1,19 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "syscall"
+
+var (
+ errTimedout = syscall.ETIMEDOUT
+ errOpNotSupported = syscall.EOPNOTSUPP
+
+ abortedConnRequestErrors = []error{syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET} // see accept in fd_windows.go
+)
+
+func isPlatformError(err error) bool {
+ _, ok := err.(syscall.Errno)
+ return ok
+}
diff --git a/libgo/go/net/external_test.go b/libgo/go/net/external_test.go
index d5ff2be20a..e18b547cac 100644
--- a/libgo/go/net/external_test.go
+++ b/libgo/go/net/external_test.go
@@ -6,15 +6,15 @@ package net
import (
"fmt"
+ "internal/testenv"
"io"
"strings"
"testing"
)
func TestResolveGoogle(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
@@ -60,9 +60,8 @@ var dialGoogleTests = []struct {
}
func TestDialGoogle(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
diff --git a/libgo/go/net/fd_io_plan9.go b/libgo/go/net/fd_io_plan9.go
new file mode 100644
index 0000000000..76da0c546c
--- /dev/null
+++ b/libgo/go/net/fd_io_plan9.go
@@ -0,0 +1,93 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "runtime"
+ "sync"
+ "syscall"
+)
+
+// asyncIO implements asynchronous cancelable I/O.
+// An asyncIO represents a single asynchronous Read or Write
+// operation. The result is returned on the result channel.
+// The undergoing I/O system call can either complete or be
+// interrupted by a note.
+type asyncIO struct {
+ res chan result
+
+ // mu guards the pid field.
+ mu sync.Mutex
+
+ // pid holds the process id of
+ // the process running the IO operation.
+ pid int
+}
+
+// result is the return value of a Read or Write operation.
+type result struct {
+ n int
+ err error
+}
+
+// newAsyncIO returns a new asyncIO that performs an I/O
+// operation by calling fn, which must do one and only one
+// interruptible system call.
+func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
+ aio := &asyncIO{
+ res: make(chan result, 0),
+ }
+ aio.mu.Lock()
+ go func() {
+ // Lock the current goroutine to its process
+ // and store the pid in io so that Cancel can
+ // interrupt it. We ignore the "hangup" signal,
+ // so the signal does not take down the entire
+ // Go runtime.
+ runtime.LockOSThread()
+ runtime_ignoreHangup()
+ aio.pid = os.Getpid()
+ aio.mu.Unlock()
+
+ n, err := fn(b)
+
+ aio.mu.Lock()
+ aio.pid = -1
+ runtime_unignoreHangup()
+ aio.mu.Unlock()
+
+ aio.res <- result{n, err}
+ }()
+ return aio
+}
+
+var hangupNote os.Signal = syscall.Note("hangup")
+
+// Cancel interrupts the I/O operation, causing
+// the Wait function to return.
+func (aio *asyncIO) Cancel() {
+ aio.mu.Lock()
+ defer aio.mu.Unlock()
+ if aio.pid == -1 {
+ return
+ }
+ proc, err := os.FindProcess(aio.pid)
+ if err != nil {
+ return
+ }
+ proc.Signal(hangupNote)
+}
+
+// Wait for the I/O operation to complete.
+func (aio *asyncIO) Wait() (int, error) {
+ res := <-aio.res
+ return res.n, res.err
+}
+
+// The following functions, provided by the runtime, are used to
+// ignore and unignore the "hangup" signal received by the process.
+func runtime_ignoreHangup()
+func runtime_unignoreHangup()
diff --git a/libgo/go/net/fd_mutex.go b/libgo/go/net/fd_mutex.go
index 6d5509d7f2..4591fd1cac 100644
--- a/libgo/go/net/fd_mutex.go
+++ b/libgo/go/net/fd_mutex.go
@@ -6,9 +6,9 @@ package net
import "sync/atomic"
-// fdMutex is a specialized synchronization primitive
-// that manages lifetime of an fd and serializes access
-// to Read and Write methods on netFD.
+// fdMutex is a specialized synchronization primitive that manages
+// lifetime of an fd and serializes access to Read, Write and Close
+// methods on netFD.
type fdMutex struct {
state uint64
rsema uint32
@@ -34,18 +34,21 @@ const (
mutexWMask = (1<<20 - 1) << 43
)
-// Read operations must do RWLock(true)/RWUnlock(true).
-// Write operations must do RWLock(false)/RWUnlock(false).
-// Misc operations must do Incref/Decref. Misc operations include functions like
-// setsockopt and setDeadline. They need to use Incref/Decref to ensure that
-// they operate on the correct fd in presence of a concurrent Close call
-// (otherwise fd can be closed under their feet).
-// Close operation must do IncrefAndClose/Decref.
+// Read operations must do rwlock(true)/rwunlock(true).
+//
+// Write operations must do rwlock(false)/rwunlock(false).
+//
+// Misc operations must do incref/decref.
+// Misc operations include functions like setsockopt and setDeadline.
+// They need to use incref/decref to ensure that they operate on the
+// correct fd in presence of a concurrent close call (otherwise fd can
+// be closed under their feet).
+//
+// Close operations must do increfAndClose/decref.
-// RWLock/Incref return whether fd is open.
-// RWUnlock/Decref return whether fd is closed and there are no remaining references.
-
-func (mu *fdMutex) Incref() bool {
+// incref adds a reference to mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) incref() bool {
for {
old := atomic.LoadUint64(&mu.state)
if old&mutexClosed != 0 {
@@ -61,7 +64,9 @@ func (mu *fdMutex) Incref() bool {
}
}
-func (mu *fdMutex) IncrefAndClose() bool {
+// increfAndClose sets the state of mu to closed.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) increfAndClose() bool {
for {
old := atomic.LoadUint64(&mu.state)
if old&mutexClosed != 0 {
@@ -90,7 +95,9 @@ func (mu *fdMutex) IncrefAndClose() bool {
}
}
-func (mu *fdMutex) Decref() bool {
+// decref removes a reference from mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) decref() bool {
for {
old := atomic.LoadUint64(&mu.state)
if old&mutexRefMask == 0 {
@@ -103,7 +110,9 @@ func (mu *fdMutex) Decref() bool {
}
}
-func (mu *fdMutex) RWLock(read bool) bool {
+// lock adds a reference to mu and locks mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) rwlock(read bool) bool {
var mutexBit, mutexWait, mutexMask uint64
var mutexSema *uint32
if read {
@@ -146,7 +155,9 @@ func (mu *fdMutex) RWLock(read bool) bool {
}
}
-func (mu *fdMutex) RWUnlock(read bool) bool {
+// unlock removes a reference from mu and unlocks mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) rwunlock(read bool) bool {
var mutexBit, mutexWait, mutexMask uint64
var mutexSema *uint32
if read {
@@ -182,3 +193,57 @@ func (mu *fdMutex) RWUnlock(read bool) bool {
// Implemented in runtime package.
func runtime_Semacquire(sema *uint32)
func runtime_Semrelease(sema *uint32)
+
+// incref adds a reference to fd.
+// It returns an error when fd cannot be used.
+func (fd *netFD) incref() error {
+ if !fd.fdmu.incref() {
+ return errClosing
+ }
+ return nil
+}
+
+// decref removes a reference from fd.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) decref() {
+ if fd.fdmu.decref() {
+ fd.destroy()
+ }
+}
+
+// readLock adds a reference to fd and locks fd for reading.
+// It returns an error when fd cannot be used for reading.
+func (fd *netFD) readLock() error {
+ if !fd.fdmu.rwlock(true) {
+ return errClosing
+ }
+ return nil
+}
+
+// readUnlock removes a reference from fd and unlocks fd for reading.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) readUnlock() {
+ if fd.fdmu.rwunlock(true) {
+ fd.destroy()
+ }
+}
+
+// writeLock adds a reference to fd and locks fd for writing.
+// It returns an error when fd cannot be used for writing.
+func (fd *netFD) writeLock() error {
+ if !fd.fdmu.rwlock(false) {
+ return errClosing
+ }
+ return nil
+}
+
+// writeUnlock removes a reference from fd and unlocks fd for writing.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) writeUnlock() {
+ if fd.fdmu.rwunlock(false) {
+ fd.destroy()
+ }
+}
diff --git a/libgo/go/net/fd_mutex_test.go b/libgo/go/net/fd_mutex_test.go
index c34ec59b99..3542c70f9d 100644
--- a/libgo/go/net/fd_mutex_test.go
+++ b/libgo/go/net/fd_mutex_test.go
@@ -14,44 +14,44 @@ import (
func TestMutexLock(t *testing.T) {
var mu fdMutex
- if !mu.Incref() {
+ if !mu.incref() {
t.Fatal("broken")
}
- if mu.Decref() {
+ if mu.decref() {
t.Fatal("broken")
}
- if !mu.RWLock(true) {
+ if !mu.rwlock(true) {
t.Fatal("broken")
}
- if mu.RWUnlock(true) {
+ if mu.rwunlock(true) {
t.Fatal("broken")
}
- if !mu.RWLock(false) {
+ if !mu.rwlock(false) {
t.Fatal("broken")
}
- if mu.RWUnlock(false) {
+ if mu.rwunlock(false) {
t.Fatal("broken")
}
}
func TestMutexClose(t *testing.T) {
var mu fdMutex
- if !mu.IncrefAndClose() {
+ if !mu.increfAndClose() {
t.Fatal("broken")
}
- if mu.Incref() {
+ if mu.incref() {
t.Fatal("broken")
}
- if mu.RWLock(true) {
+ if mu.rwlock(true) {
t.Fatal("broken")
}
- if mu.RWLock(false) {
+ if mu.rwlock(false) {
t.Fatal("broken")
}
- if mu.IncrefAndClose() {
+ if mu.increfAndClose() {
t.Fatal("broken")
}
}
@@ -59,10 +59,10 @@ func TestMutexClose(t *testing.T) {
func TestMutexCloseUnblock(t *testing.T) {
c := make(chan bool)
var mu fdMutex
- mu.RWLock(true)
+ mu.rwlock(true)
for i := 0; i < 4; i++ {
go func() {
- if mu.RWLock(true) {
+ if mu.rwlock(true) {
t.Error("broken")
return
}
@@ -76,7 +76,7 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken")
default:
}
- mu.IncrefAndClose() // Must unblock the readers.
+ mu.increfAndClose() // Must unblock the readers.
for i := 0; i < 4; i++ {
select {
case <-c:
@@ -84,10 +84,10 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken")
}
}
- if mu.Decref() {
+ if mu.decref() {
t.Fatal("broken")
}
- if !mu.RWUnlock(true) {
+ if !mu.rwunlock(true) {
t.Fatal("broken")
}
}
@@ -103,21 +103,21 @@ func TestMutexPanic(t *testing.T) {
}
var mu fdMutex
- ensurePanics(func() { mu.Decref() })
- ensurePanics(func() { mu.RWUnlock(true) })
- ensurePanics(func() { mu.RWUnlock(false) })
+ ensurePanics(func() { mu.decref() })
+ ensurePanics(func() { mu.rwunlock(true) })
+ ensurePanics(func() { mu.rwunlock(false) })
- ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
- ensurePanics(func() { mu.RWLock(true); mu.RWUnlock(true); mu.RWUnlock(true) })
- ensurePanics(func() { mu.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
+ ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() })
+ ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) })
+ ensurePanics(func() { mu.rwlock(false); mu.rwunlock(false); mu.rwunlock(false) })
// ensure that it's still not broken
- mu.Incref()
- mu.Decref()
- mu.RWLock(true)
- mu.RWUnlock(true)
- mu.RWLock(false)
- mu.RWUnlock(false)
+ mu.incref()
+ mu.decref()
+ mu.rwlock(true)
+ mu.rwunlock(true)
+ mu.rwlock(false)
+ mu.rwunlock(false)
}
func TestMutexStress(t *testing.T) {
@@ -138,16 +138,16 @@ func TestMutexStress(t *testing.T) {
for i := 0; i < N; i++ {
switch r.Intn(3) {
case 0:
- if !mu.Incref() {
+ if !mu.incref() {
t.Error("broken")
return
}
- if mu.Decref() {
+ if mu.decref() {
t.Error("broken")
return
}
case 1:
- if !mu.RWLock(true) {
+ if !mu.rwlock(true) {
t.Error("broken")
return
}
@@ -158,12 +158,12 @@ func TestMutexStress(t *testing.T) {
}
readState[0]++
readState[1]++
- if mu.RWUnlock(true) {
+ if mu.rwunlock(true) {
t.Error("broken")
return
}
case 2:
- if !mu.RWLock(false) {
+ if !mu.rwlock(false) {
t.Error("broken")
return
}
@@ -174,7 +174,7 @@ func TestMutexStress(t *testing.T) {
}
writeState[0]++
writeState[1]++
- if mu.RWUnlock(false) {
+ if mu.rwunlock(false) {
t.Error("broken")
return
}
@@ -186,10 +186,10 @@ func TestMutexStress(t *testing.T) {
for p := 0; p < P; p++ {
<-done
}
- if !mu.IncrefAndClose() {
+ if !mu.increfAndClose() {
t.Fatal("broken")
}
- if !mu.Decref() {
+ if !mu.decref() {
t.Fatal("broken")
}
}
diff --git a/libgo/go/net/fd_plan9.go b/libgo/go/net/fd_plan9.go
index cec88609d0..300d8c4543 100644
--- a/libgo/go/net/fd_plan9.go
+++ b/libgo/go/net/fd_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,21 +7,37 @@ package net
import (
"io"
"os"
+ "sync/atomic"
"syscall"
"time"
)
+type atomicBool int32
+
+func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
+func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
+func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
+
// Network file descriptor.
type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods
fdmu fdMutex
// immutable until Close
- net string
- n string
- dir string
- ctl, data *os.File
- laddr, raddr Addr
+ net string
+ n string
+ dir string
+ listen, ctl, data *os.File
+ laddr, raddr Addr
+ isStream bool
+
+ // deadlines
+ raio *asyncIO
+ waio *asyncIO
+ rtimer *time.Timer
+ wtimer *time.Timer
+ rtimedout atomicBool // set true when read deadline has been reached
+ wtimedout atomicBool // set true when write deadline has been reached
}
var (
@@ -32,14 +48,16 @@ func sysInit() {
netdir = "/net"
}
-func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
- // On plan9, use the relatively inefficient
- // goroutine-racing implementation.
- return dialChannel(net, ra, dialer, deadline)
-}
-
-func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
- return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+ return &netFD{
+ net: net,
+ n: name,
+ dir: netdir + "/" + net + "/" + name,
+ listen: listen,
+ ctl: ctl, data: data,
+ laddr: laddr,
+ raddr: raddr,
+ }, nil
}
func (fd *netFD) init() error {
@@ -70,60 +88,20 @@ func (fd *netFD) destroy() {
err = err1
}
}
+ if fd.listen != nil {
+ if err1 := fd.listen.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
fd.ctl = nil
fd.data = nil
-}
-
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
- if !fd.fdmu.Incref() {
- return errClosing
- }
- return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
- if fd.fdmu.Decref() {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
- if !fd.fdmu.RWLock(true) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
- if fd.fdmu.RWUnlock(true) {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
- if !fd.fdmu.RWLock(false) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
- if fd.fdmu.RWUnlock(false) {
- fd.destroy()
- }
+ fd.listen = nil
}
func (fd *netFD) Read(b []byte) (n int, err error) {
+ if fd.rtimedout.isSet() {
+ return 0, errTimeout
+ }
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
@@ -131,7 +109,18 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
return 0, err
}
defer fd.readUnlock()
- n, err = fd.data.Read(b)
+ if len(b) == 0 {
+ return 0, nil
+ }
+ fd.raio = newAsyncIO(fd.data.Read, b)
+ n, err = fd.raio.Wait()
+ fd.raio = nil
+ if isHangup(err) {
+ err = io.EOF
+ }
+ if isInterrupted(err) {
+ err = errTimeout
+ }
if fd.net == "udp" && err == io.EOF {
n = 0
err = nil
@@ -140,6 +129,9 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
}
func (fd *netFD) Write(b []byte) (n int, err error) {
+ if fd.wtimedout.isSet() {
+ return 0, errTimeout
+ }
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
@@ -147,7 +139,13 @@ func (fd *netFD) Write(b []byte) (n int, err error) {
return 0, err
}
defer fd.writeUnlock()
- return fd.data.Write(b)
+ fd.waio = newAsyncIO(fd.data.Write, b)
+ n, err = fd.waio.Wait()
+ fd.waio = nil
+ if isInterrupted(err) {
+ err = errTimeout
+ }
+ return
}
func (fd *netFD) closeRead() error {
@@ -165,7 +163,7 @@ func (fd *netFD) closeWrite() error {
}
func (fd *netFD) Close() error {
- if !fd.fdmu.IncrefAndClose() {
+ if !fd.fdmu.increfAndClose() {
return errClosing
}
if !fd.ok() {
@@ -173,11 +171,10 @@ func (fd *netFD) Close() error {
}
if fd.net == "tcp" {
// The following line is required to unblock Reads.
- // For some reason, WriteString returns an error:
- // "write /net/tcp/39/listen: inappropriate use of fd"
- // But without it, Reads on dead conns hang forever.
- // See Issue 9554.
- fd.ctl.WriteString("hangup")
+ _, err := fd.ctl.WriteString("close")
+ if err != nil {
+ return err
+ }
}
err := fd.ctl.Close()
if fd.data != nil {
@@ -185,8 +182,14 @@ func (fd *netFD) Close() error {
err = err1
}
}
+ if fd.listen != nil {
+ if err1 := fd.listen.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
fd.ctl = nil
fd.data = nil
+ fd.listen = nil
return err
}
@@ -206,9 +209,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)
}
@@ -216,15 +217,74 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
}
func (fd *netFD) setDeadline(t time.Time) error {
- return syscall.EPLAN9
+ return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *netFD) setReadDeadline(t time.Time) error {
- return syscall.EPLAN9
+ return setDeadlineImpl(fd, t, 'r')
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
- return syscall.EPLAN9
+ return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+ d := t.Sub(time.Now())
+ if mode == 'r' || mode == 'r'+'w' {
+ fd.rtimedout.setFalse()
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ fd.wtimedout.setFalse()
+ }
+ if t.IsZero() || d < 0 {
+ // Stop timer
+ if mode == 'r' || mode == 'r'+'w' {
+ if fd.rtimer != nil {
+ fd.rtimer.Stop()
+ }
+ fd.rtimer = nil
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ if fd.wtimer != nil {
+ fd.wtimer.Stop()
+ }
+ fd.wtimer = nil
+ }
+ } else {
+ // Interrupt I/O operation once timer has expired
+ if mode == 'r' || mode == 'r'+'w' {
+ fd.rtimer = time.AfterFunc(d, func() {
+ fd.rtimedout.setTrue()
+ if fd.raio != nil {
+ fd.raio.Cancel()
+ }
+ })
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ fd.wtimer = time.AfterFunc(d, func() {
+ fd.wtimedout.setTrue()
+ if fd.waio != nil {
+ fd.waio.Cancel()
+ }
+ })
+ }
+ }
+ if !t.IsZero() && d < 0 {
+ // Interrupt current I/O operation
+ if mode == 'r' || mode == 'r'+'w' {
+ fd.rtimedout.setTrue()
+ if fd.raio != nil {
+ fd.raio.Cancel()
+ }
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ fd.wtimedout.setTrue()
+ if fd.waio != nil {
+ fd.waio.Cancel()
+ }
+ }
+ }
+ return nil
}
func setReadBuffer(fd *netFD, bytes int) error {
@@ -234,3 +294,11 @@ func setReadBuffer(fd *netFD, bytes int) error {
func setWriteBuffer(fd *netFD, bytes int) error {
return syscall.EPLAN9
}
+
+func isHangup(err error) bool {
+ return err != nil && stringsHasSuffix(err.Error(), "Hangup")
+}
+
+func isInterrupted(err error) bool {
+ return err != nil && stringsHasSuffix(err.Error(), "interrupted")
+}
diff --git a/libgo/go/net/fd_poll_nacl.go b/libgo/go/net/fd_poll_nacl.go
index cdf14e32ce..83987602a5 100644
--- a/libgo/go/net/fd_poll_nacl.go
+++ b/libgo/go/net/fd_poll_nacl.go
@@ -1,10 +1,11 @@
-// 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.
package net
import (
+ "runtime"
"syscall"
"time"
)
@@ -14,44 +15,45 @@ type pollDesc struct {
closing bool
}
-func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+func (pd *pollDesc) init(fd *netFD) error { pd.fd = fd; return nil }
-func (pd *pollDesc) Close() {}
+func (pd *pollDesc) close() {}
-func (pd *pollDesc) Evict() {
+func (pd *pollDesc) evict() {
pd.closing = true
if pd.fd != nil {
syscall.StopIO(pd.fd.sysfd)
+ runtime.KeepAlive(pd.fd)
}
}
-func (pd *pollDesc) Prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int) error {
if pd.closing {
return errClosing
}
return nil
}
-func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+func (pd *pollDesc) prepareRead() error { return pd.prepare('r') }
-func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+func (pd *pollDesc) prepareWrite() error { return pd.prepare('w') }
-func (pd *pollDesc) Wait(mode int) error {
+func (pd *pollDesc) wait(mode int) error {
if pd.closing {
return errClosing
}
return errTimeout
}
-func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+func (pd *pollDesc) waitRead() error { return pd.wait('r') }
-func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+func (pd *pollDesc) waitWrite() error { return pd.wait('w') }
-func (pd *pollDesc) WaitCanceled(mode int) {}
+func (pd *pollDesc) waitCanceled(mode int) {}
-func (pd *pollDesc) WaitCanceledRead() {}
+func (pd *pollDesc) waitCanceledRead() {}
-func (pd *pollDesc) WaitCanceledWrite() {}
+func (pd *pollDesc) waitCanceledWrite() {}
func (fd *netFD) setDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w')
diff --git a/libgo/go/net/fd_poll_runtime.go b/libgo/go/net/fd_poll_runtime.go
index 8522ccebfb..62b69fcbf1 100644
--- a/libgo/go/net/fd_poll_runtime.go
+++ b/libgo/go/net/fd_poll_runtime.go
@@ -7,6 +7,7 @@
package net
import (
+ "runtime"
"sync"
"syscall"
"time"
@@ -30,9 +31,10 @@ type pollDesc struct {
var serverInit sync.Once
-func (pd *pollDesc) Init(fd *netFD) error {
+func (pd *pollDesc) init(fd *netFD) error {
serverInit.Do(runtime_pollServerInit)
ctx, errno := runtime_pollOpen(uintptr(fd.sysfd))
+ runtime.KeepAlive(fd)
if errno != 0 {
return syscall.Errno(errno)
}
@@ -40,7 +42,7 @@ func (pd *pollDesc) Init(fd *netFD) error {
return nil
}
-func (pd *pollDesc) Close() {
+func (pd *pollDesc) close() {
if pd.runtimeCtx == 0 {
return
}
@@ -49,49 +51,49 @@ func (pd *pollDesc) Close() {
}
// Evict evicts fd from the pending list, unblocking any I/O running on fd.
-func (pd *pollDesc) Evict() {
+func (pd *pollDesc) evict() {
if pd.runtimeCtx == 0 {
return
}
runtime_pollUnblock(pd.runtimeCtx)
}
-func (pd *pollDesc) Prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int) error {
res := runtime_pollReset(pd.runtimeCtx, mode)
return convertErr(res)
}
-func (pd *pollDesc) PrepareRead() error {
- return pd.Prepare('r')
+func (pd *pollDesc) prepareRead() error {
+ return pd.prepare('r')
}
-func (pd *pollDesc) PrepareWrite() error {
- return pd.Prepare('w')
+func (pd *pollDesc) prepareWrite() error {
+ return pd.prepare('w')
}
-func (pd *pollDesc) Wait(mode int) error {
+func (pd *pollDesc) wait(mode int) error {
res := runtime_pollWait(pd.runtimeCtx, mode)
return convertErr(res)
}
-func (pd *pollDesc) WaitRead() error {
- return pd.Wait('r')
+func (pd *pollDesc) waitRead() error {
+ return pd.wait('r')
}
-func (pd *pollDesc) WaitWrite() error {
- return pd.Wait('w')
+func (pd *pollDesc) waitWrite() error {
+ return pd.wait('w')
}
-func (pd *pollDesc) WaitCanceled(mode int) {
+func (pd *pollDesc) waitCanceled(mode int) {
runtime_pollWaitCanceled(pd.runtimeCtx, mode)
}
-func (pd *pollDesc) WaitCanceledRead() {
- pd.WaitCanceled('r')
+func (pd *pollDesc) waitCanceledRead() {
+ pd.waitCanceled('r')
}
-func (pd *pollDesc) WaitCanceledWrite() {
- pd.WaitCanceled('w')
+func (pd *pollDesc) waitCanceledWrite() {
+ pd.waitCanceled('w')
}
func convertErr(res int) error {
@@ -120,7 +122,13 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
- d := runtimeNano() + int64(t.Sub(time.Now()))
+ diff := int64(time.Until(t))
+ d := runtimeNano() + diff
+ if d <= 0 && diff > 0 {
+ // If the user has a deadline in the future, but the delay calculation
+ // overflows, then set the deadline to the maximum possible value.
+ d = 1<<63 - 1
+ }
if t.IsZero() {
d = 0
}
diff --git a/libgo/go/net/fd_select.go b/libgo/go/net/fd_select.go
deleted file mode 100644
index 4103c57e2c..0000000000
--- a/libgo/go/net/fd_select.go
+++ /dev/null
@@ -1,182 +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.
-
-// Waiting for FDs via select(2).
-
-package net
-
-import (
- "errors"
- "os"
- "syscall"
-)
-
-type pollster struct {
- readFds, writeFds, repeatFds *syscall.FdSet
- maxFd int
- readyReadFds, readyWriteFds *syscall.FdSet
- nReady int
- lastFd int
- closed bool
-}
-
-func newpollster() (p *pollster, err error) {
- p = new(pollster)
- p.readFds = new(syscall.FdSet)
- p.writeFds = new(syscall.FdSet)
- p.repeatFds = new(syscall.FdSet)
- p.readyReadFds = new(syscall.FdSet)
- p.readyWriteFds = new(syscall.FdSet)
- p.maxFd = -1
- p.nReady = 0
- p.lastFd = 0
- return p, nil
-}
-
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
- // pollServer is locked.
-
- if p.closed {
- return false, errors.New("pollster closed")
- }
-
- if mode == 'r' {
- syscall.FDSet(fd, p.readFds)
- } else {
- syscall.FDSet(fd, p.writeFds)
- }
-
- if repeat {
- syscall.FDSet(fd, p.repeatFds)
- }
-
- if fd > p.maxFd {
- p.maxFd = fd
- }
-
- return true, nil
-}
-
-func (p *pollster) DelFD(fd int, mode int) bool {
- // pollServer is locked.
-
- if p.closed {
- return false
- }
-
- if mode == 'r' {
- if !syscall.FDIsSet(fd, p.readFds) {
- print("Select unexpected fd=", fd, " for read\n")
- return false
- }
- syscall.FDClr(fd, p.readFds)
- } else {
- if !syscall.FDIsSet(fd, p.writeFds) {
- print("Select unexpected fd=", fd, " for write\n")
- return false
- }
- syscall.FDClr(fd, p.writeFds)
- }
-
- // Doesn't matter if not already present.
- syscall.FDClr(fd, p.repeatFds)
-
- // We don't worry about maxFd here.
-
- return true
-}
-
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
- if p.nReady == 0 {
- var timeout *syscall.Timeval
- var tv syscall.Timeval
- timeout = nil
- if nsec > 0 {
- tv = syscall.NsecToTimeval(nsec)
- timeout = &tv
- }
-
- var n int
- var e error
- var tmpReadFds, tmpWriteFds syscall.FdSet
- for {
- if p.closed {
- return -1, 0, errors.New("pollster closed")
- }
-
- // Temporary syscall.FdSet's into which the values are copied
- // because select mutates the values.
- tmpReadFds = *p.readFds
- tmpWriteFds = *p.writeFds
-
- s.Unlock()
- n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout)
- s.Lock()
-
- if e != syscall.EINTR {
- break
- }
- }
- if e == syscall.EBADF {
- // Some file descriptor has been closed.
- tmpReadFds = syscall.FdSet{}
- tmpWriteFds = syscall.FdSet{}
- n = 0
- for i := 0; i < p.maxFd+1; i++ {
- if syscall.FDIsSet(i, p.readFds) {
- var s syscall.Stat_t
- if syscall.Fstat(i, &s) == syscall.EBADF {
- syscall.FDSet(i, &tmpReadFds)
- n++
- }
- } else if syscall.FDIsSet(i, p.writeFds) {
- var s syscall.Stat_t
- if syscall.Fstat(i, &s) == syscall.EBADF {
- syscall.FDSet(i, &tmpWriteFds)
- n++
- }
- }
- }
- } else if e != nil {
- return -1, 0, os.NewSyscallError("select", e)
- }
- if n == 0 {
- return -1, 0, nil
- }
-
- p.nReady = n
- *p.readyReadFds = tmpReadFds
- *p.readyWriteFds = tmpWriteFds
- p.lastFd = 0
- }
-
- flag := false
- for i := p.lastFd; i < p.maxFd+1; i++ {
- if syscall.FDIsSet(i, p.readyReadFds) {
- flag = true
- mode = 'r'
- syscall.FDClr(i, p.readyReadFds)
- } else if syscall.FDIsSet(i, p.readyWriteFds) {
- flag = true
- mode = 'w'
- syscall.FDClr(i, p.readyWriteFds)
- }
- if flag {
- if !syscall.FDIsSet(i, p.repeatFds) {
- p.DelFD(i, mode)
- }
- p.nReady--
- p.lastFd = i
- return i, mode, nil
- }
- }
-
- // Will not reach here. Just to shut up the compiler.
- return -1, 0, nil
-}
-
-func (p *pollster) Close() error {
- p.closed = true
- return nil
-}
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go
index ff498c2bff..9bc5ebc7a0 100644
--- a/libgo/go/net/fd_unix.go
+++ b/libgo/go/net/fd_unix.go
@@ -7,12 +7,12 @@
package net
import (
+ "context"
"io"
"os"
"runtime"
"sync/atomic"
"syscall"
- "time"
)
// Network file descriptor.
@@ -24,11 +24,15 @@ type netFD struct {
sysfd int
family int
sotype int
+ isStream bool
isConnected bool
net string
laddr Addr
raddr Addr
+ // writev cache.
+ iovecs *[]syscall.Iovec
+
// wait server
pd pollDesc
}
@@ -36,16 +40,12 @@ type netFD struct {
func sysInit() {
}
-func dial(network string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
- return dialer(deadline)
-}
-
func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
- return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
+ return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
}
func (fd *netFD) init() error {
- if err := fd.pd.Init(fd); err != nil {
+ if err := fd.pd.init(fd); err != nil {
return err
}
return nil
@@ -68,15 +68,17 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs
}
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret error) {
// Do not need to call fd.writeLock here,
// because fd is not yet accessible to user,
// so no concurrent operations are possible.
switch err := connectFunc(fd.sysfd, ra); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case nil, syscall.EISCONN:
- if !deadline.IsZero() && deadline.Before(time.Now()) {
- return errTimeout
+ select {
+ case <-ctx.Done():
+ return mapErr(ctx.Err())
+ default:
}
if err := fd.init(); err != nil {
return err
@@ -98,23 +100,50 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
if err := fd.init(); err != nil {
return err
}
- if !deadline.IsZero() {
+ if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
fd.setWriteDeadline(deadline)
defer fd.setWriteDeadline(noDeadline)
}
- if cancel != nil {
- done := make(chan bool)
- defer close(done)
+
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot)
+ //
+ // The interrupter goroutine waits for the context to be done and
+ // interrupts the dial (by altering the fd's write deadline, which
+ // wakes up waitWrite).
+ if ctx != context.Background() {
+ // Wait for the interrupter goroutine to exit before returning
+ // from connect.
+ done := make(chan struct{})
+ interruptRes := make(chan error)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
+ // The interrupter goroutine called setWriteDeadline,
+ // but the connect code below had returned from
+ // waitWrite already and did a successful connect (ret
+ // == nil). Because we've now poisoned the connection
+ // by making it unwritable, don't return a successful
+ // dial. This was issue 16523.
+ ret = ctxErr
+ fd.Close() // prevent a leak
+ }
+ }()
go func() {
select {
- case <-cancel:
- // Force the runtime's poller to immediately give
- // up waiting for writability.
+ case <-ctx.Done():
+ // Force the runtime's poller to immediately give up
+ // waiting for writability, unblocking waitWrite
+ // below.
fd.setWriteDeadline(aLongTimeAgo)
+ testHookCanceledDial()
+ interruptRes <- ctx.Err()
case <-done:
+ interruptRes <- nil
}
}()
}
+
for {
// Performing multiple connect system calls on a
// non-blocking socket under Unix variants does not
@@ -124,10 +153,10 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
// SO_ERROR socket option to see if the connection
// succeeded or failed. See issue 7474 for further
// details.
- if err := fd.pd.WaitWrite(); err != nil {
+ if err := fd.pd.waitWrite(); err != nil {
select {
- case <-cancel:
- return errCanceled
+ case <-ctx.Done():
+ return mapErr(ctx.Err())
default:
}
return err
@@ -139,7 +168,16 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
switch err := syscall.Errno(nerr); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case syscall.Errno(0), syscall.EISCONN:
- return nil
+ if runtime.GOOS != "darwin" {
+ return nil
+ }
+ // See golang.org/issue/14548.
+ // On Darwin, multiple connect system calls on
+ // a non-blocking socket never harm SO_ERROR.
+ switch err := connectFunc(fd.sysfd, ra); err {
+ case nil, syscall.EISCONN:
+ return nil
+ }
default:
return os.NewSyscallError("getsockopt", err)
}
@@ -149,71 +187,22 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
func (fd *netFD) destroy() {
// Poller may want to unregister fd in readiness notification mechanism,
// so this must be executed before closeFunc.
- fd.pd.Close()
+ fd.pd.close()
closeFunc(fd.sysfd)
fd.sysfd = -1
runtime.SetFinalizer(fd, nil)
}
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
- if !fd.fdmu.Incref() {
- return errClosing
- }
- return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
- if fd.fdmu.Decref() {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
- if !fd.fdmu.RWLock(true) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
- if fd.fdmu.RWUnlock(true) {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
- if !fd.fdmu.RWLock(false) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
- if fd.fdmu.RWUnlock(false) {
- fd.destroy()
- }
-}
-
func (fd *netFD) Close() error {
- if !fd.fdmu.IncrefAndClose() {
+ if !fd.fdmu.increfAndClose() {
return errClosing
}
// Unblock any I/O. Once it all unblocks and returns,
// so that it cannot be referring to fd.sysfd anymore,
- // the final decref will close fd.sysfd. This should happen
+ // the final decref will close fd.sysfd. This should happen
// fairly quickly, since all the I/O is non-blocking, and any
// attempts to block in the pollDesc will return errClosing.
- fd.pd.Evict()
+ fd.pd.evict()
fd.decref()
return nil
}
@@ -239,15 +228,26 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
return 0, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ 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
}
+ if fd.isStream && len(p) > 1<<30 {
+ p = p[:1<<30]
+ }
for {
n, err = syscall.Read(fd.sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -266,7 +266,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return 0, nil, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ if err := fd.pd.prepareRead(); err != nil {
return 0, nil, err
}
for {
@@ -274,7 +274,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -293,7 +293,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
return 0, 0, 0, nil, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ if err := fd.pd.prepareRead(); err != nil {
return 0, 0, 0, nil, err
}
for {
@@ -301,7 +301,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
if err != nil {
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -320,12 +320,16 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
return 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
var n int
- n, err = syscall.Write(fd.sysfd, p[nn:])
+ max := len(p)
+ if fd.isStream && max-nn > 1<<30 {
+ max = nn + 1<<30
+ }
+ n, err = syscall.Write(fd.sysfd, p[nn:max])
if n > 0 {
nn += n
}
@@ -333,7 +337,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
break
}
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -356,13 +360,13 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
return 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -382,13 +386,13 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return 0, 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, 0, err
}
for {
n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -411,7 +415,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
var s int
var rsa syscall.Sockaddr
- if err = fd.pd.PrepareRead(); err != nil {
+ if err = fd.pd.prepareRead(); err != nil {
return nil, err
}
for {
@@ -423,7 +427,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
}
switch nerr.Err {
case syscall.EAGAIN:
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
case syscall.ECONNABORTED:
@@ -472,7 +476,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
// and fcntl there falls back (undocumented)
// to doing an ioctl instead, returning EBADF
// in this case because fd is not of the
- // expected device fd type. Treat it as
+ // expected device fd type. Treat it as
// EINVAL instead, so we fall back to the
// normal dup path.
// TODO: only do this on 10.6 if we can detect 10.6
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index fd50d772d6..a976f2ac7f 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -5,12 +5,12 @@
package net
import (
+ "context"
"internal/race"
"os"
"runtime"
"sync"
"syscall"
- "time"
"unsafe"
)
@@ -42,11 +42,6 @@ func sysInit() {
initErr = os.NewSyscallError("wsastartup", e)
}
canCancelIO = syscall.LoadCancelIoEx() == nil
- if syscall.LoadGetAddrInfo() == nil {
- lookupPort = newLookupPort
- lookupIP = newLookupIP
- }
-
hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
if hasLoadSetFileCompletionNotificationModes {
// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
@@ -69,22 +64,15 @@ func sysInit() {
}
}
+// canUseConnectEx reports whether we can use the ConnectEx Windows API call
+// for the given network type.
func canUseConnectEx(net string) bool {
switch net {
- case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
- // ConnectEx windows API does not support connectionless sockets.
- return false
- }
- return syscall.LoadConnectEx() == nil
-}
-
-func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
- if !canUseConnectEx(net) {
- // Use the relatively inefficient goroutine-racing
- // implementation of DialTimeout.
- return dialChannel(net, ra, dialer, deadline)
+ case "tcp", "tcp4", "tcp6":
+ return true
}
- return dialer(deadline)
+ // ConnectEx windows API does not support connectionless sockets.
+ return false
}
// operation contains superset of data necessary to perform all async IO.
@@ -108,6 +96,7 @@ type operation struct {
rsan int32
handle syscall.Handle
flags uint32
+ bufs []syscall.WSABuf
}
func (o *operation) InitBuf(buf []byte) {
@@ -118,6 +107,30 @@ func (o *operation) InitBuf(buf []byte) {
}
}
+func (o *operation) InitBufs(buf *Buffers) {
+ if o.bufs == nil {
+ o.bufs = make([]syscall.WSABuf, 0, len(*buf))
+ } else {
+ o.bufs = o.bufs[:0]
+ }
+ for _, b := range *buf {
+ var p *byte
+ if len(b) > 0 {
+ p = &b[0]
+ }
+ o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
+ }
+}
+
+// ClearBufs clears all pointers to Buffers parameter captured
+// by InitBufs, so it can be released by garbage collector.
+func (o *operation) ClearBufs() {
+ for i := range o.bufs {
+ o.bufs[i].Buf = nil
+ }
+ o.bufs = o.bufs[:0]
+}
+
// ioSrv executes net IO requests.
type ioSrv struct {
req chan ioSrvReq
@@ -152,7 +165,7 @@ func (s *ioSrv) ProcessRemoteIO() {
func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) error) (int, error) {
fd := o.fd
// Notify runtime netpoll about starting IO.
- err := fd.pd.Prepare(int(o.mode))
+ err := fd.pd.prepare(int(o.mode))
if err != nil {
return 0, err
}
@@ -180,7 +193,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
return 0, err
}
// Wait for our request to complete.
- err = fd.pd.Wait(int(o.mode))
+ err = fd.pd.wait(int(o.mode))
if err == nil {
// All is good. Extract our IO results and return.
if o.errno != 0 {
@@ -210,7 +223,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
<-o.errc
}
// Wait for cancelation to complete.
- fd.pd.WaitCanceled(int(o.mode))
+ fd.pd.waitCanceled(int(o.mode))
if o.errno != 0 {
err = syscall.Errno(o.errno)
if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
@@ -251,6 +264,7 @@ type netFD struct {
sysfd syscall.Handle
family int
sotype int
+ isStream bool
isConnected bool
skipSyncNotif bool
net string
@@ -269,11 +283,11 @@ func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)
return nil, initErr
}
onceStartServer.Do(startServer)
- return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
+ return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
}
func (fd *netFD) init() error {
- if err := fd.pd.Init(fd); err != nil {
+ if err := fd.pd.init(fd); err != nil {
return err
}
if hasLoadSetFileCompletionNotificationModes {
@@ -320,19 +334,20 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
runtime.SetFinalizer(fd, (*netFD).Close)
}
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
// Do not need to call fd.writeLock here,
// because fd is not yet accessible to user,
// so no concurrent operations are possible.
if err := fd.init(); err != nil {
return err
}
- if !deadline.IsZero() {
+ if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
fd.setWriteDeadline(deadline)
defer fd.setWriteDeadline(noDeadline)
}
if !canUseConnectEx(fd.net) {
- return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
+ err := connectFunc(fd.sysfd, ra)
+ return os.NewSyscallError("connect", err)
}
// ConnectEx windows API requires an unconnected, previously bound socket.
if la == nil {
@@ -351,26 +366,30 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
// Call ConnectEx API.
o := &fd.wop
o.sa = ra
- if cancel != nil {
- done := make(chan struct{})
- defer close(done)
- go func() {
- select {
- case <-cancel:
- // Force the runtime's poller to immediately give
- // up waiting for writability.
- fd.setWriteDeadline(aLongTimeAgo)
- case <-done:
- }
- }()
- }
+
+ // Wait for the goroutine converting context.Done into a write timeout
+ // to exist, otherwise our caller might cancel the context and
+ // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
+ done := make(chan bool) // must be unbuffered
+ defer func() { done <- true }()
+ go func() {
+ select {
+ case <-ctx.Done():
+ // Force the runtime's poller to immediately give
+ // up waiting for writability.
+ fd.setWriteDeadline(aLongTimeAgo)
+ <-done
+ case <-done:
+ }
+ }()
+
_, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
})
if err != nil {
select {
- case <-cancel:
- return errCanceled
+ case <-ctx.Done():
+ return mapErr(ctx.Err())
default:
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("connectex", err)
@@ -388,68 +407,19 @@ func (fd *netFD) destroy() {
}
// Poller may want to unregister fd in readiness notification mechanism,
// so this must be executed before closeFunc.
- fd.pd.Close()
+ fd.pd.close()
closeFunc(fd.sysfd)
fd.sysfd = syscall.InvalidHandle
// no need for a finalizer anymore
runtime.SetFinalizer(fd, nil)
}
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
- if !fd.fdmu.Incref() {
- return errClosing
- }
- return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
- if fd.fdmu.Decref() {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
- if !fd.fdmu.RWLock(true) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
- if fd.fdmu.RWUnlock(true) {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
- if !fd.fdmu.RWLock(false) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
- if fd.fdmu.RWUnlock(false) {
- fd.destroy()
- }
-}
-
func (fd *netFD) Close() error {
- if !fd.fdmu.IncrefAndClose() {
+ if !fd.fdmu.increfAndClose() {
return errClosing
}
// unblock pending reader and writer
- fd.pd.Evict()
+ fd.pd.evict()
fd.decref()
return nil
}
@@ -483,7 +453,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)
}
@@ -537,6 +509,42 @@ func (fd *netFD) Write(buf []byte) (int, error) {
return n, err
}
+func (c *conn) writeBuffers(v *Buffers) (int64, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.fd.writeBuffers(v)
+ if err != nil {
+ return n, &OpError{Op: "WSASend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, nil
+}
+
+func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
+ if len(*buf) == 0 {
+ return 0, nil
+ }
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
+ if race.Enabled {
+ race.ReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ o := &fd.wop
+ o.InitBufs(buf)
+ n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+ return syscall.WSASend(o.fd.sysfd, &o.bufs[0], uint32(len(*buf)), &o.qty, 0, &o.o, nil)
+ })
+ o.ClearBufs()
+ if _, ok := err.(syscall.Errno); ok {
+ err = os.NewSyscallError("wsasend", err)
+ }
+ testHookDidWritev(n)
+ buf.consume(int64(n))
+ return int64(n), err
+}
+
func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 {
return 0, nil
@@ -579,7 +587,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
o.handle = s
o.rsan = int32(unsafe.Sizeof(rawsa[0]))
_, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
- return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
+ return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
})
if err != nil {
netfd.Close()
@@ -595,7 +603,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
netfd.Close()
return nil, os.NewSyscallError("setsockopt", err)
}
-
+ runtime.KeepAlive(fd)
return netfd, nil
}
diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go
index 1aad477400..07099851cb 100644
--- a/libgo/go/net/file.go
+++ b/libgo/go/net/file.go
@@ -6,6 +6,9 @@ package net
import "os"
+// BUG(mikio): On NaCl and Windows, the FileConn, FileListener and
+// FilePacketConn functions are not implemented.
+
type fileAddr string
func (fileAddr) Network() string { return "file+net" }
diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go
index 892775a024..d16e5a166c 100644
--- a/libgo/go/net/file_plan9.go
+++ b/libgo/go/net/file_plan9.go
@@ -50,9 +50,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
name := comp[2]
switch file := comp[n-1]; file {
case "ctl", "clone":
- syscall.ForkLock.RLock()
fd, err := syscall.Dup(int(f.Fd()), -1)
- syscall.ForkLock.RUnlock()
if err != nil {
return nil, os.NewSyscallError("dup", err)
}
@@ -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 {
@@ -83,7 +81,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
if err != nil {
return nil, err
}
- return newFD(comp[1], name, ctl, nil, laddr, nil)
+ return newFD(comp[1], name, nil, ctl, nil, laddr, nil)
}
func fileConn(f *os.File) (Conn, error) {
diff --git a/libgo/go/net/hook.go b/libgo/go/net/hook.go
index 9ab34c0e36..d7316ea438 100644
--- a/libgo/go/net/hook.go
+++ b/libgo/go/net/hook.go
@@ -4,9 +4,19 @@
package net
+import "context"
+
var (
- testHookDialTCP = dialTCP
- testHookHostsPath = "/etc/hosts"
- testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { return fn(host) }
+ // if non-nil, overrides dialTCP.
+ testHookDialTCP func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error)
+
+ testHookHostsPath = "/etc/hosts"
+ testHookLookupIP = func(
+ ctx context.Context,
+ fn func(context.Context, string) ([]IPAddr, error),
+ host string,
+ ) ([]IPAddr, error) {
+ return fn(ctx, host)
+ }
testHookSetKeepAlive = func() {}
)
diff --git a/libgo/go/net/hook_unix.go b/libgo/go/net/hook_unix.go
index 361ca5980c..cf52567fcf 100644
--- a/libgo/go/net/hook_unix.go
+++ b/libgo/go/net/hook_unix.go
@@ -9,7 +9,8 @@ package net
import "syscall"
var (
- testHookDialChannel = func() {} // see golang.org/issue/5349
+ testHookDialChannel = func() {} // for golang.org/issue/5349
+ testHookCanceledDial = func() {} // for golang.org/issue/16523
// Placeholders for socket system calls.
socketFunc func(int, int, int) (int, error) = syscall.Socket
diff --git a/libgo/go/net/hook_windows.go b/libgo/go/net/hook_windows.go
index 126b0ebdd1..63ea35ab8c 100644
--- a/libgo/go/net/hook_windows.go
+++ b/libgo/go/net/hook_windows.go
@@ -13,9 +13,10 @@ var (
testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
// Placeholders for socket system calls.
- socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
- closeFunc func(syscall.Handle) error = syscall.Closesocket
- connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
- connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
- listenFunc func(syscall.Handle, int) error = syscall.Listen
+ socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
+ closeFunc func(syscall.Handle) error = syscall.Closesocket
+ connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
+ connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
+ listenFunc func(syscall.Handle, int) error = syscall.Listen
+ acceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
)
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
index c4de1b6a97..9c101c6ef5 100644
--- a/libgo/go/net/hosts.go
+++ b/libgo/go/net/hosts.go
@@ -110,7 +110,9 @@ func lookupStaticHost(host string) []string {
lowerHost := []byte(host)
lowerASCIIBytes(lowerHost)
if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok {
- return ips
+ ipsCp := make([]string, len(ips))
+ copy(ipsCp, ips)
+ return ipsCp
}
}
return nil
@@ -127,7 +129,9 @@ func lookupStaticAddr(addr string) []string {
}
if len(hosts.byAddr) != 0 {
if hosts, ok := hosts.byAddr[addr]; ok {
- return hosts
+ hostsCp := make([]string, len(hosts))
+ copy(hostsCp, hosts)
+ return hostsCp
}
}
return nil
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index 4c67bfa982..5d6c9cfe19 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -64,13 +64,17 @@ func TestLookupStaticHost(t *testing.T) {
for _, tt := range lookupStaticHostTests {
testHookHostsPath = tt.name
for _, ent := range tt.ents {
- ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
- for _, in := range ins {
- addrs := lookupStaticHost(in)
- if !reflect.DeepEqual(addrs, ent.out) {
- t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, in, addrs, ent.out)
- }
- }
+ testStaticHost(t, tt.name, ent)
+ }
+ }
+}
+
+func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
+ ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
+ for _, in := range ins {
+ addrs := lookupStaticHost(in)
+ if !reflect.DeepEqual(addrs, ent.out) {
+ t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
}
}
}
@@ -129,13 +133,43 @@ func TestLookupStaticAddr(t *testing.T) {
for _, tt := range lookupStaticAddrTests {
testHookHostsPath = tt.name
for _, ent := range tt.ents {
- hosts := lookupStaticAddr(ent.in)
- for i := range ent.out {
- ent.out[i] = absDomainName([]byte(ent.out[i]))
- }
- if !reflect.DeepEqual(hosts, ent.out) {
- t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
- }
+ testStaticAddr(t, tt.name, ent)
}
}
}
+
+func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) {
+ hosts := lookupStaticAddr(ent.in)
+ for i := range ent.out {
+ ent.out[i] = absDomainName([]byte(ent.out[i]))
+ }
+ if !reflect.DeepEqual(hosts, ent.out) {
+ t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out)
+ }
+}
+
+func TestHostCacheModification(t *testing.T) {
+ // Ensure that programs can't modify the internals of the host cache.
+ // See https://github.com/golang/go/issues/14212.
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+ testHookHostsPath = "testdata/ipv4-hosts"
+ ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
+ testStaticHost(t, testHookHostsPath, ent)
+ // Modify the addresses return by lookupStaticHost.
+ addrs := lookupStaticHost(ent.in)
+ for i := range addrs {
+ addrs[i] += "junk"
+ }
+ testStaticHost(t, testHookHostsPath, ent)
+
+ testHookHostsPath = "testdata/ipv6-hosts"
+ ent = staticHostEntry{"::1", []string{"localhost"}}
+ testStaticAddr(t, testHookHostsPath, ent)
+ // Modify the hosts return by lookupStaticAddr.
+ hosts := lookupStaticAddr(ent.in)
+ for i := range hosts {
+ hosts[i] += "junk"
+ }
+ testStaticAddr(t, testHookHostsPath, ent)
+}
diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go
index 9b4d875418..58e9f7132a 100644
--- a/libgo/go/net/http/cgi/host.go
+++ b/libgo/go/net/http/cgi/host.go
@@ -10,7 +10,7 @@
//
// Note that using CGI means starting a new process to handle each
// request, which is typically less efficient than using a
-// long-running server. This package is intended primarily for
+// long-running server. This package is intended primarily for
// compatibility with existing systems.
package cgi
@@ -58,6 +58,7 @@ type Handler struct {
InheritEnv []string // environment variables to inherit from host, as "key"
Logger *log.Logger // optional log for errors or nil to use log.Print
Args []string // optional arguments to pass to child process
+ Stderr io.Writer // optional stderr for the child process; nil means os.Stderr
// PathLocationHandler specifies the root http Handler that
// should handle internal redirects when the CGI process
@@ -70,6 +71,13 @@ type Handler struct {
PathLocationHandler http.Handler
}
+func (h *Handler) stderr() io.Writer {
+ if h.Stderr != nil {
+ return h.Stderr
+ }
+ return os.Stderr
+}
+
// removeLeadingDuplicates remove leading duplicate in environments.
// It's possible to override environment like following.
// cgi.Handler{
@@ -145,6 +153,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
for k, v := range req.Header {
k = strings.Map(upperCaseAndUnderscore, k)
+ if k == "PROXY" {
+ // See Issue 16405
+ continue
+ }
joinStr := ", "
if k == "COOKIE" {
joinStr = "; "
@@ -204,7 +216,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
Args: append([]string{h.Path}, h.Args...),
Dir: cwd,
Env: env,
- Stderr: os.Stderr, // for now
+ Stderr: h.stderr(),
}
if req.ContentLength != 0 {
cmd.Stdin = req.Body
diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go
index fb7d66adb9..f0583729eb 100644
--- a/libgo/go/net/http/cgi/host_test.go
+++ b/libgo/go/net/http/cgi/host_test.go
@@ -8,6 +8,7 @@ package cgi
import (
"bufio"
+ "bytes"
"fmt"
"io"
"net"
@@ -34,15 +35,18 @@ func newRequest(httpreq string) *http.Request {
return req
}
-func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string]string) *httptest.ResponseRecorder {
+func runCgiTest(t *testing.T, h *Handler,
+ httpreq string,
+ expectedMap map[string]string, checks ...func(reqInfo map[string]string)) *httptest.ResponseRecorder {
rw := httptest.NewRecorder()
req := newRequest(httpreq)
h.ServeHTTP(rw, req)
- runResponseChecks(t, rw, expectedMap)
+ runResponseChecks(t, rw, expectedMap, checks...)
return rw
}
-func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) {
+func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder,
+ expectedMap map[string]string, checks ...func(reqInfo map[string]string)) {
// Make a map to hold the test map that the CGI returns.
m := make(map[string]string)
m["_body"] = rw.Body.String()
@@ -80,6 +84,9 @@ readlines:
t.Errorf("for key %q got %q; expected %q", key, got, expected)
}
}
+ for _, check := range checks {
+ check(m)
+ }
}
var cgiTested, cgiWorks bool
@@ -235,6 +242,31 @@ func TestDupHeaders(t *testing.T) {
expectedMap)
}
+// Issue 16405: CGI+http.Transport differing uses of HTTP_PROXY.
+// Verify we don't set the HTTP_PROXY environment variable.
+// Hope nobody was depending on it. It's not a known header, though.
+func TestDropProxyHeader(t *testing.T) {
+ check(t)
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "env-REQUEST_URI": "/myscript/bar?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-HTTP_X_FOO": "a",
+ }
+ runCgiTest(t, h, "GET /myscript/bar?a=b HTTP/1.0\n"+
+ "X-Foo: a\n"+
+ "Proxy: should_be_stripped\n"+
+ "Host: example.com\n\n",
+ expectedMap,
+ func(reqInfo map[string]string) {
+ if v, ok := reqInfo["env-HTTP_PROXY"]; ok {
+ t.Errorf("HTTP_PROXY = %q; should be absent", v)
+ }
+ })
+}
+
func TestPathInfoNoRoot(t *testing.T) {
check(t)
h := &Handler{
@@ -501,6 +533,23 @@ func TestEnvOverride(t *testing.T) {
runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
}
+func TestHandlerStderr(t *testing.T) {
+ check(t)
+ var stderr bytes.Buffer
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ Stderr: &stderr,
+ }
+
+ rw := httptest.NewRecorder()
+ req := newRequest("GET /test.cgi?writestderr=1 HTTP/1.0\nHost: example.com\n\n")
+ h.ServeHTTP(rw, req)
+ if got, want := stderr.String(), "Hello, stderr!\n"; got != want {
+ t.Errorf("Stderr = %q; want %q", got, want)
+ }
+}
+
func TestRemoveLeadingDuplicates(t *testing.T) {
tests := []struct {
env []string
diff --git a/libgo/go/net/http/cgi/testdata/test.cgi b/libgo/go/net/http/cgi/testdata/test.cgi
index ec7ee6f386..667fce217e 100644
--- a/libgo/go/net/http/cgi/testdata/test.cgi
+++ b/libgo/go/net/http/cgi/testdata/test.cgi
@@ -23,6 +23,10 @@ print "X-CGI-Pid: $$\r\n";
print "X-Test-Header: X-Test-Value\r\n";
print "\r\n";
+if ($params->{"writestderr"}) {
+ print STDERR "Hello, stderr!\n";
+}
+
if ($params->{"bigresponse"}) {
# 17 MB, for OS X: golang.org/issue/4958
for (1..(17 * 1024)) {
diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go
index 3106d229da..0005538e70 100644
--- a/libgo/go/net/http/client.go
+++ b/libgo/go/net/http/client.go
@@ -18,6 +18,7 @@ import (
"io/ioutil"
"log"
"net/url"
+ "sort"
"strings"
"sync"
"time"
@@ -33,6 +34,25 @@ import (
// A Client is higher-level than a RoundTripper (such as Transport)
// and additionally handles HTTP details such as cookies and
// redirects.
+//
+// When following redirects, the Client will forward all headers set on the
+// initial Request except:
+//
+// * when forwarding sensitive headers like "Authorization",
+// "WWW-Authenticate", and "Cookie" to untrusted targets.
+// These headers will be ignored when following a redirect to a domain
+// that is not a subdomain match or exact match of the initial domain.
+// For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com"
+// will forward the sensitive headers, but a redirect to "bar.com" will not.
+//
+// * when forwarding the "Cookie" header with a non-nil cookie Jar.
+// Since each redirect may mutate the state of the cookie jar,
+// a redirect may possibly alter a cookie set in the initial request.
+// When forwarding the "Cookie" header, any mutated cookies will be omitted,
+// with the expectation that the Jar will insert those mutated cookies
+// with the updated values (assuming the origin matches).
+// If Jar is nil, the initial cookies are forwarded without change.
+//
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
@@ -44,17 +64,26 @@ type Client struct {
// following an HTTP redirect. The arguments req and via are
// the upcoming request and the requests made already, oldest
// first. If CheckRedirect returns an error, the Client's Get
- // method returns both the previous Response and
- // CheckRedirect's error (wrapped in a url.Error) instead of
- // issuing the Request req.
+ // 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.
CheckRedirect func(req *Request, via []*Request) error
// Jar specifies the cookie jar.
- // If Jar is nil, cookies are not sent in requests and ignored
- // in responses.
+ //
+ // The Jar is used to insert relevant cookies into every
+ // outbound Request and is updated with the cookie values
+ // of every inbound Response. The Jar is consulted for every
+ // redirect that the Client follows.
+ //
+ // If Jar is nil, cookies are only sent if they are explicitly
+ // set on the Request.
Jar CookieJar
// Timeout specifies a time limit for requests made by this
@@ -110,10 +139,6 @@ type RoundTripper interface {
RoundTrip(*Request) (*Response, error)
}
-// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
-// return true if the string includes a port.
-func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
-
// refererForURL returns a referer without any authentication info or
// an empty string if lastReq scheme is https and newReq scheme is http.
func refererForURL(lastReq, newReq *url.URL) string {
@@ -138,59 +163,23 @@ func refererForURL(lastReq, newReq *url.URL) string {
return referer
}
-// Used in Send to implement io.ReadCloser by bundling together the
-// bufio.Reader through which we read the response, and the underlying
-// network connection.
-type readClose struct {
- io.Reader
- io.Closer
-}
-
-func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
+// didTimeout is non-nil only if err != nil.
+func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
if c.Jar != nil {
for _, cookie := range c.Jar.Cookies(req.URL) {
req.AddCookie(cookie)
}
}
- resp, err := send(req, c.transport(), deadline)
+ resp, didTimeout, err = send(req, c.transport(), deadline)
if err != nil {
- return nil, err
+ return nil, didTimeout, err
}
if c.Jar != nil {
if rc := resp.Cookies(); len(rc) > 0 {
c.Jar.SetCookies(req.URL, rc)
}
}
- return resp, err
-}
-
-// Do sends an HTTP request and returns an HTTP response, following
-// policy (e.g. redirects, cookies, auth) as configured on the client.
-//
-// An error is returned if caused by client policy (such as
-// CheckRedirect), or if there was an HTTP protocol error.
-// A non-2xx response doesn't cause an error.
-//
-// When err is nil, resp always contains a non-nil resp.Body.
-//
-// Callers should close resp.Body when done reading from it. If
-// resp.Body is not closed, the Client's underlying RoundTripper
-// (typically Transport) may not be able to re-use a persistent TCP
-// connection to the server for a subsequent "keep-alive" request.
-//
-// The request Body, if non-nil, will be closed by the underlying
-// Transport, even on errors.
-//
-// Generally Get, Post, or PostForm will be used instead of Do.
-func (c *Client) Do(req *Request) (resp *Response, err error) {
- method := valueOrDefault(req.Method, "GET")
- if method == "GET" || method == "HEAD" {
- return c.doFollowingRedirects(req, shouldRedirectGet)
- }
- if method == "POST" || method == "PUT" {
- return c.doFollowingRedirects(req, shouldRedirectPost)
- }
- return c.send(req, c.deadline())
+ return resp, nil, nil
}
func (c *Client) deadline() time.Time {
@@ -209,22 +198,22 @@ func (c *Client) transport() RoundTripper {
// send issues an HTTP request.
// Caller should close resp.Body when done reading from it.
-func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error) {
+func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
req := ireq // req is either the original request, or a modified fork
if rt == nil {
req.closeBody()
- return nil, errors.New("http: no Client.Transport or DefaultTransport")
+ return nil, alwaysFalse, errors.New("http: no Client.Transport or DefaultTransport")
}
if req.URL == nil {
req.closeBody()
- return nil, errors.New("http: nil Request.URL")
+ return nil, alwaysFalse, errors.New("http: nil Request.URL")
}
if req.RequestURI != "" {
req.closeBody()
- return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
+ return nil, alwaysFalse, errors.New("http: Request.RequestURI can't be set in client requests.")
}
// forkReq forks req into a shallow clone of ireq the first
@@ -237,7 +226,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
}
// Most the callers of send (Get, Post, et al) don't need
- // Headers, leaving it uninitialized. We guarantee to the
+ // Headers, leaving it uninitialized. We guarantee to the
// Transport that this has been initialized, though.
if req.Header == nil {
forkReq()
@@ -255,9 +244,9 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
if !deadline.IsZero() {
forkReq()
}
- stopTimer, wasCanceled := setRequestCancel(req, rt, deadline)
+ stopTimer, didTimeout := setRequestCancel(req, rt, deadline)
- resp, err := rt.RoundTrip(req)
+ resp, err = rt.RoundTrip(req)
if err != nil {
stopTimer()
if resp != nil {
@@ -271,22 +260,27 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
err = errors.New("http: server gave HTTP response to HTTPS client")
}
}
- return nil, err
+ return nil, didTimeout, err
}
if !deadline.IsZero() {
resp.Body = &cancelTimerBody{
- stop: stopTimer,
- rc: resp.Body,
- reqWasCanceled: wasCanceled,
+ stop: stopTimer,
+ rc: resp.Body,
+ reqDidTimeout: didTimeout,
}
}
- return resp, nil
+ return resp, nil, nil
}
// setRequestCancel sets the Cancel field of req, if deadline is
// non-zero. The RoundTripper's type is used to determine whether the legacy
// CancelRequest behavior should be used.
-func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), wasCanceled func() bool) {
+//
+// As background, there are three ways to cancel a request:
+// First was Transport.CancelRequest. (deprecated)
+// Second was Request.Cancel (this mechanism).
+// Third was Request.Context.
+func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), didTimeout func() bool) {
if deadline.IsZero() {
return nop, alwaysFalse
}
@@ -296,17 +290,8 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi
cancel := make(chan struct{})
req.Cancel = cancel
- wasCanceled = func() bool {
- select {
- case <-cancel:
- return true
- default:
- return false
- }
- }
-
doCancel := func() {
- // The new way:
+ // The newer way (the second way in the func comment):
close(cancel)
// The legacy compatibility way, used only
@@ -328,19 +313,23 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi
var once sync.Once
stopTimer = func() { once.Do(func() { close(stopTimerCh) }) }
- timer := time.NewTimer(deadline.Sub(time.Now()))
+ timer := time.NewTimer(time.Until(deadline))
+ var timedOut atomicBool
+
go func() {
select {
case <-initialReqCancel:
doCancel()
+ timer.Stop()
case <-timer.C:
+ timedOut.setTrue()
doCancel()
case <-stopTimerCh:
timer.Stop()
}
}()
- return stopTimer, wasCanceled
+ return stopTimer, timedOut.isSet
}
// See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
@@ -353,26 +342,6 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth))
}
-// True if the specified HTTP status code is one for which the Get utility should
-// automatically redirect.
-func shouldRedirectGet(statusCode int) bool {
- switch statusCode {
- case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
- return true
- }
- return false
-}
-
-// True if the specified HTTP status code is one for which the Post utility should
-// automatically redirect.
-func shouldRedirectPost(statusCode int) bool {
- switch statusCode {
- case StatusFound, StatusSeeOther:
- return true
- }
- return false
-}
-
// Get issues a GET to the specified URL. If the response is one of
// the following redirect codes, Get follows the redirect, up to a
// maximum of 10 redirects:
@@ -381,6 +350,7 @@ func shouldRedirectPost(statusCode int) bool {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// An error is returned if there were too many redirects or if there
// was an HTTP protocol error. A non-2xx response doesn't cause an
@@ -405,6 +375,7 @@ func Get(url string) (resp *Response, err error) {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// An error is returned if the Client's CheckRedirect function fails
// or if there was an HTTP protocol error. A non-2xx response doesn't
@@ -419,106 +390,290 @@ func (c *Client) Get(url string) (resp *Response, err error) {
if err != nil {
return nil, err
}
- return c.doFollowingRedirects(req, shouldRedirectGet)
+ return c.Do(req)
}
func alwaysFalse() bool { return false }
-func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
- var base *url.URL
- redirectChecker := c.CheckRedirect
- if redirectChecker == nil {
- redirectChecker = defaultCheckRedirect
+// 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 {
+ fn := c.CheckRedirect
+ if fn == nil {
+ fn = defaultCheckRedirect
}
- var via []*Request
+ return fn(req, via)
+}
- if ireq.URL == nil {
- ireq.closeBody()
+// redirectBehavior describes what should happen when the
+// client encounters a 3xx status code from the server
+func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
+ switch resp.StatusCode {
+ case 301, 302, 303:
+ redirectMethod = reqMethod
+ shouldRedirect = true
+ includeBody = false
+
+ // RFC 2616 allowed automatic redirection only with GET and
+ // HEAD requests. RFC 7231 lifts this restriction, but we still
+ // restrict other methods to GET to maintain compatibility.
+ // See Issue 18570.
+ if reqMethod != "GET" && reqMethod != "HEAD" {
+ redirectMethod = "GET"
+ }
+ case 307, 308:
+ redirectMethod = reqMethod
+ shouldRedirect = true
+ includeBody = true
+
+ // Treat 307 and 308 specially, since they're new in
+ // Go 1.8, and they also require re-sending the request body.
+ if resp.Header.Get("Location") == "" {
+ // 308s have been observed in the wild being served
+ // without Location headers. Since Go 1.7 and earlier
+ // didn't follow these codes, just stop here instead
+ // of returning an error.
+ // See Issue 17773.
+ shouldRedirect = false
+ break
+ }
+ if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
+ // We had a request body, and 307/308 require
+ // re-sending it, but GetBody is not defined. So just
+ // return this response to the user instead of an
+ // error, like we did in Go 1.7 and earlier.
+ shouldRedirect = false
+ }
+ }
+ return redirectMethod, shouldRedirect, includeBody
+}
+
+// Do sends an HTTP request and returns an HTTP response, following
+// policy (such as redirects, cookies, auth) as configured on the
+// client.
+//
+// An error is returned if caused by client policy (such as
+// CheckRedirect), or failure to speak HTTP (such as a network
+// connectivity problem). A non-2xx status code doesn't cause an
+// error.
+//
+// If the returned error is nil, the Response will contain a non-nil
+// Body which the user is expected to close. If the Body is not
+// closed, the Client's underlying RoundTripper (typically Transport)
+// may not be able to re-use a persistent TCP connection to the server
+// for a subsequent "keep-alive" request.
+//
+// The request Body, if non-nil, will be closed by the underlying
+// Transport, even on errors.
+//
+// On error, any Response can be ignored. A non-nil Response with a
+// non-nil error only occurs when CheckRedirect fails, and even then
+// the returned Response.Body is already closed.
+//
+// Generally Get, Post, or PostForm will be used instead of Do.
+//
+// If the server replies with a redirect, the Client first uses the
+// CheckRedirect function to determine whether the redirect should be
+// followed. If permitted, a 301, 302, or 303 redirect causes
+// subsequent requests to use HTTP method GET
+// (or HEAD if the original request was HEAD), with no body.
+// A 307 or 308 redirect preserves the original HTTP method and body,
+// provided that the Request.GetBody function is defined.
+// The NewRequest function automatically sets GetBody for common
+// standard library body types.
+func (c *Client) Do(req *Request) (*Response, error) {
+ if req.URL == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
- req := ireq
- deadline := c.deadline()
+ var (
+ deadline = c.deadline()
+ reqs []*Request
+ resp *Response
+ copyHeaders = c.makeHeadersCopier(req)
- urlStr := "" // next relative or absolute URL to fetch (after first request)
- redirectFailed := false
- for redirect := 0; ; redirect++ {
- if redirect != 0 {
- nreq := new(Request)
- nreq.Cancel = ireq.Cancel
- nreq.Method = ireq.Method
- if ireq.Method == "POST" || ireq.Method == "PUT" {
- nreq.Method = "GET"
+ // Redirect behavior:
+ redirectMethod string
+ includeBody bool
+ )
+ uerr := func(err error) error {
+ req.closeBody()
+ method := valueOrDefault(reqs[0].Method, "GET")
+ var urlStr string
+ if resp != nil && resp.Request != nil {
+ urlStr = resp.Request.URL.String()
+ } else {
+ urlStr = req.URL.String()
+ }
+ return &url.Error{
+ Op: method[:1] + strings.ToLower(method[1:]),
+ URL: urlStr,
+ Err: err,
+ }
+ }
+ for {
+ // For all but the first request, create the next
+ // request hop and replace req.
+ if len(reqs) > 0 {
+ loc := resp.Header.Get("Location")
+ if loc == "" {
+ return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode))
}
- nreq.Header = make(Header)
- nreq.URL, err = base.Parse(urlStr)
+ u, err := req.URL.Parse(loc)
if err != nil {
- break
+ return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err))
}
- if len(via) > 0 {
- // Add the Referer header.
- lastReq := via[len(via)-1]
- if ref := refererForURL(lastReq.URL, nreq.URL); ref != "" {
- nreq.Header.Set("Referer", ref)
- }
-
- err = redirectChecker(nreq, via)
+ ireq := reqs[0]
+ req = &Request{
+ Method: redirectMethod,
+ Response: resp,
+ URL: u,
+ Header: make(Header),
+ Cancel: ireq.Cancel,
+ ctx: ireq.ctx,
+ }
+ if includeBody && ireq.GetBody != nil {
+ req.Body, err = ireq.GetBody()
if err != nil {
- redirectFailed = true
- break
+ return nil, uerr(err)
}
+ req.ContentLength = ireq.ContentLength
}
- req = nreq
- }
- urlStr = req.URL.String()
- if resp, err = c.send(req, deadline); err != nil {
- if !deadline.IsZero() && !time.Now().Before(deadline) {
- err = &httpError{
- err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
- timeout: true,
- }
+ // Copy original headers before setting the Referer,
+ // in case the user set Referer on their first request.
+ // If they really want to override, they can do it in
+ // their CheckRedirect func.
+ copyHeaders(req)
+
+ // Add the Referer header from the most recent
+ // request URL to the new one, if it's not https->http:
+ if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
+ req.Header.Set("Referer", ref)
+ }
+ 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
}
- break
- }
- if shouldRedirect(resp.StatusCode) {
- // 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.
+ // 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 urlStr = resp.Header.Get("Location"); urlStr == "" {
- err = fmt.Errorf("%d response missing Location header", resp.StatusCode)
- break
+
+ 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
+ // The resp.Body has already been closed.
+ ue := uerr(err)
+ ue.(*url.Error).URL = loc
+ return resp, ue
}
- base = req.URL
- via = append(via, req)
- continue
}
- return resp, nil
- }
- method := valueOrDefault(ireq.Method, "GET")
- urlErr := &url.Error{
- Op: method[:1] + strings.ToLower(method[1:]),
- URL: urlStr,
- Err: err,
+ reqs = append(reqs, req)
+ var err error
+ var didTimeout func() bool
+ if resp, didTimeout, err = c.send(req, deadline); err != nil {
+ if !deadline.IsZero() && didTimeout() {
+ err = &httpError{
+ err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
+ timeout: true,
+ }
+ }
+ return nil, uerr(err)
+ }
+
+ var shouldRedirect bool
+ redirectMethod, shouldRedirect, includeBody = redirectBehavior(req.Method, resp, reqs[0])
+ if !shouldRedirect {
+ return resp, nil
+ }
+
+ req.closeBody()
}
+}
- if redirectFailed {
- // Special case for Go 1 compatibility: return both the response
- // and an error if the CheckRedirect function failed.
- // See https://golang.org/issue/3795
- return resp, urlErr
+// makeHeadersCopier makes a function that copies headers from the
+// initial Request, ireq. For every redirect, this function must be called
+// so that it can copy headers into the upcoming Request.
+func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
+ // The headers to copy are from the very initial request.
+ // We use a closured callback to keep a reference to these original headers.
+ var (
+ ireqhdr = ireq.Header.clone()
+ icookies map[string][]*Cookie
+ )
+ if c.Jar != nil && ireq.Header.Get("Cookie") != "" {
+ icookies = make(map[string][]*Cookie)
+ for _, c := range ireq.Cookies() {
+ icookies[c.Name] = append(icookies[c.Name], c)
+ }
}
- if resp != nil {
- resp.Body.Close()
+ preq := ireq // The previous request
+ return func(req *Request) {
+ // If Jar is present and there was some initial cookies provided
+ // via the request header, then we may need to alter the initial
+ // cookies as we follow redirects since each redirect may end up
+ // modifying a pre-existing cookie.
+ //
+ // Since cookies already set in the request header do not contain
+ // information about the original domain and path, the logic below
+ // assumes any new set cookies override the original cookie
+ // regardless of domain or path.
+ //
+ // See https://golang.org/issue/17494
+ if c.Jar != nil && icookies != nil {
+ var changed bool
+ resp := req.Response // The response that caused the upcoming redirect
+ for _, c := range resp.Cookies() {
+ if _, ok := icookies[c.Name]; ok {
+ delete(icookies, c.Name)
+ changed = true
+ }
+ }
+ if changed {
+ ireqhdr.Del("Cookie")
+ var ss []string
+ for _, cs := range icookies {
+ for _, c := range cs {
+ ss = append(ss, c.Name+"="+c.Value)
+ }
+ }
+ sort.Strings(ss) // Ensure deterministic headers
+ ireqhdr.Set("Cookie", strings.Join(ss, "; "))
+ }
+ }
+
+ // Copy the initial request's Header values
+ // (at least the safe ones).
+ for k, vv := range ireqhdr {
+ if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
+ req.Header[k] = vv
+ }
+ }
+
+ preq = req // Update previous Request with the current request
}
- return nil, urlErr
}
func defaultCheckRedirect(req *Request, via []*Request) error {
@@ -538,8 +693,11 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
// Post is a wrapper around DefaultClient.Post.
//
// To set custom headers, use NewRequest and DefaultClient.Do.
-func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
- return DefaultClient.Post(url, bodyType, body)
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
+func Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
+ return DefaultClient.Post(url, contentType, body)
}
// Post issues a POST to the specified URL.
@@ -550,13 +708,16 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
// request.
//
// To set custom headers, use NewRequest and Client.Do.
-func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
+func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
- req.Header.Set("Content-Type", bodyType)
- return c.doFollowingRedirects(req, shouldRedirectPost)
+ req.Header.Set("Content-Type", contentType)
+ return c.Do(req)
}
// PostForm issues a POST to the specified URL, with data's keys and
@@ -569,6 +730,9 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Respon
// Caller should close resp.Body when done reading from it.
//
// PostForm is a wrapper around DefaultClient.PostForm.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
func PostForm(url string, data url.Values) (resp *Response, err error) {
return DefaultClient.PostForm(url, data)
}
@@ -581,11 +745,14 @@ func PostForm(url string, data url.Values) (resp *Response, err error) {
//
// When err is nil, resp always contains a non-nil resp.Body.
// Caller should close resp.Body when done reading from it.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
-// Head issues a HEAD to the specified URL. If the response is one of
+// Head issues a HEAD to the specified URL. If the response is one of
// the following redirect codes, Head follows the redirect, up to a
// maximum of 10 redirects:
//
@@ -593,13 +760,14 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// Head is a wrapper around DefaultClient.Head
func Head(url string) (resp *Response, err error) {
return DefaultClient.Head(url)
}
-// Head issues a HEAD to the specified URL. If the response is one of the
+// Head issues a HEAD to the specified URL. If the response is one of the
// following redirect codes, Head follows the redirect after calling the
// Client's CheckRedirect function:
//
@@ -607,22 +775,23 @@ func Head(url string) (resp *Response, err error) {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
func (c *Client) Head(url string) (resp *Response, err error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
}
- return c.doFollowingRedirects(req, shouldRedirectGet)
+ return c.Do(req)
}
// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
// 1) on Read error or close, the stop func is called.
-// 2) On Read failure, if reqWasCanceled is true, the error is wrapped and
+// 2) On Read failure, if reqDidTimeout is true, the error is wrapped and
// marked as net.Error that hit its timeout.
type cancelTimerBody struct {
- stop func() // stops the time.Timer waiting to cancel the request
- rc io.ReadCloser
- reqWasCanceled func() bool
+ stop func() // stops the time.Timer waiting to cancel the request
+ rc io.ReadCloser
+ reqDidTimeout func() bool
}
func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
@@ -634,7 +803,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
if err == io.EOF {
return n, err
}
- if b.reqWasCanceled() {
+ if b.reqDidTimeout() {
err = &httpError{
err: err.Error() + " (Client.Timeout exceeded while reading body)",
timeout: true,
@@ -648,3 +817,52 @@ func (b *cancelTimerBody) Close() error {
b.stop()
return err
}
+
+func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
+ switch CanonicalHeaderKey(headerKey) {
+ case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
+ // Permit sending auth/cookie headers from "foo.com"
+ // to "sub.foo.com".
+
+ // Note that we don't send all cookies to subdomains
+ // automatically. This function is only used for
+ // Cookies set explicitly on the initial outgoing
+ // client request. Cookies automatically added via the
+ // CookieJar mechanism continue to follow each
+ // cookie's scope as set by Set-Cookie. But for
+ // outgoing requests with the Cookie header set
+ // directly, we don't know their scope, so we assume
+ // it's for *.domain.com.
+
+ // TODO(bradfitz): once issue 16142 is fixed, make
+ // this code use those URL accessors, and consider
+ // "http://foo.com" and "http://foo.com:80" as
+ // equivalent?
+
+ // TODO(bradfitz): better hostname canonicalization,
+ // at least once we figure out IDNA/Punycode (issue
+ // 13835).
+ ihost := strings.ToLower(initial.Host)
+ dhost := strings.ToLower(dest.Host)
+ return isDomainOrSubdomain(dhost, ihost)
+ }
+ // All other headers are copied:
+ return true
+}
+
+// isDomainOrSubdomain reports whether sub is a subdomain (or exact
+// match) of the parent domain.
+//
+// Both domains must already be in canonical form.
+func isDomainOrSubdomain(sub, parent string) bool {
+ if sub == parent {
+ return true
+ }
+ // If sub is "foo.example.com" and parent is "example.com",
+ // that means sub must end in "."+parent.
+ // Do it without allocating.
+ if !strings.HasSuffix(sub, parent) {
+ return false
+ }
+ return sub[len(sub)-len(parent)-1] == '.'
+}
diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go
index 8939dc8baf..4f674dd8d6 100644
--- a/libgo/go/net/http/client_test.go
+++ b/libgo/go/net/http/client_test.go
@@ -8,6 +8,7 @@ package http_test
import (
"bytes"
+ "context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
@@ -18,11 +19,14 @@ import (
"log"
"net"
. "net/http"
+ "net/http/cookiejar"
"net/http/httptest"
"net/url"
+ "reflect"
"strconv"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -64,11 +68,13 @@ func (w chanWriter) Write(p []byte) (n int, err error) {
}
func TestClient(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
- r, err := Get(ts.URL)
+ c := &Client{Transport: &Transport{DisableKeepAlives: true}}
+ r, err := c.Get(ts.URL)
var b []byte
if err == nil {
b, err = pedanticReadAll(r.Body)
@@ -108,6 +114,7 @@ func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error)
}
func TestGetRequestFormat(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
@@ -194,6 +201,7 @@ func TestPostFormRequestFormat(t *testing.T) {
}
func TestClientRedirects(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -205,14 +213,17 @@ func TestClientRedirects(t *testing.T) {
}
}
if n < 15 {
- Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
+ Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusTemporaryRedirect)
return
}
fmt.Fprintf(w, "n=%d", n)
}))
defer ts.Close()
- c := &Client{}
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ c := &Client{Transport: tr}
_, err := c.Get(ts.URL)
if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
t.Errorf("with default client Get, expected error %q, got %q", e, g)
@@ -241,11 +252,14 @@ func TestClientRedirects(t *testing.T) {
var checkErr error
var lastVia []*Request
var lastReq *Request
- c = &Client{CheckRedirect: func(req *Request, via []*Request) error {
- lastReq = req
- lastVia = via
- return checkErr
- }}
+ c = &Client{
+ Transport: tr,
+ CheckRedirect: func(req *Request, via []*Request) error {
+ lastReq = req
+ lastVia = via
+ return checkErr
+ },
+ }
res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
@@ -273,7 +287,7 @@ func TestClientRedirects(t *testing.T) {
t.Fatal("didn't see redirect")
}
if lastReq.Cancel != cancel {
- t.Errorf("expected lastReq to have the cancel channel set on the inital req")
+ t.Errorf("expected lastReq to have the cancel channel set on the initial req")
}
checkErr = errors.New("no redirects allowed")
@@ -290,7 +304,125 @@ func TestClientRedirects(t *testing.T) {
}
}
+func TestClientRedirectContext(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ Redirect(w, r, "/", StatusTemporaryRedirect)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ c := &Client{
+ Transport: tr,
+ CheckRedirect: func(req *Request, via []*Request) error {
+ cancel()
+ if len(via) > 2 {
+ return errors.New("too many redirects")
+ }
+ return nil
+ },
+ }
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req = req.WithContext(ctx)
+ _, err := c.Do(req)
+ ue, ok := err.(*url.Error)
+ if !ok {
+ t.Fatalf("got error %T; want *url.Error", err)
+ }
+ if ue.Err != context.Canceled {
+ t.Errorf("url.Error.Err = %v; want %v", ue.Err, context.Canceled)
+ }
+}
+
+type redirectTest struct {
+ suffix string
+ want int // response code
+ redirectBody string
+}
+
func TestPostRedirects(t *testing.T) {
+ postRedirectTests := []redirectTest{
+ {"/", 200, "first"},
+ {"/?code=301&next=302", 200, "c301"},
+ {"/?code=302&next=302", 200, "c302"},
+ {"/?code=303&next=301", 200, "c303wc301"}, // Issue 9348
+ {"/?code=304", 304, "c304"},
+ {"/?code=305", 305, "c305"},
+ {"/?code=307&next=303,308,302", 200, "c307"},
+ {"/?code=308&next=302,301", 200, "c308"},
+ {"/?code=404", 404, "c404"},
+ }
+
+ wantSegments := []string{
+ `POST / "first"`,
+ `POST /?code=301&next=302 "c301"`,
+ `GET /?code=302 ""`,
+ `GET / ""`,
+ `POST /?code=302&next=302 "c302"`,
+ `GET /?code=302 ""`,
+ `GET / ""`,
+ `POST /?code=303&next=301 "c303wc301"`,
+ `GET /?code=301 ""`,
+ `GET / ""`,
+ `POST /?code=304 "c304"`,
+ `POST /?code=305 "c305"`,
+ `POST /?code=307&next=303,308,302 "c307"`,
+ `POST /?code=303&next=308,302 "c307"`,
+ `GET /?code=308&next=302 ""`,
+ `GET /?code=302 "c307"`,
+ `GET / ""`,
+ `POST /?code=308&next=302,301 "c308"`,
+ `POST /?code=302&next=301 "c308"`,
+ `GET /?code=301 ""`,
+ `GET / ""`,
+ `POST /?code=404 "c404"`,
+ }
+ want := strings.Join(wantSegments, "\n")
+ testRedirectsByMethod(t, "POST", postRedirectTests, want)
+}
+
+func TestDeleteRedirects(t *testing.T) {
+ deleteRedirectTests := []redirectTest{
+ {"/", 200, "first"},
+ {"/?code=301&next=302,308", 200, "c301"},
+ {"/?code=302&next=302", 200, "c302"},
+ {"/?code=303", 200, "c303"},
+ {"/?code=307&next=301,308,303,302,304", 304, "c307"},
+ {"/?code=308&next=307", 200, "c308"},
+ {"/?code=404", 404, "c404"},
+ }
+
+ wantSegments := []string{
+ `DELETE / "first"`,
+ `DELETE /?code=301&next=302,308 "c301"`,
+ `GET /?code=302&next=308 ""`,
+ `GET /?code=308 ""`,
+ `GET / "c301"`,
+ `DELETE /?code=302&next=302 "c302"`,
+ `GET /?code=302 ""`,
+ `GET / ""`,
+ `DELETE /?code=303 "c303"`,
+ `GET / ""`,
+ `DELETE /?code=307&next=301,308,303,302,304 "c307"`,
+ `DELETE /?code=301&next=308,303,302,304 "c307"`,
+ `GET /?code=308&next=303,302,304 ""`,
+ `GET /?code=303&next=302,304 "c307"`,
+ `GET /?code=302&next=304 ""`,
+ `GET /?code=304 ""`,
+ `DELETE /?code=308&next=307 "c308"`,
+ `DELETE /?code=307 "c308"`,
+ `DELETE / "c308"`,
+ `DELETE /?code=404 "c404"`,
+ }
+ want := strings.Join(wantSegments, "\n")
+ testRedirectsByMethod(t, "DELETE", deleteRedirectTests, want)
+}
+
+func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, want string) {
defer afterTest(t)
var log struct {
sync.Mutex
@@ -299,29 +431,39 @@ func TestPostRedirects(t *testing.T) {
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
log.Lock()
- fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI)
+ slurp, _ := ioutil.ReadAll(r.Body)
+ fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp)
+ if cl := r.Header.Get("Content-Length"); r.Method == "GET" && len(slurp) == 0 && (r.ContentLength != 0 || cl != "") {
+ fmt.Fprintf(&log.Buffer, " (but with body=%T, content-length = %v, %q)", r.Body, r.ContentLength, cl)
+ }
+ log.WriteByte('\n')
log.Unlock()
- if v := r.URL.Query().Get("code"); v != "" {
+ urlQuery := r.URL.Query()
+ if v := urlQuery.Get("code"); v != "" {
+ location := ts.URL
+ if final := urlQuery.Get("next"); final != "" {
+ splits := strings.Split(final, ",")
+ first, rest := splits[0], splits[1:]
+ location = fmt.Sprintf("%s?code=%s", location, first)
+ if len(rest) > 0 {
+ location = fmt.Sprintf("%s&next=%s", location, strings.Join(rest, ","))
+ }
+ }
code, _ := strconv.Atoi(v)
if code/100 == 3 {
- w.Header().Set("Location", ts.URL)
+ w.Header().Set("Location", location)
}
w.WriteHeader(code)
}
}))
defer ts.Close()
- tests := []struct {
- suffix string
- want int // response code
- }{
- {"/", 200},
- {"/?code=301", 301},
- {"/?code=302", 200},
- {"/?code=303", 200},
- {"/?code=404", 404},
- }
- for _, tt := range tests {
- res, err := Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content"))
+
+ for _, tt := range table {
+ content := tt.redirectBody
+ req, _ := NewRequest(method, ts.URL+tt.suffix, strings.NewReader(content))
+ req.GetBody = func() (io.ReadCloser, error) { return ioutil.NopCloser(strings.NewReader(content)), nil }
+ res, err := DefaultClient.Do(req)
+
if err != nil {
t.Fatal(err)
}
@@ -332,9 +474,125 @@ func TestPostRedirects(t *testing.T) {
log.Lock()
got := log.String()
log.Unlock()
- want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 "
+
+ got = strings.TrimSpace(got)
+ want = strings.TrimSpace(want)
+
if got != want {
- t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want)
+ got, want, lines := removeCommonLines(got, want)
+ t.Errorf("Log differs after %d common lines.\n\nGot:\n%s\n\nWant:\n%s\n", lines, got, want)
+ }
+}
+
+func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) {
+ for {
+ nl := strings.IndexByte(a, '\n')
+ if nl < 0 {
+ return a, b, commonLines
+ }
+ line := a[:nl+1]
+ if !strings.HasPrefix(b, line) {
+ return a, b, commonLines
+ }
+ commonLines++
+ a = a[len(line):]
+ b = b[len(line):]
+ }
+}
+
+func TestClientRedirectUseResponse(t *testing.T) {
+ setParallel(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()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ c := &Client{
+ Transport: tr,
+ 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)
+ }
+}
+
+// Issue 17773: don't follow a 308 (or 307) if the response doesn't
+// have a Location header.
+func TestClientRedirect308NoLocation(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Foo", "Bar")
+ w.WriteHeader(308)
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if res.StatusCode != 308 {
+ t.Errorf("status = %d; want %d", res.StatusCode, 308)
+ }
+ if got := res.Header.Get("Foo"); got != "Bar" {
+ t.Errorf("Foo header = %q; want Bar", got)
+ }
+}
+
+// Don't follow a 307/308 if we can't resent the request body.
+func TestClientRedirect308NoGetBody(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ const fakeURL = "https://localhost:1234/" // won't be hit
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Location", fakeURL)
+ w.WriteHeader(308)
+ }))
+ defer ts.Close()
+ req, err := NewRequest("POST", ts.URL, strings.NewReader("some body"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.GetBody = nil // so it can't rewind.
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if res.StatusCode != 308 {
+ t.Errorf("status = %d; want %d", res.StatusCode, 308)
+ }
+ if got := res.Header.Get("Location"); got != fakeURL {
+ t.Errorf("Location header = %q; want %q", got, fakeURL)
}
}
@@ -410,12 +668,16 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
}
func TestRedirectCookiesJar(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
c := &Client{
- Jar: new(TestJar),
+ Transport: tr,
+ Jar: new(TestJar),
}
u, _ := url.Parse(ts.URL)
c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
@@ -599,6 +861,7 @@ func TestClientWrites(t *testing.T) {
}
func TestClientInsecureTransport(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
@@ -776,6 +1039,7 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
func TestHTTPSClientDetectsHTTPServer(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ ts.Config.ErrorLog = quietLog
defer ts.Close()
_, err := Get(strings.Replace(ts.URL, "http", "https", 1))
@@ -829,6 +1093,7 @@ func testClientHeadContentLength(t *testing.T, h2 bool) {
}
func TestEmptyPasswordAuth(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
gopher := "gopher"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -849,7 +1114,9 @@ func TestEmptyPasswordAuth(t *testing.T) {
}
}))
defer ts.Close()
- c := &Client{}
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
req, err := NewRequest("GET", ts.URL, nil)
if err != nil {
t.Fatal(err)
@@ -941,10 +1208,10 @@ func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) }
func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) }
func testClientTimeout(t *testing.T, h2 bool) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
+ setParallel(t)
defer afterTest(t)
+ testDone := make(chan struct{}) // closed in defer below
+
sawRoot := make(chan bool, 1)
sawSlow := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -954,19 +1221,26 @@ func testClientTimeout(t *testing.T, h2 bool) {
return
}
if r.URL.Path == "/slow" {
+ sawSlow <- true
w.Write([]byte("Hello"))
w.(Flusher).Flush()
- sawSlow <- true
- time.Sleep(2 * time.Second)
+ <-testDone
return
}
}))
defer cst.close()
- const timeout = 500 * time.Millisecond
+ defer close(testDone) // before cst.close, to unblock /slow handler
+
+ // 200ms should be long enough to get a normal request (the /
+ // handler), but not so long that it makes the test slow.
+ const timeout = 200 * time.Millisecond
cst.c.Timeout = timeout
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
+ if strings.Contains(err.Error(), "Client.Timeout") {
+ t.Skipf("host too slow to get fast resource in %v", timeout)
+ }
t.Fatal(err)
}
@@ -991,7 +1265,7 @@ func testClientTimeout(t *testing.T, h2 bool) {
res.Body.Close()
}()
- const failTime = timeout * 2
+ const failTime = 5 * time.Second
select {
case err := <-errc:
if err == nil {
@@ -1016,11 +1290,9 @@ func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h
// Client.Timeout firing before getting to the body
func testClientTimeout_Headers(t *testing.T, h2 bool) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
+ setParallel(t)
defer afterTest(t)
- donec := make(chan bool)
+ donec := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
<-donec
}))
@@ -1034,9 +1306,10 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) {
// doesn't know this, so synchronize explicitly.
defer func() { donec <- true }()
- cst.c.Timeout = 500 * time.Millisecond
- _, err := cst.c.Get(cst.ts.URL)
+ cst.c.Timeout = 5 * time.Millisecond
+ res, err := cst.c.Get(cst.ts.URL)
if err == nil {
+ res.Body.Close()
t.Fatal("got response from Get; expected error")
}
if _, ok := err.(*url.Error); !ok {
@@ -1054,9 +1327,40 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) {
}
}
+// Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be
+// returned.
+func TestClientTimeoutCancel(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ testDone := make(chan struct{})
+ ctx, cancel := context.WithCancel(context.Background())
+
+ cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(Flusher).Flush()
+ <-testDone
+ }))
+ defer cst.close()
+ defer close(testDone)
+
+ cst.c.Timeout = 1 * time.Hour
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req.Cancel = ctx.Done()
+ res, err := cst.c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cancel()
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != ExportErrRequestCanceled {
+ t.Fatalf("error = %v; want errRequestCanceled", err)
+ }
+}
+
func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) }
func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) }
func testClientRedirectEatsBody(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
saw := make(chan string, 2)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1072,10 +1376,10 @@ func testClientRedirectEatsBody(t *testing.T, h2 bool) {
t.Fatal(err)
}
_, err = ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
t.Fatal(err)
}
- res.Body.Close()
var first string
select {
@@ -1140,3 +1444,392 @@ 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")
+}
+
+// Issue 4800: copy (some) headers when Client follows a redirect
+func TestClientCopyHeadersOnRedirect(t *testing.T) {
+ const (
+ ua = "some-agent/1.2"
+ xfoo = "foo-val"
+ )
+ var ts2URL string
+ ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ want := Header{
+ "User-Agent": []string{ua},
+ "X-Foo": []string{xfoo},
+ "Referer": []string{ts2URL},
+ "Accept-Encoding": []string{"gzip"},
+ }
+ if !reflect.DeepEqual(r.Header, want) {
+ t.Errorf("Request.Header = %#v; want %#v", r.Header, want)
+ }
+ if t.Failed() {
+ w.Header().Set("Result", "got errors")
+ } else {
+ w.Header().Set("Result", "ok")
+ }
+ }))
+ defer ts1.Close()
+ ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ Redirect(w, r, ts1.URL, StatusFound)
+ }))
+ defer ts2.Close()
+ ts2URL = ts2.URL
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{
+ Transport: tr,
+ CheckRedirect: func(r *Request, via []*Request) error {
+ want := Header{
+ "User-Agent": []string{ua},
+ "X-Foo": []string{xfoo},
+ "Referer": []string{ts2URL},
+ }
+ if !reflect.DeepEqual(r.Header, want) {
+ t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want)
+ }
+ return nil
+ },
+ }
+
+ req, _ := NewRequest("GET", ts2.URL, nil)
+ req.Header.Add("User-Agent", ua)
+ req.Header.Add("X-Foo", xfoo)
+ req.Header.Add("Cookie", "foo=bar")
+ req.Header.Add("Authorization", "secretpassword")
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ t.Fatal(res.Status)
+ }
+ if got := res.Header.Get("Result"); got != "ok" {
+ t.Errorf("result = %q; want ok", got)
+ }
+}
+
+// Issue 17494: cookies should be altered when Client follows redirects.
+func TestClientAltersCookiesOnRedirect(t *testing.T) {
+ cookieMap := func(cs []*Cookie) map[string][]string {
+ m := make(map[string][]string)
+ for _, c := range cs {
+ m[c.Name] = append(m[c.Name], c.Value)
+ }
+ return m
+ }
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ var want map[string][]string
+ got := cookieMap(r.Cookies())
+
+ c, _ := r.Cookie("Cycle")
+ switch c.Value {
+ case "0":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie2": {"OldValue2"},
+ "Cookie3": {"OldValue3a", "OldValue3b"},
+ "Cookie4": {"OldValue4"},
+ "Cycle": {"0"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "1", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie2", Path: "/", MaxAge: -1}) // Delete cookie from Header
+ Redirect(w, r, "/", StatusFound)
+ case "1":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"OldValue3a", "OldValue3b"},
+ "Cookie4": {"OldValue4"},
+ "Cycle": {"1"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "2", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie3", Value: "NewValue3", Path: "/"}) // Modify cookie in Header
+ SetCookie(w, &Cookie{Name: "Cookie4", Value: "NewValue4", Path: "/"}) // Modify cookie in Jar
+ Redirect(w, r, "/", StatusFound)
+ case "2":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"NewValue3"},
+ "Cookie4": {"NewValue4"},
+ "Cycle": {"2"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "3", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie5", Value: "NewValue5", Path: "/"}) // Insert cookie into Jar
+ Redirect(w, r, "/", StatusFound)
+ case "3":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"NewValue3"},
+ "Cookie4": {"NewValue4"},
+ "Cookie5": {"NewValue5"},
+ "Cycle": {"3"},
+ }
+ // Don't redirect to ensure the loop ends.
+ default:
+ t.Errorf("unexpected redirect cycle")
+ return
+ }
+
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want)
+ }
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ jar, _ := cookiejar.New(nil)
+ c := &Client{
+ Transport: tr,
+ Jar: jar,
+ }
+
+ u, _ := url.Parse(ts.URL)
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1a"})
+ req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1b"})
+ req.AddCookie(&Cookie{Name: "Cookie2", Value: "OldValue2"})
+ req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3a"})
+ req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3b"})
+ jar.SetCookies(u, []*Cookie{{Name: "Cookie4", Value: "OldValue4", Path: "/"}})
+ jar.SetCookies(u, []*Cookie{{Name: "Cycle", Value: "0", Path: "/"}})
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ t.Fatal(res.Status)
+ }
+}
+
+// Part of Issue 4800
+func TestShouldCopyHeaderOnRedirect(t *testing.T) {
+ tests := []struct {
+ header string
+ initialURL string
+ destURL string
+ want bool
+ }{
+ {"User-Agent", "http://foo.com/", "http://bar.com/", true},
+ {"X-Foo", "http://foo.com/", "http://bar.com/", true},
+
+ // Sensitive headers:
+ {"cookie", "http://foo.com/", "http://bar.com/", false},
+ {"cookie2", "http://foo.com/", "http://bar.com/", false},
+ {"authorization", "http://foo.com/", "http://bar.com/", false},
+ {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
+
+ // But subdomains should work:
+ {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
+ {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
+ {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
+ // TODO(bradfitz): make this test work, once issue 16142 is fixed:
+ // {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
+ }
+ for i, tt := range tests {
+ u0, err := url.Parse(tt.initialURL)
+ if err != nil {
+ t.Errorf("%d. initial URL %q parse error: %v", i, tt.initialURL, err)
+ continue
+ }
+ u1, err := url.Parse(tt.destURL)
+ if err != nil {
+ t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err)
+ continue
+ }
+ got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1)
+ if got != tt.want {
+ t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
+ i, tt.header, tt.initialURL, tt.destURL, got, tt.want)
+ }
+ }
+}
+
+func TestClientRedirectTypes(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ tests := [...]struct {
+ method string
+ serverStatus int
+ wantMethod string // desired subsequent client method
+ }{
+ 0: {method: "POST", serverStatus: 301, wantMethod: "GET"},
+ 1: {method: "POST", serverStatus: 302, wantMethod: "GET"},
+ 2: {method: "POST", serverStatus: 303, wantMethod: "GET"},
+ 3: {method: "POST", serverStatus: 307, wantMethod: "POST"},
+ 4: {method: "POST", serverStatus: 308, wantMethod: "POST"},
+
+ 5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"},
+ 6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"},
+ 7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"},
+ 8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"},
+ 9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"},
+
+ 10: {method: "GET", serverStatus: 301, wantMethod: "GET"},
+ 11: {method: "GET", serverStatus: 302, wantMethod: "GET"},
+ 12: {method: "GET", serverStatus: 303, wantMethod: "GET"},
+ 13: {method: "GET", serverStatus: 307, wantMethod: "GET"},
+ 14: {method: "GET", serverStatus: 308, wantMethod: "GET"},
+
+ 15: {method: "DELETE", serverStatus: 301, wantMethod: "GET"},
+ 16: {method: "DELETE", serverStatus: 302, wantMethod: "GET"},
+ 17: {method: "DELETE", serverStatus: 303, wantMethod: "GET"},
+ 18: {method: "DELETE", serverStatus: 307, wantMethod: "DELETE"},
+ 19: {method: "DELETE", serverStatus: 308, wantMethod: "DELETE"},
+
+ 20: {method: "PUT", serverStatus: 301, wantMethod: "GET"},
+ 21: {method: "PUT", serverStatus: 302, wantMethod: "GET"},
+ 22: {method: "PUT", serverStatus: 303, wantMethod: "GET"},
+ 23: {method: "PUT", serverStatus: 307, wantMethod: "PUT"},
+ 24: {method: "PUT", serverStatus: 308, wantMethod: "PUT"},
+
+ 25: {method: "MADEUPMETHOD", serverStatus: 301, wantMethod: "GET"},
+ 26: {method: "MADEUPMETHOD", serverStatus: 302, wantMethod: "GET"},
+ 27: {method: "MADEUPMETHOD", serverStatus: 303, wantMethod: "GET"},
+ 28: {method: "MADEUPMETHOD", serverStatus: 307, wantMethod: "MADEUPMETHOD"},
+ 29: {method: "MADEUPMETHOD", serverStatus: 308, wantMethod: "MADEUPMETHOD"},
+ }
+
+ handlerc := make(chan HandlerFunc, 1)
+
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ h := <-handlerc
+ h(rw, req)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ for i, tt := range tests {
+ handlerc <- func(w ResponseWriter, r *Request) {
+ w.Header().Set("Location", ts.URL)
+ w.WriteHeader(tt.serverStatus)
+ }
+
+ req, err := NewRequest(tt.method, ts.URL, nil)
+ if err != nil {
+ t.Errorf("#%d: NewRequest: %v", i, err)
+ continue
+ }
+
+ c := &Client{Transport: tr}
+ c.CheckRedirect = func(req *Request, via []*Request) error {
+ if got, want := req.Method, tt.wantMethod; got != want {
+ return fmt.Errorf("#%d: got next method %q; want %q", i, got, want)
+ }
+ handlerc <- func(rw ResponseWriter, req *Request) {
+ // TODO: Check that the body is valid when we do 307 and 308 support
+ }
+ return nil
+ }
+
+ res, err := c.Do(req)
+ if err != nil {
+ t.Errorf("#%d: Response: %v", i, err)
+ continue
+ }
+
+ res.Body.Close()
+ }
+}
+
+// issue18239Body is an io.ReadCloser for TestTransportBodyReadError.
+// Its Read returns readErr and increments *readCalls atomically.
+// Its Close returns nil and increments *closeCalls atomically.
+type issue18239Body struct {
+ readCalls *int32
+ closeCalls *int32
+ readErr error
+}
+
+func (b issue18239Body) Read([]byte) (int, error) {
+ atomic.AddInt32(b.readCalls, 1)
+ return 0, b.readErr
+}
+
+func (b issue18239Body) Close() error {
+ atomic.AddInt32(b.closeCalls, 1)
+ return nil
+}
+
+// Issue 18239: make sure the Transport doesn't retry requests with bodies.
+// (Especially if Request.GetBody is not defined.)
+func TestTransportBodyReadError(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/ping" {
+ return
+ }
+ buf := make([]byte, 1)
+ n, err := r.Body.Read(buf)
+ w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err))
+ }))
+ defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ // Do one initial successful request to create an idle TCP connection
+ // for the subsequent request to reuse. (The Transport only retries
+ // requests on reused connections.)
+ res, err := c.Get(ts.URL + "/ping")
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+
+ var readCallsAtomic int32
+ var closeCallsAtomic int32 // atomic
+ someErr := errors.New("some body read error")
+ body := issue18239Body{&readCallsAtomic, &closeCallsAtomic, someErr}
+
+ req, err := NewRequest("POST", ts.URL, body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = tr.RoundTrip(req)
+ if err != someErr {
+ t.Errorf("Got error: %v; want Request.Body read error: %v", err, someErr)
+ }
+
+ // And verify that our Body wasn't used multiple times, which
+ // would indicate retries. (as it buggily was during part of
+ // Go 1.8's dev cycle)
+ readCalls := atomic.LoadInt32(&readCallsAtomic)
+ closeCalls := atomic.LoadInt32(&closeCallsAtomic)
+ if readCalls != 1 {
+ t.Errorf("read calls = %d; want 1", readCalls)
+ }
+ if closeCalls != 1 {
+ t.Errorf("close calls = %d; want 1", closeCalls)
+ }
+}
diff --git a/libgo/go/net/http/clientserver_test.go b/libgo/go/net/http/clientserver_test.go
index aa2473a277..580115ca9c 100644
--- a/libgo/go/net/http/clientserver_test.go
+++ b/libgo/go/net/http/clientserver_test.go
@@ -17,6 +17,7 @@ import (
"net"
. "net/http"
"net/http/httptest"
+ "net/http/httputil"
"net/url"
"os"
"reflect"
@@ -43,11 +44,35 @@ func (t *clientServerTest) close() {
t.ts.Close()
}
+func (t *clientServerTest) getURL(u string) string {
+ res, err := t.c.Get(u)
+ if err != nil {
+ t.t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.t.Fatal(err)
+ }
+ return string(slurp)
+}
+
+func (t *clientServerTest) scheme() string {
+ if t.h2 {
+ return "https"
+ }
+ return "http"
+}
+
const (
h1Mode = false
h2Mode = true
)
+var optQuietLog = func(ts *httptest.Server) {
+ ts.Config.ErrorLog = quietLog
+}
+
func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{}) *clientServerTest {
cst := &clientServerTest{
t: t,
@@ -56,21 +81,23 @@ func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{})
tr: &Transport{},
}
cst.c = &Client{Transport: cst.tr}
+ cst.ts = httptest.NewUnstartedServer(h)
for _, opt := range opts {
switch opt := opt.(type) {
case func(*Transport):
opt(cst.tr)
+ case func(*httptest.Server):
+ opt(cst.ts)
default:
t.Fatalf("unhandled option type %T", opt)
}
}
if !h2 {
- cst.ts = httptest.NewServer(h)
+ cst.ts.Start()
return cst
}
- cst.ts = httptest.NewUnstartedServer(h)
ExportHttp2ConfigureServer(cst.ts.Config, nil)
cst.ts.TLS = cst.ts.Config.TLSConfig
cst.ts.StartTLS()
@@ -147,10 +174,11 @@ type reqFunc func(c *Client, url string) (*Response, error)
// h12Compare is a test that compares HTTP/1 and HTTP/2 behavior
// against each other.
type h12Compare struct {
- Handler func(ResponseWriter, *Request) // required
- ReqFunc reqFunc // optional
- CheckResponse func(proto string, res *Response) // optional
- Opts []interface{}
+ Handler func(ResponseWriter, *Request) // required
+ ReqFunc reqFunc // optional
+ CheckResponse func(proto string, res *Response) // optional
+ EarlyCheckResponse func(proto string, res *Response) // optional; pre-normalize
+ Opts []interface{}
}
func (tt h12Compare) reqFunc() reqFunc {
@@ -161,6 +189,7 @@ func (tt h12Compare) reqFunc() reqFunc {
}
func (tt h12Compare) run(t *testing.T) {
+ setParallel(t)
cst1 := newClientServerTest(t, false, HandlerFunc(tt.Handler), tt.Opts...)
defer cst1.close()
cst2 := newClientServerTest(t, true, HandlerFunc(tt.Handler), tt.Opts...)
@@ -176,6 +205,12 @@ func (tt h12Compare) run(t *testing.T) {
t.Errorf("HTTP/2 request: %v", err)
return
}
+
+ if fn := tt.EarlyCheckResponse; fn != nil {
+ fn("HTTP/1.1", res1)
+ fn("HTTP/2.0", res2)
+ }
+
tt.normalizeRes(t, res1, "HTTP/1.1")
tt.normalizeRes(t, res2, "HTTP/2.0")
res1body, res2body := res1.Body, res2.Body
@@ -220,6 +255,7 @@ func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string)
t.Errorf("got %q response; want %q", res.Proto, wantProto)
}
slurp, err := ioutil.ReadAll(res.Body)
+
res.Body.Close()
res.Body = slurpResult{
ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)),
@@ -356,7 +392,7 @@ func TestH12_HandlerWritesTooLittle(t *testing.T) {
}
// Tests that the HTTP/1 and HTTP/2 servers prevent handlers from
-// writing more than they declared. This test does not test whether
+// writing more than they declared. This test does not test whether
// the transport deals with too much data, though, since the server
// doesn't make it possible to send bogus data. For those tests, see
// transport_test.go (for HTTP/1) or x/net/http2/transport_test.go
@@ -452,7 +488,7 @@ func TestH12_RequestContentLength_Known_NonZero(t *testing.T) {
}
func TestH12_RequestContentLength_Known_Zero(t *testing.T) {
- h12requestContentLength(t, func() io.Reader { return strings.NewReader("") }, 0)
+ h12requestContentLength(t, func() io.Reader { return nil }, 0)
}
func TestH12_RequestContentLength_Unknown(t *testing.T) {
@@ -922,6 +958,7 @@ func testStarRequest(t *testing.T, method string, h2 bool) {
// Issue 13957
func TestTransportDiscardsUnneededConns(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hello, %v", r.RemoteAddr)
@@ -1010,6 +1047,7 @@ func testTransportGCRequest(t *testing.T, h2, body bool) {
t.Skip("skipping on gccgo because conservative GC means that finalizer may never run")
}
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
ioutil.ReadAll(r.Body)
@@ -1049,6 +1087,228 @@ func testTransportGCRequest(t *testing.T, h2, body bool) {
}
}
+func TestTransportRejectsInvalidHeaders_h1(t *testing.T) {
+ testTransportRejectsInvalidHeaders(t, h1Mode)
+}
+func TestTransportRejectsInvalidHeaders_h2(t *testing.T) {
+ testTransportRejectsInvalidHeaders(t, h2Mode)
+}
+func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "Handler saw headers: %q", r.Header)
+ }), optQuietLog)
+ defer cst.close()
+ cst.tr.DisableKeepAlives = true
+
+ tests := []struct {
+ key, val string
+ ok bool
+ }{
+ {"Foo", "capital-key", true}, // verify h2 allows capital keys
+ {"Foo", "foo\x00bar", false}, // \x00 byte in value not allowed
+ {"Foo", "two\nlines", false}, // \n byte in value not allowed
+ {"bogus\nkey", "v", false}, // \n byte also not allowed in key
+ {"A space", "v", false}, // spaces in keys not allowed
+ {"имÑ", "v", false}, // key must be ascii
+ {"name", "валю", true}, // value may be non-ascii
+ {"", "v", false}, // key must be non-empty
+ {"k", "", true}, // value may be empty
+ }
+ for _, tt := range tests {
+ dialedc := make(chan bool, 1)
+ cst.tr.Dial = func(netw, addr string) (net.Conn, error) {
+ dialedc <- true
+ return net.Dial(netw, addr)
+ }
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req.Header[tt.key] = []string{tt.val}
+ res, err := cst.c.Do(req)
+ var body []byte
+ if err == nil {
+ body, _ = ioutil.ReadAll(res.Body)
+ res.Body.Close()
+ }
+ var dialed bool
+ select {
+ case <-dialedc:
+ dialed = true
+ default:
+ }
+
+ if !tt.ok && dialed {
+ t.Errorf("For key %q, value %q, transport dialed. Expected local failure. Response was: (%v, %v)\nServer replied with: %s", tt.key, tt.val, res, err, body)
+ } else if (err == nil) != tt.ok {
+ t.Errorf("For key %q, value %q; got err = %v; want ok=%v", tt.key, tt.val, err, tt.ok)
+ }
+ }
+}
+
+// Tests that we support bogus under-100 HTTP statuses, because we historically
+// have. This might change at some point, but not yet in Go 1.6.
+func TestBogusStatusWorks_h1(t *testing.T) { testBogusStatusWorks(t, h1Mode) }
+func TestBogusStatusWorks_h2(t *testing.T) { testBogusStatusWorks(t, h2Mode) }
+func testBogusStatusWorks(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ const code = 7
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.WriteHeader(code)
+ }))
+ defer cst.close()
+
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if res.StatusCode != code {
+ t.Errorf("StatusCode = %d; want %d", res.StatusCode, code)
+ }
+}
+
+func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, "boom") }
+func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, "boom") }
+func TestInterruptWithPanic_nil_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, nil) }
+func TestInterruptWithPanic_nil_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, nil) }
+func TestInterruptWithPanic_ErrAbortHandler_h1(t *testing.T) {
+ testInterruptWithPanic(t, h1Mode, ErrAbortHandler)
+}
+func TestInterruptWithPanic_ErrAbortHandler_h2(t *testing.T) {
+ testInterruptWithPanic(t, h2Mode, ErrAbortHandler)
+}
+func testInterruptWithPanic(t *testing.T, h2 bool, panicValue interface{}) {
+ setParallel(t)
+ const msg = "hello"
+ defer afterTest(t)
+
+ testDone := make(chan struct{})
+ defer close(testDone)
+
+ var errorLog lockedBytesBuffer
+ gotHeaders := make(chan bool, 1)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, msg)
+ w.(Flusher).Flush()
+
+ select {
+ case <-gotHeaders:
+ case <-testDone:
+ }
+ panic(panicValue)
+ }), func(ts *httptest.Server) {
+ ts.Config.ErrorLog = log.New(&errorLog, "", 0)
+ })
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gotHeaders <- true
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if string(slurp) != msg {
+ t.Errorf("client read %q; want %q", slurp, msg)
+ }
+ if err == nil {
+ t.Errorf("client read all successfully; want some error")
+ }
+ logOutput := func() string {
+ errorLog.Lock()
+ defer errorLog.Unlock()
+ return errorLog.String()
+ }
+ wantStackLogged := panicValue != nil && panicValue != ErrAbortHandler
+
+ if err := waitErrCondition(5*time.Second, 10*time.Millisecond, func() error {
+ gotLog := logOutput()
+ if !wantStackLogged {
+ if gotLog == "" {
+ return nil
+ }
+ return fmt.Errorf("want no log output; got: %s", gotLog)
+ }
+ if gotLog == "" {
+ return fmt.Errorf("wanted a stack trace logged; got nothing")
+ }
+ if !strings.Contains(gotLog, "created by ") && strings.Count(gotLog, "\n") < 6 {
+ return fmt.Errorf("output doesn't look like a panic stack trace. Got: %s", gotLog)
+ }
+ return nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type lockedBytesBuffer struct {
+ sync.Mutex
+ bytes.Buffer
+}
+
+func (b *lockedBytesBuffer) Write(p []byte) (int, error) {
+ b.Lock()
+ defer b.Unlock()
+ return b.Buffer.Write(p)
+}
+
+// Issue 15366
+func TestH12_AutoGzipWithDumpResponse(t *testing.T) {
+ h12Compare{
+ Handler: func(w ResponseWriter, r *Request) {
+ h := w.Header()
+ h.Set("Content-Encoding", "gzip")
+ h.Set("Content-Length", "23")
+ h.Set("Connection", "keep-alive")
+ 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 !res.Uncompressed {
+ t.Errorf("%s: expected Uncompressed to be set", proto)
+ }
+ dump, err := httputil.DumpResponse(res, true)
+ if err != nil {
+ t.Errorf("%s: DumpResponse: %v", proto, err)
+ return
+ }
+ if strings.Contains(string(dump), "Connection: close") {
+ t.Errorf("%s: should not see \"Connection: close\" in dump; got:\n%s", proto, dump)
+ }
+ if !strings.Contains(string(dump), "FOO") {
+ t.Errorf("%s: should see \"FOO\" in response; got:\n%s", proto, dump)
+ }
+ },
+ }.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) {
+ setParallel(t)
+ 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()
@@ -1058,3 +1318,70 @@ func (x noteCloseConn) Close() error {
x.closeFunc()
return x.Conn.Close()
}
+
+type testErrorReader struct{ t *testing.T }
+
+func (r testErrorReader) Read(p []byte) (n int, err error) {
+ r.t.Error("unexpected Read call")
+ return 0, io.EOF
+}
+
+func TestNoSniffExpectRequestBody_h1(t *testing.T) { testNoSniffExpectRequestBody(t, h1Mode) }
+func TestNoSniffExpectRequestBody_h2(t *testing.T) { testNoSniffExpectRequestBody(t, h2Mode) }
+
+func testNoSniffExpectRequestBody(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.WriteHeader(StatusUnauthorized)
+ }))
+ defer cst.close()
+
+ // Set ExpectContinueTimeout non-zero so RoundTrip won't try to write it.
+ cst.tr.ExpectContinueTimeout = 10 * time.Second
+
+ req, err := NewRequest("POST", cst.ts.URL, testErrorReader{t})
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.ContentLength = 0 // so transport is tempted to sniff it
+ req.Header.Set("Expect", "100-continue")
+ res, err := cst.tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != StatusUnauthorized {
+ t.Errorf("status code = %v; want %v", res.StatusCode, StatusUnauthorized)
+ }
+}
+
+func TestServerUndeclaredTrailers_h1(t *testing.T) { testServerUndeclaredTrailers(t, h1Mode) }
+func TestServerUndeclaredTrailers_h2(t *testing.T) { testServerUndeclaredTrailers(t, h2Mode) }
+func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Foo", "Bar")
+ w.Header().Set("Trailer:Foo", "Baz")
+ w.(Flusher).Flush()
+ w.Header().Add("Trailer:Foo", "Baz2")
+ w.Header().Set("Trailer:Bar", "Quux")
+ }))
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ delete(res.Header, "Date")
+ delete(res.Header, "Content-Type")
+
+ if want := (Header{"Foo": {"Bar"}}); !reflect.DeepEqual(res.Header, want) {
+ t.Errorf("Header = %#v; want %#v", res.Header, want)
+ }
+ if want := (Header{"Foo": {"Baz", "Baz2"}, "Bar": {"Quux"}}); !reflect.DeepEqual(res.Trailer, want) {
+ t.Errorf("Trailer = %#v; want %#v", res.Trailer, want)
+ }
+}
diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go
index 648709dd99..5a67476cd4 100644
--- a/libgo/go/net/http/cookie.go
+++ b/libgo/go/net/http/cookie.go
@@ -6,7 +6,6 @@ package http
import (
"bytes"
- "fmt"
"log"
"net"
"strconv"
@@ -40,7 +39,11 @@ type Cookie struct {
// readSetCookies parses all "Set-Cookie" values from
// the header h and returns the successfully parsed Cookies.
func readSetCookies(h Header) []*Cookie {
- cookies := []*Cookie{}
+ cookieCount := len(h["Set-Cookie"])
+ if cookieCount == 0 {
+ return []*Cookie{}
+ }
+ cookies := make([]*Cookie, 0, cookieCount)
for _, line := range h["Set-Cookie"] {
parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
@@ -55,8 +58,8 @@ func readSetCookies(h Header) []*Cookie {
if !isCookieNameValid(name) {
continue
}
- value, success := parseCookieValue(value, true)
- if !success {
+ value, ok := parseCookieValue(value, true)
+ if !ok {
continue
}
c := &Cookie{
@@ -75,8 +78,8 @@ func readSetCookies(h Header) []*Cookie {
attr, val = attr[:j], attr[j+1:]
}
lowerAttr := strings.ToLower(attr)
- val, success = parseCookieValue(val, false)
- if !success {
+ val, ok = parseCookieValue(val, false)
+ if !ok {
c.Unparsed = append(c.Unparsed, parts[i])
continue
}
@@ -96,10 +99,9 @@ func readSetCookies(h Header) []*Cookie {
break
}
if secs <= 0 {
- c.MaxAge = -1
- } else {
- c.MaxAge = secs
+ secs = -1
}
+ c.MaxAge = secs
continue
case "expires":
c.RawExpires = val
@@ -142,9 +144,13 @@ func (c *Cookie) String() string {
return ""
}
var b bytes.Buffer
- fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
+ b.WriteString(sanitizeCookieName(c.Name))
+ b.WriteRune('=')
+ b.WriteString(sanitizeCookieValue(c.Value))
+
if len(c.Path) > 0 {
- fmt.Fprintf(&b, "; Path=%s", sanitizeCookiePath(c.Path))
+ b.WriteString("; Path=")
+ b.WriteString(sanitizeCookiePath(c.Path))
}
if len(c.Domain) > 0 {
if validCookieDomain(c.Domain) {
@@ -156,25 +162,31 @@ func (c *Cookie) String() string {
if d[0] == '.' {
d = d[1:]
}
- fmt.Fprintf(&b, "; Domain=%s", d)
+ b.WriteString("; Domain=")
+ b.WriteString(d)
} else {
- log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute",
- c.Domain)
+ log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", c.Domain)
}
}
- if c.Expires.Unix() > 0 {
- fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(TimeFormat))
+ if validCookieExpires(c.Expires) {
+ b.WriteString("; Expires=")
+ b2 := b.Bytes()
+ b.Reset()
+ b.Write(c.Expires.UTC().AppendFormat(b2, TimeFormat))
}
if c.MaxAge > 0 {
- fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
+ b.WriteString("; Max-Age=")
+ b2 := b.Bytes()
+ b.Reset()
+ b.Write(strconv.AppendInt(b2, int64(c.MaxAge), 10))
} else if c.MaxAge < 0 {
- fmt.Fprintf(&b, "; Max-Age=0")
+ b.WriteString("; Max-Age=0")
}
if c.HttpOnly {
- fmt.Fprintf(&b, "; HttpOnly")
+ b.WriteString("; HttpOnly")
}
if c.Secure {
- fmt.Fprintf(&b, "; Secure")
+ b.WriteString("; Secure")
}
return b.String()
}
@@ -184,12 +196,12 @@ func (c *Cookie) String() string {
//
// if filter isn't empty, only cookies of that name are returned
func readCookies(h Header, filter string) []*Cookie {
- cookies := []*Cookie{}
lines, ok := h["Cookie"]
if !ok {
- return cookies
+ return []*Cookie{}
}
+ cookies := []*Cookie{}
for _, line := range lines {
parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
@@ -212,8 +224,8 @@ func readCookies(h Header, filter string) []*Cookie {
if filter != "" && filter != name {
continue
}
- val, success := parseCookieValue(val, true)
- if !success {
+ val, ok := parseCookieValue(val, true)
+ if !ok {
continue
}
cookies = append(cookies, &Cookie{Name: name, Value: val})
@@ -223,7 +235,7 @@ func readCookies(h Header, filter string) []*Cookie {
return cookies
}
-// validCookieDomain returns wheter v is a valid cookie domain-value.
+// validCookieDomain returns whether v is a valid cookie domain-value.
func validCookieDomain(v string) bool {
if isCookieDomainName(v) {
return true
@@ -234,6 +246,12 @@ func validCookieDomain(v string) bool {
return false
}
+// validCookieExpires returns whether v is a valid cookie expires-value.
+func validCookieExpires(t time.Time) bool {
+ // IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601
+ return t.Year() >= 1601
+}
+
// isCookieDomainName returns whether s is a valid domain name or a valid
// domain name with a leading dot '.'. It is almost a direct copy of
// package net's isDomainName.
diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go
index d474f31347..b3e54f8db3 100644
--- a/libgo/go/net/http/cookie_test.go
+++ b/libgo/go/net/http/cookie_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -56,6 +56,15 @@ var writeSetCookiesTests = []struct {
&Cookie{Name: "cookie-9", Value: "expiring", Expires: time.Unix(1257894000, 0)},
"cookie-9=expiring; Expires=Tue, 10 Nov 2009 23:00:00 GMT",
},
+ // According to IETF 6265 Section 5.1.1.5, the year cannot be less than 1601
+ {
+ &Cookie{Name: "cookie-10", Value: "expiring-1601", Expires: time.Date(1601, 1, 1, 1, 1, 1, 1, time.UTC)},
+ "cookie-10=expiring-1601; Expires=Mon, 01 Jan 1601 01:01:01 GMT",
+ },
+ {
+ &Cookie{Name: "cookie-11", Value: "invalid-expiry", Expires: time.Date(1600, 1, 1, 1, 1, 1, 1, time.UTC)},
+ "cookie-11=invalid-expiry",
+ },
// The "special" cookies have values containing commas or spaces which
// are disallowed by RFC 6265 but are common in the wild.
{
@@ -426,3 +435,92 @@ func TestCookieSanitizePath(t *testing.T) {
t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
}
}
+
+func BenchmarkCookieString(b *testing.B) {
+ const wantCookieString = `cookie-9=i3e01nf61b6t23bvfmplnanol3; Path=/restricted/; Domain=example.com; Expires=Tue, 10 Nov 2009 23:00:00 GMT; Max-Age=3600`
+ c := &Cookie{
+ Name: "cookie-9",
+ Value: "i3e01nf61b6t23bvfmplnanol3",
+ Expires: time.Unix(1257894000, 0),
+ Path: "/restricted/",
+ Domain: ".example.com",
+ MaxAge: 3600,
+ }
+ var benchmarkCookieString string
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ benchmarkCookieString = c.String()
+ }
+ if have, want := benchmarkCookieString, wantCookieString; have != want {
+ b.Fatalf("Have: %v Want: %v", have, want)
+ }
+}
+
+func BenchmarkReadSetCookies(b *testing.B) {
+ header := Header{
+ "Set-Cookie": {
+ "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ },
+ }
+ wantCookies := []*Cookie{
+ {
+ Name: "NID",
+ Value: "99=YsDT5i3E-CXax-",
+ Path: "/",
+ Domain: ".google.ch",
+ HttpOnly: true,
+ Expires: time.Date(2011, 11, 23, 1, 5, 3, 0, time.UTC),
+ RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
+ Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ },
+ {
+ Name: ".ASPXAUTH",
+ Value: "7E3AA",
+ Path: "/",
+ Expires: time.Date(2012, 3, 7, 14, 25, 6, 0, time.UTC),
+ RawExpires: "Wed, 07-Mar-2012 14:25:06 GMT",
+ HttpOnly: true,
+ Raw: ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ },
+ }
+ var c []*Cookie
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c = readSetCookies(header)
+ }
+ if !reflect.DeepEqual(c, wantCookies) {
+ b.Fatalf("readSetCookies:\nhave: %s\nwant: %s\n", toJSON(c), toJSON(wantCookies))
+ }
+}
+
+func BenchmarkReadCookies(b *testing.B) {
+ header := Header{
+ "Cookie": {
+ `de=; client_region=0; rpld1=0:hispeed.ch|20:che|21:zh|22:zurich|23:47.36|24:8.53|; rpld0=1:08|; backplane-channel=newspaper.com:1471; devicetype=0; osfam=0; rplmct=2; s_pers=%20s_vmonthnum%3D1472680800496%2526vn%253D1%7C1472680800496%3B%20s_nr%3D1471686767664-New%7C1474278767664%3B%20s_lv%3D1471686767669%7C1566294767669%3B%20s_lv_s%3DFirst%2520Visit%7C1471688567669%3B%20s_monthinvisit%3Dtrue%7C1471688567677%3B%20gvp_p5%3Dsports%253Ablog%253Aearly-lead%2520-%2520184693%2520-%252020160820%2520-%2520u-s%7C1471688567681%3B%20gvp_p51%3Dwp%2520-%2520sports%7C1471688567684%3B; s_sess=%20s_wp_ep%3Dhomepage%3B%20s._ref%3Dhttps%253A%252F%252Fwww.google.ch%252F%3B%20s_cc%3Dtrue%3B%20s_ppvl%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B%20s_ppv%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-s-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B%20s_dslv%3DFirst%2520Visit%3B%20s_sq%3Dwpninewspapercom%253D%252526pid%25253Dsports%2525253Ablog%2525253Aearly-lead%25252520-%25252520184693%25252520-%2525252020160820%25252520-%25252520u-s%252526pidt%25253D1%252526oid%25253Dhttps%2525253A%2525252F%2525252Fwww.newspaper.com%2525252F%2525253Fnid%2525253Dmenu_nav_homepage%252526ot%25253DA%3B`,
+ },
+ }
+ wantCookies := []*Cookie{
+ {Name: "de", Value: ""},
+ {Name: "client_region", Value: "0"},
+ {Name: "rpld1", Value: "0:hispeed.ch|20:che|21:zh|22:zurich|23:47.36|24:8.53|"},
+ {Name: "rpld0", Value: "1:08|"},
+ {Name: "backplane-channel", Value: "newspaper.com:1471"},
+ {Name: "devicetype", Value: "0"},
+ {Name: "osfam", Value: "0"},
+ {Name: "rplmct", Value: "2"},
+ {Name: "s_pers", Value: "%20s_vmonthnum%3D1472680800496%2526vn%253D1%7C1472680800496%3B%20s_nr%3D1471686767664-New%7C1474278767664%3B%20s_lv%3D1471686767669%7C1566294767669%3B%20s_lv_s%3DFirst%2520Visit%7C1471688567669%3B%20s_monthinvisit%3Dtrue%7C1471688567677%3B%20gvp_p5%3Dsports%253Ablog%253Aearly-lead%2520-%2520184693%2520-%252020160820%2520-%2520u-s%7C1471688567681%3B%20gvp_p51%3Dwp%2520-%2520sports%7C1471688567684%3B"},
+ {Name: "s_sess", Value: "%20s_wp_ep%3Dhomepage%3B%20s._ref%3Dhttps%253A%252F%252Fwww.google.ch%252F%3B%20s_cc%3Dtrue%3B%20s_ppvl%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B%20s_ppv%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-s-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B%20s_dslv%3DFirst%2520Visit%3B%20s_sq%3Dwpninewspapercom%253D%252526pid%25253Dsports%2525253Ablog%2525253Aearly-lead%25252520-%25252520184693%25252520-%2525252020160820%25252520-%25252520u-s%252526pidt%25253D1%252526oid%25253Dhttps%2525253A%2525252F%2525252Fwww.newspaper.com%2525252F%2525253Fnid%2525253Dmenu_nav_homepage%252526ot%25253DA%3B"},
+ }
+ var c []*Cookie
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c = readCookies(header, "")
+ }
+ if !reflect.DeepEqual(c, wantCookies) {
+ b.Fatalf("readCookies:\nhave: %s\nwant: %s\n", toJSON(c), toJSON(wantCookies))
+ }
+}
diff --git a/libgo/go/net/http/cookiejar/dummy_publicsuffix_test.go b/libgo/go/net/http/cookiejar/dummy_publicsuffix_test.go
new file mode 100644
index 0000000000..748ec5cc43
--- /dev/null
+++ b/libgo/go/net/http/cookiejar/dummy_publicsuffix_test.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package cookiejar_test
+
+import "net/http/cookiejar"
+
+type dummypsl struct {
+ List cookiejar.PublicSuffixList
+}
+
+func (dummypsl) PublicSuffix(domain string) string {
+ return domain
+}
+
+func (dummypsl) String() string {
+ return "dummy"
+}
+
+var publicsuffix = dummypsl{}
diff --git a/libgo/go/net/http/cookiejar/example_test.go b/libgo/go/net/http/cookiejar/example_test.go
new file mode 100644
index 0000000000..19a57465ff
--- /dev/null
+++ b/libgo/go/net/http/cookiejar/example_test.go
@@ -0,0 +1,67 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package cookiejar_test
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/cookiejar"
+ "net/http/httptest"
+ "net/url"
+)
+
+func ExampleNew() {
+ // Start a server to give us cookies.
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if cookie, err := r.Cookie("Flavor"); err != nil {
+ http.SetCookie(w, &http.Cookie{Name: "Flavor", Value: "Chocolate Chip"})
+ } else {
+ cookie.Value = "Oatmeal Raisin"
+ http.SetCookie(w, cookie)
+ }
+ }))
+ defer ts.Close()
+
+ u, err := url.Parse(ts.URL)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // All users of cookiejar should import "golang.org/x/net/publicsuffix"
+ jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ client := &http.Client{
+ Jar: jar,
+ }
+
+ if _, err = client.Get(u.String()); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("After 1st request:")
+ for _, cookie := range jar.Cookies(u) {
+ fmt.Printf(" %s: %s\n", cookie.Name, cookie.Value)
+ }
+
+ if _, err = client.Get(u.String()); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("After 2nd request:")
+ for _, cookie := range jar.Cookies(u) {
+ fmt.Printf(" %s: %s\n", cookie.Name, cookie.Value)
+ }
+ // Output:
+ // After 1st request:
+ // Flavor: Chocolate Chip
+ // After 2nd request:
+ // Flavor: Oatmeal Raisin
+}
diff --git a/libgo/go/net/http/cookiejar/jar.go b/libgo/go/net/http/cookiejar/jar.go
index 0e0fac9286..f89abbcd18 100644
--- a/libgo/go/net/http/cookiejar/jar.go
+++ b/libgo/go/net/http/cookiejar/jar.go
@@ -107,7 +107,7 @@ type entry struct {
seqNum uint64
}
-// Id returns the domain;path;name triple of e as an id.
+// id returns the domain;path;name triple of e as an id.
func (e *entry) id() string {
return fmt.Sprintf("%s;%s;%s", e.Domain, e.Path, e.Name)
}
@@ -147,24 +147,6 @@ func hasDotSuffix(s, suffix string) bool {
return len(s) > len(suffix) && s[len(s)-len(suffix)-1] == '.' && s[len(s)-len(suffix):] == suffix
}
-// byPathLength is a []entry sort.Interface that sorts according to RFC 6265
-// section 5.4 point 2: by longest path and then by earliest creation time.
-type byPathLength []entry
-
-func (s byPathLength) Len() int { return len(s) }
-
-func (s byPathLength) Less(i, j int) bool {
- if len(s[i].Path) != len(s[j].Path) {
- return len(s[i].Path) > len(s[j].Path)
- }
- if !s[i].Creation.Equal(s[j].Creation) {
- return s[i].Creation.Before(s[j].Creation)
- }
- return s[i].seqNum < s[j].seqNum
-}
-
-func (s byPathLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
// Cookies implements the Cookies method of the http.CookieJar interface.
//
// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
@@ -221,7 +203,18 @@ func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) {
}
}
- sort.Sort(byPathLength(selected))
+ // sort according to RFC 6265 section 5.4 point 2: by longest
+ // path and then by earliest creation time.
+ sort.Slice(selected, func(i, j int) bool {
+ s := selected
+ if len(s[i].Path) != len(s[j].Path) {
+ return len(s[i].Path) > len(s[j].Path)
+ }
+ if !s[i].Creation.Equal(s[j].Creation) {
+ return s[i].Creation.Before(s[j].Creation)
+ }
+ return s[i].seqNum < s[j].seqNum
+ })
for _, e := range selected {
cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value})
}
diff --git a/libgo/go/net/http/cookiejar/punycode.go b/libgo/go/net/http/cookiejar/punycode.go
index ea7ceb5ef3..a9cc666e8c 100644
--- a/libgo/go/net/http/cookiejar/punycode.go
+++ b/libgo/go/net/http/cookiejar/punycode.go
@@ -37,7 +37,7 @@ func encode(prefix, s string) (string, error) {
delta, n, bias := int32(0), initialN, initialBias
b, remaining := int32(0), int32(0)
for _, r := range s {
- if r < 0x80 {
+ if r < utf8.RuneSelf {
b++
output = append(output, byte(r))
} else {
diff --git a/libgo/go/net/http/doc.go b/libgo/go/net/http/doc.go
index 4ec8272f62..7855feaaa9 100644
--- a/libgo/go/net/http/doc.go
+++ b/libgo/go/net/http/doc.go
@@ -44,7 +44,8 @@ For control over proxies, TLS configuration, keep-alives,
compression, and other settings, create a Transport:
tr := &http.Transport{
- TLSClientConfig: &tls.Config{RootCAs: pool},
+ MaxIdleConns: 10,
+ IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}
client := &http.Client{Transport: tr}
@@ -77,19 +78,30 @@ custom Server:
}
log.Fatal(s.ListenAndServe())
-The http package has transparent support for the HTTP/2 protocol when
-using HTTPS. Programs that must disable HTTP/2 can do so by setting
-Transport.TLSNextProto (for clients) or Server.TLSNextProto (for
-servers) to a non-nil, empty map. Alternatively, the following GODEBUG
-environment variables are currently supported:
+Starting with Go 1.6, the http package has transparent support for the
+HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2
+can do so by setting Transport.TLSNextProto (for clients) or
+Server.TLSNextProto (for servers) to a non-nil, empty
+map. Alternatively, the following GODEBUG environment variables are
+currently supported:
GODEBUG=http2client=0 # disable HTTP/2 client support
GODEBUG=http2server=0 # disable HTTP/2 server support
GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs
GODEBUG=http2debug=2 # ... even more verbose, with frame dumps
-The GODEBUG variables are not covered by Go's API compatibility promise.
-HTTP/2 support was added in Go 1.6. Please report any issues instead of
-disabling HTTP/2 support: https://golang.org/s/http2bug
+The GODEBUG variables are not covered by Go's API compatibility
+promise. Please report any issues before disabling HTTP/2
+support: https://golang.org/s/http2bug
+
+The http package's Transport and Server both automatically enable
+HTTP/2 support for simple configurations. To enable HTTP/2 for more
+complex configurations, to use lower-level HTTP/2 features, or to use
+a newer version of Go's http2 package, import "golang.org/x/net/http2"
+directly and use its ConfigureTransport and/or ConfigureServer
+functions. Manually configuring HTTP/2 via the golang.org/x/net/http2
+package takes precedence over the net/http package's built-in HTTP/2
+support.
+
*/
package http
diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go
index 52bccbdce3..b61f58b2db 100644
--- a/libgo/go/net/http/export_test.go
+++ b/libgo/go/net/http/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -9,22 +9,23 @@ package http
import (
"net"
+ "sort"
"sync"
"time"
)
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
+ ExportScanETag = scanETag
+ ExportHttp2ConfigureServer = http2ConfigureServer
)
func init() {
@@ -35,9 +36,8 @@ func init() {
}
var (
- SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip)
- SetTestHookWaitResLoop = hookSetter(&testHookWaitResLoop)
- SetRoundTripRetried = hookSetter(&testHookRoundTripRetried)
+ SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip)
+ SetRoundTripRetried = hookSetter(&testHookRoundTripRetried)
)
func SetReadLoopBeforeNextReadHook(f func()) {
@@ -59,9 +59,9 @@ func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServ
func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
return &timeoutHandler{
- handler: handler,
- timeout: func() <-chan time.Time { return ch },
- // (no body and nil cancelTimer)
+ handler: handler,
+ testTimeout: ch,
+ // (no body)
}
}
@@ -81,21 +81,53 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
keys = make([]string, 0)
t.idleMu.Lock()
defer t.idleMu.Unlock()
- if t.idleConn == nil {
- return
- }
for key := range t.idleConn {
keys = append(keys, key.String())
}
+ sort.Strings(keys)
return
}
-func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
+func (t *Transport) IdleConnKeyCountForTesting() int {
t.idleMu.Lock()
defer t.idleMu.Unlock()
- if t.idleConn == nil {
- return 0
+ return len(t.idleConn)
+}
+
+func (t *Transport) IdleConnStrsForTesting() []string {
+ var ret []string
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ for _, conns := range t.idleConn {
+ for _, pc := range conns {
+ ret = append(ret, pc.conn.LocalAddr().String()+"/"+pc.conn.RemoteAddr().String())
+ }
}
+ sort.Strings(ret)
+ return ret
+}
+
+func (t *Transport) IdleConnStrsForTesting_h2() []string {
+ var ret []string
+ noDialPool := t.h2transport.ConnPool.(http2noDialClientConnPool)
+ pool := noDialPool.http2clientConnPool
+
+ pool.mu.Lock()
+ defer pool.mu.Unlock()
+
+ for k, cc := range pool.conns {
+ for range cc {
+ ret = append(ret, k)
+ }
+ }
+
+ sort.Strings(ret)
+ return ret
+}
+
+func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
for k, conns := range t.idleConn {
if k.String() == cacheKey {
return len(conns)
@@ -144,3 +176,26 @@ 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
+}
+
+var Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect
+
+func (s *Server) ExportAllConnsIdle() bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for c := range s.activeConn {
+ st, ok := c.curState.Load().(ConnState)
+ if !ok || st != StateIdle {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/net/http/fcgi/fcgi.go b/libgo/go/net/http/fcgi/fcgi.go
index 06bba0488a..5057d70098 100644
--- a/libgo/go/net/http/fcgi/fcgi.go
+++ b/libgo/go/net/http/fcgi/fcgi.go
@@ -3,8 +3,12 @@
// license that can be found in the LICENSE file.
// Package fcgi implements the FastCGI protocol.
+//
+// The protocol is not an official standard and the original
+// documentation is no longer online. See the Internet Archive's
+// mirror at: https://web.archive.org/web/20150420080736/http://www.fastcgi.com/drupal/node/6?q=node/22
+//
// Currently only the responder role is supported.
-// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22
package fcgi
// This file defines the raw protocol and some utilities used by the child and
@@ -58,8 +62,6 @@ const (
statusUnknownRole
)
-const headerLen = 8
-
type header struct {
Version uint8
Type recType
@@ -158,11 +160,6 @@ func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
return err
}
-func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
- b := [8]byte{byte(role >> 8), byte(role), flags}
- return c.writeRecord(typeBeginRequest, reqId, b[:])
-}
-
func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
b := make([]byte, 8)
binary.BigEndian.PutUint32(b, uint32(appStatus))
diff --git a/libgo/go/net/http/filetransport.go b/libgo/go/net/http/filetransport.go
index 821787e0c4..32126d7ec0 100644
--- a/libgo/go/net/http/filetransport.go
+++ b/libgo/go/net/http/filetransport.go
@@ -33,7 +33,7 @@ func NewFileTransport(fs FileSystem) RoundTripper {
func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
// We start ServeHTTP in a goroutine, which may take a long
- // time if the file is large. The newPopulateResponseWriter
+ // time if the file is large. The newPopulateResponseWriter
// call returns a channel which either ServeHTTP or finish()
// sends our *Response on, once the *Response itself has been
// populated (even if the body itself is still being
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index f61c138c1d..bf63bb5441 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -34,7 +34,7 @@ import (
type Dir string
func (d Dir) Open(name string) (File, error) {
- if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
+ if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
@@ -77,7 +77,7 @@ func dirList(w ResponseWriter, f File) {
Error(w, "Error reading directory", StatusInternalServerError)
return
}
- sort.Sort(byName(dirs))
+ sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<pre>\n")
@@ -96,9 +96,10 @@ func dirList(w ResponseWriter, f File) {
}
// ServeContent replies to the request using the content in the
-// provided ReadSeeker. The main benefit of ServeContent over io.Copy
+// provided ReadSeeker. The main benefit of ServeContent over io.Copy
// is that it handles Range requests properly, sets the MIME type, and
-// handles If-Modified-Since requests.
+// handles If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since,
+// and If-Range requests.
//
// If the response's Content-Type header is not set, ServeContent
// first tries to deduce the type from name's file extension and,
@@ -108,24 +109,24 @@ func dirList(w ResponseWriter, f File) {
// never sent in the response.
//
// If modtime is not the zero time or Unix epoch, ServeContent
-// includes it in a Last-Modified header in the response. If the
+// includes it in a Last-Modified header in the response. If the
// request includes an If-Modified-Since header, ServeContent uses
// modtime to decide whether the content needs to be sent at all.
//
// The content's Seek method must work: ServeContent uses
// a seek to the end of the content to determine its size.
//
-// If the caller has set w's ETag header, ServeContent uses it to
-// handle requests using If-Range and If-None-Match.
+// If the caller has set w's ETag header formatted per RFC 7232, section 2.3,
+// ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range.
//
// Note that *os.File implements the io.ReadSeeker interface.
func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) {
sizeFunc := func() (int64, error) {
- size, err := content.Seek(0, os.SEEK_END)
+ size, err := content.Seek(0, io.SeekEnd)
if err != nil {
return 0, errSeeker
}
- _, err = content.Seek(0, os.SEEK_SET)
+ _, err = content.Seek(0, io.SeekStart)
if err != nil {
return 0, errSeeker
}
@@ -140,15 +141,17 @@ func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time
// users.
var errSeeker = errors.New("seeker can't seek")
+// errNoOverlap is returned by serveContent's parseRange if first-byte-pos of
+// all of the byte-range-spec values is greater than the content size.
+var errNoOverlap = errors.New("invalid range: failed to overlap")
+
// if name is empty, filename is unknown. (used for mime type, before sniffing)
// if modtime.IsZero(), modtime is unknown.
// content must be seeked to the beginning of the file.
// The sizeFunc is called at most once. Its error, if any, is sent in the HTTP response.
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) {
- if checkLastModified(w, r, modtime) {
- return
- }
- rangeReq, done := checkETag(w, r, modtime)
+ setLastModified(w, modtime)
+ done, rangeReq := checkPreconditions(w, r, modtime)
if done {
return
}
@@ -166,7 +169,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
var buf [sniffLen]byte
n, _ := io.ReadFull(content, buf[:])
ctype = DetectContentType(buf[:n])
- _, err := content.Seek(0, os.SEEK_SET) // rewind to output whole file
+ _, err := content.Seek(0, io.SeekStart) // rewind to output whole file
if err != nil {
Error(w, "seeker can't seek", StatusInternalServerError)
return
@@ -189,6 +192,9 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
if size >= 0 {
ranges, err := parseRange(rangeReq, size)
if err != nil {
+ if err == errNoOverlap {
+ w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
+ }
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
return
}
@@ -196,7 +202,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
// The total number of bytes in all the ranges
// is larger than the size of the file by
// itself, so this is probably an attack, or a
- // dumb client. Ignore the range request.
+ // dumb client. Ignore the range request.
ranges = nil
}
switch {
@@ -213,7 +219,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
// A response to a request for a single range MUST NOT
// be sent using the multipart/byteranges media type."
ra := ranges[0]
- if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil {
+ if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
return
}
@@ -236,7 +242,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
pw.CloseWithError(err)
return
}
- if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil {
+ if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
pw.CloseWithError(err)
return
}
@@ -263,90 +269,245 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
}
}
-var unixEpochTime = time.Unix(0, 0)
-
-// modtime is the modification time of the resource to be served, or IsZero().
-// return value is whether this request is now complete.
-func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
- if modtime.IsZero() || modtime.Equal(unixEpochTime) {
- // If the file doesn't have a modtime (IsZero), or the modtime
- // is obviously garbage (Unix time == 0), then ignore modtimes
- // and don't process the If-Modified-Since header.
- return false
+// scanETag determines if a syntactically valid ETag is present at s. If so,
+// the ETag and remaining text after consuming ETag is returned. Otherwise,
+// it returns "", "".
+func scanETag(s string) (etag string, remain string) {
+ s = textproto.TrimString(s)
+ start := 0
+ if strings.HasPrefix(s, "W/") {
+ start = 2
+ }
+ if len(s[start:]) < 2 || s[start] != '"' {
+ return "", ""
+ }
+ // ETag is either W/"text" or "text".
+ // See RFC 7232 2.3.
+ for i := start + 1; i < len(s); i++ {
+ c := s[i]
+ switch {
+ // Character values allowed in ETags.
+ case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80:
+ case c == '"':
+ return string(s[:i+1]), s[i+1:]
+ default:
+ break
+ }
}
+ return "", ""
+}
- // The Date-Modified header truncates sub-second precision, so
- // use mtime < t+1s instead of mtime <= t to check for unmodified.
- if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) {
- h := w.Header()
- delete(h, "Content-Type")
- delete(h, "Content-Length")
- w.WriteHeader(StatusNotModified)
- return true
- }
- w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
- return false
+// etagStrongMatch reports whether a and b match using strong ETag comparison.
+// Assumes a and b are valid ETags.
+func etagStrongMatch(a, b string) bool {
+ return a == b && a != "" && a[0] == '"'
}
-// checkETag implements If-None-Match and If-Range checks.
-//
-// The ETag or modtime must have been previously set in the
-// ResponseWriter's headers. The modtime is only compared at second
-// granularity and may be the zero value to mean unknown.
-//
-// The return value is the effective request "Range" header to use and
-// whether this request is now considered done.
-func checkETag(w ResponseWriter, r *Request, modtime time.Time) (rangeReq string, done bool) {
- etag := w.Header().get("Etag")
- rangeReq = r.Header.get("Range")
-
- // Invalidate the range request if the entity doesn't match the one
- // the client was expecting.
- // "If-Range: version" means "ignore the Range: header unless version matches the
- // current file."
- // We only support ETag versions.
- // The caller must have set the ETag on the response already.
- if ir := r.Header.get("If-Range"); ir != "" && ir != etag {
- // The If-Range value is typically the ETag value, but it may also be
- // the modtime date. See golang.org/issue/8367.
- timeMatches := false
- if !modtime.IsZero() {
- if t, err := ParseTime(ir); err == nil && t.Unix() == modtime.Unix() {
- timeMatches = true
- }
+// etagWeakMatch reports whether a and b match using weak ETag comparison.
+// Assumes a and b are valid ETags.
+func etagWeakMatch(a, b string) bool {
+ return strings.TrimPrefix(a, "W/") == strings.TrimPrefix(b, "W/")
+}
+
+// condResult is the result of an HTTP request precondition check.
+// See https://tools.ietf.org/html/rfc7232 section 3.
+type condResult int
+
+const (
+ condNone condResult = iota
+ condTrue
+ condFalse
+)
+
+func checkIfMatch(w ResponseWriter, r *Request) condResult {
+ im := r.Header.Get("If-Match")
+ if im == "" {
+ return condNone
+ }
+ for {
+ im = textproto.TrimString(im)
+ if len(im) == 0 {
+ break
+ }
+ if im[0] == ',' {
+ im = im[1:]
+ continue
+ }
+ if im[0] == '*' {
+ return condTrue
+ }
+ etag, remain := scanETag(im)
+ if etag == "" {
+ break
}
- if !timeMatches {
- rangeReq = ""
+ if etagStrongMatch(etag, w.Header().get("Etag")) {
+ return condTrue
}
+ im = remain
}
- if inm := r.Header.get("If-None-Match"); inm != "" {
- // Must know ETag.
+ return condFalse
+}
+
+func checkIfUnmodifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ ius := r.Header.Get("If-Unmodified-Since")
+ if ius == "" || isZeroTime(modtime) {
+ return condNone
+ }
+ if t, err := ParseTime(ius); err == nil {
+ // The Date-Modified header truncates sub-second precision, so
+ // use mtime < t+1s instead of mtime <= t to check for unmodified.
+ if modtime.Before(t.Add(1 * time.Second)) {
+ return condTrue
+ }
+ return condFalse
+ }
+ return condNone
+}
+
+func checkIfNoneMatch(w ResponseWriter, r *Request) condResult {
+ inm := r.Header.get("If-None-Match")
+ if inm == "" {
+ return condNone
+ }
+ buf := inm
+ for {
+ buf = textproto.TrimString(buf)
+ if len(buf) == 0 {
+ break
+ }
+ if buf[0] == ',' {
+ buf = buf[1:]
+ }
+ if buf[0] == '*' {
+ return condFalse
+ }
+ etag, remain := scanETag(buf)
if etag == "" {
- return rangeReq, false
+ break
+ }
+ if etagWeakMatch(etag, w.Header().get("Etag")) {
+ return condFalse
}
+ buf = remain
+ }
+ return condTrue
+}
- // TODO(bradfitz): non-GET/HEAD requests require more work:
- // sending a different status code on matches, and
- // also can't use weak cache validators (those with a "W/
- // prefix). But most users of ServeContent will be using
- // it on GET or HEAD, so only support those for now.
- if r.Method != "GET" && r.Method != "HEAD" {
- return rangeReq, false
+func checkIfModifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ if r.Method != "GET" && r.Method != "HEAD" {
+ return condNone
+ }
+ ims := r.Header.Get("If-Modified-Since")
+ if ims == "" || isZeroTime(modtime) {
+ return condNone
+ }
+ t, err := ParseTime(ims)
+ if err != nil {
+ return condNone
+ }
+ // The Date-Modified header truncates sub-second precision, so
+ // use mtime < t+1s instead of mtime <= t to check for unmodified.
+ if modtime.Before(t.Add(1 * time.Second)) {
+ return condFalse
+ }
+ return condTrue
+}
+
+func checkIfRange(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ if r.Method != "GET" {
+ return condNone
+ }
+ ir := r.Header.get("If-Range")
+ if ir == "" {
+ return condNone
+ }
+ etag, _ := scanETag(ir)
+ if etag != "" {
+ if etagStrongMatch(etag, w.Header().Get("Etag")) {
+ return condTrue
+ } else {
+ return condFalse
}
+ }
+ // The If-Range value is typically the ETag value, but it may also be
+ // the modtime date. See golang.org/issue/8367.
+ if modtime.IsZero() {
+ return condFalse
+ }
+ t, err := ParseTime(ir)
+ if err != nil {
+ return condFalse
+ }
+ if t.Unix() == modtime.Unix() {
+ return condTrue
+ }
+ return condFalse
+}
+
+var unixEpochTime = time.Unix(0, 0)
+
+// isZeroTime reports whether t is obviously unspecified (either zero or Unix()=0).
+func isZeroTime(t time.Time) bool {
+ return t.IsZero() || t.Equal(unixEpochTime)
+}
- // TODO(bradfitz): deal with comma-separated or multiple-valued
- // list of If-None-match values. For now just handle the common
- // case of a single item.
- if inm == etag || inm == "*" {
- h := w.Header()
- delete(h, "Content-Type")
- delete(h, "Content-Length")
- w.WriteHeader(StatusNotModified)
- return "", true
+func setLastModified(w ResponseWriter, modtime time.Time) {
+ if !isZeroTime(modtime) {
+ w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
+ }
+}
+
+func writeNotModified(w ResponseWriter) {
+ // RFC 7232 section 4.1:
+ // a sender SHOULD NOT generate representation metadata other than the
+ // above listed fields unless said metadata exists for the purpose of
+ // guiding cache updates (e.g., Last-Modified might be useful if the
+ // response does not have an ETag field).
+ h := w.Header()
+ delete(h, "Content-Type")
+ delete(h, "Content-Length")
+ if h.Get("Etag") != "" {
+ delete(h, "Last-Modified")
+ }
+ w.WriteHeader(StatusNotModified)
+}
+
+// checkPreconditions evaluates request preconditions and reports whether a precondition
+// resulted in sending StatusNotModified or StatusPreconditionFailed.
+func checkPreconditions(w ResponseWriter, r *Request, modtime time.Time) (done bool, rangeHeader string) {
+ // This function carefully follows RFC 7232 section 6.
+ ch := checkIfMatch(w, r)
+ if ch == condNone {
+ ch = checkIfUnmodifiedSince(w, r, modtime)
+ }
+ if ch == condFalse {
+ w.WriteHeader(StatusPreconditionFailed)
+ return true, ""
+ }
+ switch checkIfNoneMatch(w, r) {
+ case condFalse:
+ if r.Method == "GET" || r.Method == "HEAD" {
+ writeNotModified(w)
+ return true, ""
+ } else {
+ w.WriteHeader(StatusPreconditionFailed)
+ return true, ""
+ }
+ case condNone:
+ if checkIfModifiedSince(w, r, modtime) == condFalse {
+ writeNotModified(w)
+ return true, ""
+ }
+ }
+
+ rangeHeader = r.Header.get("Range")
+ if rangeHeader != "" {
+ if checkIfRange(w, r, modtime) == condFalse {
+ rangeHeader = ""
}
}
- return rangeReq, false
+ return false, rangeHeader
}
// name is '/'-separated, not filepath.Separator.
@@ -393,6 +554,15 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
}
}
+ // redirect if the directory name doesn't end in a slash
+ if d.IsDir() {
+ url := r.URL.Path
+ if url[len(url)-1] != '/' {
+ localRedirect(w, r, path.Base(url)+"/")
+ return
+ }
+ }
+
// use contents of index.html for directory, if present
if d.IsDir() {
index := strings.TrimSuffix(name, "/") + indexPage
@@ -410,9 +580,11 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
// Still a directory? (we didn't find an index.html file)
if d.IsDir() {
- if checkLastModified(w, r, d.ModTime()) {
+ if checkIfModifiedSince(w, r, d.ModTime()) == condFalse {
+ writeNotModified(w)
return
}
+ w.Header().Set("Last-Modified", d.ModTime().UTC().Format(TimeFormat))
dirList(w, f)
return
}
@@ -451,7 +623,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
// ServeFile replies to the request with the contents of the named
// file or directory.
//
-// If the provided file or direcory name is a relative path, it is
+// If the provided file or directory name is a relative path, it is
// interpreted relative to the current directory and may ascend to parent
// directories. If the provided name is constructed from user input, it
// should be sanitized before calling ServeFile. As a precaution, ServeFile
@@ -534,6 +706,7 @@ func (r httpRange) mimeHeader(contentType string, size int64) textproto.MIMEHead
}
// parseRange parses a Range header string as per RFC 2616.
+// errNoOverlap is returned if none of the ranges overlap.
func parseRange(s string, size int64) ([]httpRange, error) {
if s == "" {
return nil, nil // header not present
@@ -543,6 +716,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
return nil, errors.New("invalid range")
}
var ranges []httpRange
+ noOverlap := false
for _, ra := range strings.Split(s[len(b):], ",") {
ra = strings.TrimSpace(ra)
if ra == "" {
@@ -568,9 +742,15 @@ func parseRange(s string, size int64) ([]httpRange, error) {
r.length = size - r.start
} else {
i, err := strconv.ParseInt(start, 10, 64)
- if err != nil || i >= size || i < 0 {
+ if err != nil || i < 0 {
return nil, errors.New("invalid range")
}
+ if i >= size {
+ // If the range begins after the size of the content,
+ // then it does not overlap.
+ noOverlap = true
+ continue
+ }
r.start = i
if end == "" {
// If no end is specified, range extends to end of the file.
@@ -588,6 +768,10 @@ func parseRange(s string, size int64) ([]httpRange, error) {
}
ranges = append(ranges, r)
}
+ if noOverlap && len(ranges) == 0 {
+ // The specified ranges did not overlap with the content.
+ return nil, errNoOverlap
+ }
return ranges, nil
}
@@ -619,9 +803,3 @@ func sumRangesSize(ranges []httpRange) (size int64) {
}
return
}
-
-type byName []os.FileInfo
-
-func (s byName) Len() int { return len(s) }
-func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
-func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index cf5b63c9f7..bba5682115 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -24,7 +24,6 @@ import (
"reflect"
"regexp"
"runtime"
- "strconv"
"strings"
"testing"
"time"
@@ -39,8 +38,6 @@ type wantRange struct {
start, end int64 // range [start,end)
}
-var itoa = strconv.Itoa
-
var ServeFileRangeTests = []struct {
r string
code int
@@ -71,6 +68,7 @@ var ServeFileRangeTests = []struct {
}
func TestServeFile(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
@@ -277,6 +275,7 @@ func TestFileServerEscapesNames(t *testing.T) {
{`"'<>&`, `<a href="%22%27%3C%3E&">&#34;&#39;&lt;&gt;&amp;</a>`},
{`?foo=bar#baz`, `<a href="%3Ffoo=bar%23baz">?foo=bar#baz</a>`},
{`<combo>?foo`, `<a href="%3Ccombo%3E%3Ffoo">&lt;combo&gt;?foo</a>`},
+ {`foo:bar`, `<a href="./foo:bar">foo:bar</a>`},
}
// We put each test file in its own directory in the fakeFS so we can look at it in isolation.
@@ -508,6 +507,24 @@ func TestServeFileFromCWD(t *testing.T) {
}
}
+// Issue 13996
+func TestServeDirWithoutTrailingSlash(t *testing.T) {
+ e := "/testdata/"
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, ".")
+ }))
+ defer ts.Close()
+ r, err := Get(ts.URL + "/testdata")
+ if err != nil {
+ t.Fatal(err)
+ }
+ r.Body.Close()
+ if g := r.Request.URL.Path; g != e {
+ t.Errorf("got %s, want %s", g, e)
+ }
+}
+
// Tests that ServeFile doesn't add a Content-Length if a Content-Encoding is
// specified.
func TestServeFileWithContentEncoding_h1(t *testing.T) { testServeFileWithContentEncoding(t, h1Mode) }
@@ -750,6 +767,7 @@ func TestServeContent(t *testing.T) {
reqHeader map[string]string
wantLastMod string
wantContentType string
+ wantContentRange string
wantStatus int
}
htmlModTime := mustStat(t, "testdata/index.html").ModTime()
@@ -767,8 +785,9 @@ func TestServeContent(t *testing.T) {
wantStatus: 200,
},
"not_modified_modtime": {
- file: "testdata/style.css",
- modtime: htmlModTime,
+ file: "testdata/style.css",
+ serveETag: `"foo"`, // Last-Modified sent only when no ETag
+ modtime: htmlModTime,
reqHeader: map[string]string{
"If-Modified-Since": htmlModTime.UTC().Format(TimeFormat),
},
@@ -777,6 +796,7 @@ func TestServeContent(t *testing.T) {
"not_modified_modtime_with_contenttype": {
file: "testdata/style.css",
serveContentType: "text/css", // explicit content type
+ serveETag: `"foo"`, // Last-Modified sent only when no ETag
modtime: htmlModTime,
reqHeader: map[string]string{
"If-Modified-Since": htmlModTime.UTC().Format(TimeFormat),
@@ -793,21 +813,62 @@ func TestServeContent(t *testing.T) {
},
"not_modified_etag_no_seek": {
content: panicOnSeek{nil}, // should never be called
- serveETag: `"foo"`,
+ serveETag: `W/"foo"`, // If-None-Match uses weak ETag comparison
reqHeader: map[string]string{
- "If-None-Match": `"foo"`,
+ "If-None-Match": `"baz", W/"foo"`,
},
wantStatus: 304,
},
+ "if_none_match_mismatch": {
+ file: "testdata/style.css",
+ serveETag: `"foo"`,
+ reqHeader: map[string]string{
+ "If-None-Match": `"Foo"`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
"range_good": {
file: "testdata/style.css",
serveETag: `"A"`,
reqHeader: map[string]string{
"Range": "bytes=0-4",
},
- wantStatus: StatusPartialContent,
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ },
+ "range_match": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": `"A"`,
+ },
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ },
+ "range_match_weak_etag": {
+ file: "testdata/style.css",
+ serveETag: `W/"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": `W/"A"`,
+ },
+ wantStatus: 200,
wantContentType: "text/css; charset=utf-8",
},
+ "range_no_overlap": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=10-20",
+ },
+ wantStatus: StatusRequestedRangeNotSatisfiable,
+ wantContentType: "text/plain; charset=utf-8",
+ wantContentRange: "bytes */8",
+ },
// An If-Range resource for entity "A", but entity "B" is now current.
// The Range request should be ignored.
"range_no_match": {
@@ -827,9 +888,10 @@ func TestServeContent(t *testing.T) {
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
- wantStatus: StatusPartialContent,
- wantContentType: "text/css; charset=utf-8",
- wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
"range_with_modtime_nanos": {
file: "testdata/style.css",
@@ -838,9 +900,10 @@ func TestServeContent(t *testing.T) {
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
- wantStatus: StatusPartialContent,
- wantContentType: "text/css; charset=utf-8",
- wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
"unix_zero_modtime": {
content: strings.NewReader("<html>foo"),
@@ -848,6 +911,62 @@ func TestServeContent(t *testing.T) {
wantStatus: StatusOK,
wantContentType: "text/html; charset=utf-8",
},
+ "ifmatch_matches": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `"Z", "A"`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
+ "ifmatch_star": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `*`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
+ "ifmatch_failed": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `"B"`,
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ },
+ "ifmatch_fails_on_weak_etag": {
+ file: "testdata/style.css",
+ serveETag: `W/"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `W/"A"`,
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ },
+ "if_unmodified_since_true": {
+ file: "testdata/style.css",
+ modtime: htmlModTime,
+ reqHeader: map[string]string{
+ "If-Unmodified-Since": htmlModTime.UTC().Format(TimeFormat),
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ wantLastMod: htmlModTime.UTC().Format(TimeFormat),
+ },
+ "if_unmodified_since_false": {
+ file: "testdata/style.css",
+ modtime: htmlModTime,
+ reqHeader: map[string]string{
+ "If-Unmodified-Since": htmlModTime.Add(-2 * time.Second).UTC().Format(TimeFormat),
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ wantLastMod: htmlModTime.UTC().Format(TimeFormat),
+ },
}
for testName, tt := range tests {
var content io.ReadSeeker
@@ -888,6 +1007,9 @@ func TestServeContent(t *testing.T) {
if g, e := res.Header.Get("Content-Type"), tt.wantContentType; g != e {
t.Errorf("test %q: content-type = %q, want %q", testName, g, e)
}
+ if g, e := res.Header.Get("Content-Range"), tt.wantContentRange; g != e {
+ t.Errorf("test %q: content-range = %q, want %q", testName, g, e)
+ }
if g, e := res.Header.Get("Last-Modified"), tt.wantLastMod; g != e {
t.Errorf("test %q: last-modified = %q, want %q", testName, g, e)
}
@@ -943,6 +1065,7 @@ func TestServeContentErrorMessages(t *testing.T) {
// verifies that sendfile is being used on Linux
func TestLinuxSendfile(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
if runtime.GOOS != "linux" {
t.Skip("skipping; linux-only test")
@@ -963,10 +1086,12 @@ func TestLinuxSendfile(t *testing.T) {
syscalls := "sendfile,sendfile64"
switch runtime.GOARCH {
- case "mips64", "mips64le", "alpha":
- // mips64 strace doesn't support sendfile64 and will error out
- // if we specify that with `-e trace='.
+ case "mips64", "mips64le", "s390x", "alpha":
+ // strace on the above platforms doesn't support sendfile64
+ // and will error out if we specify that with `-e trace='.
syscalls = "sendfile"
+ case "mips64":
+ t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/33430")
}
var buf bytes.Buffer
@@ -993,10 +1118,9 @@ func TestLinuxSendfile(t *testing.T) {
Post(fmt.Sprintf("http://%s/quit", ln.Addr()), "", nil)
child.Wait()
- rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+\)\s*=\s*\d+\s*\n`)
- rxResume := regexp.MustCompile(`<\.\.\. sendfile(64)? resumed> \)\s*=\s*\d+\s*\n`)
+ rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+`)
out := buf.String()
- if !rx.MatchString(out) && !rxResume.MatchString(out) {
+ if !rx.MatchString(out) {
t.Errorf("no sendfile system call found in:\n%s", out)
}
}
@@ -1075,3 +1199,26 @@ func (d fileServerCleanPathDir) Open(path string) (File, error) {
}
type panicOnSeek struct{ io.ReadSeeker }
+
+func Test_scanETag(t *testing.T) {
+ tests := []struct {
+ in string
+ wantETag string
+ wantRemain string
+ }{
+ {`W/"etag-1"`, `W/"etag-1"`, ""},
+ {`"etag-2"`, `"etag-2"`, ""},
+ {`"etag-1", "etag-2"`, `"etag-1"`, `, "etag-2"`},
+ {"", "", ""},
+ {"", "", ""},
+ {"W/", "", ""},
+ {`W/"truc`, "", ""},
+ {`w/"case-sensitive"`, "", ""},
+ }
+ for _, test := range tests {
+ etag, remain := ExportScanETag(test.in)
+ if etag != test.wantETag || remain != test.wantRemain {
+ t.Errorf("scanETag(%q)=%q %q, want %q %q", test.in, etag, remain, test.wantETag, test.wantRemain)
+ }
+ }
+}
diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go
index 4e19b3e71f..25fdf09d92 100644
--- a/libgo/go/net/http/h2_bundle.go
+++ b/libgo/go/net/http/h2_bundle.go
@@ -1,5 +1,5 @@
// Code generated by golang.org/x/tools/cmd/bundle.
-//go:generate bundle -o h2_bundle.go -prefix http2 -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack golang.org/x/net/http2
+//go:generate bundle -o h2_bundle.go -prefix http2 -underscore golang.org/x/net/http2
// Package http2 implements the HTTP/2 protocol.
//
@@ -20,15 +20,18 @@ import (
"bufio"
"bytes"
"compress/gzip"
+ "context"
+ "crypto/rand"
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
- "internal/golang.org/x/net/http2/hpack"
"io"
"io/ioutil"
"log"
+ "math"
"net"
+ "net/http/httptrace"
"net/textproto"
"net/url"
"os"
@@ -39,6 +42,10 @@ import (
"strings"
"sync"
"time"
+
+ "golang_org/x/net/http2/hpack"
+ "golang_org/x/net/idna"
+ "golang_org/x/net/lex/httplex"
)
// ClientConnPool manages a pool of HTTP/2 client connections.
@@ -47,6 +54,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
@@ -69,7 +88,16 @@ const (
http2noDialOnMiss = false
)
-func (p *http2clientConnPool) getClientConn(_ *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+ if http2isConnectionCloseRequest(req) && dialOnMiss {
+ // It gets its own connection.
+ const singleUse = true
+ cc, err := p.t.dialClientConn(addr, singleUse)
+ if err != nil {
+ return nil, err
+ }
+ return cc, nil
+ }
p.mu.Lock()
for _, cc := range p.conns[addr] {
if cc.CanTakeNewRequest() {
@@ -112,7 +140,8 @@ func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall {
// run in its own goroutine.
func (c *http2dialCall) dial(addr string) {
- c.res, c.err = c.p.t.dialClientConn(addr)
+ const singleUse = false // shared conn
+ c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
close(c.done)
c.p.mu.Lock()
@@ -247,6 +276,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{
@@ -267,7 +305,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
}
upgradeFn := func(authority string, c *tls.Conn) RoundTripper {
- addr := http2authorityAddr(authority)
+ addr := http2authorityAddr("https", authority)
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
go c.Close()
return http2erringRoundTripper{err}
@@ -299,15 +337,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 }
@@ -377,9 +406,17 @@ func (e http2ConnectionError) Error() string {
type http2StreamError struct {
StreamID uint32
Code http2ErrCode
+ Cause error // optional additional detail
+}
+
+func http2streamError(id uint32, code http2ErrCode) http2StreamError {
+ return http2StreamError{StreamID: id, Code: code}
}
func (e http2StreamError) Error() string {
+ if e.Cause != nil {
+ return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
+ }
return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
}
@@ -403,6 +440,35 @@ func (e http2connError) Error() string {
return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
}
+type http2pseudoHeaderError string
+
+func (e http2pseudoHeaderError) Error() string {
+ return fmt.Sprintf("invalid pseudo-header %q", string(e))
+}
+
+type http2duplicatePseudoHeaderError string
+
+func (e http2duplicatePseudoHeaderError) Error() string {
+ return fmt.Sprintf("duplicate pseudo-header %q", string(e))
+}
+
+type http2headerFieldNameError string
+
+func (e http2headerFieldNameError) Error() string {
+ return fmt.Sprintf("invalid header field name %q", string(e))
+}
+
+type http2headerFieldValueError string
+
+func (e http2headerFieldValueError) Error() string {
+ return fmt.Sprintf("invalid header field value %q", string(e))
+}
+
+var (
+ http2errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
+ http2errPseudoAfterRegular = errors.New("pseudo header field after regular")
+)
+
// fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
// It never allocates, but moves old data as new data is written.
type http2fixedBuffer struct {
@@ -743,7 +809,7 @@ type http2Frame interface {
type http2Framer struct {
r io.Reader
lastFrame http2Frame
- errReason string
+ errDetail error
// lastHeaderStream is non-zero if the last frame was an
// unfinished HEADERS/CONTINUATION.
@@ -775,12 +841,33 @@ type http2Framer struct {
// to return non-compliant frames or frame orders.
// This is for testing and permits using the Framer to test
// other HTTP/2 implementations' conformance to the spec.
+ // It is not compatible with ReadMetaHeaders.
AllowIllegalReads bool
- logReads bool
+ // ReadMetaHeaders if non-nil causes ReadFrame to merge
+ // HEADERS and CONTINUATION frames together and return
+ // MetaHeadersFrame instead.
+ ReadMetaHeaders *hpack.Decoder
- debugFramer *http2Framer // only use for logging written writes
- debugFramerBuf *bytes.Buffer
+ // MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
+ // It's used only if ReadMetaHeaders is set; 0 means a sane default
+ // (currently 16MB)
+ // If the limit is hit, MetaHeadersFrame.Truncated is set true.
+ MaxHeaderListSize uint32
+
+ logReads, logWrites bool
+
+ debugFramer *http2Framer // only use for logging written writes
+ debugFramerBuf *bytes.Buffer
+ debugReadLoggerf func(string, ...interface{})
+ debugWriteLoggerf func(string, ...interface{})
+}
+
+func (fr *http2Framer) maxHeaderListSize() uint32 {
+ if fr.MaxHeaderListSize == 0 {
+ return 16 << 20
+ }
+ return fr.MaxHeaderListSize
}
func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) {
@@ -807,7 +894,7 @@ func (f *http2Framer) endWrite() error {
byte(length>>16),
byte(length>>8),
byte(length))
- if http2logFrameWrites {
+ if f.logWrites {
f.logWrite()
}
@@ -829,10 +916,10 @@ func (f *http2Framer) logWrite() {
f.debugFramerBuf.Write(f.wbuf)
fr, err := f.debugFramer.ReadFrame()
if err != nil {
- log.Printf("http2: Framer %p: failed to decode just-written frame", f)
+ f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
return
}
- log.Printf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
+ f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
}
func (f *http2Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
@@ -853,9 +940,12 @@ const (
// NewFramer returns a Framer that writes frames to w and reads them from r.
func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
fr := &http2Framer{
- w: w,
- r: r,
- logReads: http2logFrameReads,
+ w: w,
+ r: r,
+ logReads: http2logFrameReads,
+ logWrites: http2logFrameWrites,
+ debugReadLoggerf: log.Printf,
+ debugWriteLoggerf: log.Printf,
}
fr.getReadBuf = func(size uint32) []byte {
if cap(fr.readBuf) >= int(size) {
@@ -879,6 +969,17 @@ func (fr *http2Framer) SetMaxReadFrameSize(v uint32) {
fr.maxReadSize = v
}
+// ErrorDetail returns a more detailed error of the last error
+// returned by Framer.ReadFrame. For instance, if ReadFrame
+// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
+// will say exactly what was invalid. ErrorDetail is not guaranteed
+// to return a non-nil value and like the rest of the http2 package,
+// its return value is not protected by an API compatibility promise.
+// ErrorDetail is reset after the next call to ReadFrame.
+func (fr *http2Framer) ErrorDetail() error {
+ return fr.errDetail
+}
+
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
// sends a frame that is larger than declared with SetMaxReadFrameSize.
var http2ErrFrameTooLarge = errors.New("http2: frame too large")
@@ -897,9 +998,10 @@ func http2terminalReadFrameError(err error) bool {
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// returned error is ErrFrameTooLarge. Other errors may be of type
-// ConnectionError, StreamError, or anything else from from the underlying
+// ConnectionError, StreamError, or anything else from the underlying
// reader.
func (fr *http2Framer) ReadFrame() (http2Frame, error) {
+ fr.errDetail = nil
if fr.lastFrame != nil {
fr.lastFrame.invalidate()
}
@@ -925,7 +1027,10 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
return nil, err
}
if fr.logReads {
- log.Printf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
+ fr.debugReadLoggerf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
+ }
+ if fh.Type == http2FrameHeaders && fr.ReadMetaHeaders != nil {
+ return fr.readMetaFrame(f.(*http2HeadersFrame))
}
return f, nil
}
@@ -935,7 +1040,7 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
// to the peer before hanging up on them. This might help others debug
// their implementations.
func (fr *http2Framer) connError(code http2ErrCode, reason string) error {
- fr.errReason = reason
+ fr.errDetail = errors.New(reason)
return http2ConnectionError(code)
}
@@ -1023,7 +1128,15 @@ 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")
+ http2errPadLength = errors.New("pad length too large")
+)
+
+func http2validStreamIDOrZero(streamID uint32) bool {
+ return streamID&(1<<31) == 0
+}
func http2validStreamID(streamID uint32) bool {
return streamID != 0 && streamID&(1<<31) == 0
@@ -1032,18 +1145,40 @@ func http2validStreamID(streamID uint32) bool {
// WriteData writes a DATA frame.
//
// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
+ return f.WriteDataPadded(streamID, endStream, data, nil)
+}
+// WriteData writes a DATA frame with optional padding.
+//
+// If pad is nil, the padding bit is not sent.
+// The length of pad must not exceed 255 bytes.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
+func (f *http2Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
return http2errStreamID
}
+ if len(pad) > 255 {
+ return http2errPadLength
+ }
var flags http2Flags
if endStream {
flags |= http2FlagDataEndStream
}
+ if pad != nil {
+ flags |= http2FlagDataPadded
+ }
f.startWrite(http2FrameData, flags, streamID)
+ if pad != nil {
+ f.wbuf = append(f.wbuf, byte(len(pad)))
+ }
f.wbuf = append(f.wbuf, data...)
+ f.wbuf = append(f.wbuf, pad...)
return f.endWrite()
}
@@ -1126,7 +1261,7 @@ func (f *http2Framer) WriteSettings(settings ...http2Setting) error {
return f.endWrite()
}
-// WriteSettings writes an empty SETTINGS frame with the ACK bit set.
+// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
@@ -1247,7 +1382,7 @@ func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, err
if fh.StreamID == 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
- return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+ return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
}
return &http2WindowUpdateFrame{
http2FrameHeader: fh,
@@ -1325,7 +1460,7 @@ func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err er
}
}
if len(p)-int(padLength) <= 0 {
- return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+ return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
}
hf.headerFragBuf = p[:len(p)-int(padLength)]
return hf, nil
@@ -1389,8 +1524,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
@@ -1458,6 +1593,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 {
@@ -1669,6 +1807,202 @@ type http2headersEnder interface {
HeadersEnded() bool
}
+type http2headersOrContinuation interface {
+ http2headersEnder
+ HeaderBlockFragment() []byte
+}
+
+// A MetaHeadersFrame is the representation of one HEADERS frame and
+// zero or more contiguous CONTINUATION frames and the decoding of
+// their HPACK-encoded contents.
+//
+// This type of frame does not appear on the wire and is only returned
+// by the Framer when Framer.ReadMetaHeaders is set.
+type http2MetaHeadersFrame struct {
+ *http2HeadersFrame
+
+ // Fields are the fields contained in the HEADERS and
+ // CONTINUATION frames. The underlying slice is owned by the
+ // Framer and must not be retained after the next call to
+ // ReadFrame.
+ //
+ // Fields are guaranteed to be in the correct http2 order and
+ // not have unknown pseudo header fields or invalid header
+ // field names or values. Required pseudo header fields may be
+ // missing, however. Use the MetaHeadersFrame.Pseudo accessor
+ // method access pseudo headers.
+ Fields []hpack.HeaderField
+
+ // Truncated is whether the max header list size limit was hit
+ // and Fields is incomplete. The hpack decoder state is still
+ // valid, however.
+ Truncated bool
+}
+
+// PseudoValue returns the given pseudo header field's value.
+// The provided pseudo field should not contain the leading colon.
+func (mh *http2MetaHeadersFrame) PseudoValue(pseudo string) string {
+ for _, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return ""
+ }
+ if hf.Name[1:] == pseudo {
+ return hf.Value
+ }
+ }
+ return ""
+}
+
+// RegularFields returns the regular (non-pseudo) header fields of mh.
+// The caller does not own the returned slice.
+func (mh *http2MetaHeadersFrame) RegularFields() []hpack.HeaderField {
+ for i, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return mh.Fields[i:]
+ }
+ }
+ return nil
+}
+
+// PseudoFields returns the pseudo header fields of mh.
+// The caller does not own the returned slice.
+func (mh *http2MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
+ for i, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return mh.Fields[:i]
+ }
+ }
+ return mh.Fields
+}
+
+func (mh *http2MetaHeadersFrame) checkPseudos() error {
+ var isRequest, isResponse bool
+ pf := mh.PseudoFields()
+ for i, hf := range pf {
+ switch hf.Name {
+ case ":method", ":path", ":scheme", ":authority":
+ isRequest = true
+ case ":status":
+ isResponse = true
+ default:
+ return http2pseudoHeaderError(hf.Name)
+ }
+
+ for _, hf2 := range pf[:i] {
+ if hf.Name == hf2.Name {
+ return http2duplicatePseudoHeaderError(hf.Name)
+ }
+ }
+ }
+ if isRequest && isResponse {
+ return http2errMixPseudoHeaderTypes
+ }
+ return nil
+}
+
+func (fr *http2Framer) maxHeaderStringLen() int {
+ v := fr.maxHeaderListSize()
+ if uint32(int(v)) == v {
+ return int(v)
+ }
+
+ return 0
+}
+
+// readMetaFrame returns 0 or more CONTINUATION frames from fr and
+// merge them into into the provided hf and returns a MetaHeadersFrame
+// with the decoded hpack values.
+func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFrame, error) {
+ if fr.AllowIllegalReads {
+ return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
+ }
+ mh := &http2MetaHeadersFrame{
+ http2HeadersFrame: hf,
+ }
+ var remainSize = fr.maxHeaderListSize()
+ var sawRegular bool
+
+ var invalid error // pseudo header field errors
+ hdec := fr.ReadMetaHeaders
+ hdec.SetEmitEnabled(true)
+ hdec.SetMaxStringLength(fr.maxHeaderStringLen())
+ hdec.SetEmitFunc(func(hf hpack.HeaderField) {
+ if http2VerboseLogs && fr.logReads {
+ fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
+ }
+ if !httplex.ValidHeaderFieldValue(hf.Value) {
+ invalid = http2headerFieldValueError(hf.Value)
+ }
+ isPseudo := strings.HasPrefix(hf.Name, ":")
+ if isPseudo {
+ if sawRegular {
+ invalid = http2errPseudoAfterRegular
+ }
+ } else {
+ sawRegular = true
+ if !http2validWireHeaderFieldName(hf.Name) {
+ invalid = http2headerFieldNameError(hf.Name)
+ }
+ }
+
+ if invalid != nil {
+ hdec.SetEmitEnabled(false)
+ return
+ }
+
+ size := hf.Size()
+ if size > remainSize {
+ hdec.SetEmitEnabled(false)
+ mh.Truncated = true
+ return
+ }
+ remainSize -= size
+
+ mh.Fields = append(mh.Fields, hf)
+ })
+
+ defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
+
+ var hc http2headersOrContinuation = hf
+ for {
+ frag := hc.HeaderBlockFragment()
+ if _, err := hdec.Write(frag); err != nil {
+ return nil, http2ConnectionError(http2ErrCodeCompression)
+ }
+
+ if hc.HeadersEnded() {
+ break
+ }
+ if f, err := fr.ReadFrame(); err != nil {
+ return nil, err
+ } else {
+ hc = f.(*http2ContinuationFrame)
+ }
+ }
+
+ mh.http2HeadersFrame.headerFragBuf = nil
+ mh.http2HeadersFrame.invalidate()
+
+ if err := hdec.Close(); err != nil {
+ return nil, http2ConnectionError(http2ErrCodeCompression)
+ }
+ if invalid != nil {
+ fr.errDetail = invalid
+ if http2VerboseLogs {
+ log.Printf("http2: invalid header: %v", invalid)
+ }
+ return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, invalid}
+ }
+ if err := mh.checkPseudos(); err != nil {
+ fr.errDetail = err
+ if http2VerboseLogs {
+ log.Printf("http2: invalid pseudo headers: %v", err)
+ }
+ return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, err}
+ }
+ return mh, nil
+}
+
func http2summarizeFrame(f http2Frame) string {
var buf bytes.Buffer
f.Header().writeDebug(&buf)
@@ -1712,7 +2046,160 @@ 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
+}
+
+// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
+func http2isBadCipher(cipher uint16) bool {
+ switch cipher {
+ case tls.TLS_RSA_WITH_RC4_128_SHA,
+ tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+
+ return true
+ default:
+ return false
+ }
+}
+
+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 (t *http2Transport) idleConnTimeout() time.Duration {
+ if t.t1 != nil {
+ return t.t1.IdleConnTimeout
+ }
+ return 0
+}
+
+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)
+}
+
+// Ping sends a PING frame to the server and waits for the ack.
+func (cc *http2ClientConn) Ping(ctx context.Context) error {
+ return cc.ping(ctx)
+}
+
+func http2cloneTLSConfig(c *tls.Config) *tls.Config { return c.Clone() }
+
+var _ Pusher = (*http2responseWriter)(nil)
+
+// Push implements http.Pusher.
+func (w *http2responseWriter) Push(target string, opts *PushOptions) error {
+ internalOpts := http2pushOptions{}
+ if opts != nil {
+ internalOpts.Method = opts.Method
+ internalOpts.Header = opts.Header
+ }
+ return w.push(target, internalOpts)
+}
+
+func http2configureServer18(h1 *Server, h2 *http2Server) error {
+ if h2.IdleTimeout == 0 {
+ if h1.IdleTimeout != 0 {
+ h2.IdleTimeout = h1.IdleTimeout
+ } else {
+ h2.IdleTimeout = h1.ReadTimeout
+ }
+ }
+ return nil
+}
+
+func http2shouldLogPanic(panicValue interface{}) bool {
+ return panicValue != nil && panicValue != ErrAbortHandler
+}
+
+func http2reqGetBody(req *Request) func() (io.ReadCloser, error) {
+ return req.GetBody
+}
+
+func http2reqBodyIsNoBody(body io.ReadCloser) bool {
+ return body == NoBody
+}
var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
@@ -1937,6 +2424,7 @@ var (
http2VerboseLogs bool
http2logFrameWrites bool
http2logFrameReads bool
+ http2inTests bool
)
func init() {
@@ -1978,13 +2466,23 @@ var (
type http2streamState int
+// HTTP/2 stream states.
+//
+// See http://tools.ietf.org/html/rfc7540#section-5.1.
+//
+// For simplicity, the server code merges "reserved (local)" into
+// "half-closed (remote)". This is one less state transition to track.
+// The only downside is that we send PUSH_PROMISEs slightly less
+// liberally than allowable. More discussion here:
+// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
+//
+// "reserved (remote)" is omitted since the client code does not
+// support server push.
const (
http2stateIdle http2streamState = iota
http2stateOpen
http2stateHalfClosedLocal
http2stateHalfClosedRemote
- http2stateResvLocal
- http2stateResvRemote
http2stateClosed
)
@@ -1993,8 +2491,6 @@ var http2stateName = [...]string{
http2stateOpen: "Open",
http2stateHalfClosedLocal: "HalfClosedLocal",
http2stateHalfClosedRemote: "HalfClosedRemote",
- http2stateResvLocal: "ResvLocal",
- http2stateResvRemote: "ResvRemote",
http2stateClosed: "Closed",
}
@@ -2070,57 +2566,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
-// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
-// "^" / "_" / "
+// validWireHeaderFieldName reports whether v is a valid header field
+// name (key). See httplex.ValidHeaderName for the base rules.
+//
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to
// lowercase prior to their encoding in HTTP/2. "
-func http2validHeaderFieldName(v string) bool {
+func http2validWireHeaderFieldName(v string) bool {
if len(v) == 0 {
return false
}
for _, r := range v {
- if int(r) >= len(http2isTokenTable) || ('A' <= r && r <= 'Z') {
+ if !httplex.IsTokenRune(r) {
return false
}
- if !http2isTokenTable[byte(r)] {
- return false
- }
- }
- return true
-}
-
-// validHeaderFieldValue reports whether v is a valid header field value.
-//
-// RFC 7230 says:
-// field-value = *( field-content / obs-fold )
-// obj-fold = N/A to http2, and deprecated
-// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
-// field-vchar = VCHAR / obs-text
-// obs-text = %x80-FF
-// VCHAR = "any visible [USASCII] character"
-//
-// http2 further says: "Similarly, HTTP/2 allows header field values
-// that are not valid. While most of the values that can be encoded
-// will not alter header field parsing, carriage return (CR, ASCII
-// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
-// 0x0) might be exploited by an attacker if they are translated
-// verbatim. Any request or response that contains a character not
-// permitted in a header field value MUST be treated as malformed
-// (Section 8.1.2.6). Valid characters are defined by the
-// field-content ABNF rule in Section 3.2 of [RFC7230]."
-//
-// This function does not (yet?) properly handle the rejection of
-// strings that begin or end with SP or HTAB.
-func http2validHeaderFieldValue(v string) bool {
- for i := 0; i < len(v); i++ {
- if b := v[i]; b < ' ' && b != '\t' || b == 0x7f {
+ if 'A' <= r && r <= 'Z' {
return false
}
}
@@ -2189,13 +2651,27 @@ func http2newBufferedWriter(w io.Writer) *http2bufferedWriter {
return &http2bufferedWriter{w: w}
}
+// bufWriterPoolBufferSize is the size of bufio.Writer's
+// buffers created using bufWriterPool.
+//
+// TODO: pick a less arbitrary value? this is a bit under
+// (3 x typical 1500 byte MTU) at least. Other than that,
+// not much thought went into it.
+const http2bufWriterPoolBufferSize = 4 << 10
+
var http2bufWriterPool = sync.Pool{
New: func() interface{} {
-
- return bufio.NewWriterSize(nil, 4<<10)
+ return bufio.NewWriterSize(nil, http2bufWriterPoolBufferSize)
},
}
+func (w *http2bufferedWriter) Available() int {
+ if w.bw == nil {
+ return http2bufWriterPoolBufferSize
+ }
+ return w.bw.Available()
+}
+
func (w *http2bufferedWriter) Write(p []byte) (n int, err error) {
if w.bw == nil {
bw := http2bufWriterPool.Get().(*bufio.Writer)
@@ -2225,7 +2701,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:
@@ -2251,90 +2727,57 @@ 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
}
+var http2sorterPool = sync.Pool{New: func() interface{} { return new(http2sorter) }}
+
+type http2sorter struct {
+ v []string // owned by sorter
+}
+
+func (s *http2sorter) Len() int { return len(s.v) }
+
+func (s *http2sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
+
+func (s *http2sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
+
+// Keys returns the sorted keys of h.
+//
+// The returned slice is only valid until s used again or returned to
+// its pool.
+func (s *http2sorter) Keys(h Header) []string {
+ keys := s.v[:0]
+ for k := range h {
+ keys = append(keys, k)
+ }
+ s.v = keys
+ sort.Sort(s)
+ return keys
+}
+
+func (s *http2sorter) SortStrings(ss []string) {
+
+ save := s.v
+ s.v = ss
+ sort.Sort(s)
+ s.v = save
+}
+
+// validPseudoPath reports whether v is a valid :path pseudo-header
+// value. It must be either:
+//
+// *) a non-empty string starting with '/', but not with with "//",
+// *) the string '*', for OPTIONS requests.
+//
+// For now this is only used a quick check for deciding when to clean
+// up Opaque URLs before sending requests from the Transport.
+// See golang.org/issue/16847
+func http2validPseudoPath(v string) bool {
+ return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*"
+}
+
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered)
@@ -2354,6 +2797,12 @@ type http2pipeBuffer interface {
io.Reader
}
+func (p *http2pipe) Len() int {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ return p.b.Len()
+}
+
// Read waits until data is available and copies bytes
// from the buffer into p.
func (p *http2pipe) Read(d []byte) (n int, err error) {
@@ -2525,6 +2974,15 @@ type http2Server struct {
// PermitProhibitedCipherSuites, if true, permits the use of
// cipher suites prohibited by the HTTP/2 spec.
PermitProhibitedCipherSuites bool
+
+ // IdleTimeout specifies how long until idle clients should be
+ // closed with a GOAWAY frame. PING frames are not considered
+ // activity for the purposes of IdleTimeout.
+ IdleTimeout time.Duration
+
+ // NewWriteScheduler constructs a write scheduler for a connection.
+ // If nil, a default scheduler is chosen.
+ NewWriteScheduler func() http2WriteScheduler
}
func (s *http2Server) maxReadFrameSize() uint32 {
@@ -2547,9 +3005,15 @@ func (s *http2Server) maxConcurrentStreams() uint32 {
//
// ConfigureServer must be called before s begins serving.
func http2ConfigureServer(s *Server, conf *http2Server) error {
+ if s == nil {
+ panic("nil *http.Server")
+ }
if conf == nil {
conf = new(http2Server)
}
+ if err := http2configureServer18(s, conf); err != nil {
+ return err
+ }
if s.TLSConfig == nil {
s.TLSConfig = new(tls.Config)
@@ -2588,8 +3052,6 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS)
}
- s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2-14")
-
if s.TLSNextProto == nil {
s.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
}
@@ -2603,7 +3065,6 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
})
}
s.TLSNextProto[http2NextProtoTLS] = protoHandler
- s.TLSNextProto["h2-14"] = protoHandler
return nil
}
@@ -2653,35 +3114,50 @@ 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,
- remoteAddrStr: c.RemoteAddr().String(),
- bw: http2newBufferedWriter(c),
- handler: opts.handler(),
- streams: make(map[uint32]*http2stream),
- readFrameCh: make(chan http2readFrameResult),
- wantWriteFrameCh: make(chan http2frameWriteMsg, 8),
- wroteFrameCh: make(chan http2frameWriteResult, 1),
- bodyReadCh: make(chan http2bodyReadMsg),
- doneServing: make(chan struct{}),
- advMaxStreams: s.maxConcurrentStreams(),
- writeSched: http2writeScheduler{
- maxFrameSize: http2initialMaxFrameSize,
- },
+ srv: s,
+ hs: opts.baseConfig(),
+ conn: c,
+ baseCtx: baseCtx,
+ remoteAddrStr: c.RemoteAddr().String(),
+ bw: http2newBufferedWriter(c),
+ handler: opts.handler(),
+ streams: make(map[uint32]*http2stream),
+ readFrameCh: make(chan http2readFrameResult),
+ wantWriteFrameCh: make(chan http2FrameWriteRequest, 8),
+ wantStartPushCh: make(chan http2startPushRequest, 8),
+ wroteFrameCh: make(chan http2frameWriteResult, 1),
+ bodyReadCh: make(chan http2bodyReadMsg),
+ doneServing: make(chan struct{}),
+ clientMaxStreams: math.MaxUint32,
+ advMaxStreams: s.maxConcurrentStreams(),
initialWindowSize: http2initialWindowSize,
+ maxFrameSize: http2initialMaxFrameSize,
headerTableSize: http2initialHeaderTableSize,
serveG: http2newGoroutineLock(),
pushEnabled: true,
}
+
+ if sc.hs.WriteTimeout != 0 {
+ sc.conn.SetWriteDeadline(time.Time{})
+ }
+
+ if s.NewWriteScheduler != nil {
+ sc.writeSched = s.NewWriteScheduler()
+ } else {
+ sc.writeSched = http2NewRandomWriteScheduler()
+ }
+
sc.flow.add(http2initialWindowSize)
sc.inflow.add(http2initialWindowSize)
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
- sc.hpackDecoder = hpack.NewDecoder(http2initialHeaderTableSize, nil)
- sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
fr := http2NewFramer(sc.bw, c)
+ fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
+ fr.MaxHeaderListSize = sc.maxHeaderListSize()
fr.SetMaxReadFrameSize(s.maxReadFrameSize())
sc.framer = fr
@@ -2711,27 +3187,6 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
sc.serve()
}
-// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
-func http2isBadCipher(cipher uint16) bool {
- switch cipher {
- case tls.TLS_RSA_WITH_RC4_128_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-
- return true
- default:
- return false
- }
-}
-
func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
@@ -2747,18 +3202,20 @@ type http2serverConn struct {
conn net.Conn
bw *http2bufferedWriter // writing to conn
handler Handler
+ baseCtx http2contextContext
framer *http2Framer
- hpackDecoder *hpack.Decoder
- doneServing chan struct{} // closed when serverConn.serve ends
- readFrameCh chan http2readFrameResult // written by serverConn.readFrames
- wantWriteFrameCh chan http2frameWriteMsg // from handlers -> serve
- wroteFrameCh chan http2frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
- bodyReadCh chan http2bodyReadMsg // from handlers -> serve
- testHookCh chan func(int) // code to run on the serve loop
- flow http2flow // conn-wide (not stream-specific) outbound flow control
- inflow http2flow // conn-wide inbound flow control
- tlsState *tls.ConnectionState // shared by all handlers, like net/http
+ doneServing chan struct{} // closed when serverConn.serve ends
+ readFrameCh chan http2readFrameResult // written by serverConn.readFrames
+ wantWriteFrameCh chan http2FrameWriteRequest // from handlers -> serve
+ wantStartPushCh chan http2startPushRequest // from handlers -> serve
+ wroteFrameCh chan http2frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
+ bodyReadCh chan http2bodyReadMsg // from handlers -> serve
+ testHookCh chan func(int) // code to run on the serve loop
+ flow http2flow // conn-wide (not stream-specific) outbound flow control
+ inflow http2flow // conn-wide inbound flow control
+ tlsState *tls.ConnectionState // shared by all handlers, like net/http
remoteAddrStr string
+ writeSched http2WriteScheduler
// Everything following is owned by the serve loop; use serveG.check():
serveG http2goroutineLock // used to verify funcs are on serve()
@@ -2768,37 +3225,33 @@ type http2serverConn struct {
unackedSettings int // how many SETTINGS have we sent without ACKs?
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
- curOpenStreams uint32 // client's number of open streams
- maxStreamID uint32 // max ever seen
+ curClientStreams uint32 // number of open streams initiated by the client
+ curPushedStreams uint32 // number of open streams initiated by server push
+ maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
+ maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
streams map[uint32]*http2stream
initialWindowSize int32
+ maxFrameSize int32
headerTableSize uint32
peerMaxHeaderListSize uint32 // zero means unknown (default)
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
- req http2requestParam // non-zero while reading request headers
- writingFrame bool // started write goroutine but haven't heard back on wroteFrameCh
+ writingFrame bool // started writing a frame (on serve goroutine or separate)
+ writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
needsFrameFlush bool // last frame write wasn't a flush
- writeSched http2writeScheduler
- inGoAway bool // we've started to or sent GOAWAY
- needToSendGoAway bool // we need to schedule a GOAWAY frame write
+ inGoAway bool // we've started to or sent GOAWAY
+ inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
+ needToSendGoAway bool // we need to schedule a GOAWAY frame write
goAwayCode http2ErrCode
shutdownTimerCh <-chan time.Time // nil until used
shutdownTimer *time.Timer // nil until used
+ idleTimer *time.Timer // nil if unused
+ idleTimerCh <-chan time.Time // nil if unused
// Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes.Buffer
hpackEncoder *hpack.Encoder
}
-func (sc *http2serverConn) maxHeaderStringLen() int {
- v := sc.maxHeaderListSize()
- if uint32(int(v)) == v {
- return int(v)
- }
-
- return 0
-}
-
func (sc *http2serverConn) maxHeaderListSize() uint32 {
n := sc.hs.MaxHeaderBytes
if n <= 0 {
@@ -2811,19 +3264,9 @@ func (sc *http2serverConn) maxHeaderListSize() uint32 {
return uint32(n + typicalHeaders*perFieldOverhead)
}
-// requestParam is the state of the next request, initialized over
-// potentially several frames HEADERS + zero or more CONTINUATION
-// frames.
-type http2requestParam struct {
- // stream is non-nil if we're reading (HEADER or CONTINUATION)
- // frames for a request (but not DATA).
- stream *http2stream
- header Header
- method, path string
- scheme, authority string
- sawRegularHeader bool // saw a non-pseudo header already
- invalidHeader bool // an invalid header was seen
- headerListSize int64 // actually uint32, but easier math this way
+func (sc *http2serverConn) curOpenStreams() uint32 {
+ sc.serveG.check()
+ return sc.curClientStreams + sc.curPushedStreams
}
// stream represents a stream. This is the minimal metadata needed by
@@ -2835,10 +3278,12 @@ type http2requestParam struct {
// 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
@@ -2849,9 +3294,10 @@ type http2stream struct {
numTrailerValues int64
weight uint8
state http2streamState
- 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
+ resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
+ gotTrailerHeader bool // HEADER frame for trailers was seen
+ wroteHeaders bool // whether we wrote headers (not status 100)
+ reqBuf []byte // if non-nil, body pipe buffer to return later at EOF
trailer Header // accumulated trailers
reqTrailer Header // handler's Request.Trailer
@@ -2874,8 +3320,14 @@ func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2strea
return st.state, st
}
- if streamID <= sc.maxStreamID {
- return http2stateClosed, nil
+ if streamID%2 == 1 {
+ if streamID <= sc.maxClientStreamID {
+ return http2stateClosed, nil
+ }
+ } else {
+ if streamID <= sc.maxPushPromiseID {
+ return http2stateClosed, nil
+ }
}
return http2stateIdle, nil
}
@@ -2952,83 +3404,6 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{
}
}
-func (sc *http2serverConn) onNewHeaderField(f hpack.HeaderField) {
- sc.serveG.check()
- if http2VerboseLogs {
- sc.vlogf("http2: server decoded %v", f)
- }
- switch {
- case !http2validHeaderFieldValue(f.Value):
- sc.req.invalidHeader = true
- case strings.HasPrefix(f.Name, ":"):
- if sc.req.sawRegularHeader {
- sc.logf("pseudo-header after regular header")
- sc.req.invalidHeader = true
- return
- }
- var dst *string
- switch f.Name {
- case ":method":
- dst = &sc.req.method
- case ":path":
- dst = &sc.req.path
- case ":scheme":
- dst = &sc.req.scheme
- case ":authority":
- dst = &sc.req.authority
- default:
-
- sc.logf("invalid pseudo-header %q", f.Name)
- sc.req.invalidHeader = true
- return
- }
- if *dst != "" {
- sc.logf("duplicate pseudo-header %q sent", f.Name)
- sc.req.invalidHeader = true
- return
- }
- *dst = f.Value
- case !http2validHeaderFieldName(f.Name):
- sc.req.invalidHeader = true
- default:
- sc.req.sawRegularHeader = true
- sc.req.header.Add(sc.canonicalHeader(f.Name), f.Value)
- const headerFieldOverhead = 32 // per spec
- sc.req.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
- if sc.req.headerListSize > int64(sc.maxHeaderListSize()) {
- sc.hpackDecoder.SetEmitEnabled(false)
- }
- }
-}
-
-func (st *http2stream) onNewTrailerField(f hpack.HeaderField) {
- sc := st.sc
- sc.serveG.check()
- if http2VerboseLogs {
- sc.vlogf("http2: server decoded trailer %v", f)
- }
- switch {
- case strings.HasPrefix(f.Name, ":"):
- sc.req.invalidHeader = true
- return
- case !http2validHeaderFieldName(f.Name) || !http2validHeaderFieldValue(f.Value):
- sc.req.invalidHeader = true
- return
- default:
- key := sc.canonicalHeader(f.Name)
- if st.trailer != nil {
- vv := append(st.trailer[key], f.Value)
- st.trailer[key] = vv
-
- // arbitrary; TODO: read spec about header list size limits wrt trailers
- const tooBig = 1000
- if len(vv) >= tooBig {
- sc.hpackDecoder.SetEmitEnabled(false)
- }
- }
- }
-}
-
func (sc *http2serverConn) canonicalHeader(v string) string {
sc.serveG.check()
cv, ok := http2commonCanonHeader[v]
@@ -3063,10 +3438,11 @@ type http2readFrameResult struct {
// It's run on its own goroutine.
func (sc *http2serverConn) readFrames() {
gate := make(http2gate)
+ gateDone := gate.Done
for {
f, err := sc.framer.ReadFrame()
select {
- case sc.readFrameCh <- http2readFrameResult{f, err, gate.Done}:
+ case sc.readFrameCh <- http2readFrameResult{f, err, gateDone}:
case <-sc.doneServing:
return
}
@@ -3083,17 +3459,17 @@ func (sc *http2serverConn) readFrames() {
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
type http2frameWriteResult struct {
- wm http2frameWriteMsg // what was written (or attempted)
- err error // result of the writeFrame call
+ wr http2FrameWriteRequest // what was written (or attempted)
+ err error // result of the writeFrame call
}
// writeFrameAsync runs in its own goroutine and writes a single frame
// and then reports when it's done.
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
-func (sc *http2serverConn) writeFrameAsync(wm http2frameWriteMsg) {
- err := wm.write.writeFrame(sc)
- sc.wroteFrameCh <- http2frameWriteResult{wm, err}
+func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest) {
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrameCh <- http2frameWriteResult{wr, err}
}
func (sc *http2serverConn) closeAllStreamsOnConnClose() {
@@ -3137,7 +3513,7 @@ func (sc *http2serverConn) serve() {
sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
}
- sc.writeFrame(http2frameWriteMsg{
+ sc.writeFrame(http2FrameWriteRequest{
write: http2writeSettings{
{http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
{http2SettingMaxConcurrentStreams, sc.advMaxStreams},
@@ -3154,6 +3530,17 @@ func (sc *http2serverConn) serve() {
sc.setConnState(StateActive)
sc.setConnState(StateIdle)
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer = time.NewTimer(sc.srv.IdleTimeout)
+ defer sc.idleTimer.Stop()
+ sc.idleTimerCh = sc.idleTimer.C
+ }
+
+ var gracefulShutdownCh <-chan struct{}
+ if sc.hs != nil {
+ gracefulShutdownCh = http2h1ServerShutdownChan(sc.hs)
+ }
+
go sc.readFrames()
settingsTimer := time.NewTimer(http2firstSettingsTimeout)
@@ -3161,8 +3548,10 @@ func (sc *http2serverConn) serve() {
for {
loopNum++
select {
- case wm := <-sc.wantWriteFrameCh:
- sc.writeFrame(wm)
+ case wr := <-sc.wantWriteFrameCh:
+ sc.writeFrame(wr)
+ case spr := <-sc.wantStartPushCh:
+ sc.startPush(spr)
case res := <-sc.wroteFrameCh:
sc.wroteFrame(res)
case res := <-sc.readFrameCh:
@@ -3179,12 +3568,22 @@ func (sc *http2serverConn) serve() {
case <-settingsTimer.C:
sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
return
+ case <-gracefulShutdownCh:
+ gracefulShutdownCh = nil
+ sc.startGracefulShutdown()
case <-sc.shutdownTimerCh:
sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
return
+ case <-sc.idleTimerCh:
+ sc.vlogf("connection is idle")
+ sc.goAway(http2ErrCodeNo)
case fn := <-sc.testHookCh:
fn(loopNum)
}
+
+ if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame {
+ return
+ }
}
}
@@ -3232,7 +3631,7 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
ch := http2errChanPool.Get().(chan error)
writeArg := http2writeDataPool.Get().(*http2writeData)
*writeArg = http2writeData{stream.id, data, endStream}
- err := sc.writeFrameFromHandler(http2frameWriteMsg{
+ err := sc.writeFrameFromHandler(http2FrameWriteRequest{
write: writeArg,
stream: stream,
done: ch,
@@ -3262,17 +3661,17 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
return err
}
-// writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts
+// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
// if the connection has gone away.
//
// This must not be run from the serve goroutine itself, else it might
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
// buffered and is read by serve itself). If you're on the serve
// goroutine, call writeFrame instead.
-func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
+func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) error {
sc.serveG.checkNotOn()
select {
- case sc.wantWriteFrameCh <- wm:
+ case sc.wantWriteFrameCh <- wr:
return nil
case <-sc.doneServing:
@@ -3288,39 +3687,81 @@ func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
// make it onto the wire
//
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
-func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) {
+func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
sc.serveG.check()
- sc.writeSched.add(wm)
+
+ // If true, wr will not be written and wr.done will not be signaled.
+ var ignoreWrite bool
+
+ if wr.StreamID() != 0 {
+ _, isReset := wr.write.(http2StreamError)
+ if state, _ := sc.state(wr.StreamID()); state == http2stateClosed && !isReset {
+ ignoreWrite = true
+ }
+ }
+
+ switch wr.write.(type) {
+ case *http2writeResHeaders:
+ wr.stream.wroteHeaders = true
+ case http2write100ContinueHeadersFrame:
+ if wr.stream.wroteHeaders {
+
+ if wr.done != nil {
+ panic("wr.done != nil for write100ContinueHeadersFrame")
+ }
+ ignoreWrite = true
+ }
+ }
+
+ if !ignoreWrite {
+ sc.writeSched.Push(wr)
+ }
sc.scheduleFrameWrite()
}
-// startFrameWrite starts a goroutine to write wm (in a separate
+// startFrameWrite starts a goroutine to write wr (in a separate
// goroutine since that might block on the network), and updates the
-// serve goroutine's state about the world, updated from info in wm.
-func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
+// serve goroutine's state about the world, updated from info in wr.
+func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
sc.serveG.check()
if sc.writingFrame {
panic("internal error: can only be writing one frame at a time")
}
- st := wm.stream
+ st := wr.stream
if st != nil {
switch st.state {
case http2stateHalfClosedLocal:
- panic("internal error: attempt to send frame on half-closed-local stream")
- case http2stateClosed:
- if st.sentReset || st.gotReset {
+ switch wr.write.(type) {
+ case http2StreamError, http2handlerPanicRST, http2writeWindowUpdate:
- sc.scheduleFrameWrite()
- return
+ default:
+ panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
}
- panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm))
+ case http2stateClosed:
+ panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
+ }
+ }
+ if wpp, ok := wr.write.(*http2writePushPromise); ok {
+ var err error
+ wpp.promisedID, err = wpp.allocatePromisedID()
+ if err != nil {
+ sc.writingFrameAsync = false
+ wr.replyToWriter(err)
+ return
}
}
sc.writingFrame = true
sc.needsFrameFlush = true
- go sc.writeFrameAsync(wm)
+ if wr.write.staysWithinBuffer(sc.bw.Available()) {
+ sc.writingFrameAsync = false
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrame(http2frameWriteResult{wr, err})
+ } else {
+ sc.writingFrameAsync = true
+ go sc.writeFrameAsync(wr)
+ }
}
// errHandlerPanicked is the error given to any callers blocked in a read from
@@ -3336,26 +3777,12 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
panic("internal error: expected to be already writing a frame")
}
sc.writingFrame = false
+ sc.writingFrameAsync = false
- wm := res.wm
- st := wm.stream
-
- closeStream := http2endsStream(wm.write)
-
- if _, ok := wm.write.(http2handlerPanicRST); ok {
- sc.closeStream(st, http2errHandlerPanicked)
- }
+ wr := res.wr
- if ch := wm.done; ch != nil {
- select {
- case ch <- res.err:
- default:
- panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write))
- }
- }
- wm.write = nil
-
- if closeStream {
+ if http2writeEndsStream(wr.write) {
+ st := wr.stream
if st == nil {
panic("internal error: expecting non-nil stream")
}
@@ -3363,13 +3790,24 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
case http2stateOpen:
st.state = http2stateHalfClosedLocal
- errCancel := http2StreamError{st.id, http2ErrCodeCancel}
- sc.resetStream(errCancel)
+ sc.resetStream(http2streamError(st.id, http2ErrCodeCancel))
case http2stateHalfClosedRemote:
sc.closeStream(st, http2errHandlerComplete)
}
+ } else {
+ switch v := wr.write.(type) {
+ case http2StreamError:
+
+ if st, ok := sc.streams[v.StreamID]; ok {
+ sc.closeStream(st, v)
+ }
+ case http2handlerPanicRST:
+ sc.closeStream(wr.stream, http2errHandlerPanicked)
+ }
}
+ wr.replyToWriter(res.err)
+
sc.scheduleFrameWrite()
}
@@ -3387,47 +3825,68 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
// flush the write buffer.
func (sc *http2serverConn) scheduleFrameWrite() {
sc.serveG.check()
- if sc.writingFrame {
+ if sc.writingFrame || sc.inFrameScheduleLoop {
return
}
- if sc.needToSendGoAway {
- sc.needToSendGoAway = false
- sc.startFrameWrite(http2frameWriteMsg{
- write: &http2writeGoAway{
- maxStreamID: sc.maxStreamID,
- code: sc.goAwayCode,
- },
- })
- return
- }
- if sc.needToSendSettingsAck {
- sc.needToSendSettingsAck = false
- sc.startFrameWrite(http2frameWriteMsg{write: http2writeSettingsAck{}})
- return
- }
- if !sc.inGoAway {
- if wm, ok := sc.writeSched.take(); ok {
- sc.startFrameWrite(wm)
- return
+ sc.inFrameScheduleLoop = true
+ for !sc.writingFrameAsync {
+ if sc.needToSendGoAway {
+ sc.needToSendGoAway = false
+ sc.startFrameWrite(http2FrameWriteRequest{
+ write: &http2writeGoAway{
+ maxStreamID: sc.maxClientStreamID,
+ code: sc.goAwayCode,
+ },
+ })
+ continue
}
+ if sc.needToSendSettingsAck {
+ sc.needToSendSettingsAck = false
+ sc.startFrameWrite(http2FrameWriteRequest{write: http2writeSettingsAck{}})
+ continue
+ }
+ if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo {
+ if wr, ok := sc.writeSched.Pop(); ok {
+ sc.startFrameWrite(wr)
+ continue
+ }
+ }
+ if sc.needsFrameFlush {
+ sc.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}})
+ sc.needsFrameFlush = false
+ continue
+ }
+ break
}
- if sc.needsFrameFlush {
- sc.startFrameWrite(http2frameWriteMsg{write: http2flushFrameWriter{}})
- sc.needsFrameFlush = false
- return
- }
+ sc.inFrameScheduleLoop = false
+}
+
+// startGracefulShutdown sends a GOAWAY with ErrCodeNo to tell the
+// client we're gracefully shutting down. The connection isn't closed
+// until all current streams are done.
+func (sc *http2serverConn) startGracefulShutdown() {
+ sc.goAwayIn(http2ErrCodeNo, 0)
}
func (sc *http2serverConn) goAway(code http2ErrCode) {
sc.serveG.check()
- if sc.inGoAway {
- return
- }
+ var forceCloseIn time.Duration
if code != http2ErrCodeNo {
- sc.shutDownIn(250 * time.Millisecond)
+ forceCloseIn = 250 * time.Millisecond
} else {
- sc.shutDownIn(1 * time.Second)
+ forceCloseIn = 1 * time.Second
+ }
+ sc.goAwayIn(code, forceCloseIn)
+}
+
+func (sc *http2serverConn) goAwayIn(code http2ErrCode, forceCloseIn time.Duration) {
+ sc.serveG.check()
+ if sc.inGoAway {
+ return
+ }
+ if forceCloseIn != 0 {
+ sc.shutDownIn(forceCloseIn)
}
sc.inGoAway = true
sc.needToSendGoAway = true
@@ -3443,10 +3902,9 @@ func (sc *http2serverConn) shutDownIn(d time.Duration) {
func (sc *http2serverConn) resetStream(se http2StreamError) {
sc.serveG.check()
- sc.writeFrame(http2frameWriteMsg{write: se})
+ sc.writeFrame(http2FrameWriteRequest{write: se})
if st, ok := sc.streams[se.StreamID]; ok {
- st.sentReset = true
- sc.closeStream(st, se)
+ st.resetQueued = true
}
}
@@ -3511,10 +3969,8 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
switch f := f.(type) {
case *http2SettingsFrame:
return sc.processSettings(f)
- case *http2HeadersFrame:
+ case *http2MetaHeadersFrame:
return sc.processHeaders(f)
- case *http2ContinuationFrame:
- return sc.processContinuation(f)
case *http2WindowUpdateFrame:
return sc.processWindowUpdate(f)
case *http2PingFrame:
@@ -3525,6 +3981,8 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
return sc.processResetStream(f)
case *http2PriorityFrame:
return sc.processPriority(f)
+ case *http2GoAwayFrame:
+ return sc.processGoAway(f)
case *http2PushPromiseFrame:
return http2ConnectionError(http2ErrCodeProtocol)
@@ -3544,7 +4002,10 @@ func (sc *http2serverConn) processPing(f *http2PingFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
- sc.writeFrame(http2frameWriteMsg{write: http2writePingAck{f}})
+ if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
+ return nil
+ }
+ sc.writeFrame(http2FrameWriteRequest{write: http2writePingAck{f}})
return nil
}
@@ -3552,13 +4013,17 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error
sc.serveG.check()
switch {
case f.StreamID != 0:
- st := sc.streams[f.StreamID]
+ state, st := sc.state(f.StreamID)
+ if state == http2stateIdle {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
if st == nil {
return nil
}
if !st.flow.add(int32(f.Increment)) {
- return http2StreamError{f.StreamID, http2ErrCodeFlowControl}
+ return http2streamError(f.StreamID, http2ErrCodeFlowControl)
}
default:
if !sc.flow.add(int32(f.Increment)) {
@@ -3578,8 +4043,8 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
if st != nil {
- st.gotReset = true
- sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode})
+ st.cancelCtx()
+ sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode))
}
return nil
}
@@ -3590,16 +4055,29 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
}
st.state = http2stateClosed
- sc.curOpenStreams--
- if sc.curOpenStreams == 0 {
- sc.setConnState(StateIdle)
+ if st.isPushed() {
+ sc.curPushedStreams--
+ } else {
+ sc.curClientStreams--
}
delete(sc.streams, st.id)
+ if len(sc.streams) == 0 {
+ sc.setConnState(StateIdle)
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer.Reset(sc.srv.IdleTimeout)
+ }
+ if http2h1ServerKeepAlivesDisabled(sc.hs) {
+ sc.startGracefulShutdown()
+ }
+ }
if p := st.body; p != nil {
+
+ sc.sendWindowUpdate(nil, p.Len())
+
p.CloseWithError(err)
}
st.cw.Close()
- sc.writeSched.forgetStream(st.id)
+ sc.writeSched.CloseStream(st.id)
}
func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
@@ -3639,7 +4117,7 @@ func (sc *http2serverConn) processSetting(s http2Setting) error {
case http2SettingInitialWindowSize:
return sc.processSettingInitialWindowSize(s.Val)
case http2SettingMaxFrameSize:
- sc.writeSched.maxFrameSize = s.Val
+ sc.maxFrameSize = int32(s.Val)
case http2SettingMaxHeaderListSize:
sc.peerMaxHeaderListSize = s.Val
default:
@@ -3668,36 +4146,62 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
func (sc *http2serverConn) processData(f *http2DataFrame) error {
sc.serveG.check()
+ if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
+ return nil
+ }
+ data := f.Data()
id := f.Header().StreamID
- st, ok := sc.streams[id]
- if !ok || st.state != http2stateOpen || st.gotTrailerHeader {
+ state, st := sc.state(id)
+ if id == 0 || state == http2stateIdle {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued {
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ if sc.inflow.available() < int32(f.Length) {
+ return http2streamError(id, http2ErrCodeFlowControl)
+ }
+
+ sc.inflow.take(int32(f.Length))
+ sc.sendWindowUpdate(nil, int(f.Length))
+
+ if st != nil && st.resetQueued {
+
+ return nil
+ }
+ return http2streamError(id, http2ErrCodeStreamClosed)
}
if st.body == nil {
panic("internal error: should have a body in this state")
}
- data := f.Data()
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ return http2streamError(id, http2ErrCodeStreamClosed)
}
- if len(data) > 0 {
+ if f.Length > 0 {
- if int(st.inflow.available()) < len(data) {
- return http2StreamError{id, http2ErrCodeFlowControl}
+ if st.inflow.available() < int32(f.Length) {
+ return http2streamError(id, http2ErrCodeFlowControl)
}
- st.inflow.take(int32(len(data)))
- wrote, err := st.body.Write(data)
- if err != nil {
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ st.inflow.take(int32(f.Length))
+
+ if len(data) > 0 {
+ wrote, err := st.body.Write(data)
+ if err != nil {
+ return http2streamError(id, http2ErrCodeStreamClosed)
+ }
+ if wrote != len(data) {
+ panic("internal error: bad Writer")
+ }
+ st.bodyBytes += int64(len(data))
}
- if wrote != len(data) {
- panic("internal error: bad Writer")
+
+ if pad := int32(f.Length) - int32(len(data)); pad > 0 {
+ sc.sendWindowUpdate32(nil, pad)
+ sc.sendWindowUpdate32(st, pad)
}
- st.bodyBytes += int64(len(data))
}
if f.StreamEnded() {
st.endStream()
@@ -3705,6 +4209,24 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
return nil
}
+func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error {
+ sc.serveG.check()
+ if f.ErrCode != http2ErrCodeNo {
+ sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ } else {
+ sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ }
+ sc.startGracefulShutdown()
+
+ sc.pushEnabled = false
+ return nil
+}
+
+// isPushed reports whether the stream is server-initiated.
+func (st *http2stream) isPushed() bool {
+ return st.id%2 == 0
+}
+
// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func (st *http2stream) endStream() {
@@ -3732,9 +4254,9 @@ func (st *http2stream) copyTrailersToHandlerRequest() {
}
}
-func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
+func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
sc.serveG.check()
- id := f.Header().StreamID
+ id := f.StreamID
if sc.inGoAway {
return nil
@@ -3744,96 +4266,46 @@ func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
- st := sc.streams[f.Header().StreamID]
- if st != nil {
+ if st := sc.streams[f.StreamID]; st != nil {
+ if st.resetQueued {
+
+ return nil
+ }
return st.processTrailerHeaders(f)
}
- if id <= sc.maxStreamID || sc.req.stream != nil {
+ if id <= sc.maxClientStreamID {
return http2ConnectionError(http2ErrCodeProtocol)
}
+ sc.maxClientStreamID = id
- if id > sc.maxStreamID {
- sc.maxStreamID = id
- }
- st = &http2stream{
- sc: sc,
- id: id,
- state: http2stateOpen,
+ if sc.idleTimer != nil {
+ sc.idleTimer.Stop()
}
- if f.StreamEnded() {
- st.state = http2stateHalfClosedRemote
- }
- st.cw.Init()
- st.flow.conn = &sc.flow
- st.flow.add(sc.initialWindowSize)
- st.inflow.conn = &sc.inflow
- st.inflow.add(http2initialWindowSize)
-
- sc.streams[id] = st
- if f.HasPriority() {
- http2adjustStreamPriority(sc.streams, st.id, f.Priority)
- }
- sc.curOpenStreams++
- if sc.curOpenStreams == 1 {
- sc.setConnState(StateActive)
- }
- sc.req = http2requestParam{
- stream: st,
- header: make(Header),
- }
- sc.hpackDecoder.SetEmitFunc(sc.onNewHeaderField)
- sc.hpackDecoder.SetEmitEnabled(true)
- return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
+ if sc.curClientStreams+1 > sc.advMaxStreams {
+ if sc.unackedSettings == 0 {
-func (st *http2stream) processTrailerHeaders(f *http2HeadersFrame) error {
- sc := st.sc
- sc.serveG.check()
- if st.gotTrailerHeader {
- return http2ConnectionError(http2ErrCodeProtocol)
- }
- st.gotTrailerHeader = true
- if !f.StreamEnded() {
- return http2StreamError{st.id, http2ErrCodeProtocol}
- }
- sc.resetPendingRequest()
- return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
-}
+ return http2streamError(id, http2ErrCodeProtocol)
+ }
-func (sc *http2serverConn) processContinuation(f *http2ContinuationFrame) error {
- sc.serveG.check()
- st := sc.streams[f.Header().StreamID]
- if st.gotTrailerHeader {
- return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
+ return http2streamError(id, http2ErrCodeRefusedStream)
}
- return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
-func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []byte, end bool) error {
- sc.serveG.check()
- if _, err := sc.hpackDecoder.Write(frag); err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
- }
- if !end {
- return nil
- }
- if err := sc.hpackDecoder.Close(); err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
+ initialState := http2stateOpen
+ if f.StreamEnded() {
+ initialState = http2stateHalfClosedRemote
}
- defer sc.resetPendingRequest()
- if sc.curOpenStreams > sc.advMaxStreams {
-
- if sc.unackedSettings == 0 {
+ st := sc.newStream(id, 0, initialState)
- return http2StreamError{st.id, http2ErrCodeProtocol}
+ if f.HasPriority() {
+ if err := http2checkPriority(f.StreamID, f.Priority); err != nil {
+ return err
}
-
- return http2StreamError{st.id, http2ErrCodeRefusedStream}
+ sc.writeSched.AdjustStream(st.id, f.Priority)
}
- rw, req, err := sc.newWriterAndRequest()
+ rw, req, err := sc.newWriterAndRequest(st, f)
if err != nil {
return err
}
@@ -3845,114 +4317,169 @@ func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []by
st.declBodyBytes = req.ContentLength
handler := sc.handler.ServeHTTP
- if !sc.hpackDecoder.EmitEnabled() {
+ if f.Truncated {
handler = http2handleHeaderListTooLong
+ } else if err := http2checkValidHTTP2RequestHeaders(req.Header); err != nil {
+ handler = http2new400Handler(err)
+ }
+
+ if sc.hs.ReadTimeout != 0 {
+ sc.conn.SetReadDeadline(time.Time{})
}
go sc.runHandler(rw, req, handler)
return nil
}
-func (st *http2stream) processTrailerHeaderBlockFragment(frag []byte, end bool) error {
+func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
sc := st.sc
sc.serveG.check()
- sc.hpackDecoder.SetEmitFunc(st.onNewTrailerField)
- if _, err := sc.hpackDecoder.Write(frag); err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
+ if st.gotTrailerHeader {
+ return http2ConnectionError(http2ErrCodeProtocol)
}
- if !end {
- return nil
+ st.gotTrailerHeader = true
+ if !f.StreamEnded() {
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
- rp := &sc.req
- if rp.invalidHeader {
- return http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ if len(f.PseudoFields()) > 0 {
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
+ if st.trailer != nil {
+ for _, hf := range f.RegularFields() {
+ key := sc.canonicalHeader(hf.Name)
+ if !http2ValidTrailerHeader(key) {
- err := sc.hpackDecoder.Close()
+ return http2streamError(st.id, http2ErrCodeProtocol)
+ }
+ st.trailer[key] = append(st.trailer[key], hf.Value)
+ }
+ }
st.endStream()
- if err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
+ return nil
+}
+
+func http2checkPriority(streamID uint32, p http2PriorityParam) error {
+ if streamID == p.StreamDep {
+
+ return http2streamError(streamID, http2ErrCodeProtocol)
}
return nil
}
func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
- http2adjustStreamPriority(sc.streams, f.StreamID, f.http2PriorityParam)
+ if sc.inGoAway {
+ return nil
+ }
+ if err := http2checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
+ return err
+ }
+ sc.writeSched.AdjustStream(f.StreamID, f.http2PriorityParam)
return nil
}
-func http2adjustStreamPriority(streams map[uint32]*http2stream, streamID uint32, priority http2PriorityParam) {
- st, ok := streams[streamID]
- if !ok {
-
- return
+func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState) *http2stream {
+ sc.serveG.check()
+ if id == 0 {
+ panic("internal error: cannot create stream with id 0")
}
- st.weight = priority.Weight
- parent := streams[priority.StreamDep]
- if parent == st {
- return
+ ctx, cancelCtx := http2contextWithCancel(sc.baseCtx)
+ st := &http2stream{
+ sc: sc,
+ id: id,
+ state: state,
+ ctx: ctx,
+ cancelCtx: cancelCtx,
}
+ st.cw.Init()
+ st.flow.conn = &sc.flow
+ st.flow.add(sc.initialWindowSize)
+ st.inflow.conn = &sc.inflow
+ st.inflow.add(http2initialWindowSize)
- for piter := parent; piter != nil; piter = piter.parent {
- if piter == st {
- parent.parent = st.parent
- break
- }
+ sc.streams[id] = st
+ sc.writeSched.OpenStream(st.id, http2OpenStreamOptions{PusherID: pusherID})
+ if st.isPushed() {
+ sc.curPushedStreams++
+ } else {
+ sc.curClientStreams++
}
- st.parent = parent
- if priority.Exclusive && (st.parent != nil || priority.StreamDep == 0) {
- for _, openStream := range streams {
- if openStream != st && openStream.parent == st.parent {
- openStream.parent = st
- }
- }
+ if sc.curOpenStreams() == 1 {
+ sc.setConnState(StateActive)
}
-}
-// resetPendingRequest zeros out all state related to a HEADERS frame
-// and its zero or more CONTINUATION frames sent to start a new
-// request.
-func (sc *http2serverConn) resetPendingRequest() {
- sc.serveG.check()
- sc.req = http2requestParam{}
+ return st
}
-func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request, error) {
+func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) {
sc.serveG.check()
- rp := &sc.req
- if rp.invalidHeader {
- return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ rp := http2requestParam{
+ method: f.PseudoValue("method"),
+ scheme: f.PseudoValue("scheme"),
+ authority: f.PseudoValue("authority"),
+ path: f.PseudoValue("path"),
}
isConnect := rp.method == "CONNECT"
if isConnect {
if rp.path != "" || rp.scheme != "" || rp.authority == "" {
- return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
- } else if rp.method == "" || rp.path == "" ||
- (rp.scheme != "https" && rp.scheme != "http") {
+ } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
- return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
- bodyOpen := rp.stream.state == http2stateOpen
+ bodyOpen := !f.StreamEnded()
if rp.method == "HEAD" && bodyOpen {
- return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
+ }
+
+ rp.header = make(Header)
+ for _, hf := range f.RegularFields() {
+ rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+ }
+ if rp.authority == "" {
+ rp.authority = rp.header.Get("Host")
}
- var tlsState *tls.ConnectionState // nil if not scheme https
+ rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
+ if err != nil {
+ return nil, nil, err
+ }
+ if bodyOpen {
+ st.reqBuf = http2getRequestBodyBuf()
+ req.Body.(*http2requestBody).pipe = &http2pipe{
+ b: &http2fixedBuffer{buf: st.reqBuf},
+ }
+
+ if vv, ok := rp.header["Content-Length"]; ok {
+ req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
+ } else {
+ req.ContentLength = -1
+ }
+ }
+ return rw, req, nil
+}
+
+type http2requestParam struct {
+ method string
+ scheme, authority, path string
+ header Header
+}
+
+func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2requestParam) (*http2responseWriter, *Request, error) {
+ sc.serveG.check()
+
+ var tlsState *tls.ConnectionState // nil if not scheme https
if rp.scheme == "https" {
tlsState = sc.tlsState
}
- authority := rp.authority
- if authority == "" {
- authority = rp.header.Get("Host")
- }
+
needsContinue := rp.header.Get("Expect") == "100-continue"
if needsContinue {
rp.header.Del("Expect")
@@ -3980,24 +4507,25 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
}
delete(rp.header, "Trailer")
- body := &http2requestBody{
- conn: sc,
- stream: rp.stream,
- needsContinue: needsContinue,
- }
var url_ *url.URL
var requestURI string
- if isConnect {
+ if rp.method == "CONNECT" {
url_ = &url.URL{Host: rp.authority}
requestURI = rp.authority
} else {
var err error
url_, err = url.ParseRequestURI(rp.path)
if err != nil {
- return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(st.id, http2ErrCodeProtocol)
}
requestURI = rp.path
}
+
+ body := &http2requestBody{
+ conn: sc,
+ stream: st,
+ needsContinue: needsContinue,
+ }
req := &Request{
Method: rp.method,
URL: url_,
@@ -4008,21 +4536,11 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
ProtoMajor: 2,
ProtoMinor: 0,
TLS: tlsState,
- Host: authority,
+ Host: rp.authority,
Body: body,
Trailer: trailer,
}
- if bodyOpen {
- body.pipe = &http2pipe{
- b: &http2fixedBuffer{buf: make([]byte, http2initialWindowSize)},
- }
-
- if vv, ok := rp.header["Content-Length"]; ok {
- req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
- } else {
- req.ContentLength = -1
- }
- }
+ req = http2requestWithContext(req, st.ctx)
rws := http2responseWriterStatePool.Get().(*http2responseWriterState)
bwSave := rws.bw
@@ -4030,7 +4548,7 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
rws.conn = sc
rws.bw = bwSave
rws.bw.Reset(http2chunkWriter{rws})
- rws.stream = rp.stream
+ rws.stream = st
rws.req = req
rws.body = body
@@ -4038,21 +4556,42 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
return rw, req, nil
}
+var http2reqBodyCache = make(chan []byte, 8)
+
+func http2getRequestBodyBuf() []byte {
+ select {
+ case b := <-http2reqBodyCache:
+ return b
+ default:
+ return make([]byte, http2initialWindowSize)
+ }
+}
+
+func http2putRequestBodyBuf(b []byte) {
+ select {
+ case http2reqBodyCache <- b:
+ default:
+ }
+}
+
// Run on its own goroutine.
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:
- const size = 64 << 10
- buf := make([]byte, size)
- buf = buf[:runtime.Stack(buf, false)]
- sc.writeFrameFromHandler(http2frameWriteMsg{
+ sc.writeFrameFromHandler(http2FrameWriteRequest{
write: http2handlerPanicRST{rw.rws.stream.id},
stream: rw.rws.stream,
})
- sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+
+ if http2shouldLogPanic(e) {
+ const size = 64 << 10
+ buf := make([]byte, size)
+ buf = buf[:runtime.Stack(buf, false)]
+ sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+ }
return
}
rw.handlerDone()
@@ -4080,7 +4619,7 @@ func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeR
errc = http2errChanPool.Get().(chan error)
}
- if err := sc.writeFrameFromHandler(http2frameWriteMsg{
+ if err := sc.writeFrameFromHandler(http2FrameWriteRequest{
write: headerData,
stream: st,
done: errc,
@@ -4103,7 +4642,7 @@ func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeR
// called from handler goroutines.
func (sc *http2serverConn) write100ContinueHeaders(st *http2stream) {
- sc.writeFrameFromHandler(http2frameWriteMsg{
+ sc.writeFrameFromHandler(http2FrameWriteRequest{
write: http2write100ContinueHeadersFrame{st.id},
stream: st,
})
@@ -4119,11 +4658,19 @@ type http2bodyReadMsg struct {
// called from handler goroutines.
// Notes that the handler for the given stream ID read n bytes of its body
// and schedules flow control tokens to be sent.
-func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int) {
+func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err error) {
sc.serveG.checkNotOn()
- select {
- case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
- case <-sc.doneServing:
+ if n > 0 {
+ select {
+ case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
+ case <-sc.doneServing:
+ }
+ }
+ if err == io.EOF {
+ if buf := st.reqBuf; buf != nil {
+ st.reqBuf = nil
+ http2putRequestBodyBuf(buf)
+ }
}
}
@@ -4165,7 +4712,7 @@ func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
if st != nil {
streamID = st.id
}
- sc.writeFrame(http2frameWriteMsg{
+ sc.writeFrame(http2FrameWriteRequest{
write: http2writeWindowUpdate{streamID: streamID, n: uint32(n)},
stream: st,
})
@@ -4180,17 +4727,20 @@ func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
}
}
+// requestBody is the Handler's Request.Body type.
+// Read and Close may be called concurrently.
type http2requestBody struct {
stream *http2stream
conn *http2serverConn
- closed bool
+ closed bool // for use by Close only
+ sawEOF bool // for use by Read only
pipe *http2pipe // non-nil if we have a HTTP entity message body
needsContinue bool // need to send a 100-continue
}
func (b *http2requestBody) Close() error {
- if b.pipe != nil {
- b.pipe.CloseWithError(http2errClosedBody)
+ if b.pipe != nil && !b.closed {
+ b.pipe.BreakWithError(http2errClosedBody)
}
b.closed = true
return nil
@@ -4201,13 +4751,17 @@ func (b *http2requestBody) Read(p []byte) (n int, err error) {
b.needsContinue = false
b.conn.write100ContinueHeaders(b.stream)
}
- if b.pipe == nil {
+ if b.pipe == nil || b.sawEOF {
return 0, io.EOF
}
n, err = b.pipe.Read(p)
- if n > 0 {
- b.conn.noteBodyReadFromHandler(b.stream, n)
+ if err == io.EOF {
+ b.sawEOF = true
+ }
+ if b.conn == nil && http2inTests {
+ return
}
+ b.conn.noteBodyReadFromHandler(b.stream, n, err)
return
}
@@ -4265,9 +4819,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) {
@@ -4408,7 +4962,12 @@ func (rws *http2responseWriterState) promoteUndeclaredTrailers() {
rws.declareTrailer(trailerKey)
rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv
}
- sort.Strings(rws.trailers)
+
+ if len(rws.trailers) > 1 {
+ sorter := http2sorterPool.Get().(*http2sorter)
+ sorter.SortStrings(rws.trailers)
+ http2sorterPool.Put(sorter)
+ }
}
func (w *http2responseWriter) Flush() {
@@ -4437,8 +4996,9 @@ func (w *http2responseWriter) CloseNotify() <-chan bool {
if ch == nil {
ch = make(chan bool, 1)
rws.closeNotifierCh = ch
+ cw := rws.stream.cw
go func() {
- rws.stream.cw.Wait()
+ cw.Wait()
ch <- true
}()
}
@@ -4534,6 +5094,172 @@ func (w *http2responseWriter) handlerDone() {
http2responseWriterStatePool.Put(rws)
}
+// Push errors.
+var (
+ http2ErrRecursivePush = errors.New("http2: recursive push not allowed")
+ http2ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
+)
+
+// pushOptions is the internal version of http.PushOptions, which we
+// cannot include here because it's only defined in Go 1.8 and later.
+type http2pushOptions struct {
+ Method string
+ Header Header
+}
+
+func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
+ st := w.rws.stream
+ sc := st.sc
+ sc.serveG.checkNotOn()
+
+ if st.isPushed() {
+ return http2ErrRecursivePush
+ }
+
+ if opts.Method == "" {
+ opts.Method = "GET"
+ }
+ if opts.Header == nil {
+ opts.Header = Header{}
+ }
+ wantScheme := "http"
+ if w.rws.req.TLS != nil {
+ wantScheme = "https"
+ }
+
+ u, err := url.Parse(target)
+ if err != nil {
+ return err
+ }
+ if u.Scheme == "" {
+ if !strings.HasPrefix(target, "/") {
+ return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target)
+ }
+ u.Scheme = wantScheme
+ u.Host = w.rws.req.Host
+ } else {
+ if u.Scheme != wantScheme {
+ return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme)
+ }
+ if u.Host == "" {
+ return errors.New("URL must have a host")
+ }
+ }
+ for k := range opts.Header {
+ if strings.HasPrefix(k, ":") {
+ return fmt.Errorf("promised request headers cannot include pseudo header %q", k)
+ }
+
+ switch strings.ToLower(k) {
+ case "content-length", "content-encoding", "trailer", "te", "expect", "host":
+ return fmt.Errorf("promised request headers cannot include %q", k)
+ }
+ }
+ if err := http2checkValidHTTP2RequestHeaders(opts.Header); err != nil {
+ return err
+ }
+
+ if opts.Method != "GET" && opts.Method != "HEAD" {
+ return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
+ }
+
+ msg := http2startPushRequest{
+ parent: st,
+ method: opts.Method,
+ url: u,
+ header: http2cloneHeader(opts.Header),
+ done: http2errChanPool.Get().(chan error),
+ }
+
+ select {
+ case <-sc.doneServing:
+ return http2errClientDisconnected
+ case <-st.cw:
+ return http2errStreamClosed
+ case sc.wantStartPushCh <- msg:
+ }
+
+ select {
+ case <-sc.doneServing:
+ return http2errClientDisconnected
+ case <-st.cw:
+ return http2errStreamClosed
+ case err := <-msg.done:
+ http2errChanPool.Put(msg.done)
+ return err
+ }
+}
+
+type http2startPushRequest struct {
+ parent *http2stream
+ method string
+ url *url.URL
+ header Header
+ done chan error
+}
+
+func (sc *http2serverConn) startPush(msg http2startPushRequest) {
+ sc.serveG.check()
+
+ if msg.parent.state != http2stateOpen && msg.parent.state != http2stateHalfClosedRemote {
+
+ msg.done <- http2errStreamClosed
+ return
+ }
+
+ if !sc.pushEnabled {
+ msg.done <- ErrNotSupported
+ return
+ }
+
+ allocatePromisedID := func() (uint32, error) {
+ sc.serveG.check()
+
+ if !sc.pushEnabled {
+ return 0, ErrNotSupported
+ }
+
+ if sc.curPushedStreams+1 > sc.clientMaxStreams {
+ return 0, http2ErrPushLimitReached
+ }
+
+ if sc.maxPushPromiseID+2 >= 1<<31 {
+ sc.startGracefulShutdown()
+ return 0, http2ErrPushLimitReached
+ }
+ sc.maxPushPromiseID += 2
+ promisedID := sc.maxPushPromiseID
+
+ promised := sc.newStream(promisedID, msg.parent.id, http2stateHalfClosedRemote)
+ rw, req, err := sc.newWriterAndRequestNoBody(promised, http2requestParam{
+ method: msg.method,
+ scheme: msg.url.Scheme,
+ authority: msg.url.Host,
+ path: msg.url.RequestURI(),
+ header: http2cloneHeader(msg.header),
+ })
+ if err != nil {
+
+ panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
+ }
+
+ go sc.runHandler(rw, req, sc.handler.ServeHTTP)
+ return promisedID, nil
+ }
+
+ sc.writeFrame(http2FrameWriteRequest{
+ write: &http2writePushPromise{
+ streamID: msg.parent.id,
+ method: msg.method,
+ url: msg.url,
+ h: msg.header,
+ allocatePromisedID: allocatePromisedID,
+ },
+ stream: msg.parent,
+ done: msg.done,
+ })
+}
+
// foreachHeaderElement splits v according to the "#rule" construction
// in RFC 2616 section 2.1 and calls fn for each non-empty element.
func http2foreachHeaderElement(v string, fn func(string)) {
@@ -4552,6 +5278,111 @@ 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",
+}
+
+// checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request,
+// per RFC 7540 Section 8.1.2.2.
+// The returned error is reported to users.
+func http2checkValidHTTP2RequestHeaders(h Header) error {
+ for _, k := range http2connHeaders {
+ if _, ok := h[k]; ok {
+ return fmt.Errorf("request header %q is not valid in HTTP/2", k)
+ }
+ }
+ te := h["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,
+}
+
+// h1ServerShutdownChan returns a channel that will be closed when the
+// provided *http.Server wants to shut down.
+//
+// This is a somewhat hacky way to get at http1 innards. It works
+// when the http2 code is bundled into the net/http package in the
+// standard library. The alternatives ended up making the cmd/go tool
+// depend on http Servers. This is the lightest option for now.
+// This is tested via the TestServeShutdown* tests in net/http.
+func http2h1ServerShutdownChan(hs *Server) <-chan struct{} {
+ if fn := http2testh1ServerShutdownChan; fn != nil {
+ return fn(hs)
+ }
+ var x interface{} = hs
+ type I interface {
+ getDoneChan() <-chan struct{}
+ }
+ if hs, ok := x.(I); ok {
+ return hs.getDoneChan()
+ }
+ return nil
+}
+
+// optional test hook for h1ServerShutdownChan.
+var http2testh1ServerShutdownChan func(hs *Server) <-chan struct{}
+
+// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
+// disabled. See comments on h1ServerShutdownChan above for why
+// the code is written this way.
+func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
+ var x interface{} = hs
+ type I interface {
+ doKeepAlives() bool
+ }
+ if hs, ok := x.(I); ok {
+ return !hs.doKeepAlives()
+ }
+ return false
+}
+
const (
// transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k.
@@ -4601,6 +5432,10 @@ type http2Transport struct {
// uncompressed.
DisableCompression bool
+ // AllowHTTP, if true, permits HTTP/2 requests using the insecure,
+ // plain-text "http" scheme. Note that this does not enable h2c support.
+ AllowHTTP bool
+
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
// send in the initial settings frame. It is how many bytes
// of response headers are allow. Unlike the http2 spec, zero here
@@ -4659,32 +5494,41 @@ func (t *http2Transport) initConnPool() {
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
type http2ClientConn struct {
- t *http2Transport
- tconn net.Conn // usually *tls.Conn, except specialized impls
- tlsState *tls.ConnectionState // nil only for specialized impls
+ t *http2Transport
+ tconn net.Conn // usually *tls.Conn, except specialized impls
+ tlsState *tls.ConnectionState // nil only for specialized impls
+ singleUse bool // whether being used for a single http.Request
// readLoop goroutine fields:
readerDone chan struct{} // closed on error
readerErr error // set before readerDone is closed
- mu sync.Mutex // guards following
- cond *sync.Cond // hold mu; broadcast on flow/closed changes
- flow http2flow // our conn-level flow control quota (cs.flow is per stream)
- inflow http2flow // peer's conn-level flow control
- closed bool
- goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received
- streams map[uint32]*http2clientStream // client-initiated
- nextStreamID uint32
- bw *bufio.Writer
- br *bufio.Reader
- fr *http2Framer
- // Settings from peer:
+ idleTimeout time.Duration // or 0 for never
+ idleTimer *time.Timer
+
+ mu sync.Mutex // guards following
+ cond *sync.Cond // hold mu; broadcast on flow/closed changes
+ flow http2flow // our conn-level flow control quota (cs.flow is per stream)
+ inflow http2flow // peer's conn-level flow control
+ closed bool
+ wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
+ goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received
+ goAwayDebug string // goAway frame's debug data, retained as a string
+ streams map[uint32]*http2clientStream // client-initiated
+ nextStreamID uint32
+ pings map[[8]byte]chan struct{} // in flight ping data to notification channel
+ bw *bufio.Writer
+ br *bufio.Reader
+ fr *http2Framer
+ lastActive time.Time
+ // Settings from peer: (also guarded by mu)
maxFrameSize uint32
maxConcurrentStreams uint32
initialWindowSize uint32
- hbuf bytes.Buffer // HPACK encoder writes into this
- henc *hpack.Encoder
- freeBuf [][]byte
+
+ hbuf bytes.Buffer // HPACK encoder writes into this
+ henc *hpack.Encoder
+ freeBuf [][]byte
wmu sync.Mutex // held while writing; acquire AFTER mu if holding both
werr error // first write error that has occurred
@@ -4695,16 +5539,20 @@ 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
+ startedWrite bool // started request body write; guarded by cc.mu
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
bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
readErr error // sticky read error; owned by transportResponseBody.Read
stopReqBody error // if non-nil, stop writing req body; guarded by cc.mu
+ didReset bool // whether we sent a RST_STREAM to the server; guarded by cc.mu
peerReset chan struct{} // closed on peer reset
resetErr error // populated before peerReset is closed
@@ -4712,36 +5560,54 @@ type http2clientStream struct {
done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
// owned by clientConnReadLoop:
- pastHeaders bool // got HEADERS w/ END_HEADERS
- pastTrailers bool // got second HEADERS frame w/ END_HEADERS
+ firstByte bool // got the first response byte
+ pastHeaders bool // got first MetaHeadersFrame (actual headers)
+ pastTrailers bool // got optional second MetaHeadersFrame (trailers)
trailer Header // accumulated trailers
resTrailer *Header // client's Response.Trailer
}
// 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.cancelStream()
cs.bufPipe.CloseWithError(http2errRequestCanceled)
- cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ case <-ctx.Done():
+ cs.cancelStream()
+ cs.bufPipe.CloseWithError(ctx.Err())
case <-cs.done:
}
}
-// checkReset reports any error sent in a RST_STREAM frame by the
-// server.
-func (cs *http2clientStream) checkReset() error {
+func (cs *http2clientStream) cancelStream() {
+ cs.cc.mu.Lock()
+ didReset := cs.didReset
+ cs.didReset = true
+ cs.cc.mu.Unlock()
+
+ if !didReset {
+ cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ }
+}
+
+// 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
}
@@ -4789,29 +5655,44 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
-func http2authorityAddr(authority string) (addr string) {
- if _, _, err := net.SplitHostPort(authority); err == nil {
- return authority
+func http2authorityAddr(scheme string, authority string) (addr string) {
+ host, port, err := net.SplitHostPort(authority)
+ if err != nil {
+ port = "443"
+ if scheme == "http" {
+ port = "80"
+ }
+ host = authority
+ }
+ if a, err := idna.ToASCII(host); err == nil {
+ host = a
}
- return net.JoinHostPort(authority, "443")
+
+ if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
+ return host + ":" + port
+ }
+ return net.JoinHostPort(host, port)
}
// RoundTripOpt is like RoundTrip, but takes options.
func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
- if req.URL.Scheme != "https" {
+ if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
return nil, errors.New("http2: unsupported scheme")
}
- addr := http2authorityAddr(req.URL.Host)
+ addr := http2authorityAddr(req.URL.Scheme, req.URL.Host)
for {
cc, err := t.connPool().GetClientConn(req, addr)
if err != nil {
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
+ if err != nil {
+ if req, err = http2shouldRetryRequest(req, err); err == nil {
+ continue
+ }
}
if err != nil {
t.vlogf("RoundTrip failure: %v", err)
@@ -4825,7 +5706,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()
}
}
@@ -4833,14 +5714,42 @@ func (t *http2Transport) CloseIdleConnections() {
var (
http2errClientConnClosed = errors.New("http2: client conn is closed")
http2errClientConnUnusable = errors.New("http2: client conn not usable")
+
+ http2errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
+ http2errClientConnGotGoAwayAfterSomeReqBody = errors.New("http2: Transport received Server's graceful shutdown GOAWAY; some request body already written")
)
-func http2shouldRetryRequest(req *Request, err error) bool {
+// shouldRetryRequest is called by RoundTrip when a request fails to get
+// response headers. It is always called with a non-nil error.
+// It returns either a request to retry (either the same request, or a
+// modified clone), or an error if the request can't be replayed.
+func http2shouldRetryRequest(req *Request, err error) (*Request, error) {
+ switch err {
+ default:
+ return nil, err
+ case http2errClientConnUnusable, http2errClientConnGotGoAway:
+ return req, nil
+ case http2errClientConnGotGoAwayAfterSomeReqBody:
+
+ if req.Body == nil || http2reqBodyIsNoBody(req.Body) {
+ return req, nil
+ }
- return err == http2errClientConnUnusable
+ getBody := http2reqGetBody(req)
+ if getBody == nil {
+ return nil, errors.New("http2: Transport: peer server initiated graceful shutdown after some of Request.Body was written; define Request.GetBody to avoid this error")
+ }
+ body, err := getBody()
+ if err != nil {
+ return nil, err
+ }
+ newReq := *req
+ newReq.Body = body
+ return &newReq, nil
+ }
}
-func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) {
+func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
@@ -4849,16 +5758,20 @@ func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) {
if err != nil {
return nil, err
}
- return t.NewClientConn(tconn)
+ return t.newClientConn(tconn, singleUse)
}
func (t *http2Transport) newTLSConfig(host string) *tls.Config {
cfg := new(tls.Config)
if t.TLSClientConfig != nil {
- *cfg = *t.TLSClientConfig
+ *cfg = *http2cloneTLSConfig(t.TLSClientConfig)
+ }
+ if !http2strSliceContains(cfg.NextProtos, http2NextProtoTLS) {
+ cfg.NextProtos = append([]string{http2NextProtoTLS}, cfg.NextProtos...)
+ }
+ if cfg.ServerName == "" {
+ cfg.ServerName = host
}
- cfg.NextProtos = []string{http2NextProtoTLS}
- cfg.ServerName = host
return cfg
}
@@ -4898,15 +5811,18 @@ func (t *http2Transport) disableKeepAlives() bool {
return t.t1 != nil && t.t1.DisableKeepAlives
}
-func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
- if http2VerboseLogs {
- t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
- }
- if _, err := c.Write(http2clientPreface); err != nil {
- t.vlogf("client preface write error: %v", err)
- return nil, err
+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) {
+ return t.newClientConn(c, false)
+}
+func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) {
cc := &http2ClientConn{
t: t,
tconn: c,
@@ -4916,13 +5832,26 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
initialWindowSize: 65535,
maxConcurrentStreams: 1000,
streams: make(map[uint32]*http2clientStream),
+ singleUse: singleUse,
+ wantSettingsAck: true,
+ pings: make(map[[8]byte]chan struct{}),
}
+ if d := t.idleConnTimeout(); d != 0 {
+ cc.idleTimeout = d
+ cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
+ }
+ if http2VerboseLogs {
+ t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
+ }
+
cc.cond = sync.NewCond(&cc.mu)
cc.flow.add(int32(http2initialWindowSize))
cc.bw = bufio.NewWriter(http2stickyErrWriter{c, &cc.werr})
cc.br = bufio.NewReader(c)
cc.fr = http2NewFramer(cc.bw, cc.br)
+ cc.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
+ cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
cc.henc = hpack.NewEncoder(&cc.hbuf)
@@ -4932,12 +5861,14 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
}
initialSettings := []http2Setting{
- http2Setting{ID: http2SettingEnablePush, Val: 0},
- http2Setting{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
+ {ID: http2SettingEnablePush, Val: 0},
+ {ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
}
if max := t.maxHeaderListSize(); max != 0 {
initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max})
}
+
+ cc.bw.Write(http2clientPreface)
cc.fr.WriteSettings(initialSettings...)
cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow)
cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
@@ -4946,32 +5877,6 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
return nil, cc.werr
}
- f, err := cc.fr.ReadFrame()
- if err != nil {
- return nil, err
- }
- sf, ok := f.(*http2SettingsFrame)
- if !ok {
- return nil, fmt.Errorf("expected settings frame, got: %T", f)
- }
- cc.fr.WriteSettingsAck()
- cc.bw.Flush()
-
- sf.ForeachSetting(func(s http2Setting) error {
- switch s.ID {
- case http2SettingMaxFrameSize:
- cc.maxFrameSize = s.Val
- case http2SettingMaxConcurrentStreams:
- cc.maxConcurrentStreams = s.Val
- case http2SettingInitialWindowSize:
- cc.initialWindowSize = s.Val
- default:
-
- t.vlogf("Unhandled Setting: %v", s)
- }
- return nil
- })
-
go cc.readLoop()
return cc, nil
}
@@ -4979,7 +5884,25 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
cc.mu.Lock()
defer cc.mu.Unlock()
+
+ old := cc.goAway
cc.goAway = f
+
+ if cc.goAwayDebug == "" {
+ cc.goAwayDebug = string(f.DebugData())
+ }
+ if old != nil && old.ErrCode != http2ErrCodeNo {
+ cc.goAway.ErrCode = old.ErrCode
+ }
+ last := f.LastStreamID
+ for streamID, cs := range cc.streams {
+ if streamID > last {
+ select {
+ case cs.resc <- http2resAndError{err: http2errClientConnGotGoAway}:
+ default:
+ }
+ }
+ }
}
func (cc *http2ClientConn) CanTakeNewRequest() bool {
@@ -4989,9 +5912,22 @@ func (cc *http2ClientConn) CanTakeNewRequest() bool {
}
func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
+ if cc.singleUse && cc.nextStreamID > 1 {
+ return false
+ }
return cc.goAway == nil && !cc.closed &&
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
- cc.nextStreamID < 2147483647
+ cc.nextStreamID < math.MaxInt32
+}
+
+// onIdleTimeout is called from a time.AfterFunc goroutine. It will
+// only be called when we're idle, but because we're coming from a new
+// goroutine, there could be a new request coming in at the same time,
+// so this simply calls the synchronized closeIfIdle to shut down this
+// connection. The timer could just call closeIfIdle, but this is more
+// clear.
+func (cc *http2ClientConn) onIdleTimeout() {
+ cc.closeIfIdle()
}
func (cc *http2ClientConn) closeIfIdle() {
@@ -5001,9 +5937,13 @@ func (cc *http2ClientConn) closeIfIdle() {
return
}
cc.closed = true
+ nextID := cc.nextStreamID
cc.mu.Unlock()
+ if http2VerboseLogs {
+ cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
+ }
cc.tconn.Close()
}
@@ -5082,21 +6022,37 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
// Certain headers are special-cased as okay but not transmitted later.
func http2checkConnHeaders(req *Request) error {
if v := req.Header.Get("Upgrade"); v != "" {
- return errors.New("http2: invalid Upgrade request header")
+ return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"])
}
- if v := req.Header.Get("Transfer-Encoding"); (v != "" && v != "chunked") || len(req.Header["Transfer-Encoding"]) > 1 {
- return errors.New("http2: invalid Transfer-Encoding request header")
+ if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
+ return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
}
- if v := req.Header.Get("Connection"); (v != "" && v != "close" && v != "keep-alive") || len(req.Header["Connection"]) > 1 {
- return errors.New("http2: invalid Connection request header")
+ if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "close" && vv[0] != "keep-alive") {
+ return fmt.Errorf("http2: invalid Connection request header: %q", vv)
}
return nil
}
+// actualContentLength returns a sanitized version of
+// req.ContentLength, where 0 actually means zero (not unknown) and -1
+// means unknown.
+func http2actualContentLength(req *Request) int64 {
+ if req.Body == nil {
+ return 0
+ }
+ if req.ContentLength != 0 {
+ return req.ContentLength
+ }
+ return -1
+}
+
func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
if err := http2checkConnHeaders(req); err != nil {
return nil, err
}
+ if cc.idleTimer != nil {
+ cc.idleTimer.Stop()
+ }
trailers, err := http2commaSeparatedTrailers(req)
if err != nil {
@@ -5104,67 +6060,63 @@ 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
- }
- }
-
cc.mu.Lock()
+ cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
cc.mu.Unlock()
return nil, http2errClientConnUnusable
}
- cs := cc.newStream()
- cs.req = req
+ body := req.Body
hasBody := body != nil
+ contentLen := http2actualContentLength(req)
+ // 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()
@@ -5173,44 +6125,87 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
}
readLoopResCh := cs.resc
- requestCanceledCh := http2requestCancel(req)
bodyWritten := false
+ ctx := http2reqContext(req)
+
+ handleReadLoopResponse := func(re http2resAndError) (*Response, error) {
+ res := re.res
+ if re.err != nil || res.StatusCode > 299 {
+
+ bodyWriter.cancel()
+ cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
+ }
+ if re.err != nil {
+ if re.err == http2errClientConnGotGoAway {
+ cc.mu.Lock()
+ if cs.startedWrite {
+ re.err = http2errClientConnGotGoAwayAfterSomeReqBody
+ }
+ cc.mu.Unlock()
+ }
+ cc.forgetStreamID(cs.ID)
+ return nil, re.err
+ }
+ res.Request = req
+ res.TLS = cc.tlsState
+ return res, nil
+ }
for {
select {
case re := <-readLoopResCh:
- res := re.res
- if re.err != nil || res.StatusCode > 299 {
-
- cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
- }
- if re.err != nil {
- cc.forgetStreamID(cs.ID)
- return nil, re.err
- }
- res.Request = req
- res.TLS = cc.tlsState
- return res, nil
+ return handleReadLoopResponse(re)
case <-respHeaderTimer:
cc.forgetStreamID(cs.ID)
if !hasBody || bodyWritten {
cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
} else {
+ bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
}
return nil, http2errTimeout
- case <-requestCanceledCh:
+ case <-ctx.Done():
+ select {
+ case re := <-readLoopResCh:
+ return handleReadLoopResponse(re)
+ default:
+ }
+ 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:
+ select {
+ case re := <-readLoopResCh:
+ return handleReadLoopResponse(re)
+ default:
+ }
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:
-
+ select {
+ case re := <-readLoopResCh:
+ return handleReadLoopResponse(re)
+ default:
+ }
return nil, cs.resetErr
- case err := <-bodyCopyErrc:
+ case err := <-bodyWriter.resc:
+
+ select {
+ case re := <-readLoopResCh:
+ return handleReadLoopResponse(re)
+ default:
+ }
if err != nil {
return nil, err
}
@@ -5268,6 +6263,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 {
@@ -5317,26 +6313,29 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
}
}
+ if sentEnd {
+
+ return nil
+ }
+
+ var trls []byte
+ if hasTrailers {
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
+ trls = cc.encodeTrailers(req)
+ }
+
cc.wmu.Lock()
- if !sentEnd {
- var trls []byte
- if hasTrailers {
- cc.mu.Lock()
- trls = cc.encodeTrailers(req)
- cc.mu.Unlock()
- }
+ defer cc.wmu.Unlock()
- if len(trls) > 0 {
- err = cc.writeHeaders(cs.ID, true, trls)
- } else {
- err = cc.fr.WriteData(cs.ID, true, nil)
- }
+ if len(trls) > 0 {
+ err = cc.writeHeaders(cs.ID, true, trls)
+ } else {
+ err = cc.fr.WriteData(cs.ID, true, nil)
}
if ferr := cc.bw.Flush(); ferr != nil && err == nil {
err = ferr
}
- cc.wmu.Unlock()
-
return err
}
@@ -5355,7 +6354,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 {
@@ -5382,19 +6381,50 @@ 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
if host == "" {
host = req.URL.Host
}
+ host, err := httplex.PunycodeHostPort(host)
+ if err != nil {
+ return nil, err
+ }
+
+ var path string
+ if req.Method != "CONNECT" {
+ path = req.URL.RequestURI()
+ if !http2validPseudoPath(path) {
+ orig := path
+ path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
+ if !http2validPseudoPath(path) {
+ if req.URL.Opaque != "" {
+ return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
+ } else {
+ return nil, fmt.Errorf("invalid request :path %q", orig)
+ }
+ }
+ }
+ }
+
+ 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" {
- cc.writeHeader(":path", req.URL.RequestURI())
- cc.writeHeader(":scheme", "https")
+ cc.writeHeader(":path", path)
+ cc.writeHeader(":scheme", req.URL.Scheme)
}
if trailers != "" {
cc.writeHeader("trailer", trailers)
@@ -5407,7 +6437,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":
@@ -5434,7 +6464,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
@@ -5510,8 +6540,13 @@ 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)
+ if len(cc.streams) == 0 && cc.idleTimer != nil {
+ cc.idleTimer.Reset(cc.idleTimeout)
+ }
close(cs.done)
+ cc.cond.Broadcast()
}
return cs
}
@@ -5521,15 +6556,6 @@ type http2clientConnReadLoop struct {
cc *http2ClientConn
activeRes map[uint32]*http2clientStream // keyed by streamID
closeWhenIdle bool
-
- hdec *hpack.Decoder
-
- // Fields reset on each HEADERS:
- nextRes *Response
- sawRegHeader bool // saw non-pseudo header
- reqMalformed error // non-nil once known to be malformed
- lastHeaderEndsStream bool
- headerListSize int64 // actually uint32, but easier math this way
}
// readLoop runs in its own goroutine and reads and dispatches frames.
@@ -5538,7 +6564,6 @@ func (cc *http2ClientConn) readLoop() {
cc: cc,
activeRes: make(map[uint32]*http2clientStream),
}
- rl.hdec = hpack.NewDecoder(http2initialHeaderTableSize, rl.onNewHeaderField)
defer rl.cleanup()
cc.readerErr = rl.run()
@@ -5549,17 +6574,48 @@ func (cc *http2ClientConn) readLoop() {
}
}
+// GoAwayError is returned by the Transport when the server closes the
+// TCP connection after sending a GOAWAY frame.
+type http2GoAwayError struct {
+ LastStreamID uint32
+ ErrCode http2ErrCode
+ DebugData string
+}
+
+func (e http2GoAwayError) Error() string {
+ return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
+ e.LastStreamID, e.ErrCode, e.DebugData)
+}
+
+func http2isEOFOrNetReadError(err error) bool {
+ if err == io.EOF {
+ return true
+ }
+ ne, ok := err.(*net.OpError)
+ return ok && ne.Op == "read"
+}
+
func (rl *http2clientConnReadLoop) cleanup() {
cc := rl.cc
defer cc.tconn.Close()
defer cc.t.connPool().MarkDead(cc)
defer close(cc.readerDone)
+ if cc.idleTimer != nil {
+ cc.idleTimer.Stop()
+ }
+
err := cc.readerErr
- if err == io.EOF {
+ cc.mu.Lock()
+ if cc.goAway != nil && http2isEOFOrNetReadError(err) {
+ err = http2GoAwayError{
+ LastStreamID: cc.goAway.LastStreamID,
+ ErrCode: cc.goAway.ErrCode,
+ DebugData: cc.goAwayDebug,
+ }
+ } else if err == io.EOF {
err = io.ErrUnexpectedEOF
}
- cc.mu.Lock()
for _, cs := range rl.activeRes {
cs.bufPipe.CloseWithError(err)
}
@@ -5577,32 +6633,43 @@ func (rl *http2clientConnReadLoop) cleanup() {
func (rl *http2clientConnReadLoop) run() error {
cc := rl.cc
- rl.closeWhenIdle = cc.t.disableKeepAlives()
+ rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
gotReply := false
+ gotSettings := false
for {
f, err := cc.fr.ReadFrame()
if err != nil {
- cc.vlogf("Transport readFrame error: (%T) %v", err, err)
+ cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
}
if se, ok := err.(http2StreamError); ok {
-
- return se
+ if cs := cc.streamByID(se.StreamID, true); cs != nil {
+ cs.cc.writeStreamReset(cs.ID, se.Code, err)
+ if se.Cause == nil {
+ se.Cause = cc.fr.errDetail
+ }
+ rl.endStreamError(cs, se)
+ }
+ continue
} else if err != nil {
return err
}
if http2VerboseLogs {
cc.vlogf("http2: Transport received %s", http2summarizeFrame(f))
}
+ if !gotSettings {
+ if _, ok := f.(*http2SettingsFrame); !ok {
+ cc.logf("protocol error: received %T before a SETTINGS frame", f)
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ gotSettings = true
+ }
maybeIdle := false
switch f := f.(type) {
- case *http2HeadersFrame:
+ case *http2MetaHeadersFrame:
err = rl.processHeaders(f)
maybeIdle = true
gotReply = true
- case *http2ContinuationFrame:
- err = rl.processContinuation(f)
- maybeIdle = true
case *http2DataFrame:
err = rl.processData(f)
maybeIdle = true
@@ -5624,6 +6691,9 @@ func (rl *http2clientConnReadLoop) run() error {
cc.logf("Transport: unhandled response frame type %T", f)
}
if err != nil {
+ if http2VerboseLogs {
+ cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, http2summarizeFrame(f), err)
+ }
return err
}
if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
@@ -5632,83 +6702,105 @@ func (rl *http2clientConnReadLoop) run() error {
}
}
-func (rl *http2clientConnReadLoop) processHeaders(f *http2HeadersFrame) error {
- rl.sawRegHeader = false
- rl.reqMalformed = nil
- rl.lastHeaderEndsStream = f.StreamEnded()
- rl.headerListSize = 0
- rl.nextRes = &Response{
- Proto: "HTTP/2.0",
- ProtoMajor: 2,
- Header: make(Header),
- }
- rl.hdec.SetEmitEnabled(true)
- return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *http2clientConnReadLoop) processContinuation(f *http2ContinuationFrame) error {
- return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID uint32, finalFrag bool) error {
+func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error {
cc := rl.cc
- streamEnded := rl.lastHeaderEndsStream
- cs := cc.streamByID(streamID, streamEnded && finalFrag)
+ cs := cc.streamByID(f.StreamID, f.StreamEnded())
if cs == nil {
return nil
}
- if cs.pastHeaders {
- rl.hdec.SetEmitFunc(func(f hpack.HeaderField) { rl.onNewTrailerField(cs, f) })
- } else {
- rl.hdec.SetEmitFunc(rl.onNewHeaderField)
- }
- _, err := rl.hdec.Write(frag)
- if err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
- }
- if finalFrag {
- if err := rl.hdec.Close(); err != nil {
- return http2ConnectionError(http2ErrCodeCompression)
- }
- }
+ if !cs.firstByte {
+ if cs.trace != nil {
- if !finalFrag {
- return nil
+ http2traceFirstResponseByte(cs.trace)
+ }
+ cs.firstByte = true
}
-
if !cs.pastHeaders {
cs.pastHeaders = true
} else {
+ return rl.processTrailers(cs, f)
+ }
- if cs.pastTrailers {
-
- return http2ConnectionError(http2ErrCodeProtocol)
+ res, err := rl.handleResponse(cs, f)
+ if err != nil {
+ if _, ok := err.(http2ConnectionError); ok {
+ return err
}
- cs.pastTrailers = true
- if !streamEnded {
- return http2ConnectionError(http2ErrCodeProtocol)
- }
- rl.endStream(cs)
+ cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err)
+ cs.resc <- http2resAndError{err: err}
return nil
}
+ if res == nil {
- if rl.reqMalformed != nil {
- cs.resc <- http2resAndError{err: rl.reqMalformed}
- rl.cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, rl.reqMalformed)
return nil
}
+ if res.Body != http2noBody {
+ rl.activeRes[cs.ID] = cs
+ }
+ cs.resTrailer = &res.Trailer
+ cs.resc <- http2resAndError{res: res}
+ return nil
+}
- res := rl.nextRes
+// may return error types nil, or ConnectionError. Any other error value
+// is a StreamError of type ErrCodeProtocol. The returned error in that case
+// is the detail.
+//
+// As a special case, handleResponse may return (nil, nil) to skip the
+// frame (currently only used for 100 expect continue). This special
+// case is going away after Issue 13851 is fixed.
+func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http2MetaHeadersFrame) (*Response, error) {
+ if f.Truncated {
+ return nil, http2errResponseHeaderListSize
+ }
- if res.StatusCode == 100 {
+ status := f.PseudoValue("status")
+ if status == "" {
+ return nil, errors.New("missing status pseudo header")
+ }
+ statusCode, err := strconv.Atoi(status)
+ if err != nil {
+ return nil, errors.New("malformed non-numeric status pseudo header")
+ }
+ if statusCode == 100 {
+ http2traceGot100Continue(cs.trace)
+ if cs.on100 != nil {
+ cs.on100()
+ }
cs.pastHeaders = false
- return nil
+ return nil, nil
}
- if !streamEnded || cs.req.Method == "HEAD" {
+ header := make(Header)
+ res := &Response{
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ Header: header,
+ StatusCode: statusCode,
+ Status: status + " " + StatusText(statusCode),
+ }
+ for _, hf := range f.RegularFields() {
+ key := CanonicalHeaderKey(hf.Name)
+ if key == "Trailer" {
+ t := res.Trailer
+ if t == nil {
+ t = make(Header)
+ res.Trailer = t
+ }
+ http2foreachHeaderElement(hf.Value, func(v string) {
+ t[CanonicalHeaderKey(v)] = nil
+ })
+ } else {
+ header[key] = append(header[key], hf.Value)
+ }
+ }
+
+ streamEnded := f.StreamEnded()
+ isHead := cs.req.Method == "HEAD"
+ if !streamEnded || isHead {
res.ContentLength = -1
if clens := res.Header["Content-Length"]; len(clens) == 1 {
if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
@@ -5721,27 +6813,50 @@ func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, strea
}
}
- if streamEnded {
+ if streamEnded || isHead {
res.Body = http2noBody
- } else {
- buf := new(bytes.Buffer)
- cs.bufPipe = http2pipe{b: buf}
- cs.bytesRemain = res.ContentLength
- res.Body = http2transportResponseBody{cs}
- go cs.awaitRequestCancel(http2requestCancel(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}
- }
- rl.activeRes[cs.ID] = cs
+ return res, nil
}
- cs.resTrailer = &res.Trailer
- cs.resc <- http2resAndError{res: res}
- rl.nextRes = nil
+ buf := new(bytes.Buffer)
+ cs.bufPipe = http2pipe{b: buf}
+ cs.bytesRemain = res.ContentLength
+ res.Body = http2transportResponseBody{cs}
+ 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
+}
+
+func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *http2MetaHeadersFrame) error {
+ if cs.pastTrailers {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ cs.pastTrailers = true
+ if !f.StreamEnded() {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ if len(f.PseudoFields()) > 0 {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+
+ trailer := make(Header)
+ for _, hf := range f.RegularFields() {
+ key := CanonicalHeaderKey(hf.Name)
+ trailer[key] = append(trailer[key], hf.Value)
+ }
+ cs.trailer = trailer
+
+ rl.endStream(cs)
return nil
}
@@ -5792,8 +6907,10 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
cc.inflow.add(connAdd)
}
if err == nil {
- if v := cs.inflow.available(); v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
- streamAdd = http2transportDefaultStreamFlow - v
+
+ v := int(cs.inflow.available()) + cs.bufPipe.Len()
+ if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
+ streamAdd = int32(http2transportDefaultStreamFlow - v)
cs.inflow.add(streamAdd)
}
}
@@ -5815,10 +6932,27 @@ var http2errClosedResponseBody = errors.New("http2: response body closed")
func (b http2transportResponseBody) Close() error {
cs := b.cs
- if cs.bufPipe.Err() != io.EOF {
+ cc := cs.cc
- cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
+ unread := cs.bufPipe.Len()
+
+ if unread > 0 || !serverSentStreamEnd {
+ cc.mu.Lock()
+ cc.wmu.Lock()
+ if !serverSentStreamEnd {
+ cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel)
+ }
+
+ if unread > 0 {
+ cc.inflow.add(int32(unread))
+ cc.fr.WriteWindowUpdate(0, uint32(unread))
+ }
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ cc.mu.Unlock()
}
+
cs.bufPipe.BreakWithError(http2errClosedResponseBody)
return nil
}
@@ -5826,6 +6960,7 @@ func (b http2transportResponseBody) Close() error {
func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
cc := rl.cc
cs := cc.streamByID(f.StreamID, f.StreamEnded())
+ data := f.Data()
if cs == nil {
cc.mu.Lock()
neverSent := cc.nextStreamID
@@ -5836,26 +6971,50 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
+ if f.Length > 0 {
+ cc.mu.Lock()
+ cc.inflow.add(int32(f.Length))
+ cc.mu.Unlock()
+
+ cc.wmu.Lock()
+ cc.fr.WriteWindowUpdate(0, uint32(f.Length))
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ }
return nil
}
- if data := f.Data(); len(data) > 0 {
- if cs.bufPipe.b == nil {
+ if f.Length > 0 {
+ if len(data) > 0 && cs.bufPipe.b == nil {
cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
return http2ConnectionError(http2ErrCodeProtocol)
}
cc.mu.Lock()
- if cs.inflow.available() >= int32(len(data)) {
- cs.inflow.take(int32(len(data)))
+ if cs.inflow.available() >= int32(f.Length) {
+ cs.inflow.take(int32(f.Length))
} else {
cc.mu.Unlock()
return http2ConnectionError(http2ErrCodeFlowControl)
}
+
+ if pad := int32(f.Length) - int32(len(data)); pad > 0 {
+ cs.inflow.add(pad)
+ cc.inflow.add(pad)
+ cc.wmu.Lock()
+ cc.fr.WriteWindowUpdate(0, uint32(pad))
+ cc.fr.WriteWindowUpdate(cs.ID, uint32(pad))
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ }
+ didReset := cs.didReset
cc.mu.Unlock()
- if _, err := cs.bufPipe.Write(data); err != nil {
- return err
+ if len(data) > 0 && !didReset {
+ if _, err := cs.bufPipe.Write(data); err != nil {
+ rl.endStreamError(cs, err)
+ return err
+ }
}
}
@@ -5869,17 +7028,25 @@ var http2errInvalidTrailers = errors.New("http2: invalid trailers")
func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
- err := io.EOF
- code := cs.copyTrailers
- if rl.reqMalformed != nil {
- err = rl.reqMalformed
- code = nil
+ rl.endStreamError(cs, nil)
+}
+
+func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err error) {
+ var code func()
+ if err == nil {
+ err = io.EOF
+ code = cs.copyTrailers
}
cs.bufPipe.closeWithErrorAndCode(err, code)
delete(rl.activeRes, cs.ID)
- if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
+ if http2isConnectionCloseRequest(cs.req) {
rl.closeWhenIdle = true
}
+
+ select {
+ case cs.resc <- http2resAndError{err: err}:
+ default:
+ }
}
func (cs *http2clientStream) copyTrailers() {
@@ -5907,7 +7074,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
cc := rl.cc
cc.mu.Lock()
defer cc.mu.Unlock()
- return f.ForeachSetting(func(s http2Setting) error {
+
+ if f.IsAck() {
+ if cc.wantSettingsAck {
+ cc.wantSettingsAck = false
+ return nil
+ }
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+
+ err := f.ForeachSetting(func(s http2Setting) error {
switch s.ID {
case http2SettingMaxFrameSize:
cc.maxFrameSize = s.Val
@@ -5915,6 +7091,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
cc.maxConcurrentStreams = s.Val
case http2SettingInitialWindowSize:
+ if s.Val > math.MaxInt32 {
+ return http2ConnectionError(http2ErrCodeFlowControl)
+ }
+
+ delta := int32(s.Val) - int32(cc.initialWindowSize)
+ for _, cs := range cc.streams {
+ cs.flow.add(delta)
+ }
+ cc.cond.Broadcast()
+
cc.initialWindowSize = s.Val
default:
@@ -5922,6 +7108,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
}
return nil
})
+ if err != nil {
+ return err
+ }
+
+ cc.wmu.Lock()
+ defer cc.wmu.Unlock()
+
+ cc.fr.WriteSettingsAck()
+ cc.bw.Flush()
+ return cc.werr
}
func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error {
@@ -5955,7 +7151,7 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
case <-cs.peerReset:
default:
- err := http2StreamError{cs.ID, f.ErrCode}
+ err := http2streamError(cs.ID, f.ErrCode)
cs.resetErr = err
close(cs.peerReset)
cs.bufPipe.CloseWithError(err)
@@ -5965,9 +7161,56 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
return nil
}
+// Ping sends a PING frame to the server and waits for the ack.
+// Public implementation is in go17.go and not_go17.go
+func (cc *http2ClientConn) ping(ctx http2contextContext) error {
+ c := make(chan struct{})
+ // Generate a random payload
+ var p [8]byte
+ for {
+ if _, err := rand.Read(p[:]); err != nil {
+ return err
+ }
+ cc.mu.Lock()
+
+ if _, found := cc.pings[p]; !found {
+ cc.pings[p] = c
+ cc.mu.Unlock()
+ break
+ }
+ cc.mu.Unlock()
+ }
+ cc.wmu.Lock()
+ if err := cc.fr.WritePing(false, p); err != nil {
+ cc.wmu.Unlock()
+ return err
+ }
+ if err := cc.bw.Flush(); err != nil {
+ cc.wmu.Unlock()
+ return err
+ }
+ cc.wmu.Unlock()
+ select {
+ case <-c:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-cc.readerDone:
+
+ return cc.readerErr
+ }
+}
+
func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
if f.IsAck() {
+ cc := rl.cc
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
+ if c, ok := cc.pings[f.Data]; ok {
+ close(c)
+ delete(cc.pings, f.Data)
+ }
return nil
}
cc := rl.cc
@@ -5997,113 +7240,6 @@ var (
http2errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers")
)
-func (rl *http2clientConnReadLoop) checkHeaderField(f hpack.HeaderField) bool {
- if rl.reqMalformed != nil {
- return false
- }
-
- const headerFieldOverhead = 32 // per spec
- rl.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
- if max := rl.cc.t.maxHeaderListSize(); max != 0 && rl.headerListSize > int64(max) {
- rl.hdec.SetEmitEnabled(false)
- rl.reqMalformed = http2errResponseHeaderListSize
- return false
- }
-
- if !http2validHeaderFieldValue(f.Value) {
- rl.reqMalformed = http2errInvalidHeaderFieldValue
- return false
- }
-
- isPseudo := strings.HasPrefix(f.Name, ":")
- if isPseudo {
- if rl.sawRegHeader {
- rl.reqMalformed = errors.New("http2: invalid pseudo header after regular header")
- return false
- }
- } else {
- if !http2validHeaderFieldName(f.Name) {
- rl.reqMalformed = http2errInvalidHeaderFieldName
- return false
- }
- rl.sawRegHeader = true
- }
-
- return true
-}
-
-// onNewHeaderField runs on the readLoop goroutine whenever a new
-// hpack header field is decoded.
-func (rl *http2clientConnReadLoop) onNewHeaderField(f hpack.HeaderField) {
- cc := rl.cc
- if http2VerboseLogs {
- cc.logf("http2: Transport decoded %v", f)
- }
-
- if !rl.checkHeaderField(f) {
- return
- }
-
- isPseudo := strings.HasPrefix(f.Name, ":")
- if isPseudo {
- switch f.Name {
- case ":status":
- code, err := strconv.Atoi(f.Value)
- if err != nil {
- rl.reqMalformed = errors.New("http2: invalid :status")
- return
- }
- rl.nextRes.Status = f.Value + " " + StatusText(code)
- rl.nextRes.StatusCode = code
- default:
-
- rl.reqMalformed = fmt.Errorf("http2: unknown response pseudo header %q", f.Name)
- }
- return
- }
-
- key := CanonicalHeaderKey(f.Name)
- if key == "Trailer" {
- t := rl.nextRes.Trailer
- if t == nil {
- t = make(Header)
- rl.nextRes.Trailer = t
- }
- http2foreachHeaderElement(f.Value, func(v string) {
- t[CanonicalHeaderKey(v)] = nil
- })
- } else {
- rl.nextRes.Header.Add(key, f.Value)
- }
-}
-
-func (rl *http2clientConnReadLoop) onNewTrailerField(cs *http2clientStream, f hpack.HeaderField) {
- if http2VerboseLogs {
- rl.cc.logf("http2: Transport decoded trailer %v", f)
- }
- if !rl.checkHeaderField(f) {
- return
- }
- if strings.HasPrefix(f.Name, ":") {
-
- rl.reqMalformed = http2errPseudoTrailers
- return
- }
-
- key := CanonicalHeaderKey(f.Name)
-
- // The spec says one must predeclare their trailers but in practice
- // popular users (which is to say the only user we found) do not so we
- // violate the spec and accept all of them.
- const acceptAllTrailers = true
- if _, ok := (*cs.resTrailer)[key]; ok || acceptAllTrailers {
- if cs.trailer == nil {
- cs.trailer = make(Header)
- }
- cs.trailer[key] = append(cs.trailer[key], f.Value)
- }
-}
-
func (cc *http2ClientConn) logf(format string, args ...interface{}) {
cc.t.logf(format, args...)
}
@@ -6167,9 +7303,96 @@ 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() {
+ cs.cc.mu.Lock()
+ cs.startedWrite = true
+ cs.cc.mu.Unlock()
+ 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)
+ }
+}
+
+// isConnectionCloseRequest reports whether req should use its own
+// connection for a single request and then close the connection.
+func http2isConnectionCloseRequest(req *Request) bool {
+ return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
+}
+
// writeFramer is implemented by any type that is used to write frames.
type http2writeFramer interface {
writeFrame(http2writeContext) error
+
+ // staysWithinBuffer reports whether this writer promises that
+ // it will only write less than or equal to size bytes, and it
+ // won't Flush the write context.
+ staysWithinBuffer(size int) bool
}
// writeContext is the interface needed by the various frame writer
@@ -6191,9 +7414,10 @@ type http2writeContext interface {
HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
}
-// endsStream reports whether the given frame writer w will locally
-// close the stream.
-func http2endsStream(w http2writeFramer) bool {
+// writeEndsStream reports whether w writes a frame that will transition
+// the stream to a half-closed local state. This returns false for RST_STREAM,
+// which closes the entire stream (not just the local half).
+func http2writeEndsStream(w http2writeFramer) bool {
switch v := w.(type) {
case *http2writeData:
return v.endStream
@@ -6201,7 +7425,7 @@ func http2endsStream(w http2writeFramer) bool {
return v.endStream
case nil:
- panic("endsStream called on nil writeFramer")
+ panic("writeEndsStream called on nil writeFramer")
}
return false
}
@@ -6212,8 +7436,16 @@ func (http2flushFrameWriter) writeFrame(ctx http2writeContext) error {
return ctx.Flush()
}
+func (http2flushFrameWriter) staysWithinBuffer(max int) bool { return false }
+
type http2writeSettings []http2Setting
+func (s http2writeSettings) staysWithinBuffer(max int) bool {
+ const settingSize = 6 // uint16 + uint32
+ return http2frameHeaderLen+settingSize*len(s) <= max
+
+}
+
func (s http2writeSettings) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteSettings([]http2Setting(s)...)
}
@@ -6233,6 +7465,8 @@ func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error {
return err
}
+func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false }
+
type http2writeData struct {
streamID uint32
p []byte
@@ -6247,6 +7481,10 @@ func (w *http2writeData) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
}
+func (w *http2writeData) staysWithinBuffer(max int) bool {
+ return http2frameHeaderLen+len(w.p) <= max
+}
+
// handlerPanicRST is the message sent from handler goroutines when
// the handler panics.
type http2handlerPanicRST struct {
@@ -6257,22 +7495,59 @@ func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal)
}
+func (hp http2handlerPanicRST) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
func (se http2StreamError) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
}
+func (se http2StreamError) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
type http2writePingAck struct{ pf *http2PingFrame }
func (w http2writePingAck) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WritePing(true, w.pf.Data)
}
+func (w http2writePingAck) staysWithinBuffer(max int) bool {
+ return http2frameHeaderLen+len(w.pf.Data) <= max
+}
+
type http2writeSettingsAck struct{}
func (http2writeSettingsAck) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteSettingsAck()
}
+func (http2writeSettingsAck) staysWithinBuffer(max int) bool { return http2frameHeaderLen <= max }
+
+// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
+// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
+// for the first/last fragment, respectively.
+func http2splitHeaderBlock(ctx http2writeContext, headerBlock []byte, fn func(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
+ // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
+ // that all peers must support (16KB). Later we could care
+ // more and send larger frames if the peer advertised it, but
+ // there's little point. Most headers are small anyway (so we
+ // generally won't have CONTINUATION frames), and extra frames
+ // only waste 9 bytes anyway.
+ const maxFrameSize = 16384
+
+ first := true
+ for len(headerBlock) > 0 {
+ frag := headerBlock
+ if len(frag) > maxFrameSize {
+ frag = frag[:maxFrameSize]
+ }
+ headerBlock = headerBlock[len(frag):]
+ if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
+ return err
+ }
+ first = false
+ }
+ return nil
+}
+
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
// for HTTP response headers or trailers from a server handler.
type http2writeResHeaders struct {
@@ -6294,6 +7569,11 @@ func http2encKV(enc *hpack.Encoder, k, v string) {
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
}
+func (w *http2writeResHeaders) staysWithinBuffer(max int) bool {
+
+ return false
+}
+
func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
enc, buf := ctx.HeaderEncoder()
buf.Reset()
@@ -6319,39 +7599,69 @@ func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
panic("unexpected empty hpack")
}
- // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
- // that all peers must support (16KB). Later we could care
- // more and send larger frames if the peer advertised it, but
- // there's little point. Most headers are small anyway (so we
- // generally won't have CONTINUATION frames), and extra frames
- // only waste 9 bytes anyway.
- const maxFrameSize = 16384
+ return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
+}
- first := true
- for len(headerBlock) > 0 {
- frag := headerBlock
- if len(frag) > maxFrameSize {
- frag = frag[:maxFrameSize]
- }
- headerBlock = headerBlock[len(frag):]
- endHeaders := len(headerBlock) == 0
- var err error
- if first {
- first = false
- err = ctx.Framer().WriteHeaders(http2HeadersFrameParam{
- StreamID: w.streamID,
- BlockFragment: frag,
- EndStream: w.endStream,
- EndHeaders: endHeaders,
- })
- } else {
- err = ctx.Framer().WriteContinuation(w.streamID, endHeaders, frag)
- }
- if err != nil {
- return err
- }
+func (w *http2writeResHeaders) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
+ if firstFrag {
+ return ctx.Framer().WriteHeaders(http2HeadersFrameParam{
+ StreamID: w.streamID,
+ BlockFragment: frag,
+ EndStream: w.endStream,
+ EndHeaders: lastFrag,
+ })
+ } else {
+ return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
+ }
+}
+
+// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
+type http2writePushPromise struct {
+ streamID uint32 // pusher stream
+ method string // for :method
+ url *url.URL // for :scheme, :authority, :path
+ h Header
+
+ // Creates an ID for a pushed stream. This runs on serveG just before
+ // the frame is written. The returned ID is copied to promisedID.
+ allocatePromisedID func() (uint32, error)
+ promisedID uint32
+}
+
+func (w *http2writePushPromise) staysWithinBuffer(max int) bool {
+
+ return false
+}
+
+func (w *http2writePushPromise) writeFrame(ctx http2writeContext) error {
+ enc, buf := ctx.HeaderEncoder()
+ buf.Reset()
+
+ http2encKV(enc, ":method", w.method)
+ http2encKV(enc, ":scheme", w.url.Scheme)
+ http2encKV(enc, ":authority", w.url.Host)
+ http2encKV(enc, ":path", w.url.RequestURI())
+ http2encodeHeaders(enc, w.h, nil)
+
+ headerBlock := buf.Bytes()
+ if len(headerBlock) == 0 {
+ panic("unexpected empty hpack")
+ }
+
+ return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
+}
+
+func (w *http2writePushPromise) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
+ if firstFrag {
+ return ctx.Framer().WritePushPromise(http2PushPromiseParam{
+ StreamID: w.streamID,
+ PromiseID: w.promisedID,
+ BlockFragment: frag,
+ EndHeaders: lastFrag,
+ })
+ } else {
+ return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
}
- return nil
}
type http2write100ContinueHeadersFrame struct {
@@ -6370,34 +7680,41 @@ func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) err
})
}
+func (w http2write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
+
+ return 9+2*(len(":status")+len("100")) <= max
+}
+
type http2writeWindowUpdate struct {
streamID uint32 // or 0 for conn-level
n uint32
}
+func (wu http2writeWindowUpdate) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
}
+// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
+// is encoded only only if k is in keys.
func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
-
if keys == nil {
- keys = make([]string, 0, len(h))
- for k := range h {
- keys = append(keys, k)
- }
- sort.Strings(keys)
+ sorter := http2sorterPool.Get().(*http2sorter)
+
+ defer http2sorterPool.Put(sorter)
+ keys = sorter.Keys(h)
}
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
}
@@ -6410,14 +7727,53 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
}
}
-// frameWriteMsg is a request to write a frame.
-type http2frameWriteMsg struct {
+// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
+// Methods are never called concurrently.
+type http2WriteScheduler interface {
+ // OpenStream opens a new stream in the write scheduler.
+ // It is illegal to call this with streamID=0 or with a streamID that is
+ // already open -- the call may panic.
+ OpenStream(streamID uint32, options http2OpenStreamOptions)
+
+ // CloseStream closes a stream in the write scheduler. Any frames queued on
+ // this stream should be discarded. It is illegal to call this on a stream
+ // that is not open -- the call may panic.
+ CloseStream(streamID uint32)
+
+ // AdjustStream adjusts the priority of the given stream. This may be called
+ // on a stream that has not yet been opened or has been closed. Note that
+ // RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
+ // https://tools.ietf.org/html/rfc7540#section-5.1
+ AdjustStream(streamID uint32, priority http2PriorityParam)
+
+ // Push queues a frame in the scheduler. In most cases, this will not be
+ // called with wr.StreamID()!=0 unless that stream is currently open. The one
+ // exception is RST_STREAM frames, which may be sent on idle or closed streams.
+ Push(wr http2FrameWriteRequest)
+
+ // Pop dequeues the next frame to write. Returns false if no frames can
+ // be written. Frames with a given wr.StreamID() are Pop'd in the same
+ // order they are Push'd.
+ Pop() (wr http2FrameWriteRequest, ok bool)
+}
+
+// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
+type http2OpenStreamOptions struct {
+ // PusherID is zero if the stream was initiated by the client. Otherwise,
+ // PusherID names the stream that pushed the newly opened stream.
+ PusherID uint32
+}
+
+// FrameWriteRequest is a request to write a frame.
+type http2FrameWriteRequest struct {
// write is the interface value that does the writing, once the
- // writeScheduler (below) has decided to select this frame
- // to write. The write functions are all defined in write.go.
+ // WriteScheduler has selected this frame to write. The write
+ // functions are all defined in write.go.
write http2writeFramer
- stream *http2stream // used for prioritization. nil for non-stream frames.
+ // stream is the stream on which this frame will be written.
+ // nil for non-stream frames like PING and SETTINGS.
+ stream *http2stream
// done, if non-nil, must be a buffered channel with space for
// 1 message and is sent the return value from write (or an
@@ -6425,247 +7781,644 @@ type http2frameWriteMsg struct {
done chan error
}
-// for debugging only:
-func (wm http2frameWriteMsg) String() string {
- var streamID uint32
- if wm.stream != nil {
- streamID = wm.stream.id
+// StreamID returns the id of the stream this frame will be written to.
+// 0 is used for non-stream frames such as PING and SETTINGS.
+func (wr http2FrameWriteRequest) StreamID() uint32 {
+ if wr.stream == nil {
+ if se, ok := wr.write.(http2StreamError); ok {
+
+ return se.StreamID
+ }
+ return 0
+ }
+ return wr.stream.id
+}
+
+// DataSize returns the number of flow control bytes that must be consumed
+// to write this entire frame. This is 0 for non-DATA frames.
+func (wr http2FrameWriteRequest) DataSize() int {
+ if wd, ok := wr.write.(*http2writeData); ok {
+ return len(wd.p)
+ }
+ return 0
+}
+
+// Consume consumes min(n, available) bytes from this frame, where available
+// is the number of flow control bytes available on the stream. Consume returns
+// 0, 1, or 2 frames, where the integer return value gives the number of frames
+// returned.
+//
+// If flow control prevents consuming any bytes, this returns (_, _, 0). If
+// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
+// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
+// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
+// underlying stream's flow control budget.
+func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) {
+ var empty http2FrameWriteRequest
+
+ wd, ok := wr.write.(*http2writeData)
+ if !ok || len(wd.p) == 0 {
+ return wr, empty, 1
+ }
+
+ allowed := wr.stream.flow.available()
+ if n < allowed {
+ allowed = n
+ }
+ if wr.stream.sc.maxFrameSize < allowed {
+ allowed = wr.stream.sc.maxFrameSize
+ }
+ if allowed <= 0 {
+ return empty, empty, 0
+ }
+ if len(wd.p) > int(allowed) {
+ wr.stream.flow.take(allowed)
+ consumed := http2FrameWriteRequest{
+ stream: wr.stream,
+ write: &http2writeData{
+ streamID: wd.streamID,
+ p: wd.p[:allowed],
+
+ endStream: false,
+ },
+
+ done: nil,
+ }
+ rest := http2FrameWriteRequest{
+ stream: wr.stream,
+ write: &http2writeData{
+ streamID: wd.streamID,
+ p: wd.p[allowed:],
+ endStream: wd.endStream,
+ },
+ done: wr.done,
+ }
+ return consumed, rest, 2
}
+
+ wr.stream.flow.take(int32(len(wd.p)))
+ return wr, empty, 1
+}
+
+// String is for debugging only.
+func (wr http2FrameWriteRequest) String() string {
var des string
- if s, ok := wm.write.(fmt.Stringer); ok {
+ if s, ok := wr.write.(fmt.Stringer); ok {
des = s.String()
} else {
- des = fmt.Sprintf("%T", wm.write)
+ des = fmt.Sprintf("%T", wr.write)
}
- return fmt.Sprintf("[frameWriteMsg stream=%d, ch=%v, type: %v]", streamID, wm.done != nil, des)
+ return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
}
-// writeScheduler tracks pending frames to write, priorities, and decides
-// the next one to use. It is not thread-safe.
-type http2writeScheduler struct {
- // zero are frames not associated with a specific stream.
- // They're sent before any stream-specific freams.
- zero http2writeQueue
+// replyToWriter sends err to wr.done and panics if the send must block
+// This does nothing if wr.done is nil.
+func (wr *http2FrameWriteRequest) replyToWriter(err error) {
+ if wr.done == nil {
+ return
+ }
+ select {
+ case wr.done <- err:
+ default:
+ panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
+ }
+ wr.write = nil
+}
- // maxFrameSize is the maximum size of a DATA frame
- // we'll write. Must be non-zero and between 16K-16M.
- maxFrameSize uint32
+// writeQueue is used by implementations of WriteScheduler.
+type http2writeQueue struct {
+ s []http2FrameWriteRequest
+}
- // sq contains the stream-specific queues, keyed by stream ID.
- // when a stream is idle, it's deleted from the map.
- sq map[uint32]*http2writeQueue
+func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }
- // canSend is a slice of memory that's reused between frame
- // scheduling decisions to hold the list of writeQueues (from sq)
- // which have enough flow control data to send. After canSend is
- // built, the best is selected.
- canSend []*http2writeQueue
+func (q *http2writeQueue) push(wr http2FrameWriteRequest) {
+ q.s = append(q.s, wr)
+}
- // pool of empty queues for reuse.
- queuePool []*http2writeQueue
+func (q *http2writeQueue) shift() http2FrameWriteRequest {
+ if len(q.s) == 0 {
+ panic("invalid use of queue")
+ }
+ wr := q.s[0]
+
+ copy(q.s, q.s[1:])
+ q.s[len(q.s)-1] = http2FrameWriteRequest{}
+ q.s = q.s[:len(q.s)-1]
+ return wr
}
-func (ws *http2writeScheduler) putEmptyQueue(q *http2writeQueue) {
- if len(q.s) != 0 {
- panic("queue must be empty")
+// consume consumes up to n bytes from q.s[0]. If the frame is
+// entirely consumed, it is removed from the queue. If the frame
+// is partially consumed, the frame is kept with the consumed
+// bytes removed. Returns true iff any bytes were consumed.
+func (q *http2writeQueue) consume(n int32) (http2FrameWriteRequest, bool) {
+ if len(q.s) == 0 {
+ return http2FrameWriteRequest{}, false
+ }
+ consumed, rest, numresult := q.s[0].Consume(n)
+ switch numresult {
+ case 0:
+ return http2FrameWriteRequest{}, false
+ case 1:
+ q.shift()
+ case 2:
+ q.s[0] = rest
}
- ws.queuePool = append(ws.queuePool, q)
+ return consumed, true
}
-func (ws *http2writeScheduler) getEmptyQueue() *http2writeQueue {
- ln := len(ws.queuePool)
+type http2writeQueuePool []*http2writeQueue
+
+// put inserts an unused writeQueue into the pool.
+func (p *http2writeQueuePool) put(q *http2writeQueue) {
+ for i := range q.s {
+ q.s[i] = http2FrameWriteRequest{}
+ }
+ q.s = q.s[:0]
+ *p = append(*p, q)
+}
+
+// get returns an empty writeQueue.
+func (p *http2writeQueuePool) get() *http2writeQueue {
+ ln := len(*p)
if ln == 0 {
return new(http2writeQueue)
}
- q := ws.queuePool[ln-1]
- ws.queuePool = ws.queuePool[:ln-1]
+ x := ln - 1
+ q := (*p)[x]
+ (*p)[x] = nil
+ *p = (*p)[:x]
return q
}
-func (ws *http2writeScheduler) empty() bool { return ws.zero.empty() && len(ws.sq) == 0 }
+// RFC 7540, Section 5.3.5: the default weight is 16.
+const http2priorityDefaultWeight = 15 // 16 = 15 + 1
-func (ws *http2writeScheduler) add(wm http2frameWriteMsg) {
- st := wm.stream
- if st == nil {
- ws.zero.push(wm)
+// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
+type http2PriorityWriteSchedulerConfig struct {
+ // MaxClosedNodesInTree controls the maximum number of closed streams to
+ // retain in the priority tree. Setting this to zero saves a small amount
+ // of memory at the cost of performance.
+ //
+ // See RFC 7540, Section 5.3.4:
+ // "It is possible for a stream to become closed while prioritization
+ // information ... is in transit. ... This potentially creates suboptimal
+ // prioritization, since the stream could be given a priority that is
+ // different from what is intended. To avoid these problems, an endpoint
+ // SHOULD retain stream prioritization state for a period after streams
+ // become closed. The longer state is retained, the lower the chance that
+ // streams are assigned incorrect or default priority values."
+ MaxClosedNodesInTree int
+
+ // MaxIdleNodesInTree controls the maximum number of idle streams to
+ // retain in the priority tree. Setting this to zero saves a small amount
+ // of memory at the cost of performance.
+ //
+ // See RFC 7540, Section 5.3.4:
+ // Similarly, streams that are in the "idle" state can be assigned
+ // priority or become a parent of other streams. This allows for the
+ // creation of a grouping node in the dependency tree, which enables
+ // more flexible expressions of priority. Idle streams begin with a
+ // default priority (Section 5.3.5).
+ MaxIdleNodesInTree int
+
+ // ThrottleOutOfOrderWrites enables write throttling to help ensure that
+ // data is delivered in priority order. This works around a race where
+ // stream B depends on stream A and both streams are about to call Write
+ // to queue DATA frames. If B wins the race, a naive scheduler would eagerly
+ // write as much data from B as possible, but this is suboptimal because A
+ // is a higher-priority stream. With throttling enabled, we write a small
+ // amount of data from B to minimize the amount of bandwidth that B can
+ // steal from A.
+ ThrottleOutOfOrderWrites bool
+}
+
+// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
+// frames by following HTTP/2 priorities as described in RFC 7340 Section 5.3.
+// If cfg is nil, default options are used.
+func http2NewPriorityWriteScheduler(cfg *http2PriorityWriteSchedulerConfig) http2WriteScheduler {
+ if cfg == nil {
+
+ cfg = &http2PriorityWriteSchedulerConfig{
+ MaxClosedNodesInTree: 10,
+ MaxIdleNodesInTree: 10,
+ ThrottleOutOfOrderWrites: false,
+ }
+ }
+
+ ws := &http2priorityWriteScheduler{
+ nodes: make(map[uint32]*http2priorityNode),
+ maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
+ maxIdleNodesInTree: cfg.MaxIdleNodesInTree,
+ enableWriteThrottle: cfg.ThrottleOutOfOrderWrites,
+ }
+ ws.nodes[0] = &ws.root
+ if cfg.ThrottleOutOfOrderWrites {
+ ws.writeThrottleLimit = 1024
} else {
- ws.streamQueue(st.id).push(wm)
+ ws.writeThrottleLimit = math.MaxInt32
}
+ return ws
+}
+
+type http2priorityNodeState int
+
+const (
+ http2priorityNodeOpen http2priorityNodeState = iota
+ http2priorityNodeClosed
+ http2priorityNodeIdle
+)
+
+// priorityNode is a node in an HTTP/2 priority tree.
+// Each node is associated with a single stream ID.
+// See RFC 7540, Section 5.3.
+type http2priorityNode struct {
+ q http2writeQueue // queue of pending frames to write
+ id uint32 // id of the stream, or 0 for the root of the tree
+ weight uint8 // the actual weight is weight+1, so the value is in [1,256]
+ state http2priorityNodeState // open | closed | idle
+ bytes int64 // number of bytes written by this node, or 0 if closed
+ subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
+
+ // These links form the priority tree.
+ parent *http2priorityNode
+ kids *http2priorityNode // start of the kids list
+ prev, next *http2priorityNode // doubly-linked list of siblings
}
-func (ws *http2writeScheduler) streamQueue(streamID uint32) *http2writeQueue {
- if q, ok := ws.sq[streamID]; ok {
- return q
+func (n *http2priorityNode) setParent(parent *http2priorityNode) {
+ if n == parent {
+ panic("setParent to self")
}
- if ws.sq == nil {
- ws.sq = make(map[uint32]*http2writeQueue)
+ if n.parent == parent {
+ return
+ }
+
+ if parent := n.parent; parent != nil {
+ if n.prev == nil {
+ parent.kids = n.next
+ } else {
+ n.prev.next = n.next
+ }
+ if n.next != nil {
+ n.next.prev = n.prev
+ }
+ }
+
+ n.parent = parent
+ if parent == nil {
+ n.next = nil
+ n.prev = nil
+ } else {
+ n.next = parent.kids
+ n.prev = nil
+ if n.next != nil {
+ n.next.prev = n
+ }
+ parent.kids = n
}
- q := ws.getEmptyQueue()
- ws.sq[streamID] = q
- return q
}
-// take returns the most important frame to write and removes it from the scheduler.
-// It is illegal to call this if the scheduler is empty or if there are no connection-level
-// flow control bytes available.
-func (ws *http2writeScheduler) take() (wm http2frameWriteMsg, ok bool) {
- if ws.maxFrameSize == 0 {
- panic("internal error: ws.maxFrameSize not initialized or invalid")
+func (n *http2priorityNode) addBytes(b int64) {
+ n.bytes += b
+ for ; n != nil; n = n.parent {
+ n.subtreeBytes += b
}
+}
- if !ws.zero.empty() {
- return ws.zero.shift(), true
+// walkReadyInOrder iterates over the tree in priority order, calling f for each node
+// with a non-empty write queue. When f returns true, this funcion returns true and the
+// walk halts. tmp is used as scratch space for sorting.
+//
+// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
+// if any ancestor p of n is still open (ignoring the root node).
+func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2priorityNode, f func(*http2priorityNode, bool) bool) bool {
+ if !n.q.empty() && f(n, openParent) {
+ return true
}
- if len(ws.sq) == 0 {
- return
+ if n.kids == nil {
+ return false
}
- for id, q := range ws.sq {
- if q.firstIsNoCost() {
- return ws.takeFrom(id, q)
+ if n.id != 0 {
+ openParent = openParent || (n.state == http2priorityNodeOpen)
+ }
+
+ w := n.kids.weight
+ needSort := false
+ for k := n.kids.next; k != nil; k = k.next {
+ if k.weight != w {
+ needSort = true
+ break
}
}
+ if !needSort {
+ for k := n.kids; k != nil; k = k.next {
+ if k.walkReadyInOrder(openParent, tmp, f) {
+ return true
+ }
+ }
+ return false
+ }
- if len(ws.canSend) != 0 {
- panic("should be empty")
+ *tmp = (*tmp)[:0]
+ for n.kids != nil {
+ *tmp = append(*tmp, n.kids)
+ n.kids.setParent(nil)
}
- for _, q := range ws.sq {
- if n := ws.streamWritableBytes(q); n > 0 {
- ws.canSend = append(ws.canSend, q)
+ sort.Sort(http2sortPriorityNodeSiblings(*tmp))
+ for i := len(*tmp) - 1; i >= 0; i-- {
+ (*tmp)[i].setParent(n)
+ }
+ for k := n.kids; k != nil; k = k.next {
+ if k.walkReadyInOrder(openParent, tmp, f) {
+ return true
}
}
- if len(ws.canSend) == 0 {
- return
+ return false
+}
+
+type http2sortPriorityNodeSiblings []*http2priorityNode
+
+func (z http2sortPriorityNodeSiblings) Len() int { return len(z) }
+
+func (z http2sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] }
+
+func (z http2sortPriorityNodeSiblings) Less(i, k int) bool {
+
+ wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
+ wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
+ if bi == 0 && bk == 0 {
+ return wi >= wk
+ }
+ if bk == 0 {
+ return false
}
- defer ws.zeroCanSend()
+ return bi/bk <= wi/wk
+}
+
+type http2priorityWriteScheduler struct {
+ // root is the root of the priority tree, where root.id = 0.
+ // The root queues control frames that are not associated with any stream.
+ root http2priorityNode
+
+ // nodes maps stream ids to priority tree nodes.
+ nodes map[uint32]*http2priorityNode
+
+ // maxID is the maximum stream id in nodes.
+ maxID uint32
+
+ // lists of nodes that have been closed or are idle, but are kept in
+ // the tree for improved prioritization. When the lengths exceed either
+ // maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
+ closedNodes, idleNodes []*http2priorityNode
- q := ws.canSend[0]
+ // From the config.
+ maxClosedNodesInTree int
+ maxIdleNodesInTree int
+ writeThrottleLimit int32
+ enableWriteThrottle bool
- return ws.takeFrom(q.streamID(), q)
+ // tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
+ tmp []*http2priorityNode
+
+ // pool of empty queues for reuse.
+ queuePool http2writeQueuePool
}
-// zeroCanSend is defered from take.
-func (ws *http2writeScheduler) zeroCanSend() {
- for i := range ws.canSend {
- ws.canSend[i] = nil
+func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
+
+ if curr := ws.nodes[streamID]; curr != nil {
+ if curr.state != http2priorityNodeIdle {
+ panic(fmt.Sprintf("stream %d already opened", streamID))
+ }
+ curr.state = http2priorityNodeOpen
+ return
+ }
+
+ parent := ws.nodes[options.PusherID]
+ if parent == nil {
+ parent = &ws.root
+ }
+ n := &http2priorityNode{
+ q: *ws.queuePool.get(),
+ id: streamID,
+ weight: http2priorityDefaultWeight,
+ state: http2priorityNodeOpen,
+ }
+ n.setParent(parent)
+ ws.nodes[streamID] = n
+ if streamID > ws.maxID {
+ ws.maxID = streamID
}
- ws.canSend = ws.canSend[:0]
}
-// streamWritableBytes returns the number of DATA bytes we could write
-// from the given queue's stream, if this stream/queue were
-// selected. It is an error to call this if q's head isn't a
-// *writeData.
-func (ws *http2writeScheduler) streamWritableBytes(q *http2writeQueue) int32 {
- wm := q.head()
- ret := wm.stream.flow.available()
- if ret == 0 {
- return 0
+func (ws *http2priorityWriteScheduler) CloseStream(streamID uint32) {
+ if streamID == 0 {
+ panic("violation of WriteScheduler interface: cannot close stream 0")
}
- if int32(ws.maxFrameSize) < ret {
- ret = int32(ws.maxFrameSize)
+ if ws.nodes[streamID] == nil {
+ panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
}
- if ret == 0 {
- panic("internal error: ws.maxFrameSize not initialized or invalid")
+ if ws.nodes[streamID].state != http2priorityNodeOpen {
+ panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
}
- wd := wm.write.(*http2writeData)
- if len(wd.p) < int(ret) {
- ret = int32(len(wd.p))
+
+ n := ws.nodes[streamID]
+ n.state = http2priorityNodeClosed
+ n.addBytes(-n.bytes)
+
+ q := n.q
+ ws.queuePool.put(&q)
+ n.q.s = nil
+ if ws.maxClosedNodesInTree > 0 {
+ ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
+ } else {
+ ws.removeNode(n)
}
- return ret
}
-func (ws *http2writeScheduler) takeFrom(id uint32, q *http2writeQueue) (wm http2frameWriteMsg, ok bool) {
- wm = q.head()
-
- if wd, ok := wm.write.(*http2writeData); ok && len(wd.p) > 0 {
- allowed := wm.stream.flow.available()
- if allowed == 0 {
+func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
+ if streamID == 0 {
+ panic("adjustPriority on root")
+ }
- return http2frameWriteMsg{}, false
+ n := ws.nodes[streamID]
+ if n == nil {
+ if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
+ return
}
- if int32(ws.maxFrameSize) < allowed {
- allowed = int32(ws.maxFrameSize)
+ ws.maxID = streamID
+ n = &http2priorityNode{
+ q: *ws.queuePool.get(),
+ id: streamID,
+ weight: http2priorityDefaultWeight,
+ state: http2priorityNodeIdle,
}
+ n.setParent(&ws.root)
+ ws.nodes[streamID] = n
+ ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
+ }
- if len(wd.p) > int(allowed) {
- wm.stream.flow.take(allowed)
- chunk := wd.p[:allowed]
- wd.p = wd.p[allowed:]
+ parent := ws.nodes[priority.StreamDep]
+ if parent == nil {
+ n.setParent(&ws.root)
+ n.weight = http2priorityDefaultWeight
+ return
+ }
- return http2frameWriteMsg{
- stream: wm.stream,
- write: &http2writeData{
- streamID: wd.streamID,
- p: chunk,
+ if n == parent {
+ return
+ }
- endStream: false,
- },
+ for x := parent.parent; x != nil; x = x.parent {
+ if x == n {
+ parent.setParent(n.parent)
+ break
+ }
+ }
- done: nil,
- }, true
+ if priority.Exclusive {
+ k := parent.kids
+ for k != nil {
+ next := k.next
+ if k != n {
+ k.setParent(n)
+ }
+ k = next
}
- wm.stream.flow.take(int32(len(wd.p)))
}
- q.shift()
- if q.empty() {
- ws.putEmptyQueue(q)
- delete(ws.sq, id)
+ n.setParent(parent)
+ n.weight = priority.Weight
+}
+
+func (ws *http2priorityWriteScheduler) Push(wr http2FrameWriteRequest) {
+ var n *http2priorityNode
+ if id := wr.StreamID(); id == 0 {
+ n = &ws.root
+ } else {
+ n = ws.nodes[id]
+ if n == nil {
+
+ if wr.DataSize() > 0 {
+ panic("add DATA on non-open stream")
+ }
+ n = &ws.root
+ }
}
- return wm, true
+ n.q.push(wr)
}
-func (ws *http2writeScheduler) forgetStream(id uint32) {
- q, ok := ws.sq[id]
- if !ok {
+func (ws *http2priorityWriteScheduler) Pop() (wr http2FrameWriteRequest, ok bool) {
+ ws.root.walkReadyInOrder(false, &ws.tmp, func(n *http2priorityNode, openParent bool) bool {
+ limit := int32(math.MaxInt32)
+ if openParent {
+ limit = ws.writeThrottleLimit
+ }
+ wr, ok = n.q.consume(limit)
+ if !ok {
+ return false
+ }
+ n.addBytes(int64(wr.DataSize()))
+
+ if openParent {
+ ws.writeThrottleLimit += 1024
+ if ws.writeThrottleLimit < 0 {
+ ws.writeThrottleLimit = math.MaxInt32
+ }
+ } else if ws.enableWriteThrottle {
+ ws.writeThrottleLimit = 1024
+ }
+ return true
+ })
+ return wr, ok
+}
+
+func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorityNode, maxSize int, n *http2priorityNode) {
+ if maxSize == 0 {
return
}
- delete(ws.sq, id)
+ if len(*list) == maxSize {
- for i := range q.s {
- q.s[i] = http2frameWriteMsg{}
+ ws.removeNode((*list)[0])
+ x := (*list)[1:]
+ copy(*list, x)
+ *list = (*list)[:len(x)]
}
- q.s = q.s[:0]
- ws.putEmptyQueue(q)
+ *list = append(*list, n)
}
-type http2writeQueue struct {
- s []http2frameWriteMsg
+func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) {
+ for k := n.kids; k != nil; k = k.next {
+ k.setParent(n.parent)
+ }
+ n.setParent(nil)
+ delete(ws.nodes, n.id)
}
-// streamID returns the stream ID for a non-empty stream-specific queue.
-func (q *http2writeQueue) streamID() uint32 { return q.s[0].stream.id }
+// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
+// priorities. Control frames like SETTINGS and PING are written before DATA
+// frames, but if no control frames are queued and multiple streams have queued
+// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
+func http2NewRandomWriteScheduler() http2WriteScheduler {
+ return &http2randomWriteScheduler{sq: make(map[uint32]*http2writeQueue)}
+}
-func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }
+type http2randomWriteScheduler struct {
+ // zero are frames not associated with a specific stream.
+ zero http2writeQueue
+
+ // sq contains the stream-specific queues, keyed by stream ID.
+ // When a stream is idle or closed, it's deleted from the map.
+ sq map[uint32]*http2writeQueue
-func (q *http2writeQueue) push(wm http2frameWriteMsg) {
- q.s = append(q.s, wm)
+ // pool of empty queues for reuse.
+ queuePool http2writeQueuePool
}
-// head returns the next item that would be removed by shift.
-func (q *http2writeQueue) head() http2frameWriteMsg {
- if len(q.s) == 0 {
- panic("invalid use of queue")
- }
- return q.s[0]
+func (ws *http2randomWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
+
}
-func (q *http2writeQueue) shift() http2frameWriteMsg {
- if len(q.s) == 0 {
- panic("invalid use of queue")
+func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) {
+ q, ok := ws.sq[streamID]
+ if !ok {
+ return
}
- wm := q.s[0]
+ delete(ws.sq, streamID)
+ ws.queuePool.put(q)
+}
+
+func (ws *http2randomWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
- copy(q.s, q.s[1:])
- q.s[len(q.s)-1] = http2frameWriteMsg{}
- q.s = q.s[:len(q.s)-1]
- return wm
}
-func (q *http2writeQueue) firstIsNoCost() bool {
- if df, ok := q.s[0].write.(*http2writeData); ok {
- return len(df.p) == 0
+func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) {
+ id := wr.StreamID()
+ if id == 0 {
+ ws.zero.push(wr)
+ return
}
- return true
+ q, ok := ws.sq[id]
+ if !ok {
+ q = ws.queuePool.get()
+ ws.sq[id] = q
+ }
+ q.push(wr)
+}
+
+func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) {
+
+ if !ws.zero.empty() {
+ return ws.zero.shift(), true
+ }
+
+ for _, q := range ws.sq {
+ if wr, ok := q.consume(math.MaxInt32); ok {
+ return wr, true
+ }
+ }
+ return http2FrameWriteRequest{}, false
}
diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go
index 049f32f27d..832169247f 100644
--- a/libgo/go/net/http/header.go
+++ b/libgo/go/net/http/header.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -25,16 +25,18 @@ func (h Header) Add(key, value string) {
}
// Set sets the header entries associated with key to
-// the single element value. It replaces any existing
+// the single element value. It replaces any existing
// values associated with key.
func (h Header) Set(key, value string) {
textproto.MIMEHeader(h).Set(key, value)
}
// Get gets the first value associated with the given key.
+// It is case insensitive; textproto.CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
-// To access multiple values of a key, access the map directly
-// with CanonicalHeaderKey.
+// To access multiple values of a key, or to use non-canonical keys,
+// access the map directly.
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
@@ -164,9 +166,9 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
}
// CanonicalHeaderKey returns the canonical format of the
-// header key s. The canonicalization converts the first
+// header key s. The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
-// the rest are converted to lowercase. For example, the
+// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
// If s contains a space or invalid header field bytes, it is
// returned without modifications.
@@ -186,7 +188,7 @@ func hasToken(v, token string) bool {
for sp := 0; sp <= len(v)-len(token); sp++ {
// Check that first character is good.
// The token is ASCII, so checking only a single byte
- // is sufficient. We skip this potential starting
+ // is sufficient. We skip this potential starting
// position if both the first byte and its potential
// ASCII uppercase equivalent (b|0x20) don't match.
// False positives ('^' => '~') are caught by EqualFold.
diff --git a/libgo/go/net/http/header_test.go b/libgo/go/net/http/header_test.go
index 299576ba8c..5c0de15b73 100644
--- a/libgo/go/net/http/header_test.go
+++ b/libgo/go/net/http/header_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/http/http.go b/libgo/go/net/http/http.go
new file mode 100644
index 0000000000..b95ca89f40
--- /dev/null
+++ b/libgo/go/net/http/http.go
@@ -0,0 +1,141 @@
+// 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
+
+import (
+ "io"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "golang_org/x/net/lex/httplex"
+)
+
+// maxInt64 is the effective "infinite" value for the Server and
+// Transport's byte-limiting readers.
+const maxInt64 = 1<<63 - 1
+
+// aLongTimeAgo is a non-zero time, far in the past, used for
+// immediate cancelation of network operations.
+var aLongTimeAgo = time.Unix(1, 0)
+
+// TODO(bradfitz): move common stuff here. The other files have accumulated
+// generic http stuff in random places.
+
+// contextKey is a value for use with context.WithValue. It's used as
+// a pointer so it fits in an interface{} without allocation.
+type contextKey struct {
+ name string
+}
+
+func (k *contextKey) String() string { return "net/http context value " + k.name }
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+// removeEmptyPort strips the empty port in ":port" to ""
+// as mandated by RFC 3986 Section 6.2.3.
+func removeEmptyPort(host string) string {
+ if hasPort(host) {
+ return strings.TrimSuffix(host, ":")
+ }
+ return host
+}
+
+func isNotToken(r rune) bool {
+ return !httplex.IsTokenRune(r)
+}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+func hexEscapeNonASCII(s string) string {
+ newLen := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ newLen += 3
+ } else {
+ newLen++
+ }
+ }
+ if newLen == len(s) {
+ return s
+ }
+ b := make([]byte, 0, newLen)
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ b = append(b, '%')
+ b = strconv.AppendInt(b, int64(s[i]), 16)
+ } else {
+ b = append(b, s[i])
+ }
+ }
+ return string(b)
+}
+
+// NoBody is an io.ReadCloser with no bytes. Read always returns EOF
+// and Close always returns nil. It can be used in an outgoing client
+// request to explicitly signal that a request has zero bytes.
+// An alternative, however, is to simply set Request.Body to nil.
+var NoBody = noBody{}
+
+type noBody struct{}
+
+func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
+func (noBody) Close() error { return nil }
+func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil }
+
+var (
+ // verify that an io.Copy from NoBody won't require a buffer:
+ _ io.WriterTo = NoBody
+ _ io.ReadCloser = NoBody
+)
+
+// PushOptions describes options for Pusher.Push.
+type PushOptions struct {
+ // Method specifies the HTTP method for the promised request.
+ // If set, it must be "GET" or "HEAD". Empty means "GET".
+ Method string
+
+ // Header specifies additional promised request headers. This cannot
+ // include HTTP/2 pseudo header fields like ":path" and ":scheme",
+ // which will be added automatically.
+ Header Header
+}
+
+// Pusher is the interface implemented by ResponseWriters that support
+// HTTP/2 server push. For more background, see
+// https://tools.ietf.org/html/rfc7540#section-8.2.
+type Pusher interface {
+ // Push initiates an HTTP/2 server push. This constructs a synthetic
+ // request using the given target and options, serializes that request
+ // into a PUSH_PROMISE frame, then dispatches that request using the
+ // server's request handler. If opts is nil, default options are used.
+ //
+ // The target must either be an absolute path (like "/path") or an absolute
+ // URL that contains a valid host and the same scheme as the parent request.
+ // If the target is a path, it will inherit the scheme and host of the
+ // parent request.
+ //
+ // The HTTP/2 spec disallows recursive pushes and cross-authority pushes.
+ // Push may or may not detect these invalid pushes; however, invalid
+ // pushes will be detected and canceled by conforming clients.
+ //
+ // Handlers that wish to push URL X should call Push before sending any
+ // data that may trigger a request for URL X. This avoids a race where the
+ // client issues requests for X before receiving the PUSH_PROMISE for X.
+ //
+ // Push returns ErrNotSupported if the client has disabled push or if push
+ // is not supported on the underlying connection.
+ Push(target string, opts *PushOptions) error
+}
diff --git a/libgo/go/net/http/http_test.go b/libgo/go/net/http/http_test.go
index dead3b0454..8f466bb366 100644
--- a/libgo/go/net/http/http_test.go
+++ b/libgo/go/net/http/http_test.go
@@ -2,15 +2,23 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Tests of internal functions with no better homes.
+// Tests of internal functions and things with no better homes.
package http
import (
+ "bytes"
+ "internal/testenv"
+ "os/exec"
"reflect"
"testing"
+ "time"
)
+func init() {
+ shutdownPollInterval = 5 * time.Millisecond
+}
+
func TestForeachHeaderElement(t *testing.T) {
tests := []struct {
in string
@@ -48,6 +56,18 @@ func TestCleanHost(t *testing.T) {
{"www.google.com foo", "www.google.com"},
{"www.google.com/foo", "www.google.com"},
{" first character is a space", ""},
+ {"[1::6]:8080", "[1::6]:8080"},
+
+ // Punycode:
+ {"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
+ {"bücher.de", "xn--bcher-kva.de"},
+ {"bücher.de:8080", "xn--bcher-kva.de:8080"},
+ // Verify we convert to lowercase before punycode:
+ {"BÃœCHER.de", "xn--bcher-kva.de"},
+ {"BÃœCHER.de:8080", "xn--bcher-kva.de:8080"},
+ // Verify we normalize to NFC before punycode:
+ {"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
+ {"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
}
for _, tt := range tests {
got := cleanHost(tt.in)
@@ -56,3 +76,36 @@ func TestCleanHost(t *testing.T) {
}
}
}
+
+// Test that cmd/go doesn't link in the HTTP server.
+//
+// This catches accidental dependencies between the HTTP transport and
+// server code.
+func TestCmdGoNoHTTPServer(t *testing.T) {
+ t.Parallel()
+ goBin := testenv.GoToolPath(t)
+ out, err := exec.Command(goBin, "tool", "nm", goBin).CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool nm: %v: %s", err, out)
+ }
+ wantSym := map[string]bool{
+ // Verify these exist: (sanity checking this test)
+ "net/http.(*Client).Get": true,
+ "net/http.(*Transport).RoundTrip": true,
+
+ // Verify these don't exist:
+ "net/http.http2Server": false,
+ "net/http.(*Server).Serve": false,
+ "net/http.(*ServeMux).ServeHTTP": false,
+ "net/http.DefaultServeMux": false,
+ }
+ for sym, want := range wantSym {
+ got := bytes.Contains(out, []byte(sym))
+ if !want && got {
+ t.Errorf("cmd/go unexpectedly links in HTTP server code; found symbol %q in cmd/go", sym)
+ }
+ if want && !got {
+ t.Errorf("expected to find symbol %q in cmd/go; not found", sym)
+ }
+ }
+}
diff --git a/libgo/go/net/http/httptest/httptest.go b/libgo/go/net/http/httptest/httptest.go
new file mode 100644
index 0000000000..f7202da92f
--- /dev/null
+++ b/libgo/go/net/http/httptest/httptest.go
@@ -0,0 +1,91 @@
+// 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 httptest provides utilities for HTTP testing.
+package httptest
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strings"
+)
+
+// NewRequest returns a new incoming server Request, suitable
+// for passing to an http.Handler for testing.
+//
+// The target is the RFC 7230 "request-target": it may be either a
+// path or an absolute URL. If target is an absolute URL, the host name
+// from the URL is used. Otherwise, "example.com" is used.
+//
+// The TLS field is set to a non-nil dummy value if target has scheme
+// "https".
+//
+// The Request.Proto is always HTTP/1.1.
+//
+// An empty method means "GET".
+//
+// The provided body may be nil. If the body is of type *bytes.Reader,
+// *strings.Reader, or *bytes.Buffer, the Request.ContentLength is
+// set.
+//
+// NewRequest panics on error for ease of use in testing, where a
+// panic is acceptable.
+//
+// To generate a client HTTP request instead of a server request, see
+// the NewRequest function in the net/http package.
+func NewRequest(method, target string, body io.Reader) *http.Request {
+ if method == "" {
+ method = "GET"
+ }
+ req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n")))
+ if err != nil {
+ panic("invalid NewRequest arguments; " + err.Error())
+ }
+
+ // HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here.
+ req.Proto = "HTTP/1.1"
+ req.ProtoMinor = 1
+ req.Close = false
+
+ if body != nil {
+ switch v := body.(type) {
+ case *bytes.Buffer:
+ req.ContentLength = int64(v.Len())
+ case *bytes.Reader:
+ req.ContentLength = int64(v.Len())
+ case *strings.Reader:
+ req.ContentLength = int64(v.Len())
+ default:
+ req.ContentLength = -1
+ }
+ if rc, ok := body.(io.ReadCloser); ok {
+ req.Body = rc
+ } else {
+ req.Body = ioutil.NopCloser(body)
+ }
+ }
+
+ // 192.0.2.0/24 is "TEST-NET" in RFC 5737 for use solely in
+ // documentation and example source code and should not be
+ // used publicly.
+ req.RemoteAddr = "192.0.2.1:1234"
+
+ if req.Host == "" {
+ req.Host = "example.com"
+ }
+
+ if strings.HasPrefix(target, "https://") {
+ req.TLS = &tls.ConnectionState{
+ Version: tls.VersionTLS12,
+ HandshakeComplete: true,
+ ServerName: req.Host,
+ }
+ }
+
+ return req
+}
diff --git a/libgo/go/net/http/httptest/httptest_test.go b/libgo/go/net/http/httptest/httptest_test.go
new file mode 100644
index 0000000000..4f9ecbd8bb
--- /dev/null
+++ b/libgo/go/net/http/httptest/httptest_test.go
@@ -0,0 +1,177 @@
+// 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 httptest
+
+import (
+ "crypto/tls"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func TestNewRequest(t *testing.T) {
+ tests := [...]struct {
+ method, uri string
+ body io.Reader
+
+ want *http.Request
+ wantBody string
+ }{
+ // Empty method means GET:
+ 0: {
+ method: "",
+ uri: "/",
+ body: nil,
+ want: &http.Request{
+ Method: "GET",
+ Host: "example.com",
+ URL: &url.URL{Path: "/"},
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "/",
+ },
+ wantBody: "",
+ },
+
+ // GET with full URL:
+ 1: {
+ method: "GET",
+ uri: "http://foo.com/path/%2f/bar/",
+ body: nil,
+ want: &http.Request{
+ Method: "GET",
+ Host: "foo.com",
+ URL: &url.URL{
+ Scheme: "http",
+ Path: "/path///bar/",
+ RawPath: "/path/%2f/bar/",
+ Host: "foo.com",
+ },
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "http://foo.com/path/%2f/bar/",
+ },
+ wantBody: "",
+ },
+
+ // GET with full https URL:
+ 2: {
+ method: "GET",
+ uri: "https://foo.com/path/",
+ body: nil,
+ want: &http.Request{
+ Method: "GET",
+ Host: "foo.com",
+ URL: &url.URL{
+ Scheme: "https",
+ Path: "/path/",
+ Host: "foo.com",
+ },
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "https://foo.com/path/",
+ TLS: &tls.ConnectionState{
+ Version: tls.VersionTLS12,
+ HandshakeComplete: true,
+ ServerName: "foo.com",
+ },
+ },
+ wantBody: "",
+ },
+
+ // Post with known length
+ 3: {
+ method: "POST",
+ uri: "/",
+ body: strings.NewReader("foo"),
+ want: &http.Request{
+ Method: "POST",
+ Host: "example.com",
+ URL: &url.URL{Path: "/"},
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ContentLength: 3,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "/",
+ },
+ wantBody: "foo",
+ },
+
+ // Post with unknown length
+ 4: {
+ method: "POST",
+ uri: "/",
+ body: struct{ io.Reader }{strings.NewReader("foo")},
+ want: &http.Request{
+ Method: "POST",
+ Host: "example.com",
+ URL: &url.URL{Path: "/"},
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ContentLength: -1,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "/",
+ },
+ wantBody: "foo",
+ },
+
+ // OPTIONS *
+ 5: {
+ method: "OPTIONS",
+ uri: "*",
+ want: &http.Request{
+ Method: "OPTIONS",
+ Host: "example.com",
+ URL: &url.URL{Path: "*"},
+ Header: http.Header{},
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RemoteAddr: "192.0.2.1:1234",
+ RequestURI: "*",
+ },
+ },
+ }
+ for i, tt := range tests {
+ got := NewRequest(tt.method, tt.uri, tt.body)
+ slurp, err := ioutil.ReadAll(got.Body)
+ if err != nil {
+ t.Errorf("%d. ReadAll: %v", i, err)
+ }
+ if string(slurp) != tt.wantBody {
+ t.Errorf("%d. Body = %q; want %q", i, slurp, tt.wantBody)
+ }
+ got.Body = nil // before DeepEqual
+ if !reflect.DeepEqual(got.URL, tt.want.URL) {
+ t.Errorf("%d. Request.URL mismatch:\n got: %#v\nwant: %#v", i, got.URL, tt.want.URL)
+ }
+ if !reflect.DeepEqual(got.Header, tt.want.Header) {
+ t.Errorf("%d. Request.Header mismatch:\n got: %#v\nwant: %#v", i, got.Header, tt.want.Header)
+ }
+ if !reflect.DeepEqual(got.TLS, tt.want.TLS) {
+ t.Errorf("%d. Request.TLS mismatch:\n got: %#v\nwant: %#v", i, got.TLS, tt.want.TLS)
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("%d. Request mismatch:\n got: %#v\nwant: %#v", i, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/net/http/httptest/recorder.go b/libgo/go/net/http/httptest/recorder.go
index 7c51af1867..5f1aa6af47 100644
--- a/libgo/go/net/http/httptest/recorder.go
+++ b/libgo/go/net/http/httptest/recorder.go
@@ -2,22 +2,42 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package httptest provides utilities for HTTP testing.
package httptest
import (
"bytes"
+ "io/ioutil"
"net/http"
+ "strconv"
+ "strings"
)
// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
- Code int // the HTTP response code from WriteHeader
- HeaderMap http.Header // the HTTP response headers
- Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
- Flushed bool
+ // Code is the HTTP response code set by WriteHeader.
+ //
+ // Note that if a Handler never calls WriteHeader or Write,
+ // this might end up being 0, rather than the implicit
+ // http.StatusOK. To get the implicit value, use the Result
+ // method.
+ Code int
+ // HeaderMap contains the headers explicitly set by the Handler.
+ //
+ // To get the implicit headers set by the server (such as
+ // automatic Content-Type), use the Result method.
+ HeaderMap http.Header
+
+ // Body is the buffer to which the Handler's Write calls are sent.
+ // If nil, the Writes are silently discarded.
+ Body *bytes.Buffer
+
+ // Flushed is whether the Handler called Flush.
+ Flushed bool
+
+ result *http.Response // cache of Result's return value
+ snapHeader http.Header // snapshot of HeaderMap at first Write
wroteHeader bool
}
@@ -59,16 +79,15 @@ func (rw *ResponseRecorder) writeHeader(b []byte, str string) {
str = str[:512]
}
- _, hasType := rw.HeaderMap["Content-Type"]
- hasTE := rw.HeaderMap.Get("Transfer-Encoding") != ""
+ m := rw.Header()
+
+ _, hasType := m["Content-Type"]
+ hasTE := m.Get("Transfer-Encoding") != ""
if !hasType && !hasTE {
if b == nil {
b = []byte(str)
}
- if rw.HeaderMap == nil {
- rw.HeaderMap = make(http.Header)
- }
- rw.HeaderMap.Set("Content-Type", http.DetectContentType(b))
+ m.Set("Content-Type", http.DetectContentType(b))
}
rw.WriteHeader(200)
@@ -92,12 +111,28 @@ func (rw *ResponseRecorder) WriteString(str string) (int, error) {
return len(str), nil
}
-// WriteHeader sets rw.Code.
+// WriteHeader sets rw.Code. After it is called, changing rw.Header
+// will not affect rw.HeaderMap.
func (rw *ResponseRecorder) WriteHeader(code int) {
- if !rw.wroteHeader {
- rw.Code = code
- rw.wroteHeader = true
+ if rw.wroteHeader {
+ return
+ }
+ rw.Code = code
+ rw.wroteHeader = true
+ if rw.HeaderMap == nil {
+ rw.HeaderMap = make(http.Header)
}
+ 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)
+ h2[k] = vv2
+ }
+ return h2
}
// Flush sets rw.Flushed to true.
@@ -107,3 +142,94 @@ func (rw *ResponseRecorder) Flush() {
}
rw.Flushed = true
}
+
+// 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.
+//
+// The Response.Body is guaranteed to be non-nil and Body.Read call is
+// guaranteed to not return any error other than io.EOF.
+//
+// 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()))
+ }
+ res.ContentLength = parseContentLength(res.Header.Get("Content-Length"))
+
+ 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
+ }
+ }
+ for k, vv := range rw.HeaderMap {
+ if !strings.HasPrefix(k, http.TrailerPrefix) {
+ continue
+ }
+ if res.Trailer == nil {
+ res.Trailer = make(http.Header)
+ }
+ for _, v := range vv {
+ res.Trailer.Add(strings.TrimPrefix(k, http.TrailerPrefix), v)
+ }
+ }
+ return res
+}
+
+// parseContentLength trims whitespace from s and returns -1 if no value
+// is set, or the value if it's >= 0.
+//
+// This a modified version of same function found in net/http/transfer.go. This
+// one just ignores an invalid header.
+func parseContentLength(cl string) int64 {
+ cl = strings.TrimSpace(cl)
+ if cl == "" {
+ return -1
+ }
+ n, err := strconv.ParseInt(cl, 10, 64)
+ if err != nil {
+ return -1
+ }
+ return n
+}
diff --git a/libgo/go/net/http/httptest/recorder_test.go b/libgo/go/net/http/httptest/recorder_test.go
index c29b6d4cf9..9afba4e556 100644
--- a/libgo/go/net/http/httptest/recorder_test.go
+++ b/libgo/go/net/http/httptest/recorder_test.go
@@ -23,6 +23,14 @@ func TestRecorder(t *testing.T) {
return nil
}
}
+ hasResultStatus := func(wantCode int) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if rec.Result().StatusCode != wantCode {
+ return fmt.Errorf("Result().StatusCode = %d; want %d", rec.Result().StatusCode, wantCode)
+ }
+ return nil
+ }
+ }
hasContents := func(want string) checkFunc {
return func(rec *ResponseRecorder) error {
if rec.Body.String() != want {
@@ -39,10 +47,57 @@ 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
+ }
+ }
+ hasNotHeaders := func(keys ...string) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ for _, k := range keys {
+ v, ok := rec.Result().Header[http.CanonicalHeaderKey(k)]
+ if ok {
+ return fmt.Errorf("unexpected header %s with value %q", k, v)
+ }
+ }
+ return nil
+ }
+ }
+ hasTrailer := func(key, want string) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if got := rec.Result().Trailer.Get(key); got != want {
+ return fmt.Errorf("trailer %s = %q; want %q", key, got, want)
+ }
+ return nil
+ }
+ }
+ hasNotTrailers := func(keys ...string) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ trailers := rec.Result().Trailer
+ for _, k := range keys {
+ _, ok := trailers[http.CanonicalHeaderKey(k)]
+ if ok {
+ return fmt.Errorf("unexpected trailer %s", k)
+ }
+ }
+ return nil
+ }
+ }
+ hasContentLength := func(length int64) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if got := rec.Result().ContentLength; got != length {
+ return fmt.Errorf("ContentLength = %d; want %d", got, length)
}
return nil
}
@@ -94,7 +149,7 @@ func TestRecorder(t *testing.T) {
w.(http.Flusher).Flush() // also sends a 200
w.WriteHeader(201)
},
- check(hasStatus(200), hasFlush(true)),
+ check(hasStatus(200), hasFlush(true), hasContentLength(-1)),
},
{
"Content-Type detection",
@@ -130,6 +185,85 @@ func TestRecorder(t *testing.T) {
},
check(hasHeader("Content-Type", "text/html; charset=utf-8")),
},
+ {
+ "Header is not changed after write",
+ func(w http.ResponseWriter, r *http.Request) {
+ hdr := w.Header()
+ hdr.Set("Key", "correct")
+ w.WriteHeader(200)
+ hdr.Set("Key", "incorrect")
+ },
+ check(hasHeader("Key", "correct")),
+ },
+ {
+ "Trailer headers are correctly recorded",
+ func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Non-Trailer", "correct")
+ w.Header().Set("Trailer", "Trailer-A")
+ w.Header().Add("Trailer", "Trailer-B")
+ w.Header().Add("Trailer", "Trailer-C")
+ io.WriteString(w, "<html>")
+ w.Header().Set("Non-Trailer", "incorrect")
+ w.Header().Set("Trailer-A", "valuea")
+ w.Header().Set("Trailer-C", "valuec")
+ w.Header().Set("Trailer-NotDeclared", "should be omitted")
+ w.Header().Set("Trailer:Trailer-D", "with prefix")
+ },
+ check(
+ hasStatus(200),
+ hasHeader("Content-Type", "text/html; charset=utf-8"),
+ hasHeader("Non-Trailer", "correct"),
+ hasNotHeaders("Trailer-A", "Trailer-B", "Trailer-C", "Trailer-NotDeclared"),
+ hasTrailer("Trailer-A", "valuea"),
+ hasTrailer("Trailer-C", "valuec"),
+ hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"),
+ hasTrailer("Trailer-D", "with prefix"),
+ ),
+ },
+ {
+ "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"),
+ ),
+ },
+ {
+ "setting Content-Length header",
+ func(w http.ResponseWriter, r *http.Request) {
+ body := "Some body"
+ contentLength := fmt.Sprintf("%d", len(body))
+ w.Header().Set("Content-Length", contentLength)
+ io.WriteString(w, body)
+ },
+ check(hasStatus(200), hasContents("Some body"), hasContentLength(9)),
+ },
}
r, _ := http.NewRequest("GET", "http://foo.com/", nil)
for _, tt := range tests {
diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go
index bbe323396f..5e9ace591f 100644
--- a/libgo/go/net/http/httptest/server.go
+++ b/libgo/go/net/http/httptest/server.go
@@ -16,7 +16,6 @@ import (
"net/http"
"net/http/internal"
"os"
- "runtime"
"sync"
"time"
)
@@ -114,9 +113,10 @@ func (s *Server) StartTLS() {
}
existingConfig := s.TLS
- s.TLS = new(tls.Config)
if existingConfig != nil {
- *s.TLS = *existingConfig
+ s.TLS = existingConfig.Clone()
+ } else {
+ s.TLS = new(tls.Config)
}
if s.TLS.NextProtos == nil {
s.TLS.NextProtos = []string{"http/1.1"}
@@ -158,7 +158,7 @@ func (s *Server) Close() {
// previously-flaky tests) in the case of
// socket-late-binding races from the http Client
// dialing this server and then getting an idle
- // connection before the dial completed. There is thus
+ // connection before the dial completed. There is thus
// a connected connection in StateNew with no
// associated Request. We only close StateIdle and
// StateNew because they're not doing anything. It's
@@ -167,7 +167,7 @@ func (s *Server) Close() {
// few milliseconds wasn't liked (early versions of
// https://golang.org/cl/15151) so now we just
// forcefully close StateNew. The docs for Server.Close say
- // we wait for "oustanding requests", so we don't close things
+ // we wait for "outstanding requests", so we don't close things
// in StateActive.
if st == http.StateIdle || st == http.StateNew {
s.closeConn(c)
@@ -202,12 +202,10 @@ func (s *Server) logCloseHangDebugInfo() {
// CloseClientConnections closes any open HTTP connections to the test Server.
func (s *Server) CloseClientConnections() {
- var conns int
- ch := make(chan bool)
-
s.mu.Lock()
+ nconn := len(s.conns)
+ ch := make(chan struct{}, nconn)
for c := range s.conns {
- conns++
s.closeConnChan(c, ch)
}
s.mu.Unlock()
@@ -220,7 +218,7 @@ func (s *Server) CloseClientConnections() {
// in tests.
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
- for i := 0; i < conns; i++ {
+ for i := 0; i < nconn; i++ {
select {
case <-ch:
case <-timer.C:
@@ -294,30 +292,11 @@ func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
// closeConnChan is like closeConn, but takes an optional channel to receive a value
// when the goroutine closing c is done.
-func (s *Server) closeConnChan(c net.Conn, done chan<- bool) {
- if runtime.GOOS == "plan9" {
- // Go's Plan 9 net package isn't great at unblocking reads when
- // their underlying TCP connections are closed. Don't trust
- // that that the ConnState state machine will get to
- // StateClosed. Instead, just go there directly. Plan 9 may leak
- // resources if the syscall doesn't end up returning. Oh well.
- s.forgetConn(c)
+func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) {
+ c.Close()
+ if done != nil {
+ done <- struct{}{}
}
-
- // Somewhere in the chaos of https://golang.org/cl/15151 we found that
- // some types of conns were blocking in Close too long (or deadlocking?)
- // and we had to call Close in a goroutine. I (bradfitz) forget what
- // that was at this point, but I suspect it was *tls.Conns, which
- // were later fixed in https://golang.org/cl/18572, so this goroutine
- // is _probably_ unnecessary now. But it's too late in Go 1.6 too remove
- // it with confidence.
- // TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291)
- go func() {
- c.Close()
- if done != nil {
- done <- true
- }
- }()
}
// forgetConn removes c from the set of tracked conns and decrements it from the
diff --git a/libgo/go/net/http/httptest/server_test.go b/libgo/go/net/http/httptest/server_test.go
index c9606f2419..d032c5983b 100644
--- a/libgo/go/net/http/httptest/server_test.go
+++ b/libgo/go/net/http/httptest/server_test.go
@@ -53,7 +53,7 @@ func TestGetAfterClose(t *testing.T) {
res, err = http.Get(ts.URL)
if err == nil {
body, _ := ioutil.ReadAll(res.Body)
- t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
+ t.Fatalf("Unexpected response after close: %v, %v, %s", res.Status, res.Header, body)
}
}
@@ -95,6 +95,6 @@ func TestServerCloseClientConnections(t *testing.T) {
res, err := http.Get(s.URL)
if err == nil {
res.Body.Close()
- t.Fatal("Unexpected response: %#v", res)
+ t.Fatalf("Unexpected response: %#v", res)
}
}
diff --git a/libgo/go/net/http/httptrace/example_test.go b/libgo/go/net/http/httptrace/example_test.go
new file mode 100644
index 0000000000..27cdcdec31
--- /dev/null
+++ b/libgo/go/net/http/httptrace/example_test.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package httptrace_test
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httptrace"
+)
+
+func Example() {
+ req, _ := http.NewRequest("GET", "http://example.com", nil)
+ trace := &httptrace.ClientTrace{
+ GotConn: func(connInfo httptrace.GotConnInfo) {
+ fmt.Printf("Got Conn: %+v\n", connInfo)
+ },
+ DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
+ fmt.Printf("DNS Info: %+v\n", dnsInfo)
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+ _, err := http.DefaultTransport.RoundTrip(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/libgo/go/net/http/httptrace/trace.go b/libgo/go/net/http/httptrace/trace.go
new file mode 100644
index 0000000000..ea7b38c8fc
--- /dev/null
+++ b/libgo/go/net/http/httptrace/trace.go
@@ -0,0 +1,243 @@
+// 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 httptrace provides mechanisms to trace the events within
+// HTTP client requests.
+package httptrace
+
+import (
+ "context"
+ "crypto/tls"
+ "internal/nettrace"
+ "net"
+ "reflect"
+ "time"
+)
+
+// unique type to prevent assignment.
+type clientEventContextKey struct{}
+
+// ContextClientTrace returns the ClientTrace associated with the
+// provided context. If none, it returns nil.
+func ContextClientTrace(ctx context.Context) *ClientTrace {
+ trace, _ := ctx.Value(clientEventContextKey{}).(*ClientTrace)
+ return trace
+}
+
+// WithClientTrace returns a new context based on the provided parent
+// ctx. HTTP client requests made with the returned context will use
+// the provided trace hooks, in addition to any previous hooks
+// registered with ctx. Any hooks defined in the provided trace will
+// be called first.
+func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context {
+ if trace == nil {
+ panic("nil trace")
+ }
+ old := ContextClientTrace(ctx)
+ trace.compose(old)
+
+ ctx = context.WithValue(ctx, clientEventContextKey{}, trace)
+ if trace.hasNetHooks() {
+ nt := &nettrace.Trace{
+ ConnectStart: trace.ConnectStart,
+ ConnectDone: trace.ConnectDone,
+ }
+ if trace.DNSStart != nil {
+ nt.DNSStart = func(name string) {
+ trace.DNSStart(DNSStartInfo{Host: name})
+ }
+ }
+ if trace.DNSDone != nil {
+ nt.DNSDone = func(netIPs []interface{}, coalesced bool, err error) {
+ addrs := make([]net.IPAddr, len(netIPs))
+ for i, ip := range netIPs {
+ addrs[i] = ip.(net.IPAddr)
+ }
+ trace.DNSDone(DNSDoneInfo{
+ Addrs: addrs,
+ Coalesced: coalesced,
+ Err: err,
+ })
+ }
+ }
+ ctx = context.WithValue(ctx, nettrace.TraceKey{}, nt)
+ }
+ return ctx
+}
+
+// ClientTrace is a set of hooks to run at various stages of an outgoing
+// HTTP request. Any particular hook may be nil. Functions may be
+// called concurrently from different goroutines and some may be called
+// after the request has completed or failed.
+//
+// ClientTrace currently traces a single HTTP request & response
+// during a single round trip and has no hooks that span a series
+// of redirected requests.
+//
+// See https://blog.golang.org/http-tracing for more.
+type ClientTrace struct {
+ // GetConn is called before a connection is created or
+ // retrieved from an idle pool. The hostPort is the
+ // "host:port" of the target or proxy. GetConn is called even
+ // if there's already an idle cached connection available.
+ GetConn func(hostPort string)
+
+ // GotConn is called after a successful connection is
+ // obtained. There is no hook for failure to obtain a
+ // connection; instead, use the error from
+ // Transport.RoundTrip.
+ GotConn func(GotConnInfo)
+
+ // PutIdleConn is called when the connection is returned to
+ // the idle pool. If err is nil, the connection was
+ // successfully returned to the idle pool. If err is non-nil,
+ // it describes why not. PutIdleConn is not called if
+ // 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
+ // headers is available.
+ GotFirstResponseByte func()
+
+ // Got100Continue is called if the server replies with a "100
+ // Continue" response.
+ Got100Continue func()
+
+ // DNSStart is called when a DNS lookup begins.
+ DNSStart func(DNSStartInfo)
+
+ // DNSDone is called when a DNS lookup ends.
+ DNSDone func(DNSDoneInfo)
+
+ // ConnectStart is called when a new connection's Dial begins.
+ // If net.Dialer.DualStack (IPv6 "Happy Eyeballs") support is
+ // enabled, this may be called multiple times.
+ ConnectStart func(network, addr string)
+
+ // ConnectDone is called when a new connection's Dial
+ // completes. The provided err indicates whether the
+ // connection completedly successfully.
+ // If net.Dialer.DualStack ("Happy Eyeballs") support is
+ // enabled, this may be called multiple times.
+ ConnectDone func(network, addr string, err error)
+
+ // TLSHandshakeStart is called when the TLS handshake is started. When
+ // connecting to a HTTPS site via a HTTP proxy, the handshake happens after
+ // the CONNECT request is processed by the proxy.
+ TLSHandshakeStart func()
+
+ // TLSHandshakeDone is called after the TLS handshake with either the
+ // successful handshake's connection state, or a non-nil error on handshake
+ // failure.
+ TLSHandshakeDone func(tls.ConnectionState, error)
+
+ // WroteHeaders is called after the Transport has written
+ // the request headers.
+ WroteHeaders func()
+
+ // Wait100Continue is called if the Request specified
+ // "Expected: 100-continue" and the Transport has written the
+ // request headers but is waiting for "100 Continue" from the
+ // server before writing the request body.
+ Wait100Continue func()
+
+ // WroteRequest is called with the result of writing the
+ // request and any body. It may be called multiple times
+ // in the case of retried requests.
+ WroteRequest func(WroteRequestInfo)
+}
+
+// WroteRequestInfo contains information provided to the WroteRequest
+// hook.
+type WroteRequestInfo struct {
+ // Err is any error encountered while writing the Request.
+ Err error
+}
+
+// compose modifies t such that it respects the previously-registered hooks in old,
+// subject to the composition policy requested in t.Compose.
+func (t *ClientTrace) compose(old *ClientTrace) {
+ if old == nil {
+ return
+ }
+ tv := reflect.ValueOf(t).Elem()
+ ov := reflect.ValueOf(old).Elem()
+ structType := tv.Type()
+ for i := 0; i < structType.NumField(); i++ {
+ tf := tv.Field(i)
+ hookType := tf.Type()
+ if hookType.Kind() != reflect.Func {
+ continue
+ }
+ of := ov.Field(i)
+ if of.IsNil() {
+ continue
+ }
+ if tf.IsNil() {
+ tf.Set(of)
+ continue
+ }
+
+ // Make a copy of tf for tf to call. (Otherwise it
+ // creates a recursive call cycle and stack overflows)
+ tfCopy := reflect.ValueOf(tf.Interface())
+
+ // We need to call both tf and of in some order.
+ newFunc := reflect.MakeFunc(hookType, func(args []reflect.Value) []reflect.Value {
+ tfCopy.Call(args)
+ return of.Call(args)
+ })
+ tv.Field(i).Set(newFunc)
+ }
+}
+
+// DNSStartInfo contains information about a DNS request.
+type DNSStartInfo struct {
+ Host string
+}
+
+// DNSDoneInfo contains information about the results of a DNS lookup.
+type DNSDoneInfo struct {
+ // Addrs are the IPv4 and/or IPv6 addresses found in the DNS
+ // lookup. The contents of the slice should not be mutated.
+ Addrs []net.IPAddr
+
+ // Err is any error that occurred during the DNS lookup.
+ Err error
+
+ // Coalesced is whether the Addrs were shared with another
+ // caller who was doing the same DNS lookup concurrently.
+ Coalesced bool
+}
+
+func (t *ClientTrace) hasNetHooks() bool {
+ if t == nil {
+ return false
+ }
+ return t.DNSStart != nil || t.DNSDone != nil || t.ConnectStart != nil || t.ConnectDone != nil
+}
+
+// GotConnInfo is the argument to the ClientTrace.GotConn function and
+// contains information about the obtained connection.
+type GotConnInfo struct {
+ // Conn is the connection that was obtained. It is owned by
+ // the http.Transport and should not be read, written or
+ // closed by users of ClientTrace.
+ Conn net.Conn
+
+ // Reused is whether this connection has been previously
+ // used for another HTTP request.
+ Reused bool
+
+ // WasIdle is whether this connection was obtained from an
+ // idle pool.
+ WasIdle bool
+
+ // IdleTime reports how long the connection was previously
+ // idle, if WasIdle is true.
+ IdleTime time.Duration
+}
diff --git a/libgo/go/net/http/httptrace/trace_test.go b/libgo/go/net/http/httptrace/trace_test.go
new file mode 100644
index 0000000000..bb57ada853
--- /dev/null
+++ b/libgo/go/net/http/httptrace/trace_test.go
@@ -0,0 +1,89 @@
+// 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 httptrace
+
+import (
+ "bytes"
+ "context"
+ "testing"
+)
+
+func TestWithClientTrace(t *testing.T) {
+ var buf bytes.Buffer
+ connectStart := func(b byte) func(network, addr string) {
+ return func(network, addr string) {
+ buf.WriteByte(b)
+ }
+ }
+
+ ctx := context.Background()
+ oldtrace := &ClientTrace{
+ ConnectStart: connectStart('O'),
+ }
+ ctx = WithClientTrace(ctx, oldtrace)
+ newtrace := &ClientTrace{
+ ConnectStart: connectStart('N'),
+ }
+ ctx = WithClientTrace(ctx, newtrace)
+ trace := ContextClientTrace(ctx)
+
+ buf.Reset()
+ trace.ConnectStart("net", "addr")
+ if got, want := buf.String(), "NO"; got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+func TestCompose(t *testing.T) {
+ var buf bytes.Buffer
+ var testNum int
+
+ 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)
+ }
+ buf.WriteByte(b)
+ }
+ }
+
+ tests := [...]struct {
+ trace, old *ClientTrace
+ want string
+ }{
+ 0: {
+ want: "T",
+ trace: &ClientTrace{
+ ConnectStart: connectStart('T'),
+ },
+ },
+ 1: {
+ want: "TO",
+ trace: &ClientTrace{
+ ConnectStart: connectStart('T'),
+ },
+ old: &ClientTrace{ConnectStart: connectStart('O')},
+ },
+ 2: {
+ want: "O",
+ trace: &ClientTrace{},
+ old: &ClientTrace{ConnectStart: connectStart('O')},
+ },
+ }
+ for i, tt := range tests {
+ testNum = i
+ buf.Reset()
+
+ tr := *tt.trace
+ tr.compose(tt.old)
+ if tr.ConnectStart != nil {
+ tr.ConnectStart("net", "addr")
+ }
+ if got := buf.String(); got != tt.want {
+ t.Errorf("%d. got = %q; want %q", i, got, tt.want)
+ }
+ }
+
+}
diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go
index e22cc66dbf..7104c37454 100644
--- a/libgo/go/net/http/httputil/dump.go
+++ b/libgo/go/net/http/httputil/dump.go
@@ -18,11 +18,16 @@ import (
"time"
)
-// One of the copies, say from b to r2, could be avoided by using a more
-// elaborate trick where the other copy is made during Request/Response.Write.
-// This would complicate things too much, given that these functions are for
-// debugging only.
+// drainBody reads all of b to memory and then returns two equivalent
+// ReadClosers yielding the same bytes.
+//
+// It returns an error if the initial slurp of all bytes fails. It does not attempt
+// to make the returned ReadClosers have identical error-matching behavior.
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
+ if b == http.NoBody {
+ // No copying needed. Preserve the magic sentinel meaning of NoBody.
+ return http.NoBody, http.NoBody, nil
+ }
var buf bytes.Buffer
if _, err = buf.ReadFrom(b); err != nil {
return nil, b, err
@@ -128,7 +133,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
// If we used a dummy body above, remove it now.
// TODO: if the req.ContentLength is large, we allocate memory
- // unnecessarily just to slice it off here. But this is just
+ // unnecessarily just to slice it off here. But this is just
// a debug function, so this is acceptable for now. We could
// discard the body earlier if this matters.
if dummyBody {
@@ -163,18 +168,10 @@ func valueOrDefault(value, def string) string {
var reqWriteExcludeHeaderDump = map[string]bool{
"Host": true, // not in Header map anyway
- "Content-Length": true,
"Transfer-Encoding": true,
"Trailer": true,
}
-// dumpAsReceived writes req to w in the form as it was received, or
-// at least as accurately as possible from the information retained in
-// the request.
-func dumpAsReceived(req *http.Request, w io.Writer) error {
- return nil
-}
-
// DumpRequest returns the given request in its HTTP/1.x wire
// representation. It should only be used by servers to debug client
// requests. The returned representation is an approximation only;
@@ -191,7 +188,8 @@ func dumpAsReceived(req *http.Request, w io.Writer) error {
//
// The documentation for http.Request.Write details which fields
// of req are included in the dump.
-func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
+func DumpRequest(req *http.Request, body bool) ([]byte, error) {
+ var err error
save := req.Body
if !body || req.Body == nil {
req.Body = nil
@@ -239,7 +237,7 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
if err != nil {
- return
+ return nil, err
}
io.WriteString(&b, "\r\n")
@@ -258,35 +256,42 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
req.Body = save
if err != nil {
- return
+ return nil, err
}
- dump = b.Bytes()
- return
+ return b.Bytes(), nil
}
-// errNoBody is a sentinel error value used by failureToReadBody so we can detect
-// that the lack of body was intentional.
+// errNoBody is a sentinel error value used by failureToReadBody so we
+// can detect that the lack of body was intentional.
var errNoBody = errors.New("sentinel error value")
// failureToReadBody is a io.ReadCloser that just returns errNoBody on
-// Read. It's swapped in when we don't actually want to consume the
-// body, but need a non-nil one, and want to distinguish the error
-// from reading the dummy body.
+// Read. It's swapped in when we don't actually want to consume
+// the body, but need a non-nil one, and want to distinguish the
+// error from reading the dummy body.
type failureToReadBody struct{}
func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
func (failureToReadBody) Close() error { return nil }
+// emptyBody is an instance of empty reader.
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
// DumpResponse is like DumpRequest but dumps a response.
-func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
+func DumpResponse(resp *http.Response, body bool) ([]byte, error) {
var b bytes.Buffer
+ var err error
save := resp.Body
savecl := resp.ContentLength
if !body {
- resp.Body = failureToReadBody{}
+ // For content length of zero. Make sure the body is an empty
+ // reader, instead of returning error through failureToReadBody{}.
+ if resp.ContentLength == 0 {
+ resp.Body = emptyBody
+ } else {
+ resp.Body = failureToReadBody{}
+ }
} else if resp.Body == nil {
resp.Body = emptyBody
} else {
diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go
index 46bf521723..f881020fef 100644
--- a/libgo/go/net/http/httputil/dump_test.go
+++ b/libgo/go/net/http/httputil/dump_test.go
@@ -122,6 +122,10 @@ var dumpTests = []dumpTest{
Host: "post.tld",
Path: "/",
},
+ Header: http.Header{
+ "Content-Length": []string{"8193"},
+ },
+
ContentLength: 8193,
ProtoMajor: 1,
ProtoMinor: 1,
@@ -135,6 +139,10 @@ var dumpTests = []dumpTest{
"Content-Length: 8193\r\n" +
"Accept-Encoding: gzip\r\n\r\n" +
strings.Repeat("a", 8193),
+ WantDump: "POST / HTTP/1.1\r\n" +
+ "Host: post.tld\r\n" +
+ "Content-Length: 8193\r\n\r\n" +
+ strings.Repeat("a", 8193),
},
{
@@ -144,6 +152,50 @@ var dumpTests = []dumpTest{
WantDump: "GET http://foo.com/ HTTP/1.1\r\n" +
"User-Agent: blah\r\n\r\n",
},
+
+ // Issue #7215. DumpRequest should return the "Content-Length" when set
+ {
+ Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n" +
+ "Content-Length: 3\r\n" +
+ "\r\nkey1=name1&key2=name2"),
+ WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n" +
+ "Content-Length: 3\r\n" +
+ "\r\nkey",
+ },
+
+ // Issue #7215. DumpRequest should return the "Content-Length" in ReadRequest
+ {
+ Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\nkey1=name1&key2=name2"),
+ WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n" +
+ "Content-Length: 0\r\n\r\n",
+ },
+
+ // Issue #7215. DumpRequest should not return the "Content-Length" if unset
+ {
+ Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n" +
+ "\r\nkey1=name1&key2=name2"),
+ WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+ "Host: passport.myhost.com\r\n\r\n",
+ },
+
+ // Issue 18506: make drainBody recognize NoBody. Otherwise
+ // this was turning into a chunked request.
+ {
+ Req: *mustNewRequest("POST", "http://example.com/foo", http.NoBody),
+
+ WantDumpOut: "POST /foo HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "Content-Length: 0\r\n" +
+ "Accept-Encoding: gzip\r\n\r\n",
+ },
}
func TestDumpRequest(t *testing.T) {
@@ -288,6 +340,27 @@ Transfer-Encoding: chunked
foo
0`,
},
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0,
+ Header: http.Header{
+ // To verify if headers are not filtered out.
+ "Foo1": []string{"Bar1"},
+ "Foo2": []string{"Bar2"},
+ },
+ Body: nil,
+ },
+ body: false, // to verify we see 0, not empty.
+ want: `HTTP/1.1 200 OK
+Foo1: Bar1
+Foo2: Bar2
+Content-Length: 0`,
+ },
}
func TestDumpResponse(t *testing.T) {
diff --git a/libgo/go/net/http/httputil/example_test.go b/libgo/go/net/http/httputil/example_test.go
index 8fb1a2d279..e8dc962d3e 100644
--- a/libgo/go/net/http/httputil/example_test.go
+++ b/libgo/go/net/http/httputil/example_test.go
@@ -49,7 +49,7 @@ func ExampleDumpRequest() {
fmt.Printf("%s", b)
// Output:
- // "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
+ // "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nContent-Length: 75\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
}
func ExampleDumpRequestOut() {
diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go
index 987bcc96ba..cbedf25ad1 100644
--- a/libgo/go/net/http/httputil/persist.go
+++ b/libgo/go/net/http/httputil/persist.go
@@ -15,26 +15,27 @@ import (
)
var (
+ // Deprecated: No longer used.
ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
- ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
- ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
+
+ // Deprecated: No longer used.
+ ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
+
+ // Deprecated: No longer used.
+ ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)
// This is an API usage error - the local side is closed.
// ErrPersistEOF (above) reports that the remote side is closed.
var errClosed = errors.New("i/o operation on closed connection")
-// A ServerConn reads requests and sends responses over an underlying
-// connection, until the HTTP keepalive logic commands an end. ServerConn
-// also allows hijacking the underlying connection by calling Hijack
-// to regain control over the connection. ServerConn supports pipe-lining,
-// i.e. requests can be read out of sync (but in the same order) while the
-// respective responses are sent.
+// ServerConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
//
-// ServerConn is low-level and old. Applications should instead use Server
-// in the net/http package.
+// Deprecated: Use the Server in package net/http instead.
type ServerConn struct {
- lk sync.Mutex // read-write protects the following fields
+ mu sync.Mutex // read-write protects the following fields
c net.Conn
r *bufio.Reader
re, we error // read/write errors
@@ -45,11 +46,11 @@ type ServerConn struct {
pipe textproto.Pipeline
}
-// NewServerConn returns a new ServerConn reading and writing c. If r is not
-// nil, it is the buffer to use when reading c.
+// NewServerConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
//
-// ServerConn is low-level and old. Applications should instead use Server
-// in the net/http package.
+// Deprecated: Use the Server in package net/http instead.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
if r == nil {
r = bufio.NewReader(c)
@@ -61,17 +62,17 @@ func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
// as the read-side bufio which may have some left over data. Hijack may be
// called before Read has signaled the end of the keep-alive logic. The user
// should not call Hijack while Read or Write is in progress.
-func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
- sc.lk.Lock()
- defer sc.lk.Unlock()
- c = sc.c
- r = sc.r
+func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader) {
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
+ c := sc.c
+ r := sc.r
sc.c = nil
sc.r = nil
- return
+ return c, r
}
-// Close calls Hijack and then also closes the underlying connection
+// Close calls Hijack and then also closes the underlying connection.
func (sc *ServerConn) Close() error {
c, _ := sc.Hijack()
if c != nil {
@@ -84,7 +85,9 @@ func (sc *ServerConn) Close() error {
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
-func (sc *ServerConn) Read() (req *http.Request, err error) {
+func (sc *ServerConn) Read() (*http.Request, error) {
+ var req *http.Request
+ var err error
// Ensure ordered execution of Reads and Writes
id := sc.pipe.Next()
@@ -96,29 +99,29 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
sc.pipe.EndResponse(id)
} else {
// Remember the pipeline id of this request
- sc.lk.Lock()
+ sc.mu.Lock()
sc.pipereq[req] = id
- sc.lk.Unlock()
+ sc.mu.Unlock()
}
}()
- sc.lk.Lock()
+ sc.mu.Lock()
if sc.we != nil { // no point receiving if write-side broken or closed
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return nil, sc.we
}
if sc.re != nil {
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return nil, sc.re
}
if sc.r == nil { // connection closed by user in the meantime
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return nil, errClosed
}
r := sc.r
lastbody := sc.lastbody
sc.lastbody = nil
- sc.lk.Unlock()
+ sc.mu.Unlock()
// Make sure body is fully consumed, even if user does not call body.Close
if lastbody != nil {
@@ -127,16 +130,16 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
// returned.
err = lastbody.Close()
if err != nil {
- sc.lk.Lock()
- defer sc.lk.Unlock()
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
sc.re = err
return nil, err
}
}
req, err = http.ReadRequest(r)
- sc.lk.Lock()
- defer sc.lk.Unlock()
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
if err != nil {
if err == io.ErrUnexpectedEOF {
// A close from the opposing client is treated as a
@@ -161,8 +164,8 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
// Pending returns the number of unanswered requests
// that have been received on the connection.
func (sc *ServerConn) Pending() int {
- sc.lk.Lock()
- defer sc.lk.Unlock()
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
return sc.nread - sc.nwritten
}
@@ -172,31 +175,31 @@ func (sc *ServerConn) Pending() int {
func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
// Retrieve the pipeline ID of this request/response pair
- sc.lk.Lock()
+ sc.mu.Lock()
id, ok := sc.pipereq[req]
delete(sc.pipereq, req)
if !ok {
- sc.lk.Unlock()
+ sc.mu.Unlock()
return ErrPipeline
}
- sc.lk.Unlock()
+ sc.mu.Unlock()
// Ensure pipeline order
sc.pipe.StartResponse(id)
defer sc.pipe.EndResponse(id)
- sc.lk.Lock()
+ sc.mu.Lock()
if sc.we != nil {
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return sc.we
}
if sc.c == nil { // connection closed by user in the meantime
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return ErrClosed
}
c := sc.c
if sc.nread <= sc.nwritten {
- defer sc.lk.Unlock()
+ defer sc.mu.Unlock()
return errors.New("persist server pipe count")
}
if resp.Close {
@@ -205,11 +208,11 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
// before signaling.
sc.re = ErrPersistEOF
}
- sc.lk.Unlock()
+ sc.mu.Unlock()
err := resp.Write(c)
- sc.lk.Lock()
- defer sc.lk.Unlock()
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
if err != nil {
sc.we = err
return err
@@ -219,15 +222,13 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
return nil
}
-// A ClientConn sends request and receives headers over an underlying
-// connection, while respecting the HTTP keepalive logic. ClientConn
-// supports hijacking the connection calling Hijack to
-// regain control of the underlying net.Conn and deal with it as desired.
+// ClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
//
-// ClientConn is low-level and old. Applications should instead use
-// Client or Transport in the net/http package.
+// Deprecated: Use Client or Transport in package net/http instead.
type ClientConn struct {
- lk sync.Mutex // read-write protects the following fields
+ mu sync.Mutex // read-write protects the following fields
c net.Conn
r *bufio.Reader
re, we error // read/write errors
@@ -239,11 +240,11 @@ type ClientConn struct {
writeReq func(*http.Request, io.Writer) error
}
-// NewClientConn returns a new ClientConn reading and writing c. If r is not
-// nil, it is the buffer to use when reading c.
+// NewClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
//
-// ClientConn is low-level and old. Applications should use Client or
-// Transport in the net/http package.
+// Deprecated: Use the Client or Transport in package net/http instead.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
if r == nil {
r = bufio.NewReader(c)
@@ -256,11 +257,11 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
}
}
-// NewProxyClientConn works like NewClientConn but writes Requests
-// using Request's WriteProxy method.
+// NewProxyClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
//
-// New code should not use NewProxyClientConn. See Client or
-// Transport in the net/http package instead.
+// Deprecated: Use the Client or Transport in package net/http instead.
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
cc := NewClientConn(c, r)
cc.writeReq = (*http.Request).WriteProxy
@@ -272,8 +273,8 @@ func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
// called before the user or Read have signaled the end of the keep-alive
// logic. The user should not call Hijack while Read or Write is in progress.
func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
- cc.lk.Lock()
- defer cc.lk.Unlock()
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
c = cc.c
r = cc.r
cc.c = nil
@@ -281,7 +282,7 @@ func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
return
}
-// Close calls Hijack and then also closes the underlying connection
+// Close calls Hijack and then also closes the underlying connection.
func (cc *ClientConn) Close() error {
c, _ := cc.Hijack()
if c != nil {
@@ -295,7 +296,8 @@ func (cc *ClientConn) Close() error {
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
-func (cc *ClientConn) Write(req *http.Request) (err error) {
+func (cc *ClientConn) Write(req *http.Request) error {
+ var err error
// Ensure ordered execution of Writes
id := cc.pipe.Next()
@@ -307,23 +309,23 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
cc.pipe.EndResponse(id)
} else {
// Remember the pipeline id of this request
- cc.lk.Lock()
+ cc.mu.Lock()
cc.pipereq[req] = id
- cc.lk.Unlock()
+ cc.mu.Unlock()
}
}()
- cc.lk.Lock()
+ cc.mu.Lock()
if cc.re != nil { // no point sending if read-side closed or broken
- defer cc.lk.Unlock()
+ defer cc.mu.Unlock()
return cc.re
}
if cc.we != nil {
- defer cc.lk.Unlock()
+ defer cc.mu.Unlock()
return cc.we
}
if cc.c == nil { // connection closed by user in the meantime
- defer cc.lk.Unlock()
+ defer cc.mu.Unlock()
return errClosed
}
c := cc.c
@@ -332,11 +334,11 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
// still might be some pipelined reads
cc.we = ErrPersistEOF
}
- cc.lk.Unlock()
+ cc.mu.Unlock()
err = cc.writeReq(req, c)
- cc.lk.Lock()
- defer cc.lk.Unlock()
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
if err != nil {
cc.we = err
return err
@@ -349,8 +351,8 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
// Pending returns the number of unanswered requests
// that have been sent on the connection.
func (cc *ClientConn) Pending() int {
- cc.lk.Lock()
- defer cc.lk.Unlock()
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
return cc.nwritten - cc.nread
}
@@ -360,32 +362,32 @@ func (cc *ClientConn) Pending() int {
// concurrently with Write, but not with another Read.
func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
// Retrieve the pipeline ID of this request/response pair
- cc.lk.Lock()
+ cc.mu.Lock()
id, ok := cc.pipereq[req]
delete(cc.pipereq, req)
if !ok {
- cc.lk.Unlock()
+ cc.mu.Unlock()
return nil, ErrPipeline
}
- cc.lk.Unlock()
+ cc.mu.Unlock()
// Ensure pipeline order
cc.pipe.StartResponse(id)
defer cc.pipe.EndResponse(id)
- cc.lk.Lock()
+ cc.mu.Lock()
if cc.re != nil {
- defer cc.lk.Unlock()
+ defer cc.mu.Unlock()
return nil, cc.re
}
if cc.r == nil { // connection closed by user in the meantime
- defer cc.lk.Unlock()
+ defer cc.mu.Unlock()
return nil, errClosed
}
r := cc.r
lastbody := cc.lastbody
cc.lastbody = nil
- cc.lk.Unlock()
+ cc.mu.Unlock()
// Make sure body is fully consumed, even if user does not call body.Close
if lastbody != nil {
@@ -394,16 +396,16 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
// returned.
err = lastbody.Close()
if err != nil {
- cc.lk.Lock()
- defer cc.lk.Unlock()
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
cc.re = err
return nil, err
}
}
resp, err = http.ReadResponse(r, req)
- cc.lk.Lock()
- defer cc.lk.Unlock()
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
if err != nil {
cc.re = err
return resp, err
@@ -420,10 +422,10 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
}
// Do is convenience method that writes a request and reads a response.
-func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {
- err = cc.Write(req)
+func (cc *ClientConn) Do(req *http.Request) (*http.Response, error) {
+ err := cc.Write(req)
if err != nil {
- return
+ return nil, err
}
return cc.Read(req)
}
diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go
index 54411caeca..79c8fe2770 100644
--- a/libgo/go/net/http/httputil/reverseproxy.go
+++ b/libgo/go/net/http/httputil/reverseproxy.go
@@ -7,6 +7,7 @@
package httputil
import (
+ "context"
"io"
"log"
"net"
@@ -29,6 +30,8 @@ type ReverseProxy struct {
// the request into a new request to be sent
// using Transport. Its response is then copied
// back to the original client unmodified.
+ // Director must not access the provided Request
+ // after returning.
Director func(*http.Request)
// The transport used to perform proxy requests.
@@ -51,6 +54,11 @@ type ReverseProxy struct {
// get byte slices for use by io.CopyBuffer when
// copying HTTP response bodies.
BufferPool BufferPool
+
+ // ModifyResponse is an optional function that
+ // modifies the Response from the backend.
+ // If it returns an error, the proxy returns a StatusBadGateway error.
+ ModifyResponse func(*http.Response) error
}
// A BufferPool is an interface for getting and returning temporary
@@ -90,6 +98,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}
}
@@ -116,76 +128,59 @@ var hopHeaders = []string{
"Upgrade",
}
-type requestCanceler interface {
- CancelRequest(*http.Request)
-}
-
-type runOnFirstRead struct {
- io.Reader // optional; nil means empty body
-
- fn func() // Run before first Read, then set to nil
-}
-
-func (c *runOnFirstRead) Read(bs []byte) (int, error) {
- if c.fn != nil {
- c.fn()
- c.fn = nil
- }
- if c.Reader == nil {
- return 0, io.EOF
- }
- return c.Reader.Read(bs)
-}
-
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
transport = http.DefaultTransport
}
+ ctx := req.Context()
+ if cn, ok := rw.(http.CloseNotifier); ok {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithCancel(ctx)
+ defer cancel()
+ notifyChan := cn.CloseNotify()
+ go func() {
+ select {
+ case <-notifyChan:
+ cancel()
+ case <-ctx.Done():
+ }
+ }()
+ }
+
outreq := new(http.Request)
*outreq = *req // includes shallow copies of maps, but okay
-
- if closeNotifier, ok := rw.(http.CloseNotifier); ok {
- if requestCanceler, ok := transport.(requestCanceler); ok {
- reqDone := make(chan struct{})
- defer close(reqDone)
-
- clientGone := closeNotifier.CloseNotify()
-
- outreq.Body = struct {
- io.Reader
- io.Closer
- }{
- Reader: &runOnFirstRead{
- Reader: outreq.Body,
- fn: func() {
- go func() {
- select {
- case <-clientGone:
- requestCanceler.CancelRequest(outreq)
- case <-reqDone:
- }
- }()
- },
- },
- Closer: outreq.Body,
- }
- }
+ if req.ContentLength == 0 {
+ outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
}
+ outreq = outreq.WithContext(ctx)
p.Director(outreq)
- outreq.Proto = "HTTP/1.1"
- outreq.ProtoMajor = 1
- outreq.ProtoMinor = 1
outreq.Close = false
- // Remove hop-by-hop headers to the backend. Especially
- // important is "Connection" because we want a persistent
- // connection, regardless of what the client sent to us. This
- // is modifying the same underlying map from req (shallow
+ // We are modifying the same underlying map from req (shallow
// copied above) so we only copy it if necessary.
copiedHeaders := false
+
+ // Remove hop-by-hop headers listed in the "Connection" header.
+ // See RFC 2616, section 14.10.
+ if c := outreq.Header.Get("Connection"); c != "" {
+ for _, f := range strings.Split(c, ",") {
+ if f = strings.TrimSpace(f); f != "" {
+ if !copiedHeaders {
+ outreq.Header = make(http.Header)
+ copyHeader(outreq.Header, req.Header)
+ copiedHeaders = true
+ }
+ outreq.Header.Del(f)
+ }
+ }
+ }
+
+ // Remove hop-by-hop headers to the backend. Especially
+ // important is "Connection" because we want a persistent
+ // connection, regardless of what the client sent to us.
for _, h := range hopHeaders {
if outreq.Header.Get(h) != "" {
if !copiedHeaders {
@@ -210,20 +205,38 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
res, err := transport.RoundTrip(outreq)
if err != nil {
p.logf("http: proxy error: %v", err)
- rw.WriteHeader(http.StatusInternalServerError)
+ rw.WriteHeader(http.StatusBadGateway)
return
}
+ // Remove hop-by-hop headers listed in the
+ // "Connection" header of the response.
+ if c := res.Header.Get("Connection"); c != "" {
+ for _, f := range strings.Split(c, ",") {
+ if f = strings.TrimSpace(f); f != "" {
+ res.Header.Del(f)
+ }
+ }
+ }
+
for _, h := range hopHeaders {
res.Header.Del(h)
}
+ if p.ModifyResponse != nil {
+ if err := p.ModifyResponse(res); err != nil {
+ p.logf("http: proxy error: %v", err)
+ rw.WriteHeader(http.StatusBadGateway)
+ return
+ }
+ }
+
copyHeader(rw.Header(), res.Header)
// The "Trailer" header isn't included in the Transport's response,
// at least for *http.Transport. Build it up from Trailer.
if len(res.Trailer) > 0 {
- var trailerKeys []string
+ trailerKeys := make([]string, 0, len(res.Trailer))
for k := range res.Trailer {
trailerKeys = append(trailerKeys, k)
}
@@ -262,12 +275,40 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
if p.BufferPool != nil {
buf = p.BufferPool.Get()
}
- io.CopyBuffer(dst, src, buf)
+ p.copyBuffer(dst, src, buf)
if p.BufferPool != nil {
p.BufferPool.Put(buf)
}
}
+func (p *ReverseProxy) copyBuffer(dst io.Writer, src io.Reader, buf []byte) (int64, error) {
+ if len(buf) == 0 {
+ buf = make([]byte, 32*1024)
+ }
+ var written int64
+ for {
+ nr, rerr := src.Read(buf)
+ if rerr != nil && rerr != io.EOF {
+ p.logf("httputil: ReverseProxy read error during body copy: %v", rerr)
+ }
+ if nr > 0 {
+ nw, werr := dst.Write(buf[:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if werr != nil {
+ return written, werr
+ }
+ if nr != nw {
+ return written, io.ErrShortWrite
+ }
+ }
+ if rerr != nil {
+ return written, rerr
+ }
+ }
+}
+
func (p *ReverseProxy) logf(format string, args ...interface{}) {
if p.ErrorLog != nil {
p.ErrorLog.Printf(format, args...)
@@ -285,13 +326,13 @@ type maxLatencyWriter struct {
dst writeFlusher
latency time.Duration
- lk sync.Mutex // protects Write + Flush
+ mu sync.Mutex // protects Write + Flush
done chan bool
}
func (m *maxLatencyWriter) Write(p []byte) (int, error) {
- m.lk.Lock()
- defer m.lk.Unlock()
+ m.mu.Lock()
+ defer m.mu.Unlock()
return m.dst.Write(p)
}
@@ -306,9 +347,9 @@ func (m *maxLatencyWriter) flushLoop() {
}
return
case <-t.C:
- m.lk.Lock()
+ m.mu.Lock()
m.dst.Flush()
- m.lk.Unlock()
+ m.mu.Unlock()
}
}
}
diff --git a/libgo/go/net/http/httputil/reverseproxy_test.go b/libgo/go/net/http/httputil/reverseproxy_test.go
index 0849427b85..20c4e16bcb 100644
--- a/libgo/go/net/http/httputil/reverseproxy_test.go
+++ b/libgo/go/net/http/httputil/reverseproxy_test.go
@@ -9,6 +9,8 @@ package httputil
import (
"bufio"
"bytes"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
"log"
@@ -33,6 +35,11 @@ func TestReverseProxy(t *testing.T) {
const backendResponse = "I am the backend"
const backendStatus = 404
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "GET" && r.FormValue("mode") == "hangup" {
+ c, _, _ := w.(http.Hijacker).Hijack()
+ c.Close()
+ return
+ }
if len(r.TransferEncoding) > 0 {
t.Errorf("backend got unexpected TransferEncoding: %v", r.TransferEncoding)
}
@@ -69,6 +76,7 @@ func TestReverseProxy(t *testing.T) {
t.Fatal(err)
}
proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
@@ -113,6 +121,75 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
}
+
+ // Test that a backend failing to be reached or one which doesn't return
+ // a response results in a StatusBadGateway.
+ getReq, _ = http.NewRequest("GET", frontend.URL+"/?mode=hangup", nil)
+ getReq.Close = true
+ res, err = http.DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if res.StatusCode != http.StatusBadGateway {
+ t.Errorf("request to bad proxy = %v; want 502 StatusBadGateway", res.Status)
+ }
+
+}
+
+// Issue 16875: remove any proxied headers mentioned in the "Connection"
+// header value.
+func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
+ const fakeConnectionToken = "X-Fake-Connection-Token"
+ const backendResponse = "I am the backend"
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if c := r.Header.Get(fakeConnectionToken); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", fakeConnectionToken, c)
+ }
+ if c := r.Header.Get("Upgrade"); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", "Upgrade", c)
+ }
+ w.Header().Set("Connection", "Upgrade, "+fakeConnectionToken)
+ w.Header().Set("Upgrade", "should be deleted")
+ w.Header().Set(fakeConnectionToken, "should be deleted")
+ io.WriteString(w, backendResponse)
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ proxyHandler.ServeHTTP(w, r)
+ if c := r.Header.Get("Upgrade"); c != "original value" {
+ t.Errorf("handler modified header %q = %q; want %q", "Upgrade", c, "original value")
+ }
+ }))
+ defer frontend.Close()
+
+ getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+ getReq.Header.Set("Connection", "Upgrade, "+fakeConnectionToken)
+ getReq.Header.Set("Upgrade", "original value")
+ getReq.Header.Set(fakeConnectionToken, "should be deleted")
+ res, err := http.DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ defer res.Body.Close()
+ bodyBytes, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("reading body: %v", err)
+ }
+ if got, want := string(bodyBytes), backendResponse; got != want {
+ t.Errorf("got body %q; want %q", got, want)
+ }
+ if c := res.Header.Get("Upgrade"); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", "Upgrade", c)
+ }
+ if c := res.Header.Get(fakeConnectionToken); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", fakeConnectionToken, c)
+ }
}
func TestXForwardedFor(t *testing.T) {
@@ -240,14 +317,14 @@ func TestReverseProxyCancelation(t *testing.T) {
reqInFlight := make(chan struct{})
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- close(reqInFlight)
+ close(reqInFlight) // cause the client to cancel its request
select {
case <-time.After(10 * time.Second):
// Note: this should only happen in broken implementations, and the
// closenotify case should be instantaneous.
- t.Log("Failed to close backend connection")
- t.Fail()
+ t.Error("Handler never saw CloseNotify")
+ return
case <-w.(http.CloseNotifier).CloseNotify():
}
@@ -280,13 +357,13 @@ func TestReverseProxyCancelation(t *testing.T) {
}()
res, err := http.DefaultClient.Do(getReq)
if res != nil {
- t.Fatal("Non-nil response")
+ t.Errorf("got response %v; want nil", res.Status)
}
if err == nil {
// This should be an error like:
// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
// use of closed network connection
- t.Fatal("DefaultClient.Do() returned nil error")
+ t.Error("DefaultClient.Do() returned nil error; want non-nil error")
}
}
@@ -328,6 +405,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)
@@ -432,3 +552,115 @@ func TestReverseProxy_Post(t *testing.T) {
t.Errorf("got body %q; expected %q", g, e)
}
}
+
+type RoundTripperFunc func(*http.Request) (*http.Response, error)
+
+func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
+ return fn(req)
+}
+
+// Issue 16036: send a Request with a nil Body when possible
+func TestReverseProxy_NilBody(t *testing.T) {
+ backendURL, _ := url.Parse("http://fake.tld/")
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+ proxyHandler.Transport = RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
+ if req.Body != nil {
+ t.Error("Body != nil; want a nil Body")
+ }
+ return nil, errors.New("done testing the interesting part; so force a 502 Gateway error")
+ })
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ res, err := http.DefaultClient.Get(frontend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 502 {
+ t.Errorf("status code = %v; want 502 (Gateway Error)", res.Status)
+ }
+}
+
+// Issue 14237. Test ModifyResponse and that an error from it
+// causes the proxy to return StatusBadGateway, or StatusOK otherwise.
+func TestReverseProxyModifyResponse(t *testing.T) {
+ backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("X-Hit-Mod", fmt.Sprintf("%v", r.URL.Path == "/mod"))
+ }))
+ defer backendServer.Close()
+
+ rpURL, _ := url.Parse(backendServer.URL)
+ rproxy := NewSingleHostReverseProxy(rpURL)
+ rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+ rproxy.ModifyResponse = func(resp *http.Response) error {
+ if resp.Header.Get("X-Hit-Mod") != "true" {
+ return fmt.Errorf("tried to by-pass proxy")
+ }
+ return nil
+ }
+
+ frontendProxy := httptest.NewServer(rproxy)
+ defer frontendProxy.Close()
+
+ tests := []struct {
+ url string
+ wantCode int
+ }{
+ {frontendProxy.URL + "/mod", http.StatusOK},
+ {frontendProxy.URL + "/schedule", http.StatusBadGateway},
+ }
+
+ for i, tt := range tests {
+ resp, err := http.Get(tt.url)
+ if err != nil {
+ t.Fatalf("failed to reach proxy: %v", err)
+ }
+ if g, e := resp.StatusCode, tt.wantCode; g != e {
+ t.Errorf("#%d: got res.StatusCode %d; expected %d", i, g, e)
+ }
+ resp.Body.Close()
+ }
+}
+
+// Issue 16659: log errors from short read
+func TestReverseProxy_CopyBuffer(t *testing.T) {
+ backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ out := "this call was relayed by the reverse proxy"
+ // Coerce a wrong content length to induce io.UnexpectedEOF
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2))
+ fmt.Fprintln(w, out)
+ }))
+ defer backendServer.Close()
+
+ rpURL, err := url.Parse(backendServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var proxyLog bytes.Buffer
+ rproxy := NewSingleHostReverseProxy(rpURL)
+ rproxy.ErrorLog = log.New(&proxyLog, "", log.Lshortfile)
+ frontendProxy := httptest.NewServer(rproxy)
+ defer frontendProxy.Close()
+
+ resp, err := http.Get(frontendProxy.URL)
+ if err != nil {
+ t.Fatalf("failed to reach proxy: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if _, err := ioutil.ReadAll(resp.Body); err == nil {
+ t.Fatalf("want non-nil error")
+ }
+ expected := []string{
+ "EOF",
+ "read",
+ }
+ for _, phrase := range expected {
+ if !bytes.Contains(proxyLog.Bytes(), []byte(phrase)) {
+ t.Errorf("expected log to contain phrase %q", phrase)
+ }
+ }
+}
diff --git a/libgo/go/net/http/internal/chunked.go b/libgo/go/net/http/internal/chunked.go
index 2e62c00d5d..63f321d03b 100644
--- a/libgo/go/net/http/internal/chunked.go
+++ b/libgo/go/net/http/internal/chunked.go
@@ -35,10 +35,11 @@ func NewChunkedReader(r io.Reader) io.Reader {
}
type chunkedReader struct {
- r *bufio.Reader
- n uint64 // unread bytes in chunk
- err error
- buf [2]byte
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+ buf [2]byte
+ checkEnd bool // whether need to check for \r\n chunk footer
}
func (cr *chunkedReader) beginChunk() {
@@ -68,6 +69,21 @@ func (cr *chunkedReader) chunkHeaderAvailable() bool {
func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
for cr.err == nil {
+ if cr.checkEnd {
+ if n > 0 && cr.r.Buffered() < 2 {
+ // We have some data. Return early (per the io.Reader
+ // contract) instead of potentially blocking while
+ // reading more.
+ break
+ }
+ if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+ if string(cr.buf[:]) != "\r\n" {
+ cr.err = errors.New("malformed chunked encoding")
+ break
+ }
+ }
+ cr.checkEnd = false
+ }
if cr.n == 0 {
if n > 0 && !cr.chunkHeaderAvailable() {
// We've read enough. Don't potentially block
@@ -92,11 +108,7 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
// If we're at the end of a chunk, read the next two
// bytes to verify they are "\r\n".
if cr.n == 0 && cr.err == nil {
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
- }
- }
+ cr.checkEnd = true
}
}
return n, cr.err
diff --git a/libgo/go/net/http/internal/chunked_test.go b/libgo/go/net/http/internal/chunked_test.go
index a136dc99a6..d06716591a 100644
--- a/libgo/go/net/http/internal/chunked_test.go
+++ b/libgo/go/net/http/internal/chunked_test.go
@@ -122,7 +122,7 @@ func TestChunkReaderAllocs(t *testing.T) {
byter := bytes.NewReader(buf.Bytes())
bufr := bufio.NewReader(byter)
mallocs := testing.AllocsPerRun(100, func() {
- byter.Seek(0, 0)
+ byter.Seek(0, io.SeekStart)
bufr.Reset(byter)
r := NewChunkedReader(bufr)
n, err := io.ReadFull(r, readBuf)
@@ -185,3 +185,30 @@ func TestChunkReadingIgnoresExtensions(t *testing.T) {
t.Errorf("read %q; want %q", g, e)
}
}
+
+// Issue 17355: ChunkedReader shouldn't block waiting for more data
+// if it can return something.
+func TestChunkReadPartial(t *testing.T) {
+ pr, pw := io.Pipe()
+ go func() {
+ pw.Write([]byte("7\r\n1234567"))
+ }()
+ cr := NewChunkedReader(pr)
+ readBuf := make([]byte, 7)
+ n, err := cr.Read(readBuf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "1234567"
+ if n != 7 || string(readBuf) != want {
+ t.Fatalf("Read: %v %q; want %d, %q", n, readBuf[:n], len(want), want)
+ }
+ go func() {
+ pw.Write([]byte("xx"))
+ }()
+ _, err = cr.Read(readBuf)
+ if got := fmt.Sprint(err); !strings.Contains(got, "malformed") {
+ t.Fatalf("second read = %v; want malformed error", err)
+ }
+
+}
diff --git a/libgo/go/net/http/lex.go b/libgo/go/net/http/lex.go
deleted file mode 100644
index 52b6481c14..0000000000
--- a/libgo/go/net/http/lex.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http
-
-import (
- "strings"
- "unicode/utf8"
-)
-
-// This file deals with lexical matters of HTTP
-
-var isTokenTable = [127]bool{
- '!': true,
- '#': true,
- '$': true,
- '%': true,
- '&': true,
- '\'': true,
- '*': true,
- '+': true,
- '-': true,
- '.': true,
- '0': true,
- '1': true,
- '2': true,
- '3': true,
- '4': true,
- '5': true,
- '6': true,
- '7': true,
- '8': true,
- '9': true,
- 'A': true,
- 'B': true,
- 'C': true,
- 'D': true,
- 'E': true,
- 'F': true,
- 'G': true,
- 'H': true,
- 'I': true,
- 'J': true,
- 'K': true,
- 'L': true,
- 'M': true,
- 'N': true,
- 'O': true,
- 'P': true,
- 'Q': true,
- 'R': true,
- 'S': true,
- 'T': true,
- 'U': true,
- 'W': true,
- 'V': true,
- 'X': true,
- 'Y': true,
- 'Z': true,
- '^': true,
- '_': true,
- '`': true,
- 'a': true,
- 'b': true,
- 'c': true,
- 'd': true,
- 'e': true,
- 'f': true,
- 'g': true,
- 'h': true,
- 'i': true,
- 'j': true,
- 'k': true,
- 'l': true,
- 'm': true,
- 'n': true,
- 'o': true,
- 'p': true,
- 'q': true,
- 'r': true,
- 's': true,
- 't': true,
- 'u': true,
- 'v': true,
- 'w': true,
- 'x': true,
- 'y': true,
- 'z': true,
- '|': true,
- '~': true,
-}
-
-func isToken(r rune) bool {
- i := int(r)
- return i < len(isTokenTable) && isTokenTable[i]
-}
-
-func isNotToken(r rune) bool {
- return !isToken(r)
-}
-
-// headerValuesContainsToken reports whether any string in values
-// contains the provided token, ASCII case-insensitively.
-func headerValuesContainsToken(values []string, token string) bool {
- for _, v := range values {
- if headerValueContainsToken(v, token) {
- return true
- }
- }
- return false
-}
-
-// isOWS reports whether b is an optional whitespace byte, as defined
-// by RFC 7230 section 3.2.3.
-func isOWS(b byte) bool { return b == ' ' || b == '\t' }
-
-// trimOWS returns x with all optional whitespace removes from the
-// beginning and end.
-func trimOWS(x string) string {
- // TODO: consider using strings.Trim(x, " \t") instead,
- // if and when it's fast enough. See issue 10292.
- // But this ASCII-only code will probably always beat UTF-8
- // aware code.
- for len(x) > 0 && isOWS(x[0]) {
- x = x[1:]
- }
- for len(x) > 0 && isOWS(x[len(x)-1]) {
- x = x[:len(x)-1]
- }
- return x
-}
-
-// headerValueContainsToken reports whether v (assumed to be a
-// 0#element, in the ABNF extension described in RFC 7230 section 7)
-// contains token amongst its comma-separated tokens, ASCII
-// case-insensitively.
-func headerValueContainsToken(v string, token string) bool {
- v = trimOWS(v)
- if comma := strings.IndexByte(v, ','); comma != -1 {
- return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
- }
- return tokenEqual(v, token)
-}
-
-// lowerASCII returns the ASCII lowercase version of b.
-func lowerASCII(b byte) byte {
- if 'A' <= b && b <= 'Z' {
- return b + ('a' - 'A')
- }
- return b
-}
-
-// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
-func tokenEqual(t1, t2 string) bool {
- if len(t1) != len(t2) {
- return false
- }
- for i, b := range t1 {
- if b >= utf8.RuneSelf {
- // No UTF-8 or non-ASCII allowed in tokens.
- return false
- }
- if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
- return false
- }
- }
- return true
-}
-
-// isLWS reports whether b is linear white space, according
-// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
-// LWS = [CRLF] 1*( SP | HT )
-func isLWS(b byte) bool { return b == ' ' || b == '\t' }
-
-// isCTL reports whether b is a control byte, according
-// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
-// CTL = <any US-ASCII control character
-// (octets 0 - 31) and DEL (127)>
-func isCTL(b byte) bool {
- const del = 0x7f // a CTL
- return b < ' ' || b == del
-}
diff --git a/libgo/go/net/http/main_test.go b/libgo/go/net/http/main_test.go
index 299cd7b2d2..438bd2e58f 100644
--- a/libgo/go/net/http/main_test.go
+++ b/libgo/go/net/http/main_test.go
@@ -5,8 +5,9 @@
package http_test
import (
- "flag"
"fmt"
+ "io/ioutil"
+ "log"
"net/http"
"os"
"runtime"
@@ -16,7 +17,7 @@ import (
"time"
)
-var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
+var quietLog = log.New(ioutil.Discard, "", 0)
func TestMain(m *testing.M) {
v := m.Run()
@@ -91,12 +92,6 @@ func setParallel(t *testing.T) {
}
}
-func setFlaky(t *testing.T, issue int) {
- if !*flaky {
- t.Skipf("skipping known flaky test; see golang.org/issue/%d", issue)
- }
-}
-
func afterTest(t testing.TB) {
http.DefaultTransport.(*http.Transport).CloseIdleConnections()
if testing.Short() {
@@ -129,3 +124,34 @@ func afterTest(t testing.TB) {
}
t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
}
+
+// waitCondition reports whether fn eventually returned true,
+// checking immediately and then every checkEvery amount,
+// until waitFor has elapsed, at which point it returns false.
+func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
+ deadline := time.Now().Add(waitFor)
+ for time.Now().Before(deadline) {
+ if fn() {
+ return true
+ }
+ time.Sleep(checkEvery)
+ }
+ return false
+}
+
+// waitErrCondition is like waitCondition but with errors instead of bools.
+func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
+ deadline := time.Now().Add(waitFor)
+ var err error
+ for time.Now().Before(deadline) {
+ if err = fn(); err == nil {
+ return nil
+ }
+ time.Sleep(checkEvery)
+ }
+ return err
+}
+
+func closeClient(c *http.Client) {
+ c.Transport.(*http.Transport).CloseIdleConnections()
+}
diff --git a/libgo/go/net/http/method.go b/libgo/go/net/http/method.go
index b74f9604d3..6f46155069 100644
--- a/libgo/go/net/http/method.go
+++ b/libgo/go/net/http/method.go
@@ -12,7 +12,7 @@ const (
MethodHead = "HEAD"
MethodPost = "POST"
MethodPut = "PUT"
- MethodPatch = "PATCH" // RFC 5741
+ MethodPatch = "PATCH" // RFC 5789
MethodDelete = "DELETE"
MethodConnect = "CONNECT"
MethodOptions = "OPTIONS"
diff --git a/libgo/go/net/http/npn_test.go b/libgo/go/net/http/npn_test.go
index e2e911d3dd..4c1f6b573d 100644
--- a/libgo/go/net/http/npn_test.go
+++ b/libgo/go/net/http/npn_test.go
@@ -18,6 +18,7 @@ import (
)
func TestNextProtoUpgrade(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "path=%s,proto=", r.URL.Path)
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index 7262c6c101..05d0890fdf 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -1,11 +1,9 @@
-// Copyright 2010 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 pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
-// For more information about pprof, see
-// http://code.google.com/p/google-perftools/.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
@@ -15,7 +13,7 @@
// import _ "net/http/pprof"
//
// If your application is not already running an http server, you
-// need to start one. Add "net/http" and "log" to your imports and
+// need to start one. Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// go func() {
@@ -30,7 +28,8 @@
//
// go tool pprof http://localhost:6060/debug/pprof/profile
//
-// Or to look at the goroutine blocking profile:
+// Or to look at the goroutine blocking profile, after calling
+// runtime.SetBlockProfileRate in your program:
//
// go tool pprof http://localhost:6060/debug/pprof/block
//
@@ -118,8 +117,8 @@ func Profile(w http.ResponseWriter, r *http.Request) {
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
// The package initialization registers it as /debug/pprof/trace.
func Trace(w http.ResponseWriter, r *http.Request) {
- sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
- if sec == 0 {
+ sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
+ if sec <= 0 || err != nil {
sec = 1
}
@@ -127,18 +126,16 @@ func Trace(w http.ResponseWriter, r *http.Request) {
// because if it does it starts writing.
w.Header().Set("Content-Type", "application/octet-stream")
w.Write([]byte("tracing not yet supported with gccgo"))
- /*
- if err := trace.Start(w); err != nil {
- // trace.Start failed, so no writes yet.
- // Can change header back to text content and send error code.
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusInternalServerError)
- fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
- return
- }
- sleep(w, time.Duration(sec)*time.Second)
- trace.Stop()
- */
+ // if err := trace.Start(w); err != nil {
+ // // trace.Start failed, so no writes yet.
+ // // Can change header back to text content and send error code.
+ // w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ // w.WriteHeader(http.StatusInternalServerError)
+ // fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
+ // return
+ // }
+ // sleep(w, time.Duration(sec*float64(time.Second)))
+ // trace.Stop()
}
// Symbol looks up the program counters listed in the request,
@@ -148,11 +145,11 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
// We have to read the whole POST body before
- // writing any output. Buffer the output here.
+ // writing any output. Buffer the output here.
var buf bytes.Buffer
// We don't know how many symbols we have, but we
- // do have symbol information. Pprof only cares whether
+ // do have symbol information. Pprof only cares whether
// this number is 0 (no symbols available) or > 0.
fmt.Fprintf(&buf, "num_symbols: 1\n")
diff --git a/libgo/go/net/http/range_test.go b/libgo/go/net/http/range_test.go
index ef911af7b0..114987ed2c 100644
--- a/libgo/go/net/http/range_test.go
+++ b/libgo/go/net/http/range_test.go
@@ -38,7 +38,7 @@ var ParseRangeTests = []struct {
{"bytes=0-", 10, []httpRange{{0, 10}}},
{"bytes=5-", 10, []httpRange{{5, 5}}},
{"bytes=0-20", 10, []httpRange{{0, 10}}},
- {"bytes=15-,0-5", 10, nil},
+ {"bytes=15-,0-5", 10, []httpRange{{0, 6}}},
{"bytes=1-2,5-", 10, []httpRange{{1, 2}, {5, 5}}},
{"bytes=-2 , 7-", 11, []httpRange{{9, 2}, {7, 4}}},
{"bytes=0-0 ,2-2, 7-", 11, []httpRange{{0, 1}, {2, 1}, {7, 4}}},
diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go
index 60e2be41d1..28a148b9ac 100644
--- a/libgo/go/net/http/readrequest_test.go
+++ b/libgo/go/net/http/readrequest_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -25,7 +25,7 @@ type reqTest struct {
}
var noError = ""
-var noBody = ""
+var noBodyStr = ""
var noTrailer Header = nil
var reqTests = []reqTest{
@@ -95,7 +95,7 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -121,7 +121,7 @@ var reqTests = []reqTest{
RequestURI: "//user@host/is/actually/a/path/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -131,7 +131,7 @@ var reqTests = []reqTest{
"GET ../../../../etc/passwd HTTP/1.1\r\n" +
"Host: test\r\n\r\n",
nil,
- noBody,
+ noBodyStr,
noTrailer,
"parse ../../../../etc/passwd: invalid URI for request",
},
@@ -141,7 +141,7 @@ var reqTests = []reqTest{
"GET HTTP/1.1\r\n" +
"Host: test\r\n\r\n",
nil,
- noBody,
+ noBodyStr,
noTrailer,
"parse : empty url",
},
@@ -227,7 +227,7 @@ var reqTests = []reqTest{
RequestURI: "www.google.com:443",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -251,7 +251,7 @@ var reqTests = []reqTest{
RequestURI: "127.0.0.1:6060",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -275,7 +275,7 @@ var reqTests = []reqTest{
RequestURI: "/_goRPC_",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -299,7 +299,7 @@ var reqTests = []reqTest{
RequestURI: "*",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -323,7 +323,7 @@ var reqTests = []reqTest{
RequestURI: "*",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -350,7 +350,7 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -376,7 +376,28 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
+ noTrailer,
+ noError,
+ },
+
+ // http2 client preface:
+ {
+ "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n",
+ &Request{
+ Method: "PRI",
+ URL: &url.URL{
+ Path: "*",
+ },
+ Header: Header{},
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ RequestURI: "*",
+ ContentLength: -1,
+ Close: true,
+ },
+ noBodyStr,
noTrailer,
noError,
},
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index 8cdab02af5..fb6bb0aab5 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -9,6 +9,7 @@ package http
import (
"bufio"
"bytes"
+ "context"
"crypto/tls"
"encoding/base64"
"errors"
@@ -17,11 +18,17 @@ import (
"io/ioutil"
"mime"
"mime/multipart"
+ "net"
+ "net/http/httptrace"
"net/textproto"
"net/url"
"strconv"
"strings"
"sync"
+
+ "golang_org/x/net/idna"
+ "golang_org/x/text/unicode/norm"
+ "golang_org/x/text/width"
)
const (
@@ -32,21 +39,40 @@ const (
// is either not present in the request or not a file field.
var ErrMissingFile = errors.New("http: no such file")
-// HTTP request parsing errors.
+// ProtocolError represents an HTTP protocol error.
+//
+// Deprecated: Not all errors in the http package related to protocol errors
+// are of type ProtocolError.
type ProtocolError struct {
ErrorString string
}
-func (err *ProtocolError) Error() string { return err.ErrorString }
+func (pe *ProtocolError) Error() string { return pe.ErrorString }
var (
- ErrHeaderTooLong = &ProtocolError{"header too long"}
- ErrShortBody = &ProtocolError{"entity body too short"}
- ErrNotSupported = &ProtocolError{"feature not supported"}
- ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+ // ErrNotSupported is returned by the Push method of Pusher
+ // implementations to indicate that HTTP/2 Push support is not
+ // available.
+ ErrNotSupported = &ProtocolError{"feature not supported"}
+
+ // ErrUnexpectedTrailer is returned by the Transport when a server
+ // replies with a Trailer header, but without a chunked reply.
+ ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+
+ // ErrMissingBoundary is returned by Request.MultipartReader when the
+ // request's Content-Type does not include a "boundary" parameter.
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
+
+ // ErrNotMultipart is returned by Request.MultipartReader when the
+ // request's Content-Type is not multipart/form-data.
+ ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+
+ // Deprecated: ErrHeaderTooLong is not used.
+ ErrHeaderTooLong = &ProtocolError{"header too long"}
+ // Deprecated: ErrShortBody is not used.
+ ErrShortBody = &ProtocolError{"entity body too short"}
+ // Deprecated: ErrMissingContentLength is not used.
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
- ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
- ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
)
type badStringError struct {
@@ -144,11 +170,20 @@ type Request struct {
// Handler does not need to.
Body io.ReadCloser
+ // GetBody defines an optional func to return a new copy of
+ // Body. It is used for client requests when a redirect requires
+ // reading the body more than once. Use of GetBody still
+ // requires setting Body.
+ //
+ // For server requests it is unused.
+ GetBody func() (io.ReadCloser, error)
+
// ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
- // For client requests, a value of 0 means unknown if Body is not nil.
+ // For client requests, a value of 0 with a non-nil Body is
+ // also treated as unknown.
ContentLength int64
// TransferEncoding lists the transfer encodings from outermost to
@@ -173,11 +208,15 @@ type Request struct {
// For server requests Host specifies the host on which the
// URL is sought. Per RFC 2616, this is either the value of
// the "Host" header or the host name given in the URL itself.
- // It may be of the form "host:port".
+ // It may be of the form "host:port". For international domain
+ // names, Host may be in Punycode or Unicode form. Use
+ // golang.org/x/net/idna to convert it to either format if
+ // needed.
//
// For client requests Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
- // the value of URL.Host.
+ // the value of URL.Host. Host may contain an international
+ // domain name.
Host string
// Form contains the parsed form data, including both the URL
@@ -247,7 +286,52 @@ type Request struct {
// RoundTripper may support Cancel.
//
// For server requests, this field is not applicable.
+ //
+ // Deprecated: Use the Context and WithContext methods
+ // instead. If a Request's Cancel field and context are both
+ // 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
+ // and mutating the contexts held by callers of the same request.
+ ctx context.Context
+}
+
+// Context returns the request's context. To change the context, use
+// WithContext.
+//
+// The returned context is always non-nil; it defaults to the
+// background context.
+//
+// For outgoing client requests, the context controls cancelation.
+//
+// For incoming server requests, the context is canceled when the
+// client's connection closes, the request is canceled (with HTTP/2),
+// or when the ServeHTTP method returns.
+func (r *Request) Context() context.Context {
+ if r.ctx != nil {
+ return r.ctx
+ }
+ return context.Background()
+}
+
+// WithContext returns a shallow copy of r with its context changed
+// to ctx. The provided ctx must be non-nil.
+func (r *Request) WithContext(ctx context.Context) *Request {
+ if ctx == nil {
+ panic("nil context")
+ }
+ r2 := new(Request)
+ *r2 = *r
+ r2.ctx = ctx
+ return r2
}
// ProtoAtLeast reports whether the HTTP protocol used
@@ -257,6 +341,18 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
r.ProtoMajor == major && r.ProtoMinor >= minor
}
+// protoAtLeastOutgoing is like ProtoAtLeast, but is for outgoing
+// requests (see issue 18407) where these fields aren't supposed to
+// matter. As a minor fix for Go 1.8, at least treat (0, 0) as
+// matching HTTP/1.1 or HTTP/1.0. Only HTTP/1.1 is used.
+// TODO(bradfitz): ideally remove this whole method. It shouldn't be used.
+func (r *Request) protoAtLeastOutgoing(major, minor int) bool {
+ if r.ProtoMajor == 0 && r.ProtoMinor == 0 && major == 1 && minor <= 1 {
+ return true
+ }
+ return r.ProtoAtLeast(major, minor)
+}
+
// UserAgent returns the client's User-Agent, if sent in the request.
func (r *Request) UserAgent() string {
return r.Header.Get("User-Agent")
@@ -272,6 +368,8 @@ var ErrNoCookie = errors.New("http: named cookie not present")
// Cookie returns the named cookie provided in the request or
// ErrNoCookie if not found.
+// If multiple cookies match the given name, only one cookie will
+// be returned.
func (r *Request) Cookie(name string) (*Cookie, error) {
for _, c := range readCookies(r.Header, name) {
return c, nil
@@ -279,8 +377,8 @@ func (r *Request) Cookie(name string) (*Cookie, error) {
return nil, ErrNoCookie
}
-// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
-// AddCookie does not attach more than one Cookie header field. That
+// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
+// AddCookie does not attach more than one Cookie header field. That
// means all cookies, if any, are written into the same line,
// separated by semicolon.
func (r *Request) AddCookie(c *Cookie) {
@@ -343,6 +441,12 @@ func (r *Request) multipartReader() (*multipart.Reader, error) {
return multipart.NewReader(r.Body, boundary), nil
}
+// isH2Upgrade reports whether r represents the http2 "client preface"
+// magic string.
+func (r *Request) isH2Upgrade() bool {
+ return r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0"
+}
+
// Return value if nonempty, def otherwise.
func valueOrDefault(value, def string) string {
if value != "" {
@@ -375,7 +479,7 @@ func (r *Request) Write(w io.Writer) error {
}
// WriteProxy is like Write but writes the request in the form
-// expected by an HTTP proxy. In particular, WriteProxy writes the
+// expected by an HTTP proxy. In particular, WriteProxy writes the
// initial Request-URI line of the request with an absolute URI, per
// section 5.1.2 of RFC 2616, including the scheme and host.
// In either case, WriteProxy also writes a Host header, using
@@ -390,7 +494,16 @@ var errMissingHost = errors.New("http: Request.Write on Request with no Host or
// extraHeaders may be nil
// waitForContinue may be nil
-func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) error {
+func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) {
+ trace := httptrace.ContextClientTrace(req.Context())
+ if trace != nil && trace.WroteRequest != nil {
+ defer func() {
+ trace.WroteRequest(httptrace.WroteRequestInfo{
+ Err: err,
+ })
+ }()
+ }
+
// Find the target host. Prefer the Host: header, but if that
// is not given, use the host from the request URL.
//
@@ -427,7 +540,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
w = bw
}
- _, err := fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
+ _, err = fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
if err != nil {
return err
}
@@ -478,6 +591,10 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
return err
}
+ if trace != nil && trace.WroteHeaders != nil {
+ trace.WroteHeaders()
+ }
+
// Flush and wait for 100-continue if expected.
if waitForContinue != nil {
if bw, ok := w.(*bufio.Writer); ok {
@@ -486,13 +603,21 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
return err
}
}
-
+ if trace != nil && trace.Wait100Continue != nil {
+ trace.Wait100Continue()
+ }
if !waitForContinue() {
req.closeBody()
return nil
}
}
+ if bw, ok := w.(*bufio.Writer); ok && tw.FlushHeaders {
+ if err := bw.Flush(); err != nil {
+ return err
+ }
+ }
+
// Write body and trailer
err = tw.WriteBody(w)
if err != nil {
@@ -505,7 +630,24 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
return nil
}
-// cleanHost strips anything after '/' or ' '.
+func idnaASCII(v string) (string, error) {
+ if isASCII(v) {
+ return v, nil
+ }
+ // The idna package doesn't do everything from
+ // https://tools.ietf.org/html/rfc5895 so we do it here.
+ // TODO(bradfitz): should the idna package do this instead?
+ v = strings.ToLower(v)
+ v = width.Fold.String(v)
+ v = norm.NFC.String(v)
+ return idna.ToASCII(v)
+}
+
+// cleanHost cleans up the host sent in request's Host header.
+//
+// It both strips anything after '/' or ' ', and puts the value
+// into Punycode form, if necessary.
+//
// Ideally we'd clean the Host header according to the spec:
// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
@@ -516,12 +658,24 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
// first offending character.
func cleanHost(in string) string {
if i := strings.IndexAny(in, " /"); i != -1 {
- return in[:i]
+ in = in[:i]
+ }
+ host, port, err := net.SplitHostPort(in)
+ if err != nil { // input was just a host
+ a, err := idnaASCII(in)
+ if err != nil {
+ return in // garbage in, garbage out
+ }
+ return a
+ }
+ a, err := idnaASCII(host)
+ if err != nil {
+ return in // garbage in, garbage out
}
- return in
+ return net.JoinHostPort(a, port)
}
-// removeZone removes IPv6 zone identifer from host.
+// removeZone removes IPv6 zone identifier from host.
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
func removeZone(host string) string {
if !strings.HasPrefix(host, "[") {
@@ -590,11 +744,17 @@ func validMethod(method string) bool {
// methods Do, Post, and PostForm, and Transport.RoundTrip.
//
// NewRequest returns a Request suitable for use with Client.Do or
-// Transport.RoundTrip.
-// To create a request for use with testing a Server Handler use either
-// ReadRequest or manually update the Request fields. See the Request
-// type's documentation for the difference between inbound and outbound
-// request fields.
+// Transport.RoundTrip. To create a request for use with testing a
+// Server Handler, either use the NewRequest function in the
+// net/http/httptest package, use ReadRequest, or manually update the
+// Request fields. See the Request type's documentation for the
+// difference between inbound and outbound request fields.
+//
+// If body is of type *bytes.Buffer, *bytes.Reader, or
+// *strings.Reader, the returned request's ContentLength is set to its
+// exact value (instead of -1), GetBody is populated (so 307 and 308
+// redirects can replay the body), and Body is set to NoBody if the
+// ContentLength is 0.
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
if method == "" {
// We document that "" means "GET" for Request.Method, and people have
@@ -613,6 +773,8 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
if !ok && body != nil {
rc = ioutil.NopCloser(body)
}
+ // The host's colon:port should be normalized. See Issue 14836.
+ u.Host = removeEmptyPort(u.Host)
req := &Request{
Method: method,
URL: u,
@@ -627,10 +789,43 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
switch v := body.(type) {
case *bytes.Buffer:
req.ContentLength = int64(v.Len())
+ buf := v.Bytes()
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := bytes.NewReader(buf)
+ return ioutil.NopCloser(r), nil
+ }
case *bytes.Reader:
req.ContentLength = int64(v.Len())
+ snapshot := *v
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := snapshot
+ return ioutil.NopCloser(&r), nil
+ }
case *strings.Reader:
req.ContentLength = int64(v.Len())
+ snapshot := *v
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := snapshot
+ return ioutil.NopCloser(&r), nil
+ }
+ default:
+ // This is where we'd set it to -1 (at least
+ // if body != NoBody) to mean unknown, but
+ // that broke people during the Go 1.8 testing
+ // period. People depend on it being 0 I
+ // guess. Maybe retry later. See Issue 18117.
+ }
+ // For client requests, Request.ContentLength of 0
+ // means either actually 0, or unknown. The only way
+ // to explicitly say that the ContentLength is zero is
+ // to set the Body to nil. But turns out too much code
+ // depends on NewRequest returning a non-nil Body,
+ // so we use a well-known ReadCloser variable instead
+ // and have the http package also treat that sentinel
+ // variable to mean explicitly zero.
+ if req.GetBody != nil && req.ContentLength == 0 {
+ req.Body = NoBody
+ req.GetBody = func() (io.ReadCloser, error) { return NoBody, nil }
}
}
@@ -704,7 +899,9 @@ func putTextprotoReader(r *textproto.Reader) {
}
// ReadRequest reads and parses an incoming request from b.
-func ReadRequest(b *bufio.Reader) (req *Request, err error) { return readRequest(b, deleteHostHeader) }
+func ReadRequest(b *bufio.Reader) (*Request, error) {
+ return readRequest(b, deleteHostHeader)
+}
// Constants for readRequest's deleteHostHeader parameter.
const (
@@ -768,13 +965,13 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
}
req.Header = Header(mimeHeader)
- // RFC2616: Must treat
+ // RFC 2616: Must treat
// GET /index.html HTTP/1.1
// Host: www.google.com
// and
// GET http://www.google.com/index.html HTTP/1.1
// Host: doesntmatter
- // the same. In the second case, any Host line is ignored.
+ // the same. In the second case, any Host line is ignored.
req.Host = req.URL.Host
if req.Host == "" {
req.Host = req.Header.get("Host")
@@ -792,6 +989,16 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
return nil, err
}
+ if req.isH2Upgrade() {
+ // Because it's neither chunked, nor declared:
+ req.ContentLength = -1
+
+ // We want to give handlers a chance to hijack the
+ // connection, but we need to prevent the Server from
+ // dealing with the connection further if it's not
+ // hijacked. Set Close to ensure that:
+ req.Close = true
+ }
return req, nil
}
@@ -808,57 +1015,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
- if res, ok := l.w.(*response); ok {
- res.requestTooLarge()
- }
- }
- return 0, errors.New("http: request body too large")
+ l.err = errors.New("http: request body too large")
+ return 0, l.err
}
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
- toRead := l.n
- if l.n == 0 {
- if l.sawEOF {
- return l.tooLarge()
- }
- // The underlying io.Reader may not return (0, io.EOF)
- // at EOF if the requested size is 0, so read 1 byte
- // instead. The io.Reader docs are a bit ambiguous
- // about the return value of Read when 0 bytes are
- // requested, and {bytes,strings}.Reader gets it wrong
- // too (it returns (0, nil) even at EOF).
- toRead = 1
+ if l.err != nil {
+ return 0, l.err
+ }
+ if len(p) == 0 {
+ return 0, nil
}
- if int64(len(p)) > toRead {
- p = p[:toRead]
+ // If they asked for a 32KB byte read but only 5 bytes are
+ // remaining, no need to read 32KB. 6 bytes will answer the
+ // question of the whether we hit the limit or go past it.
+ if int64(len(p)) > l.n+1 {
+ p = p[:l.n+1]
}
n, err = l.r.Read(p)
- if err == io.EOF {
- l.sawEOF = true
- }
- if l.n == 0 {
- // If we had zero bytes to read remaining (but hadn't seen EOF)
- // and we get a byte here, that means we went over our limit.
- if n > 0 {
- return l.tooLarge()
- }
- return 0, err
+
+ if int64(n) <= l.n {
+ l.n -= int64(n)
+ l.err = err
+ return n, err
}
- l.n -= int64(n)
- if l.n < 0 {
- l.n = 0
+
+ n = int(l.n)
+ l.n = 0
+
+ // The server code and client code both use
+ // maxBytesReader. This "requestTooLarge" check is
+ // only used by the server code. To prevent binaries
+ // which only using the HTTP Client code (such as
+ // cmd/go) from also linking in the HTTP server, don't
+ // use a static type assertion to the server
+ // "*response" type. Check this interface instead:
+ type requestTooLarger interface {
+ requestTooLarge()
}
- return
+ if res, ok := l.w.(requestTooLarger); ok {
+ res.requestTooLarge()
+ }
+ l.err = errors.New("http: request body too large")
+ return n, l.err
}
func (l *maxBytesReader) Close() error {
@@ -919,18 +1125,24 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
-// ParseForm parses the raw query from the URL and updates r.Form.
+// ParseForm populates r.Form and r.PostForm.
+//
+// For all requests, ParseForm parses the raw query from the URL and updates
+// r.Form.
//
-// For POST or PUT requests, it also parses the request body as a form and
-// put the results into both r.PostForm and r.Form.
-// POST and PUT body parameters take precedence over URL query string values
-// in r.Form.
+// For POST, PUT, and PATCH requests, it also parses the request body as a form
+// and puts the results into both r.PostForm and r.Form. Request body parameters
+// take precedence over URL query string values in r.Form.
+//
+// For other HTTP methods, or when the Content-Type is not
+// application/x-www-form-urlencoded, the request Body is not read, and
+// r.PostForm is initialized to a non-nil, empty value.
//
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.
//
// ParseMultipartForm calls ParseForm automatically.
-// It is idempotent.
+// ParseForm is idempotent.
func (r *Request) ParseForm() error {
var err error
if r.PostForm == nil {
@@ -995,9 +1207,16 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
if err != nil {
return err
}
+
+ if r.PostForm == nil {
+ r.PostForm = make(url.Values)
+ }
for k, v := range f.Value {
r.Form[k] = append(r.Form[k], v...)
+ // r.PostForm should also be populated. See Issue 9305.
+ r.PostForm[k] = append(r.PostForm[k], v...)
}
+
r.MultipartForm = f
return nil
@@ -1087,91 +1306,29 @@ func (r *Request) isReplayable() bool {
return false
}
-func validHostHeader(h string) bool {
- // The latests spec is actually this:
- //
- // http://tools.ietf.org/html/rfc7230#section-5.4
- // Host = uri-host [ ":" port ]
- //
- // Where uri-host is:
- // http://tools.ietf.org/html/rfc3986#section-3.2.2
- //
- // But we're going to be much more lenient for now and just
- // search for any byte that's not a valid byte in any of those
- // expressions.
- for i := 0; i < len(h); i++ {
- if !validHostByte[h[i]] {
- return false
- }
+// outgoingLength reports the Content-Length of this outgoing (Client) request.
+// It maps 0 into -1 (unknown) when the Body is non-nil.
+func (r *Request) outgoingLength() int64 {
+ if r.Body == nil || r.Body == NoBody {
+ return 0
}
- return true
-}
-
-// See the validHostHeader comment.
-var validHostByte = [256]bool{
- '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, 'v': true, 'w': true, 'x': true,
- 'y': true, 'z': 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, // sub-delims
- '$': true, // sub-delims
- '%': true, // pct-encoded (and used in IPv6 zones)
- '&': true, // sub-delims
- '(': true, // sub-delims
- ')': true, // sub-delims
- '*': true, // sub-delims
- '+': true, // sub-delims
- ',': true, // sub-delims
- '-': true, // unreserved
- '.': true, // unreserved
- ':': true, // IPv6address + Host expression's optional port
- ';': true, // sub-delims
- '=': true, // sub-delims
- '[': true,
- '\'': true, // sub-delims
- ']': true,
- '_': true, // unreserved
- '~': true, // unreserved
-}
-
-func validHeaderName(v string) bool {
- if len(v) == 0 {
- return false
+ if r.ContentLength != 0 {
+ return r.ContentLength
}
- return strings.IndexFunc(v, isNotToken) == -1
+ return -1
}
-// validHeaderValue 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 ]
-// field-value = *( field-content | LWS )
-// field-content = <the OCTETs making up the field-value
-// and consisting of either *TEXT or combinations
-// of token, separators, and quoted-string>
-//
-// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
-//
-// TEXT = <any OCTET except CTLs,
-// but including LWS>
-// LWS = [CRLF] 1*( SP | HT )
-// CTL = <any US-ASCII control character
-// (octets 0 - 31) and DEL (127)>
-func validHeaderValue(v string) bool {
- for i := 0; i < len(v); i++ {
- b := v[i]
- if isCTL(b) && !isLWS(b) {
- return false
- }
+// requestMethodUsuallyLacksBody reports whether the given request
+// method is one that typically does not involve a request body.
+// This is used by the Transport (via
+// transferWriter.shouldSendChunkedRequestBody) to determine whether
+// we try to test-read a byte from a non-nil Request.Body when
+// Request.outgoingLength() returns -1. See the comments in
+// shouldSendChunkedRequestBody.
+func requestMethodUsuallyLacksBody(method string) bool {
+ switch method {
+ case "GET", "HEAD", "DELETE", "OPTIONS", "PROPFIND", "SEARCH":
+ return true
}
- return true
+ return false
}
diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go
index 0ecdf85a56..e6748375b5 100644
--- a/libgo/go/net/http/request_test.go
+++ b/libgo/go/net/http/request_test.go
@@ -29,9 +29,9 @@ func TestQuery(t *testing.T) {
}
}
-func TestPostQuery(t *testing.T) {
- req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
- strings.NewReader("z=post&both=y&prio=2&empty="))
+func TestParseFormQuery(t *testing.T) {
+ req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
if q := req.FormValue("q"); q != "foo" {
@@ -55,39 +55,30 @@ func TestPostQuery(t *testing.T) {
if prio := req.FormValue("prio"); prio != "2" {
t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
}
- if empty := req.FormValue("empty"); empty != "" {
+ if orphan := req.Form["orphan"]; !reflect.DeepEqual(orphan, []string{"", "nope"}) {
+ t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
+ }
+ if empty := req.Form["empty"]; !reflect.DeepEqual(empty, []string{"", "not"}) {
t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
}
+ if nokey := req.Form[""]; !reflect.DeepEqual(nokey, []string{"nokey"}) {
+ t.Errorf(`req.FormValue("nokey") = %q, want "nokey" (from body)`, nokey)
+ }
}
-func TestPatchQuery(t *testing.T) {
- req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
- strings.NewReader("z=post&both=y&prio=2&empty="))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
-
- if q := req.FormValue("q"); q != "foo" {
- t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
- }
- if z := req.FormValue("z"); z != "post" {
- t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
- }
- if bq, found := req.PostForm["q"]; found {
- t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
- }
- if bz := req.PostFormValue("z"); bz != "post" {
- t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
- }
- if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
- t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
- }
- if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
- t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
- }
- if prio := req.FormValue("prio"); prio != "2" {
- t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
- }
- if empty := req.FormValue("empty"); empty != "" {
- t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
+// Tests that we only parse the form automatically for certain methods.
+func TestParseFormQueryMethods(t *testing.T) {
+ for _, method := range []string{"POST", "PATCH", "PUT", "FOO"} {
+ req, _ := NewRequest(method, "http://www.google.com/search",
+ strings.NewReader("foo=bar"))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+ want := "bar"
+ if method == "FOO" {
+ want = ""
+ }
+ if got := req.FormValue("foo"); got != want {
+ t.Errorf(`for method %s, FormValue("foo") = %q; want %q`, method, got, want)
+ }
}
}
@@ -99,7 +90,7 @@ type parseContentTypeTest struct {
var parseContentTypeTests = []parseContentTypeTest{
{false, stringMap{"Content-Type": {"text/plain"}}},
- // Empty content type is legal - shoult be treated as
+ // Empty content type is legal - should be treated as
// application/octet-stream (RFC 2616, section 7.2.1)
{false, stringMap{}},
{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
@@ -158,6 +149,68 @@ func TestMultipartReader(t *testing.T) {
}
}
+// Issue 9305: ParseMultipartForm should populate PostForm too
+func TestParseMultipartFormPopulatesPostForm(t *testing.T) {
+ postData :=
+ `--xxx
+Content-Disposition: form-data; name="field1"
+
+value1
+--xxx
+Content-Disposition: form-data; name="field2"
+
+value2
+--xxx
+Content-Disposition: form-data; name="file"; filename="file"
+Content-Type: application/octet-stream
+Content-Transfer-Encoding: binary
+
+binary data
+--xxx--
+`
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
+ Body: ioutil.NopCloser(strings.NewReader(postData)),
+ }
+
+ initialFormItems := map[string]string{
+ "language": "Go",
+ "name": "gopher",
+ "skill": "go-ing",
+ "field2": "initial-value2",
+ }
+
+ req.Form = make(url.Values)
+ for k, v := range initialFormItems {
+ req.Form.Add(k, v)
+ }
+
+ err := req.ParseMultipartForm(10000)
+ if err != nil {
+ t.Fatalf("unexpected multipart error %v", err)
+ }
+
+ wantForm := url.Values{
+ "language": []string{"Go"},
+ "name": []string{"gopher"},
+ "skill": []string{"go-ing"},
+ "field1": []string{"value1"},
+ "field2": []string{"initial-value2", "value2"},
+ }
+ if !reflect.DeepEqual(req.Form, wantForm) {
+ t.Fatalf("req.Form = %v, want %v", req.Form, wantForm)
+ }
+
+ wantPostForm := url.Values{
+ "field1": []string{"value1"},
+ "field2": []string{"value2"},
+ }
+ if !reflect.DeepEqual(req.PostForm, wantPostForm) {
+ t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm)
+ }
+}
+
func TestParseMultipartForm(t *testing.T) {
req := &Request{
Method: "POST",
@@ -312,18 +365,68 @@ func TestFormFileOrder(t *testing.T) {
var readRequestErrorTests = []struct {
in string
- err error
+ err string
+
+ header Header
}{
- {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
- {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
- {"", io.EOF},
+ 0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}},
+ 1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
+ 2: {"", io.EOF.Error(), nil},
+ 3: {
+ in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
+ err: "http: method cannot contain a Content-Length",
+ },
+ 4: {
+ in: "HEAD / HTTP/1.1\r\n\r\n",
+ header: Header{},
+ },
+
+ // Multiple Content-Length values should either be
+ // deduplicated if same or reject otherwise
+ // See Issue 16490.
+ 5: {
+ in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 6: {
+ in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 7: {
+ in: "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
+ err: "",
+ header: Header{"Content-Length": {"6"}},
+ },
+ 8: {
+ in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 9: {
+ in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 10: {
+ in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
+ header: Header{"Content-Length": {"0"}},
+ },
}
func TestReadRequestErrors(t *testing.T) {
for i, tt := range readRequestErrorTests {
- _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
- if err != tt.err {
- t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err == nil {
+ if tt.err != "" {
+ t.Errorf("#%d: got nil err; want %q", i, tt.err)
+ }
+
+ if !reflect.DeepEqual(tt.header, req.Header) {
+ t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header)
+ }
+ continue
+ }
+
+ if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
+ t.Errorf("%d: got error = %v; want %v", i, err, tt.err)
}
}
}
@@ -336,11 +439,13 @@ var newRequestHostTests = []struct {
{"http://192.168.0.1/", "192.168.0.1"},
{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
+ {"http://192.168.0.1:/", "192.168.0.1"},
{"http://[fe80::1]/", "[fe80::1]"},
{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
+ {"http://[fe80::1%25en0]:/", "[fe80::1%en0]"},
}
func TestNewRequestHost(t *testing.T) {
@@ -392,18 +497,23 @@ func TestNewRequestContentLength(t *testing.T) {
{bytes.NewReader([]byte("123")), 3},
{bytes.NewBuffer([]byte("1234")), 4},
{strings.NewReader("12345"), 5},
- // Not detected:
+ {strings.NewReader(""), 0},
+ {NoBody, 0},
+
+ // Not detected. During Go 1.8 we tried to make these set to -1, but
+ // due to Issue 18117, we keep these returning 0, even though they're
+ // unknown.
{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
}
- for _, tt := range tests {
+ for i, tt := range tests {
req, err := NewRequest("POST", "http://localhost/", tt.r)
if err != nil {
t.Fatal(err)
}
if req.ContentLength != tt.want {
- t.Errorf("ContentLength(%T) = %d; want %d", tt.r, req.ContentLength, tt.want)
+ t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want)
}
}
}
@@ -562,11 +672,31 @@ func TestStarRequest(t *testing.T) {
if err != nil {
return
}
+ if req.ContentLength != 0 {
+ t.Errorf("ContentLength = %d; want 0", req.ContentLength)
+ }
+ if req.Body == nil {
+ t.Errorf("Body = nil; want non-nil")
+ }
+
+ // Request.Write has Client semantics for Body/ContentLength,
+ // where ContentLength 0 means unknown if Body is non-nil, and
+ // thus chunking will happen unless we change semantics and
+ // signal that we want to serialize it as exactly zero. The
+ // only way to do that for outbound requests is with a nil
+ // Body:
+ clientReq := *req
+ clientReq.Body = nil
+
var out bytes.Buffer
- if err := req.Write(&out); err != nil {
+ if err := clientReq.Write(&out); err != nil {
t.Fatal(err)
}
- back, err := ReadRequest(bufio.NewReader(&out))
+
+ if strings.Contains(out.String(), "chunked") {
+ t.Error("wrote chunked request; want no body")
+ }
+ back, err := ReadRequest(bufio.NewReader(bytes.NewReader(out.Bytes())))
if err != nil {
t.Fatal(err)
}
@@ -615,6 +745,87 @@ 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)
+ }
+ }
+}
+
+// verify that NewRequest sets Request.GetBody and that it works
+func TestNewRequestGetBody(t *testing.T) {
+ tests := []struct {
+ r io.Reader
+ }{
+ {r: strings.NewReader("hello")},
+ {r: bytes.NewReader([]byte("hello"))},
+ {r: bytes.NewBuffer([]byte("hello"))},
+ }
+ for i, tt := range tests {
+ req, err := NewRequest("POST", "http://foo.tld/", tt.r)
+ if err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ continue
+ }
+ if req.Body == nil {
+ t.Errorf("test[%d]: Body = nil", i)
+ continue
+ }
+ if req.GetBody == nil {
+ t.Errorf("test[%d]: GetBody = nil", i)
+ continue
+ }
+ slurp1, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ t.Errorf("test[%d]: ReadAll(Body) = %v", i, err)
+ }
+ newBody, err := req.GetBody()
+ if err != nil {
+ t.Errorf("test[%d]: GetBody = %v", i, err)
+ }
+ slurp2, err := ioutil.ReadAll(newBody)
+ if err != nil {
+ t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err)
+ }
+ if string(slurp1) != string(slurp2) {
+ t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go
index cfb95b0a80..eb65b9f736 100644
--- a/libgo/go/net/http/requestwrite_test.go
+++ b/libgo/go/net/http/requestwrite_test.go
@@ -1,18 +1,21 @@
-// Copyright 2010 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 http
import (
+ "bufio"
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
+ "net"
"net/url"
"strings"
"testing"
+ "time"
)
type reqWriteTest struct {
@@ -28,7 +31,7 @@ type reqWriteTest struct {
var reqWriteTests = []reqWriteTest{
// HTTP/1.1 => chunked coding; no body; no trailer
- {
+ 0: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -75,7 +78,7 @@ var reqWriteTests = []reqWriteTest{
"Proxy-Connection: keep-alive\r\n\r\n",
},
// HTTP/1.1 => chunked coding; body; empty trailer
- {
+ 1: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -104,7 +107,7 @@ var reqWriteTests = []reqWriteTest{
chunk("abcdef") + chunk(""),
},
// HTTP/1.1 POST => chunked coding; body; empty trailer
- {
+ 2: {
Req: Request{
Method: "POST",
URL: &url.URL{
@@ -137,7 +140,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 POST with Content-Length, no chunking
- {
+ 3: {
Req: Request{
Method: "POST",
URL: &url.URL{
@@ -172,7 +175,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 POST with Content-Length in headers
- {
+ 4: {
Req: Request{
Method: "POST",
URL: mustParseURL("http://example.com/"),
@@ -201,7 +204,7 @@ var reqWriteTests = []reqWriteTest{
},
// default to HTTP/1.1
- {
+ 5: {
Req: Request{
Method: "GET",
URL: mustParseURL("/search"),
@@ -215,7 +218,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a 0 byte body.
- {
+ 6: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -227,9 +230,32 @@ var reqWriteTests = []reqWriteTest{
Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
- // RFC 2616 Section 14.13 says Content-Length should be specified
- // unless body is prohibited by the request method.
- // Also, nginx expects it for POST and PUT.
+ WantWrite: "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n0\r\n\r\n",
+
+ WantProxy: "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n0\r\n\r\n",
+ },
+
+ // Request with a 0 ContentLength and a nil body.
+ 7: {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser { return nil },
+
WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"User-Agent: Go-http-client/1.1\r\n" +
@@ -244,7 +270,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a 1 byte body.
- {
+ 8: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -270,7 +296,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a ContentLength of 10 but a 5 byte body.
- {
+ 9: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -284,7 +310,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a ContentLength of 4 but an 8 byte body.
- {
+ 10: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -298,7 +324,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 5 ContentLength and nil body.
- {
+ 11: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -311,7 +337,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a body with 1 byte content and an error.
- {
+ 12: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -331,7 +357,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a body without content and an error.
- {
+ 13: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -352,7 +378,7 @@ var reqWriteTests = []reqWriteTest{
// Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
// and doesn't add a User-Agent.
- {
+ 14: {
Req: Request{
Method: "GET",
URL: mustParseURL("/foo"),
@@ -373,7 +399,7 @@ var reqWriteTests = []reqWriteTest{
// an empty Host header, and don't use
// Request.Header["Host"]. This is just testing that
// we don't change Go 1.0 behavior.
- {
+ 15: {
Req: Request{
Method: "GET",
Host: "",
@@ -395,7 +421,7 @@ var reqWriteTests = []reqWriteTest{
},
// Opaque test #1 from golang.org/issue/4860
- {
+ 16: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -414,7 +440,7 @@ var reqWriteTests = []reqWriteTest{
},
// Opaque test #2 from golang.org/issue/4860
- {
+ 17: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -433,7 +459,7 @@ var reqWriteTests = []reqWriteTest{
},
// Testing custom case in header keys. Issue 5022.
- {
+ 18: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -457,7 +483,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with host header field; IPv6 address with zone identifier
- {
+ 19: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -472,7 +498,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with optional host header field; IPv6 address with zone identifier
- {
+ 20: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -543,6 +569,138 @@ func TestRequestWrite(t *testing.T) {
}
}
+func TestRequestWriteTransport(t *testing.T) {
+ t.Parallel()
+
+ matchSubstr := func(substr string) func(string) error {
+ return func(written string) error {
+ if !strings.Contains(written, substr) {
+ return fmt.Errorf("expected substring %q in request: %s", substr, written)
+ }
+ return nil
+ }
+ }
+
+ noContentLengthOrTransferEncoding := func(req string) error {
+ if strings.Contains(req, "Content-Length: ") {
+ return fmt.Errorf("unexpected Content-Length in request: %s", req)
+ }
+ if strings.Contains(req, "Transfer-Encoding: ") {
+ return fmt.Errorf("unexpected Transfer-Encoding in request: %s", req)
+ }
+ return nil
+ }
+
+ all := func(checks ...func(string) error) func(string) error {
+ return func(req string) error {
+ for _, c := range checks {
+ if err := c(req); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ }
+
+ type testCase struct {
+ method string
+ clen int64 // ContentLength
+ body io.ReadCloser
+ want func(string) error
+
+ // optional:
+ init func(*testCase)
+ afterReqRead func()
+ }
+
+ tests := []testCase{
+ {
+ method: "GET",
+ want: noContentLengthOrTransferEncoding,
+ },
+ {
+ method: "GET",
+ body: ioutil.NopCloser(strings.NewReader("")),
+ want: noContentLengthOrTransferEncoding,
+ },
+ {
+ method: "GET",
+ clen: -1,
+ body: ioutil.NopCloser(strings.NewReader("")),
+ want: noContentLengthOrTransferEncoding,
+ },
+ // A GET with a body, with explicit content length:
+ {
+ method: "GET",
+ clen: 7,
+ body: ioutil.NopCloser(strings.NewReader("foobody")),
+ want: all(matchSubstr("Content-Length: 7"),
+ matchSubstr("foobody")),
+ },
+ // A GET with a body, sniffing the leading "f" from "foobody".
+ {
+ method: "GET",
+ clen: -1,
+ body: ioutil.NopCloser(strings.NewReader("foobody")),
+ want: all(matchSubstr("Transfer-Encoding: chunked"),
+ matchSubstr("\r\n1\r\nf\r\n"),
+ matchSubstr("oobody")),
+ },
+ // But a POST request is expected to have a body, so
+ // no sniffing happens:
+ {
+ method: "POST",
+ clen: -1,
+ body: ioutil.NopCloser(strings.NewReader("foobody")),
+ want: all(matchSubstr("Transfer-Encoding: chunked"),
+ matchSubstr("foobody")),
+ },
+ {
+ method: "POST",
+ clen: -1,
+ body: ioutil.NopCloser(strings.NewReader("")),
+ want: all(matchSubstr("Transfer-Encoding: chunked")),
+ },
+ // Verify that a blocking Request.Body doesn't block forever.
+ {
+ method: "GET",
+ clen: -1,
+ init: func(tt *testCase) {
+ pr, pw := io.Pipe()
+ tt.afterReqRead = func() {
+ pw.Close()
+ }
+ tt.body = ioutil.NopCloser(pr)
+ },
+ want: matchSubstr("Transfer-Encoding: chunked"),
+ },
+ }
+
+ for i, tt := range tests {
+ if tt.init != nil {
+ tt.init(&tt)
+ }
+ req := &Request{
+ Method: tt.method,
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "example.com",
+ },
+ Header: make(Header),
+ ContentLength: tt.clen,
+ Body: tt.body,
+ }
+ got, err := dumpRequestOut(req, tt.afterReqRead)
+ if err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ continue
+ }
+ if err := tt.want(string(got)); err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ }
+ }
+}
+
type closeChecker struct {
io.Reader
closed bool
@@ -553,17 +711,19 @@ func (rc *closeChecker) Close() error {
return nil
}
-// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
+// TestRequestWriteClosesBody tests that Request.Write closes its request.Body.
// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
// inside a NopCloser, and that it serializes it correctly.
func TestRequestWriteClosesBody(t *testing.T) {
rc := &closeChecker{Reader: strings.NewReader("my body")}
- req, _ := NewRequest("POST", "http://foo.com/", rc)
- if req.ContentLength != 0 {
- t.Errorf("got req.ContentLength %d, want 0", req.ContentLength)
+ req, err := NewRequest("POST", "http://foo.com/", rc)
+ if err != nil {
+ t.Fatal(err)
}
buf := new(bytes.Buffer)
- req.Write(buf)
+ if err := req.Write(buf); err != nil {
+ t.Error(err)
+ }
if !rc.closed {
t.Error("body not closed after write")
}
@@ -571,12 +731,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
"Host: foo.com\r\n" +
"User-Agent: Go-http-client/1.1\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
- // TODO: currently we don't buffer before chunking, so we get a
- // single "m" chunk before the other chunks, as this was the 1-byte
- // read from our MultiReader where we stiched the Body back together
- // after sniffing whether the Body was 0 bytes or not.
- chunk("m") +
- chunk("y body") +
+ chunk("my body") +
chunk("")
if buf.String() != expected {
t.Errorf("write:\n got: %s\nwant: %s", buf.String(), expected)
@@ -604,7 +759,7 @@ func TestRequestWriteError(t *testing.T) {
failAfter, writeCount := 0, 0
errFail := errors.New("fake write failure")
- // w is the buffered io.Writer to write the request to. It
+ // w is the buffered io.Writer to write the request to. It
// fails exactly once on its Nth Write call, as controlled by
// failAfter. It also tracks the number of calls in
// writeCount.
@@ -652,3 +807,76 @@ func TestRequestWriteError(t *testing.T) {
t.Fatalf("writeCalls constant is outdated in test")
}
}
+
+// dumpRequestOut is a modified copy of net/http/httputil.DumpRequestOut.
+// Unlike the original, this version doesn't mutate the req.Body and
+// try to restore it. It always dumps the whole body.
+// And it doesn't support https.
+func dumpRequestOut(req *Request, onReadHeaders func()) ([]byte, error) {
+
+ // Use the actual Transport code to record what we would send
+ // on the wire, but not using TCP. Use a Transport with a
+ // custom dialer that returns a fake net.Conn that waits
+ // for the full input (and recording it), and then responds
+ // with a dummy response.
+ var buf bytes.Buffer // records the output
+ pr, pw := io.Pipe()
+ defer pr.Close()
+ defer pw.Close()
+ dr := &delegateReader{c: make(chan io.Reader)}
+
+ t := &Transport{
+ Dial: func(net, addr string) (net.Conn, error) {
+ return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
+ },
+ }
+ defer t.CloseIdleConnections()
+
+ // Wait for the request before replying with a dummy response:
+ go func() {
+ req, err := ReadRequest(bufio.NewReader(pr))
+ if err == nil {
+ if onReadHeaders != nil {
+ onReadHeaders()
+ }
+ // Ensure all the body is read; otherwise
+ // we'll get a partial dump.
+ io.Copy(ioutil.Discard, req.Body)
+ req.Body.Close()
+ }
+ dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
+ }()
+
+ _, err := t.RoundTrip(req)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// delegateReader is a reader that delegates to another reader,
+// once it arrives on a channel.
+type delegateReader struct {
+ c chan io.Reader
+ r io.Reader // nil until received from c
+}
+
+func (r *delegateReader) Read(p []byte) (int, error) {
+ if r.r == nil {
+ r.r = <-r.c
+ }
+ return r.r.Read(p)
+}
+
+// dumpConn is a net.Conn that writes to Writer and reads from Reader.
+type dumpConn struct {
+ io.Writer
+ io.Reader
+}
+
+func (c *dumpConn) Close() error { return nil }
+func (c *dumpConn) LocalAddr() net.Addr { return nil }
+func (c *dumpConn) RemoteAddr() net.Addr { return nil }
+func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
diff --git a/libgo/go/net/http/response.go b/libgo/go/net/http/response.go
index c424f61cd0..ae118fb386 100644
--- a/libgo/go/net/http/response.go
+++ b/libgo/go/net/http/response.go
@@ -11,6 +11,7 @@ import (
"bytes"
"crypto/tls"
"errors"
+ "fmt"
"io"
"net/textproto"
"net/url"
@@ -33,7 +34,7 @@ type Response struct {
ProtoMajor int // e.g. 1
ProtoMinor int // e.g. 0
- // Header maps header keys to values. If the response had multiple
+ // Header maps header keys to values. If the response had multiple
// headers with the same key, they may be concatenated, with comma
// delimiters. (Section 4.2 of RFC 2616 requires that multiple headers
// be semantically equivalent to a comma-delimited sequence.) Values
@@ -57,8 +58,8 @@ type Response struct {
// with a "chunked" Transfer-Encoding.
Body io.ReadCloser
- // ContentLength records the length of the associated content. The
- // value -1 indicates that the length is unknown. Unless Request.Method
+ // ContentLength records the length of the associated content. The
+ // value -1 indicates that the length is unknown. Unless Request.Method
// is "HEAD", values >= 0 indicate that the given number of bytes may
// be read from Body.
ContentLength int64
@@ -68,10 +69,19 @@ type Response struct {
TransferEncoding []string
// Close records whether the header directed that the connection be
- // closed after reading Body. The value is advice for clients: neither
+ // closed after reading Body. The value is advice for clients: neither
// ReadResponse nor Response.Write ever closes a connection.
Close bool
+ // Uncompressed reports whether the response was sent compressed but
+ // was decompressed by the http package. When true, reading from
+ // Body yields the uncompressed content instead of the compressed
+ // content actually set from the server, ContentLength is set to -1,
+ // and the "Content-Length" and "Content-Encoding" fields are deleted
+ // from the responseHeader. To get the original response from
+ // the server, set Transport.DisableCompression to true.
+ Uncompressed bool
+
// Trailer maps trailer keys to values in the same
// format as Header.
//
@@ -86,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
@@ -108,8 +118,8 @@ func (r *Response) Cookies() []*Cookie {
var ErrNoLocation = errors.New("http: no Location header in response")
// Location returns the URL of the response's "Location" header,
-// if present. Relative redirects are resolved relative to
-// the Response's Request. ErrNoLocation is returned if no
+// if present. Relative redirects are resolved relative to
+// the Response's Request. ErrNoLocation is returned if no
// Location header is present.
func (r *Response) Location() (*url.URL, error) {
lv := r.Header.Get("Location")
@@ -184,7 +194,7 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
return resp, nil
}
-// RFC2616: Should treat
+// RFC 2616: Should treat
// Pragma: no-cache
// like
// Cache-Control: no-cache
@@ -203,7 +213,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
r.ProtoMajor == major && r.ProtoMinor >= minor
}
-// Write writes r to w in the HTTP/1.n server response format,
+// Write writes r to w in the HTTP/1.x server response format,
// including the status line, headers, body, and optional trailer.
//
// This method consults the following fields of the response r:
@@ -228,11 +238,13 @@ func (r *Response) Write(w io.Writer) error {
if !ok {
text = "status code " + strconv.Itoa(r.StatusCode)
}
+ } else {
+ // Just to reduce stutter, if user set r.Status to "200 OK" and StatusCode to 200.
+ // Not important.
+ text = strings.TrimPrefix(text, strconv.Itoa(r.StatusCode)+" ")
}
- protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
- statusCode := strconv.Itoa(r.StatusCode) + " "
- text = strings.TrimPrefix(text, statusCode)
- if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil {
+
+ if _, err := fmt.Fprintf(w, "HTTP/%d.%d %03d %s\r\n", r.ProtoMajor, r.ProtoMinor, r.StatusCode, text); err != nil {
return err
}
@@ -249,7 +261,7 @@ func (r *Response) Write(w io.Writer) error {
if n == 0 {
// Reset it to a known zero reader, in case underlying one
// is unhappy being read repeatedly.
- r1.Body = eofReader
+ r1.Body = NoBody
} else {
r1.ContentLength = -1
r1.Body = struct {
@@ -265,7 +277,7 @@ func (r *Response) Write(w io.Writer) error {
// content-length, the only way to do that is the old HTTP/1.0
// way, by noting the EOF with a connection close, so we need
// to set Close.
- if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) {
+ if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) && !r1.Uncompressed {
r1.Close = true
}
@@ -288,7 +300,7 @@ func (r *Response) Write(w io.Writer) error {
// contentLengthAlreadySent may have been already sent for
// POST/PUT requests, even if zero length. See Issue 8180.
contentLengthAlreadySent := tw.shouldSendContentLength()
- if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent {
+ if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent && bodyAllowedForStatus(r.StatusCode) {
if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil {
return err
}
diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go
index d8a53400cf..660d51791b 100644
--- a/libgo/go/net/http/response_test.go
+++ b/libgo/go/net/http/response_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -10,6 +10,7 @@ import (
"compress/gzip"
"crypto/rand"
"fmt"
+ "go/ast"
"io"
"io/ioutil"
"net/http/internal"
@@ -505,6 +506,32 @@ some body`,
"Body here\n",
},
+
+ {
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Encoding: gzip\r\n" +
+ "Content-Length: 23\r\n" +
+ "Connection: keep-alive\r\n" +
+ "Keep-Alive: timeout=7200\r\n\r\n" +
+ "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Content-Length": {"23"},
+ "Content-Encoding": {"gzip"},
+ "Connection": {"keep-alive"},
+ "Keep-Alive": {"timeout=7200"},
+ },
+ Close: false,
+ ContentLength: 23,
+ },
+ "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+ },
}
// tests successful calls to ReadResponse, and inspects the returned Response.
@@ -562,6 +589,7 @@ var readResponseCloseInMiddleTests = []struct {
// reading only part of its contents advances the read to the end of
// the request, right up until the next request.
func TestReadResponseCloseInMiddle(t *testing.T) {
+ t.Parallel()
for _, test := range readResponseCloseInMiddleTests {
fatalf := func(format string, args ...interface{}) {
args = append([]interface{}{test.chunked, test.compressed}, args...)
@@ -656,10 +684,14 @@ func diff(t *testing.T, prefix string, have, want interface{}) {
t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
}
for i := 0; i < hv.NumField(); i++ {
+ name := hv.Type().Field(i).Name
+ if !ast.IsExported(name) {
+ continue
+ }
hf := hv.Field(i).Interface()
wf := wv.Field(i).Interface()
if !reflect.DeepEqual(hf, wf) {
- t.Errorf("%s: %s = %v want %v", prefix, hv.Type().Field(i).Name, hf, wf)
+ t.Errorf("%s: %s = %v want %v", prefix, name, hf, wf)
}
}
}
@@ -761,6 +793,7 @@ func TestReadResponseErrors(t *testing.T) {
type testCase struct {
name string // optional, defaults to in
in string
+ header Header
wantErr interface{} // nil, err value, or string substring
}
@@ -786,11 +819,22 @@ func TestReadResponseErrors(t *testing.T) {
}
}
+ contentLength := func(status, body string, wantErr interface{}, header Header) testCase {
+ return testCase{
+ name: fmt.Sprintf("status %q %q", status, body),
+ in: fmt.Sprintf("HTTP/1.1 %s\r\n%s", status, body),
+ wantErr: wantErr,
+ header: header,
+ }
+ }
+
+ errMultiCL := "message cannot contain multiple Content-Length headers"
+
tests := []testCase{
- {"", "", io.ErrUnexpectedEOF},
- {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", io.ErrUnexpectedEOF},
- {"", "HTTP/1.1", "malformed HTTP response"},
- {"", "HTTP/2.0", "malformed HTTP response"},
+ {"", "", nil, io.ErrUnexpectedEOF},
+ {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", nil, io.ErrUnexpectedEOF},
+ {"", "HTTP/1.1", nil, "malformed HTTP response"},
+ {"", "HTTP/2.0", nil, "malformed HTTP response"},
status("20X Unknown", true),
status("abcd Unknown", true),
status("二百/两百 OK", true),
@@ -815,7 +859,21 @@ func TestReadResponseErrors(t *testing.T) {
version("HTTP/A.B", true),
version("HTTP/1", true),
version("http/1.1", true),
+
+ contentLength("200 OK", "Content-Length: 10\r\nContent-Length: 7\r\n\r\nGopher hey\r\n", errMultiCL, nil),
+ contentLength("200 OK", "Content-Length: 7\r\nContent-Length: 7\r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"7"}}),
+ contentLength("201 OK", "Content-Length: 0\r\nContent-Length: 7\r\n\r\nGophers\r\n", errMultiCL, nil),
+ contentLength("300 OK", "Content-Length: 0\r\nContent-Length: 0 \r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"0"}}),
+ contentLength("200 OK", "Content-Length:\r\nContent-Length:\r\n\r\nGophers\r\n", nil, nil),
+ contentLength("206 OK", "Content-Length:\r\nContent-Length: 0 \r\nConnection: close\r\n\r\nGophers\r\n", errMultiCL, nil),
+
+ // multiple content-length headers for 204 and 304 should still be checked
+ contentLength("204 OK", "Content-Length: 7\r\nContent-Length: 8\r\n\r\n", errMultiCL, nil),
+ contentLength("204 OK", "Content-Length: 3\r\nContent-Length: 3\r\n\r\n", nil, nil),
+ contentLength("304 OK", "Content-Length: 880\r\nContent-Length: 1\r\n\r\n", errMultiCL, nil),
+ contentLength("304 OK", "Content-Length: 961\r\nContent-Length: 961\r\n\r\n", nil, nil),
}
+
for i, tt := range tests {
br := bufio.NewReader(strings.NewReader(tt.in))
_, rerr := ReadResponse(br, nil)
diff --git a/libgo/go/net/http/responsewrite_test.go b/libgo/go/net/http/responsewrite_test.go
index 5b8d47ab58..d41d89896e 100644
--- a/libgo/go/net/http/responsewrite_test.go
+++ b/libgo/go/net/http/responsewrite_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -222,6 +222,56 @@ func TestResponseWrite(t *testing.T) {
},
"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
},
+
+ // Status code under 100 should be zero-padded to
+ // three digits. Still bogus, but less bogus. (be
+ // consistent with generating three digits, since the
+ // Transport requires it)
+ {
+ Response{
+ StatusCode: 7,
+ Status: "license to violate specs",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: nil,
+ },
+
+ "HTTP/1.0 007 license to violate specs\r\nContent-Length: 0\r\n\r\n",
+ },
+
+ // No stutter. Status code in 1xx range response should
+ // not include a Content-Length header. See issue #16942.
+ {
+ Response{
+ StatusCode: 123,
+ Status: "123 Sesame Street",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: nil,
+ },
+
+ "HTTP/1.0 123 Sesame Street\r\n\r\n",
+ },
+
+ // Status code 204 (No content) response should not include a
+ // Content-Length header. See issue #16942.
+ {
+ Response{
+ StatusCode: 204,
+ Status: "No Content",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: nil,
+ },
+
+ "HTTP/1.0 204 No Content\r\n\r\n",
+ },
}
for i := range respWriteTests {
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index 384b453ce0..73dd56e8c4 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -9,7 +9,10 @@ package http_test
import (
"bufio"
"bytes"
+ "compress/gzip"
+ "context"
"crypto/tls"
+ "encoding/json"
"errors"
"fmt"
"internal/testenv"
@@ -153,6 +156,7 @@ func (ht handlerTest) rawResponse(req string) string {
}
func TestConsumingBodyOnNextConn(t *testing.T) {
+ t.Parallel()
defer afterTest(t)
conn := new(testConn)
for i := 0; i < 2; i++ {
@@ -234,6 +238,7 @@ var vtests = []struct {
}
func TestHostHandlers(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
mux := NewServeMux()
for _, h := range handlers {
@@ -350,6 +355,7 @@ var serveMuxTests = []struct {
}
func TestServeMuxHandler(t *testing.T) {
+ setParallel(t)
mux := NewServeMux()
for _, e := range serveMuxRegister {
mux.Handle(e.pattern, e.h)
@@ -387,15 +393,16 @@ var serveMuxTests2 = []struct {
// TestServeMuxHandlerRedirects tests that automatic redirects generated by
// mux.Handler() shouldn't clear the request's query string.
func TestServeMuxHandlerRedirects(t *testing.T) {
+ setParallel(t)
mux := NewServeMux()
for _, e := range serveMuxRegister {
mux.Handle(e.pattern, e.h)
}
for _, tt := range serveMuxTests2 {
- tries := 1
+ tries := 1 // expect at most 1 redirection if redirOk is true.
turl := tt.url
- for tries > 0 {
+ for {
u, e := url.Parse(turl)
if e != nil {
t.Fatal(e)
@@ -429,6 +436,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
// Tests for https://golang.org/issue/900
func TestMuxRedirectLeadingSlashes(t *testing.T) {
+ setParallel(t)
paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
for _, path := range paths {
req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
@@ -453,9 +461,6 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
}
func TestServerTimeouts(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
setParallel(t)
defer afterTest(t)
reqNum := 0
@@ -476,11 +481,11 @@ func TestServerTimeouts(t *testing.T) {
if err != nil {
t.Fatalf("http Get #1: %v", err)
}
- got, _ := ioutil.ReadAll(r.Body)
+ got, err := ioutil.ReadAll(r.Body)
expected := "req=1"
- if string(got) != expected {
- t.Errorf("Unexpected response for request #1; got %q; expected %q",
- string(got), expected)
+ if string(got) != expected || err != nil {
+ t.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
+ string(got), err, expected)
}
// Slow client that should timeout.
@@ -491,6 +496,7 @@ func TestServerTimeouts(t *testing.T) {
}
buf := make([]byte, 1)
n, err := conn.Read(buf)
+ conn.Close()
latency := time.Since(t1)
if n != 0 || err != io.EOF {
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
@@ -502,14 +508,14 @@ func TestServerTimeouts(t *testing.T) {
// Hit the HTTP server successfully again, verifying that the
// previous slow connection didn't run our handler. (that we
// get "req=2", not "req=3")
- r, err = Get(ts.URL)
+ r, err = c.Get(ts.URL)
if err != nil {
t.Fatalf("http Get #2: %v", err)
}
- got, _ = ioutil.ReadAll(r.Body)
+ got, err = ioutil.ReadAll(r.Body)
expected = "req=2"
- if string(got) != expected {
- t.Errorf("Get #2 got %q, want %q", string(got), expected)
+ if string(got) != expected || err != nil {
+ t.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
}
if !testing.Short() {
@@ -529,13 +535,61 @@ func TestServerTimeouts(t *testing.T) {
}
}
+// Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437)
+func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {}))
+ ts.Config.WriteTimeout = 250 * time.Millisecond
+ ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
+ ts.StartTLS()
+ defer ts.Close()
+
+ tr := newTLSTransport(t, ts)
+ defer tr.CloseIdleConnections()
+ if err := ExportHttp2ConfigureTransport(tr); err != nil {
+ t.Fatal(err)
+ }
+ c := &Client{Transport: tr}
+
+ for i := 1; i <= 3; i++ {
+ req, err := NewRequest("GET", ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // fail test if no response after 1 second
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ req = req.WithContext(ctx)
+
+ r, err := c.Do(req)
+ select {
+ case <-ctx.Done():
+ if ctx.Err() == context.DeadlineExceeded {
+ t.Fatalf("http2 Get #%d response timed out", i)
+ }
+ default:
+ }
+ if err != nil {
+ t.Fatalf("http2 Get #%d: %v", i, err)
+ }
+ r.Body.Close()
+ if r.ProtoMajor != 2 {
+ t.Fatalf("http2 Get expected HTTP/2.0, got %q", r.Proto)
+ }
+ time.Sleep(ts.Config.WriteTimeout / 2)
+ }
+}
+
// golang.org/issue/4741 -- setting only a write timeout that triggers
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
@@ -595,6 +649,7 @@ func (l trackLastConnListener) Accept() (c net.Conn, err error) {
// TestIdentityResponse verifies that a handler can unset
func TestIdentityResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
rw.Header().Set("Content-Length", "3")
@@ -616,13 +671,16 @@ func TestIdentityResponse(t *testing.T) {
ts := httptest.NewServer(handler)
defer ts.Close()
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
// Note: this relies on the assumption (which is true) that
- // Get sends HTTP/1.1 or greater requests. Otherwise the
+ // Get sends HTTP/1.1 or greater requests. Otherwise the
// server wouldn't have the choice to send back chunked
// responses.
for _, te := range []string{"", "identity"} {
url := ts.URL + "/?te=" + te
- res, err := Get(url)
+ res, err := c.Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -641,7 +699,7 @@ func TestIdentityResponse(t *testing.T) {
// Verify that ErrContentLength is returned
url := ts.URL + "/?overwrite=1"
- res, err := Get(url)
+ res, err := c.Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -671,6 +729,7 @@ func TestIdentityResponse(t *testing.T) {
}
func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
+ setParallel(t)
defer afterTest(t)
s := httptest.NewServer(h)
defer s.Close()
@@ -713,6 +772,32 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
}
}
+func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) {
+ setParallel(t)
+ 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) {
@@ -722,7 +807,7 @@ func TestServeHTTP10Close(t *testing.T) {
// TestClientCanClose verifies that clients can also force a connection to close.
func TestClientCanClose(t *testing.T) {
- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
// Nothing.
}))
}
@@ -730,7 +815,7 @@ func TestClientCanClose(t *testing.T) {
// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
// even for HTTP/1.1 requests.
func TestHandlersCanSetConnectionClose11(t *testing.T) {
- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Connection", "close")
}))
}
@@ -741,10 +826,67 @@ func TestHandlersCanSetConnectionClose10(t *testing.T) {
}))
}
+func TestHTTP2UpgradeClosesConnection(t *testing.T) {
+ testTCPConnectionCloses(t, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ // Nothing. (if not hijacked, the server should close the connection
+ // afterwards)
+ }))
+}
+
+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) {
+ setParallel(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) }
func testSetsRemoteAddr(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", r.RemoteAddr)
@@ -794,6 +936,7 @@ func (c *blockingRemoteAddrConn) RemoteAddr() net.Addr {
// Issue 12943
func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "RA:%s", r.RemoteAddr)
@@ -865,7 +1008,9 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
t.Fatalf("response 1 addr = %q; want %q", g, e)
}
}
+
func TestIdentityResponseHeaders(t *testing.T) {
+ // Not parallel; changes log output.
defer afterTest(t)
log.SetOutput(ioutil.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
@@ -877,7 +1022,10 @@ func TestIdentityResponseHeaders(t *testing.T) {
}))
defer ts.Close()
- res, err := Get(ts.URL)
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
}
@@ -900,6 +1048,7 @@ func TestHeadResponses_h1(t *testing.T) { testHeadResponses(t, h1Mode) }
func TestHeadResponses_h2(t *testing.T) { testHeadResponses(t, h2Mode) }
func testHeadResponses(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := w.Write([]byte("<html>"))
@@ -937,9 +1086,6 @@ func testHeadResponses(t *testing.T, h2 bool) {
}
func TestTLSHandshakeTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
setParallel(t)
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -971,6 +1117,7 @@ func TestTLSHandshakeTimeout(t *testing.T) {
}
func TestTLSServer(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS != nil {
@@ -984,7 +1131,7 @@ func TestTLSServer(t *testing.T) {
defer ts.Close()
// Connect an idle TCP connection to this server before we run
- // our real tests. This idle connection used to block forever
+ // our real tests. This idle connection used to block forever
// in the TLS handshake, preventing future connections from
// being accepted. It may prevent future accidental blocking
// in newConn.
@@ -1024,11 +1171,46 @@ func TestTLSServer(t *testing.T) {
})
}
-func TestAutomaticHTTP2_Serve(t *testing.T) {
+// Issue 15908
+func TestAutomaticHTTP2_Serve_NoTLSConfig(t *testing.T) {
+ testAutomaticHTTP2_Serve(t, nil, true)
+}
+
+func TestAutomaticHTTP2_Serve_NonH2TLSConfig(t *testing.T) {
+ testAutomaticHTTP2_Serve(t, &tls.Config{}, false)
+}
+
+func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) {
+ testAutomaticHTTP2_Serve(t, &tls.Config{NextProtos: []string{"h2"}}, true)
+}
+
+func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
+ setParallel(t)
defer afterTest(t)
ln := newLocalListener(t)
ln.Close() // immediately (not a defer!)
var s Server
+ s.TLSConfig = tlsConf
+ if err := s.Serve(ln); err == nil {
+ t.Fatal("expected an error")
+ }
+ gotH2 := s.TLSNextProto["h2"] != nil
+ if gotH2 != wantH2 {
+ t.Errorf("http2 configured = %v; want %v", gotH2, wantH2)
+ }
+}
+
+func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ln := newLocalListener(t)
+ ln.Close() // immediately (not a defer!)
+ var s Server
+ // Set the TLSConfig. In reality, this would be the
+ // *tls.Config given to tls.NewListener.
+ s.TLSConfig = &tls.Config{
+ NextProtos: []string{"h2"},
+ }
if err := s.Serve(ln); err == nil {
t.Fatal("expected an error")
}
@@ -1061,6 +1243,7 @@ func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) {
}
func testAutomaticHTTP2_ListenAndServe(t *testing.T, tlsConf *tls.Config) {
+ // Not parallel: uses global test hooks.
defer afterTest(t)
defer SetTestHookServerServe(nil)
var ok bool
@@ -1164,6 +1347,7 @@ var serverExpectTests = []serverExpectTest{
// correctly.
// http2 test: TestServer_Response_Automatic100Continue
func TestServerExpect(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
// Note using r.FormValue("readbody") because for POST
@@ -1257,6 +1441,7 @@ func TestServerExpect(t *testing.T) {
// Under a ~256KB (maxPostHandlerReadBytes) threshold, the server
// should consume client request bodies that a handler didn't read.
func TestServerUnreadRequestBodyLittle(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
conn := new(testConn)
body := strings.Repeat("x", 100<<10)
@@ -1297,6 +1482,7 @@ func TestServerUnreadRequestBodyLittle(t *testing.T) {
// should ignore client request bodies that a handler didn't read
// and close the connection.
func TestServerUnreadRequestBodyLarge(t *testing.T) {
+ setParallel(t)
if testing.Short() && testenv.Builder() == "" {
t.Log("skipping in short mode")
}
@@ -1430,6 +1616,7 @@ var handlerBodyCloseTests = [...]handlerBodyCloseTest{
}
func TestHandlerBodyClose(t *testing.T) {
+ setParallel(t)
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in -short mode")
}
@@ -1509,6 +1696,7 @@ var testHandlerBodyConsumers = []testHandlerBodyConsumer{
}
func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
for _, handler := range testHandlerBodyConsumers {
conn := new(testConn)
@@ -1539,6 +1727,7 @@ func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
}
func TestInvalidTrailerClosesConnection(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
for _, handler := range testHandlerBodyConsumers {
conn := new(testConn)
@@ -1621,7 +1810,7 @@ restart:
if !c.rd.IsZero() {
// If the deadline falls in the middle of our sleep window, deduct
// part of the sleep, then return a timeout.
- if remaining := c.rd.Sub(time.Now()); remaining < cue {
+ if remaining := time.Until(c.rd); remaining < cue {
c.script[0] = cue - remaining
time.Sleep(remaining)
return 0, syscall.ETIMEDOUT
@@ -1707,6 +1896,7 @@ func TestRequestBodyTimeoutClosesConnection(t *testing.T) {
func TestTimeoutHandler_h1(t *testing.T) { testTimeoutHandler(t, h1Mode) }
func TestTimeoutHandler_h2(t *testing.T) { testTimeoutHandler(t, h2Mode) }
func testTimeoutHandler(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
@@ -1760,6 +1950,7 @@ func testTimeoutHandler(t *testing.T, h2 bool) {
// See issues 8209 and 8414.
func TestTimeoutHandlerRace(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
delayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1776,6 +1967,9 @@ func TestTimeoutHandlerRace(t *testing.T) {
ts := httptest.NewServer(TimeoutHandler(delayHi, 20*time.Millisecond, ""))
defer ts.Close()
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
var wg sync.WaitGroup
gate := make(chan bool, 10)
n := 50
@@ -1789,7 +1983,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
go func() {
defer wg.Done()
defer func() { <-gate }()
- res, err := Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
+ res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
if err == nil {
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
@@ -1801,6 +1995,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
// See issues 8209 and 8414.
func TestTimeoutHandlerRaceHeader(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
delay204 := HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1816,13 +2011,15 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
if testing.Short() {
n = 10
}
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
for i := 0; i < n; i++ {
gate <- true
wg.Add(1)
go func() {
defer wg.Done()
defer func() { <-gate }()
- res, err := Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
return
@@ -1836,6 +2033,7 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
// Issue 9162
func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
@@ -1888,20 +2086,57 @@ func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) {
}
}
-// Verifies we don't path.Clean() on the wrong parts in redirects.
-func TestRedirectMunging(t *testing.T) {
- req, _ := NewRequest("GET", "http://example.com/", nil)
+// Issue 14568.
+func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping sleeping test in -short mode")
+ }
+ defer afterTest(t)
+ var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
+ w.WriteHeader(StatusNoContent)
+ }
+ timeout := 300 * time.Millisecond
+ ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
+ defer ts.Close()
+
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ // Issue was caused by the timeout handler starting the timer when
+ // was created, not when the request. So wait for more than the timeout
+ // to ensure that's not the case.
+ time.Sleep(2 * timeout)
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != StatusNoContent {
+ t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusNoContent)
+ }
+}
- resp := httptest.NewRecorder()
- Redirect(resp, req, "/foo?next=http://bar.com/", 302)
- if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e {
- t.Errorf("Location header was %q; want %q", g, e)
+// https://golang.org/issue/15948
+func TestTimeoutHandlerEmptyResponse(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
+ // No response.
}
+ timeout := 300 * time.Millisecond
+ ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
+ defer ts.Close()
+
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
- resp = httptest.NewRecorder()
- Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302)
- if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e {
- t.Errorf("Location header was %q; want %q", g, e)
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != StatusOK {
+ t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusOK)
}
}
@@ -1923,7 +2158,7 @@ func TestRedirectBadPath(t *testing.T) {
}
// Test different URL formats and schemes
-func TestRedirectURLFormat(t *testing.T) {
+func TestRedirect(t *testing.T) {
req, _ := NewRequest("GET", "http://example.com/qux/", nil)
var tests = []struct {
@@ -1946,6 +2181,14 @@ func TestRedirectURLFormat(t *testing.T) {
{"../quux/foobar.com/baz", "/quux/foobar.com/baz"},
// incorrect number of slashes
{"///foobar.com/baz", "/foobar.com/baz"},
+
+ // Verifies we don't path.Clean() on the wrong parts in redirects:
+ {"/foo?next=http://bar.com/", "/foo?next=http://bar.com/"},
+ {"http://localhost:8080/_ah/login?continue=http://localhost:8080/",
+ "http://localhost:8080/_ah/login?continue=http://localhost:8080/"},
+
+ {"/фубар", "/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
+ {"http://foo.com/фубар", "http://foo.com/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
}
for _, tt := range tests {
@@ -1971,6 +2214,7 @@ func TestZeroLengthPostAndResponse_h2(t *testing.T) {
}
func testZeroLengthPostAndResponse(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, r *Request) {
all, err := ioutil.ReadAll(r.Body)
@@ -2027,7 +2271,7 @@ func TestHandlerPanicWithHijack(t *testing.T) {
func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) {
defer afterTest(t)
// Unlike the other tests that set the log output to ioutil.Discard
- // to quiet the output, this test uses a pipe. The pipe serves three
+ // to quiet the output, this test uses a pipe. The pipe serves three
// purposes:
//
// 1) The log.Print from the http server (generated by the caught
@@ -2060,7 +2304,7 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
defer cst.close()
// Do a blocking read on the log output pipe so its logging
- // doesn't bleed into the next test. But wait only 5 seconds
+ // doesn't bleed into the next test. But wait only 5 seconds
// for it.
done := make(chan bool, 1)
go func() {
@@ -2090,12 +2334,58 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
}
}
+type terrorWriter struct{ t *testing.T }
+
+func (w terrorWriter) Write(p []byte) (int, error) {
+ w.t.Errorf("%s", p)
+ return len(p), nil
+}
+
+// Issue 16456: allow writing 0 bytes on hijacked conn to test hijack
+// without any log spam.
+func TestServerWriteHijackZeroBytes(t *testing.T) {
+ defer afterTest(t)
+ done := make(chan struct{})
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+ w.(Flusher).Flush()
+ conn, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Errorf("Hijack: %v", err)
+ return
+ }
+ defer conn.Close()
+ _, err = w.Write(nil)
+ if err != ErrHijacked {
+ t.Errorf("Write error = %v; want ErrHijacked", err)
+ }
+ }))
+ ts.Config.ErrorLog = log.New(terrorWriter{t}, "Unexpected write: ", 0)
+ ts.Start()
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout")
+ }
+}
+
func TestServerNoDate_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Date") }
func TestServerNoDate_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Date") }
func TestServerNoContentType_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Content-Type") }
func TestServerNoContentType_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Content-Type") }
func testServerNoHeader(t *testing.T, h2 bool, header string) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header()[header] = nil
@@ -2113,6 +2403,7 @@ func testServerNoHeader(t *testing.T, h2 bool, header string) {
}
func TestStripPrefix(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
h := HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Path", r.URL.Path)
@@ -2120,7 +2411,10 @@ func TestStripPrefix(t *testing.T) {
ts := httptest.NewServer(StripPrefix("/foo", h))
defer ts.Close()
- res, err := Get(ts.URL + "/foo/bar")
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ res, err := c.Get(ts.URL + "/foo/bar")
if err != nil {
t.Fatal(err)
}
@@ -2142,10 +2436,11 @@ func TestStripPrefix(t *testing.T) {
func TestRequestLimit_h1(t *testing.T) { testRequestLimit(t, h1Mode) }
func TestRequestLimit_h2(t *testing.T) { testRequestLimit(t, h2Mode) }
func testRequestLimit(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
t.Fatalf("didn't expect to get request in Handler")
- }))
+ }), optQuietLog)
defer cst.close()
req, _ := NewRequest("GET", cst.ts.URL, nil)
var bytesPerHeader = len("header12345: val12345\r\n")
@@ -2188,6 +2483,7 @@ func (cr countReader) Read(p []byte) (n int, err error) {
func TestRequestBodyLimit_h1(t *testing.T) { testRequestBodyLimit(t, h1Mode) }
func TestRequestBodyLimit_h2(t *testing.T) { testRequestBodyLimit(t, h2Mode) }
func testRequestBodyLimit(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
const limit = 1 << 20
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2205,10 +2501,10 @@ func testRequestBodyLimit(t *testing.T, h2 bool) {
nWritten := new(int64)
req, _ := NewRequest("POST", cst.ts.URL, io.LimitReader(countReader{neverEnding('a'), nWritten}, limit*200))
- // Send the POST, but don't care it succeeds or not. The
+ // Send the POST, but don't care it succeeds or not. The
// remote side is going to reply and then close the TCP
// connection, and HTTP doesn't really define if that's
- // allowed or not. Some HTTP clients will get the response
+ // allowed or not. Some HTTP clients will get the response
// and some (like ours, currently) will complain that the
// request write failed, without reading the response.
//
@@ -2237,14 +2533,14 @@ func TestClientWriteShutdown(t *testing.T) {
}
err = conn.(*net.TCPConn).CloseWrite()
if err != nil {
- t.Fatalf("Dial: %v", err)
+ t.Fatalf("CloseWrite: %v", err)
}
donec := make(chan bool)
go func() {
defer close(donec)
bs, err := ioutil.ReadAll(conn)
if err != nil {
- t.Fatalf("ReadAll: %v", err)
+ t.Errorf("ReadAll: %v", err)
}
got := string(bs)
if got != "" {
@@ -2283,6 +2579,7 @@ func TestServerBufferedChunking(t *testing.T) {
// closing the TCP connection, causing the client to get a RST.
// See https://golang.org/issue/3595
func TestServerGracefulClose(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, "bye", StatusUnauthorized)
@@ -2395,7 +2692,8 @@ func TestCloseNotifier(t *testing.T) {
go func() {
_, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
<-diec
conn.Close()
@@ -2437,7 +2735,8 @@ func TestCloseNotifierPipelined(t *testing.T) {
const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
_, err = io.WriteString(conn, req+req) // two requests
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
<-diec
conn.Close()
@@ -2545,6 +2844,7 @@ func TestHijackAfterCloseNotifier(t *testing.T) {
}
func TestHijackBeforeRequestBodyRead(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var requestBody = bytes.Repeat([]byte("a"), 1<<20)
bodyOkay := make(chan bool, 1)
@@ -2650,7 +2950,7 @@ func TestOptions(t *testing.T) {
}
// Tests regarding the ordering of Write, WriteHeader, Header, and
-// Flush calls. In Go 1.0, rw.WriteHeader immediately flushed the
+// Flush calls. In Go 1.0, rw.WriteHeader immediately flushed the
// (*response).header to the wire. In Go 1.1, the actual wire flush is
// delayed, so we could maybe tack on a Content-Length and better
// Content-Type after we see more (or all) of the output. To preserve
@@ -2866,15 +3166,18 @@ func (l *errorListener) Addr() net.Addr {
}
func TestAcceptMaxFds(t *testing.T) {
- log.SetOutput(ioutil.Discard) // is noisy otherwise
- defer log.SetOutput(os.Stderr)
+ setParallel(t)
ln := &errorListener{[]error{
&net.OpError{
Op: "accept",
Err: syscall.EMFILE,
}}}
- err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
+ server := &Server{
+ Handler: HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})),
+ ErrorLog: log.New(ioutil.Discard, "", 0), // noisy otherwise
+ }
+ err := server.Serve(ln)
if err != io.EOF {
t.Errorf("got error %v, want EOF", err)
}
@@ -2999,6 +3302,7 @@ func TestHTTP10ConnectionHeader(t *testing.T) {
func TestServerReaderFromOrder_h1(t *testing.T) { testServerReaderFromOrder(t, h1Mode) }
func TestServerReaderFromOrder_h2(t *testing.T) { testServerReaderFromOrder(t, h2Mode) }
func testServerReaderFromOrder(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
pr, pw := io.Pipe()
const size = 3 << 20
@@ -3103,11 +3407,12 @@ func TestTransportAndServerSharedBodyRace_h2(t *testing.T) {
testTransportAndServerSharedBodyRace(t, h2Mode)
}
func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
const bodySize = 1 << 20
- // errorf is like t.Errorf, but also writes to println. When
+ // errorf is like t.Errorf, but also writes to println. When
// this test fails, it hangs. This helps debugging and I've
// added this enough times "temporarily". It now gets added
// full time.
@@ -3291,6 +3596,7 @@ func TestAppendTime(t *testing.T) {
}
func TestServerConnState(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
handler := map[string]func(w ResponseWriter, r *Request){
"/": func(w ResponseWriter, r *Request) {
@@ -3338,14 +3644,39 @@ func TestServerConnState(t *testing.T) {
}
ts.Start()
- mustGet(t, ts.URL+"/")
- mustGet(t, ts.URL+"/close")
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ mustGet := func(url string, headers ...string) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for len(headers) > 0 {
+ req.Header.Add(headers[0], headers[1])
+ headers = headers[2:]
+ }
+ res, err := c.Do(req)
+ if err != nil {
+ t.Errorf("Error fetching %s: %v", url, err)
+ return
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ defer res.Body.Close()
+ if err != nil {
+ t.Errorf("Error reading %s: %v", url, err)
+ }
+ }
+
+ mustGet(ts.URL + "/")
+ mustGet(ts.URL + "/close")
- mustGet(t, ts.URL+"/")
- mustGet(t, ts.URL+"/", "Connection", "close")
+ mustGet(ts.URL + "/")
+ mustGet(ts.URL+"/", "Connection", "close")
- mustGet(t, ts.URL+"/hijack")
- mustGet(t, ts.URL+"/hijack-panic")
+ mustGet(ts.URL + "/hijack")
+ mustGet(ts.URL + "/hijack-panic")
// New->Closed
{
@@ -3425,31 +3756,10 @@ func TestServerConnState(t *testing.T) {
}
mu.Lock()
- t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want))
+ t.Errorf("Unexpected events.\nGot log:\n%s\n Want:\n%s\n", logString(stateLog), logString(want))
mu.Unlock()
}
-func mustGet(t *testing.T, url string, headers ...string) {
- req, err := NewRequest("GET", url, nil)
- if err != nil {
- t.Fatal(err)
- }
- for len(headers) > 0 {
- req.Header.Add(headers[0], headers[1])
- headers = headers[2:]
- }
- res, err := DefaultClient.Do(req)
- if err != nil {
- t.Errorf("Error fetching %s: %v", url, err)
- return
- }
- _, err = ioutil.ReadAll(res.Body)
- defer res.Body.Close()
- if err != nil {
- t.Errorf("Error reading %s: %v", url, err)
- }
-}
-
func TestServerKeepAlivesEnabled(t *testing.T) {
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -3470,6 +3780,7 @@ func TestServerKeepAlivesEnabled(t *testing.T) {
func TestServerEmptyBodyRace_h1(t *testing.T) { testServerEmptyBodyRace(t, h1Mode) }
func TestServerEmptyBodyRace_h2(t *testing.T) { testServerEmptyBodyRace(t, h2Mode) }
func testServerEmptyBodyRace(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
var n int32
cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -3533,6 +3844,7 @@ func (c *closeWriteTestConn) CloseWrite() error {
}
func TestCloseWrite(t *testing.T) {
+ setParallel(t)
var srv Server
var testConn closeWriteTestConn
c := ExportServerNewConn(&srv, &testConn)
@@ -3773,6 +4085,7 @@ Host: foo
// If a Handler finishes and there's an unread request body,
// verify the server try to do implicit read on it before replying.
func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
+ setParallel(t)
conn := &testConn{closec: make(chan bool)}
conn.readBuf.Write([]byte(fmt.Sprintf(
"POST / HTTP/1.1\r\n" +
@@ -3829,6 +4142,8 @@ func TestServerValidatesHostHeader(t *testing.T) {
host string
want int
}{
+ {"HTTP/0.9", "", 400},
+
{"HTTP/1.1", "", 400},
{"HTTP/1.1", "Host: \r\n", 200},
{"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
@@ -3851,13 +4166,29 @@ func TestServerValidatesHostHeader(t *testing.T) {
{"HTTP/1.0", "", 200},
{"HTTP/1.0", "Host: first\r\nHost: second\r\n", 400},
{"HTTP/1.0", "Host: \xff\r\n", 400},
+
+ // Make an exception for HTTP upgrade requests:
+ {"PRI * HTTP/2.0", "", 200},
+
+ // But not other HTTP/2 stuff:
+ {"PRI / HTTP/2.0", "", 400},
+ {"GET / HTTP/2.0", "", 400},
+ {"GET / HTTP/3.0", "", 400},
}
for _, tt := range tests {
conn := &testConn{closec: make(chan bool, 1)}
- io.WriteString(&conn.readBuf, "GET / "+tt.proto+"\r\n"+tt.host+"\r\n")
+ methodTarget := "GET / "
+ if !strings.HasPrefix(tt.proto, "HTTP/") {
+ methodTarget = ""
+ }
+ io.WriteString(&conn.readBuf, methodTarget+tt.proto+"\r\n"+tt.host+"\r\n")
ln := &oneConnListener{conn}
- go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+ srv := Server{
+ ErrorLog: quietLog,
+ Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
+ }
+ go srv.Serve(ln)
<-conn.closec
res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
if err != nil {
@@ -3870,9 +4201,49 @@ func TestServerValidatesHostHeader(t *testing.T) {
}
}
+func TestServerHandlersCanHandleH2PRI(t *testing.T) {
+ const upgradeResponse = "upgrade here"
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ conn, br, err := w.(Hijacker).Hijack()
+ defer conn.Close()
+ if r.Method != "PRI" || r.RequestURI != "*" {
+ t.Errorf("Got method/target %q %q; want PRI *", r.Method, r.RequestURI)
+ return
+ }
+ if !r.Close {
+ t.Errorf("Request.Close = true; want false")
+ }
+ const want = "SM\r\n\r\n"
+ buf := make([]byte, len(want))
+ n, err := io.ReadFull(br, buf)
+ if err != nil || string(buf[:n]) != want {
+ t.Errorf("Read = %v, %v (%q), want %q", n, err, buf[:n], want)
+ return
+ }
+ io.WriteString(conn, upgradeResponse)
+ }))
+ defer ts.Close()
+
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer c.Close()
+ io.WriteString(c, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
+ slurp, err := ioutil.ReadAll(c)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != upgradeResponse {
+ t.Errorf("Handler response = %q; want %q", slurp, upgradeResponse)
+ }
+}
+
// Test that we validate the valid bytes in HTTP/1 headers.
// Issue 11207.
func TestServerValidatesHeaders(t *testing.T) {
+ setParallel(t)
tests := []struct {
header string
want int
@@ -3882,9 +4253,10 @@ func TestServerValidatesHeaders(t *testing.T) {
{"X-Foo: bar\r\n", 200},
{"Foo: a space\r\n", 200},
- {"A space: foo\r\n", 400}, // space in header
- {"foo\xffbar: foo\r\n", 400}, // binary in header
- {"foo\x00bar: foo\r\n", 400}, // binary in header
+ {"A space: foo\r\n", 400}, // space in header
+ {"foo\xffbar: foo\r\n", 400}, // binary in header
+ {"foo\x00bar: foo\r\n", 400}, // binary in header
+ {"Foo: " + strings.Repeat("x", 1<<21) + "\r\n", 431}, // header too large
{"foo: foo foo\r\n", 200}, // LWS space is okay
{"foo: foo\tfoo\r\n", 200}, // LWS tab is okay
@@ -3897,7 +4269,11 @@ func TestServerValidatesHeaders(t *testing.T) {
io.WriteString(&conn.readBuf, "GET / HTTP/1.1\r\nHost: foo\r\n"+tt.header+"\r\n")
ln := &oneConnListener{conn}
- go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+ srv := Server{
+ ErrorLog: quietLog,
+ Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
+ }
+ go srv.Serve(ln)
<-conn.closec
res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
if err != nil {
@@ -3910,6 +4286,143 @@ func TestServerValidatesHeaders(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) {
+ setParallel(t)
+ defer afterTest(t)
+ ctxc := make(chan context.Context, 1)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ ctx := r.Context()
+ select {
+ case <-ctx.Done():
+ t.Error("should not be Done in ServeHTTP")
+ default:
+ }
+ ctxc <- ctx
+ }))
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ ctx := <-ctxc
+ select {
+ case <-ctx.Done():
+ default:
+ t.Error("context should be done after ServeHTTP completes")
+ }
+}
+
+// Tests that the Request.Context available to the Handler is canceled
+// if the peer closes their TCP connection. This requires that the server
+// is always blocked in a Read call so it notices the EOF from the client.
+// See issues 15927 and 15224.
+func TestServerRequestContextCancel_ConnClose(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ inHandler := make(chan struct{})
+ handlerDone := make(chan struct{})
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ close(inHandler)
+ select {
+ case <-r.Context().Done():
+ case <-time.After(3 * time.Second):
+ t.Errorf("timeout waiting for context to be done")
+ }
+ close(handlerDone)
+ }))
+ defer ts.Close()
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+ io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
+ select {
+ case <-inHandler:
+ case <-time.After(3 * time.Second):
+ t.Fatalf("timeout waiting to see ServeHTTP get called")
+ }
+ c.Close() // this should trigger the context being done
+
+ select {
+ case <-handlerDone:
+ case <-time.After(4 * time.Second):
+ t.Fatalf("timeout waiting to see ServeHTTP exit")
+ }
+}
+
+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) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ ctx := r.Context()
+ got := ctx.Value(ServerContextKey)
+ if _, ok := got.(*Server); !ok {
+ t.Errorf("context value = %T; want *http.Server", got)
+ }
+
+ got = ctx.Value(LocalAddrContextKey)
+ 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 cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+}
+
+// https://golang.org/issue/15960
+func TestHandlerSetTransferEncodingChunked(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Transfer-Encoding", "chunked")
+ w.Write([]byte("hello"))
+ }))
+ resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
+ const hdr = "Transfer-Encoding: chunked"
+ if n := strings.Count(resp, hdr); n != 1 {
+ t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
+ }
+}
+
+// https://golang.org/issue/16063
+func TestHandlerSetTransferEncodingGzip(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Transfer-Encoding", "gzip")
+ gz := gzip.NewWriter(w)
+ gz.Write([]byte("hello"))
+ gz.Close()
+ }))
+ resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
+ for _, v := range []string{"gzip", "chunked"} {
+ hdr := "Transfer-Encoding: " + v
+ if n := strings.Count(resp, hdr); n != 1 {
+ t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
+ }
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
@@ -4067,13 +4580,19 @@ func BenchmarkClient(b *testing.B) {
b.StopTimer()
defer afterTest(b)
- port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
- if port == "" {
- port = "39207"
- }
var data = []byte("Hello world.\n")
if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
// Server process mode.
+ port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
+ if port == "" {
+ port = "0"
+ }
+ ln, err := net.Listen("tcp", "localhost:"+port)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+ fmt.Println(ln.Addr().String())
HandleFunc("/", func(w ResponseWriter, r *Request) {
r.ParseForm()
if r.Form.Get("stop") != "" {
@@ -4082,33 +4601,44 @@ func BenchmarkClient(b *testing.B) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write(data)
})
- log.Fatal(ListenAndServe("localhost:"+port, nil))
+ var srv Server
+ log.Fatal(srv.Serve(ln))
}
// Start server process.
cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$")
cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes")
+ cmd.Stderr = os.Stderr
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ b.Fatal(err)
+ }
if err := cmd.Start(); err != nil {
b.Fatalf("subprocess failed to start: %v", err)
}
defer cmd.Process.Kill()
+
+ // Wait for the server in the child process to respond and tell us
+ // its listening address, once it's started listening:
+ timer := time.AfterFunc(10*time.Second, func() {
+ cmd.Process.Kill()
+ })
+ defer timer.Stop()
+ bs := bufio.NewScanner(stdout)
+ if !bs.Scan() {
+ b.Fatalf("failed to read listening URL from child: %v", bs.Err())
+ }
+ url := "http://" + strings.TrimSpace(bs.Text()) + "/"
+ timer.Stop()
+ if _, err := getNoBody(url); err != nil {
+ b.Fatalf("initial probe of child process failed: %v", err)
+ }
+
done := make(chan error)
go func() {
done <- cmd.Wait()
}()
- // Wait for the server process to respond.
- url := "http://localhost:" + port + "/"
- for i := 0; i < 100; i++ {
- time.Sleep(50 * time.Millisecond)
- if _, err := getNoBody(url); err == nil {
- break
- }
- if i == 99 {
- b.Fatalf("subprocess does not respond")
- }
- }
-
// Do b.N requests to the server.
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -4121,7 +4651,7 @@ func BenchmarkClient(b *testing.B) {
if err != nil {
b.Fatalf("ReadAll: %v", err)
}
- if bytes.Compare(body, data) != 0 {
+ if !bytes.Equal(body, data) {
b.Fatalf("Got body: %q", body)
}
}
@@ -4367,3 +4897,418 @@ func BenchmarkCloseNotifier(b *testing.B) {
}
b.StopTimer()
}
+
+// Verify this doesn't race (Issue 16505)
+func TestConcurrentServerServe(t *testing.T) {
+ setParallel(t)
+ for i := 0; i < 100; i++ {
+ ln1 := &oneConnListener{conn: nil}
+ ln2 := &oneConnListener{conn: nil}
+ srv := Server{}
+ go func() { srv.Serve(ln1) }()
+ go func() { srv.Serve(ln2) }()
+ }
+}
+
+func TestServerIdleTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.Copy(ioutil.Discard, r.Body)
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ ts.Config.ReadHeaderTimeout = 1 * time.Second
+ ts.Config.IdleTimeout = 2 * time.Second
+ ts.Start()
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ get := func() string {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return string(slurp)
+ }
+
+ a1, a2 := get(), get()
+ if a1 != a2 {
+ t.Fatalf("did requests on different connections")
+ }
+ time.Sleep(3 * time.Second)
+ a3 := get()
+ if a2 == a3 {
+ t.Fatal("request three unexpectedly on same connection")
+ }
+
+ // And test that ReadHeaderTimeout still works:
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo.com\r\n"))
+ time.Sleep(2 * time.Second)
+ if _, err := io.CopyN(ioutil.Discard, conn, 1); err == nil {
+ t.Fatal("copy byte succeeded; want err")
+ }
+}
+
+func get(t *testing.T, c *Client, url string) string {
+ res, err := c.Get(url)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return string(slurp)
+}
+
+// Tests that calls to Server.SetKeepAlivesEnabled(false) closes any
+// currently-open connections.
+func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ get := func() string { return get(t, c, ts.URL) }
+
+ a1, a2 := get(), get()
+ if a1 != a2 {
+ t.Fatal("expected first two requests on same connection")
+ }
+ var idle0 int
+ if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
+ idle0 = tr.IdleConnKeyCountForTesting()
+ return idle0 == 1
+ }) {
+ t.Fatalf("idle count before SetKeepAlivesEnabled called = %v; want 1", idle0)
+ }
+
+ ts.Config.SetKeepAlivesEnabled(false)
+
+ var idle1 int
+ if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
+ idle1 = tr.IdleConnKeyCountForTesting()
+ return idle1 == 0
+ }) {
+ t.Fatalf("idle count after SetKeepAlivesEnabled called = %v; want 0", idle1)
+ }
+
+ a3 := get()
+ if a3 == a2 {
+ t.Fatal("expected third request on new connection")
+ }
+}
+
+func TestServerShutdown_h1(t *testing.T) { testServerShutdown(t, h1Mode) }
+func TestServerShutdown_h2(t *testing.T) { testServerShutdown(t, h2Mode) }
+
+func testServerShutdown(t *testing.T, h2 bool) {
+ setParallel(t)
+ defer afterTest(t)
+ var doShutdown func() // set later
+ var shutdownRes = make(chan error, 1)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ go doShutdown()
+ // Shutdown is graceful, so it should not interrupt
+ // this in-flight response. Add a tiny sleep here to
+ // increase the odds of a failure if shutdown has
+ // bugs.
+ time.Sleep(20 * time.Millisecond)
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ defer cst.close()
+
+ doShutdown = func() {
+ shutdownRes <- cst.ts.Config.Shutdown(context.Background())
+ }
+ get(t, cst.c, cst.ts.URL) // calls t.Fail on failure
+
+ if err := <-shutdownRes; err != nil {
+ t.Fatalf("Shutdown: %v", err)
+ }
+
+ res, err := cst.c.Get(cst.ts.URL)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("second request should fail. server should be shut down")
+ }
+}
+
+// Issue 17878: tests that we can call Close twice.
+func TestServerCloseDeadlock(t *testing.T) {
+ var s Server
+ s.Close()
+ s.Close()
+}
+
+// Issue 17717: tests that Server.SetKeepAlivesEnabled is respected by
+// both HTTP/1 and HTTP/2.
+func TestServerKeepAlivesEnabled_h1(t *testing.T) { testServerKeepAlivesEnabled(t, h1Mode) }
+func TestServerKeepAlivesEnabled_h2(t *testing.T) { testServerKeepAlivesEnabled(t, h2Mode) }
+func testServerKeepAlivesEnabled(t *testing.T, h2 bool) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "%v", r.RemoteAddr)
+ }))
+ defer cst.close()
+ srv := cst.ts.Config
+ srv.SetKeepAlivesEnabled(false)
+ a := cst.getURL(cst.ts.URL)
+ if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
+ t.Fatalf("test server has active conns")
+ }
+ b := cst.getURL(cst.ts.URL)
+ if a == b {
+ t.Errorf("got same connection between first and second requests")
+ }
+ if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
+ t.Fatalf("test server has active conns")
+ }
+}
+
+// Issue 18447: test that the Server's ReadTimeout is stopped while
+// the server's doing its 1-byte background read between requests,
+// waiting for the connection to maybe close.
+func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ const timeout = 250 * time.Millisecond
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ select {
+ case <-time.After(2 * timeout):
+ fmt.Fprint(w, "ok")
+ case <-r.Context().Done():
+ fmt.Fprint(w, r.Context().Err())
+ }
+ }))
+ ts.Config.ReadTimeout = timeout
+ ts.Start()
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ slurp, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != "ok" {
+ t.Fatalf("Got: %q, want ok", slurp)
+ }
+}
+
+// Issue 18535: test that the Server doesn't try to do a background
+// read if it's already done one.
+func TestServerDuplicateBackgroundRead(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ const goroutines = 5
+ const requests = 2000
+
+ hts := httptest.NewServer(HandlerFunc(NotFound))
+ defer hts.Close()
+
+ reqBytes := []byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")
+
+ var wg sync.WaitGroup
+ for i := 0; i < goroutines; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ cn, err := net.Dial("tcp", hts.Listener.Addr().String())
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer cn.Close()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ io.Copy(ioutil.Discard, cn)
+ }()
+
+ for j := 0; j < requests; j++ {
+ if t.Failed() {
+ return
+ }
+ _, err := cn.Write(reqBytes)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+// Test that the bufio.Reader returned by Hijack includes any buffered
+// byte (from the Server's backgroundRead) in its buffer. We want the
+// Handler code to be able to tell that a byte is available via
+// bufio.Reader.Buffered(), without resorting to Reading it
+// (potentially blocking) to get at it.
+func TestServerHijackGetsBackgroundByte(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see https://golang.org/issue/18657")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ done := make(chan struct{})
+ inHandler := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+
+ // Tell the client to send more data after the GET request.
+ inHandler <- true
+
+ // Wait until the HTTP server sees the extra data
+ // after the GET request. The HTTP server fires the
+ // close notifier here, assuming it's a pipelined
+ // request, as documented.
+ select {
+ case <-w.(CloseNotifier).CloseNotify():
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
+ return
+ }
+
+ conn, buf, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer conn.Close()
+ n := buf.Reader.Buffered()
+ if n != 1 {
+ t.Errorf("buffered data = %d; want 1", n)
+ }
+ peek, err := buf.Reader.Peek(3)
+ if string(peek) != "foo" || err != nil {
+ t.Errorf("Peek = %q, %v; want foo, nil", peek, err)
+ }
+ }))
+ defer ts.Close()
+
+ cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cn.Close()
+ if _, err := cn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
+ t.Fatal(err)
+ }
+ <-inHandler
+ if _, err := cn.Write([]byte("foo")); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+ t.Fatal(err)
+ }
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Error("timeout")
+ }
+}
+
+// Like TestServerHijackGetsBackgroundByte above but sending a
+// immediate 1MB of data to the server to fill up the server's 4KB
+// buffer.
+func TestServerHijackGetsBackgroundByte_big(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see https://golang.org/issue/18657")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ done := make(chan struct{})
+ const size = 8 << 10
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+
+ // Wait until the HTTP server sees the extra data
+ // after the GET request. The HTTP server fires the
+ // close notifier here, assuming it's a pipelined
+ // request, as documented.
+ select {
+ case <-w.(CloseNotifier).CloseNotify():
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
+ return
+ }
+
+ conn, buf, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer conn.Close()
+ slurp, err := ioutil.ReadAll(buf.Reader)
+ if err != nil {
+ t.Errorf("Copy: %v", err)
+ }
+ allX := true
+ for _, v := range slurp {
+ if v != 'x' {
+ allX = false
+ }
+ }
+ if len(slurp) != size {
+ t.Errorf("read %d; want %d", len(slurp), size)
+ } else if !allX {
+ t.Errorf("read %q; want %d 'x'", slurp, size)
+ }
+ }))
+ defer ts.Close()
+
+ cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cn.Close()
+ if _, err := fmt.Fprintf(cn, "GET / HTTP/1.1\r\nHost: e.com\r\n\r\n%s",
+ strings.Repeat("x", size)); err != nil {
+ t.Fatal(err)
+ }
+ if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Error("timeout")
+ }
+}
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 5e3b6084ae..df70a15193 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// HTTP server. See RFC 2616.
+// HTTP server. See RFC 2616.
package http
import (
"bufio"
"bytes"
+ "context"
"crypto/tls"
"errors"
"fmt"
@@ -26,14 +27,32 @@ import (
"sync"
"sync/atomic"
"time"
+
+ "golang_org/x/net/lex/httplex"
)
-// Errors introduced by the HTTP server.
+// Errors used by the HTTP server.
var (
- ErrWriteAfterFlush = errors.New("Conn.Write called after Flush")
- ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
- ErrHijacked = errors.New("Conn has been hijacked")
- ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length")
+ // ErrBodyNotAllowed is returned by ResponseWriter.Write calls
+ // when the HTTP method or response code does not permit a
+ // body.
+ ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
+
+ // ErrHijacked is returned by ResponseWriter.Write calls when
+ // the underlying connection has been hijacked using the
+ // Hijacker interface. A zero-byte write on a hijacked
+ // connection will return ErrHijacked without any other side
+ // effects.
+ ErrHijacked = errors.New("http: connection has been hijacked")
+
+ // ErrContentLength is returned by ResponseWriter.Write calls
+ // when a Handler set a Content-Length response header with a
+ // declared size and then attempted to write more bytes than
+ // declared.
+ ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
+
+ // Deprecated: ErrWriteAfterFlush is no longer used.
+ ErrWriteAfterFlush = errors.New("unused")
)
// A Handler responds to an HTTP request.
@@ -50,10 +69,15 @@ var (
// ResponseWriter. Cautious handlers should read the Request.Body
// first, and then reply.
//
+// Except for reading the body, handlers should not modify the
+// provided Request.
+//
// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
// that the effect of the panic was isolated to the active request.
// It recovers the panic, logs a stack trace to the server error log,
-// and hangs up the connection.
+// and hangs up the connection. To abort a handler so the client sees
+// an interrupted response but the server doesn't log an error, panic
+// with the value ErrAbortHandler.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
@@ -65,18 +89,46 @@ type Handler interface {
// has returned.
type ResponseWriter interface {
// Header returns the header map that will be sent by
- // WriteHeader. Changing the header after a call to
- // WriteHeader (or Write) has no effect unless the modified
- // headers were declared as trailers by setting the
- // "Trailer" header before the call to WriteHeader (see example).
- // To suppress implicit response headers, set their value to nil.
+ // WriteHeader. The Header map also is the mechanism with which
+ // Handlers can set HTTP trailers.
+ //
+ // Changing the header map after a call to WriteHeader (or
+ // Write) has no effect unless the modified headers are
+ // trailers.
+ //
+ // There are two ways to set Trailers. The preferred way is to
+ // predeclare in the headers which trailers you will later
+ // send by setting the "Trailer" header to the names of the
+ // trailer keys which will come later. In this case, those
+ // keys of the Header map are treated as if they were
+ // trailers. See the example. The second way, for trailer
+ // keys not known to the Handler until after the first Write,
+ // is to prefix the Header map keys with the TrailerPrefix
+ // constant value. See TrailerPrefix.
+ //
+ // To suppress implicit response headers (such as "Date"), set
+ // their value to nil.
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.
@@ -90,6 +142,10 @@ type ResponseWriter interface {
// The Flusher interface is implemented by ResponseWriters that allow
// an HTTP handler to flush buffered data to the client.
//
+// The default HTTP/1.x and HTTP/2 ResponseWriter implementations
+// support Flusher, but ResponseWriter wrappers may not. Handlers
+// should always test for this ability at runtime.
+//
// Note that even for ResponseWriters that support Flush,
// if the client is connected through an HTTP proxy,
// the buffered data may not reach the client until the response
@@ -101,9 +157,14 @@ type Flusher interface {
// The Hijacker interface is implemented by ResponseWriters that allow
// an HTTP handler to take over the connection.
+//
+// The default ResponseWriter for HTTP/1.x connections supports
+// Hijacker, but HTTP/2 connections intentionally do not.
+// ResponseWriter wrappers may also not support Hijacker. Handlers
+// should always test for this ability at runtime.
type Hijacker interface {
// Hijack lets the caller take over the connection.
- // After a call to Hijack(), the HTTP server library
+ // After a call to Hijack the HTTP server library
// will not do anything else with the connection.
//
// It becomes the caller's responsibility to manage
@@ -113,6 +174,9 @@ type Hijacker interface {
// already set, depending on the configuration of the
// Server. It is the caller's responsibility to set
// or clear those deadlines as needed.
+ //
+ // The returned bufio.Reader may contain unprocessed buffered
+ // data from the client.
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
@@ -143,12 +207,29 @@ type CloseNotifier interface {
CloseNotify() <-chan bool
}
+var (
+ // ServerContextKey is a context key. It can be used in HTTP
+ // handlers with context.WithValue to access the server that
+ // started the handler. The associated value will be of
+ // type *Server.
+ ServerContextKey = &contextKey{"http-server"}
+
+ // LocalAddrContextKey is a context key. It can be used in
+ // HTTP handlers with context.WithValue to access the address
+ // the local address the connection arrived on.
+ // The associated value will be of type net.Addr.
+ LocalAddrContextKey = &contextKey{"local-addr"}
+)
+
// A conn represents the server side of an HTTP connection.
type conn struct {
// server is the server on which the connection arrived.
// Immutable; never nil.
server *Server
+ // cancelCtx cancels the connection-level context.
+ cancelCtx context.CancelFunc
+
// rwc is the underlying network connection.
// This is never wrapped by other types and is the value given out
// to CloseNotifier callers. It is usually of type *net.TCPConn or
@@ -175,7 +256,6 @@ type conn struct {
r *connReader
// bufr reads from r.
- // Users of bufr must hold mu.
bufr *bufio.Reader
// bufw writes to checkConnErrorWriter{c}, which populates werr on error.
@@ -185,7 +265,11 @@ type conn struct {
// on this connection, if any.
lastMethod string
- // mu guards hijackedv, use of bufr, (*response).closeNotifyCh.
+ curReq atomic.Value // of *response (which has a Request in it)
+
+ curState atomic.Value // of ConnState
+
+ // mu guards hijackedv
mu sync.Mutex
// hijackedv is whether this connection has been hijacked
@@ -205,9 +289,18 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if c.hijackedv {
return nil, nil, ErrHijacked
}
+ c.r.abortPendingRead()
+
c.hijackedv = true
rwc = c.rwc
+ rwc.SetDeadline(time.Time{})
+
buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
+ if c.r.hasByte {
+ if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil {
+ return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err)
+ }
+ }
c.setState(rwc, StateHijacked)
return
}
@@ -289,13 +382,7 @@ func (cw *chunkWriter) close() {
bw := cw.res.conn.bufw // conn's bufio writer
// zero chunk to mark EOF
bw.WriteString("0\r\n")
- if len(cw.res.trailers) > 0 {
- trailers := make(Header)
- for _, h := range cw.res.trailers {
- if vv := cw.res.handlerHeader[h]; len(vv) > 0 {
- trailers[h] = vv
- }
- }
+ if trailers := cw.res.finalTrailers(); trailers != nil {
trailers.Write(bw) // the writer handles noting errors
}
// final blank line after the trailers (whether
@@ -306,11 +393,14 @@ func (cw *chunkWriter) close() {
// A response represents the server side of an HTTP response.
type response struct {
- conn *conn
- req *Request // request for this response
- reqBody io.ReadCloser
- wroteHeader bool // reply header has been (logically) written
- wroteContinue bool // 100 Continue response was written
+ conn *conn
+ req *Request // request for this response
+ reqBody io.ReadCloser
+ cancelCtx context.CancelFunc // when ServeHTTP exits
+ wroteHeader bool // reply header has been (logically) written
+ wroteContinue bool // 100 Continue response was written
+ wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
+ wantsClose bool // HTTP request has Connection "close"
w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter
@@ -342,7 +432,7 @@ type response struct {
requestBodyLimitHit bool
// trailers are the headers to be sent after the handler
- // finishes writing the body. This field is initialized from
+ // finishes writing the body. This field is initialized from
// the Trailer response header when the response header is
// written.
trailers []string
@@ -353,9 +443,48 @@ type response struct {
dateBuf [len(TimeFormat)]byte
clenBuf [10]byte
- // closeNotifyCh is non-nil once CloseNotify is called.
- // Guarded by conn.mu
- closeNotifyCh <-chan bool
+ // closeNotifyCh is the channel returned by CloseNotify.
+ // TODO(bradfitz): this is currently (for Go 1.8) always
+ // non-nil. Make this lazily-created again as it used to be?
+ closeNotifyCh chan bool
+ didCloseNotify int32 // atomic (only 0->1 winner should send)
+}
+
+// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
+// that, if present, signals that the map entry is actually for
+// the response trailers, and not the response headers. The prefix
+// is stripped after the ServeHTTP call finishes and the values are
+// sent in the trailers.
+//
+// This mechanism is intended only for trailers that are not known
+// prior to the headers being written. If the set of trailers is fixed
+// or known before the header is written, the normal Go trailers mechanism
+// is preferred:
+// https://golang.org/pkg/net/http/#ResponseWriter
+// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+const TrailerPrefix = "Trailer:"
+
+// finalTrailers is called after the Handler exits and returns a non-nil
+// value if the Handler set any trailers.
+func (w *response) finalTrailers() Header {
+ var t Header
+ for k, vv := range w.handlerHeader {
+ if strings.HasPrefix(k, TrailerPrefix) {
+ if t == nil {
+ t = make(Header)
+ }
+ t[strings.TrimPrefix(k, TrailerPrefix)] = vv
+ }
+ }
+ for _, k := range w.trailers {
+ if t == nil {
+ t = make(Header)
+ }
+ for _, v := range w.handlerHeader[k] {
+ t.Add(k, v)
+ }
+ }
+ return t
}
type atomicBool int32
@@ -488,60 +617,152 @@ type readResult struct {
// call blocked in a background goroutine to wait for activity and
// trigger a CloseNotifier channel.
type connReader struct {
- r io.Reader
- remain int64 // bytes remaining
+ conn *conn
- // ch is non-nil if a background read is in progress.
- // It is guarded by conn.mu.
- ch chan readResult
+ mu sync.Mutex // guards following
+ hasByte bool
+ byteBuf [1]byte
+ bgErr error // non-nil means error happened on background read
+ cond *sync.Cond
+ inRead bool
+ aborted bool // set true before conn.rwc deadline is set to past
+ remain int64 // bytes remaining
+}
+
+func (cr *connReader) lock() {
+ cr.mu.Lock()
+ if cr.cond == nil {
+ cr.cond = sync.NewCond(&cr.mu)
+ }
+}
+
+func (cr *connReader) unlock() { cr.mu.Unlock() }
+
+func (cr *connReader) startBackgroundRead() {
+ cr.lock()
+ defer cr.unlock()
+ if cr.inRead {
+ panic("invalid concurrent Body.Read call")
+ }
+ if cr.hasByte {
+ return
+ }
+ cr.inRead = true
+ cr.conn.rwc.SetReadDeadline(time.Time{})
+ go cr.backgroundRead()
+}
+
+func (cr *connReader) backgroundRead() {
+ n, err := cr.conn.rwc.Read(cr.byteBuf[:])
+ cr.lock()
+ if n == 1 {
+ cr.hasByte = true
+ // We were at EOF already (since we wouldn't be in a
+ // background read otherwise), so this is a pipelined
+ // HTTP request.
+ cr.closeNotifyFromPipelinedRequest()
+ }
+ if ne, ok := err.(net.Error); ok && cr.aborted && ne.Timeout() {
+ // Ignore this error. It's the expected error from
+ // another goroutine calling abortPendingRead.
+ } else if err != nil {
+ cr.handleReadError(err)
+ }
+ cr.aborted = false
+ cr.inRead = false
+ cr.unlock()
+ cr.cond.Broadcast()
+}
+
+func (cr *connReader) abortPendingRead() {
+ cr.lock()
+ defer cr.unlock()
+ if !cr.inRead {
+ return
+ }
+ cr.aborted = true
+ cr.conn.rwc.SetReadDeadline(aLongTimeAgo)
+ for cr.inRead {
+ cr.cond.Wait()
+ }
+ cr.conn.rwc.SetReadDeadline(time.Time{})
}
func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain }
-func (cr *connReader) setInfiniteReadLimit() { cr.remain = 1<<63 - 1 }
+func (cr *connReader) setInfiniteReadLimit() { cr.remain = maxInt64 }
func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 }
+// may be called from multiple goroutines.
+func (cr *connReader) handleReadError(err error) {
+ cr.conn.cancelCtx()
+ cr.closeNotify()
+}
+
+// closeNotifyFromPipelinedRequest simply calls closeNotify.
+//
+// This method wrapper is here for documentation. The callers are the
+// cases where we send on the closenotify channel because of a
+// pipelined HTTP request, per the previous Go behavior and
+// documentation (that this "MAY" happen).
+//
+// TODO: consider changing this behavior and making context
+// cancelation and closenotify work the same.
+func (cr *connReader) closeNotifyFromPipelinedRequest() {
+ cr.closeNotify()
+}
+
+// may be called from multiple goroutines.
+func (cr *connReader) closeNotify() {
+ res, _ := cr.conn.curReq.Load().(*response)
+ if res != nil {
+ if atomic.CompareAndSwapInt32(&res.didCloseNotify, 0, 1) {
+ res.closeNotifyCh <- true
+ }
+ }
+}
+
func (cr *connReader) Read(p []byte) (n int, err error) {
+ cr.lock()
+ if cr.inRead {
+ cr.unlock()
+ panic("invalid concurrent Body.Read call")
+ }
if cr.hitReadLimit() {
+ cr.unlock()
return 0, io.EOF
}
+ if cr.bgErr != nil {
+ err = cr.bgErr
+ cr.unlock()
+ return 0, err
+ }
if len(p) == 0 {
- return
+ cr.unlock()
+ return 0, nil
}
if int64(len(p)) > cr.remain {
p = p[:cr.remain]
}
-
- // Is a background read (started by CloseNotifier) already in
- // flight? If so, wait for it and use its result.
- ch := cr.ch
- if ch != nil {
- cr.ch = nil
- res := <-ch
- if res.n == 1 {
- p[0] = res.b
- cr.remain -= 1
- }
- return res.n, res.err
+ if cr.hasByte {
+ p[0] = cr.byteBuf[0]
+ cr.hasByte = false
+ cr.unlock()
+ return 1, nil
}
- n, err = cr.r.Read(p)
- cr.remain -= int64(n)
- return
-}
+ cr.inRead = true
+ cr.unlock()
+ n, err = cr.conn.rwc.Read(p)
-func (cr *connReader) startBackgroundRead(onReadComplete func()) {
- if cr.ch != nil {
- // Background read already started.
- return
+ cr.lock()
+ cr.inRead = false
+ if err != nil {
+ cr.handleReadError(err)
}
- cr.ch = make(chan readResult, 1)
- go cr.closeNotifyAwaitActivityRead(cr.ch, onReadComplete)
-}
+ cr.remain -= int64(n)
+ cr.unlock()
-func (cr *connReader) closeNotifyAwaitActivityRead(ch chan<- readResult, onReadComplete func()) {
- var buf [1]byte
- n, err := cr.r.Read(buf[:1])
- onReadComplete()
- ch <- readResult{n, err, buf[0]}
+ cr.cond.Broadcast()
+ return n, err
}
var (
@@ -573,7 +794,7 @@ func newBufioReader(r io.Reader) *bufio.Reader {
br.Reset(r)
return br
}
- // Note: if this reader size is every changed, update
+ // Note: if this reader size is ever changed, update
// TestHandlerBodyClose's assumptions.
return bufio.NewReader(r)
}
@@ -681,14 +902,23 @@ func appendTime(b []byte, t time.Time) []byte {
var errTooLarge = errors.New("http: request too large")
// Read next request from connection.
-func (c *conn) readRequest() (w *response, err error) {
+func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
if c.hijacked() {
return nil, ErrHijacked
}
+ var (
+ wholeReqDeadline time.Time // or zero if none
+ hdrDeadline time.Time // or zero if none
+ )
+ t0 := time.Now()
+ if d := c.server.readHeaderTimeout(); d != 0 {
+ hdrDeadline = t0.Add(d)
+ }
if d := c.server.ReadTimeout; d != 0 {
- c.rwc.SetReadDeadline(time.Now().Add(d))
+ wholeReqDeadline = t0.Add(d)
}
+ c.rwc.SetReadDeadline(hdrDeadline)
if d := c.server.WriteTimeout; d != 0 {
defer func() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
@@ -696,63 +926,102 @@ func (c *conn) readRequest() (w *response, err error) {
}
c.r.setReadLimit(c.server.initialReadLimitSize())
- c.mu.Lock() // while using bufr
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
c.bufr.Discard(numLeadingCRorLF(peek))
}
req, err := readRequest(c.bufr, keepHostHeader)
- c.mu.Unlock()
if err != nil {
if c.r.hitReadLimit() {
return nil, errTooLarge
}
return nil, err
}
+
+ if !http1ServerSupportsRequest(req) {
+ return nil, badRequestError("unsupported protocol version")
+ }
+
c.lastMethod = req.Method
c.r.setInfiniteReadLimit()
hosts, haveHost := req.Header["Host"]
- if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
+ isH2Upgrade := req.isH2Upgrade()
+ if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade {
return nil, badRequestError("missing required Host header")
}
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")
}
}
}
delete(req.Header, "Host")
+ ctx, cancelCtx := context.WithCancel(ctx)
+ req.ctx = ctx
req.RemoteAddr = c.remoteAddr
req.TLS = c.tlsState
if body, ok := req.Body.(*body); ok {
body.doEarlyClose = true
}
+ // Adjust the read deadline if necessary.
+ if !hdrDeadline.Equal(wholeReqDeadline) {
+ c.rwc.SetReadDeadline(wholeReqDeadline)
+ }
+
w = &response{
conn: c,
+ cancelCtx: cancelCtx,
req: req,
reqBody: req.Body,
handlerHeader: make(Header),
contentLength: -1,
+ closeNotifyCh: make(chan bool, 1),
+
+ // We populate these ahead of time so we're not
+ // reading from req.Header after their Handler starts
+ // and maybe mutates it (Issue 14940)
+ wants10KeepAlive: req.wantsHttp10KeepAlive(),
+ wantsClose: req.wantsClose(),
+ }
+ if isH2Upgrade {
+ w.closeAfterReply = true
}
w.cw.res = w
w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
return w, nil
}
+// http1ServerSupportsRequest reports whether Go's HTTP/1.x server
+// supports the given request.
+func http1ServerSupportsRequest(req *Request) bool {
+ if req.ProtoMajor == 1 {
+ return true
+ }
+ // Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can
+ // wire up their own HTTP/2 upgrades.
+ if req.ProtoMajor == 2 && req.ProtoMinor == 0 &&
+ req.Method == "PRI" && req.RequestURI == "*" {
+ return true
+ }
+ // Reject HTTP/0.x, and all other HTTP/2+ requests (which
+ // aren't encoded in ASCII anyway).
+ return false
+}
+
func (w *response) Header() Header {
if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader {
// Accessing the header between logically writing it
@@ -766,7 +1035,7 @@ func (w *response) Header() Header {
// maxPostHandlerReadBytes is the max number of Request.Body bytes not
// consumed by a handler that the server will read from the client
-// in order to keep a connection alive. If there are more bytes than
+// in order to keep a connection alive. If there are more bytes than
// this then the server to be paranoid instead sends a "Connection:
// close" response.
//
@@ -855,8 +1124,8 @@ func (h extraHeader) Write(w *bufio.Writer) {
// to cw.res.conn.bufw.
//
// p is not written by writeHeader, but is the first chunk of the body
-// that will be written. It is sniffed for a Content-Type if none is
-// set explicitly. It's also used to set the Content-Length, if the
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly. It's also used to set the Content-Length, if the
// total body size was small and the handler has already finished
// running.
func (cw *chunkWriter) writeHeader(p []byte) {
@@ -895,7 +1164,17 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
var setHeader extraHeader
+ // Don't write out the fake "Trailer:foo" keys. See TrailerPrefix.
trailers := false
+ for k := range cw.header {
+ if strings.HasPrefix(k, TrailerPrefix) {
+ if excludeHeader == nil {
+ excludeHeader = make(map[string]bool)
+ }
+ excludeHeader[k] = true
+ trailers = true
+ }
+ }
for _, v := range cw.header["Trailer"] {
trailers = true
foreachHeaderElement(v, cw.res.declareTrailer)
@@ -911,9 +1190,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// Exceptions: 304/204/1xx responses never get Content-Length, and if
// it was a HEAD request, we don't know the difference between
// 0 actual bytes and 0 bytes because the handler noticed it
- // was a HEAD request and chose not to write anything. So for
+ // was a HEAD request and chose not to write anything. So for
// HEAD, the handler should either write the Content-Length or
- // write non-zero bytes. If it's actually 0 bytes and the
+ // write non-zero bytes. If it's actually 0 bytes and the
// handler never looked at the Request.Method, we just don't
// send a Content-Length header.
// Further, we don't send an automatic Content-Length if they
@@ -925,7 +1204,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// If this was an HTTP/1.0 request with keep-alive and we sent a
// Content-Length back, we can make this a keep-alive response ...
- if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled {
+ if w.wants10KeepAlive && keepAlivesEnabled {
sentLength := header.get("Content-Length") != ""
if sentLength && header.get("Connection") == "keep-alive" {
w.closeAfterReply = false
@@ -935,12 +1214,12 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// Check for a explicit (and valid) Content-Length header.
hasCL := w.contentLength != -1
- if w.req.wantsHttp10KeepAlive() && (isHEAD || hasCL) {
+ if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) {
_, connectionHeaderSet := header["Connection"]
if !connectionHeaderSet {
setHeader.connection = "keep-alive"
}
- } else if !w.req.ProtoAtLeast(1, 1) || w.req.wantsClose() {
+ } else if !w.req.ProtoAtLeast(1, 1) || w.wantsClose {
w.closeAfterReply = true
}
@@ -965,9 +1244,12 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
// Per RFC 2616, we should consume the request body before
- // replying, if the handler hasn't already done so. But we
+ // 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
@@ -1009,7 +1291,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
w.closeAfterReply = true
}
default:
- // Some other kind of error occured, like a read timeout, or
+ // Some other kind of error occurred, like a read timeout, or
// corrupt chunked encoding. In any case, whatever remains
// on the wire must not be parsed as another HTTP request.
w.closeAfterReply = true
@@ -1069,6 +1351,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// to avoid closing the connection at EOF.
cw.chunking = true
setHeader.transferEncoding = "chunked"
+ if hasTE && te == "chunked" {
+ // We will send the chunked Transfer-Encoding header later.
+ delHeader("Transfer-Encoding")
+ }
}
} else {
// HTTP version < 1.1: cannot do chunked transfer
@@ -1148,7 +1434,7 @@ func statusLine(req *Request, code int) string {
if proto11 {
proto = "HTTP/1.1"
}
- codestring := strconv.Itoa(code)
+ codestring := fmt.Sprintf("%03d", code)
text, ok := statusText[code]
if !ok {
text = "status code " + codestring
@@ -1174,7 +1460,7 @@ func (w *response) bodyAllowed() bool {
// The Life Of A Write is like this:
//
// Handler starts. No header has been sent. The handler can either
-// write a header, or just start writing. Writing before sending a header
+// write a header, or just start writing. Writing before sending a header
// sends an implicitly empty 200 OK header.
//
// If the handler didn't declare a Content-Length up front, we either
@@ -1200,7 +1486,7 @@ func (w *response) bodyAllowed() bool {
// initial header contains both a Content-Type and Content-Length.
// Also short-circuit in (1) when the header's been sent and not in
// chunking mode, writing directly to (4) instead, if (2) has no
-// buffered data. More generally, we could short-circuit from (1) to
+// buffered data. More generally, we could short-circuit from (1) to
// (3) even in chunking mode if the write size from (1) is over some
// threshold and nothing is in (2). The answer might be mostly making
// bufferBeforeChunkingSize smaller and having bufio's fast-paths deal
@@ -1216,7 +1502,9 @@ func (w *response) WriteString(data string) (n int, err error) {
// either dataB or dataS is non-zero.
func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
if w.conn.hijacked() {
- w.conn.server.logf("http: response.Write on hijacked connection")
+ if lenData > 0 {
+ w.conn.server.logf("http: response.Write on hijacked connection")
+ }
return 0, ErrHijacked
}
if !w.wroteHeader {
@@ -1252,6 +1540,8 @@ func (w *response) finishRequest() {
w.cw.close()
w.conn.bufw.Flush()
+ w.conn.r.abortPendingRead()
+
// Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely.
w.reqBody.Close()
@@ -1341,7 +1631,7 @@ type closeWriter interface {
var _ closeWriter = (*net.TCPConn)(nil)
// closeWrite flushes any outstanding data and sends a FIN packet (if
-// client is connected via TCP), signalling that we're done. We then
+// client is connected via TCP), signalling that we're done. We then
// pause for a bit, hoping the client processes it before any
// subsequent RST.
//
@@ -1355,7 +1645,7 @@ func (c *conn) closeWriteAndWait() {
}
// validNPN reports whether the proto is not a blacklisted Next
-// Protocol Negotiation protocol. Empty and built-in protocol types
+// Protocol Negotiation protocol. Empty and built-in protocol types
// are blacklisted and can't be overridden with alternate
// implementations.
func validNPN(proto string) bool {
@@ -1367,23 +1657,65 @@ func validNPN(proto string) bool {
}
func (c *conn) setState(nc net.Conn, state ConnState) {
- if hook := c.server.ConnState; hook != nil {
+ srv := c.server
+ switch state {
+ case StateNew:
+ srv.trackConn(c, true)
+ case StateHijacked, StateClosed:
+ srv.trackConn(c, false)
+ }
+ c.curState.Store(connStateInterface[state])
+ if hook := srv.ConnState; hook != nil {
hook(nc, state)
}
}
+// connStateInterface is an array of the interface{} versions of
+// ConnState values, so we can use them in atomic.Values later without
+// paying the cost of shoving their integers in an interface{}.
+var connStateInterface = [...]interface{}{
+ StateNew: StateNew,
+ StateActive: StateActive,
+ StateIdle: StateIdle,
+ StateHijacked: StateHijacked,
+ StateClosed: StateClosed,
+}
+
// badRequestError is a literal string (used by in the server in HTML,
// unescaped) to tell the user why their request was bad. It should
-// be plain text without user info or other embeddded errors.
+// be plain text without user info or other embedded errors.
type badRequestError string
func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
+// ErrAbortHandler is a sentinel panic value to abort a handler.
+// While any panic from ServeHTTP aborts the response to the client,
+// panicking with ErrAbortHandler also suppresses logging of a stack
+// trace to the server's error log.
+var ErrAbortHandler = errors.New("net/http: abort Handler")
+
+// isCommonNetReadError reports whether err is a common error
+// encountered during reading a request off the network when the
+// client has gone away or had its read fail somehow. This is used to
+// determine which logs are interesting enough to log about.
+func isCommonNetReadError(err error) bool {
+ if err == io.EOF {
+ return true
+ }
+ if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ return true
+ }
+ if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
+ return true
+ }
+ return false
+}
+
// Serve a new connection.
-func (c *conn) serve() {
+func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String()
defer func() {
- if err := recover(); err != nil {
+ if err := recover(); err != nil && err != ErrAbortHandler {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
@@ -1417,38 +1749,46 @@ func (c *conn) serve() {
}
}
- c.r = &connReader{r: c.rwc}
+ // HTTP/1.x from here on.
+
+ ctx, cancelCtx := context.WithCancel(ctx)
+ c.cancelCtx = cancelCtx
+ defer cancelCtx()
+
+ c.r = &connReader{conn: c}
c.bufr = newBufioReader(c.r)
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
for {
- w, err := c.readRequest()
+ w, err := c.readRequest(ctx)
if c.r.remain != c.server.initialReadLimitSize() {
// If we read any bytes off the wire, we're active.
c.setState(c.rwc, StateActive)
}
if err != nil {
+ const errorHeaders = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n"
+
if err == errTooLarge {
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
- // request. Undefined behavior.
- io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")
+ // request. Undefined behavior.
+ const publicErr = "431 Request Header Fields Too Large"
+ fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
c.closeWriteAndWait()
return
}
- if err == io.EOF {
- return // don't reply
- }
- if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ if isCommonNetReadError(err) {
return // don't reply
}
- var publicErr string
+
+ publicErr := "400 Bad Request"
if v, ok := err.(badRequestError); ok {
- publicErr = ": " + string(v)
+ publicErr = publicErr + ": " + string(v)
}
- io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)
+
+ fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
return
}
@@ -1464,12 +1804,26 @@ func (c *conn) serve() {
return
}
+ c.curReq.Store(w)
+
+ if requestBodyRemains(req.Body) {
+ registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
+ } else {
+ if w.conn.bufr.Buffered() > 0 {
+ w.conn.r.closeNotifyFromPipelinedRequest()
+ }
+ w.conn.r.startBackgroundRead()
+ }
+
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
- // [*] Not strictly true: HTTP pipelining. We could let them all process
+ // [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
+ // But we're not going to implement HTTP pipelining because it
+ // was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req)
+ w.cancelCtx()
if c.hijacked() {
return
}
@@ -1481,6 +1835,23 @@ func (c *conn) serve() {
return
}
c.setState(c.rwc, StateIdle)
+ c.curReq.Store((*response)(nil))
+
+ if !w.conn.server.doKeepAlives() {
+ // We're in shutdown mode. We might've replied
+ // to the user without "Connection: close" and
+ // they might think they can send another
+ // request, but such is life with HTTP/1.1.
+ return
+ }
+
+ if d := c.server.idleTimeout(); d != 0 {
+ c.rwc.SetReadDeadline(time.Now().Add(d))
+ if _, err := c.bufr.Peek(4); err != nil {
+ return
+ }
+ }
+ c.rwc.SetReadDeadline(time.Time{})
}
}
@@ -1488,7 +1859,7 @@ func (w *response) sendExpectationFailed() {
// TODO(bradfitz): let ServeHTTP handlers handle
// requests with non-standard expectation[s]? Seems
// theoretical at best, and doesn't fit into the
- // current ServeHTTP model anyway. We'd need to
+ // current ServeHTTP model anyway. We'd need to
// make the ResponseWriter an optional
// "ExpectReplier" interface or something.
//
@@ -1516,10 +1887,6 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
c.mu.Lock()
defer c.mu.Unlock()
- if w.closeNotifyCh != nil {
- return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier in same ServeHTTP call")
- }
-
// Release the bufioWriter that writes to the chunk writer, it is not
// used after a connection has been hijacked.
rwc, buf, err = c.hijackLocked()
@@ -1534,50 +1901,7 @@ func (w *response) CloseNotify() <-chan bool {
if w.handlerDone.isSet() {
panic("net/http: CloseNotify called after ServeHTTP finished")
}
- c := w.conn
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if w.closeNotifyCh != nil {
- return w.closeNotifyCh
- }
- ch := make(chan bool, 1)
- w.closeNotifyCh = ch
-
- if w.conn.hijackedv {
- // CloseNotify is undefined after a hijack, but we have
- // no place to return an error, so just return a channel,
- // even though it'll never receive a value.
- return ch
- }
-
- var once sync.Once
- notify := func() { once.Do(func() { ch <- true }) }
-
- if requestBodyRemains(w.reqBody) {
- // They're still consuming the request body, so we
- // shouldn't notify yet.
- registerOnHitEOF(w.reqBody, func() {
- c.mu.Lock()
- defer c.mu.Unlock()
- startCloseNotifyBackgroundRead(c, notify)
- })
- } else {
- startCloseNotifyBackgroundRead(c, notify)
- }
- return ch
-}
-
-// c.mu must be held.
-func startCloseNotifyBackgroundRead(c *conn, notify func()) {
- if c.bufr.Buffered() > 0 {
- // They've consumed the request body, so anything
- // remaining is a pipelined request, which we
- // document as firing on.
- notify()
- } else {
- c.r.startBackgroundRead(notify)
- }
+ return w.closeNotifyCh
}
func registerOnHitEOF(rc io.ReadCloser, fn func()) {
@@ -1594,7 +1918,7 @@ func registerOnHitEOF(rc io.ReadCloser, fn func()) {
// requestBodyRemains reports whether future calls to Read
// on rc might yield more data.
func requestBodyRemains(rc io.ReadCloser) bool {
- if rc == eofReader {
+ if rc == NoBody {
return false
}
switch v := rc.(type) {
@@ -1608,7 +1932,7 @@ func requestBodyRemains(rc io.ReadCloser) bool {
}
// The HandlerFunc type is an adapter to allow the use of
-// ordinary functions as HTTP handlers. If f is a function
+// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
@@ -1621,6 +1945,8 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
// Helper handlers
// Error replies to the request with the specified error message and HTTP code.
+// It does not otherwise end the request; the caller should ensure no further
+// writes are done to w.
// The error message should be plain text.
func Error(w ResponseWriter, error string, code int) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
@@ -1706,10 +2032,10 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
}
}
- w.Header().Set("Location", urlStr)
+ w.Header().Set("Location", hexEscapeNonASCII(urlStr))
w.WriteHeader(code)
- // RFC2616 recommends that a short note "SHOULD" be included in the
+ // RFC 2616 recommends that a short note "SHOULD" be included in the
// response because older user agents may not understand 301/307.
// Shouldn't send the response for POST or HEAD; that leaves GET.
if r.Method == "GET" {
@@ -1779,7 +2105,7 @@ func RedirectHandler(url string, code int) Handler {
// been registered separately.
//
// Patterns may optionally begin with a host name, restricting matches to
-// URLs on that host only. Host-specific patterns take precedence over
+// URLs on that host only. Host-specific patterns take precedence over
// general patterns, so that a handler might register for the two patterns
// "/codesearch" and "codesearch.google.com/" without also taking over
// requests for "http://www.google.com/".
@@ -1800,10 +2126,12 @@ type muxEntry struct {
}
// NewServeMux allocates and returns a new ServeMux.
-func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
+func NewServeMux() *ServeMux { return new(ServeMux) }
// DefaultServeMux is the default ServeMux used by Serve.
-var DefaultServeMux = NewServeMux()
+var DefaultServeMux = &defaultServeMux
+
+var defaultServeMux ServeMux
// Does path match pattern?
func pathMatch(pattern, path string) bool {
@@ -1926,6 +2254,9 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
panic("http: multiple registrations for " + pattern)
}
+ if mux.m == nil {
+ mux.m = make(map[string]muxEntry)
+ }
mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
if pattern[0] != '/' {
@@ -1968,7 +2299,7 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
}
// Serve accepts incoming HTTP connections on the listener l,
-// creating a new service goroutine for each. The service goroutines
+// creating a new service goroutine for each. The service goroutines
// read requests and then call handler to reply to them.
// Handler is typically nil, in which case the DefaultServeMux is used.
func Serve(l net.Listener, handler Handler) error {
@@ -1979,21 +2310,53 @@ func Serve(l net.Listener, handler Handler) error {
// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
- Addr string // TCP address to listen on, ":http" if empty
- Handler Handler // handler to invoke, http.DefaultServeMux if nil
- ReadTimeout time.Duration // maximum duration before timing out read of the request
- WriteTimeout time.Duration // maximum duration before timing out write of the response
- MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
- TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
+ Addr string // TCP address to listen on, ":http" if empty
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
+ TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
+
+ // ReadTimeout is the maximum duration for reading the entire
+ // request, including the body.
+ //
+ // Because ReadTimeout does not let Handlers make per-request
+ // decisions on each request body's acceptable deadline or
+ // upload rate, most users will prefer to use
+ // ReadHeaderTimeout. It is valid to use them both.
+ ReadTimeout time.Duration
+
+ // ReadHeaderTimeout is the amount of time allowed to read
+ // request headers. The connection's read deadline is reset
+ // after reading the headers and the Handler can decide what
+ // is considered too slow for the body.
+ ReadHeaderTimeout time.Duration
+
+ // WriteTimeout is the maximum duration before timing out
+ // writes of the response. It is reset whenever a new
+ // request's header is read. Like ReadTimeout, it does not
+ // let Handlers make decisions on a per-request basis.
+ WriteTimeout time.Duration
+
+ // IdleTimeout is the maximum amount of time to wait for the
+ // next request when keep-alives are enabled. If IdleTimeout
+ // is zero, the value of ReadTimeout is used. If both are
+ // zero, there is no timeout.
+ IdleTimeout time.Duration
+
+ // MaxHeaderBytes controls the maximum number of bytes the
+ // server will read parsing the request header's keys and
+ // values, including the request line. It does not limit the
+ // size of the request body.
+ // If zero, DefaultMaxHeaderBytes is used.
+ MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
- // ownership of the provided TLS connection when an NPN
- // protocol upgrade has occurred. The map key is the protocol
+ // 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
- // and RemoteAddr if not already set. The connection is
+ // and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
- // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
+ // If TLSNextProto is not nil, HTTP/2 support is not enabled
+ // automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
@@ -2008,8 +2371,132 @@ type Server struct {
ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically.
- nextProtoOnce sync.Once // guards initialization of TLSNextProto in Serve
- nextProtoErr error
+ inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)
+ nextProtoOnce sync.Once // guards setupHTTP2_* init
+ nextProtoErr error // result of http2.ConfigureServer if used
+
+ mu sync.Mutex
+ listeners map[net.Listener]struct{}
+ activeConn map[*conn]struct{}
+ doneChan chan struct{}
+}
+
+func (s *Server) getDoneChan() <-chan struct{} {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.getDoneChanLocked()
+}
+
+func (s *Server) getDoneChanLocked() chan struct{} {
+ if s.doneChan == nil {
+ s.doneChan = make(chan struct{})
+ }
+ return s.doneChan
+}
+
+func (s *Server) closeDoneChanLocked() {
+ ch := s.getDoneChanLocked()
+ select {
+ case <-ch:
+ // Already closed. Don't close again.
+ default:
+ // Safe to close here. We're the only closer, guarded
+ // by s.mu.
+ close(ch)
+ }
+}
+
+// Close immediately closes all active net.Listeners and any
+// connections in state StateNew, StateActive, or StateIdle. For a
+// graceful shutdown, use Shutdown.
+//
+// Close does not attempt to close (and does not even know about)
+// any hijacked connections, such as WebSockets.
+//
+// Close returns any error returned from closing the Server's
+// underlying Listener(s).
+func (srv *Server) Close() error {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ srv.closeDoneChanLocked()
+ err := srv.closeListenersLocked()
+ for c := range srv.activeConn {
+ c.rwc.Close()
+ delete(srv.activeConn, c)
+ }
+ return err
+}
+
+// shutdownPollInterval is how often we poll for quiescence
+// during Server.Shutdown. This is lower during tests, to
+// speed up tests.
+// Ideally we could find a solution that doesn't involve polling,
+// but which also doesn't have a high runtime cost (and doesn't
+// involve any contentious mutexes), but that is left as an
+// exercise for the reader.
+var shutdownPollInterval = 500 * time.Millisecond
+
+// Shutdown gracefully shuts down the server without interrupting any
+// active connections. Shutdown works by first closing all open
+// listeners, then closing all idle connections, and then waiting
+// indefinitely for connections to return to idle and then shut down.
+// If the provided context expires before the shutdown is complete,
+// then the context's error is returned.
+//
+// Shutdown does not attempt to close nor wait for hijacked
+// connections such as WebSockets. The caller of Shutdown should
+// separately notify such long-lived connections of shutdown and wait
+// for them to close, if desired.
+func (srv *Server) Shutdown(ctx context.Context) error {
+ atomic.AddInt32(&srv.inShutdown, 1)
+ defer atomic.AddInt32(&srv.inShutdown, -1)
+
+ srv.mu.Lock()
+ lnerr := srv.closeListenersLocked()
+ srv.closeDoneChanLocked()
+ srv.mu.Unlock()
+
+ ticker := time.NewTicker(shutdownPollInterval)
+ defer ticker.Stop()
+ for {
+ if srv.closeIdleConns() {
+ return lnerr
+ }
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-ticker.C:
+ }
+ }
+}
+
+// closeIdleConns closes all idle connections and reports whether the
+// server is quiescent.
+func (s *Server) closeIdleConns() bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ quiescent := true
+ for c := range s.activeConn {
+ st, ok := c.curState.Load().(ConnState)
+ if !ok || st != StateIdle {
+ quiescent = false
+ continue
+ }
+ c.rwc.Close()
+ delete(s.activeConn, c)
+ }
+ return quiescent
+}
+
+func (s *Server) closeListenersLocked() error {
+ var err error
+ for ln := range s.listeners {
+ if cerr := ln.Close(); cerr != nil && err == nil {
+ err = cerr
+ }
+ delete(s.listeners, ln)
+ }
+ return err
}
// A ConnState represents the state of a client connection to a server.
@@ -2032,7 +2519,7 @@ const (
// For HTTP/2, StateActive fires on the transition from zero
// to one active request, and only transitions away once all
// active requests are complete. That means that ConnState
- // can not be used to do per-request work; ConnState only notes
+ // cannot be used to do per-request work; ConnState only notes
// the overall state of the connection.
StateActive
@@ -2100,22 +2587,66 @@ func (srv *Server) ListenAndServe() error {
var testHookServerServe func(*Server, net.Listener) // used if non-nil
+// shouldDoServeHTTP2 reports whether Server.Serve should configure
+// automatic HTTP/2. (which sets up the srv.TLSNextProto map)
+func (srv *Server) shouldConfigureHTTP2ForServe() bool {
+ if srv.TLSConfig == nil {
+ // Compatibility with Go 1.6:
+ // If there's no TLSConfig, it's possible that the user just
+ // didn't set it on the http.Server, but did pass it to
+ // tls.NewListener and passed that listener to Serve.
+ // So we should configure HTTP/2 (to set up srv.TLSNextProto)
+ // in case the listener returns an "h2" *tls.Conn.
+ return true
+ }
+ // The user specified a TLSConfig on their http.Server.
+ // In this, case, only configure HTTP/2 if their tls.Config
+ // explicitly mentions "h2". Otherwise http2.ConfigureServer
+ // would modify the tls.Config to add it, but they probably already
+ // passed this tls.Config to tls.NewListener. And if they did,
+ // it's too late anyway to fix it. It would only be potentially racy.
+ // See Issue 15908.
+ return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS)
+}
+
+var ErrServerClosed = errors.New("http: Server closed")
+
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call srv.Handler to reply to them.
-// Serve always returns a non-nil error.
+//
+// For HTTP/2 support, srv.TLSConfig should be initialized to the
+// provided listener's TLS Config before calling Serve. If
+// srv.TLSConfig is non-nil and doesn't include the string "h2" in
+// Config.NextProtos, HTTP/2 support is not enabled.
+//
+// Serve always returns a non-nil error. After Shutdown or Close, the
+// returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // how long to sleep on accept failure
- if err := srv.setupHTTP2(); err != nil {
+
+ if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
+
+ srv.trackListener(l, true)
+ defer srv.trackListener(l, false)
+
+ baseCtx := context.Background() // base is always background, per Issue 16220
+ ctx := context.WithValue(baseCtx, ServerContextKey, srv)
+ ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())
for {
rw, e := l.Accept()
if e != nil {
+ select {
+ case <-srv.getDoneChan():
+ return ErrServerClosed
+ default:
+ }
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
@@ -2134,12 +2665,61 @@ func (srv *Server) Serve(l net.Listener) error {
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
- go c.serve()
+ go c.serve(ctx)
+ }
+}
+
+func (s *Server) trackListener(ln net.Listener, add bool) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.listeners == nil {
+ s.listeners = make(map[net.Listener]struct{})
+ }
+ if add {
+ // If the *Server is being reused after a previous
+ // Close or Shutdown, reset its doneChan:
+ if len(s.listeners) == 0 && len(s.activeConn) == 0 {
+ s.doneChan = nil
+ }
+ s.listeners[ln] = struct{}{}
+ } else {
+ delete(s.listeners, ln)
}
}
+func (s *Server) trackConn(c *conn, add bool) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.activeConn == nil {
+ s.activeConn = make(map[*conn]struct{})
+ }
+ if add {
+ s.activeConn[c] = struct{}{}
+ } else {
+ delete(s.activeConn, c)
+ }
+}
+
+func (s *Server) idleTimeout() time.Duration {
+ if s.IdleTimeout != 0 {
+ return s.IdleTimeout
+ }
+ return s.ReadTimeout
+}
+
+func (s *Server) readHeaderTimeout() time.Duration {
+ if s.ReadHeaderTimeout != 0 {
+ return s.ReadHeaderTimeout
+ }
+ return s.ReadTimeout
+}
+
func (s *Server) doKeepAlives() bool {
- return atomic.LoadInt32(&s.disableKeepAlives) == 0
+ return atomic.LoadInt32(&s.disableKeepAlives) == 0 && !s.shuttingDown()
+}
+
+func (s *Server) shuttingDown() bool {
+ return atomic.LoadInt32(&s.inShutdown) != 0
}
// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
@@ -2149,9 +2729,21 @@ func (s *Server) doKeepAlives() bool {
func (srv *Server) SetKeepAlivesEnabled(v bool) {
if v {
atomic.StoreInt32(&srv.disableKeepAlives, 0)
- } else {
- atomic.StoreInt32(&srv.disableKeepAlives, 1)
+ return
}
+ atomic.StoreInt32(&srv.disableKeepAlives, 1)
+
+ // Close idle HTTP/1 conns:
+ srv.closeIdleConns()
+
+ // Close HTTP/2 conns, as soon as they become idle, but reset
+ // the chan so future conns (if the listener is still active)
+ // still work and don't get a GOAWAY immediately, before their
+ // first request:
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ srv.closeDoneChanLocked() // closes http2 conns
+ srv.doneChan = nil
}
func (s *Server) logf(format string, args ...interface{}) {
@@ -2250,7 +2842,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
// Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
// before we clone it and create the TLS Listener.
- if err := srv.setupHTTP2(); err != nil {
+ if err := srv.setupHTTP2_ListenAndServeTLS(); err != nil {
return err
}
@@ -2278,14 +2870,36 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return srv.Serve(tlsListener)
}
-func (srv *Server) setupHTTP2() error {
+// setupHTTP2_ListenAndServeTLS conditionally configures HTTP/2 on
+// srv and returns whether there was an error setting it up. If it is
+// not configured for policy reasons, nil is returned.
+func (srv *Server) setupHTTP2_ListenAndServeTLS() error {
srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
return srv.nextProtoErr
}
+// setupHTTP2_Serve is called from (*Server).Serve and conditionally
+// configures HTTP/2 on srv using a more conservative policy than
+// setupHTTP2_ListenAndServeTLS because Serve may be called
+// concurrently.
+//
+// The tests named TestTransportAutomaticHTTP2* and
+// TestConcurrentServerServe in server_test.go demonstrate some
+// of the supported use cases and motivations.
+func (srv *Server) setupHTTP2_Serve() error {
+ srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve)
+ return srv.nextProtoErr
+}
+
+func (srv *Server) onceSetNextProtoDefaults_Serve() {
+ if srv.shouldConfigureHTTP2ForServe() {
+ srv.onceSetNextProtoDefaults()
+ }
+}
+
// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
// configured otherwise. (by setting srv.TLSNextProto non-nil)
-// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2).
+// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*).
func (srv *Server) onceSetNextProtoDefaults() {
if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
return
@@ -2309,15 +2923,10 @@ func (srv *Server) onceSetNextProtoDefaults() {
// TimeoutHandler buffers all Handler writes to memory and does not
// support the Hijacker or Flusher interfaces.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
- t := time.NewTimer(dt)
return &timeoutHandler{
handler: h,
body: msg,
-
- // Effectively storing a *time.Timer, but decomposed
- // for testing:
- timeout: func() <-chan time.Time { return t.C },
- cancelTimer: t.Stop,
+ dt: dt,
}
}
@@ -2328,12 +2937,11 @@ var ErrHandlerTimeout = errors.New("http: Handler timeout")
type timeoutHandler struct {
handler Handler
body string
+ dt time.Duration
- // timeout returns the channel of a *time.Timer and
- // cancelTimer cancels it. They're stored separately for
- // testing purposes.
- timeout func() <-chan time.Time // returns channel producing a timeout
- cancelTimer func() bool // optional
+ // When set, no timer will be created and this channel will
+ // be used instead.
+ testTimeout <-chan time.Time
}
func (h *timeoutHandler) errorBody() string {
@@ -2344,6 +2952,12 @@ func (h *timeoutHandler) errorBody() string {
}
func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ var t *time.Timer
+ timeout := h.testTimeout
+ if timeout == nil {
+ t = time.NewTimer(h.dt)
+ timeout = t.C
+ }
done := make(chan struct{})
tw := &timeoutWriter{
w: w,
@@ -2361,12 +2975,15 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
for k, vv := range tw.h {
dst[k] = vv
}
+ if !tw.wroteHeader {
+ tw.code = StatusOK
+ }
w.WriteHeader(tw.code)
w.Write(tw.wbuf.Bytes())
- if h.cancelTimer != nil {
- h.cancelTimer()
+ if t != nil {
+ t.Stop()
}
- case <-h.timeout():
+ case <-timeout:
tw.mu.Lock()
defer tw.mu.Unlock()
w.WriteHeader(StatusServiceUnavailable)
@@ -2449,24 +3066,6 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
}
}
-type eofReaderWithWriteTo struct{}
-
-func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil }
-func (eofReaderWithWriteTo) Read([]byte) (int, error) { return 0, io.EOF }
-
-// eofReader is a non-nil io.ReadCloser that always returns EOF.
-// It has a WriteTo method so io.Copy won't need a buffer.
-var eofReader = &struct {
- eofReaderWithWriteTo
- io.Closer
-}{
- eofReaderWithWriteTo{},
- ioutil.NopCloser(nil),
-}
-
-// Verify that an io.Copy from an eofReader won't require a buffer.
-var _ io.WriterTo = eofReader
-
// initNPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
// Requests come from NPN protocol handlers.
@@ -2481,7 +3080,7 @@ func (h initNPNRequest) ServeHTTP(rw ResponseWriter, req *Request) {
*req.TLS = h.c.ConnectionState()
}
if req.Body == nil {
- req.Body = eofReader
+ req.Body = NoBody
}
if req.RemoteAddr == "" {
req.RemoteAddr = h.c.RemoteAddr().String()
@@ -2542,6 +3141,7 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
n, err = w.c.rwc.Write(p)
if err != nil && w.c.werr == nil {
w.c.werr = err
+ w.c.cancelCtx()
}
return
}
diff --git a/libgo/go/net/http/sniff.go b/libgo/go/net/http/sniff.go
index 18810bad06..0d21b44a56 100644
--- a/libgo/go/net/http/sniff.go
+++ b/libgo/go/net/http/sniff.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -14,8 +14,8 @@ const sniffLen = 512
// DetectContentType implements the algorithm described
// at http://mimesniff.spec.whatwg.org/ to determine the
-// Content-Type of the given data. It considers at most the
-// first 512 bytes of data. DetectContentType always returns
+// Content-Type of the given data. It considers at most the
+// first 512 bytes of data. DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
func DetectContentType(data []byte) string {
@@ -91,12 +91,41 @@ var sniffSignatures = []sniffSig{
ct: "image/webp",
},
&exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"},
- &exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"},
&maskedSig{
mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
pat: []byte("RIFF\x00\x00\x00\x00WAVE"),
ct: "audio/wave",
},
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+ pat: []byte("FORM\x00\x00\x00\x00AIFF"),
+ ct: "audio/aiff",
+ },
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF"),
+ pat: []byte(".snd"),
+ ct: "audio/basic",
+ },
+ &maskedSig{
+ mask: []byte("OggS\x00"),
+ pat: []byte("\x4F\x67\x67\x53\x00"),
+ ct: "application/ogg",
+ },
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"),
+ pat: []byte("MThd\x00\x00\x00\x06"),
+ ct: "audio/midi",
+ },
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF"),
+ pat: []byte("ID3"),
+ ct: "audio/mpeg",
+ },
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+ pat: []byte("RIFF\x00\x00\x00\x00AVI "),
+ ct: "video/avi",
+ },
&exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"},
&exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"},
&exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
@@ -126,9 +155,15 @@ type maskedSig struct {
}
func (m *maskedSig) match(data []byte, firstNonWS int) string {
+ // pattern matching algorithm section 6
+ // https://mimesniff.spec.whatwg.org/#pattern-matching-algorithm
+
if m.skipWS {
data = data[firstNonWS:]
}
+ if len(m.pat) != len(m.mask) {
+ return ""
+ }
if len(data) < len(m.mask) {
return ""
}
diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go
index e0085516da..38f3f8197e 100644
--- a/libgo/go/net/http/sniff_test.go
+++ b/libgo/go/net/http/sniff_test.go
@@ -39,7 +39,18 @@ var sniffTests = []struct {
{"GIF 87a", []byte(`GIF87a`), "image/gif"},
{"GIF 89a", []byte(`GIF89a...`), "image/gif"},
+ // Audio types.
+ {"MIDI audio", []byte("MThd\x00\x00\x00\x06\x00\x01"), "audio/midi"},
+ {"MP3 audio/MPEG audio", []byte("ID3\x03\x00\x00\x00\x00\x0f"), "audio/mpeg"},
+ {"WAV audio #1", []byte("RIFFb\xb8\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
+ {"WAV audio #2", []byte("RIFF,\x00\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
+ {"AIFF audio #1", []byte("FORM\x00\x00\x00\x00AIFFCOMM\x00\x00\x00\x12\x00\x01\x00\x00\x57\x55\x00\x10\x40\x0d\xf3\x34"), "audio/aiff"},
+ {"OGG audio", []byte("OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x7e\x46\x00\x00\x00\x00\x00\x00\x1f\xf6\xb4\xfc\x01\x1e\x01\x76\x6f\x72"), "application/ogg"},
+
+ // Video types.
{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
+ {"AVI video #1", []byte("RIFF,O\n\x00AVI LISTÀ"), "video/avi"},
+ {"AVI video #2", []byte("RIFF,\n\x00\x00AVI LISTÀ"), "video/avi"},
}
func TestDetectContentType(t *testing.T) {
@@ -55,6 +66,7 @@ func TestServerContentType_h1(t *testing.T) { testServerContentType(t, h1Mode) }
func TestServerContentType_h2(t *testing.T) { testServerContentType(t, h2Mode) }
func testServerContentType(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
i, _ := strconv.Atoi(r.FormValue("i"))
@@ -149,6 +161,7 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
func TestSniffWriteSize_h2(t *testing.T) { testSniffWriteSize(t, h2Mode) }
func testSniffWriteSize(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
size, _ := strconv.Atoi(r.FormValue("size"))
diff --git a/libgo/go/net/http/status.go b/libgo/go/net/http/status.go
index f3dacab6a9..98645b7d74 100644
--- a/libgo/go/net/http/status.go
+++ b/libgo/go/net/http/status.go
@@ -4,63 +4,79 @@
package http
-// HTTP status codes, defined in RFC 2616.
+// HTTP status codes as registered with IANA.
+// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
- StatusContinue = 100
- StatusSwitchingProtocols = 101
+ StatusContinue = 100 // RFC 7231, 6.2.1
+ StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
+ StatusProcessing = 102 // RFC 2518, 10.1
- StatusOK = 200
- StatusCreated = 201
- StatusAccepted = 202
- StatusNonAuthoritativeInfo = 203
- StatusNoContent = 204
- StatusResetContent = 205
- StatusPartialContent = 206
+ StatusOK = 200 // RFC 7231, 6.3.1
+ StatusCreated = 201 // RFC 7231, 6.3.2
+ StatusAccepted = 202 // RFC 7231, 6.3.3
+ StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
+ StatusNoContent = 204 // RFC 7231, 6.3.5
+ StatusResetContent = 205 // RFC 7231, 6.3.6
+ StatusPartialContent = 206 // RFC 7233, 4.1
+ StatusMultiStatus = 207 // RFC 4918, 11.1
+ StatusAlreadyReported = 208 // RFC 5842, 7.1
+ StatusIMUsed = 226 // RFC 3229, 10.4.1
- StatusMultipleChoices = 300
- StatusMovedPermanently = 301
- StatusFound = 302
- StatusSeeOther = 303
- StatusNotModified = 304
- StatusUseProxy = 305
- StatusTemporaryRedirect = 307
+ StatusMultipleChoices = 300 // RFC 7231, 6.4.1
+ StatusMovedPermanently = 301 // RFC 7231, 6.4.2
+ StatusFound = 302 // RFC 7231, 6.4.3
+ StatusSeeOther = 303 // RFC 7231, 6.4.4
+ StatusNotModified = 304 // RFC 7232, 4.1
+ StatusUseProxy = 305 // RFC 7231, 6.4.5
+ _ = 306 // RFC 7231, 6.4.6 (Unused)
+ StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
+ StatusPermanentRedirect = 308 // RFC 7538, 3
- StatusBadRequest = 400
- StatusUnauthorized = 401
- StatusPaymentRequired = 402
- StatusForbidden = 403
- StatusNotFound = 404
- StatusMethodNotAllowed = 405
- StatusNotAcceptable = 406
- StatusProxyAuthRequired = 407
- StatusRequestTimeout = 408
- StatusConflict = 409
- StatusGone = 410
- StatusLengthRequired = 411
- StatusPreconditionFailed = 412
- StatusRequestEntityTooLarge = 413
- StatusRequestURITooLong = 414
- StatusUnsupportedMediaType = 415
- StatusRequestedRangeNotSatisfiable = 416
- StatusExpectationFailed = 417
- StatusTeapot = 418
- StatusPreconditionRequired = 428
- StatusTooManyRequests = 429
- StatusRequestHeaderFieldsTooLarge = 431
- StatusUnavailableForLegalReasons = 451
+ StatusBadRequest = 400 // RFC 7231, 6.5.1
+ StatusUnauthorized = 401 // RFC 7235, 3.1
+ StatusPaymentRequired = 402 // RFC 7231, 6.5.2
+ StatusForbidden = 403 // RFC 7231, 6.5.3
+ StatusNotFound = 404 // RFC 7231, 6.5.4
+ StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5
+ StatusNotAcceptable = 406 // RFC 7231, 6.5.6
+ StatusProxyAuthRequired = 407 // RFC 7235, 3.2
+ StatusRequestTimeout = 408 // RFC 7231, 6.5.7
+ StatusConflict = 409 // RFC 7231, 6.5.8
+ StatusGone = 410 // RFC 7231, 6.5.9
+ StatusLengthRequired = 411 // RFC 7231, 6.5.10
+ StatusPreconditionFailed = 412 // RFC 7232, 4.2
+ StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11
+ StatusRequestURITooLong = 414 // RFC 7231, 6.5.12
+ StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13
+ StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
+ StatusExpectationFailed = 417 // RFC 7231, 6.5.14
+ StatusTeapot = 418 // RFC 7168, 2.3.3
+ StatusUnprocessableEntity = 422 // RFC 4918, 11.2
+ StatusLocked = 423 // RFC 4918, 11.3
+ StatusFailedDependency = 424 // RFC 4918, 11.4
+ StatusUpgradeRequired = 426 // RFC 7231, 6.5.15
+ StatusPreconditionRequired = 428 // RFC 6585, 3
+ StatusTooManyRequests = 429 // RFC 6585, 4
+ StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
+ StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
- StatusInternalServerError = 500
- StatusNotImplemented = 501
- StatusBadGateway = 502
- StatusServiceUnavailable = 503
- StatusGatewayTimeout = 504
- StatusHTTPVersionNotSupported = 505
- StatusNetworkAuthenticationRequired = 511
+ StatusInternalServerError = 500 // RFC 7231, 6.6.1
+ StatusNotImplemented = 501 // RFC 7231, 6.6.2
+ StatusBadGateway = 502 // RFC 7231, 6.6.3
+ StatusServiceUnavailable = 503 // RFC 7231, 6.6.4
+ StatusGatewayTimeout = 504 // RFC 7231, 6.6.5
+ StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6
+ StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
+ StatusInsufficientStorage = 507 // RFC 4918, 11.5
+ StatusLoopDetected = 508 // RFC 5842, 7.2
+ StatusNotExtended = 510 // RFC 2774, 7
+ StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
var statusText = map[int]string{
StatusContinue: "Continue",
StatusSwitchingProtocols: "Switching Protocols",
+ StatusProcessing: "Processing",
StatusOK: "OK",
StatusCreated: "Created",
@@ -69,6 +85,9 @@ var statusText = map[int]string{
StatusNoContent: "No Content",
StatusResetContent: "Reset Content",
StatusPartialContent: "Partial Content",
+ StatusMultiStatus: "Multi-Status",
+ StatusAlreadyReported: "Already Reported",
+ StatusIMUsed: "IM Used",
StatusMultipleChoices: "Multiple Choices",
StatusMovedPermanently: "Moved Permanently",
@@ -77,6 +96,7 @@ var statusText = map[int]string{
StatusNotModified: "Not Modified",
StatusUseProxy: "Use Proxy",
StatusTemporaryRedirect: "Temporary Redirect",
+ StatusPermanentRedirect: "Permanent Redirect",
StatusBadRequest: "Bad Request",
StatusUnauthorized: "Unauthorized",
@@ -97,6 +117,10 @@ var statusText = map[int]string{
StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
StatusExpectationFailed: "Expectation Failed",
StatusTeapot: "I'm a teapot",
+ StatusUnprocessableEntity: "Unprocessable Entity",
+ StatusLocked: "Locked",
+ StatusFailedDependency: "Failed Dependency",
+ StatusUpgradeRequired: "Upgrade Required",
StatusPreconditionRequired: "Precondition Required",
StatusTooManyRequests: "Too Many Requests",
StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large",
@@ -108,6 +132,10 @@ var statusText = map[int]string{
StatusServiceUnavailable: "Service Unavailable",
StatusGatewayTimeout: "Gateway Timeout",
StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+ StatusVariantAlsoNegotiates: "Variant Also Negotiates",
+ StatusInsufficientStorage: "Insufficient Storage",
+ StatusLoopDetected: "Loop Detected",
+ StatusNotExtended: "Not Extended",
StatusNetworkAuthenticationRequired: "Network Authentication Required",
}
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go
index 6e59af8f6f..4f47637aa7 100644
--- a/libgo/go/net/http/transfer.go
+++ b/libgo/go/net/http/transfer.go
@@ -17,6 +17,9 @@ import (
"strconv"
"strings"
"sync"
+ "time"
+
+ "golang_org/x/net/lex/httplex"
)
// ErrLineTooLong is returned when reading request or response bodies
@@ -31,6 +34,23 @@ func (r errorReader) Read(p []byte) (n int, err error) {
return 0, r.err
}
+type byteReader struct {
+ b byte
+ done bool
+}
+
+func (br *byteReader) Read(p []byte) (n int, err error) {
+ if br.done {
+ return 0, io.EOF
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ br.done = true
+ p[0] = br.b
+ return 1, io.EOF
+}
+
// transferWriter inspects the fields of a user-supplied Request or Response,
// sanitizes them without changing the user object and provides methods for
// writing the respective header, body and trailer in wire format.
@@ -44,6 +64,9 @@ type transferWriter struct {
TransferEncoding []string
Trailer Header
IsResponse bool
+
+ FlushHeaders bool // flush headers to network before body
+ ByteReadCh chan readResult // non-nil if probeRequestBody called
}
func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -57,37 +80,15 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
}
t.Method = valueOrDefault(rr.Method, "GET")
- t.Body = rr.Body
- t.BodyCloser = rr.Body
- t.ContentLength = rr.ContentLength
t.Close = rr.Close
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
- atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
- if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
- if t.ContentLength == 0 {
- // Test to see if it's actually zero or just unset.
- var buf [1]byte
- n, rerr := io.ReadFull(t.Body, buf[:])
- if rerr != nil && rerr != io.EOF {
- t.ContentLength = -1
- t.Body = errorReader{rerr}
- } else if n == 1 {
- // Oh, guess there is data in this Body Reader after all.
- // The ContentLength field just wasn't set.
- // Stich the Body back together again, re-attaching our
- // consumed byte.
- t.ContentLength = -1
- t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
- } else {
- // Body is actually empty.
- t.Body = nil
- t.BodyCloser = nil
- }
- }
- if t.ContentLength < 0 {
- t.TransferEncoding = []string{"chunked"}
- }
+ atLeastHTTP11 = rr.protoAtLeastOutgoing(1, 1)
+ t.Body = rr.Body
+ t.BodyCloser = rr.Body
+ t.ContentLength = rr.outgoingLength()
+ if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 && t.shouldSendChunkedRequestBody() {
+ t.TransferEncoding = []string{"chunked"}
}
case *Response:
t.IsResponse = true
@@ -101,7 +102,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
- t.ResponseToHEAD = noBodyExpected(t.Method)
+ t.ResponseToHEAD = noResponseBodyExpected(t.Method)
}
// Sanitize Body,ContentLength,TransferEncoding
@@ -129,7 +130,100 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
return t, nil
}
-func noBodyExpected(requestMethod string) bool {
+// shouldSendChunkedRequestBody reports whether we should try to send a
+// chunked request body to the server. In particular, the case we really
+// want to prevent is sending a GET or other typically-bodyless request to a
+// server with a chunked body when the body has zero bytes, since GETs with
+// bodies (while acceptable according to specs), even zero-byte chunked
+// bodies, are approximately never seen in the wild and confuse most
+// servers. See Issue 18257, as one example.
+//
+// The only reason we'd send such a request is if the user set the Body to a
+// non-nil value (say, ioutil.NopCloser(bytes.NewReader(nil))) and didn't
+// set ContentLength, or NewRequest set it to -1 (unknown), so then we assume
+// there's bytes to send.
+//
+// This code tries to read a byte from the Request.Body in such cases to see
+// whether the body actually has content (super rare) or is actually just
+// a non-nil content-less ReadCloser (the more common case). In that more
+// common case, we act as if their Body were nil instead, and don't send
+// a body.
+func (t *transferWriter) shouldSendChunkedRequestBody() bool {
+ // Note that t.ContentLength is the corrected content length
+ // from rr.outgoingLength, so 0 actually means zero, not unknown.
+ if t.ContentLength >= 0 || t.Body == nil { // redundant checks; caller did them
+ return false
+ }
+ if requestMethodUsuallyLacksBody(t.Method) {
+ // Only probe the Request.Body for GET/HEAD/DELETE/etc
+ // requests, because it's only those types of requests
+ // that confuse servers.
+ t.probeRequestBody() // adjusts t.Body, t.ContentLength
+ return t.Body != nil
+ }
+ // For all other request types (PUT, POST, PATCH, or anything
+ // made-up we've never heard of), assume it's normal and the server
+ // can deal with a chunked request body. Maybe we'll adjust this
+ // later.
+ return true
+}
+
+// probeRequestBody reads a byte from t.Body to see whether it's empty
+// (returns io.EOF right away).
+//
+// But because we've had problems with this blocking users in the past
+// (issue 17480) when the body is a pipe (perhaps waiting on the response
+// headers before the pipe is fed data), we need to be careful and bound how
+// long we wait for it. This delay will only affect users if all the following
+// are true:
+// * the request body blocks
+// * the content length is not set (or set to -1)
+// * the method doesn't usually have a body (GET, HEAD, DELETE, ...)
+// * there is no transfer-encoding=chunked already set.
+// In other words, this delay will not normally affect anybody, and there
+// are workarounds if it does.
+func (t *transferWriter) probeRequestBody() {
+ t.ByteReadCh = make(chan readResult, 1)
+ go func(body io.Reader) {
+ var buf [1]byte
+ var rres readResult
+ rres.n, rres.err = body.Read(buf[:])
+ if rres.n == 1 {
+ rres.b = buf[0]
+ }
+ t.ByteReadCh <- rres
+ }(t.Body)
+ timer := time.NewTimer(200 * time.Millisecond)
+ select {
+ case rres := <-t.ByteReadCh:
+ timer.Stop()
+ if rres.n == 0 && rres.err == io.EOF {
+ // It was empty.
+ t.Body = nil
+ t.ContentLength = 0
+ } else if rres.n == 1 {
+ if rres.err != nil {
+ t.Body = io.MultiReader(&byteReader{b: rres.b}, errorReader{rres.err})
+ } else {
+ t.Body = io.MultiReader(&byteReader{b: rres.b}, t.Body)
+ }
+ } else if rres.err != nil {
+ t.Body = errorReader{rres.err}
+ }
+ case <-timer.C:
+ // Too slow. Don't wait. Read it later, and keep
+ // assuming that this is ContentLength == -1
+ // (unknown), which means we'll send a
+ // "Transfer-Encoding: chunked" header.
+ t.Body = io.MultiReader(finishAsyncByteRead{t}, t.Body)
+ // Request that Request.Write flush the headers to the
+ // network before writing the body, since our body may not
+ // become readable until it's seen the response headers.
+ t.FlushHeaders = true
+ }
+}
+
+func noResponseBodyExpected(requestMethod string) bool {
return requestMethod == "HEAD"
}
@@ -212,7 +306,7 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
if t.Body != nil {
if chunked(t.TransferEncoding) {
if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
- w = &internal.FlushAfterChunkWriter{bw}
+ w = &internal.FlushAfterChunkWriter{Writer: bw}
}
cw := internal.NewChunkedWriter(w)
_, err = io.Copy(cw, t.Body)
@@ -233,7 +327,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
if err != nil {
return err
}
- if err = t.BodyCloser.Close(); err != nil {
+ }
+ if t.BodyCloser != nil {
+ if err := t.BodyCloser.Close(); err != nil {
return err
}
}
@@ -276,7 +372,7 @@ func (t *transferReader) protoAtLeast(m, n int) bool {
}
// 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 bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
@@ -368,7 +464,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
// If there is no Content-Length or chunked Transfer-Encoding on a *Response
// and the status is not 1xx, 204 or 304, then the body is unbounded.
- // See RFC2616, section 4.4.
+ // See RFC 2616, section 4.4.
switch msg.(type) {
case *Response:
if realLength == -1 &&
@@ -379,17 +475,17 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
}
}
- // Prepare body reader. ContentLength < 0 means chunked encoding
+ // Prepare body reader. ContentLength < 0 means chunked encoding
// or close connection when finished, since multipart is not supported yet
switch {
case chunked(t.TransferEncoding):
- if noBodyExpected(t.RequestMethod) {
- t.Body = eofReader
+ if noResponseBodyExpected(t.RequestMethod) {
+ t.Body = NoBody
} else {
t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
}
case realLength == 0:
- t.Body = eofReader
+ t.Body = NoBody
case realLength > 0:
t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
default:
@@ -399,7 +495,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t.Body = &body{src: r, closing: t.Close}
} else {
// Persistent connection (i.e. HTTP/1.1)
- t.Body = eofReader
+ t.Body = NoBody
}
}
@@ -491,10 +587,31 @@ func (t *transferReader) fixTransferEncoding() error {
// function is not a method, because ultimately it should be shared by
// ReadResponse and ReadRequest.
func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) {
- contentLens := header["Content-Length"]
isRequest := !isResponse
+ contentLens := header["Content-Length"]
+
+ // Hardening against HTTP request smuggling
+ if len(contentLens) > 1 {
+ // Per RFC 7230 Section 3.3.2, prevent multiple
+ // Content-Length headers if they differ in value.
+ // If there are dups of the value, remove the dups.
+ // See Issue 16490.
+ first := strings.TrimSpace(contentLens[0])
+ for _, ct := range contentLens[1:] {
+ if first != strings.TrimSpace(ct) {
+ return 0, fmt.Errorf("http: message cannot contain multiple Content-Length headers; got %q", contentLens)
+ }
+ }
+
+ // deduplicate Content-Length
+ header.Del("Content-Length")
+ header.Add("Content-Length", first)
+
+ contentLens = header["Content-Length"]
+ }
+
// Logic based on response type or status
- if noBodyExpected(requestMethod) {
+ if noResponseBodyExpected(requestMethod) {
// For HTTP requests, as part of hardening against request
// smuggling (RFC 7230), don't allow a Content-Length header for
// methods which don't permit bodies. As an exception, allow
@@ -512,11 +629,6 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
return 0, nil
}
- if len(contentLens) > 1 {
- // harden against HTTP request smuggling. See RFC 7230.
- return 0, errors.New("http: message cannot contain multiple Content-Length headers")
- }
-
// Logic based on Transfer-Encoding
if chunked(te) {
return -1, nil
@@ -537,7 +649,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
header.Del("Content-Length")
}
- if !isResponse {
+ if isRequest {
// RFC 2616 neither explicitly permits nor forbids an
// entity-body on a GET request so we permit one if
// declared, but we default to 0 here (not -1 below)
@@ -558,21 +670,19 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
if major < 1 {
return true
- } else if major == 1 && minor == 0 {
- vv := header["Connection"]
- if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
- return true
- }
- return false
- } else {
- if headerValuesContainsToken(header["Connection"], "close") {
- if removeCloseHeader {
- header.Del("Connection")
- }
- return true
- }
}
- return false
+
+ conv := header["Connection"]
+ hasClose := httplex.HeaderValuesContainsToken(conv, "close")
+ if major == 1 && minor == 0 {
+ return hasClose || !httplex.HeaderValuesContainsToken(conv, "keep-alive")
+ }
+
+ if hasClose && removeCloseHeader {
+ header.Del("Connection")
+ }
+
+ return hasClose
}
// Parse the trailer header
@@ -729,11 +839,11 @@ func (b *body) readTrailer() error {
}
// Make sure there's a header terminator coming up, to prevent
- // a DoS with an unbounded size Trailer. It's not easy to
+ // a DoS with an unbounded size Trailer. It's not easy to
// slip in a LimitReader here, as textproto.NewReader requires
- // a concrete *bufio.Reader. Also, we can't get all the way
+ // a concrete *bufio.Reader. Also, we can't get all the way
// back up to our conn's LimitedReader that *might* be backing
- // this bufio.Reader. Instead, a hack: we iteratively Peek up
+ // this bufio.Reader. Instead, a hack: we iteratively Peek up
// to the bufio.Reader's max size, looking for a double CRLF.
// This limits the trailer to the underlying buffer size, typically 4kB.
if !seeUpcomingDoubleCRLF(b.r) {
@@ -864,3 +974,21 @@ func parseContentLength(cl string) (int64, error) {
return n, nil
}
+
+// finishAsyncByteRead finishes reading the 1-byte sniff
+// from the ContentLength==0, Body!=nil case.
+type finishAsyncByteRead struct {
+ tw *transferWriter
+}
+
+func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return
+ }
+ rres := <-fr.tw.ByteReadCh
+ n, err = rres.n, rres.err
+ if n == 1 {
+ p[0] = rres.b
+ }
+ return
+}
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index baf71d5e85..571943d6e5 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -12,17 +12,23 @@ package http
import (
"bufio"
"compress/gzip"
+ "container/list"
+ "context"
"crypto/tls"
"errors"
"fmt"
"io"
"log"
"net"
+ "net/http/httptrace"
"net/url"
"os"
"strings"
"sync"
+ "sync/atomic"
"time"
+
+ "golang_org/x/net/lex/httplex"
)
// DefaultTransport is the default implementation of Transport and is
@@ -32,10 +38,13 @@ import (
// $no_proxy) environment variables.
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
- Dial: (&net.Dialer{
+ DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
- }).Dial,
+ DualStack: true,
+ }).DialContext,
+ MaxIdleConns: 100,
+ IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
@@ -59,19 +68,22 @@ const DefaultMaxIdleConnsPerHost = 2
// For high-level functionality, such as cookies and redirects, see Client.
//
// Transport uses HTTP/1.1 for HTTP URLs and either HTTP/1.1 or HTTP/2
-// for HTTPS URLs, depending on whether the server supports HTTP/2.
-// See the package docs for more about HTTP/2.
+// for HTTPS URLs, depending on whether the server supports HTTP/2,
+// and how the Transport is configured. The DefaultTransport supports HTTP/2.
+// To explicitly enable HTTP/2 on a transport, use golang.org/x/net/http2
+// and call ConfigureTransport. See the package docs for more about HTTP/2.
type Transport struct {
idleMu sync.Mutex
- wantIdle bool // user has requested to close all idle conns
- idleConn map[connectMethodKey][]*persistConn
+ wantIdle bool // user has requested to close all idle conns
+ idleConn map[connectMethodKey][]*persistConn // most recently used at end
idleConnCh map[connectMethodKey]chan *persistConn
+ idleLRU connLRU
reqMu sync.Mutex
- reqCanceler map[*Request]func()
+ reqCanceler map[*Request]func(error)
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+ altMu sync.Mutex // guards changing altProto only
+ altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
@@ -79,9 +91,16 @@ 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 is 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 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)
// DialTLS specifies an optional dial function for creating
@@ -96,7 +115,9 @@ type Transport struct {
DialTLS func(network, addr string) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with
- // tls.Client. If nil, the default configuration is used.
+ // tls.Client.
+ // If nil, the default configuration is used.
+ // If non-nil, HTTP/2 support may not be enabled by default.
TLSClientConfig *tls.Config
// TLSHandshakeTimeout specifies the maximum amount of time waiting to
@@ -117,11 +138,21 @@ type Transport struct {
// uncompressed.
DisableCompression bool
+ // MaxIdleConns controls the maximum number of idle (keep-alive)
+ // connections across all hosts. Zero means no limit.
+ MaxIdleConns int
+
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
- // (keep-alive) to keep per-host. If zero,
+ // (keep-alive) connections to keep per-host. If zero,
// DefaultMaxIdleConnsPerHost is used.
MaxIdleConnsPerHost int
+ // IdleConnTimeout is the maximum amount of time an idle
+ // (keep-alive) connection will remain idle before closing
+ // itself.
+ // Zero means no limit.
+ IdleConnTimeout time.Duration
+
// ResponseHeaderTimeout, if non-zero, specifies the amount of
// time to wait for a server's response headers after fully
// writing the request (including its body, if any). This
@@ -131,28 +162,40 @@ type Transport struct {
// ExpectContinueTimeout, if non-zero, specifies the amount of
// time to wait for a server's first response headers after fully
// writing the request headers if the request has an
- // "Expect: 100-continue" header. Zero means no timeout.
+ // "Expect: 100-continue" header. Zero means no timeout and
+ // causes the body to be sent immediately, without
+ // waiting for the server to approve.
// This time does not include the time to send the request header.
ExpectContinueTimeout time.Duration
// TLSNextProto specifies how the Transport switches to an
// alternate protocol (such as HTTP/2) after a TLS NPN/ALPN
- // protocol negotiation. If Transport dials an TLS connection
+ // protocol negotiation. If Transport dials an TLS connection
// with a non-empty protocol name and TLSNextProto contains a
// map entry for that key (such as "h2"), then the func is
// called with the request's authority (such as "example.com"
// or "example.com:1234") and the TLS connection. The function
// must return a RoundTripper that then handles the request.
- // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
+ // If TLSNextProto is not nil, HTTP/2 support is not enabled
+ // automatically.
TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
+ // ProxyConnectHeader optionally specifies headers to send to
+ // proxies during CONNECT requests.
+ ProxyConnectHeader Header
+
+ // MaxResponseHeaderBytes specifies a limit on how many
+ // response bytes are allowed in the server's response
+ // header.
+ //
+ // Zero means to use a default limit.
+ MaxResponseHeaderBytes int64
+
// nextProtoOnce guards initialization of TLSNextProto and
// h2transport (via onceSetNextProtoDefaults)
nextProtoOnce sync.Once
h2transport *http2Transport // non-nil if http2 wired up
- // TODO: tunable on global max cached connections
- // TODO: tunable on timeout on cached connections
// TODO: tunable on max per-host TCP dials in flight (Issue 13957)
}
@@ -167,25 +210,34 @@ 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 {
- // Unsupported in http2, so disable http2 for now.
- // Issue 13851.
+ 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)
if err != nil {
log.Printf("Error enabling Transport HTTP/2 support: %v", err)
- } else {
- t.h2transport = t2
+ return
+ }
+ t.h2transport = t2
+
+ // Auto-configure the http2.Transport's MaxHeaderListSize from
+ // the http.Transport's MaxResponseHeaderBytes. They don't
+ // exactly mean the same thing, but they're close.
+ //
+ // TODO: also add this to x/net/http2.Configure Transport, behind
+ // a +build go1.7 build tag:
+ if limit1 := t.MaxResponseHeaderBytes; limit1 != 0 && t2.MaxHeaderListSize == 0 {
+ const h2max = 1<<32 - 1
+ if limit1 >= h2max {
+ t2.MaxHeaderListSize = h2max
+ } else {
+ t2.MaxHeaderListSize = uint32(limit1)
+ }
}
}
@@ -212,6 +264,9 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) {
}
if proxy == "" {
proxy = httpProxyEnv.Get()
+ if proxy != "" && os.Getenv("REQUEST_METHOD") != "" {
+ return nil, errors.New("net/http: refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")
+ }
}
if proxy == "" {
return nil, nil
@@ -245,8 +300,9 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
// transportRequest is a wrapper around a *Request that adds
// optional extra headers to write.
type transportRequest struct {
- *Request // original request, not to be mutated
- extra Header // extra headers to write, or nil
+ *Request // original request, not to be mutated
+ extra Header // extra headers to write, or nil
+ trace *httptrace.ClientTrace // optional
}
func (tr *transportRequest) extraHeaders() Header {
@@ -262,6 +318,9 @@ func (tr *transportRequest) extraHeaders() Header {
// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
+ ctx := req.Context()
+ trace := httptrace.ContextClientTrace(ctx)
+
if req.URL == nil {
req.closeBody()
return nil, errors.New("http: nil Request.URL")
@@ -270,18 +329,30 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
req.closeBody()
return nil, errors.New("http: nil Request.Header")
}
- // TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex
- t.altMu.RLock()
- altRT := t.altProto[req.URL.Scheme]
- t.altMu.RUnlock()
- if altRT != nil {
+ scheme := req.URL.Scheme
+ isHTTP := scheme == "http" || scheme == "https"
+ if isHTTP {
+ for k, vv := range req.Header {
+ if !httplex.ValidHeaderFieldName(k) {
+ return nil, fmt.Errorf("net/http: invalid header field name %q", k)
+ }
+ for _, v := range vv {
+ if !httplex.ValidHeaderFieldValue(v) {
+ return nil, fmt.Errorf("net/http: invalid header field value %q for key %v", v, k)
+ }
+ }
+ }
+ }
+
+ altProto, _ := t.altProto.Load().(map[string]RoundTripper)
+ if altRT := altProto[scheme]; altRT != nil {
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
return resp, err
}
}
- if s := req.URL.Scheme; s != "http" && s != "https" {
+ if !isHTTP {
req.closeBody()
- return nil, &badStringError{"unsupported protocol scheme", s}
+ return nil, &badStringError{"unsupported protocol scheme", scheme}
}
if req.Method != "" && !validMethod(req.Method) {
return nil, fmt.Errorf("net/http: invalid method %q", req.Method)
@@ -293,7 +364,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
for {
// treq gets modified by roundTrip, so we need to recreate for each retry.
- treq := &transportRequest{Request: req}
+ treq := &transportRequest{Request: req, trace: trace}
cm, err := t.connectMethodForRequest(treq)
if err != nil {
req.closeBody()
@@ -302,9 +373,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
// Get the cached or newly-created connection to either the
// host (for http or https), the http proxy, or the http proxy
- // pre-CONNECTed to https server. In any case, we'll be ready
+ // pre-CONNECTed to https server. In any case, we'll be ready
// to send it requests.
- pconn, err := t.getConn(req, cm)
+ pconn, err := t.getConn(treq, cm)
if err != nil {
t.setReqCanceler(req, nil)
req.closeBody()
@@ -322,46 +393,65 @@ 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) {
+ // Issue 16465: return underlying net.Conn.Read error from peek,
+ // as we've historically done.
+ if e, ok := err.(transportReadFromServerError); ok {
+ err = e.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 err 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 == http2ErrNoCachedConn {
+ // Issue 16582: if the user started a bunch of
+ // requests at once, they can all pick the same conn
+ // and violate the server's max concurrent streams.
+ // Instead, match the HTTP/1 behavior for now and dial
+ // again to get a new TCP connection, rather than failing
+ // this request.
+ return true
}
- 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 err == errMissingHost {
+ // User error.
+ return false
}
- return err
+ 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
+ }
+ if _, ok := err.(nothingWrittenError); ok {
+ // We never wrote anything, so it's safe to retry.
+ return true
+ }
+ if !req.isReplayable() {
+ // Don't retry non-idempotent requests.
+ return false
+ }
+ if _, ok := err.(transportReadFromServerError); ok {
+ // We got some non-EOF net.Conn.Read failure reading
+ // the 1st response byte from the server.
+ return true
+ }
+ if err == errServerClosedIdle {
+ // The server replied with io.EOF while we were trying to
+ // read the response. Probably an unfortunately keep-alive
+ // timeout, just as the client was writing a request.
+ return true
+ }
+ return false // conservatively
}
// ErrSkipAltProtocol is a sentinel error value defined by Transport.RegisterProtocol.
@@ -380,13 +470,16 @@ var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol")
func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
t.altMu.Lock()
defer t.altMu.Unlock()
- if t.altProto == nil {
- t.altProto = make(map[string]RoundTripper)
- }
- if _, exists := t.altProto[scheme]; exists {
+ oldMap, _ := t.altProto.Load().(map[string]RoundTripper)
+ if _, exists := oldMap[scheme]; exists {
panic("protocol " + scheme + " already registered")
}
- t.altProto[scheme] = rt
+ newMap := make(map[string]RoundTripper)
+ for k, v := range oldMap {
+ newMap[k] = v
+ }
+ newMap[scheme] = rt
+ t.altProto.Store(newMap)
}
// CloseIdleConnections closes any connections which were previously
@@ -400,6 +493,7 @@ func (t *Transport) CloseIdleConnections() {
t.idleConn = nil
t.idleConnCh = nil
t.wantIdle = true
+ t.idleLRU = connLRU{}
t.idleMu.Unlock()
for _, conns := range m {
for _, pconn := range conns {
@@ -414,15 +508,21 @@ func (t *Transport) CloseIdleConnections() {
// CancelRequest cancels an in-flight request by closing its connection.
// CancelRequest should only be called after RoundTrip has returned.
//
-// Deprecated: Use Request.Cancel instead. CancelRequest can not cancel
-// HTTP/2 requests.
+// Deprecated: Use Request.WithContext to create a request with a
+// cancelable context instead. CancelRequest cannot cancel HTTP/2
+// requests.
func (t *Transport) CancelRequest(req *Request) {
+ t.cancelRequest(req, errRequestCanceled)
+}
+
+// Cancel an in-flight request, recording the error value.
+func (t *Transport) cancelRequest(req *Request, err error) {
t.reqMu.Lock()
cancel := t.reqCanceler[req]
delete(t.reqCanceler, req)
t.reqMu.Unlock()
if cancel != nil {
- cancel()
+ cancel(err)
}
}
@@ -472,10 +572,18 @@ func (e *envOnce) reset() {
}
func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+ if port := treq.URL.Port(); !validPort(port) {
+ return cm, fmt.Errorf("invalid URL port %q", port)
+ }
cm.targetScheme = treq.URL.Scheme
cm.targetAddr = canonicalAddr(treq.URL)
if t.Proxy != nil {
cm.proxyURL, err = t.Proxy(treq.Request)
+ if err == nil && cm.proxyURL != nil {
+ if port := cm.proxyURL.Port(); !validPort(port) {
+ return cm, fmt.Errorf("invalid proxy URL port %q", port)
+ }
+ }
}
return cm, err
}
@@ -500,17 +608,43 @@ var (
errConnBroken = errors.New("http: putIdleConn: connection is in bad state")
errWantIdle = errors.New("http: putIdleConn: CloseIdleConnections was called")
errTooManyIdle = errors.New("http: putIdleConn: too many idle connections")
+ 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")
+ errIdleConnTimeout = errors.New("http: idle connection timeout")
+ errNotCachingH2Conn = errors.New("http: not caching alternate protocol's connections")
)
+// transportReadFromServerError is used by Transport.readLoop when the
+// 1 byte peek read fails and we're actually anticipating a response.
+// Usually this is just due to the inherent keep-alive shut down race,
+// where the server closed the connection at the same time the client
+// wrote. The underlying err field is usually io.EOF or some
+// ECONNRESET sort of thing which varies by platform. But it might be
+// the user's custom net.Conn.Read error too, so we carry it along for
+// them to return from Transport.RoundTrip.
+type transportReadFromServerError struct {
+ err error
+}
+
+func (e transportReadFromServerError) Error() string {
+ return fmt.Sprintf("net/http: Transport failed to read from server: %v", e.err)
+}
+
func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
if err := t.tryPutIdleConn(pconn); err != nil {
pconn.close(err)
}
}
+func (t *Transport) maxIdleConnsPerHost() int {
+ if v := t.MaxIdleConnsPerHost; v != 0 {
+ return v
+ }
+ return DefaultMaxIdleConnsPerHost
+}
+
// tryPutIdleConn adds pconn to the list of idle persistent connections awaiting
// a new request.
// If pconn is no longer needed or not in a good state, tryPutIdleConn returns
@@ -523,13 +657,14 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
if pconn.isBroken() {
return errConnBroken
}
- key := pconn.cacheKey
- max := t.MaxIdleConnsPerHost
- if max == 0 {
- max = DefaultMaxIdleConnsPerHost
+ if pconn.alt != nil {
+ return errNotCachingH2Conn
}
pconn.markReused()
+ key := pconn.cacheKey
+
t.idleMu.Lock()
+ defer t.idleMu.Unlock()
waitingDialer := t.idleConnCh[key]
select {
@@ -537,9 +672,8 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
// We're done with this pconn and somebody else is
// currently waiting for a conn of this type (they're
// actively dialing, but this conn is ready
- // first). Chrome calls this socket late binding. See
+ // first). Chrome calls this socket late binding. See
// https://insouciant.org/tech/connection-management-in-chromium/
- t.idleMu.Unlock()
return nil
default:
if waitingDialer != nil {
@@ -549,23 +683,35 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
}
}
if t.wantIdle {
- t.idleMu.Unlock()
return errWantIdle
}
if t.idleConn == nil {
t.idleConn = make(map[connectMethodKey][]*persistConn)
}
- if len(t.idleConn[key]) >= max {
- t.idleMu.Unlock()
- return errTooManyIdle
+ idles := t.idleConn[key]
+ if len(idles) >= t.maxIdleConnsPerHost() {
+ return errTooManyIdleHost
}
- for _, exist := range t.idleConn[key] {
+ for _, exist := range idles {
if exist == pconn {
log.Fatalf("dup idle pconn %p in freelist", pconn)
}
}
- t.idleConn[key] = append(t.idleConn[key], pconn)
- t.idleMu.Unlock()
+ t.idleConn[key] = append(idles, pconn)
+ t.idleLRU.add(pconn)
+ if t.MaxIdleConns != 0 && t.idleLRU.len() > t.MaxIdleConns {
+ oldest := t.idleLRU.removeOldest()
+ oldest.close(errTooManyIdle)
+ t.removeIdleConnLocked(oldest)
+ }
+ if t.IdleConnTimeout > 0 {
+ if pconn.idleTimer != nil {
+ pconn.idleTimer.Reset(t.IdleConnTimeout)
+ } else {
+ pconn.idleTimer = time.AfterFunc(t.IdleConnTimeout, pconn.closeConnIfStillIdle)
+ }
+ }
+ pconn.idleAt = time.Now()
return nil
}
@@ -591,38 +737,84 @@ func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
return ch
}
-func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
+func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn, idleSince time.Time) {
key := cm.key()
t.idleMu.Lock()
defer t.idleMu.Unlock()
- if t.idleConn == nil {
- return nil
- }
for {
pconns, ok := t.idleConn[key]
if !ok {
- return nil
+ return nil, time.Time{}
}
if len(pconns) == 1 {
pconn = pconns[0]
delete(t.idleConn, key)
} else {
- // 2 or more cached connections; pop last
- // TODO: queue?
+ // 2 or more cached connections; use the most
+ // recently used one at the end.
pconn = pconns[len(pconns)-1]
t.idleConn[key] = pconns[:len(pconns)-1]
}
- if !pconn.isBroken() {
- return
+ t.idleLRU.remove(pconn)
+ if pconn.isBroken() {
+ // There is a tiny window where this is
+ // possible, between the connecting dying and
+ // the persistConn readLoop calling
+ // Transport.removeIdleConn. Just skip it and
+ // carry on.
+ continue
}
+ if pconn.idleTimer != nil && !pconn.idleTimer.Stop() {
+ // We picked this conn at the ~same time it
+ // was expiring and it's trying to close
+ // itself in another goroutine. Don't use it.
+ continue
+ }
+ return pconn, pconn.idleAt
}
}
-func (t *Transport) setReqCanceler(r *Request, fn func()) {
+// removeIdleConn marks pconn as dead.
+func (t *Transport) removeIdleConn(pconn *persistConn) {
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ t.removeIdleConnLocked(pconn)
+}
+
+// t.idleMu must be held.
+func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
+ if pconn.idleTimer != nil {
+ pconn.idleTimer.Stop()
+ }
+ t.idleLRU.remove(pconn)
+ key := pconn.cacheKey
+ pconns, _ := t.idleConn[key]
+ switch len(pconns) {
+ case 0:
+ // Nothing
+ case 1:
+ if pconns[0] == pconn {
+ delete(t.idleConn, key)
+ }
+ default:
+ for i, v := range pconns {
+ if v != pconn {
+ continue
+ }
+ // Slide down, keeping most recently-used
+ // conns at the end.
+ copy(pconns[i:], pconns[i+1:])
+ t.idleConn[key] = pconns[:len(pconns)-1]
+ break
+ }
+ }
+}
+
+func (t *Transport) setReqCanceler(r *Request, fn func(error)) {
t.reqMu.Lock()
defer t.reqMu.Unlock()
if t.reqCanceler == nil {
- t.reqCanceler = make(map[*Request]func())
+ t.reqCanceler = make(map[*Request]func(error))
}
if fn != nil {
t.reqCanceler[r] = fn
@@ -635,7 +827,7 @@ func (t *Transport) setReqCanceler(r *Request, fn func()) {
// for the request, we don't set the function and return false.
// Since CancelRequest will clear the canceler, we can use the return value to detect if
// the request was canceled since the last setReqCancel call.
-func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
+func (t *Transport) replaceReqCanceler(r *Request, fn func(error)) bool {
t.reqMu.Lock()
defer t.reqMu.Unlock()
_, ok := t.reqCanceler[r]
@@ -650,7 +842,12 @@ func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
return true
}
-func (t *Transport) dial(network, addr string) (net.Conn, error) {
+var zeroDialer net.Dialer
+
+func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) {
+ if t.DialContext != nil {
+ return t.DialContext(ctx, network, addr)
+ }
if t.Dial != nil {
c, err := t.Dial(network, addr)
if c == nil && err == nil {
@@ -658,19 +855,28 @@ func (t *Transport) dial(network, addr string) (net.Conn, error) {
}
return c, err
}
- return net.Dial(network, addr)
+ return zeroDialer.DialContext(ctx, network, addr)
}
// getConn dials and creates a new persistConn to the target as
-// specified in the connectMethod. This includes doing a proxy CONNECT
+// specified in the connectMethod. This includes doing a proxy CONNECT
// and/or setting up TLS. If this doesn't return an error, the persistConn
// is ready to write requests to.
-func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
- if pc := t.getIdleConn(cm); pc != nil {
+func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistConn, error) {
+ req := treq.Request
+ trace := treq.trace
+ ctx := req.Context()
+ if trace != nil && trace.GetConn != nil {
+ trace.GetConn(cm.addr())
+ }
+ if pc, idleSince := t.getIdleConn(cm); pc != nil {
+ if trace != nil && trace.GotConn != nil {
+ trace.GotConn(pc.gotIdleConnTrace(idleSince))
+ }
// set request canceler to some non-nil function so we
// can detect whether it was cleared between now and when
// we enter roundTrip
- t.setReqCanceler(req, func() {})
+ t.setReqCanceler(req, func(error) {})
return pc, nil
}
@@ -695,11 +901,11 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
}()
}
- cancelc := make(chan struct{})
- t.setReqCanceler(req, func() { close(cancelc) })
+ cancelc := make(chan error, 1)
+ t.setReqCanceler(req, func(err error) { cancelc <- err })
go func() {
- pc, err := t.dialConn(cm)
+ pc, err := t.dialConn(ctx, cm)
dialc <- dialRes{pc, err}
}()
@@ -707,7 +913,31 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
select {
case v := <-dialc:
// Our dial finished.
- return v.pc, v.err
+ if v.pc != nil {
+ if trace != nil && trace.GotConn != nil && v.pc.alt == nil {
+ trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
+ }
+ return v.pc, nil
+ }
+ // Our dial failed. See why to return a nicer error
+ // value.
+ select {
+ case <-req.Cancel:
+ // It was an error due to cancelation, so prioritize that
+ // error value. (Issue 16049)
+ return nil, errRequestCanceledConn
+ case <-req.Context().Done():
+ return nil, req.Context().Err()
+ case err := <-cancelc:
+ if err == errRequestCanceled {
+ err = errRequestCanceledConn
+ }
+ return nil, err
+ default:
+ // It wasn't an error due to cancelation, so
+ // return the original error message:
+ return nil, v.err
+ }
case pc := <-idleConnCh:
// Another request finished first and its net.Conn
// became available before our dial. Or somebody
@@ -715,25 +945,36 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
// But our dial is still going, so give it away
// when it finishes:
handlePendingDial()
+ if trace != nil && trace.GotConn != nil {
+ trace.GotConn(httptrace.GotConnInfo{Conn: pc.conn, Reused: pc.isReused()})
+ }
return pc, nil
case <-req.Cancel:
handlePendingDial()
return nil, errRequestCanceledConn
- case <-cancelc:
+ case <-req.Context().Done():
handlePendingDial()
- return nil, errRequestCanceledConn
+ return nil, req.Context().Err()
+ case err := <-cancelc:
+ handlePendingDial()
+ if err == errRequestCanceled {
+ err = errRequestCanceledConn
+ }
+ return nil, err
}
}
-func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
+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{}),
+ }
+ trace := httptrace.ContextClientTrace(ctx)
tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
if tlsDial {
var err error
@@ -747,18 +988,28 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
if tc, ok := pconn.conn.(*tls.Conn); ok {
// Handshake here, in case DialTLS didn't. TLSNextProto below
// depends on it for knowing the connection state.
+ if trace != nil && trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
if err := tc.Handshake(); err != nil {
go pconn.conn.Close()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tls.ConnectionState{}, err)
+ }
return nil, err
}
cs := tc.ConnectionState()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(cs, nil)
+ }
pconn.tlsState = &cs
}
} else {
- conn, err := t.dial("tcp", cm.addr())
+ conn, err := t.dial(ctx, "tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
- err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
+ // Return a typed error, per Issue 16997:
+ err = &net.OpError{Op: "proxyconnect", Net: "tcp", Err: err}
}
return nil, err
}
@@ -778,11 +1029,15 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
}
case cm.targetScheme == "https":
conn := pconn.conn
+ hdr := t.ProxyConnectHeader
+ if hdr == nil {
+ hdr = make(Header)
+ }
connectReq := &Request{
Method: "CONNECT",
URL: &url.URL{Opaque: cm.targetAddr},
Host: cm.targetAddr,
- Header: make(Header),
+ Header: hdr,
}
if pa := cm.proxyAuth(); pa != "" {
connectReq.Header.Set("Proxy-Authorization", pa)
@@ -807,7 +1062,7 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
if cm.targetScheme == "https" && !tlsDial {
// Initiate TLS and check remote host name against certificate.
- cfg := cloneTLSClientConfig(t.TLSClientConfig)
+ cfg := cloneTLSConfig(t.TLSClientConfig)
if cfg.ServerName == "" {
cfg.ServerName = cm.tlsHost()
}
@@ -821,6 +1076,9 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
})
}
go func() {
+ if trace != nil && trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
err := tlsConn.Handshake()
if timer != nil {
timer.Stop()
@@ -829,6 +1087,9 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
}()
if err := <-errc; err != nil {
plainConn.Close()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tls.ConnectionState{}, err)
+ }
return nil, err
}
if !cfg.InsecureSkipVerify {
@@ -838,6 +1099,9 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
}
}
cs := tlsConn.ConnectionState()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(cs, nil)
+ }
pconn.tlsState = &cs
pconn.conn = tlsConn
}
@@ -848,13 +1112,29 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
}
}
- pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
- pconn.bw = bufio.NewWriter(pconn.conn)
+ pconn.br = bufio.NewReader(pconn)
+ 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.
@@ -978,32 +1258,40 @@ func (k connectMethodKey) String() string {
// (but may be used for non-keep-alive requests as well)
type persistConn struct {
// alt optionally specifies the TLS NextProto RoundTripper.
- // This is used for HTTP/2 today and future protocol laters.
+ // This is used for HTTP/2 today and future protocols later.
// If it's non-nil, the rest of the fields are unused.
alt RoundTripper
- t *Transport
- cacheKey connectMethodKey
- conn net.Conn
- tlsState *tls.ConnectionState
- br *bufio.Reader // from conn
- sawEOF bool // whether we've seen EOF from conn; owned by readLoop
- bw *bufio.Writer // to conn
- 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
- isProxy bool
+ t *Transport
+ cacheKey connectMethodKey
+ conn net.Conn
+ 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
+ isProxy bool
+ sawEOF bool // whether we've seen EOF from conn; owned by readLoop
+ readLimit int64 // bytes allowed to be read; owned by readLoop
// writeErrCh passes the request write error (usually nil)
// from the writeLoop goroutine to the readLoop which passes
// it off to the res.Body reader, which then uses it to decide
// whether or not a connection can be reused. Issue 7569.
writeErrCh chan error
- lk sync.Mutex // guards following fields
+ 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
+
+ mu sync.Mutex // guards following fields
numExpectedResponses int
closed error // set non-nil when conn is closed, before closech is closed
+ canceledErr error // set non-nil if conn is canceled
broken bool // an error has happened on this connection; marked broken so it's not reused.
- canceled bool // whether this conn was broken due a CancelRequest
reused bool // whether conn has had successful request/response and is being reused.
// mutateHeaderFunc is an optional func to modify extra
// headers on each outbound request before it's written. (the
@@ -1011,45 +1299,161 @@ type persistConn struct {
mutateHeaderFunc func(Header)
}
+func (pc *persistConn) maxHeaderResponseSize() int64 {
+ if v := pc.t.MaxResponseHeaderBytes; v != 0 {
+ return v
+ }
+ return 10 << 20 // conservative default; same as http2
+}
+
+func (pc *persistConn) Read(p []byte) (n int, err error) {
+ if pc.readLimit <= 0 {
+ return 0, fmt.Errorf("read limit of %d bytes exhausted", pc.maxHeaderResponseSize())
+ }
+ if int64(len(p)) > pc.readLimit {
+ p = p[:pc.readLimit]
+ }
+ n, err = pc.conn.Read(p)
+ if err == io.EOF {
+ pc.sawEOF = true
+ }
+ pc.readLimit -= int64(n)
+ return
+}
+
// isBroken reports whether this connection is in a known broken state.
func (pc *persistConn) isBroken() bool {
- pc.lk.Lock()
- b := pc.broken
- pc.lk.Unlock()
+ pc.mu.Lock()
+ b := pc.closed != nil
+ pc.mu.Unlock()
return b
}
-// isCanceled reports whether this connection was closed due to CancelRequest.
-func (pc *persistConn) isCanceled() bool {
- pc.lk.Lock()
- defer pc.lk.Unlock()
- return pc.canceled
+// canceled returns non-nil if the connection was closed due to
+// CancelRequest or due to context cancelation.
+func (pc *persistConn) canceled() error {
+ pc.mu.Lock()
+ defer pc.mu.Unlock()
+ return pc.canceledErr
}
// isReused reports whether this connection is in a known broken state.
func (pc *persistConn) isReused() bool {
- pc.lk.Lock()
+ pc.mu.Lock()
r := pc.reused
- pc.lk.Unlock()
+ pc.mu.Unlock()
return r
}
-func (pc *persistConn) cancelRequest() {
- pc.lk.Lock()
- defer pc.lk.Unlock()
- pc.canceled = true
+func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnInfo) {
+ pc.mu.Lock()
+ defer pc.mu.Unlock()
+ t.Reused = pc.reused
+ t.Conn = pc.conn
+ t.WasIdle = true
+ if !idleAt.IsZero() {
+ t.IdleTime = time.Since(idleAt)
+ }
+ return
+}
+
+func (pc *persistConn) cancelRequest(err error) {
+ pc.mu.Lock()
+ defer pc.mu.Unlock()
+ pc.canceledErr = err
pc.closeLocked(errRequestCanceled)
}
+// closeConnIfStillIdle closes the connection if it's still sitting idle.
+// This is what's called by the persistConn's idleTimer, and is run in its
+// own goroutine.
+func (pc *persistConn) closeConnIfStillIdle() {
+ t := pc.t
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ if _, ok := t.idleLRU.m[pc]; !ok {
+ // Not idle.
+ return
+ }
+ t.removeIdleConnLocked(pc)
+ 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(req *Request, startBytesWritten int64, err error) (out error) {
+ if err == nil {
+ return nil
+ }
+ if err := pc.canceled(); err != nil {
+ return err
+ }
+ if err == errServerClosedIdle {
+ return err
+ }
+ if _, ok := err.(transportReadFromServerError); ok {
+ return err
+ }
+ if pc.isBroken() {
+ <-pc.writeLoopDone
+ if pc.nwrite == startBytesWritten && req.outgoingLength() == 0 {
+ 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(req *Request, startBytesWritten int64) error {
+ if err := pc.canceled(); err != nil {
+ return err
+ }
+ err := pc.closed
+ if err == errServerClosedIdle {
+ // Don't decorate
+ return err
+ }
+ if _, ok := err.(transportReadFromServerError); ok {
+ // 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 && req.outgoingLength() == 0 {
+ 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() { pc.close(closeErr) }()
+ defer func() {
+ pc.close(closeErr)
+ pc.t.removeIdleConn(pc)
+ }()
- tryPutIdleConn := func() bool {
+ tryPutIdleConn := func(trace *httptrace.ClientTrace) bool {
if err := pc.t.tryPutIdleConn(pc); err != nil {
closeErr = err
+ if trace != nil && trace.PutIdleConn != nil && err != errKeepAlivesDisabled {
+ trace.PutIdleConn(err)
+ }
return false
}
+ if trace != nil && trace.PutIdleConn != nil {
+ trace.PutIdleConn(nil)
+ }
return true
}
@@ -1066,27 +1470,33 @@ func (pc *persistConn) readLoop() {
alive := true
for alive {
+ pc.readLimit = pc.maxHeaderResponseSize()
_, err := pc.br.Peek(1)
- if err != nil {
- err = beforeRespHeaderError{err}
- }
- pc.lk.Lock()
+ pc.mu.Lock()
if pc.numExpectedResponses == 0 {
pc.readLoopPeekFailLocked(err)
- pc.lk.Unlock()
+ pc.mu.Unlock()
return
}
- pc.lk.Unlock()
+ pc.mu.Unlock()
rc := <-pc.reqch
+ trace := httptrace.ContextClientTrace(rc.req.Context())
var resp *Response
if err == nil {
- resp, err = pc.readResponse(rc)
+ resp, err = pc.readResponse(rc, trace)
+ } else {
+ err = transportReadFromServerError{err}
+ 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
@@ -1094,7 +1504,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 {
@@ -1104,10 +1514,11 @@ func (pc *persistConn) readLoop() {
}
return
}
+ pc.readLimit = maxInt64 // effictively no limit for response bodies
- pc.lk.Lock()
+ pc.mu.Lock()
pc.numExpectedResponses--
- pc.lk.Unlock()
+ pc.mu.Unlock()
hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
@@ -1130,7 +1541,7 @@ func (pc *persistConn) readLoop() {
alive = alive &&
!pc.sawEOF &&
pc.wroteRequest() &&
- tryPutIdleConn()
+ tryPutIdleConn(trace)
select {
case rc.ch <- responseAndError{res: resp}:
@@ -1145,25 +1556,35 @@ func (pc *persistConn) readLoop() {
continue
}
- if rc.addedGzip {
- maybeUngzipResponse(resp)
+ waitForBodyRead := make(chan bool, 2)
+ body := &bodyEOFSignal{
+ body: resp.Body,
+ earlyCloseFn: func() error {
+ waitForBodyRead <- false
+ return nil
+
+ },
+ fn: func(err error) error {
+ isEOF := err == io.EOF
+ waitForBodyRead <- isEOF
+ if isEOF {
+ <-eofc // see comment above eofc declaration
+ } else if err != nil {
+ if cerr := pc.canceled(); cerr != nil {
+ return cerr
+ }
+ }
+ return err
+ },
}
- resp.Body = &bodyEOFSignal{body: resp.Body}
- waitForBodyRead := make(chan bool, 2)
- resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
- waitForBodyRead <- false
- return nil
- }
- resp.Body.(*bodyEOFSignal).fn = func(err error) error {
- isEOF := err == io.EOF
- waitForBodyRead <- isEOF
- if isEOF {
- <-eofc // see comment above eofc declaration
- } else if err != nil && pc.isCanceled() {
- return errRequestCanceled
- }
- return err
+ resp.Body = body
+ if rc.addedGzip && resp.Header.Get("Content-Encoding") == "gzip" {
+ resp.Body = &gzipReader{body: body}
+ resp.Header.Del("Content-Encoding")
+ resp.Header.Del("Content-Length")
+ resp.ContentLength = -1
+ resp.Uncompressed = true
}
select {
@@ -1182,13 +1603,16 @@ func (pc *persistConn) readLoop() {
bodyEOF &&
!pc.sawEOF &&
pc.wroteRequest() &&
- tryPutIdleConn()
+ tryPutIdleConn(trace)
if bodyEOF {
eofc <- struct{}{}
}
case <-rc.req.Cancel:
alive = false
pc.t.CancelRequest(rc.req)
+ case <-rc.req.Context().Done():
+ alive = false
+ pc.t.cancelRequest(rc.req, rc.req.Context().Err())
case <-pc.closech:
alive = false
}
@@ -1197,15 +1621,6 @@ func (pc *persistConn) readLoop() {
}
}
-func maybeUngzipResponse(resp *Response) {
- if resp.Header.Get("Content-Encoding") == "gzip" {
- resp.Header.Del("Content-Encoding")
- resp.Header.Del("Content-Length")
- resp.ContentLength = -1
- resp.Body = &gzipReader{body: resp.Body}
- }
-}
-
func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
if pc.closed != nil {
return
@@ -1224,19 +1639,29 @@ func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
// readResponse reads an HTTP response (or two, in the case of "Expect:
// 100-continue") from the server. It returns the final non-100 one.
-func (pc *persistConn) readResponse(rc requestAndChan) (resp *Response, err error) {
+// trace is optional.
+func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTrace) (resp *Response, err error) {
+ if trace != nil && trace.GotFirstResponseByte != nil {
+ if peek, err := pc.br.Peek(1); err == nil && len(peek) == 1 {
+ trace.GotFirstResponseByte()
+ }
+ }
resp, err = ReadResponse(pc.br, rc.req)
if err != nil {
return
}
if rc.continueCh != nil {
if resp.StatusCode == 100 {
+ if trace != nil && trace.Got100Continue != nil {
+ trace.Got100Continue()
+ }
rc.continueCh <- struct{}{}
} else {
close(rc.continueCh)
}
}
if resp.StatusCode == 100 {
+ pc.readLimit = pc.maxHeaderResponseSize() // reset the limit
resp, err = ReadResponse(pc.br, rc.req)
if err != nil {
return
@@ -1268,24 +1693,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 && wr.req.outgoingLength() == 0 {
+ 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
}
@@ -1331,9 +1765,9 @@ type requestAndChan struct {
req *Request
ch chan responseAndError // unbuffered; always send in select on callerGone
- // did the Transport (as opposed to the client code) add an
- // Accept-Encoding gzip header? only if it we set it do
- // we transparently decode the gzip.
+ // whether the Transport (as opposed to the user client code)
+ // added the Accept-Encoding gzip header. If the Transport
+ // set it, only then do we transparently decode the gzip.
addedGzip bool
// Optional blocking chan for Expect: 100-continue (for send).
@@ -1353,7 +1787,7 @@ type writeRequest struct {
req *transportRequest
ch chan<- error
- // Optional blocking chan for Expect: 100-continue (for recieve).
+ // Optional blocking chan for Expect: 100-continue (for receive).
// If not nil, writeLoop blocks sending request body until
// it receives from this chan.
continueCh <-chan struct{}
@@ -1369,7 +1803,6 @@ func (e *httpError) Timeout() bool { return e.timeout }
func (e *httpError) Temporary() bool { return true }
var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
-var errClosed error = &httpError{err: "net/http: server closed connection before response was received"}
var errRequestCanceled = errors.New("net/http: request canceled")
var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection") // TODO: unify?
@@ -1387,22 +1820,16 @@ 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) {
pc.t.putOrCloseIdleConn(pc)
return nil, errRequestCanceled
}
- pc.lk.Lock()
+ pc.mu.Lock()
pc.numExpectedResponses++
headerFn := pc.mutateHeaderFunc
- pc.lk.Unlock()
+ pc.mu.Unlock()
if headerFn != nil {
headerFn(req.extraHeaders())
@@ -1448,6 +1875,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}
@@ -1463,16 +1891,17 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
var re responseAndError
var respHeaderTimer <-chan time.Time
cancelChan := req.Request.Cancel
+ ctxDoneChan := req.Context().Done()
WaitResponse:
for {
testHookWaitResLoop()
select {
case err := <-writeErrCh:
if err != nil {
- if pc.isCanceled() {
- err = errRequestCanceled
+ if cerr := pc.canceled(); cerr != nil {
+ err = cerr
}
- re = responseAndError{err: beforeRespHeaderError{err}}
+ re = responseAndError{err: err}
pc.close(fmt.Errorf("write error: %v", err))
break WaitResponse
}
@@ -1482,26 +1911,22 @@ 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(req.Request, 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(req.Request, startBytesWritten, re.err)
break WaitResponse
case <-cancelChan:
pc.t.CancelRequest(req.Request)
cancelChan = nil
+ case <-ctxDoneChan:
+ pc.t.cancelRequest(req.Request, req.Context().Err())
+ cancelChan = nil
+ ctxDoneChan = nil
}
}
@@ -1514,21 +1939,12 @@ 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.lk.Lock()
- defer pc.lk.Unlock()
- pc.broken = true
-}
-
// markReused marks this connection as having been successfully used for a
// request and response.
func (pc *persistConn) markReused() {
- pc.lk.Lock()
+ pc.mu.Lock()
pc.reused = true
- pc.lk.Unlock()
+ pc.mu.Unlock()
}
// close closes the underlying TCP connection and closes
@@ -1537,8 +1953,8 @@ func (pc *persistConn) markReused() {
// The provided err is only for testing and debugging; in normal
// circumstances it should never be seen by users.
func (pc *persistConn) close(err error) {
- pc.lk.Lock()
- defer pc.lk.Unlock()
+ pc.mu.Lock()
+ defer pc.mu.Unlock()
pc.closeLocked(err)
}
@@ -1554,7 +1970,7 @@ func (pc *persistConn) closeLocked(err error) {
// handlePendingDial's putOrCloseIdleConn when
// it turns out the abandoned connection in
// flight ended up negotiating an alternate
- // protocol. We don't use the connection
+ // protocol. We don't use the connection
// freelist for http2. That's done by the
// alternate protocol's RoundTripper.
} else {
@@ -1572,14 +1988,22 @@ var portMap = map[string]string{
// canonicalAddr returns url.Host but always with a ":port" suffix
func canonicalAddr(url *url.URL) string {
- addr := url.Host
- if !hasPort(addr) {
- return addr + ":" + portMap[url.Scheme]
+ addr := url.Hostname()
+ if v, err := idnaASCII(addr); err == nil {
+ addr = v
+ }
+ port := url.Port()
+ if port == "" {
+ port = portMap[url.Scheme]
}
- return addr
+ return net.JoinHostPort(addr, port)
}
-// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
+// bodyEOFSignal is used by the HTTP/1 transport when reading response
+// bodies to make sure we see the end of a response body before
+// proceeding and reading on the connection again.
+//
+// It wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before its final (error-producing) Read or Close call
// returns. fn should return the new error to return from Read or Close.
//
@@ -1595,12 +2019,14 @@ type bodyEOFSignal struct {
earlyCloseFn func() error // optional alt Close func used if io.EOF not seen
}
+var errReadOnClosedResBody = errors.New("http: read on closed response body")
+
func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
es.mu.Lock()
closed, rerr := es.closed, es.rerr
es.mu.Unlock()
if closed {
- return 0, errors.New("http: read on closed response body")
+ return 0, errReadOnClosedResBody
}
if rerr != nil {
return 0, rerr
@@ -1645,17 +2071,30 @@ func (es *bodyEOFSignal) condfn(err error) error {
// gzipReader wraps a response body so it can lazily
// call gzip.NewReader on the first call to Read
type gzipReader struct {
- body io.ReadCloser // underlying Response.Body
- zr io.Reader // lazily-initialized gzip reader
+ body *bodyEOFSignal // underlying HTTP/1 response body framing
+ zr *gzip.Reader // lazily-initialized gzip reader
+ zerr error // any error from gzip.NewReader; sticky
}
func (gz *gzipReader) Read(p []byte) (n int, err error) {
if gz.zr == nil {
- gz.zr, err = gzip.NewReader(gz.body)
- if err != nil {
- return 0, err
+ if gz.zerr == nil {
+ gz.zr, gz.zerr = gzip.NewReader(gz.body)
+ }
+ if gz.zerr != nil {
+ return 0, gz.zerr
}
}
+
+ gz.body.mu.Lock()
+ if gz.body.closed {
+ err = errReadOnClosedResBody
+ }
+ gz.body.mu.Unlock()
+
+ if err != nil {
+ return 0, err
+ }
return gz.zr.Read(p)
}
@@ -1674,19 +2113,6 @@ func (tlsHandshakeTimeoutError) Timeout() bool { return true }
func (tlsHandshakeTimeoutError) Temporary() bool { return true }
func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
-type noteEOFReader struct {
- r io.Reader
- sawEOF *bool
-}
-
-func (nr noteEOFReader) Read(p []byte) (n int, err error) {
- n, err = nr.r.Read(p)
- if err == io.EOF {
- *nr.sawEOF = true
- }
- return
-}
-
// fakeLocker is a sync.Locker which does nothing. It's used to guard
// test-only fields when not under test, to avoid runtime atomic
// overhead.
@@ -1695,80 +2121,63 @@ type fakeLocker struct{}
func (fakeLocker) Lock() {}
func (fakeLocker) Unlock() {}
-func isNetWriteError(err error) bool {
- switch e := err.(type) {
- case *url.Error:
- return isNetWriteError(e.Err)
- case *net.OpError:
- return e.Op == "write"
- default:
- return false
- }
-}
-
-// cloneTLSConfig returns a shallow clone of the exported
-// fields of cfg, ignoring the unexported sync.Once, which
-// contains a mutex and must not be copied.
-//
-// The cfg must not be in active use by tls.Server, or else
-// there can still be a race with tls.Server updating SessionTicketKey
-// and our copying it, and also a race with the server setting
-// SessionTicketsDisabled=false on failure to set the random
-// ticket key.
-//
-// If cfg is nil, a new zero tls.Config is returned.
+// clneTLSConfig returns a shallow clone of cfg, or a new zero tls.Config if
+// cfg is nil. This is safe to call even if cfg is in active use by a TLS
+// client or server.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
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,
- }
-}
-
-// cloneTLSClientConfig is like cloneTLSConfig but omits
-// the fields SessionTicketsDisabled and SessionTicketKey.
-// This makes it safe to call cloneTLSClientConfig on a config
-// in active use by a server.
-func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
- if cfg == nil {
- return &tls.Config{}
+ return cfg.Clone()
+}
+
+type connLRU struct {
+ ll *list.List // list.Element.Value type is of *persistConn
+ m map[*persistConn]*list.Element
+}
+
+// add adds pc to the head of the linked list.
+func (cl *connLRU) add(pc *persistConn) {
+ if cl.ll == nil {
+ cl.ll = list.New()
+ cl.m = make(map[*persistConn]*list.Element)
}
- 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,
+ ele := cl.ll.PushFront(pc)
+ if _, ok := cl.m[pc]; ok {
+ panic("persistConn was already in LRU")
+ }
+ cl.m[pc] = ele
+}
+
+func (cl *connLRU) removeOldest() *persistConn {
+ ele := cl.ll.Back()
+ pc := ele.Value.(*persistConn)
+ cl.ll.Remove(ele)
+ delete(cl.m, pc)
+ return pc
+}
+
+// remove removes pc from cl.
+func (cl *connLRU) remove(pc *persistConn) {
+ if ele, ok := cl.m[pc]; ok {
+ cl.ll.Remove(ele)
+ delete(cl.m, pc)
}
}
+
+// len returns the number of items in the cache.
+func (cl *connLRU) len() int {
+ return len(cl.m)
+}
+
+// validPort reports whether p (without the colon) is a valid port in
+// a URL, per RFC 3986 Section 3.2.3, which says the port may be
+// empty, or only contain digits.
+func validPort(p string) bool {
+ for _, r := range []byte(p) {
+ if r < '0' || r > '9' {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/net/http/transport_internal_test.go b/libgo/go/net/http/transport_internal_test.go
new file mode 100644
index 0000000000..3d24fc127d
--- /dev/null
+++ b/libgo/go/net/http/transport_internal_test.go
@@ -0,0 +1,141 @@
+// 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 !isTransportReadFromServerError(err) && err != errServerClosedIdle {
+ t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+ }
+
+ <-pc.closech
+ err = pc.closed
+ if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
+ t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+ }
+}
+
+func isTransportReadFromServerError(err error) bool {
+ _, ok := err.(transportReadFromServerError)
+ return ok
+}
+
+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
+}
+
+func dummyRequest(method string) *Request {
+ req, err := NewRequest(method, "http://fake.tld/", nil)
+ if err != nil {
+ panic(err)
+ }
+ return req
+}
+
+func TestTransportShouldRetryRequest(t *testing.T) {
+ tests := []struct {
+ pc *persistConn
+ req *Request
+
+ err error
+ want bool
+ }{
+ 0: {
+ pc: &persistConn{reused: false},
+ req: dummyRequest("POST"),
+ err: nothingWrittenError{},
+ want: false,
+ },
+ 1: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: nothingWrittenError{},
+ want: true,
+ },
+ 2: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: http2ErrNoCachedConn,
+ want: true,
+ },
+ 3: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: errMissingHost,
+ want: false,
+ },
+ 4: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: transportReadFromServerError{},
+ want: false,
+ },
+ 5: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("GET"),
+ err: transportReadFromServerError{},
+ want: true,
+ },
+ 6: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("GET"),
+ err: errServerClosedIdle,
+ want: true,
+ },
+ }
+ for i, tt := range tests {
+ got := tt.pc.shouldRetryRequest(tt.req, tt.err)
+ if got != tt.want {
+ t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index 0c901b30a4..a58b1839cc 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -13,16 +13,20 @@ import (
"bufio"
"bytes"
"compress/gzip"
+ "context"
"crypto/rand"
"crypto/tls"
"errors"
"fmt"
+ "internal/nettrace"
+ "internal/testenv"
"io"
"io/ioutil"
"log"
"net"
. "net/http"
"net/http/httptest"
+ "net/http/httptrace"
"net/http/httputil"
"net/http/internal"
"net/url"
@@ -32,6 +36,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -379,8 +384,8 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
}
}))
defer ts.Close()
- maxIdleConns := 2
- tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
+ maxIdleConnsPerHost := 2
+ tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConnsPerHost}
c := &Client{Transport: tr}
// Start 3 outstanding requests and wait for the server to get them.
@@ -425,14 +430,63 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
resch <- "res2"
<-donech
- if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
- t.Errorf("after second response, expected %d idle conns; got %d", e, g)
+ if g, w := tr.IdleConnCountForTesting(cacheKey), 2; g != w {
+ t.Errorf("after second response, idle conns = %d; want %d", g, w)
}
resch <- "res3"
<-donech
- if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
- t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
+ if g, w := tr.IdleConnCountForTesting(cacheKey), maxIdleConnsPerHost; g != w {
+ t.Errorf("after third response, idle conns = %d; want %d", g, w)
+ }
+}
+
+func TestTransportRemovesDeadIdleConnections(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ doReq := func(name string) string {
+ // Do a POST instead of a GET to prevent the Transport's
+ // idempotent request retry logic from kicking in...
+ res, err := c.Post(ts.URL, "", nil)
+ if err != nil {
+ t.Fatalf("%s: %v", name, err)
+ }
+ if res.StatusCode != 200 {
+ t.Fatalf("%s: %v", name, res.Status)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("%s: %v", name, err)
+ }
+ return string(slurp)
+ }
+
+ first := doReq("first")
+ keys1 := tr.IdleConnKeysForTesting()
+
+ ts.CloseClientConnections()
+
+ var keys2 []string
+ if !waitCondition(3*time.Second, 50*time.Millisecond, func() bool {
+ keys2 = tr.IdleConnKeysForTesting()
+ return len(keys2) == 0
+ }) {
+ t.Fatalf("Transport didn't notice idle connection's death.\nbefore: %q\n after: %q\n", keys1, keys2)
+ }
+
+ second := doReq("second")
+ if first == second {
+ t.Errorf("expected a different connection between requests. got %q both times", first)
}
}
@@ -478,7 +532,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
// This test has an expected race. Sleeping for 25 ms prevents
// it on most fast machines, causing the next fetch() call to
- // succeed quickly. But if we do get errors, fetch() will retry 5
+ // succeed quickly. But if we do get errors, fetch() will retry 5
// times with some delays between.
time.Sleep(25 * time.Millisecond)
@@ -518,7 +572,7 @@ func TestStressSurpriseServerCloses(t *testing.T) {
// after each request completes, regardless of whether it failed.
// If these are too high, OS X exhausts its ephemeral ports
// and hangs waiting for them to transition TCP states. That's
- // not what we want to test. TODO(bradfitz): use an io.Pipe
+ // not what we want to test. TODO(bradfitz): use an io.Pipe
// dialer for this test instead?
const (
numClients = 20
@@ -645,6 +699,7 @@ var roundTripTests = []struct {
// Test that the modification made to the Request by the RoundTripper is cleaned up
func TestRoundTripGzip(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const responseBody = "test response body"
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -703,6 +758,7 @@ func TestRoundTripGzip(t *testing.T) {
}
func TestTransportGzip(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const nRandBytes = 1024 * 1024
@@ -801,6 +857,7 @@ func TestTransportGzip(t *testing.T) {
// If a request has Expect:100-continue header, the request blocks sending body until the first response.
// Premature consumption of the request body should not be occurred.
func TestTransportExpect100Continue(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -853,7 +910,7 @@ func TestTransportExpect100Continue(t *testing.T) {
{path: "/100", body: []byte("hello"), sent: 5, status: 200}, // Got 100 followed by 200, entire body is sent.
{path: "/200", body: []byte("hello"), sent: 0, status: 200}, // Got 200 without 100. body isn't sent.
{path: "/500", body: []byte("hello"), sent: 0, status: 500}, // Got 500 without 100. body isn't sent.
- {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Althogh without Connection:close, body isn't sent.
+ {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent.
{path: "/timeout", body: []byte("hello"), sent: 5, status: 200}, // Timeout exceeded and entire body is sent.
}
@@ -911,6 +968,48 @@ func TestTransportProxy(t *testing.T) {
}
}
+// Issue 16997: test transport dial preserves typed errors
+func TestTransportDialPreservesNetOpProxyError(t *testing.T) {
+ defer afterTest(t)
+
+ var errDial = errors.New("some dial error")
+
+ tr := &Transport{
+ Proxy: func(*Request) (*url.URL, error) {
+ return url.Parse("http://proxy.fake.tld/")
+ },
+ Dial: func(string, string) (net.Conn, error) {
+ return nil, errDial
+ },
+ }
+ defer tr.CloseIdleConnections()
+
+ c := &Client{Transport: tr}
+ req, _ := NewRequest("GET", "http://fake.tld", nil)
+ res, err := c.Do(req)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("wanted a non-nil error")
+ }
+
+ uerr, ok := err.(*url.Error)
+ if !ok {
+ t.Fatalf("got %T, want *url.Error", err)
+ }
+ oe, ok := uerr.Err.(*net.OpError)
+ if !ok {
+ t.Fatalf("url.Error.Err = %T; want *net.OpError", uerr.Err)
+ }
+ want := &net.OpError{
+ Op: "proxyconnect",
+ Net: "tcp",
+ Err: errDial, // original error, unwrapped.
+ }
+ if !reflect.DeepEqual(oe, want) {
+ t.Errorf("Got error %#v; want %#v", oe, want)
+ }
+}
+
// TestTransportGzipRecursive sends a gzip quine and checks that the
// client gets the same value back. This is more cute than anything,
// but checks that we don't recurse forever, and checks that
@@ -923,7 +1022,9 @@ func TestTransportGzipRecursive(t *testing.T) {
}))
defer ts.Close()
- c := &Client{Transport: &Transport{}}
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
res, err := c.Get(ts.URL)
if err != nil {
t.Fatal(err)
@@ -968,12 +1069,25 @@ func TestTransportGzipShort(t *testing.T) {
}
}
+// Wait until number of goroutines is no greater than nmax, or time out.
+func waitNumGoroutine(nmax int) int {
+ nfinal := runtime.NumGoroutine()
+ for ntries := 10; ntries > 0 && nfinal > nmax; ntries-- {
+ time.Sleep(50 * time.Millisecond)
+ runtime.GC()
+ nfinal = runtime.NumGoroutine()
+ }
+ return nfinal
+}
+
// tests that persistent goroutine connections shut down when no longer desired.
func TestTransportPersistConnLeak(t *testing.T) {
- setParallel(t)
+ // Not parallel: counts goroutines
defer afterTest(t)
- gotReqCh := make(chan bool)
- unblockCh := make(chan bool)
+
+ const numReq = 25
+ gotReqCh := make(chan bool, numReq)
+ unblockCh := make(chan bool, numReq)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
gotReqCh <- true
<-unblockCh
@@ -987,14 +1101,15 @@ func TestTransportPersistConnLeak(t *testing.T) {
n0 := runtime.NumGoroutine()
- const numReq = 25
- didReqCh := make(chan bool)
+ didReqCh := make(chan bool, numReq)
+ failed := make(chan bool, numReq)
for i := 0; i < numReq; i++ {
go func() {
res, err := c.Get(ts.URL)
didReqCh <- true
if err != nil {
t.Errorf("client fetch error: %v", err)
+ failed <- true
return
}
res.Body.Close()
@@ -1003,7 +1118,13 @@ func TestTransportPersistConnLeak(t *testing.T) {
// Wait for all goroutines to be stuck in the Handler.
for i := 0; i < numReq; i++ {
- <-gotReqCh
+ select {
+ case <-gotReqCh:
+ // ok
+ case <-failed:
+ close(unblockCh)
+ return
+ }
}
nhigh := runtime.NumGoroutine()
@@ -1019,14 +1140,11 @@ func TestTransportPersistConnLeak(t *testing.T) {
}
tr.CloseIdleConnections()
- time.Sleep(100 * time.Millisecond)
- runtime.GC()
- runtime.GC() // even more.
- nfinal := runtime.NumGoroutine()
+ nfinal := waitNumGoroutine(n0 + 5)
growth := nfinal - n0
- // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
+ // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
// Previously we were leaking one per numReq.
if int(growth) > 5 {
t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
@@ -1037,7 +1155,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
- setParallel(t)
+ // Not parallel: measures goroutines.
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
@@ -1061,13 +1179,11 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
}
nhigh := runtime.NumGoroutine()
tr.CloseIdleConnections()
- time.Sleep(400 * time.Millisecond)
- runtime.GC()
- nfinal := runtime.NumGoroutine()
+ nfinal := waitNumGoroutine(n0 + 5)
growth := nfinal - n0
- // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
+ // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
// Previously we were leaking one per numReq.
t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
if int(growth) > 5 {
@@ -1103,8 +1219,8 @@ func TestTransportIdleConnCrash(t *testing.T) {
}
// Test that the transport doesn't close the TCP connection early,
-// before the response body has been read. This was a regression
-// which sadly lacked a triggering test. The large response body made
+// before the response body has been read. This was a regression
+// which sadly lacked a triggering test. The large response body made
// the old race easier to trigger.
func TestIssue3644(t *testing.T) {
defer afterTest(t)
@@ -1135,6 +1251,7 @@ func TestIssue3644(t *testing.T) {
// Test that a client receives a server's reply, even if the server doesn't read
// the entire request body.
func TestIssue3595(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const deniedMsg = "sorry, denied."
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1183,6 +1300,7 @@ func TestChunkedNoContent(t *testing.T) {
}
func TestTransportConcurrency(t *testing.T) {
+ // Not parallel: uses global test hooks.
defer afterTest(t)
maxProcs, numReqs := 16, 500
if testing.Short() {
@@ -1199,7 +1317,7 @@ func TestTransportConcurrency(t *testing.T) {
// Due to the Transport's "socket late binding" (see
// idleConnCh in transport.go), the numReqs HTTP requests
- // below can finish with a dial still outstanding. To keep
+ // below can finish with a dial still outstanding. To keep
// the leak checker happy, keep track of pending dials and
// wait for them to finish (and be closed or returned to the
// idle pool) before we close idle connections.
@@ -1243,9 +1361,7 @@ func TestTransportConcurrency(t *testing.T) {
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1307,9 +1423,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1617,7 +1731,13 @@ func TestCancelRequestWithChannel(t *testing.T) {
}
}
-func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
+func TestCancelRequestWithChannelBeforeDo_Cancel(t *testing.T) {
+ testCancelRequestWithChannelBeforeDo(t, false)
+}
+func TestCancelRequestWithChannelBeforeDo_Context(t *testing.T) {
+ testCancelRequestWithChannelBeforeDo(t, true)
+}
+func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
setParallel(t)
defer afterTest(t)
unblockc := make(chan bool)
@@ -1627,24 +1747,33 @@ func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
defer ts.Close()
defer close(unblockc)
- // Don't interfere with the next test on plan9.
- // Cf. https://golang.org/issues/11476
- if runtime.GOOS == "plan9" {
- defer time.Sleep(500 * time.Millisecond)
- }
-
tr := &Transport{}
defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
req, _ := NewRequest("GET", ts.URL, nil)
- ch := make(chan struct{})
- req.Cancel = ch
- close(ch)
+ if withCtx {
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ req = req.WithContext(ctx)
+ } else {
+ ch := make(chan struct{})
+ req.Cancel = ch
+ close(ch)
+ }
_, err := c.Do(req)
- if err == nil || !strings.Contains(err.Error(), "canceled") {
- t.Errorf("Do error = %v; want cancelation", err)
+ if ue, ok := err.(*url.Error); ok {
+ err = ue.Err
+ }
+ if withCtx {
+ if err != context.Canceled {
+ t.Errorf("Do error = %v; want %v", err, context.Canceled)
+ }
+ } else {
+ if err == nil || !strings.Contains(err.Error(), "canceled") {
+ t.Errorf("Do error = %v; want cancelation", err)
+ }
}
}
@@ -1813,6 +1942,7 @@ func TestTransportEmptyMethod(t *testing.T) {
}
func TestTransportSocketLateBinding(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
mux := NewServeMux()
@@ -1985,7 +2115,8 @@ type proxyFromEnvTest struct {
env string // HTTP_PROXY
httpsenv string // HTTPS_PROXY
- noenv string // NO_RPXY
+ noenv string // NO_PROXY
+ reqmeth string // REQUEST_METHOD
want string
wanterr error
@@ -2009,6 +2140,10 @@ func (t proxyFromEnvTest) String() string {
space()
fmt.Fprintf(&buf, "no_proxy=%q", t.noenv)
}
+ if t.reqmeth != "" {
+ space()
+ fmt.Fprintf(&buf, "request_method=%q", t.reqmeth)
+ }
req := "http://example.com"
if t.req != "" {
req = t.req
@@ -2032,6 +2167,12 @@ var proxyFromEnvTests = []proxyFromEnvTest{
{req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"},
{req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"},
+ // Issue 16405: don't use HTTP_PROXY in a CGI environment,
+ // where HTTP_PROXY can be attacker-controlled.
+ {env: "http://10.1.2.3:8080", reqmeth: "POST",
+ want: "<nil>",
+ wanterr: errors.New("net/http: refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")},
+
{want: "<nil>"},
{noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
@@ -2047,6 +2188,7 @@ func TestProxyFromEnvironment(t *testing.T) {
os.Setenv("HTTP_PROXY", tt.env)
os.Setenv("HTTPS_PROXY", tt.httpsenv)
os.Setenv("NO_PROXY", tt.noenv)
+ os.Setenv("REQUEST_METHOD", tt.reqmeth)
ResetCachedEnvironment()
reqURL := tt.req
if reqURL == "" {
@@ -2065,6 +2207,7 @@ func TestProxyFromEnvironment(t *testing.T) {
}
func TestIdleConnChannelLeak(t *testing.T) {
+ // Not parallel: uses global test hooks.
var mu sync.Mutex
var n int
@@ -2208,7 +2351,7 @@ func TestTransportTLSHandshakeTimeout(t *testing.T) {
// Trying to repro golang.org/issue/3514
func TestTLSServerClosesConnection(t *testing.T) {
defer afterTest(t)
- setFlaky(t, 7634)
+ testenv.SkipFlaky(t, 7634)
closedc := make(chan bool, 1)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2273,7 +2416,7 @@ func TestTLSServerClosesConnection(t *testing.T) {
}
// byteFromChanReader is an io.Reader that reads a single byte at a
-// time from the channel. When the channel is closed, the reader
+// time from the channel. When the channel is closed, the reader
// returns io.EOF.
type byteFromChanReader chan byte
@@ -2296,6 +2439,7 @@ func (c byteFromChanReader) Read(p []byte) (n int, err error) {
// questionable state.
// golang.org/issue/7569
func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var sconn struct {
sync.Mutex
@@ -2398,98 +2542,101 @@ type errorReader struct {
func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
-type plan9SleepReader struct{}
-
-func (plan9SleepReader) Read(p []byte) (int, error) {
- if runtime.GOOS == "plan9" {
- // After the fix to unblock TCP Reads in
- // https://golang.org/cl/15941, this sleep is required
- // on plan9 to make sure TCP Writes before an
- // immediate TCP close go out on the wire. On Plan 9,
- // it seems that a hangup of a TCP connection with
- // queued data doesn't send the queued data first.
- // https://golang.org/issue/9554
- time.Sleep(50 * time.Millisecond)
- }
- return 0, io.EOF
-}
-
type closerFunc func() error
func (f closerFunc) Close() error { return f() }
+type writerFuncConn struct {
+ net.Conn
+ write func(p []byte) (n int, err error)
+}
+
+func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) }
+
// Issue 4677. 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.
//
// NOTE: we resend a request only if the request is idempotent, we reused a
-// keep-alive connection, and we haven't yet received any header data. This
+// keep-alive connection, and we haven't yet received any header data. This
// automatically prevents an infinite resend loop because we'll run out of the
// cached keep-alive connections eventually.
func TestRetryIdempotentRequestsOnError(t *testing.T) {
defer afterTest(t)
+ var (
+ mu sync.Mutex
+ logbuf bytes.Buffer
+ )
+ logf := func(format string, args ...interface{}) {
+ mu.Lock()
+ defer mu.Unlock()
+ fmt.Fprintf(&logbuf, format, args...)
+ logbuf.WriteByte('\n')
+ }
+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ logf("Handler")
+ w.Header().Set("X-Status", "ok")
}))
defer ts.Close()
- tr := &Transport{}
+ var writeNumAtomic int32
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ logf("Dial")
+ c, err := net.Dial(network, ts.Listener.Addr().String())
+ if err != nil {
+ logf("Dial error: %v", err)
+ return nil, err
+ }
+ return &writerFuncConn{
+ Conn: c,
+ write: func(p []byte) (n int, err error) {
+ if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
+ logf("intentional write failure")
+ return 0, errors.New("second write fails")
+ }
+ logf("Write(%q)", p)
+ return c.Write(p)
+ },
+ }, nil
+ },
+ }
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
- const N = 2
- retryc := make(chan struct{}, N)
SetRoundTripRetried(func() {
- retryc <- struct{}{}
+ logf("Retried.")
})
defer SetRoundTripRetried(nil)
- for n := 0; n < 100; n++ {
- // open 2 conns
- errc := make(chan error, N)
- for i := 0; i < N; i++ {
- // start goroutines, send on errc
- go func() {
- res, err := c.Get(ts.URL)
- if err == nil {
- res.Body.Close()
- }
- errc <- err
- }()
- }
- for i := 0; i < N; i++ {
- if err := <-errc; err != nil {
- t.Fatal(err)
- }
- }
-
- ts.CloseClientConnections()
- for i := 0; i < N; i++ {
- go func() {
- res, err := c.Get(ts.URL)
- if err == nil {
- res.Body.Close()
- }
- errc <- err
- }()
+ for i := 0; i < 3; i++ {
+ res, err := c.Get("http://fake.golang/")
+ if err != nil {
+ t.Fatalf("i=%d: Get = %v", i, err)
}
+ res.Body.Close()
+ }
- for i := 0; i < N; i++ {
- if err := <-errc; err != nil {
- t.Fatal(err)
- }
- }
- for i := 0; i < N; i++ {
- select {
- case <-retryc:
- // we triggered a retry, test was successful
- t.Logf("finished after %d runs\n", n)
- return
- default:
- }
- }
+ mu.Lock()
+ got := logbuf.String()
+ mu.Unlock()
+ const want = `Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+intentional write failure
+Retried.
+Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+`
+ if got != want {
+ t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
}
- t.Fatal("did not trigger any retries")
}
// Issue 6981
@@ -2508,7 +2655,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
io.Reader
io.Closer
}{
- io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), plan9SleepReader{}, errorReader{fakeErr}),
+ io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
closerFunc(func() error {
select {
case didClose <- true:
@@ -2540,6 +2687,8 @@ func TestTransportClosesBodyOnError(t *testing.T) {
}
func TestTransportDialTLS(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
var mu sync.Mutex // guards following
var gotReq, didDial bool
@@ -2817,14 +2966,8 @@ func TestTransportFlushesBodyChunks(t *testing.T) {
defer res.Body.Close()
want := []string{
- // Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content.
- // That explains the initial "num0" being split into "n" and "um0".
- // The first byte is included with the request headers Write. Perhaps in the future
- // we will want to flush the headers out early if the first byte of the request body is
- // taking a long time to arrive. But not yet.
"POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" +
- "1\r\nn\r\n",
- "4\r\num0\n\r\n",
+ "5\r\nnum0\n\r\n",
"5\r\nnum1\n\r\n",
"5\r\nnum2\n\r\n",
"0\r\n\r\n",
@@ -2888,6 +3031,11 @@ func TestTransportAutomaticHTTP2(t *testing.T) {
testTransportAutoHTTP(t, &Transport{}, true)
}
+// golang.org/issue/14391: also check DefaultTransport
+func TestTransportAutomaticHTTP2_DefaultTransport(t *testing.T) {
+ testTransportAutoHTTP(t, DefaultTransport.(*Transport), true)
+}
+
func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) {
testTransportAutoHTTP(t, &Transport{
TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper),
@@ -2903,6 +3051,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)
}
@@ -3033,6 +3196,701 @@ func TestNoCrashReturningTransportAltConn(t *testing.T) {
<-handledPendingDial
}
+func TestTransportReuseConnection_Gzip_Chunked(t *testing.T) {
+ testTransportReuseConnection_Gzip(t, true)
+}
+
+func TestTransportReuseConnection_Gzip_ContentLength(t *testing.T) {
+ testTransportReuseConnection_Gzip(t, false)
+}
+
+// Make sure we re-use underlying TCP connection for gzipped responses too.
+func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) {
+ setParallel(t)
+ defer afterTest(t)
+ addr := make(chan string, 2)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ addr <- r.RemoteAddr
+ w.Header().Set("Content-Encoding", "gzip")
+ if chunked {
+ w.(Flusher).Flush()
+ }
+ w.Write(rgz) // arbitrary gzip response
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ for i := 0; i < 2; i++ {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf := make([]byte, len(rgz))
+ if n, err := io.ReadFull(res.Body, buf); err != nil {
+ t.Errorf("%d. ReadFull = %v, %v", i, n, err)
+ }
+ // Note: no res.Body.Close call. It should work without it,
+ // since the flate.Reader's internal buffering will hit EOF
+ // and that should be sufficient.
+ }
+ a1, a2 := <-addr, <-addr
+ if a1 != a2 {
+ t.Fatalf("didn't reuse connection")
+ }
+}
+
+func TestTransportResponseHeaderLength(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/long" {
+ w.Header().Set("Long", strings.Repeat("a", 1<<20))
+ }
+ }))
+ defer ts.Close()
+
+ tr := &Transport{
+ MaxResponseHeaderBytes: 512 << 10,
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ if res, err := c.Get(ts.URL); err != nil {
+ t.Fatal(err)
+ } else {
+ res.Body.Close()
+ }
+
+ res, err := c.Get(ts.URL + "/long")
+ if err == nil {
+ defer res.Body.Close()
+ var n int64
+ for k, vv := range res.Header {
+ for _, v := range vv {
+ n += int64(len(k)) + int64(len(v))
+ }
+ }
+ t.Fatalf("Unexpected success. Got %v and %d bytes of response headers", res.Status, n)
+ }
+ if want := "server response headers exceeded 524288 bytes"; !strings.Contains(err.Error(), want) {
+ t.Errorf("got error: %v; want %q", err, want)
+ }
+}
+
+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, h1Mode, true) }
+func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, true) }
+
+func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
+ defer afterTest(t)
+ const resBody = "some body"
+ gotWroteReqEvent := make(chan struct{})
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ if _, err := ioutil.ReadAll(r.Body); err != nil {
+ t.Error(err)
+ }
+ if !noHooks {
+ select {
+ case <-gotWroteReqEvent:
+ case <-time.After(5 * time.Second):
+ t.Error("timeout waiting for WroteRequest event")
+ }
+ }
+ io.WriteString(w, resBody)
+ }))
+ defer cst.close()
+
+ cst.tr.ExpectContinueTimeout = 1 * time.Second
+
+ var mu sync.Mutex // guards buf
+ var buf bytes.Buffer
+ logf := func(format string, args ...interface{}) {
+ mu.Lock()
+ defer mu.Unlock()
+ fmt.Fprintf(&buf, format, args...)
+ buf.WriteByte('\n')
+ }
+
+ addrStr := cst.ts.Listener.Addr().String()
+ ip, port, err := net.SplitHostPort(addrStr)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Install a fake DNS server.
+ ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+ if host != "dns-is-faked.golang" {
+ t.Errorf("unexpected DNS host lookup for %q", host)
+ return nil, nil
+ }
+ return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+ })
+
+ 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) },
+ GotFirstResponseByte: func() { logf("first response byte") },
+ PutIdleConn: func(err error) { logf("PutIdleConn = %v", err) },
+ DNSStart: func(e httptrace.DNSStartInfo) { logf("DNS start: %+v", e) },
+ DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNS done: %+v", e) },
+ ConnectStart: func(network, addr string) { logf("ConnectStart: Connecting to %s %s ...", network, addr) },
+ ConnectDone: func(network, addr string, err error) {
+ if err != nil {
+ t.Errorf("ConnectDone: %v", err)
+ }
+ logf("ConnectDone: connected to %s %s = %v", network, addr, err)
+ },
+ Wait100Continue: func() { logf("Wait100Continue") },
+ Got100Continue: func() { logf("Got100Continue") },
+ WroteRequest: func(e httptrace.WroteRequestInfo) {
+ logf("WroteRequest: %+v", e)
+ close(gotWroteReqEvent)
+ },
+ }
+ if h2 {
+ trace.TLSHandshakeStart = func() { logf("tls handshake start") }
+ trace.TLSHandshakeDone = func(s tls.ConnectionState, err error) {
+ logf("tls handshake done. ConnectionState = %v \n err = %v", s, err)
+ }
+ }
+ if noHooks {
+ // zero out all func pointers, trying to get some path to crash
+ *trace = httptrace.ClientTrace{}
+ }
+ req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
+
+ req.Header.Set("Expect", "100-continue")
+ 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)
+ }
+ res.Body.Close()
+
+ if noHooks {
+ // Done at this point. Just testing a full HTTP
+ // requests can happen with a trace pointing to a zero
+ // ClientTrace, full of nil func pointers.
+ return
+ }
+
+ mu.Lock()
+ got := buf.String()
+ mu.Unlock()
+
+ wantOnce := func(sub string) {
+ if strings.Count(got, sub) != 1 {
+ t.Errorf("expected substring %q exactly once in output.", sub)
+ }
+ }
+ wantOnceOrMore := func(sub string) {
+ if strings.Count(got, sub) == 0 {
+ t.Errorf("expected substring %q at least once in output.", sub)
+ }
+ }
+ wantOnce("Getting conn for dns-is-faked.golang:" + port)
+ wantOnce("DNS start: {Host:dns-is-faked.golang}")
+ wantOnce("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err:<nil> Coalesced:false}")
+ wantOnce("got conn: {")
+ wantOnceOrMore("Connecting to tcp " + addrStr)
+ wantOnceOrMore("connected to tcp " + addrStr + " = <nil>")
+ wantOnce("Reused:false WasIdle:false IdleTime:0s")
+ wantOnce("first response byte")
+ if h2 {
+ wantOnce("tls handshake start")
+ wantOnce("tls handshake done")
+ } else {
+ wantOnce("PutIdleConn = <nil>")
+ }
+ wantOnce("Wait100Continue")
+ wantOnce("Got100Continue")
+ wantOnce("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) {
+ if testing.Short() && testenv.Builder() == "" {
+ // Skip this test in short mode (the default for
+ // all.bash), in case the user is using a shady/ISP
+ // DNS server hijacking queries.
+ // See issues 16732, 16716.
+ // Our builders use 8.8.8.8, though, which correctly
+ // returns NXDOMAIN, so still run this test there.
+ t.Skip("skipping in short mode")
+ }
+ defer afterTest(t)
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ var mu sync.Mutex // guards buf
+ 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")
+ }
+
+ mu.Lock()
+ got := buf.String()
+ mu.Unlock()
+
+ 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)
+ }
+}
+
+// Issue 14353: port can only contain digits.
+func TestTransportRejectsAlphaPort(t *testing.T) {
+ res, err := Get("http://dummy.tld:123foo/bar")
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("unexpected success")
+ }
+ ue, ok := err.(*url.Error)
+ if !ok {
+ t.Fatalf("got %#v; want *url.Error", err)
+ }
+ got := ue.Err.Error()
+ want := `invalid URL port "123foo"`
+ if got != want {
+ t.Errorf("got error %q; want %q", got, want)
+ }
+}
+
+// Test the httptrace.TLSHandshake{Start,Done} hooks with a https http1
+// connections. The http2 test is done in TestTransportEventTrace_h2
+func TestTLSHandshakeTrace(t *testing.T) {
+ defer afterTest(t)
+ s := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ defer s.Close()
+
+ var mu sync.Mutex
+ var start, done bool
+ trace := &httptrace.ClientTrace{
+ TLSHandshakeStart: func() {
+ mu.Lock()
+ defer mu.Unlock()
+ start = true
+ },
+ TLSHandshakeDone: func(s tls.ConnectionState, err error) {
+ mu.Lock()
+ defer mu.Unlock()
+ done = true
+ if err != nil {
+ t.Fatal("Expected error to be nil but was:", err)
+ }
+ },
+ }
+
+ tr := &Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ req, err := NewRequest("GET", s.URL, nil)
+ if err != nil {
+ t.Fatal("Unable to construct test request:", err)
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+
+ r, err := c.Do(req)
+ if err != nil {
+ t.Fatal("Unexpected error making request:", err)
+ }
+ r.Body.Close()
+ mu.Lock()
+ defer mu.Unlock()
+ if !start {
+ t.Fatal("Expected TLSHandshakeStart to be called, but wasn't")
+ }
+ if !done {
+ t.Fatal("Expected TLSHandshakeDone to be called, but wasnt't")
+ }
+}
+
+func TestTransportMaxIdleConns(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // No body for convenience.
+ }))
+ defer ts.Close()
+ tr := &Transport{
+ MaxIdleConns: 4,
+ }
+ defer tr.CloseIdleConnections()
+
+ ip, port, err := net.SplitHostPort(ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c := &Client{Transport: tr}
+ ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+ return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+ })
+
+ hitHost := func(n int) {
+ req, _ := NewRequest("GET", fmt.Sprintf("http://host-%d.dns-is-faked.golang:"+port, n), nil)
+ req = req.WithContext(ctx)
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ }
+ for i := 0; i < 4; i++ {
+ hitHost(i)
+ }
+ want := []string{
+ "|http|host-0.dns-is-faked.golang:" + port,
+ "|http|host-1.dns-is-faked.golang:" + port,
+ "|http|host-2.dns-is-faked.golang:" + port,
+ "|http|host-3.dns-is-faked.golang:" + port,
+ }
+ if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) {
+ t.Fatalf("idle conn keys mismatch.\n got: %q\nwant: %q\n", got, want)
+ }
+
+ // Now hitting the 5th host should kick out the first host:
+ hitHost(4)
+ want = []string{
+ "|http|host-1.dns-is-faked.golang:" + port,
+ "|http|host-2.dns-is-faked.golang:" + port,
+ "|http|host-3.dns-is-faked.golang:" + port,
+ "|http|host-4.dns-is-faked.golang:" + port,
+ }
+ if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) {
+ t.Fatalf("idle conn keys mismatch after 5th host.\n got: %q\nwant: %q\n", got, want)
+ }
+}
+
+func TestTransportIdleConnTimeout_h1(t *testing.T) { testTransportIdleConnTimeout(t, h1Mode) }
+func TestTransportIdleConnTimeout_h2(t *testing.T) { testTransportIdleConnTimeout(t, h2Mode) }
+func testTransportIdleConnTimeout(t *testing.T, h2 bool) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ defer afterTest(t)
+
+ const timeout = 1 * time.Second
+
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ // No body for convenience.
+ }))
+ defer cst.close()
+ tr := cst.tr
+ tr.IdleConnTimeout = timeout
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ idleConns := func() []string {
+ if h2 {
+ return tr.IdleConnStrsForTesting_h2()
+ } else {
+ return tr.IdleConnStrsForTesting()
+ }
+ }
+
+ var conn string
+ doReq := func(n int) {
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+ PutIdleConn: func(err error) {
+ if err != nil {
+ t.Errorf("failed to keep idle conn: %v", err)
+ }
+ },
+ }))
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ conns := idleConns()
+ if len(conns) != 1 {
+ t.Fatalf("req %v: unexpected number of idle conns: %q", n, conns)
+ }
+ if conn == "" {
+ conn = conns[0]
+ }
+ if conn != conns[0] {
+ t.Fatalf("req %v: cached connection changed; expected the same one throughout the test", n)
+ }
+ }
+ for i := 0; i < 3; i++ {
+ doReq(i)
+ time.Sleep(timeout / 2)
+ }
+ time.Sleep(timeout * 3 / 2)
+ if got := idleConns(); len(got) != 0 {
+ t.Errorf("idle conns = %q; want none", got)
+ }
+}
+
+// Issue 16208: Go 1.7 crashed after Transport.IdleConnTimeout if an
+// HTTP/2 connection was established but but its caller no longer
+// wanted it. (Assuming the connection cache was enabled, which it is
+// by default)
+//
+// This test reproduced the crash by setting the IdleConnTimeout low
+// (to make the test reasonable) and then making a request which is
+// canceled by the DialTLS hook, which then also waits to return the
+// real connection until after the RoundTrip saw the error. Then we
+// know the successful tls.Dial from DialTLS will need to go into the
+// idle pool. Then we give it a of time to explode.
+func TestIdleConnH2Crash(t *testing.T) {
+ setParallel(t)
+ cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ // nothing
+ }))
+ defer cst.close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ sawDoErr := make(chan bool, 1)
+ testDone := make(chan struct{})
+ defer close(testDone)
+
+ cst.tr.IdleConnTimeout = 5 * time.Millisecond
+ cst.tr.DialTLS = func(network, addr string) (net.Conn, error) {
+ c, err := tls.Dial(network, addr, &tls.Config{
+ InsecureSkipVerify: true,
+ NextProtos: []string{"h2"},
+ })
+ if err != nil {
+ t.Error(err)
+ return nil, err
+ }
+ if cs := c.ConnectionState(); cs.NegotiatedProtocol != "h2" {
+ t.Errorf("protocol = %q; want %q", cs.NegotiatedProtocol, "h2")
+ c.Close()
+ return nil, errors.New("bogus")
+ }
+
+ cancel()
+
+ failTimer := time.NewTimer(5 * time.Second)
+ defer failTimer.Stop()
+ select {
+ case <-sawDoErr:
+ case <-testDone:
+ case <-failTimer.C:
+ t.Error("timeout in DialTLS, waiting too long for cst.c.Do to fail")
+ }
+ return c, nil
+ }
+
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req = req.WithContext(ctx)
+ res, err := cst.c.Do(req)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("unexpected success")
+ }
+ sawDoErr <- true
+
+ // Wait for the explosion.
+ time.Sleep(cst.tr.IdleConnTimeout * 10)
+}
+
+type funcConn struct {
+ net.Conn
+ read func([]byte) (int, error)
+ write func([]byte) (int, error)
+}
+
+func (c funcConn) Read(p []byte) (int, error) { return c.read(p) }
+func (c funcConn) Write(p []byte) (int, error) { return c.write(p) }
+func (c funcConn) Close() error { return nil }
+
+// Issue 16465: Transport.RoundTrip should return the raw net.Conn.Read error from Peek
+// back to the caller.
+func TestTransportReturnsPeekError(t *testing.T) {
+ errValue := errors.New("specific error value")
+
+ wrote := make(chan struct{})
+ var wroteOnce sync.Once
+
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ c := funcConn{
+ read: func([]byte) (int, error) {
+ <-wrote
+ return 0, errValue
+ },
+ write: func(p []byte) (int, error) {
+ wroteOnce.Do(func() { close(wrote) })
+ return len(p), nil
+ },
+ }
+ return c, nil
+ },
+ }
+ _, err := tr.RoundTrip(httptest.NewRequest("GET", "http://fake.tld/", nil))
+ if err != errValue {
+ t.Errorf("error = %#v; want %v", err, errValue)
+ }
+}
+
+// Issue 13835: international domain names should work
+func TestTransportIDNA_h1(t *testing.T) { testTransportIDNA(t, h1Mode) }
+func TestTransportIDNA_h2(t *testing.T) { testTransportIDNA(t, h2Mode) }
+func testTransportIDNA(t *testing.T, h2 bool) {
+ defer afterTest(t)
+
+ const uniDomain = "гофер.го"
+ const punyDomain = "xn--c1ae0ajs.xn--c1aw"
+
+ var port string
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ want := punyDomain + ":" + port
+ if r.Host != want {
+ t.Errorf("Host header = %q; want %q", r.Host, want)
+ }
+ if h2 {
+ if r.TLS == nil {
+ t.Errorf("r.TLS == nil")
+ } else if r.TLS.ServerName != punyDomain {
+ t.Errorf("TLS.ServerName = %q; want %q", r.TLS.ServerName, punyDomain)
+ }
+ }
+ w.Header().Set("Hit-Handler", "1")
+ }))
+ defer cst.close()
+
+ ip, port, err := net.SplitHostPort(cst.ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Install a fake DNS server.
+ ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+ if host != punyDomain {
+ t.Errorf("got DNS host lookup for %q; want %q", host, punyDomain)
+ return nil, nil
+ }
+ return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+ })
+
+ req, _ := NewRequest("GET", cst.scheme()+"://"+uniDomain+":"+port, nil)
+ trace := &httptrace.ClientTrace{
+ GetConn: func(hostPort string) {
+ want := net.JoinHostPort(punyDomain, port)
+ if hostPort != want {
+ t.Errorf("getting conn for %q; want %q", hostPort, want)
+ }
+ },
+ DNSStart: func(e httptrace.DNSStartInfo) {
+ if e.Host != punyDomain {
+ t.Errorf("DNSStart Host = %q; want %q", e.Host, punyDomain)
+ }
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
+
+ res, err := cst.tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.Header.Get("Hit-Handler") != "1" {
+ out, err := httputil.DumpResponse(res, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Errorf("Response body wasn't from Handler. Got:\n%s\n", out)
+ }
+}
+
+// Issue 13290: send User-Agent in proxy CONNECT
+func TestTransportProxyConnectHeader(t *testing.T) {
+ defer afterTest(t)
+ reqc := make(chan *Request, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method != "CONNECT" {
+ t.Errorf("method = %q; want CONNECT", r.Method)
+ }
+ reqc <- r
+ c, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Errorf("Hijack: %v", err)
+ return
+ }
+ c.Close()
+ }))
+ defer ts.Close()
+ tr := &Transport{
+ ProxyConnectHeader: Header{
+ "User-Agent": {"foo"},
+ "Other": {"bar"},
+ },
+ Proxy: func(r *Request) (*url.URL, error) {
+ return url.Parse(ts.URL)
+ },
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get("https://dummy.tld/") // https to force a CONNECT
+ if err == nil {
+ res.Body.Close()
+ t.Errorf("unexpected success")
+ }
+ select {
+ case <-time.After(3 * time.Second):
+ t.Fatal("timeout")
+ case r := <-reqc:
+ if got, want := r.Header.Get("User-Agent"), "foo"; got != want {
+ t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
+ }
+ if got, want := r.Header.Get("Other"), "bar"; got != want {
+ t.Errorf("CONNECT request Other = %q; want %q", got, want)
+ }
+ }
+}
+
var errFakeRoundTrip = errors.New("fake roundtrip")
type funcRoundTripper func()
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index 9c7b5da8fe..b3297f249d 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -1,10 +1,20 @@
-// Copyright 2011 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 net
-import "errors"
+import (
+ "errors"
+ "sync"
+ "time"
+)
+
+// BUG(mikio): On NaCl, methods and functions related to
+// Interface are not implemented.
+
+// BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris,
+// the MulticastAddrs method of Interface is not implemented.
var (
errInvalidInterface = errors.New("invalid network interface")
@@ -15,7 +25,7 @@ var (
)
// Interface represents a mapping between network interface name
-// and index. It also represents network interface facility
+// and index. It also represents network interface facility
// information.
type Interface struct {
Index int // positive integer that starts at one, zero is never used
@@ -59,7 +69,8 @@ func (f Flags) String() string {
return s
}
-// Addrs returns interface addresses for a specific interface.
+// Addrs returns a list of unicast interface addresses for a specific
+// interface.
func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -71,8 +82,8 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
return ifat, err
}
-// MulticastAddrs returns multicast, joined group addresses for
-// a specific interface.
+// MulticastAddrs returns a list of multicast, joined group addresses
+// for a specific interface.
func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -88,13 +99,19 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
func Interfaces() ([]Interface, error) {
ift, err := interfaceTable(0)
if err != nil {
- err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+ return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+ }
+ if len(ift) != 0 {
+ zoneCache.update(ift)
}
- return ift, err
+ return ift, nil
}
-// InterfaceAddrs returns a list of the system's network interface
+// InterfaceAddrs returns a list of the system's unicast interface
// addresses.
+//
+// The returned list does not identify the associated interface; use
+// Interfaces and Interface.Addrs for more detail.
func InterfaceAddrs() ([]Addr, error) {
ifat, err := interfaceAddrTable(nil)
if err != nil {
@@ -104,6 +121,10 @@ func InterfaceAddrs() ([]Addr, error) {
}
// InterfaceByIndex returns the interface specified by index.
+//
+// On Solaris, it returns one of the logical network interfaces
+// sharing the logical data link; for more precision use
+// InterfaceByName.
func InterfaceByIndex(index int) (*Interface, error) {
if index <= 0 {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
@@ -137,6 +158,9 @@ func InterfaceByName(name string) (*Interface, error) {
if err != nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
}
+ if len(ift) != 0 {
+ zoneCache.update(ift)
+ }
for _, ifi := range ift {
if name == ifi.Name {
return &ifi, nil
@@ -144,3 +168,73 @@ func InterfaceByName(name string) (*Interface, error) {
}
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
}
+
+// An ipv6ZoneCache represents a cache holding partial network
+// interface information. It is used for reducing the cost of IPv6
+// addressing scope zone resolution.
+//
+// Multiple names sharing the index are managed by first-come
+// first-served basis for consistency.
+type ipv6ZoneCache struct {
+ sync.RWMutex // guard the following
+ lastFetched time.Time // last time routing information was fetched
+ toIndex map[string]int // interface name to its index
+ toName map[int]string // interface index to its name
+}
+
+var zoneCache = ipv6ZoneCache{
+ toIndex: make(map[string]int),
+ toName: make(map[int]string),
+}
+
+func (zc *ipv6ZoneCache) update(ift []Interface) {
+ zc.Lock()
+ defer zc.Unlock()
+ now := time.Now()
+ if zc.lastFetched.After(now.Add(-60 * time.Second)) {
+ return
+ }
+ zc.lastFetched = now
+ if len(ift) == 0 {
+ var err error
+ if ift, err = interfaceTable(0); err != nil {
+ return
+ }
+ }
+ zc.toIndex = make(map[string]int, len(ift))
+ zc.toName = make(map[int]string, len(ift))
+ for _, ifi := range ift {
+ zc.toIndex[ifi.Name] = ifi.Index
+ if _, ok := zc.toName[ifi.Index]; !ok {
+ zc.toName[ifi.Index] = ifi.Name
+ }
+ }
+}
+
+func zoneToString(zone int) string {
+ if zone == 0 {
+ return ""
+ }
+ zoneCache.update(nil)
+ zoneCache.RLock()
+ defer zoneCache.RUnlock()
+ name, ok := zoneCache.toName[zone]
+ if !ok {
+ name = uitoa(uint(zone))
+ }
+ return name
+}
+
+func zoneToInt(zone string) int {
+ if zone == "" {
+ return 0
+ }
+ zoneCache.update(nil)
+ zoneCache.RLock()
+ defer zoneCache.RUnlock()
+ index, ok := zoneCache.toIndex[zone]
+ if !ok {
+ index, _, _ = dtoi(zone)
+ }
+ return index
+}
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
index 208f37f9fd..35b1c26815 100644
--- a/libgo/go/net/interface_bsd.go
+++ b/libgo/go/net/interface_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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
+// 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] = byte(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] = byte(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
@@ -95,81 +75,44 @@ func linkFlags(rawFlags int32) Flags {
}
// If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces. Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
index := 0
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 protcol stack usually embeds
- // the interface index in the interface-local or
- // link-local address as the kernel-internal form.
- if ifa.IP.IsLinkLocalUnicast() {
- ifa.IP[2], ifa.IP[3] = 0, 0
- }
- }
- if ifa.IP == nil || ifa.Mask == nil {
- return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
- }
- return ifa, nil
-}
diff --git a/libgo/go/net/interface_bsdvar.go b/libgo/go/net/interface_bsdvar.go
new file mode 100644
index 0000000000..0b84ca37d4
--- /dev/null
+++ b/libgo/go/net/interface_bsdvar.go
@@ -0,0 +1,28 @@
+// 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.
+
+// +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) {
+ // TODO(mikio): Implement this like other platforms.
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go
index b7a333849d..2ec8e1cc6e 100644
--- a/libgo/go/net/interface_darwin.go
+++ b/libgo/go/net/interface_darwin.go
@@ -1,62 +1,53 @@
-// Copyright 2011 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 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 protcol 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/libgo/go/net/interface_dragonfly.go b/libgo/go/net/interface_dragonfly.go
deleted file mode 100644
index c9ce5a7ac1..0000000000
--- a/libgo/go/net/interface_dragonfly.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
-}
diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go
index c42d90b740..8a7d6f67c0 100644
--- a/libgo/go/net/interface_freebsd.go
+++ b/libgo/go/net/interface_freebsd.go
@@ -1,62 +1,58 @@
-// Copyright 2011 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 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 protcol 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/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index ef2042920e..5e391b28b0 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -11,7 +11,7 @@ import (
)
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
@@ -115,7 +115,7 @@ func linkFlags(rawFlags uint32) Flags {
}
// If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces. Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
diff --git a/libgo/go/net/interface_netbsd.go b/libgo/go/net/interface_netbsd.go
deleted file mode 100644
index c9ce5a7ac1..0000000000
--- a/libgo/go/net/interface_netbsd.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
-}
diff --git a/libgo/go/net/interface_openbsd.go b/libgo/go/net/interface_openbsd.go
deleted file mode 100644
index c9ce5a7ac1..0000000000
--- a/libgo/go/net/interface_openbsd.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
-}
diff --git a/libgo/go/net/interface_plan9.go b/libgo/go/net/interface_plan9.go
new file mode 100644
index 0000000000..e5d77390f8
--- /dev/null
+++ b/libgo/go/net/interface_plan9.go
@@ -0,0 +1,198 @@
+// 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 net
+
+import (
+ "errors"
+ "os"
+)
+
+// 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) {
+ if ifindex == 0 {
+ n, err := interfaceCount()
+ if err != nil {
+ return nil, err
+ }
+ ifcs := make([]Interface, n)
+ for i := range ifcs {
+ ifc, err := readInterface(i)
+ if err != nil {
+ return nil, err
+ }
+ ifcs[i] = *ifc
+ }
+ return ifcs, nil
+ }
+
+ ifc, err := readInterface(ifindex - 1)
+ if err != nil {
+ return nil, err
+ }
+ return []Interface{*ifc}, nil
+}
+
+func readInterface(i int) (*Interface, error) {
+ ifc := &Interface{
+ Index: i + 1, // Offset the index by one to suit the contract
+ Name: netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
+ }
+
+ ifcstat := ifc.Name + "/status"
+ ifcstatf, err := open(ifcstat)
+ if err != nil {
+ return nil, err
+ }
+ defer ifcstatf.close()
+
+ line, ok := ifcstatf.readLine()
+ if !ok {
+ return nil, errors.New("invalid interface status file: " + ifcstat)
+ }
+
+ fields := getFields(line)
+ if len(fields) < 4 {
+ return nil, errors.New("invalid interface status file: " + ifcstat)
+ }
+
+ device := fields[1]
+ mtustr := fields[3]
+
+ mtu, _, ok := dtoi(mtustr)
+ if !ok {
+ return nil, errors.New("invalid status file of interface: " + ifcstat)
+ }
+ ifc.MTU = mtu
+
+ // Not a loopback device
+ if device != "/dev/null" {
+ deviceaddrf, err := open(device + "/addr")
+ if err != nil {
+ return nil, err
+ }
+ defer deviceaddrf.close()
+
+ line, ok = deviceaddrf.readLine()
+ if !ok {
+ return nil, errors.New("invalid address file for interface: " + device + "/addr")
+ }
+
+ if len(line) > 0 && len(line)%2 == 0 {
+ ifc.HardwareAddr = make([]byte, len(line)/2)
+ var ok bool
+ for i := range ifc.HardwareAddr {
+ j := (i + 1) * 2
+ ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
+ if !ok {
+ ifc.HardwareAddr = ifc.HardwareAddr[:i]
+ break
+ }
+ }
+ }
+
+ ifc.Flags = FlagUp | FlagBroadcast | FlagMulticast
+ } else {
+ ifc.Flags = FlagUp | FlagMulticast | FlagLoopback
+ }
+
+ return ifc, nil
+}
+
+func interfaceCount() (int, error) {
+ d, err := os.Open(netdir + "/ipifc")
+ if err != nil {
+ return -1, err
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(0)
+ if err != nil {
+ return -1, err
+ }
+
+ // Assumes that numbered files in ipifc are strictly
+ // the incrementing numbered directories for the
+ // interfaces
+ c := 0
+ for _, name := range names {
+ if _, _, ok := dtoi(name); !ok {
+ continue
+ }
+ c++
+ }
+
+ return c, nil
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+ var ifcs []Interface
+ if ifi == nil {
+ var err error
+ ifcs, err = interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ ifcs = []Interface{*ifi}
+ }
+
+ addrs := make([]Addr, len(ifcs))
+ for i, ifc := range ifcs {
+ status := ifc.Name + "/status"
+ statusf, err := open(status)
+ if err != nil {
+ return nil, err
+ }
+ defer statusf.close()
+
+ line, ok := statusf.readLine()
+ line, ok = statusf.readLine()
+ if !ok {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+
+ // This assumes only a single address for the interface.
+ fields := getFields(line)
+ if len(fields) < 1 {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+ addr := fields[0]
+ ip := ParseIP(addr)
+ if ip == nil {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+
+ // The mask is represented as CIDR relative to the IPv6 address.
+ // Plan 9 internal representation is always IPv6.
+ maskfld := fields[1]
+ maskfld = maskfld[1:]
+ pfxlen, _, ok := dtoi(maskfld)
+ if !ok {
+ return nil, errors.New("cannot parse network mask for interface: " + status)
+ }
+ var mask IPMask
+ if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
+ mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
+ }
+ if ip.To16() != nil && ip.To4() == nil { // IPv6 address
+ mask = CIDRMask(pfxlen, 8*IPv6len)
+ }
+
+ addrs[i] = &IPNet{IP: ip, Mask: mask}
+ }
+
+ return addrs, nil
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_solaris.go b/libgo/go/net/interface_solaris.go
new file mode 100644
index 0000000000..dc8ffbfcb8
--- /dev/null
+++ b/libgo/go/net/interface_solaris.go
@@ -0,0 +1,107 @@
+// 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 net
+
+import (
+ "syscall"
+
+ "golang_org/x/net/lif"
+)
+
+// 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) {
+ lls, err := lif.Links(syscall.AF_UNSPEC, "")
+ if err != nil {
+ return nil, err
+ }
+ var ift []Interface
+ for _, ll := range lls {
+ if ifindex != 0 && ifindex != ll.Index {
+ continue
+ }
+ ifi := Interface{Index: ll.Index, MTU: ll.MTU, Name: ll.Name, Flags: linkFlags(ll.Flags)}
+ if len(ll.Addr) > 0 {
+ ifi.HardwareAddr = HardwareAddr(ll.Addr)
+ }
+ ift = append(ift, ifi)
+ }
+ return ift, nil
+}
+
+const (
+ sysIFF_UP = 0x1
+ sysIFF_BROADCAST = 0x2
+ sysIFF_DEBUG = 0x4
+ sysIFF_LOOPBACK = 0x8
+ sysIFF_POINTOPOINT = 0x10
+ sysIFF_NOTRAILERS = 0x20
+ sysIFF_RUNNING = 0x40
+ sysIFF_NOARP = 0x80
+ sysIFF_PROMISC = 0x100
+ sysIFF_ALLMULTI = 0x200
+ sysIFF_INTELLIGENT = 0x400
+ sysIFF_MULTICAST = 0x800
+ sysIFF_MULTI_BCAST = 0x1000
+ sysIFF_UNNUMBERED = 0x2000
+ sysIFF_PRIVATE = 0x8000
+)
+
+func linkFlags(rawFlags int) Flags {
+ var f Flags
+ if rawFlags&sysIFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&sysIFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&sysIFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&sysIFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&sysIFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+ var name string
+ if ifi != nil {
+ name = ifi.Name
+ }
+ as, err := lif.Addrs(syscall.AF_UNSPEC, name)
+ if err != nil {
+ return nil, err
+ }
+ var ifat []Addr
+ for _, a := range as {
+ var ip IP
+ var mask IPMask
+ switch a := a.(type) {
+ case *lif.Inet4Addr:
+ ip = IPv4(a.IP[0], a.IP[1], a.IP[2], a.IP[3])
+ mask = CIDRMask(a.PrefixLen, 8*IPv4len)
+ case *lif.Inet6Addr:
+ ip = make(IP, IPv6len)
+ copy(ip, a.IP[:])
+ mask = CIDRMask(a.PrefixLen, 8*IPv6len)
+ }
+ ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
+ }
+ return ifat, nil
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go
index c38fb7f765..3b0a1aeacf 100644
--- a/libgo/go/net/interface_stub.go
+++ b/libgo/go/net/interface_stub.go
@@ -1,20 +1,20 @@
-// Copyright 2011 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.
-// +build nacl plan9 solaris
+// +build nacl
package net
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
return nil, nil
}
// If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces. Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
return nil, nil
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
index 7bdd924150..38a2ca4656 100644
--- a/libgo/go/net/interface_test.go
+++ b/libgo/go/net/interface_test.go
@@ -1,17 +1,18 @@
-// Copyright 2011 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 net
import (
+ "fmt"
"reflect"
"runtime"
"testing"
)
// loopbackInterface returns an available logical network interface
-// for loopback tests. It returns nil if no suitable interface is
+// for loopback tests. It returns nil if no suitable interface is
// found.
func loopbackInterface() *Interface {
ift, err := Interfaces()
@@ -47,27 +48,25 @@ 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) {
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
}
- var stats routeStats
for _, ifi := range ift {
ifxi, err := InterfaceByIndex(ifi.Index)
if err != nil {
t.Fatal(err)
}
- if !reflect.DeepEqual(ifxi, &ifi) {
- t.Errorf("got %v; want %v", ifxi, ifi)
+ switch runtime.GOOS {
+ case "solaris":
+ if ifxi.Index != ifi.Index {
+ t.Errorf("got %v; want %v", ifxi, ifi)
+ }
+ default:
+ if !reflect.DeepEqual(ifxi, &ifi) {
+ t.Errorf("got %v; want %v", ifxi, ifi)
+ }
}
ifxn, err := InterfaceByName(ifi.Name)
if err != nil {
@@ -76,56 +75,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 looopback 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)
}
}
@@ -134,132 +84,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
- // looopback 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)
}
- return testMulticastAddrs(t, ifmat)
+ ifStats := interfaceStats(ift)
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatal(err)
+ }
+ uniStats, err := validateInterfaceUnicastAddrs(ifat)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var multiStats routeStats
+ for _, ifi := range ift {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ stats, err := validateInterfaceMulticastAddrs(ifmat)
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ multiStats.ipv4 += stats.ipv4
+ multiStats.ipv6 += stats.ipv6
+ }
+ if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ifStats struct {
+ loop int // # of active loopback interfaces
+ other int // # of active other interfaces
+}
+
+func interfaceStats(ift []Interface) *ifStats {
+ var stats ifStats
+ for _, ifi := range ift {
+ if ifi.Flags&FlagUp != 0 {
+ if ifi.Flags&FlagLoopback != 0 {
+ stats.loop++
+ } else {
+ stats.other++
+ }
+ }
+ }
+ return &stats
+}
+
+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.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
- t.Errorf("unexpected value: %#v", ifa)
- continue
+ if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil {
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
if len(ifa.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
- continue
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
prefixLen, maxPrefixLen := ifa.Mask.Size()
if ifa.IP.To4() != nil {
if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
- t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122
- t.Errorf("unexpected prefix length for IPv4 loopback: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
- naf4++
+ stats.ipv4++
}
if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
- t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
- t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
- naf6++
+ stats.ipv6++
}
- t.Logf("interface address %q", ifa.String())
case *IPAddr:
- if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() {
- t.Errorf("unexpected value: %#v", ifa)
- continue
+ if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() {
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
if len(ifa.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
- continue
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
if ifa.IP.To4() != nil {
- naf4++
+ stats.ipv4++
}
if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
- naf6++
+ stats.ipv6++
}
- t.Logf("interface address %s", ifa.String())
default:
- t.Errorf("unexpected type: %T", ifa)
+ return nil, fmt.Errorf("unexpected type: %T", ifa)
}
}
- return
+ return stats, nil
}
-func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
- for _, ifma := range ifmat {
- switch ifma := ifma.(type) {
+func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
+ stats := new(routeStats)
+ for _, ifa := range ifat {
+ switch ifa := ifa.(type) {
case *IPAddr:
- if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
- t.Errorf("unexpected value: %+v", ifma)
- continue
+ if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() {
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
- if len(ifma.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifma)
- continue
+ if len(ifa.IP) != IPv6len {
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
- if ifma.IP.To4() != nil {
- nmaf4++
+ if ifa.IP.To4() != nil {
+ stats.ipv4++
}
- if ifma.IP.To16() != nil && ifma.IP.To4() == nil {
- nmaf6++
+ if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
+ stats.ipv6++
}
- t.Logf("joined group address %q", ifma.String())
default:
- t.Errorf("unexpected type: %T", ifma)
+ return nil, fmt.Errorf("unexpected type: %T", ifa)
}
}
- return
+ return stats, nil
+}
+
+func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error {
+ // Test the existence of connected unicast routes for IPv4.
+ if supportsIPv4 && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 {
+ return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+ }
+ // Test the existence of connected unicast routes for IPv6.
+ // We can assume the existence of ::1/128 when at least one
+ // loopback interface is installed.
+ if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 == 0 {
+ return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+ }
+ return nil
+}
+
+func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error {
+ switch runtime.GOOS {
+ case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
+ default:
+ // Test the existence of connected multicast route
+ // clones for IPv4. Unlike IPv6, IPv4 multicast
+ // capability is not a mandatory feature, and so IPv4
+ // multicast validation is ignored and we only check
+ // IPv6 below.
+ //
+ // Test the existence of connected multicast route
+ // clones for IPv6. Some platform never uses loopback
+ // interface as the nexthop for multicast routing.
+ // We can assume the existence of connected multicast
+ // route clones when at least two connected unicast
+ // routes, ::1/128 and other, are installed.
+ if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 {
+ return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats)
+ }
+ }
+ return nil
}
func BenchmarkInterfaces(b *testing.B) {
diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go
index 4d6bcdf4c7..8b976e585f 100644
--- a/libgo/go/net/interface_windows.go
+++ b/libgo/go/net/interface_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -61,7 +61,7 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
}
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
aas, err := adapterAddresses()
@@ -116,7 +116,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
}
// If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces. Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
aas, err := adapterAddresses()
diff --git a/libgo/go/net/internal/socktest/switch.go b/libgo/go/net/internal/socktest/switch.go
index 8bef06b97c..3c37b6ff80 100644
--- a/libgo/go/net/internal/socktest/switch.go
+++ b/libgo/go/net/internal/socktest/switch.go
@@ -121,7 +121,7 @@ const (
FilterSocket FilterType = iota // for Socket
FilterConnect // for Connect or ConnectEx
FilterListen // for Listen
- FilterAccept // for Accept or Accept4
+ FilterAccept // for Accept, Accept4 or AcceptEx
FilterGetsockoptInt // for GetsockoptInt
FilterClose // for Close or Closesocket
)
diff --git a/libgo/go/net/internal/socktest/sys_windows.go b/libgo/go/net/internal/socktest/sys_windows.go
index e61bf2be60..2e3d2bc7fc 100644
--- a/libgo/go/net/internal/socktest/sys_windows.go
+++ b/libgo/go/net/internal/socktest/sys_windows.go
@@ -154,3 +154,33 @@ func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
sw.stats.getLocked(so.Cookie).Listened++
return nil
}
+
+// AcceptEx wraps syscall.AcceptEx.
+func (sw *Switch) AcceptEx(ls syscall.Handle, as syscall.Handle, b *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, rcvd *uint32, overlapped *syscall.Overlapped) error {
+ so := sw.sockso(ls)
+ if so == nil {
+ return syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+ }
+ sw.fmu.RLock()
+ f, _ := sw.fltab[FilterAccept]
+ sw.fmu.RUnlock()
+
+ af, err := f.apply(so)
+ if err != nil {
+ return err
+ }
+ so.Err = syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+ if err = af.apply(so); err != nil {
+ return err
+ }
+
+ sw.smu.Lock()
+ defer sw.smu.Unlock()
+ if so.Err != nil {
+ sw.stats.getLocked(so.Cookie).AcceptFailed++
+ return so.Err
+ }
+ nso := sw.addLocked(as, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+ sw.stats.getLocked(nso.Cookie).Accepted++
+ return nil
+}
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index cc004d6072..db3364c1b3 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -90,7 +90,7 @@ func CIDRMask(ones, bits int) IPMask {
// Well-known IPv4 addresses
var (
- IPv4bcast = IPv4(255, 255, 255, 255) // broadcast
+ IPv4bcast = IPv4(255, 255, 255, 255) // limited broadcast
IPv4allsys = IPv4(224, 0, 0, 1) // all systems
IPv4allrouter = IPv4(224, 0, 0, 2) // all routers
IPv4zero = IPv4(0, 0, 0, 0) // all zeros
@@ -153,6 +153,12 @@ func (ip IP) IsLinkLocalUnicast() bool {
// IsGlobalUnicast reports whether ip is a global unicast
// address.
+//
+// The identification of global unicast addresses uses address type
+// identification as defined in RFC 1122, RFC 4632 and RFC 4291 with
+// the exception of IPv4 directed broadcast addresses.
+// It returns true even if ip is in IPv4 private address space or
+// local IPv6 unicast address space.
func (ip IP) IsGlobalUnicast() bool {
return (len(ip) == IPv4len || len(ip) == IPv6len) &&
!ip.Equal(IPv4bcast) &&
@@ -252,9 +258,11 @@ func (ip IP) Mask(mask IPMask) IP {
}
// String returns the string form of the IP address ip.
-// If the address is an IPv4 address, the string representation
-// is dotted decimal ("74.125.19.99"). Otherwise the representation
-// is IPv6 ("2001:4860:0:2001::68").
+// 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: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
@@ -270,7 +278,7 @@ func (ip IP) String() string {
uitoa(uint(p4[3]))
}
if len(p) != IPv6len {
- return "?"
+ return "?" + hexString(ip)
}
// Find longest run of zeros.
@@ -312,6 +320,14 @@ func (ip IP) String() string {
return string(b)
}
+func hexString(b []byte) string {
+ s := make([]byte, len(b)*2)
+ for i, tn := range b {
+ s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
+ }
+ return string(s)
+}
+
// ipEmptyString is like ip.String except that it returns
// an empty string when ip is unset.
func ipEmptyString(ip IP) string {
@@ -328,7 +344,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
}
@@ -377,6 +393,10 @@ func bytesEqual(x, y []byte) bool {
return true
}
+func (ip IP) matchAddrFamily(x IP) bool {
+ return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil
+}
+
// If mask is a sequence of 1 bits followed by 0 bits,
// return the number of 1 bits.
func simpleMaskLength(mask IPMask) int {
@@ -422,11 +442,7 @@ func (m IPMask) String() string {
if len(m) == 0 {
return "<nil>"
}
- buf := make([]byte, len(m)*2)
- for i, b := range m {
- buf[i*2], buf[i*2+1] = hexDigit[b>>4], hexDigit[b&0xf]
- }
- return string(buf)
+ return hexString(m)
}
func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
@@ -473,12 +489,12 @@ func (n *IPNet) Contains(ip IP) bool {
// Network returns the address's network name, "ip+net".
func (n *IPNet) Network() string { return "ip+net" }
-// String returns the CIDR notation of n like "192.168.100.1/24"
-// or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291.
+// String returns the CIDR notation of n like "192.0.2.1/24"
+// or "2001:db8::/48" as defined in RFC 4632 and RFC 4291.
// If the mask is not in the canonical form, it returns the
// string which consists of an IP address, followed by a slash
// character and a mask expressed as hexadecimal form with no
-// punctuation like "192.168.100.1/c000ff00".
+// punctuation like "198.51.100.1/c000ff00".
func (n *IPNet) String() string {
nn, m := networkNumberAndMask(n)
if nn == nil || m == nil {
@@ -494,29 +510,25 @@ func (n *IPNet) String() string {
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
- i := 0
- for j := 0; j < IPv4len; j++ {
- if i >= len(s) {
+ for i := 0; i < IPv4len; i++ {
+ if len(s) == 0 {
// Missing octets.
return nil
}
- if j > 0 {
- if s[i] != '.' {
+ if i > 0 {
+ if s[0] != '.' {
return nil
}
- i++
+ s = s[1:]
}
- var (
- n int
- ok bool
- )
- n, i, ok = dtoi(s, i)
+ n, c, ok := dtoi(s)
if !ok || n > 0xFF {
return nil
}
- p[j] = byte(n)
+ s = s[c:]
+ p[i] = byte(n)
}
- if i != len(s) {
+ if len(s) != 0 {
return nil
}
return IPv4(p[0], p[1], p[2], p[3])
@@ -528,8 +540,7 @@ func parseIPv4(s string) IP {
// true.
func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
ip = make(IP, IPv6len)
- ellipsis := -1 // position of ellipsis in p
- i := 0 // index in string s
+ ellipsis := -1 // position of ellipsis in ip
if zoneAllowed {
s, zone = splitHostZone(s)
@@ -538,90 +549,91 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
- i = 2
+ s = s[2:]
// Might be only ellipsis
- if i == len(s) {
+ if len(s) == 0 {
return ip, zone
}
}
// Loop, parsing hex numbers followed by colon.
- j := 0
- for j < IPv6len {
+ i := 0
+ for i < IPv6len {
// Hex number.
- n, i1, ok := xtoi(s, i)
+ n, c, ok := xtoi(s)
if !ok || n > 0xFFFF {
return nil, zone
}
// If followed by dot, might be in trailing IPv4.
- if i1 < len(s) && s[i1] == '.' {
- if ellipsis < 0 && j != IPv6len-IPv4len {
+ if c < len(s) && s[c] == '.' {
+ if ellipsis < 0 && i != IPv6len-IPv4len {
// Not the right place.
return nil, zone
}
- if j+IPv4len > IPv6len {
+ if i+IPv4len > IPv6len {
// Not enough room.
return nil, zone
}
- ip4 := parseIPv4(s[i:])
+ ip4 := parseIPv4(s)
if ip4 == nil {
return nil, zone
}
- ip[j] = ip4[12]
- ip[j+1] = ip4[13]
- ip[j+2] = ip4[14]
- ip[j+3] = ip4[15]
- i = len(s)
- j += IPv4len
+ ip[i] = ip4[12]
+ ip[i+1] = ip4[13]
+ ip[i+2] = ip4[14]
+ ip[i+3] = ip4[15]
+ s = ""
+ i += IPv4len
break
}
// Save this 16-bit chunk.
- ip[j] = byte(n >> 8)
- ip[j+1] = byte(n)
- j += 2
+ ip[i] = byte(n >> 8)
+ ip[i+1] = byte(n)
+ i += 2
// Stop at end of string.
- i = i1
- if i == len(s) {
+ s = s[c:]
+ if len(s) == 0 {
break
}
// Otherwise must be followed by colon and more.
- if s[i] != ':' || i+1 == len(s) {
+ if s[0] != ':' || len(s) == 1 {
return nil, zone
}
- i++
+ s = s[1:]
// Look for ellipsis.
- if s[i] == ':' {
+ if s[0] == ':' {
if ellipsis >= 0 { // already have one
return nil, zone
}
- ellipsis = j
- if i++; i == len(s) { // can be at end
+ ellipsis = i
+ s = s[1:]
+ if len(s) == 0 { // can be at end
break
}
}
}
// Must have used entire string.
- if i != len(s) {
+ if len(s) != 0 {
return nil, zone
}
// If didn't parse enough, expand ellipsis.
- if j < IPv6len {
+ if i < IPv6len {
if ellipsis < 0 {
return nil, zone
}
- n := IPv6len - j
- for k := j - 1; k >= ellipsis; k-- {
- ip[k+n] = ip[k]
+ n := IPv6len - i
+ for j := i - 1; j >= ellipsis; j-- {
+ ip[j+n] = ip[j]
}
- for k := ellipsis + n - 1; k >= ellipsis; k-- {
- ip[k] = 0
+ for j := ellipsis + n - 1; j >= ellipsis; j-- {
+ ip[j] = 0
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
@@ -631,8 +643,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 {
@@ -648,13 +660,14 @@ func ParseIP(s string) IP {
return nil
}
-// ParseCIDR parses s as a CIDR notation IP address and mask,
-// like "192.168.100.1/24" or "2001:DB8::/48", as defined in
+// ParseCIDR parses s as a CIDR notation IP address and prefix length,
+// 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.
+// It returns the IP address and the network implied by the IP and
+// prefix length.
+// For example, ParseCIDR("192.0.2.1/24") returns the IP address
+// 198.0.2.1 and the network 198.0.2.0/24.
func ParseCIDR(s string) (IP, *IPNet, error) {
i := byteIndex(s, '/')
if i < 0 {
@@ -667,7 +680,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
iplen = IPv6len
ip, _ = parseIPv6(addr, false)
}
- n, i, ok := dtoi(mask, 0)
+ n, i, ok := dtoi(mask)
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{Type: "CIDR address", Text: s}
}
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index 3d95a73c09..46551633ce 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "bytes"
"reflect"
"runtime"
"testing"
@@ -27,6 +28,10 @@ var parseIPTests = []struct {
{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
{"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+ {"-0.0.0.0", nil},
+ {"0.-1.0.0", nil},
+ {"0.0.-2.0", nil},
+ {"0.0.0.-3", nil},
{"127.0.0.256", nil},
{"abc", nil},
{"123:", nil},
@@ -124,41 +129,132 @@ func TestMarshalEmptyIP(t *testing.T) {
}
var ipStringTests = []struct {
- in IP
- out string // see RFC 5952
+ in IP // see RFC 791 and RFC 4291
+ str string // see RFC 791, RFC 4291 and RFC 5952
+ byt []byte
+ error
}{
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "2001:db8::123:12:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0}, "2001:db8:1:0:1:0:1:0"},
- {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001::1:0:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0}, "2001:db8:0:0:1::"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1:0:0:1"},
- {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD}, "2001:db8::a:b:c:d"},
- {IPv4(192, 168, 0, 1), "192.168.0.1"},
- {nil, ""},
+ // IPv4 address
+ {
+ IP{192, 0, 2, 1},
+ "192.0.2.1",
+ []byte("192.0.2.1"),
+ nil,
+ },
+ {
+ IP{0, 0, 0, 0},
+ "0.0.0.0",
+ []byte("0.0.0.0"),
+ nil,
+ },
+
+ // IPv4-mapped IPv6 address
+ {
+ IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 0, 2, 1},
+ "192.0.2.1",
+ []byte("192.0.2.1"),
+ nil,
+ },
+ {
+ IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0},
+ "0.0.0.0",
+ []byte("0.0.0.0"),
+ nil,
+ },
+
+ // IPv6 address
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ "2001:db8::123:12:1",
+ []byte("2001:db8::123:12:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1",
+ []byte("2001:db8::1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ "2001:db8:0:1:0:1:0:1",
+ []byte("2001:db8:0:1:0:1:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ "2001:db8:1:0:1:0:1:0",
+ []byte("2001:db8:1:0:1:0:1:0"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001::1:0:0:1",
+ []byte("2001::1:0:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
+ "2001:db8:0:0:1::",
+ []byte("2001:db8:0:0:1::"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1:0:0:1",
+ []byte("2001:db8::1:0:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd},
+ "2001:db8::a:b:c:d",
+ []byte("2001:db8::a:b:c:d"),
+ nil,
+ },
+ {
+ IPv6unspecified,
+ "::",
+ []byte("::"),
+ nil,
+ },
+
+ // IP wildcard equivalent address in Dial/Listen API
+ {
+ nil,
+ "<nil>",
+ nil,
+ nil,
+ },
+
+ // Opaque byte sequence
+ {
+ IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ "?0123456789abcdef",
+ nil,
+ &AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"},
+ },
}
func TestIPString(t *testing.T) {
for _, tt := range ipStringTests {
- if tt.in != nil {
- if out := tt.in.String(); out != tt.out {
- t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.out)
- }
+ if out := tt.in.String(); out != tt.str {
+ t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.str)
}
- if out, err := tt.in.MarshalText(); string(out) != tt.out || err != nil {
- t.Errorf("IP.MarshalText(%v) = %q, %v, want %q, nil", tt.in, out, err, tt.out)
+ if out, err := tt.in.MarshalText(); !bytes.Equal(out, tt.byt) || !reflect.DeepEqual(err, tt.error) {
+ t.Errorf("IP.MarshalText(%v) = %v, %v, want %v, %v", tt.in, out, err, tt.byt, tt.error)
}
}
}
+var sink string
+
func BenchmarkIPString(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
for i := 0; i < b.N; i++ {
for _, tt := range ipStringTests {
if tt.in != nil {
- tt.in.String()
+ sink = tt.in.String()
}
}
}
@@ -209,7 +305,7 @@ func BenchmarkIPMaskString(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tt := range ipMaskStringTests {
- tt.in.String()
+ sink = tt.in.String()
}
}
}
@@ -240,6 +336,12 @@ var parseCIDRTests = []struct {
{"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"}},
+ {"2001:db8::1/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-0"}},
+ {"-0.0.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "-0.0.0.0/32"}},
+ {"0.-1.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.-1.0.0/32"}},
+ {"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
+ {"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
+ {"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
}
@@ -379,8 +481,8 @@ var splitJoinTests = []struct {
{"", "0", ":0"},
{"google.com", "https%foo", "google.com:https%foo"}, // Go 1.0 behavior
- {"127.0.0.1", "", "127.0.0.1:"}, // Go 1.0 behaviour
- {"www.google.com", "", "www.google.com:"}, // Go 1.0 behaviour
+ {"127.0.0.1", "", "127.0.0.1:"}, // Go 1.0 behavior
+ {"www.google.com", "", "www.google.com:"}, // Go 1.0 behavior
}
var splitFailureTests = []struct {
@@ -421,13 +523,16 @@ func TestSplitHostPort(t *testing.T) {
}
}
for _, tt := range splitFailureTests {
- if _, _, err := SplitHostPort(tt.hostPort); err == nil {
+ if host, port, err := SplitHostPort(tt.hostPort); err == nil {
t.Errorf("SplitHostPort(%q) should have failed", tt.hostPort)
} else {
e := err.(*AddrError)
if e.Err != tt.err {
t.Errorf("SplitHostPort(%q) = _, _, %q; want %q", tt.hostPort, e.Err, tt.err)
}
+ if host != "" || port != "" {
+ t.Errorf("SplitHostPort(%q) = %q, %q, err; want %q, %q, err on failure", tt.hostPort, host, port, "", "")
+ }
}
}
}
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
index f02df7fa8d..d994fc67c6 100644
--- a/libgo/go/net/iprawsock.go
+++ b/libgo/go/net/iprawsock.go
@@ -1,9 +1,32 @@
-// Copyright 2010 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 net
+import (
+ "context"
+ "syscall"
+)
+
+// BUG(mikio): On every POSIX platform, reads from the "ip4" network
+// using the ReadFrom or ReadFromIP method might not return a complete
+// IPv4 packet, including its header, even if there is space
+// available. This can occur even in cases where Read or ReadMsgIP
+// could return a complete packet. For this reason, it is recommended
+// that you do not use these methods if it is important to receive a
+// full packet.
+//
+// The Go 1 compatibility guidelines make it impossible for us to
+// change the behavior of these methods; use Read or ReadMsgIP
+// instead.
+
+// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgIP and
+// WriteMsgIP methods of IPConn are not implemented.
+
+// BUG(mikio): On Windows, the File method of IPConn is not
+// implemented.
+
// IPAddr represents the address of an IP end point.
type IPAddr struct {
IP IP
@@ -41,11 +64,14 @@ func (a *IPAddr) opAddr() Addr {
// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
net = "ip"
}
- afnet, _, err := parseNetwork(net)
+ afnet, _, err := parseNetwork(context.Background(), net)
if err != nil {
return nil, err
}
@@ -54,9 +80,136 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(afnet, addr, noDeadline)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), afnet, addr)
if err != nil {
return nil, err
}
return addrs.first(isIPv4).(*IPAddr), nil
}
+
+// IPConn is the implementation of the Conn and PacketConn interfaces
+// for IP network connections.
+type IPConn struct {
+ conn
+}
+
+// ReadFromIP reads an IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
+func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, addr, err
+}
+
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
+}
+
+// ReadMsgIP reads a packet from c, copying the payload into b and the
+// associated out-of-band data into oob. It returns the number of
+// bytes copied into b, the number of bytes copied into oob, the flags
+// that were set on the packet and the source address of the packet.
+func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, syscall.EINVAL
+ }
+ n, oobn, flags, addr, err = c.readMsg(b, oob)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return
+}
+
+// WriteToIP writes an IP packet to addr via c, copying the payload
+// from b.
+//
+// WriteToIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetWriteDeadline. On packet-oriented connections, write timeouts
+// are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.writeTo(b, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteTo implements the PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ a, ok := addr.(*IPAddr)
+ if !ok {
+ return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+ }
+ n, err := c.writeTo(b, a)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteMsgIP writes a packet to addr via c, copying the payload from
+// b and the associated out-of-band data from oob. It returns the
+// number of payload and out-of-band bytes written.
+func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
+ if !c.ok() {
+ return 0, 0, syscall.EINVAL
+ }
+ n, oobn, err = c.writeMsg(b, oob, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
+
+// DialIP connects to the remote address raddr on the network protocol
+// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
+// and a protocol number or name.
+func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+ c, err := dialIP(context.Background(), netProto, laddr, raddr)
+ if err != nil {
+ return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the local
+// address laddr. The returned connection's ReadFrom and WriteTo
+// methods can be used to receive and send IP packets with per-packet
+// addressing.
+func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
+ c, err := listenIP(context.Background(), netProto, laddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go
index b027adc53a..6aebea169c 100644
--- a/libgo/go/net/iprawsock_plan9.go
+++ b/libgo/go/net/iprawsock_plan9.go
@@ -1,82 +1,34 @@
-// Copyright 2010 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 net
import (
+ "context"
"syscall"
- "time"
)
-// IPConn is the implementation of the Conn and PacketConn interfaces
-// for IP network connections.
-type IPConn struct {
- conn
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
+ return 0, nil, syscall.EPLAN9
}
-// ReadFromIP reads an IP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
+ return 0, 0, 0, nil, syscall.EPLAN9
}
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
+ return 0, syscall.EPLAN9
}
-// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associated out-of-band data into oob. It returns the number of
-// bytes copied into b, the number of bytes copied into oob, the flags
-// that were set on the packet and the source address of the packet.
-func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
- return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
+ return 0, 0, syscall.EPLAN9
}
-// WriteToIP writes an IP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.EPLAN9
}
-// WriteTo implements the PacketConn WriteTo method.
-func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
-}
-
-// WriteMsgIP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob. It returns the
-// number of payload and out-of-band bytes written.
-func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
- return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
-}
-
-// DialIP connects to the remote address raddr on the network protocol
-// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
-// and a protocol number or name.
-func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
- return dialIP(netProto, laddr, raddr, noDeadline)
-}
-
-func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
- return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
-}
-
-// ListenIP listens for incoming IP packets addressed to the local
-// address laddr. The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send IP packets with per-packet
-// addressing.
-func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
- return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.EPLAN9
}
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index 93fee3e232..8f4b702e48 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -7,22 +7,10 @@
package net
import (
+ "context"
"syscall"
- "time"
)
-// BUG(mikio): On every POSIX platform, reads from the "ip4" network
-// using the ReadFrom or ReadFromIP method might not return a complete
-// IPv4 packet, including its header, even if there is space
-// available. This can occur even in cases where Read or ReadMsgIP
-// could return a complete packet. For this reason, it is recommended
-// that you do not uses these methods if it is important to receive a
-// full packet.
-//
-// The Go 1 compatibility guidelines make it impossible for us to
-// change the behavior of these methods; use Read or ReadMsgIP
-// instead.
-
func sockaddrToIP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
@@ -50,25 +38,11 @@ func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0, a.Zone)
}
-// IPConn is the implementation of the Conn and PacketConn interfaces
-// for IP network connections.
-type IPConn struct {
- conn
+func (a *IPAddr) toLocal(net string) sockaddr {
+ return &IPAddr{loopbackIP(net), a.Zone}
}
-func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
-
-// ReadFromIP reads an IP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
var addr *IPAddr
@@ -80,9 +54,6 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
case *syscall.SockaddrInet6:
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return n, addr, err
}
@@ -101,26 +72,7 @@ func stripIPv4Header(n int, b []byte) int {
return n - l
}
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
- n, addr, err := c.ReadFromIP(b)
- if addr == nil {
- return n, nil, err
- }
- return n, addr, err
-}
-
-// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associated out-of-band data into oob. It returns the number of
-// bytes copied into b, the number of bytes copied into oob, the flags
-// that were set on the packet and the source address of the packet.
-func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
- if !c.ok() {
- return 0, 0, 0, nil, syscall.EINVAL
- }
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
var sa syscall.Sockaddr
n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
@@ -129,121 +81,70 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
case *syscall.SockaddrInet6:
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return
}
-// WriteToIP writes an IP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
if c.fd.isConnected {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, ErrWriteToConnected
}
if addr == nil {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+ return 0, errMissingAddress
}
sa, err := addr.sockaddr(c.fd.family)
if err != nil {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ return 0, err
}
- n, err := c.fd.writeTo(b, sa)
- if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- return n, err
+ return c.fd.writeTo(b, sa)
}
-// WriteTo implements the PacketConn WriteTo method.
-func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- a, ok := addr.(*IPAddr)
- if !ok {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
- }
- return c.WriteToIP(b, a)
-}
-
-// WriteMsgIP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob. It returns the
-// number of payload and out-of-band bytes written.
-func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
- if !c.ok() {
- return 0, 0, syscall.EINVAL
- }
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
if c.fd.isConnected {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, 0, ErrWriteToConnected
}
if addr == nil {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+ return 0, 0, errMissingAddress
}
- var sa syscall.Sockaddr
- sa, err = addr.sockaddr(c.fd.family)
- if err != nil {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- n, oobn, err = c.fd.writeMsg(b, oob, sa)
+ sa, err := addr.sockaddr(c.fd.family)
if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ return 0, 0, err
}
- return
-}
-
-// DialIP connects to the remote address raddr on the network protocol
-// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
-// and a protocol number or name.
-func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
- return dialIP(netProto, laddr, raddr, noDeadline)
+ return c.fd.writeMsg(b, oob, sa)
}
-func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
- net, proto, err := parseNetwork(netProto)
+func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+ network, proto, err := parseNetwork(ctx, netProto)
if err != nil {
- return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ return nil, err
}
- switch net {
+ switch network {
case "ip", "ip4", "ip6":
default:
- return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)}
+ return nil, UnknownNetworkError(netProto)
}
if raddr == nil {
- return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+ return nil, errMissingAddress
}
- fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial", noCancel)
+ fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial")
if err != nil {
- return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ return nil, err
}
return newIPConn(fd), nil
}
-// ListenIP listens for incoming IP packets addressed to the local
-// address laddr. The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send IP packets with per-packet
-// addressing.
-func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
- net, proto, err := parseNetwork(netProto)
+func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
+ network, proto, err := parseNetwork(ctx, netProto)
if err != nil {
- return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+ return nil, err
}
- switch net {
+ switch network {
case "ip", "ip4", "ip6":
default:
- return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
+ return nil, UnknownNetworkError(netProto)
}
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen", noCancel)
+ fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen")
if err != nil {
- return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+ return nil, err
}
return newIPConn(fd), nil
}
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/iprawsock_test.go
index 5d86a9d031..5d33b26a91 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/iprawsock_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -43,6 +43,13 @@ var resolveIPAddrTests = []resolveIPAddrTest{
{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
+
+ {"ip4", "2001:db8::1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+ {"ip4:icmp", "2001:db8::1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+ {"ip6", "127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+ {"ip6", "::ffff:127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
+ {"ip6:ipv6-icmp", "127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+ {"ip6:ipv6-icmp", "::ffff:127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
}
func TestResolveIPAddr(t *testing.T) {
@@ -54,21 +61,17 @@ func TestResolveIPAddr(t *testing.T) {
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
- for i, tt := range resolveIPAddrTests {
+ for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
- if err != tt.err {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(addr, tt.addr) {
- t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
- }
- if err != nil {
+ if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ResolveIPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
continue
}
- rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
- if err != nil {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(rtaddr, addr) {
- t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+ if err == nil {
+ addr2, err := ResolveIPAddr(addr.Network(), addr.String())
+ if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+ t.Errorf("(%q, %q): ResolveIPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+ }
}
}
}
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index 55f697f622..f1394a7ed8 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,10 +7,16 @@
package net
import (
- "errors"
- "time"
+ "context"
)
+// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
+// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
+// connections. This is due to the fact that IPv4 traffic will not be
+// routed to an IPv6 socket - two separate sockets are required if
+// both address families are to be supported.
+// See inet6(4) for details.
+
var (
// supportsIPv4 reports whether the platform supports IPv4
// networking functionality.
@@ -22,7 +28,7 @@ var (
// supportsIPv4map reports whether the platform supports
// mapping an IPv4 address inside an IPv6 address at transport
- // layer protocols. See RFC 4291, RFC 4038 and RFC 3493.
+ // layer protocols. See RFC 4291, RFC 4038 and RFC 3493.
supportsIPv4map bool
)
@@ -73,13 +79,11 @@ func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks
return
}
-var errNoSuitableAddress = errors.New("no suitable address found")
-
// filterAddrList applies a filter to a list of IP addresses,
// yielding a list of Addr objects. Known filters are nil, ipv4only,
// and ipv6only. It returns every address when the filter is nil.
// The result contains at least one address when error is nil.
-func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
+func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr, originalAddr string) (addrList, error) {
var addrs addrList
for _, ip := range ips {
if filter == nil || filter(ip) {
@@ -87,92 +91,82 @@ func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr
}
}
if len(addrs) == 0 {
- return nil, errNoSuitableAddress
+ return nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: originalAddr}
}
return addrs, nil
}
-// ipv4only reports whether the kernel supports IPv4 addressing mode
-// and addr is an IPv4 address.
+// ipv4only reports whether addr is an IPv4 address.
func ipv4only(addr IPAddr) bool {
- return supportsIPv4 && addr.IP.To4() != nil
+ return addr.IP.To4() != nil
}
-// ipv6only reports whether the kernel supports IPv6 addressing mode
-// and addr is an IPv6 address except IPv4-mapped IPv6 address.
+// ipv6only reports whether addr is an IPv6 address except IPv4-mapped IPv6 address.
func ipv6only(addr IPAddr) bool {
- return supportsIPv6 && len(addr.IP) == IPv6len && addr.IP.To4() == nil
+ return len(addr.IP) == IPv6len && addr.IP.To4() == nil
}
// SplitHostPort splits a network address of the form "host:port",
// "[host]:port" or "[ipv6-host%zone]:port" into host or
-// ipv6-host%zone and port. A literal address or host name for IPv6
+// ipv6-host%zone and port. A literal address or host name for IPv6
// must be enclosed in square brackets, as in "[::1]:80",
// "[ipv6-host]:http" or "[ipv6-host%zone]:80".
func SplitHostPort(hostport string) (host, port string, err error) {
+ const (
+ missingPort = "missing port in address"
+ tooManyColons = "too many colons in address"
+ )
+ addrErr := func(addr, why string) (host, port string, err error) {
+ return "", "", &AddrError{Err: why, Addr: addr}
+ }
j, k := 0, 0
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
- goto missingPort
+ return addrErr(hostport, missingPort)
}
if hostport[0] == '[' {
// Expect the first ']' just before the last ':'.
end := byteIndex(hostport, ']')
if end < 0 {
- err = &AddrError{Err: "missing ']' in address", Addr: hostport}
- return
+ return addrErr(hostport, "missing ']' in address")
}
switch end + 1 {
case len(hostport):
// There can't be a ':' behind the ']' now.
- goto missingPort
+ return addrErr(hostport, missingPort)
case i:
// The expected result.
default:
// Either ']' isn't followed by a colon, or it is
// followed by a colon that is not the last one.
if hostport[end+1] == ':' {
- goto tooManyColons
+ return addrErr(hostport, tooManyColons)
}
- goto missingPort
+ return addrErr(hostport, missingPort)
}
host = hostport[1:end]
j, k = 1, end+1 // there can't be a '[' resp. ']' before these positions
} else {
host = hostport[:i]
if byteIndex(host, ':') >= 0 {
- goto tooManyColons
+ return addrErr(hostport, tooManyColons)
}
if byteIndex(host, '%') >= 0 {
- goto missingBrackets
+ return addrErr(hostport, "missing brackets in address")
}
}
if byteIndex(hostport[j:], '[') >= 0 {
- err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
- return
+ return addrErr(hostport, "unexpected '[' in address")
}
if byteIndex(hostport[k:], ']') >= 0 {
- err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
- return
+ return addrErr(hostport, "unexpected ']' in address")
}
port = hostport[i+1:]
- return
-
-missingPort:
- err = &AddrError{Err: "missing port in address", Addr: hostport}
- return
-
-tooManyColons:
- err = &AddrError{Err: "too many colons in address", Addr: hostport}
- return
-
-missingBrackets:
- err = &AddrError{Err: "missing brackets in address", Addr: hostport}
- return
+ return host, port, nil
}
func splitHostZone(s string) (host, zone string) {
@@ -201,7 +195,7 @@ func JoinHostPort(host, port string) string {
// address or a DNS name, and returns a list of internet protocol
// family addresses. The result contains at least one address when
// error is nil.
-func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
+func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
var (
err error
host, port string
@@ -213,7 +207,7 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
if host, port, err = SplitHostPort(addr); err != nil {
return nil, err
}
- if portnum, err = LookupPort(net, port); err != nil {
+ if portnum, err = r.LookupPort(ctx, net, port); err != nil {
return nil, err
}
}
@@ -239,20 +233,21 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
if host == "" {
return addrList{inetaddr(IPAddr{})}, nil
}
- // Try as a literal IP address.
- var ip IP
- if ip = parseIPv4(host); ip != nil {
- return addrList{inetaddr(IPAddr{IP: ip})}, nil
- }
- var zone string
- if ip, zone = parseIPv6(host, true); ip != nil {
- return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
- }
- // Try as a DNS name.
- ips, err := lookupIPDeadline(host, deadline)
- if err != nil {
- return nil, err
+
+ // Try as a literal IP address, then as a DNS name.
+ var ips []IPAddr
+ if ip := parseIPv4(host); ip != nil {
+ ips = []IPAddr{{IP: ip}}
+ } else if ip, zone := parseIPv6(host, true); ip != nil {
+ ips = []IPAddr{{IP: ip, Zone: zone}}
+ } else {
+ // Try as a DNS name.
+ ips, err = r.LookupIPAddr(ctx, host)
+ if err != nil {
+ return nil, err
+ }
}
+
var filter func(IPAddr) bool
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
@@ -260,26 +255,12 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
- return filterAddrList(filter, ips, inetaddr)
+ return filterAddrList(filter, ips, inetaddr, host)
}
-func zoneToString(zone int) string {
- if zone == 0 {
- return ""
- }
- if ifi, err := InterfaceByIndex(zone); err == nil {
- return ifi.Name
- }
- return uitoa(uint(zone))
-}
-
-func zoneToInt(zone string) int {
- if zone == "" {
- return 0
- }
- if ifi, err := InterfaceByName(zone); err == nil {
- return ifi.Index
+func loopbackIP(net string) IP {
+ if net != "" && net[len(net)-1] == '6' {
+ return IPv6loopback
}
- n, _, _ := dtoi(zone, 0)
- return n
+ return IP{127, 0, 0, 1}
}
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
index 9da6ec3053..b7fd344c8a 100644
--- a/libgo/go/net/ipsock_plan9.go
+++ b/libgo/go/net/ipsock_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,6 +7,7 @@
package net
import (
+ "context"
"os"
"syscall"
)
@@ -39,8 +40,8 @@ func probeIPv4Stack() bool {
return probe(netdir+"/iproute", "4i")
}
-// probeIPv6Stack returns two boolean values. If the first boolean
-// value is true, kernel supports basic IPv6 functionality. If the
+// probeIPv6Stack returns two boolean values. If the first boolean
+// value is true, kernel supports basic IPv6 functionality. If the
// second boolean value is true, kernel supports IPv6 IPv4-mapping.
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
// Plan 9 uses IPv6 natively, see ip(3).
@@ -62,7 +63,7 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
return nil, 0, &ParseError{Type: "IP address", Text: s}
}
}
- p, _, ok := dtoi(s[i+1:], 0)
+ p, _, ok := dtoi(s[i+1:])
if !ok {
return nil, 0, &ParseError{Type: "port", Text: s}
}
@@ -99,7 +100,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
return addr, nil
}
-func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
+func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
var (
ip IP
port int
@@ -118,7 +119,12 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
return
}
- clone, dest, err := queryCS1(proto, ip, port)
+ if port > 65535 {
+ err = InvalidAddrError("port should be < 65536")
+ return
+ }
+
+ clone, dest, err := queryCS1(ctx, proto, ip, port)
if err != nil {
return
}
@@ -135,8 +141,8 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
return f, dest, proto, string(buf[:n]), nil
}
-func netErr(e error) {
- oe, ok := e.(*OpError)
+func fixErr(err error) {
+ oe, ok := err.(*OpError)
if !ok {
return
}
@@ -165,81 +171,141 @@ func netErr(e error) {
}
}
-func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
- defer func() { netErr(err) }()
- f, dest, proto, name, err := startPlan9(net, raddr)
+func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
+ defer func() { fixErr(err) }()
+ type res struct {
+ fd *netFD
+ err error
+ }
+ resc := make(chan res)
+ go func() {
+ testHookDialChannel()
+ fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
+ select {
+ case resc <- res{fd, err}:
+ case <-ctx.Done():
+ if fd != nil {
+ fd.Close()
+ }
+ }
+ }()
+ select {
+ case res := <-resc:
+ return res.fd, res.err
+ case <-ctx.Done():
+ return nil, mapErr(ctx.Err())
+ }
+}
+
+func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
+ if isWildcard(raddr) {
+ raddr = toLocal(raddr, net)
+ }
+ f, dest, proto, name, err := startPlan9(ctx, net, raddr)
if err != nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+ return nil, err
}
_, err = f.WriteString("connect " + dest)
if err != nil {
f.Close()
- return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
+ return nil, err
}
data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
f.Close()
- return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+ return nil, err
}
laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
data.Close()
f.Close()
- return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
+ return nil, err
}
- return newFD(proto, name, f, data, laddr, raddr)
+ return newFD(proto, name, nil, f, data, laddr, raddr)
}
-func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
- defer func() { netErr(err) }()
- f, dest, proto, name, err := startPlan9(net, laddr)
+func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
+ defer func() { fixErr(err) }()
+ f, dest, proto, name, err := startPlan9(ctx, net, laddr)
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
_, err = f.WriteString("announce " + dest)
if err != nil {
f.Close()
- return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
f.Close()
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
- return newFD(proto, name, f, nil, laddr, nil)
+ return newFD(proto, name, nil, f, nil, laddr, nil)
}
func (fd *netFD) netFD() (*netFD, error) {
- return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
+ return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
}
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
- defer func() { netErr(err) }()
+ defer func() { fixErr(err) }()
if err := fd.readLock(); err != nil {
return nil, err
}
defer fd.readUnlock()
- f, err := os.Open(fd.dir + "/listen")
+ listen, err := os.Open(fd.dir + "/listen")
if err != nil {
- return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+ return nil, err
}
var buf [16]byte
- n, err := f.Read(buf[:])
+ n, err := listen.Read(buf[:])
if err != nil {
- f.Close()
- return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+ listen.Close()
+ return nil, err
}
name := string(buf[:n])
+ ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
+ if err != nil {
+ listen.Close()
+ return nil, err
+ }
data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
- f.Close()
- return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+ listen.Close()
+ ctl.Close()
+ return nil, err
}
raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
if err != nil {
+ listen.Close()
+ ctl.Close()
data.Close()
- f.Close()
- return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+ return nil, err
+ }
+ return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
+}
+
+func isWildcard(a Addr) bool {
+ var wildcard bool
+ switch a := a.(type) {
+ case *TCPAddr:
+ wildcard = a.isWildcard()
+ case *UDPAddr:
+ wildcard = a.isWildcard()
+ case *IPAddr:
+ wildcard = a.isWildcard()
+ }
+ return wildcard
+}
+
+func toLocal(a Addr, net string) Addr {
+ switch a := a.(type) {
+ case *TCPAddr:
+ a.IP = loopbackIP(net)
+ case *UDPAddr:
+ a.IP = loopbackIP(net)
+ case *IPAddr:
+ a.IP = loopbackIP(net)
}
- return newFD(fd.net, name, f, data, fd.laddr, raddr)
+ return a
}
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index 2bddd46a15..ff280c3e4e 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -1,26 +1,17 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
-// Internet protocol family sockets for POSIX
-
package net
import (
+ "context"
"runtime"
"syscall"
- "time"
)
-// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
-// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
-// connections. This is due to the fact that IPv4 traffic will not be
-// routed to an IPv6 socket - two separate sockets are required if
-// both address families are to be supported.
-// See inet6(4) for details.
-
func probeIPv4Stack() bool {
s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
switch err {
@@ -35,15 +26,15 @@ func probeIPv4Stack() bool {
// Should we try to use the IPv4 socket interface if we're
// only dealing with IPv4 sockets? As long as the host system
// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
-// interface. That simplifies our code and is most general.
+// interface. That simplifies our code and is most general.
// Unfortunately, we need to run on kernels built without IPv6
-// support too. So probe the kernel to figure it out.
+// support too. So probe the kernel to figure it out.
//
// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
// mapping capability which is controlled by IPV6_V6ONLY socket
// option and/or kernel state "net.inet6.ip6.v6only".
-// It returns two boolean values. If the first boolean value is
-// true, kernel supports basic IPv6 functionality. If the second
+// It returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
// boolean value is true, kernel supports IPv6 IPv4-mapping.
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
var probes = []struct {
@@ -52,7 +43,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}{
// IPv6 communication capability
{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
- // IPv6 IPv4-mapped address communication capability
+ // IPv4-mapped IPv6 address communication capability
{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
}
var supps [2]bool
@@ -61,7 +52,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
// Some released versions of DragonFly BSD pretend to
// accept IPV6_V6ONLY=0 successfully, but the state
// still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
- // stops preteding, but the transition period would
+ // stops pretending, but the transition period would
// cause unpredictable behavior and we need to avoid
// it.
//
@@ -93,8 +84,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}
// favoriteAddrFamily returns the appropriate address family to
-// the given net, laddr, raddr and mode. At first it figures
-// address family out from the net. If mode indicates "listen"
+// the given net, laddr, raddr and mode. At first it figures
+// address family out from the net. If mode indicates "listen"
// and laddr is a wildcard, it assumes that the user wants to
// make a passive connection with a wildcard address family, both
// AF_INET and AF_INET6, and a wildcard address like following:
@@ -155,10 +146,12 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
}
// Internet sockets (TCP, UDP, IP)
-
-func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, cancel <-chan struct{}) (fd *netFD, err error) {
+func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string) (fd *netFD, err error) {
+ if (runtime.GOOS == "windows" || runtime.GOOS == "openbsd" || runtime.GOOS == "nacl") && mode == "dial" && raddr.isWildcard() {
+ raddr = raddr.toLocal(net)
+ }
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
- return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline, cancel)
+ return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr)
}
func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
@@ -167,34 +160,35 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
if len(ip) == 0 {
ip = IPv4zero
}
- if ip = ip.To4(); ip == nil {
+ ip4 := ip.To4()
+ if ip4 == nil {
return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
}
- sa := new(syscall.SockaddrInet4)
- for i := 0; i < IPv4len; i++ {
- sa.Addr[i] = ip[i]
- }
- sa.Port = port
+ sa := &syscall.SockaddrInet4{Port: port}
+ copy(sa.Addr[:], ip4)
return sa, nil
case syscall.AF_INET6:
- if len(ip) == 0 {
- ip = IPv6zero
- }
- // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
- // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
- // which it refuses to do. Rewrite to the IPv6 unspecified address.
- if ip.Equal(IPv4zero) {
+ // In general, an IP wildcard address, which is either
+ // "0.0.0.0" or "::", means the entire IP addressing
+ // space. For some historical reason, it is used to
+ // specify "any available address" on some operations
+ // of IP node.
+ //
+ // When the IP node supports IPv4-mapped IPv6 address,
+ // we allow an listener to listen to the wildcard
+ // address of both IP addressing spaces by specifying
+ // IPv6 wildcard address.
+ if len(ip) == 0 || ip.Equal(IPv4zero) {
ip = IPv6zero
}
- if ip = ip.To16(); ip == nil {
+ // We accept any IPv6 address including IPv4-mapped
+ // IPv6 address.
+ ip6 := ip.To16()
+ if ip6 == nil {
return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
}
- sa := new(syscall.SockaddrInet6)
- for i := 0; i < IPv6len; i++ {
- sa.Addr[i] = ip[i]
- }
- sa.Port = port
- sa.ZoneId = uint32(zoneToInt(zone))
+ sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneToInt(zone))}
+ copy(sa.Addr[:], ip6)
return sa, nil
}
return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
diff --git a/libgo/go/net/ipsock_test.go b/libgo/go/net/ipsock_test.go
index b36557a157..1d0f00ff5e 100644
--- a/libgo/go/net/ipsock_test.go
+++ b/libgo/go/net/ipsock_test.go
@@ -205,13 +205,13 @@ var addrListTests = []struct {
nil,
},
- {nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {nil, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
- {ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv4only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
+ {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
- {ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv6only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
+ {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
}
func TestAddrList(t *testing.T) {
@@ -220,8 +220,8 @@ func TestAddrList(t *testing.T) {
}
for i, tt := range addrListTests {
- addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
- if err != tt.err {
+ addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr, "ADDR")
+ if !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%v: got %v; want %v", i, err, tt.err)
}
if tt.err != nil {
diff --git a/libgo/go/net/listen_test.go b/libgo/go/net/listen_test.go
index 51ffe67238..6037f3600d 100644
--- a/libgo/go/net/listen_test.go
+++ b/libgo/go/net/listen_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -8,6 +8,7 @@ package net
import (
"fmt"
+ "internal/testenv"
"os"
"runtime"
"syscall"
@@ -157,7 +158,7 @@ var dualStackTCPListenerTests = []struct {
network2, address2 string // second listener
xerr error // expected error value, nil or other
}{
- // Test cases and expected results for the attemping 2nd listen on the same port
+ // Test cases and expected results for the attempting 2nd listen on the same port
// 1st listen 2nd listen darwin freebsd linux openbsd
// ------------------------------------------------------------------------------------
// "tcp" "" "tcp" "" - - - -
@@ -216,9 +217,12 @@ var dualStackTCPListenerTests = []struct {
// TestDualStackTCPListener tests both single and double listen
// to a test listener with various address families, different
// listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
func TestDualStackTCPListener(t *testing.T) {
switch runtime.GOOS {
- case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+ case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv4 || !supportsIPv6 {
@@ -301,11 +305,14 @@ var dualStackUDPListenerTests = []struct {
}
// TestDualStackUDPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
// listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
func TestDualStackUDPListener(t *testing.T) {
switch runtime.GOOS {
- case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+ case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv4 || !supportsIPv6 {
@@ -477,13 +484,12 @@ func checkDualStackAddrFamily(fd *netFD) error {
}
func TestWildWildcardListener(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
defer func() {
if p := recover(); p != nil {
@@ -521,12 +527,17 @@ var ipv4MulticastListenerTests = []struct {
// test listener with same address family, same group address and same
// port.
func TestIPv4MulticastListener(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
switch runtime.GOOS {
case "android", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
case "solaris":
t.Skipf("not supported on solaris, see golang.org/issue/7399")
}
+ if !supportsIPv4 {
+ t.Skip("IPv4 is not supported")
+ }
closer := func(cs []*UDPConn) {
for _, c := range cs {
@@ -542,7 +553,7 @@ func TestIPv4MulticastListener(t *testing.T) {
// routing stuff for finding out an appropriate
// nexthop containing both network and link layer
// adjacencies.
- if ifi == nil && (testing.Short() || !*testExternal) {
+ if ifi == nil || !*testIPv4 {
continue
}
for _, tt := range ipv4MulticastListenerTests {
@@ -591,6 +602,8 @@ var ipv6MulticastListenerTests = []struct {
// test listener with same address family, same group address and same
// port.
func TestIPv6MulticastListener(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -598,7 +611,7 @@ func TestIPv6MulticastListener(t *testing.T) {
t.Skipf("not supported on solaris, see issue 7399")
}
if !supportsIPv6 {
- t.Skip("ipv6 is not supported")
+ t.Skip("IPv6 is not supported")
}
if os.Getuid() != 0 {
t.Skip("must be root")
@@ -618,7 +631,7 @@ func TestIPv6MulticastListener(t *testing.T) {
// routing stuff for finding out an appropriate
// nexthop containing both network and link layer
// adjacencies.
- if ifi == nil && (testing.Short() || !*testExternal || !*testIPv6) {
+ if ifi == nil && !*testIPv6 {
continue
}
for _, tt := range ipv6MulticastListenerTests {
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
index 7aa111ba92..cc2013e432 100644
--- a/libgo/go/net/lookup.go
+++ b/libgo/go/net/lookup.go
@@ -1,12 +1,13 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
+ "context"
+ "internal/nettrace"
"internal/singleflight"
- "time"
)
// protocols contains minimal mappings between internet protocol
@@ -14,17 +15,101 @@ import (
// protocol numbers.
//
// See http://www.iana.org/assignments/protocol-numbers
+//
+// On Unix, this map is augmented by readProtocols via lookupProtocol.
var protocols = map[string]int{
- "icmp": 1, "ICMP": 1,
- "igmp": 2, "IGMP": 2,
- "tcp": 6, "TCP": 6,
- "udp": 17, "UDP": 17,
- "ipv6-icmp": 58, "IPV6-ICMP": 58, "IPv6-ICMP": 58,
+ "icmp": 1,
+ "igmp": 2,
+ "tcp": 6,
+ "udp": 17,
+ "ipv6-icmp": 58,
+}
+
+// services contains minimal mappings between services names and port
+// numbers for platforms that don't have a complete list of port numbers
+// (some Solaris distros, nacl, etc).
+// On Unix, this map is augmented by readServices via goLookupPort.
+var services = map[string]map[string]int{
+ "udp": {
+ "domain": 53,
+ },
+ "tcp": {
+ "ftp": 21,
+ "ftps": 990,
+ "gopher": 70, // ʕ◔ϖ◔ʔ
+ "http": 80,
+ "https": 443,
+ "imap2": 143,
+ "imap3": 220,
+ "imaps": 993,
+ "pop3": 110,
+ "pop3s": 995,
+ "smtp": 25,
+ "ssh": 22,
+ "telnet": 23,
+ },
+}
+
+const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
+
+func lookupProtocolMap(name string) (int, error) {
+ var lowerProtocol [maxProtoLength]byte
+ n := copy(lowerProtocol[:], name)
+ lowerASCIIBytes(lowerProtocol[:n])
+ proto, found := protocols[string(lowerProtocol[:n])]
+ if !found || n != len(name) {
+ return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
+ }
+ return proto, nil
+}
+
+const maxServiceLength = len("mobility-header") + 10 // with room to grow
+
+func lookupPortMap(network, service string) (port int, error error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+
+ if m, ok := services[network]; ok {
+ var lowerService [maxServiceLength]byte
+ n := copy(lowerService[:], service)
+ lowerASCIIBytes(lowerService[:n])
+ if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
+ return port, nil
+ }
+ }
+ return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
+}
+
+// DefaultResolver is the resolver used by the package-level Lookup
+// functions and by Dialers without a specified Resolver.
+var DefaultResolver = &Resolver{}
+
+// A Resolver looks up names and numbers.
+//
+// A nil *Resolver is equivalent to a zero Resolver.
+type Resolver struct {
+ // PreferGo controls whether Go's built-in DNS resolver is preferred
+ // on platforms where it's available. It is equivalent to setting
+ // GODEBUG=netdns=go, but scoped to just this resolver.
+ PreferGo bool
+
+ // TODO(bradfitz): optional interface impl override hook
+ // TODO(bradfitz): Timeout time.Duration?
}
// LookupHost looks up the given host using the local resolver.
-// It returns an array of that host's addresses.
+// It returns a slice of that host's addresses.
func LookupHost(host string) (addrs []string, err error) {
+ return DefaultResolver.LookupHost(context.Background(), host)
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns a slice of that host's addresses.
+func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
// Make sure that no matter what we do later, host=="" is rejected.
// ParseIP, for example, does accept empty strings.
if host == "" {
@@ -33,43 +118,77 @@ func LookupHost(host string) (addrs []string, err error) {
if ip := ParseIP(host); ip != nil {
return []string{host}, nil
}
- return lookupHost(host)
+ return r.lookupHost(ctx, host)
}
// LookupIP looks up host using the local resolver.
-// It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (ips []IP, err error) {
+// It returns a slice of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) ([]IP, error) {
+ addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
+ if err != nil {
+ return nil, err
+ }
+ ips := make([]IP, len(addrs))
+ for i, ia := range addrs {
+ ips[i] = ia.IP
+ }
+ return ips, nil
+}
+
+// LookupIPAddr looks up host using the local resolver.
+// It returns a slice of that host's IPv4 and IPv6 addresses.
+func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
// Make sure that no matter what we do later, host=="" is rejected.
// ParseIP, for example, does accept empty strings.
if host == "" {
return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
}
if ip := ParseIP(host); ip != nil {
- return []IP{ip}, nil
+ return []IPAddr{{IP: ip}}, nil
}
- addrs, err := lookupIPMerge(host)
- if err != nil {
- return
+ trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
+ if trace != nil && trace.DNSStart != nil {
+ trace.DNSStart(host)
}
- ips = make([]IP, len(addrs))
- for i, addr := range addrs {
- ips[i] = addr.IP
+ // The underlying resolver func is lookupIP by default but it
+ // can be overridden by tests. This is needed by net/http, so it
+ // uses a context key instead of unexported variables.
+ resolverFunc := r.lookupIP
+ if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
+ resolverFunc = alt
}
- return
-}
-var lookupGroup singleflight.Group
-
-// lookupIPMerge wraps lookupIP, but makes sure that for any given
-// host, only one lookup is in-flight at a time. The returned memory
-// is always owned by the caller.
-func lookupIPMerge(host string) (addrs []IPAddr, err error) {
- addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
- return testHookLookupIP(lookupIP, host)
+ ch := lookupGroup.DoChan(host, func() (interface{}, error) {
+ return testHookLookupIP(ctx, resolverFunc, host)
})
- return lookupIPReturn(addrsi, err, shared)
+
+ select {
+ case <-ctx.Done():
+ // The DNS lookup timed out for some reason. Force
+ // future requests to start the DNS lookup again
+ // rather than waiting for the current lookup to
+ // complete. See issue 8602.
+ err := mapErr(ctx.Err())
+ lookupGroup.Forget(host)
+ if trace != nil && trace.DNSDone != nil {
+ trace.DNSDone(nil, false, err)
+ }
+ return nil, err
+ case r := <-ch:
+ if trace != nil && trace.DNSDone != nil {
+ addrs, _ := r.Val.([]IPAddr)
+ trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
+ }
+ return lookupIPReturn(r.Val, r.Err, r.Shared)
+ }
}
+// lookupGroup merges LookupIPAddr calls together for lookups
+// for the same host. The lookupGroup key is is the LookupIPAddr.host
+// argument.
+// The return values are ([]IPAddr, error).
+var lookupGroup singleflight.Group
+
// lookupIPReturn turns the return values from singleflight.Do into
// the return values from LookupIP.
func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
@@ -85,52 +204,25 @@ func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error
return addrs, nil
}
-// lookupIPDeadline looks up a hostname with a deadline.
-func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) {
- if deadline.IsZero() {
- return lookupIPMerge(host)
- }
-
- // We could push the deadline down into the name resolution
- // functions. However, the most commonly used implementation
- // calls getaddrinfo, which has no timeout.
-
- timeout := deadline.Sub(time.Now())
- if timeout <= 0 {
- return nil, errTimeout
- }
- t := time.NewTimer(timeout)
- defer t.Stop()
-
- ch := lookupGroup.DoChan(host, func() (interface{}, error) {
- return testHookLookupIP(lookupIP, host)
- })
-
- select {
- case <-t.C:
- // The DNS lookup timed out for some reason. Force
- // future requests to start the DNS lookup again
- // rather than waiting for the current lookup to
- // complete. See issue 8602.
- lookupGroup.Forget(host)
-
- return nil, errTimeout
-
- case r := <-ch:
- return lookupIPReturn(r.Val, r.Err, r.Shared)
+// ipAddrsEface returns an empty interface slice of addrs.
+func ipAddrsEface(addrs []IPAddr) []interface{} {
+ s := make([]interface{}, len(addrs))
+ for i, v := range addrs {
+ s[i] = v
}
+ return s
}
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err error) {
- if service == "" {
- // Lock in the legacy behavior that an empty string
- // means port 0. See Issue 13610.
- return 0, nil
- }
- port, _, ok := dtoi(service, 0)
- if !ok && port != big && port != -big {
- port, err = lookupPort(network, service)
+ return DefaultResolver.LookupPort(context.Background(), network, service)
+}
+
+// LookupPort looks up the port for the given network and service.
+func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
+ port, needsLookup := parsePort(service)
+ if needsLookup {
+ port, err = r.lookupPort(ctx, network, service)
if err != nil {
return 0, err
}
@@ -141,44 +233,101 @@ func LookupPort(network, service string) (port int, err error) {
return port, nil
}
-// LookupCNAME returns the canonical DNS host for the given name.
+// LookupCNAME returns the canonical name for the given host.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+//
+// A canonical name is the final name after following zero
+// or more CNAME records.
+// LookupCNAME does not return an error if host does not
+// contain DNS "CNAME" records, as long as host resolves to
+// address records.
+func LookupCNAME(host string) (cname string, err error) {
+ return DefaultResolver.lookupCNAME(context.Background(), host)
+}
+
+// LookupCNAME returns the canonical name for the given host.
// Callers that do not care about the canonical name can call
// LookupHost or LookupIP directly; both take care of resolving
// the canonical name as part of the lookup.
-func LookupCNAME(name string) (cname string, err error) {
- return lookupCNAME(name)
+//
+// A canonical name is the final name after following zero
+// or more CNAME records.
+// LookupCNAME does not return an error if host does not
+// contain DNS "CNAME" records, as long as host resolves to
+// address records.
+func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
+ return r.lookupCNAME(ctx, host)
}
// LookupSRV tries to resolve an SRV query of the given service,
-// protocol, and domain name. The proto is "tcp" or "udp".
+// protocol, and domain name. The proto is "tcp" or "udp".
// The returned records are sorted by priority and randomized
// by weight within a priority.
//
// LookupSRV constructs the DNS name to look up following RFC 2782.
-// That is, it looks up _service._proto.name. To accommodate services
+// That is, it looks up _service._proto.name. To accommodate services
// publishing SRV records under non-standard names, if both service
// and proto are empty strings, LookupSRV looks up name directly.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
- return lookupSRV(service, proto, name)
+ return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name. The proto is "tcp" or "udp".
+// The returned records are sorted by priority and randomized
+// by weight within a priority.
+//
+// LookupSRV constructs the DNS name to look up following RFC 2782.
+// That is, it looks up _service._proto.name. To accommodate services
+// publishing SRV records under non-standard names, if both service
+// and proto are empty strings, LookupSRV looks up name directly.
+func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
+ return r.lookupSRV(ctx, service, proto, name)
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) ([]*MX, error) {
+ return DefaultResolver.lookupMX(context.Background(), name)
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mxs []*MX, err error) {
- return lookupMX(name)
+func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
+ return r.lookupMX(ctx, name)
}
// LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (nss []*NS, err error) {
- return lookupNS(name)
+func LookupNS(name string) ([]*NS, error) {
+ return DefaultResolver.lookupNS(context.Background(), name)
+}
+
+// LookupNS returns the DNS NS records for the given domain name.
+func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
+ return r.lookupNS(ctx, name)
+}
+
+// LookupTXT returns the DNS TXT records for the given domain name.
+func LookupTXT(name string) ([]string, error) {
+ return DefaultResolver.lookupTXT(context.Background(), name)
}
// LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txts []string, err error) {
- return lookupTXT(name)
+func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
+ return r.lookupTXT(ctx, name)
}
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
+//
+// When using the host C library resolver, at most one result will be
+// returned. To bypass the host resolver, use a custom Resolver.
func LookupAddr(addr string) (names []string, err error) {
- return lookupAddr(addr)
+ return DefaultResolver.lookupAddr(context.Background(), addr)
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
+ return r.lookupAddr(ctx, addr)
}
diff --git a/libgo/go/net/lookup_nacl.go b/libgo/go/net/lookup_nacl.go
new file mode 100644
index 0000000000..43cebad760
--- /dev/null
+++ b/libgo/go/net/lookup_nacl.go
@@ -0,0 +1,52 @@
+// 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.
+
+// +build nacl
+
+package net
+
+import (
+ "context"
+ "syscall"
+)
+
+func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
+ return lookupProtocolMap(name)
+}
+
+func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
+ return goLookupPort(network, service)
+}
+
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
+ return "", syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, srvs []*SRV, err error) {
+ return "", nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupMX(ctx context.Context, name string) (mxs []*MX, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupNS(ctx context.Context, name string) (nss []*NS, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupTXT(ctx context.Context, name string) (txts []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
index a33162882b..f81e220fc8 100644
--- a/libgo/go/net/lookup_plan9.go
+++ b/libgo/go/net/lookup_plan9.go
@@ -1,22 +1,24 @@
-// Copyright 2011 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 net
import (
+ "context"
"errors"
+ "io"
"os"
)
-func query(filename, query string, bufSize int) (res []string, err error) {
+func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
file, err := os.OpenFile(filename, os.O_RDWR, 0)
if err != nil {
return
}
defer file.Close()
- _, err = file.Seek(0, 0)
+ _, err = file.Seek(0, io.SeekStart)
if err != nil {
return
}
@@ -24,7 +26,7 @@ func query(filename, query string, bufSize int) (res []string, err error) {
if err != nil {
return
}
- _, err = file.Seek(0, 0)
+ _, err = file.Seek(0, io.SeekStart)
if err != nil {
return
}
@@ -39,7 +41,7 @@ func query(filename, query string, bufSize int) (res []string, err error) {
return
}
-func queryCS(net, host, service string) (res []string, err error) {
+func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
switch net {
case "tcp4", "tcp6":
net = "tcp"
@@ -49,15 +51,15 @@ func queryCS(net, host, service string) (res []string, err error) {
if host == "" {
host = "*"
}
- return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
+ return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
}
-func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
+func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
ips := "*"
if len(ip) != 0 && !ip.IsUnspecified() {
ips = ip.String()
}
- lines, err := queryCS(net, ips, itoa(port))
+ lines, err := queryCS(ctx, net, ips, itoa(port))
if err != nil {
return
}
@@ -69,8 +71,8 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
return
}
-func queryDNS(addr string, typ string) (res []string, err error) {
- return query(netdir+"/dns", addr+" "+typ, 1024)
+func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
+ return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
}
// toLower returns a lower-case version of in. Restricting us to
@@ -96,8 +98,8 @@ func toLower(in string) string {
// lookupProtocol looks up IP protocol name and returns
// the corresponding protocol number.
-func lookupProtocol(name string) (proto int, err error) {
- lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
+func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
+ lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
if err != nil {
return 0, err
}
@@ -109,17 +111,20 @@ func lookupProtocol(name string) (proto int, err error) {
return 0, UnknownNetworkError(name)
}
s := f[1]
- if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
+ if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
return n, nil
}
return 0, UnknownNetworkError(name)
}
-func lookupHost(host string) (addrs []string, err error) {
+func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
// Use netdir/cs instead of netdir/dns because cs knows about
// host names in local network (e.g. from /lib/ndb/local)
- lines, err := queryCS("net", host, "1")
+ lines, err := queryCS(ctx, "net", host, "1")
if err != nil {
+ if stringsHasSuffix(err.Error(), "dns failure") {
+ err = errNoSuchHost
+ }
return
}
loop:
@@ -146,8 +151,8 @@ loop:
return
}
-func lookupIP(host string) (addrs []IPAddr, err error) {
- lits, err := LookupHost(host)
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ lits, err := r.lookupHost(ctx, host)
if err != nil {
return
}
@@ -161,14 +166,14 @@ func lookupIP(host string) (addrs []IPAddr, err error) {
return
}
-func lookupPort(network, service string) (port int, err error) {
+func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
case "udp4", "udp6":
network = "udp"
}
- lines, err := queryCS(network, "127.0.0.1", service)
+ lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
if err != nil {
return
}
@@ -184,15 +189,19 @@ func lookupPort(network, service string) (port int, err error) {
if i := byteIndex(s, '!'); i >= 0 {
s = s[i+1:] // remove address
}
- if n, _, ok := dtoi(s, 0); ok {
+ if n, _, ok := dtoi(s); ok {
return n, nil
}
return 0, unknownPortError
}
-func lookupCNAME(name string) (cname string, err error) {
- lines, err := queryDNS(name, "cname")
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
+ lines, err := queryDNS(ctx, name, "cname")
if err != nil {
+ if stringsHasSuffix(err.Error(), "dns failure") {
+ cname = name + "."
+ err = nil
+ }
return
}
if len(lines) > 0 {
@@ -203,14 +212,14 @@ func lookupCNAME(name string) (cname string, err error) {
return "", errors.New("bad response from ndb/dns")
}
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
var target string
if service == "" && proto == "" {
target = name
} else {
target = "_" + service + "._" + proto + "." + name
}
- lines, err := queryDNS(target, "srv")
+ lines, err := queryDNS(ctx, target, "srv")
if err != nil {
return
}
@@ -219,9 +228,9 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
if len(f) < 6 {
continue
}
- port, _, portOk := dtoi(f[4], 0)
- priority, _, priorityOk := dtoi(f[3], 0)
- weight, _, weightOk := dtoi(f[2], 0)
+ port, _, portOk := dtoi(f[4])
+ priority, _, priorityOk := dtoi(f[3])
+ weight, _, weightOk := dtoi(f[2])
if !(portOk && priorityOk && weightOk) {
continue
}
@@ -232,8 +241,8 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
return
}
-func lookupMX(name string) (mx []*MX, err error) {
- lines, err := queryDNS(name, "mx")
+func (*Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
+ lines, err := queryDNS(ctx, name, "mx")
if err != nil {
return
}
@@ -242,7 +251,7 @@ func lookupMX(name string) (mx []*MX, err error) {
if len(f) < 4 {
continue
}
- if pref, _, ok := dtoi(f[2], 0); ok {
+ if pref, _, ok := dtoi(f[2]); ok {
mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
}
}
@@ -250,8 +259,8 @@ func lookupMX(name string) (mx []*MX, err error) {
return
}
-func lookupNS(name string) (ns []*NS, err error) {
- lines, err := queryDNS(name, "ns")
+func (*Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
+ lines, err := queryDNS(ctx, name, "ns")
if err != nil {
return
}
@@ -265,8 +274,8 @@ func lookupNS(name string) (ns []*NS, err error) {
return
}
-func lookupTXT(name string) (txt []string, err error) {
- lines, err := queryDNS(name, "txt")
+func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
+ lines, err := queryDNS(ctx, name, "txt")
if err != nil {
return
}
@@ -278,12 +287,12 @@ func lookupTXT(name string) (txt []string, err error) {
return
}
-func lookupAddr(addr string) (name []string, err error) {
+func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, err error) {
arpa, err := reverseaddr(addr)
if err != nil {
return
}
- lines, err := queryDNS(arpa, "ptr")
+ lines, err := queryDNS(ctx, arpa, "ptr")
if err != nil {
return
}
diff --git a/libgo/go/net/lookup_stub.go b/libgo/go/net/lookup_stub.go
deleted file mode 100644
index 5636198f88..0000000000
--- a/libgo/go/net/lookup_stub.go
+++ /dev/null
@@ -1,49 +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.
-
-// +build nacl
-
-package net
-
-import "syscall"
-
-func lookupProtocol(name string) (proto int, err error) {
- return 0, syscall.ENOPROTOOPT
-}
-
-func lookupHost(host string) (addrs []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupIP(host string) (addrs []IPAddr, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupPort(network, service string) (port int, err error) {
- return 0, syscall.ENOPROTOOPT
-}
-
-func lookupCNAME(name string) (cname string, err error) {
- return "", syscall.ENOPROTOOPT
-}
-
-func lookupSRV(service, proto, name string) (cname string, srvs []*SRV, err error) {
- return "", nil, syscall.ENOPROTOOPT
-}
-
-func lookupMX(name string) (mxs []*MX, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupNS(name string) (nss []*NS, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupTXT(name string) (txts []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupAddr(addr string) (ptrs []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 439496ac81..36db56acd0 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -6,6 +6,7 @@ package net
import (
"bytes"
+ "context"
"fmt"
"internal/testenv"
"runtime"
@@ -14,7 +15,7 @@ import (
"time"
)
-func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+func lookupLocalhost(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
switch host {
case "localhost":
return []IPAddr{
@@ -22,7 +23,7 @@ func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr,
{IP: IPv6loopback},
}, nil
default:
- return fn(host)
+ return fn(ctx, host)
}
}
@@ -58,9 +59,10 @@ var lookupGoogleSRVTests = []struct {
}
func TestLookupGoogleSRV(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -68,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 {
@@ -92,9 +95,10 @@ var lookupGmailMXTests = []struct {
}
func TestLookupGmailMX(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -123,9 +127,10 @@ var lookupGmailNSTests = []struct {
}
func TestLookupGmailNS(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -133,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 {
@@ -154,9 +160,10 @@ var lookupGmailTXTTests = []struct {
}
func TestLookupGmailTXT(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -188,9 +195,10 @@ var lookupGooglePublicDNSAddrTests = []struct {
}
func TestLookupGooglePublicDNSAddr(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
@@ -235,22 +243,24 @@ func TestLookupIPv6LinkLocalAddr(t *testing.T) {
}
}
-var lookupIANACNAMETests = []struct {
+var lookupCNAMETests = []struct {
name, cname string
}{
{"www.iana.org", "icann.org."},
{"www.iana.org.", "icann.org."},
+ {"www.google.com", "google.com."},
}
-func TestLookupIANACNAME(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+func TestLookupCNAME(t *testing.T) {
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
- for _, tt := range lookupIANACNAMETests {
+ for _, tt := range lookupCNAMETests {
cname, err := LookupCNAME(tt.name)
if err != nil {
t.Fatal(err)
@@ -269,9 +279,10 @@ var lookupGoogleHostTests = []struct {
}
func TestLookupGoogleHost(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -300,9 +311,10 @@ var lookupGoogleIPTests = []struct {
}
func TestLookupGoogleIP(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -360,22 +372,38 @@ 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()
+ ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+
c := make(chan error, 2*N)
for i := 0; i < N; i++ {
name := fmt.Sprintf("%d.net-test.golang.org", i)
go func() {
- _, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
+ _, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name)
c <- err
}()
go func() {
- _, err := lookupIPDeadline(name, time.Now().Add(timeout))
+ _, err := DefaultResolver.LookupIPAddr(ctxTimeout, name)
c <- err
}()
}
@@ -426,6 +454,10 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
t.Skip("IPv4 is required")
}
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
+ }
+
for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
fixup := fn()
if fixup == nil {
@@ -463,9 +495,10 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
}
func TestLookupDotsWithRemoteSource(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" || !*testExternal {
- t.Skip("avoid external network")
+ if testenv.Builder() == "" {
+ testenv.MustHaveExternalNetwork(t)
}
+
if !supportsIPv4 || !*testIPv4 {
t.Skip("IPv4 is required")
}
@@ -483,6 +516,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 {
@@ -494,12 +528,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 {
@@ -512,6 +550,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 {
@@ -524,6 +563,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.") {
@@ -574,61 +614,128 @@ 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},
-
- // 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 test cases.
+ // 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)
+ case "android":
+ 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 {
- t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port)
+ 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)
+ }
+ }
+ }
+}
+
+// Like TestLookupPort but with minimal tests that should always pass
+// because the answers are baked-in to the net package.
+func TestLookupPort_Minimal(t *testing.T) {
+ type test struct {
+ network string
+ name string
+ port int
+ }
+ var tests = []test{
+ {"tcp", "http", 80},
+ {"tcp", "HTTP", 80}, // case shouldn't matter
+ {"tcp", "https", 443},
+ {"tcp", "ssh", 22},
+ {"tcp", "gopher", 70},
+ {"tcp4", "http", 80},
+ {"tcp6", "http", 80},
+ }
+
+ for _, tt := range tests {
+ port, err := LookupPort(tt.network, tt.name)
+ if port != tt.port || err != nil {
+ t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port)
+ }
+ }
+}
+
+func TestLookupProtocol_Minimal(t *testing.T) {
+ type test struct {
+ name string
+ want int
+ }
+ var tests = []test{
+ {"tcp", 6},
+ {"TcP", 6}, // case shouldn't matter
+ {"icmp", 1},
+ {"igmp", 2},
+ {"udp", 17},
+ {"ipv6-icmp", 58},
+ }
+
+ for _, tt := range tests {
+ got, err := lookupProtocol(context.Background(), tt.name)
+ if got != tt.want || err != nil {
+ t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
+ }
+ }
+
+}
+
+func TestLookupNonLDH(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skip on nacl")
+ }
+ if fixup := forceGoDNS(); fixup != nil {
+ defer fixup()
+ }
+
+ // "LDH" stands for letters, digits, and hyphens and is the usual
+ // description of standard DNS names.
+ // This test is checking that other kinds of names are reported
+ // as not found, not reported as invalid names.
+ addrs, err := LookupHost("!!!.###.bogus..domain.")
+ if err == nil {
+ t.Fatalf("lookup succeeded: %v", addrs)
+ }
+ if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) {
+ t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
}
}
diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
index a64da8bcb5..be2ced9c39 100644
--- a/libgo/go/net/lookup_unix.go
+++ b/libgo/go/net/lookup_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -6,7 +6,10 @@
package net
-import "sync"
+import (
+ "context"
+ "sync"
+)
var onceReadProtocols sync.Once
@@ -23,7 +26,7 @@ func readProtocols() {
if len(f) < 2 {
continue
}
- if proto, _, ok := dtoi(f[1], 0); ok {
+ if proto, _, ok := dtoi(f[1]); ok {
if _, ok := protocols[f[0]]; !ok {
protocols[f[0]] = proto
}
@@ -40,65 +43,72 @@ func readProtocols() {
// lookupProtocol looks up IP protocol name in /etc/protocols and
// returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(_ context.Context, name string) (int, error) {
onceReadProtocols.Do(readProtocols)
- proto, found := protocols[name]
- if !found {
- return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
- }
- return proto, nil
+ return lookupProtocolMap(name)
}
-func lookupHost(host string) (addrs []string, err error) {
+func (r *Resolver) 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 !r.PreferGo && order == hostLookupCgo {
+ if addrs, err, ok := cgoLookupHost(ctx, host); ok {
return addrs, err
}
// cgo not available (or netgo); fall back to Go's DNS resolver
order = hostLookupFilesDNS
}
- return goLookupHostOrder(host, order)
+ return goLookupHostOrder(ctx, host, order)
}
-func lookupIP(host string) (addrs []IPAddr, err error) {
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ if r.PreferGo {
+ return goLookupIP(ctx, host)
+ }
order := systemConf().hostLookupOrder(host)
if order == hostLookupCgo {
- 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
order = hostLookupFilesDNS
}
- return goLookupIPOrder(host, order)
+ addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+ return
}
-func lookupPort(network, service string) (int, error) {
- if systemConf().canUseCgo() {
- if port, err, ok := cgoLookupPort(network, service); ok {
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
+ if !r.PreferGo && systemConf().canUseCgo() {
+ if port, err, ok := cgoLookupPort(ctx, network, service); ok {
+ if err != nil {
+ // Issue 18213: if cgo fails, first check to see whether we
+ // have the answer baked-in to the net package.
+ if port, err := goLookupPort(network, service); err == nil {
+ return port, nil
+ }
+ }
return port, err
}
}
return goLookupPort(network, service)
}
-func lookupCNAME(name string) (string, error) {
- if systemConf().canUseCgo() {
- if cname, err, ok := cgoLookupCNAME(name); ok {
+func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
+ if !r.PreferGo && systemConf().canUseCgo() {
+ if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
return cname, err
}
}
- return goLookupCNAME(name)
+ return goLookupCNAME(ctx, name)
}
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
var target string
if service == "" && proto == "" {
target = name
} else {
target = "_" + service + "._" + proto + "." + name
}
- cname, rrs, err := lookup(target, dnsTypeSRV)
+ cname, rrs, err := lookup(ctx, target, dnsTypeSRV)
if err != nil {
return "", nil, err
}
@@ -111,8 +121,8 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
return cname, srvs, nil
}
-func lookupMX(name string) ([]*MX, error) {
- _, rrs, err := lookup(name, dnsTypeMX)
+func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
+ _, rrs, err := lookup(ctx, name, dnsTypeMX)
if err != nil {
return nil, err
}
@@ -125,8 +135,8 @@ func lookupMX(name string) ([]*MX, error) {
return mxs, nil
}
-func lookupNS(name string) ([]*NS, error) {
- _, rrs, err := lookup(name, dnsTypeNS)
+func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
+ _, rrs, err := lookup(ctx, name, dnsTypeNS)
if err != nil {
return nil, err
}
@@ -137,8 +147,8 @@ func lookupNS(name string) ([]*NS, error) {
return nss, nil
}
-func lookupTXT(name string) ([]string, error) {
- _, rrs, err := lookup(name, dnsTypeTXT)
+func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
+ _, rrs, err := lookup(ctx, name, dnsTypeTXT)
if err != nil {
return nil, err
}
@@ -149,11 +159,11 @@ func lookupTXT(name string) ([]string, error) {
return txts, nil
}
-func lookupAddr(addr string) ([]string, error) {
- if systemConf().canUseCgo() {
- if ptrs, err, ok := cgoLookupPTR(addr); ok {
+func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
+ if !r.PreferGo && systemConf().canUseCgo() {
+ if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
return ptrs, err
}
}
- return goLookupPTR(addr)
+ return goLookupPTR(ctx, addr)
}
diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go
index 13edc264e8..5808293058 100644
--- a/libgo/go/net/lookup_windows.go
+++ b/libgo/go/net/lookup_windows.go
@@ -5,54 +5,67 @@
package net
import (
+ "context"
"os"
"runtime"
"syscall"
"unsafe"
)
-var (
- lookupPort = oldLookupPort
- lookupIP = oldLookupIP
-)
+const _WSAHOST_NOT_FOUND = syscall.Errno(11001)
+
+func winError(call string, err error) error {
+ switch err {
+ case _WSAHOST_NOT_FOUND:
+ return errNoSuchHost
+ }
+ return os.NewSyscallError(call, err)
+}
func getprotobyname(name string) (proto int, err error) {
p, err := syscall.GetProtoByName(name)
if err != nil {
- return 0, os.NewSyscallError("getprotobyname", err)
+ return 0, winError("getprotobyname", err)
}
return int(p.Proto), nil
}
// lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(ctx context.Context, name string) (int, error) {
// GetProtoByName return value is stored in thread local storage.
// Start new os thread before the call to prevent races.
type result struct {
proto int
err error
}
- ch := make(chan result)
+ ch := make(chan result) // unbuffered
go func() {
acquireThread()
defer releaseThread()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
proto, err := getprotobyname(name)
- ch <- result{proto: proto, err: err}
+ select {
+ case ch <- result{proto: proto, err: err}:
+ case <-ctx.Done():
+ }
}()
- r := <-ch
- if r.err != nil {
- if proto, ok := protocols[name]; ok {
- return proto, nil
+ select {
+ case r := <-ch:
+ if r.err != nil {
+ if proto, err := lookupProtocolMap(name); err == nil {
+ return proto, nil
+ }
+ r.err = &DNSError{Err: r.err.Error(), Name: name}
}
- r.err = &DNSError{Err: r.err.Error(), Name: name}
+ return r.proto, r.err
+ case <-ctx.Done():
+ return 0, mapErr(ctx.Err())
}
- return r.proto, r.err
}
-func lookupHost(name string) ([]string, error) {
- ips, err := LookupIP(name)
+func (r *Resolver) lookupHost(ctx context.Context, name string) ([]string, error) {
+ ips, err := r.lookupIP(ctx, name)
if err != nil {
return nil, err
}
@@ -63,121 +76,71 @@ func lookupHost(name string) ([]string, error) {
return addrs, nil
}
-func gethostbyname(name string) (addrs []IPAddr, err error) {
- // caller already acquired thread
- h, err := syscall.GetHostByName(name)
- if err != nil {
- return nil, os.NewSyscallError("gethostbyname", err)
- }
- switch h.AddrType {
- case syscall.AF_INET:
- i := 0
- addrs = make([]IPAddr, 100) // plenty of room to grow
- for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
- addrs[i] = IPAddr{IP: IPv4(p[i][0], p[i][1], p[i][2], p[i][3])}
- }
- addrs = addrs[0:i]
- default: // TODO(vcc): Implement non IPv4 address lookups.
- return nil, syscall.EWINDOWS
- }
- return addrs, nil
-}
+func (r *Resolver) lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
+ // TODO(bradfitz,brainman): use ctx more. See TODO below.
-func oldLookupIP(name string) ([]IPAddr, error) {
- // GetHostByName return value is stored in thread local storage.
- // Start new os thread before the call to prevent races.
- type result struct {
+ type ret struct {
addrs []IPAddr
err error
}
- ch := make(chan result)
+ ch := make(chan ret, 1)
go func() {
acquireThread()
defer releaseThread()
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
- addrs, err := gethostbyname(name)
- ch <- result{addrs: addrs, err: err}
+ hints := syscall.AddrinfoW{
+ Family: syscall.AF_UNSPEC,
+ Socktype: syscall.SOCK_STREAM,
+ Protocol: syscall.IPPROTO_IP,
+ }
+ var result *syscall.AddrinfoW
+ e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
+ if e != nil {
+ ch <- ret{err: &DNSError{Err: winError("getaddrinfow", e).Error(), Name: name}}
+ }
+ defer syscall.FreeAddrInfoW(result)
+ addrs := make([]IPAddr, 0, 5)
+ for ; result != nil; result = result.Next {
+ addr := unsafe.Pointer(result.Addr)
+ switch result.Family {
+ case syscall.AF_INET:
+ a := (*syscall.RawSockaddrInet4)(addr).Addr
+ addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
+ case syscall.AF_INET6:
+ a := (*syscall.RawSockaddrInet6)(addr).Addr
+ zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
+ addrs = append(addrs, IPAddr{IP: IP{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]}, Zone: zone})
+ default:
+ ch <- ret{err: &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}}
+ }
+ }
+ ch <- ret{addrs: addrs}
}()
- r := <-ch
- if r.err != nil {
- r.err = &DNSError{Err: r.err.Error(), Name: name}
- }
- return r.addrs, r.err
-}
-
-func newLookupIP(name string) ([]IPAddr, error) {
- acquireThread()
- defer releaseThread()
- hints := syscall.AddrinfoW{
- Family: syscall.AF_UNSPEC,
- Socktype: syscall.SOCK_STREAM,
- Protocol: syscall.IPPROTO_IP,
- }
- var result *syscall.AddrinfoW
- e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
- if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}
- }
- defer syscall.FreeAddrInfoW(result)
- addrs := make([]IPAddr, 0, 5)
- for ; result != nil; result = result.Next {
- addr := unsafe.Pointer(result.Addr)
- switch result.Family {
- case syscall.AF_INET:
- a := (*syscall.RawSockaddrInet4)(addr).Addr
- addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
- case syscall.AF_INET6:
- a := (*syscall.RawSockaddrInet6)(addr).Addr
- zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
- addrs = append(addrs, IPAddr{IP: IP{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]}, Zone: zone})
- default:
- return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
+ select {
+ case r := <-ch:
+ return r.addrs, r.err
+ case <-ctx.Done():
+ // TODO(bradfitz,brainman): cancel the ongoing
+ // GetAddrInfoW? It would require conditionally using
+ // GetAddrInfoEx with lpOverlapped, which requires
+ // Windows 8 or newer. I guess we'll need oldLookupIP,
+ // newLookupIP, and newerLookUP.
+ //
+ // For now we just let it finish and write to the
+ // buffered channel.
+ return nil, &DNSError{
+ Name: name,
+ Err: ctx.Err().Error(),
+ IsTimeout: ctx.Err() == context.DeadlineExceeded,
}
}
- return addrs, nil
-}
-
-func getservbyname(network, service string) (int, error) {
- acquireThread()
- defer releaseThread()
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
- }
- s, err := syscall.GetServByName(service, network)
- if err != nil {
- return 0, os.NewSyscallError("getservbyname", err)
- }
- return int(syscall.Ntohs(s.Port)), nil
}
-func oldLookupPort(network, service string) (int, error) {
- // GetServByName return value is stored in thread local storage.
- // Start new os thread before the call to prevent races.
- type result struct {
- port int
- err error
- }
- ch := make(chan result)
- go func() {
- acquireThread()
- defer releaseThread()
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
- port, err := getservbyname(network, service)
- ch <- result{port: port, err: err}
- }()
- r := <-ch
- if r.err != nil {
- r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
+ if r.PreferGo {
+ return lookupPortMap(network, service)
}
- return r.port, r.err
-}
-func newLookupPort(network, service string) (int, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var stype int32
@@ -195,7 +158,10 @@ func newLookupPort(network, service string) (int, error) {
var result *syscall.AddrinfoW
e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
if e != nil {
- return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service}
+ if port, err := lookupPortMap(network, service); err == nil {
+ return port, nil
+ }
+ return 0, &DNSError{Err: winError("getaddrinfow", e).Error(), Name: network + "/" + service}
}
defer syscall.FreeAddrInfoW(result)
if result == nil {
@@ -213,7 +179,8 @@ func newLookupPort(network, service string) (int, error) {
return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
}
-func lookupCNAME(name string) (string, error) {
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
@@ -224,7 +191,7 @@ func lookupCNAME(name string) (string, error) {
return absDomainName([]byte(name)), nil
}
if e != nil {
- return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return "", &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -233,7 +200,8 @@ func lookupCNAME(name string) (string, error) {
return absDomainName([]byte(cname)), nil
}
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var target string
@@ -245,7 +213,7 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
if e != nil {
- return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target}
+ return "", nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: target}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -258,13 +226,14 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
return absDomainName([]byte(target)), srvs, nil
}
-func lookupMX(name string) ([]*MX, error) {
+func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -277,13 +246,14 @@ func lookupMX(name string) ([]*MX, error) {
return mxs, nil
}
-func lookupNS(name string) ([]*NS, error) {
+func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -295,13 +265,14 @@ func lookupNS(name string) ([]*NS, error) {
return nss, nil
}
-func lookupTXT(name string) ([]string, error) {
+func (*Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -316,7 +287,8 @@ func lookupTXT(name string) ([]string, error) {
return txts, nil
}
-func lookupAddr(addr string) ([]string, error) {
+func (*Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
+ // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
arpa, err := reverseaddr(addr)
@@ -326,7 +298,7 @@ func lookupAddr(addr string) ([]string, error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: addr}
}
defer syscall.DnsRecordListFree(r, 1)
diff --git a/libgo/go/net/mac.go b/libgo/go/net/mac.go
index 93f0b09121..f3b1694735 100644
--- a/libgo/go/net/mac.go
+++ b/libgo/go/net/mac.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/mac_test.go b/libgo/go/net/mac_test.go
index 1ec6b287ac..2630d19047 100644
--- a/libgo/go/net/mac_test.go
+++ b/libgo/go/net/mac_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go
index 923630c49c..702b765c34 100644
--- a/libgo/go/net/mail/message.go
+++ b/libgo/go/net/mail/message.go
@@ -5,13 +5,15 @@
/*
Package mail implements parsing of mail messages.
-For the most part, this package follows the syntax as specified by RFC 5322.
+For the most part, this package follows the syntax as specified by RFC 5322 and
+extended by RFC 6532.
Notable divergences:
* Obsolete address formats are not parsed, including addresses with
embedded route information.
* Group addresses are not parsed.
* The full range of spacing (the CFWS syntax element) is not supported,
such as breaking addresses across lines.
+ * No unicode normalization is performed.
*/
package mail
@@ -26,6 +28,7 @@ import (
"net/textproto"
"strings"
"time"
+ "unicode/utf8"
)
var debug = debugT(false)
@@ -89,7 +92,8 @@ func init() {
}
}
-func parseDate(date string) (time.Time, error) {
+// ParseDate parses an RFC 5322 date string.
+func ParseDate(date string) (time.Time, error) {
for _, layout := range dateLayouts {
t, err := time.Parse(layout, date)
if err == nil {
@@ -103,7 +107,11 @@ func parseDate(date string) (time.Time, error) {
type Header map[string][]string
// Get gets the first value associated with the given key.
+// It is case insensitive; CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
+// To access multiple values of a key, or to use non-canonical keys,
+// access the map directly.
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
@@ -116,7 +124,7 @@ func (h Header) Date() (time.Time, error) {
if hdr == "" {
return time.Time{}, ErrHeaderNotPresent
}
- return parseDate(hdr)
+ return ParseDate(hdr)
}
// AddressList parses the named header field as a list of addresses.
@@ -138,7 +146,7 @@ type Address struct {
// Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
func ParseAddress(address string) (*Address, error) {
- return (&addrParser{s: address}).parseAddress()
+ return (&addrParser{s: address}).parseSingleAddress()
}
// ParseAddressList parses the given string as a list of addresses.
@@ -155,7 +163,7 @@ type AddressParser struct {
// Parse parses a single RFC 5322 address of the
// form "Gogh Fir <gf@example.com>" or "foo@example.com".
func (p *AddressParser) Parse(address string) (*Address, error) {
- return (&addrParser{s: address, dec: p.WordDecoder}).parseAddress()
+ return (&addrParser{s: address, dec: p.WordDecoder}).parseSingleAddress()
}
// ParseList parses the given string as a list of comma-separated addresses
@@ -168,7 +176,6 @@ func (p *AddressParser) ParseList(list string) ([]*Address, error) {
// If the address's name contains non-ASCII characters
// the name will be rendered according to RFC 2047.
func (a *Address) String() string {
-
// Format address local@domain
at := strings.LastIndex(a.Address, "@")
var local, domain string
@@ -181,15 +188,12 @@ func (a *Address) String() string {
}
// Add quotes if needed
- // TODO: rendering quoted local part and rendering printable name
- // should be merged in helper function.
quoteLocal := false
- for i := 0; i < len(local); i++ {
- ch := local[i]
- if isAtext(ch, false) {
+ for i, r := range local {
+ if isAtext(r, false) {
continue
}
- if ch == '.' {
+ if r == '.' {
// Dots are okay if they are surrounded by atext.
// We only need to check that the previous byte is
// not a dot, and this isn't the end of the string.
@@ -213,25 +217,16 @@ func (a *Address) String() string {
// If every character is printable ASCII, quoting is simple.
allPrintable := true
- for i := 0; i < len(a.Name); i++ {
+ for _, r := range a.Name {
// isWSP here should actually be isFWS,
// but we don't support folding yet.
- if !isVchar(a.Name[i]) && !isWSP(a.Name[i]) {
+ if !isVchar(r) && !isWSP(r) || isMultibyte(r) {
allPrintable = false
break
}
}
if allPrintable {
- b := bytes.NewBufferString(`"`)
- for i := 0; i < len(a.Name); i++ {
- if !isQtext(a.Name[i]) && !isWSP(a.Name[i]) {
- b.WriteByte('\\')
- }
- b.WriteByte(a.Name[i])
- }
- b.WriteString(`" `)
- b.WriteString(s)
- return b.String()
+ return quoteString(a.Name) + " " + s
}
// Text in an encoded-word in a display-name must not contain certain
@@ -269,6 +264,18 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
return list, nil
}
+func (p *addrParser) parseSingleAddress() (*Address, error) {
+ addr, err := p.parseAddress()
+ if err != nil {
+ return nil, err
+ }
+ p.skipSpace()
+ if !p.empty() {
+ return nil, fmt.Errorf("mail: expected single address, got %q", p.s)
+ }
+ return addr, nil
+}
+
// parseAddress parses a single RFC 5322 address at the start of p.
func (p *addrParser) parseAddress() (addr *Address, err error) {
debug.Printf("parseAddress: %q", p.s)
@@ -343,6 +350,9 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
// quoted-string
debug.Printf("consumeAddrSpec: parsing quoted-string")
localPart, err = p.consumeQuotedString()
+ if localPart == "" {
+ err = errors.New("mail: empty quoted string in addr-spec")
+ }
} else {
// dot-atom
debug.Printf("consumeAddrSpec: parsing dot-atom")
@@ -416,57 +426,81 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
func (p *addrParser) consumeQuotedString() (qs string, err error) {
// Assume first byte is '"'.
i := 1
- qsb := make([]byte, 0, 10)
+ qsb := make([]rune, 0, 10)
+
+ escaped := false
+
Loop:
for {
- if i >= p.len() {
+ r, size := utf8.DecodeRuneInString(p.s[i:])
+
+ switch {
+ case size == 0:
return "", errors.New("mail: unclosed quoted-string")
- }
- switch c := p.s[i]; {
- case c == '"':
- break Loop
- case c == '\\':
- if i+1 == p.len() {
- return "", errors.New("mail: unclosed quoted-string")
+
+ case size == 1 && r == utf8.RuneError:
+ return "", fmt.Errorf("mail: invalid utf-8 in quoted-string: %q", p.s)
+
+ case escaped:
+ // quoted-pair = ("\" (VCHAR / WSP))
+
+ if !isVchar(r) && !isWSP(r) {
+ return "", fmt.Errorf("mail: bad character in quoted-string: %q", r)
}
- qsb = append(qsb, p.s[i+1])
- i += 2
- case isQtext(c), c == ' ':
+
+ qsb = append(qsb, r)
+ escaped = false
+
+ case isQtext(r) || isWSP(r):
// qtext (printable US-ASCII excluding " and \), or
// FWS (almost; we're ignoring CRLF)
- qsb = append(qsb, c)
- i++
+ qsb = append(qsb, r)
+
+ case r == '"':
+ break Loop
+
+ case r == '\\':
+ escaped = true
+
default:
- return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
+ return "", fmt.Errorf("mail: bad character in quoted-string: %q", r)
+
}
+
+ i += size
}
p.s = p.s[i+1:]
- if len(qsb) == 0 {
- return "", errors.New("mail: empty quoted-string")
- }
return string(qsb), nil
}
-var errNonASCII = errors.New("mail: unencoded non-ASCII text in address")
-
// consumeAtom parses an RFC 5322 atom at the start of p.
// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
// If permissive is true, consumeAtom will not fail on
// leading/trailing/double dots in the atom (see golang.org/issue/4938).
func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
- if c := p.peek(); !isAtext(c, false) {
- if c > 127 {
- return "", errNonASCII
+ i := 0
+
+Loop:
+ for {
+ r, size := utf8.DecodeRuneInString(p.s[i:])
+
+ switch {
+ case size == 1 && r == utf8.RuneError:
+ return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s)
+
+ case size == 0 || !isAtext(r, dot):
+ break Loop
+
+ default:
+ i += size
+
}
- return "", errors.New("mail: invalid string")
}
- i := 1
- for ; i < p.len() && isAtext(p.s[i], dot); i++ {
- }
- if i < p.len() && p.s[i] > 127 {
- return "", errNonASCII
+
+ if i == 0 {
+ return "", errors.New("mail: invalid string")
}
- atom, p.s = string(p.s[:i]), p.s[i:]
+ atom, p.s = p.s[:i], p.s[i:]
if !permissive {
if strings.HasPrefix(atom, ".") {
return "", errors.New("mail: leading dot in atom")
@@ -536,54 +570,58 @@ func (e charsetError) Error() string {
return fmt.Sprintf("charset not supported: %q", string(e))
}
-var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
- "abcdefghijklmnopqrstuvwxyz" +
- "0123456789" +
- "!#$%&'*+-/=?^_`{|}~")
-
-// isAtext reports whether c is an RFC 5322 atext character.
+// isAtext reports whether r is an RFC 5322 atext character.
// If dot is true, period is included.
-func isAtext(c byte, dot bool) bool {
- if dot && c == '.' {
- return true
+func isAtext(r rune, dot bool) bool {
+ switch r {
+ case '.':
+ return dot
+
+ case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials
+ return false
}
- return bytes.IndexByte(atextChars, c) >= 0
+ return isVchar(r)
}
-// isQtext reports whether c is an RFC 5322 qtext character.
-func isQtext(c byte) bool {
+// isQtext reports whether r is an RFC 5322 qtext character.
+func isQtext(r rune) bool {
// Printable US-ASCII, excluding backslash or quote.
- if c == '\\' || c == '"' {
+ if r == '\\' || r == '"' {
return false
}
- return '!' <= c && c <= '~'
+ return isVchar(r)
}
-// quoteString renders a string as a RFC5322 quoted-string.
+// quoteString renders a string as an RFC 5322 quoted-string.
func quoteString(s string) string {
var buf bytes.Buffer
buf.WriteByte('"')
- for _, c := range s {
- ch := byte(c)
- if isQtext(ch) || isWSP(ch) {
- buf.WriteByte(ch)
- } else if isVchar(ch) {
+ for _, r := range s {
+ if isQtext(r) || isWSP(r) {
+ buf.WriteRune(r)
+ } else if isVchar(r) {
buf.WriteByte('\\')
- buf.WriteByte(ch)
+ buf.WriteRune(r)
}
}
buf.WriteByte('"')
return buf.String()
}
-// isVchar reports whether c is an RFC 5322 VCHAR character.
-func isVchar(c byte) bool {
+// isVchar reports whether r is an RFC 5322 VCHAR character.
+func isVchar(r rune) bool {
// Visible (printing) characters.
- return '!' <= c && c <= '~'
+ return '!' <= r && r <= '~' || isMultibyte(r)
+}
+
+// isMultibyte reports whether r is a multi-byte UTF-8 character
+// as supported by RFC 6532
+func isMultibyte(r rune) bool {
+ return r >= utf8.RuneSelf
}
-// isWSP reports whether c is a WSP (white space).
-// WSP is a space or horizontal tab (RFC5234 Appendix B).
-func isWSP(c byte) bool {
- return c == ' ' || c == '\t'
+// isWSP reports whether r is a WSP (white space).
+// WSP is a space or horizontal tab (RFC 5234 Appendix B).
+func isWSP(r rune) bool {
+ return r == ' ' || r == '\t'
}
diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go
index 4e718e2636..f0761ab09f 100644
--- a/libgo/go/net/mail/message_test.go
+++ b/libgo/go/net/mail/message_test.go
@@ -92,7 +92,7 @@ func TestDateParsing(t *testing.T) {
"Fri, 21 Nov 1997 09:55:06 -0600",
time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
},
- // RFC5322, Appendix A.6.2
+ // RFC 5322, Appendix A.6.2
// Obsolete date.
{
"21 Nov 97 09:55:06 GMT",
@@ -110,28 +110,39 @@ func TestDateParsing(t *testing.T) {
}
date, err := hdr.Date()
if err != nil {
- t.Errorf("Failed parsing %q: %v", test.dateStr, err)
- continue
+ t.Errorf("Header(Date: %s).Date(): %v", test.dateStr, err)
+ } else if !date.Equal(test.exp) {
+ t.Errorf("Header(Date: %s).Date() = %+v, want %+v", test.dateStr, date, test.exp)
}
- if !date.Equal(test.exp) {
- t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
+
+ date, err = ParseDate(test.dateStr)
+ if err != nil {
+ t.Errorf("ParseDate(%s): %v", test.dateStr, err)
+ } else if !date.Equal(test.exp) {
+ t.Errorf("ParseDate(%s) = %+v, want %+v", test.dateStr, date, test.exp)
}
}
}
func TestAddressParsingError(t *testing.T) {
- const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>"
- _, err := ParseAddress(txt)
- if err == nil || !strings.Contains(err.Error(), "charset not supported") {
- t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err)
+ mustErrTestCases := [...]struct {
+ text string
+ wantErrText string
+ }{
+ 0: {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>", "charset not supported"},
+ 1: {"a@gmail.com b@gmail.com", "expected single address"},
+ 2: {string([]byte{0xed, 0xa0, 0x80}) + " <micro@example.net>", "invalid utf-8 in address"},
+ 3: {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" <half-surrogate@example.com>", "invalid utf-8 in quoted-string"},
+ 4: {"\"\\" + string([]byte{0x80}) + "\" <escaped-invalid-unicode@example.net>", "invalid utf-8 in quoted-string"},
+ 5: {"\"\x00\" <null@example.net>", "bad character in quoted-string"},
+ 6: {"\"\\\x00\" <escaped-null@example.net>", "bad character in quoted-string"},
}
-}
-func TestAddressParsingErrorUnquotedNonASCII(t *testing.T) {
- const txt = "µ <micro@example.net>"
- _, err := ParseAddress(txt)
- if err == nil || !strings.Contains(err.Error(), "unencoded non-ASCII text in address") {
- t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*unencoded non-ASCII text in address.*"`, txt, err)
+ for i, tc := range mustErrTestCases {
+ _, err := ParseAddress(tc.text)
+ if err == nil || !strings.Contains(err.Error(), tc.wantErrText) {
+ t.Errorf(`mail.ParseAddress(%q) #%d want %q, got %v`, tc.text, i, tc.wantErrText, err)
+ }
}
}
@@ -264,6 +275,56 @@ func TestAddressParsing(t *testing.T) {
},
},
},
+ // RFC 6532 3.2.3, qtext /= UTF8-non-ascii
+ {
+ `"Gø Pher" <gopher@example.com>`,
+ []*Address{
+ {
+ Name: `Gø Pher`,
+ Address: "gopher@example.com",
+ },
+ },
+ },
+ // RFC 6532 3.2, atext /= UTF8-non-ascii
+ {
+ `µ <micro@example.com>`,
+ []*Address{
+ {
+ Name: `µ`,
+ Address: "micro@example.com",
+ },
+ },
+ },
+ // RFC 6532 3.2.2, local address parts allow UTF-8
+ {
+ `Micro <µ@example.com>`,
+ []*Address{
+ {
+ Name: `Micro`,
+ Address: "µ@example.com",
+ },
+ },
+ },
+ // RFC 6532 3.2.4, domains parts allow UTF-8
+ {
+ `Micro <micro@µ.example.com>`,
+ []*Address{
+ {
+ Name: `Micro`,
+ Address: "micro@µ.example.com",
+ },
+ },
+ },
+ // Issue 14866
+ {
+ `"" <emptystring@example.com>`,
+ []*Address{
+ {
+ Name: "",
+ Address: "emptystring@example.com",
+ },
+ },
+ },
}
for _, test := range tests {
if len(test.exp) == 1 {
@@ -515,6 +576,11 @@ func TestAddressString(t *testing.T) {
&Address{Name: "world?=", Address: "hello@world.com"},
`"world?=" <hello@world.com>`,
},
+ {
+ // should q-encode even for invalid utf-8.
+ &Address{Name: string([]byte{0xed, 0xa0, 0x80}), Address: "invalid-utf8@example.net"},
+ "=?utf-8?q?=ED=A0=80?= <invalid-utf8@example.net>",
+ },
}
for _, test := range tests {
s := test.addr.String()
@@ -610,7 +676,6 @@ func TestAddressParsingAndFormatting(t *testing.T) {
`< @example.com>`,
`<""test""blah""@example.com>`,
`<""@0>`,
- "<\"\t0\"@0>",
}
for _, test := range badTests {
diff --git a/libgo/go/net/main_conf_test.go b/libgo/go/net/main_conf_test.go
new file mode 100644
index 0000000000..9875ceaf1f
--- /dev/null
+++ b/libgo/go/net/main_conf_test.go
@@ -0,0 +1,38 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !nacl,!plan9,!windows
+
+package net
+
+// forceGoDNS forces the resolver configuration to use the pure Go resolver
+// and returns a fixup function to restore the old settings.
+func forceGoDNS() func() {
+ c := systemConf()
+ oldGo := c.netGo
+ oldCgo := c.netCgo
+ fixup := func() {
+ c.netGo = oldGo
+ c.netCgo = oldCgo
+ }
+ c.netGo = true
+ c.netCgo = false
+ return fixup
+}
+
+// forceCgoDNS forces the resolver configuration to use the cgo resolver
+// and returns a fixup function to restore the old settings.
+// (On non-Unix systems forceCgoDNS returns nil.)
+func forceCgoDNS() func() {
+ c := systemConf()
+ oldGo := c.netGo
+ oldCgo := c.netCgo
+ fixup := func() {
+ c.netGo = oldGo
+ c.netCgo = oldCgo
+ }
+ c.netGo = false
+ c.netCgo = true
+ return fixup
+}
diff --git a/libgo/go/net/non_unix_test.go b/libgo/go/net/main_noconf_test.go
index db3427e7cb..489477bc97 100644
--- a/libgo/go/net/non_unix_test.go
+++ b/libgo/go/net/main_noconf_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -8,7 +8,7 @@ package net
import "runtime"
-// See unix_test.go for what these (don't) do.
+// See main_conf_test.go for what these (don't) do.
func forceGoDNS() func() {
switch runtime.GOOS {
case "plan9", "windows":
@@ -18,5 +18,5 @@ func forceGoDNS() func() {
}
}
-// See unix_test.go for what these (don't) do.
+// See main_conf_test.go for what these (don't) do.
func forceCgoDNS() func() { return nil }
diff --git a/libgo/go/net/main_plan9_test.go b/libgo/go/net/main_plan9_test.go
index 94501cada9..2bc5be88be 100644
--- a/libgo/go/net/main_plan9_test.go
+++ b/libgo/go/net/main_plan9_test.go
@@ -8,6 +8,7 @@ func installTestHooks() {}
func uninstallTestHooks() {}
+// forceCloseSockets must be called only from TestMain.
func forceCloseSockets() {}
func enableSocketConnect() {}
diff --git a/libgo/go/net/main_test.go b/libgo/go/net/main_test.go
index f3f8b1a900..28a8ff66d6 100644
--- a/libgo/go/net/main_test.go
+++ b/libgo/go/net/main_test.go
@@ -24,9 +24,9 @@ var (
)
var (
- testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
+ testTCPBig = flag.Bool("tcpbig", false, "whether to test massive size of data per read or write call on TCP connection")
- testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+ testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
// If external IPv4 connectivity exists, we can try dialing
// non-node/interface local scope IPv4 addresses.
diff --git a/libgo/go/net/main_unix_test.go b/libgo/go/net/main_unix_test.go
index bfb4cd0065..0cc129f34d 100644
--- a/libgo/go/net/main_unix_test.go
+++ b/libgo/go/net/main_unix_test.go
@@ -45,6 +45,7 @@ func uninstallTestHooks() {
}
}
+// forceCloseSockets must be called only from TestMain.
func forceCloseSockets() {
for s := range sw.Sockets() {
closeFunc(s)
diff --git a/libgo/go/net/main_windows_test.go b/libgo/go/net/main_windows_test.go
index 2d829743ec..6ea318c2a5 100644
--- a/libgo/go/net/main_windows_test.go
+++ b/libgo/go/net/main_windows_test.go
@@ -11,6 +11,7 @@ var (
origConnect = connectFunc
origConnectEx = connectExFunc
origListen = listenFunc
+ origAccept = acceptFunc
)
func installTestHooks() {
@@ -19,6 +20,7 @@ func installTestHooks() {
connectFunc = sw.Connect
connectExFunc = sw.ConnectEx
listenFunc = sw.Listen
+ acceptFunc = sw.AcceptEx
}
func uninstallTestHooks() {
@@ -27,8 +29,10 @@ func uninstallTestHooks() {
connectFunc = origConnect
connectExFunc = origConnectEx
listenFunc = origListen
+ acceptFunc = origAccept
}
+// forceCloseSockets must be called only from TestMain.
func forceCloseSockets() {
for s := range sw.Sockets() {
closeFunc(s)
diff --git a/libgo/go/net/mockserver_test.go b/libgo/go/net/mockserver_test.go
index dd6f4df3b9..766de6a815 100644
--- a/libgo/go/net/mockserver_test.go
+++ b/libgo/go/net/mockserver_test.go
@@ -30,10 +30,20 @@ func testUnixAddr() string {
func newLocalListener(network string) (Listener, error) {
switch network {
- case "tcp", "tcp4", "tcp6":
+ case "tcp":
+ if supportsIPv4 {
+ if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil {
+ return ln, nil
+ }
+ }
+ if supportsIPv6 {
+ return Listen("tcp6", "[::1]:0")
+ }
+ case "tcp4":
if supportsIPv4 {
return Listen("tcp4", "127.0.0.1:0")
}
+ case "tcp6":
if supportsIPv6 {
return Listen("tcp6", "[::1]:0")
}
@@ -142,13 +152,6 @@ func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) er
return nil
}
-func (dss *dualStackServer) putConn(c Conn) error {
- dss.cmu.Lock()
- dss.cs = append(dss.cs, c)
- dss.cmu.Unlock()
- return nil
-}
-
func (dss *dualStackServer) teardownNetwork(network string) error {
dss.lnmu.Lock()
for i := range dss.lns {
@@ -181,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) {
@@ -225,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
}
@@ -333,10 +332,18 @@ func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
func newLocalPacketListener(network string) (PacketConn, error) {
switch network {
- case "udp", "udp4", "udp6":
+ case "udp":
+ if supportsIPv4 {
+ return ListenPacket("udp4", "127.0.0.1:0")
+ }
+ if supportsIPv6 {
+ return ListenPacket("udp6", "[::1]:0")
+ }
+ case "udp4":
if supportsIPv4 {
return ListenPacket("udp4", "127.0.0.1:0")
}
+ case "udp6":
if supportsIPv6 {
return ListenPacket("udp6", "[::1]:0")
}
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index d9d23fae8f..a8b57361e6 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -14,7 +14,7 @@ the same interfaces and similar Dial and Listen functions.
The Dial function connects to a server:
- conn, err := net.Dial("tcp", "google.com:80")
+ conn, err := net.Dial("tcp", "golang.org:80")
if err != nil {
// handle error
}
@@ -79,6 +79,7 @@ On Windows, the resolver always uses C library functions, such as GetAddrInfo an
package net
import (
+ "context"
"errors"
"io"
"os"
@@ -101,9 +102,13 @@ func init() {
}
// Addr represents a network end point address.
+//
+// The two methods Network and String conventionally return strings
+// that can be passed as the arguments to Dial, but the exact form
+// and meaning of the strings is up to the implementation.
type Addr interface {
- Network() string // name of the network
- String() string // string form of address
+ Network() string // name of the network (for example, "tcp", "udp")
+ String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
}
// Conn is a generic stream-oriented network connection.
@@ -111,12 +116,12 @@ type Addr interface {
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
- // Read can be made to time out and return a Error with Timeout() == true
+ // Read can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
- // Write can be made to time out and return a Error with Timeout() == true
+ // Write can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
Write(b []byte) (n int, err error)
@@ -136,8 +141,10 @@ type Conn interface {
//
// A deadline is an absolute time after which I/O operations
// fail with a timeout (see type Error) instead of
- // blocking. The deadline applies to all future I/O, not just
- // the immediately following call to Read or Write.
+ // blocking. The deadline applies to all future and pending
+ // I/O, not just the immediately following call to Read or
+ // Write. After a deadline has been exceeded, the connection
+ // can be refreshed by setting a deadline in the future.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
@@ -145,11 +152,13 @@ type Conn interface {
// A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for future Read calls.
+ // SetReadDeadline sets the deadline for future Read calls
+ // and any currently-blocked Read call.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for future Write calls.
+ // SetWriteDeadline sets the deadline for future Write calls
+ // and any currently-blocked Write call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
@@ -297,17 +306,17 @@ func (c *conn) File() (f *os.File, err error) {
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
// ReadFrom reads a packet from the connection,
- // copying the payload into b. It returns the number of
+ // copying the payload into b. It returns the number of
// bytes copied into b and the return address that
// was on the packet.
// ReadFrom can be made to time out and return
- // an error with Timeout() == true after a fixed time limit;
+ // an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetReadDeadline.
ReadFrom(b []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload b to addr.
// WriteTo can be made to time out and return
- // an error with Timeout() == true after a fixed time limit;
+ // an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
WriteTo(b []byte, addr Addr) (n int, err error)
@@ -320,21 +329,32 @@ type PacketConn interface {
LocalAddr() Addr
// SetDeadline sets the read and write deadlines associated
- // with the connection.
+ // with the connection. It is equivalent to calling both
+ // SetReadDeadline and SetWriteDeadline.
+ //
+ // A deadline is an absolute time after which I/O operations
+ // fail with a timeout (see type Error) instead of
+ // blocking. The deadline applies to all future and pending
+ // I/O, not just the immediately following call to ReadFrom or
+ // WriteTo. After a deadline has been exceeded, the connection
+ // can be refreshed by setting a deadline in the future.
+ //
+ // An idle timeout can be implemented by repeatedly extending
+ // the deadline after successful ReadFrom or WriteTo calls.
+ //
+ // A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for future Read calls.
- // If the deadline is reached, Read will fail with a timeout
- // (see type Error) instead of blocking.
- // A zero value for t means Read will not time out.
+ // SetReadDeadline sets the deadline for future ReadFrom calls
+ // and any currently-blocked ReadFrom call.
+ // A zero value for t means ReadFrom will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for future Write calls.
- // If the deadline is reached, Write will fail with a timeout
- // (see type Error) instead of blocking.
- // A zero value for t means Write will not time out.
+ // SetWriteDeadline sets the deadline for future WriteTo calls
+ // and any currently-blocked WriteTo call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
+ // A zero value for t means WriteTo will not time out.
SetWriteDeadline(t time.Time) error
}
@@ -364,6 +384,9 @@ type Error interface {
// Various errors contained in OpError.
var (
+ // For connection setup operations.
+ errNoSuitableAddress = errors.New("no suitable address found")
+
// For connection setup and write operations.
errMissingAddress = errors.New("missing address")
@@ -374,6 +397,22 @@ var (
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)
+// mapErr maps from the context errors to the historical internal net
+// error values.
+//
+// TODO(bradfitz): get rid of this after adjusting tests and making
+// context.DeadlineExceeded implement net.Error?
+func mapErr(err error) error {
+ switch err {
+ case context.Canceled:
+ return errCanceled
+ case context.DeadlineExceeded:
+ return errTimeout
+ default:
+ return err
+ }
+}
+
// OpError is the error type usually returned by functions in the net
// package. It describes the operation, network type, and address of
// an error.
@@ -429,7 +468,7 @@ func (e *OpError) Error() string {
var (
// aLongTimeAgo is a non-zero time, far in the past, used for
// immediate cancelation of dials.
- aLongTimeAgo = time.Unix(233431200, 0)
+ aLongTimeAgo = time.Unix(1, 0)
// nonDeadline and noCancel are just zero values for
// readability with functions taking too many parameters.
@@ -492,7 +531,7 @@ func (e *AddrError) Error() string {
}
s := e.Err
if e.Addr != "" {
- s += " " + e.Addr
+ s = "address " + e.Addr + ": " + s
}
return s
}
@@ -584,3 +623,66 @@ func acquireThread() {
func releaseThread() {
<-threadLimit
}
+
+// buffersWriter is the interface implemented by Conns that support a
+// "writev"-like batch write optimization.
+// writeBuffers should fully consume and write all chunks from the
+// provided Buffers, else it should report a non-nil error.
+type buffersWriter interface {
+ writeBuffers(*Buffers) (int64, error)
+}
+
+var testHookDidWritev = func(wrote int) {}
+
+// Buffers contains zero or more runs of bytes to write.
+//
+// On certain machines, for certain types of connections, this is
+// optimized into an OS-specific batch write operation (such as
+// "writev").
+type Buffers [][]byte
+
+var (
+ _ io.WriterTo = (*Buffers)(nil)
+ _ io.Reader = (*Buffers)(nil)
+)
+
+func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
+ if wv, ok := w.(buffersWriter); ok {
+ return wv.writeBuffers(v)
+ }
+ for _, b := range *v {
+ nb, err := w.Write(b)
+ n += int64(nb)
+ if err != nil {
+ v.consume(n)
+ return n, err
+ }
+ }
+ v.consume(n)
+ return n, nil
+}
+
+func (v *Buffers) Read(p []byte) (n int, err error) {
+ for len(p) > 0 && len(*v) > 0 {
+ n0 := copy(p, (*v)[0])
+ v.consume(int64(n0))
+ p = p[n0:]
+ n += n0
+ }
+ if len(*v) == 0 {
+ err = io.EOF
+ }
+ return
+}
+
+func (v *Buffers) consume(n int64) {
+ for len(*v) > 0 {
+ ln0 := int64(len((*v)[0]))
+ if ln0 > n {
+ (*v)[0] = (*v)[0][n:]
+ return
+ }
+ n -= ln0
+ *v = (*v)[1:]
+ }
+}
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index cd62b4373e..9a9a7e552c 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -5,7 +5,10 @@
package net
import (
+ "errors"
+ "fmt"
"io"
+ "net/internal/socktest"
"os"
"runtime"
"testing"
@@ -14,7 +17,7 @@ import (
func TestCloseRead(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -304,3 +307,212 @@ func TestListenCloseListen(t *testing.T) {
}
t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
}
+
+// See golang.org/issue/6163, golang.org/issue/6987.
+func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+ }
+
+ syserr := make(chan error)
+ go func() {
+ defer close(syserr)
+ for _, err := range abortedConnRequestErrors {
+ syserr <- err
+ }
+ }()
+ sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) {
+ if err, ok := <-syserr; ok {
+ return nil, err
+ }
+ return nil, nil
+ })
+ defer sw.Set(socktest.FilterAccept, nil)
+
+ operr := make(chan error, 1)
+ handler := func(ls *localServer, ln Listener) {
+ defer close(operr)
+ c, err := ln.Accept()
+ if err != nil {
+ if perr := parseAcceptError(err); perr != nil {
+ operr <- perr
+ }
+ operr <- err
+ return
+ }
+ c.Close()
+ }
+ ls, err := newLocalServer("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ls.teardown()
+ if err := ls.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
+
+ c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+
+ for err := range operr {
+ t.Error(err)
+ }
+}
+
+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)
+ }
+ }
+}
+
+// withTCPConnPair sets up a TCP connection between two peers, then
+// runs peer1 and peer2 concurrently. withTCPConnPair returns when
+// both have completed.
+func withTCPConnPair(t *testing.T, peer1, peer2 func(c *TCPConn) error) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+ errc := make(chan error, 2)
+ go func() {
+ c1, err := ln.Accept()
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer c1.Close()
+ errc <- peer1(c1.(*TCPConn))
+ }()
+ go func() {
+ c2, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer c2.Close()
+ errc <- peer2(c2.(*TCPConn))
+ }()
+ for i := 0; i < 2; i++ {
+ if err := <-errc; err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+// Tests that a blocked Read is interrupted by a concurrent SetReadDeadline
+// modifying that Conn's read deadline to the past.
+// See golang.org/cl/30164 which documented this. The net/http package
+// depends on this.
+func TestReadTimeoutUnblocksRead(t *testing.T) {
+ serverDone := make(chan struct{})
+ server := func(cs *TCPConn) error {
+ defer close(serverDone)
+ errc := make(chan error, 1)
+ go func() {
+ defer close(errc)
+ go func() {
+ // TODO: find a better way to wait
+ // until we're blocked in the cs.Read
+ // call below. Sleep is lame.
+ time.Sleep(100 * time.Millisecond)
+
+ // Interrupt the upcoming Read, unblocking it:
+ cs.SetReadDeadline(time.Unix(123, 0)) // time in the past
+ }()
+ var buf [1]byte
+ n, err := cs.Read(buf[:1])
+ if n != 0 || err == nil {
+ errc <- fmt.Errorf("Read = %v, %v; want 0, non-nil", n, err)
+ }
+ }()
+ select {
+ case err := <-errc:
+ return err
+ case <-time.After(5 * time.Second):
+ buf := make([]byte, 2<<20)
+ buf = buf[:runtime.Stack(buf, true)]
+ println("Stacks at timeout:\n", string(buf))
+ return errors.New("timeout waiting for Read to finish")
+ }
+
+ }
+ // Do nothing in the client. Never write. Just wait for the
+ // server's half to be done.
+ client := func(*TCPConn) error {
+ <-serverDone
+ return nil
+ }
+ withTCPConnPair(t, client, server)
+}
+
+// Issue 17695: verify that a blocked Read is woken up by a Close.
+func TestCloseUnblocksRead(t *testing.T) {
+ t.Parallel()
+ server := func(cs *TCPConn) error {
+ // Give the client time to get stuck in a Read:
+ time.Sleep(20 * time.Millisecond)
+ cs.Close()
+ return nil
+ }
+ client := func(ss *TCPConn) error {
+ n, err := ss.Read([]byte{0})
+ if n != 0 || err != io.EOF {
+ return fmt.Errorf("Read = %v, %v; want 0, EOF", n, err)
+ }
+ return nil
+ }
+ withTCPConnPair(t, client, server)
+}
diff --git a/libgo/go/net/newpollserver_rtems.go b/libgo/go/net/newpollserver_rtems.go
index 410f9321d3..2add81467b 100644
--- a/libgo/go/net/newpollserver_rtems.go
+++ b/libgo/go/net/newpollserver_rtems.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build rtems
+
package net
import (
diff --git a/libgo/go/net/packetconn_test.go b/libgo/go/net/packetconn_test.go
index 7f3ea8a2d0..7d50489021 100644
--- a/libgo/go/net/packetconn_test.go
+++ b/libgo/go/net/packetconn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
index 80836a108c..b270159cd8 100644
--- a/libgo/go/net/parse.go
+++ b/libgo/go/net/parse.go
@@ -106,14 +106,14 @@ func splitAtBytes(s string, t string) []string {
for i := 0; i < len(s); i++ {
if byteIndex(t, s[i]) >= 0 {
if last < i {
- a[n] = string(s[last:i])
+ a[n] = s[last:i]
n++
}
last = i + 1
}
}
if last < len(s) {
- a[n] = string(s[last:])
+ a[n] = s[last:]
n++
}
return a[0:n]
@@ -124,39 +124,27 @@ func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
// Bigger than we need, not too big to worry about overflow
const big = 0xFFFFFF
-// Decimal to integer starting at &s[i0].
-// Returns number, new offset, success.
-func dtoi(s string, i0 int) (n int, i int, ok bool) {
+// Decimal to integer.
+// Returns number, characters consumed, success.
+func dtoi(s string) (n int, i int, ok bool) {
n = 0
- neg := false
- if len(s) > 0 && s[0] == '-' {
- neg = true
- s = s[1:]
- }
- for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0')
if n >= big {
- if neg {
- return -big, i + 1, false
- }
return big, i, false
}
}
- if i == i0 {
- return 0, i, false
- }
- if neg {
- n = -n
- i++
+ if i == 0 {
+ return 0, 0, false
}
return n, i, true
}
-// Hexadecimal to integer starting at &s[i0].
-// Returns number, new offset, success.
-func xtoi(s string, i0 int) (n int, i int, ok bool) {
+// Hexadecimal to integer.
+// Returns number, characters consumed, success.
+func xtoi(s string) (n int, i int, ok bool) {
n = 0
- for i = i0; i < len(s); i++ {
+ for i = 0; i < len(s); i++ {
if '0' <= s[i] && s[i] <= '9' {
n *= 16
n += int(s[i] - '0')
@@ -173,7 +161,7 @@ func xtoi(s string, i0 int) (n int, i int, ok bool) {
return 0, i, false
}
}
- if i == i0 {
+ if i == 0 {
return 0, i, false
}
return n, i, true
@@ -187,7 +175,7 @@ func xtoi2(s string, e byte) (byte, bool) {
if len(s) > 2 && s[2] != e {
return 0, false
}
- n, ei, ok := xtoi(s[:2], 0)
+ n, ei, ok := xtoi(s[:2])
return byte(n), ok && ei == 2
}
@@ -348,22 +336,28 @@ func stringsHasSuffix(s, suffix string) bool {
// stringsHasSuffixFold reports whether s ends in suffix,
// ASCII-case-insensitively.
func stringsHasSuffixFold(s, suffix string) bool {
- if len(suffix) > len(s) {
+ return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix)
+}
+
+// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
+func stringsHasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
+// are equal, ASCII-case-insensitively.
+func stringsEqualFold(s, t string) bool {
+ if len(s) != len(t) {
return false
}
- for i := 0; i < len(suffix); i++ {
- if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) {
+ for i := 0; i < len(s); i++ {
+ if lowerASCII(s[i]) != lowerASCII(t[i]) {
return false
}
}
return true
}
-// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
-func stringsHasPrefix(s, prefix string) bool {
- return len(s) >= len(prefix) && s[:len(prefix)] == prefix
-}
-
func readFull(r io.Reader) (all []byte, err error) {
buf := make([]byte, 1024)
for {
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
index fec9200946..c5f8bfd198 100644
--- a/libgo/go/net/parse_test.go
+++ b/libgo/go/net/parse_test.go
@@ -86,14 +86,13 @@ func TestDtoi(t *testing.T) {
ok bool
}{
{"", 0, 0, false},
-
- {"-123456789", -big, 9, false},
- {"-1", -1, 2, true},
{"0", 0, 1, true},
{"65536", 65536, 5, true},
{"123456789", big, 8, false},
+ {"-0", 0, 0, false},
+ {"-1234", 0, 0, false},
} {
- n, i, ok := dtoi(tt.in, 0)
+ n, i, ok := dtoi(tt.in)
if n != tt.out || i != tt.off || ok != tt.ok {
t.Errorf("got %d, %d, %v; want %d, %d, %v", n, i, ok, tt.out, tt.off, tt.ok)
}
diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go
index 5fc830b740..37e552f54e 100644
--- a/libgo/go/net/pipe.go
+++ b/libgo/go/net/pipe.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/net/pipe_test.go b/libgo/go/net/pipe_test.go
index 60c3920593..e3172d882f 100644
--- a/libgo/go/net/pipe_test.go
+++ b/libgo/go/net/pipe_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/net/platform_test.go b/libgo/go/net/platform_test.go
index 76c53138cd..2a14095cc2 100644
--- a/libgo/go/net/platform_test.go
+++ b/libgo/go/net/platform_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "internal/testenv"
"os"
"runtime"
"strings"
@@ -110,7 +111,7 @@ func testableListenArgs(network, address, client string) bool {
}
// Test wildcard IP addresses.
- if wildcard && (testing.Short() || !*testExternal) {
+ if wildcard && !testenv.HasExternalNetwork() {
return false
}
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
new file mode 100644
index 0000000000..8e1321afa4
--- /dev/null
+++ b/libgo/go/net/port.go
@@ -0,0 +1,62 @@
+// 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 net
+
+// parsePort parses service as a decimal interger and returns the
+// corresponding value as port. It is the caller's responsibility to
+// parse service as a non-decimal integer when needsLookup is true.
+//
+// Some system resolvers will return a valid port number when given a number
+// over 65536 (see https://github.com/golang/go/issues/11715). Alas, the parser
+// can't bail early on numbers > 65536. Therefore reasonably large/small
+// numbers are parsed in full and rejected if invalid.
+func parsePort(service string) (port int, needsLookup bool) {
+ if service == "" {
+ // Lock in the legacy behavior that an empty string
+ // means port 0. See golang.org/issue/13610.
+ return 0, false
+ }
+ const (
+ max = uint32(1<<32 - 1)
+ cutoff = uint32(1 << 30)
+ )
+ neg := false
+ if service[0] == '+' {
+ service = service[1:]
+ } else if service[0] == '-' {
+ neg = true
+ service = service[1:]
+ }
+ var n uint32
+ for _, d := range service {
+ if '0' <= d && d <= '9' {
+ d -= '0'
+ } else {
+ return 0, true
+ }
+ if n >= cutoff {
+ n = max
+ break
+ }
+ n *= 10
+ nn := n + uint32(d)
+ if nn < n || nn > max {
+ n = max
+ break
+ }
+ n = nn
+ }
+ if !neg && n >= cutoff {
+ port = int(cutoff - 1)
+ } else if neg && n > cutoff {
+ port = int(cutoff)
+ } else {
+ port = int(n)
+ }
+ if neg {
+ port = -port
+ }
+ return port, false
+}
diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go
new file mode 100644
index 0000000000..e0bdb4247d
--- /dev/null
+++ b/libgo/go/net/port_test.go
@@ -0,0 +1,52 @@
+// 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 net
+
+import "testing"
+
+var parsePortTests = []struct {
+ service string
+ port int
+ needsLookup bool
+}{
+ {"", 0, false},
+
+ // Decimal number literals
+ {"-1073741825", -1 << 30, false},
+ {"-1073741824", -1 << 30, false},
+ {"-1073741823", -(1<<30 - 1), false},
+ {"-123456789", -123456789, false},
+ {"-1", -1, false},
+ {"-0", 0, false},
+ {"0", 0, false},
+ {"+0", 0, false},
+ {"+1", 1, false},
+ {"65535", 65535, false},
+ {"65536", 65536, false},
+ {"123456789", 123456789, false},
+ {"1073741822", 1<<30 - 2, false},
+ {"1073741823", 1<<30 - 1, false},
+ {"1073741824", 1<<30 - 1, false},
+ {"1073741825", 1<<30 - 1, false},
+
+ // Others
+ {"abc", 0, true},
+ {"9pfs", 0, true},
+ {"123badport", 0, true},
+ {"bad123port", 0, true},
+ {"badport123", 0, true},
+ {"123456789badport", 0, true},
+ {"-2147483649badport", 0, true},
+ {"2147483649badport", 0, true},
+}
+
+func TestParsePort(t *testing.T) {
+ // The following test cases are cribbed from the strconv
+ for _, tt := range parsePortTests {
+ if port, needsLookup := parsePort(tt.service); port != tt.port || needsLookup != tt.needsLookup {
+ t.Errorf("parsePort(%q) = %d, %t; want %d, %t", tt.service, port, needsLookup, tt.port, tt.needsLookup)
+ }
+ }
+}
diff --git a/libgo/go/net/port_unix.go b/libgo/go/net/port_unix.go
index badf8abc79..868d1e4784 100644
--- a/libgo/go/net/port_unix.go
+++ b/libgo/go/net/port_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris nacl
// Read system port mappings from /etc/services
@@ -10,31 +10,24 @@ package net
import "sync"
-// services contains minimal mappings between services names and port
-// numbers for platforms that don't have a complete list of port numbers
-// (some Solaris distros).
-var services = map[string]map[string]int{
- "tcp": {"http": 80},
-}
-var servicesError error
var onceReadServices sync.Once
func readServices() {
- var file *file
- if file, servicesError = open("/etc/services"); servicesError != nil {
+ file, err := open("/etc/services")
+ if err != nil {
return
}
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
// "http 80/tcp www www-http # World Wide Web HTTP"
if i := byteIndex(line, '#'); i >= 0 {
- line = line[0:i]
+ line = line[:i]
}
f := getFields(line)
if len(f) < 2 {
continue
}
portnet := f[1] // "80/tcp"
- port, j, ok := dtoi(portnet, 0)
+ port, j, ok := dtoi(portnet)
if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
continue
}
@@ -56,18 +49,5 @@ func readServices() {
// goLookupPort is the native Go implementation of LookupPort.
func goLookupPort(network, service string) (port int, err error) {
onceReadServices.Do(readServices)
-
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
- }
-
- if m, ok := services[network]; ok {
- if port, ok = m[service]; ok {
- return
- }
- }
- return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
+ return lookupPortMap(network, service)
}
diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go
index c6ef23b0e1..23589d3ca8 100644
--- a/libgo/go/net/protoconn_test.go
+++ b/libgo/go/net/protoconn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go
index d0c4a69214..fce6a4866c 100644
--- a/libgo/go/net/rpc/client.go
+++ b/libgo/go/net/rpc/client.go
@@ -55,7 +55,7 @@ type Client struct {
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
-// to read responses. The client calls Close when finished with the
+// to read responses. The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
@@ -173,7 +173,7 @@ func (call *Call) done() {
case call.Done <- call:
// ok
default:
- // We don't want to block here. It is the caller's responsibility to make
+ // We don't want to block here. It is the caller's responsibility to make
// sure the channel has enough buffer space. See comment in Go().
if debugLog {
log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
@@ -274,6 +274,8 @@ func Dial(network, address string) (*Client, error) {
return NewClient(conn), nil
}
+// Close calls the underlying codec's Close method. If the connection is already
+// shutting down, ErrShutdown is returned.
func (client *Client) Close() error {
client.mutex.Lock()
if client.closing {
@@ -285,9 +287,9 @@ func (client *Client) Close() error {
return client.codec.Close()
}
-// Go invokes the function asynchronously. It returns the Call structure representing
-// the invocation. The done channel will signal when the call is complete by returning
-// the same Call object. If done is nil, Go will allocate a new channel.
+// Go invokes the function asynchronously. It returns the Call structure representing
+// the invocation. The done channel will signal when the call is complete by returning
+// the same Call object. If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
call := new(Call)
@@ -299,7 +301,7 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
} else {
// If caller passes done != nil, it must arrange that
// done has enough buffer for the number of simultaneous
- // RPCs that will be using that channel. If the channel
+ // RPCs that will be using that channel. If the channel
// is totally unbuffered, it's best not to run at all.
if cap(done) == 0 {
log.Panic("rpc: done channel is unbuffered")
diff --git a/libgo/go/net/rpc/client_test.go b/libgo/go/net/rpc/client_test.go
index ba11ff8586..d116d2acc9 100644
--- a/libgo/go/net/rpc/client_test.go
+++ b/libgo/go/net/rpc/client_test.go
@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"net"
- "runtime"
"strings"
"testing"
)
@@ -53,9 +52,6 @@ func (s *S) Recv(nul *struct{}, reply *R) error {
}
func TestGobError(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/8908")
- }
defer func() {
err := recover()
if err == nil {
diff --git a/libgo/go/net/rpc/jsonrpc/all_test.go b/libgo/go/net/rpc/jsonrpc/all_test.go
index a433a365e8..b811d3c0c7 100644
--- a/libgo/go/net/rpc/jsonrpc/all_test.go
+++ b/libgo/go/net/rpc/jsonrpc/all_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/net/rpc/jsonrpc/client.go b/libgo/go/net/rpc/jsonrpc/client.go
index 2194f21257..da1b8165fc 100644
--- a/libgo/go/net/rpc/jsonrpc/client.go
+++ b/libgo/go/net/rpc/jsonrpc/client.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/net/rpc/jsonrpc/server.go b/libgo/go/net/rpc/jsonrpc/server.go
index e6d37cfa64..40e4e6f2aa 100644
--- a/libgo/go/net/rpc/jsonrpc/server.go
+++ b/libgo/go/net/rpc/jsonrpc/server.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -110,7 +110,7 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
c.mutex.Unlock()
if b == nil {
- // Invalid request so no id. Use JSON null.
+ // Invalid request so no id. Use JSON null.
b = &null
}
resp := serverResponse{Id: b}
diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go
index c4d4479958..18ea629b0d 100644
--- a/libgo/go/net/rpc/server.go
+++ b/libgo/go/net/rpc/server.go
@@ -23,7 +23,7 @@
func (t *T) MethodName(argType T1, replyType *T2) error
- where T, T1 and T2 can be marshaled by encoding/gob.
+ where T1 and T2 can be marshaled by encoding/gob.
These requirements apply even if a different codec is used.
(In the future, these requirements may soften for custom codecs.)
@@ -55,6 +55,8 @@
package server
+ import "errors"
+
type Args struct {
A, B int
}
@@ -119,6 +121,8 @@
A server implementation will often provide a simple, type-safe wrapper for the
client.
+
+ The net/rpc package is frozen and is not accepting new features.
*/
package rpc
@@ -143,8 +147,8 @@ const (
DefaultDebugPath = "/debug/rpc"
)
-// Precompute the reflect type for error. Can't use error directly
-// because Typeof takes an empty interface value. This is annoying.
+// Precompute the reflect type for error. Can't use error directly
+// because Typeof takes an empty interface value. This is annoying.
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
type methodType struct {
@@ -162,7 +166,7 @@ type service struct {
method map[string]*methodType // registered methods
}
-// Request is a header written before every RPC call. It is used internally
+// Request is a header written before every RPC call. It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Request struct {
@@ -171,7 +175,7 @@ type Request struct {
next *Request // for free list in Server
}
-// Response is a header written before every RPC return. It is used internally
+// Response is a header written before every RPC return. It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Response struct {
@@ -442,7 +446,7 @@ func (c *gobServerCodec) Close() error {
// ServeConn blocks, serving the connection until the client hangs up.
// The caller typically invokes ServeConn in a go statement.
// ServeConn uses the gob wire format (see package gob) on the
-// connection. To use an alternate codec, use ServeCodec.
+// connection. To use an alternate codec, use ServeCodec.
func (server *Server) ServeConn(conn io.ReadWriteCloser) {
buf := bufio.NewWriter(conn)
srv := &gobServerCodec{
@@ -583,7 +587,7 @@ func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mt
return
}
- // We read the header successfully. If we see an error now,
+ // We read the header successfully. If we see an error now,
// we can still recover and move on to the next request.
keepReading = true
@@ -638,7 +642,7 @@ func RegisterName(name string, rcvr interface{}) error {
// RPC responses for the server side of an RPC session.
// The server calls ReadRequestHeader and ReadRequestBody in pairs
// to read requests from the connection, and it calls WriteResponse to
-// write a response back. The server calls Close when finished with the
+// write a response back. The server calls Close when finished with the
// connection. ReadRequestBody may be called with a nil
// argument to force the body of the request to be read and discarded.
type ServerCodec interface {
@@ -654,7 +658,7 @@ type ServerCodec interface {
// ServeConn blocks, serving the connection until the client hangs up.
// The caller typically invokes ServeConn in a go statement.
// ServeConn uses the gob wire format (see package gob) on the
-// connection. To use an alternate codec, use ServeCodec.
+// connection. To use an alternate codec, use ServeCodec.
func ServeConn(conn io.ReadWriteCloser) {
DefaultServer.ServeConn(conn)
}
diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go
index 8871c88133..8369c9dec7 100644
--- a/libgo/go/net/rpc/server_test.go
+++ b/libgo/go/net/rpc/server_test.go
@@ -183,7 +183,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Unknown", args, reply)
if err == nil {
t.Error("expected error calling unknown service")
- } else if strings.Index(err.Error(), "method") < 0 {
+ } else if !strings.Contains(err.Error(), "method") {
t.Error("expected error about method; got", err)
}
@@ -226,7 +226,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
if err == nil {
t.Error("expected error calling Arith.Add with wrong arg type")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("expected error about type; got", err)
}
@@ -657,6 +657,9 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
}
func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
+ if b.N == 0 {
+ return
+ }
const MaxConcurrentCalls = 100
once.Do(startServer)
client, err := dial()
@@ -690,7 +693,8 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
B := call.Args.(*Args).B
C := call.Reply.(*Reply).C
if A+B != C {
- b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
+ b.Errorf("incorrect reply: Add: expected %d got %d", A+B, C)
+ return
}
<-gate
if atomic.AddInt32(&recv, -1) == 0 {
diff --git a/libgo/go/net/sendfile_dragonfly.go b/libgo/go/net/sendfile_dragonfly.go
index a9cf3fe951..d4b825c370 100644
--- a/libgo/go/net/sendfile_dragonfly.go
+++ b/libgo/go/net/sendfile_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -53,7 +53,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// use the current position of the file -- if you pass it offset 0, it starts
// from offset 0. There's no way to tell it "start from current position", so
// we have to manage that explicitly.
- pos, err := f.Seek(0, os.SEEK_CUR)
+ pos, err := f.Seek(0, io.SeekCurrent)
if err != nil {
return 0, err, false
}
@@ -81,7 +81,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pd.WaitWrite(); err1 == nil {
+ if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
diff --git a/libgo/go/net/sendfile_freebsd.go b/libgo/go/net/sendfile_freebsd.go
index d0bf6034c1..18cbb27b53 100644
--- a/libgo/go/net/sendfile_freebsd.go
+++ b/libgo/go/net/sendfile_freebsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -53,7 +53,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// use the current position of the file -- if you pass it offset 0, it starts
// from offset 0. There's no way to tell it "start from current position", so
// we have to manage that explicitly.
- pos, err := f.Seek(0, os.SEEK_CUR)
+ pos, err := f.Seek(0, io.SeekCurrent)
if err != nil {
return 0, err, false
}
@@ -81,7 +81,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pd.WaitWrite(); err1 == nil {
+ if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go
index 5ca41c39eb..7e741f9794 100644
--- a/libgo/go/net/sendfile_linux.go
+++ b/libgo/go/net/sendfile_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -57,7 +57,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pd.WaitWrite(); err1 == nil {
+ if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
diff --git a/libgo/go/net/sendfile_solaris.go b/libgo/go/net/sendfile_solaris.go
index f6833813fd..add70c3147 100644
--- a/libgo/go/net/sendfile_solaris.go
+++ b/libgo/go/net/sendfile_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -26,8 +26,6 @@ const maxSendfileSize int = 4 << 20
//
// if handled == false, sendFile performed no work.
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
- return // Solaris sendfile is disabled until Issue 13892 is understood and fixed
-
// Solaris uses 0 as the "until EOF" value. If you pass in more bytes than the
// file contains, it will loop back to the beginning ad nauseam until it's sent
// exactly the number of bytes told to. As such, we need to know exactly how many
@@ -59,7 +57,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// use the current position of the file -- if you pass it offset 0, it starts
// from offset 0. There's no way to tell it "start from current position", so
// we have to manage that explicitly.
- pos, err := f.Seek(0, os.SEEK_CUR)
+ pos, err := f.Seek(0, io.SeekCurrent)
if err != nil {
return 0, err, false
}
@@ -78,6 +76,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
}
pos1 := pos
n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+ if err1 == syscall.EAGAIN || err1 == syscall.EINTR {
+ // partial write may have occurred
+ if n = int(pos1 - pos); n == 0 {
+ // nothing more to write
+ err1 = nil
+ }
+ }
if n > 0 {
pos += int64(n)
written += int64(n)
@@ -87,7 +92,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pd.WaitWrite(); err1 == nil {
+ if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
index a0760b4e52..905f1d6cef 100644
--- a/libgo/go/net/sendfile_stub.go
+++ b/libgo/go/net/sendfile_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sendfile_test.go b/libgo/go/net/sendfile_test.go
new file mode 100644
index 0000000000..2255e7c478
--- /dev/null
+++ b/libgo/go/net/sendfile_test.go
@@ -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.
+
+package net
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "os"
+ "testing"
+)
+
+const (
+ twain = "testdata/Mark.Twain-Tom.Sawyer.txt"
+ twainLen = 387851
+ twainSHA256 = "461eb7cb2d57d293fc680c836464c9125e4382be3596f7d415093ae9db8fcb0e"
+)
+
+func TestSendfile(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ errc := make(chan error, 1)
+ go func(ln Listener) {
+ // Wait for a connection.
+ conn, err := ln.Accept()
+ if err != nil {
+ errc <- err
+ close(errc)
+ return
+ }
+
+ go func() {
+ defer close(errc)
+ defer conn.Close()
+
+ f, err := os.Open(twain)
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer f.Close()
+
+ // Return file data using io.Copy, which should use
+ // sendFile if available.
+ sbytes, err := io.Copy(conn, f)
+ if err != nil {
+ errc <- err
+ return
+ }
+
+ if sbytes != twainLen {
+ errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, twainLen)
+ return
+ }
+ }()
+ }(ln)
+
+ // Connect to listener to retrieve file and verify digest matches
+ // expected.
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ h := sha256.New()
+ rbytes, err := io.Copy(h, c)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if rbytes != twainLen {
+ t.Errorf("received %d bytes; expected %d", rbytes, twainLen)
+ }
+
+ if res := hex.EncodeToString(h.Sum(nil)); res != twainSHA256 {
+ t.Error("retrieved data hash did not match")
+ }
+
+ for err := range errc {
+ t.Error(err)
+ }
+}
diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go
index f3f3b54b88..bc0b7fb5b2 100644
--- a/libgo/go/net/sendfile_windows.go
+++ b/libgo/go/net/sendfile_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -18,7 +18,7 @@ import (
//
// if handled == false, sendFile performed no work.
//
-// Note that sendfile for windows does not suppport >2GB file.
+// Note that sendfile for windows does not support >2GB file.
func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
var n int64 = 0 // by default, copy until EOF
diff --git a/libgo/go/net/smtp/smtp.go b/libgo/go/net/smtp/smtp.go
index 0988350322..a408fa5336 100644
--- a/libgo/go/net/smtp/smtp.go
+++ b/libgo/go/net/smtp/smtp.go
@@ -8,12 +8,18 @@
// AUTH RFC 2554
// STARTTLS RFC 3207
// Additional extensions may be handled by clients.
+//
+// The smtp package is frozen and is not accepting new features.
+// Some external packages provide more functionality. See:
+//
+// https://godoc.org/?q=smtp
package smtp
import (
"crypto/tls"
"encoding/base64"
"errors"
+ "fmt"
"io"
"net"
"net/textproto"
@@ -83,8 +89,8 @@ func (c *Client) hello() error {
// Hello sends a HELO or EHLO to the server as the given host name.
// Calling this method is only necessary if the client needs control
-// over the host name used. The client will introduce itself as "localhost"
-// automatically otherwise. If Hello is called, it must be called before
+// over the host name used. The client will introduce itself as "localhost"
+// automatically otherwise. If Hello is called, it must be called before
// any of the other methods.
func (c *Client) Hello(localName string) error {
if c.didHello {
@@ -195,7 +201,7 @@ func (c *Client) Auth(a Auth) error {
}
resp64 := make([]byte, encoding.EncodedLen(len(resp)))
encoding.Encode(resp64, resp)
- code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
+ code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64)))
for err == nil {
var msg []byte
switch code {
@@ -265,7 +271,7 @@ func (d *dataCloser) Close() error {
// Data issues a DATA command to the server and returns a writer that
// can be used to write the mail headers and body. The caller should
-// close the writer before calling any more methods on c. A call to
+// close the writer before calling any more methods on c. A call to
// Data must be preceded by one or more calls to Rcpt.
func (c *Client) Data() (io.WriteCloser, error) {
_, _, err := c.cmd(354, "DATA")
@@ -287,7 +293,7 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
//
// The msg parameter should be an RFC 822-style email with headers
// first, a blank line, and then the message body. The lines of msg
-// should be CRLF terminated. The msg headers should usually include
+// should be CRLF terminated. The msg headers should usually include
// fields such as "From", "To", "Subject", and "Cc". Sending "Bcc"
// messages is accomplished by including an email address in the to
// parameter but not including it in the msg headers.
diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go
index 3ae0d5bf1d..c48fae6d5a 100644
--- a/libgo/go/net/smtp/smtp_test.go
+++ b/libgo/go/net/smtp/smtp_test.go
@@ -94,6 +94,46 @@ func TestAuthPlain(t *testing.T) {
}
}
+// Issue 17794: don't send a trailing space on AUTH command when there's no password.
+func TestClientAuthTrimSpace(t *testing.T) {
+ server := "220 hello world\r\n" +
+ "200 some more"
+ var wrote bytes.Buffer
+ var fake faker
+ fake.ReadWriter = struct {
+ io.Reader
+ io.Writer
+ }{
+ strings.NewReader(server),
+ &wrote,
+ }
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v", err)
+ }
+ c.tls = true
+ c.didHello = true
+ c.Auth(toServerEmptyAuth{})
+ c.Close()
+ if got, want := wrote.String(), "AUTH FOOAUTH\r\n*\r\nQUIT\r\n"; got != want {
+ t.Errorf("wrote %q; want %q", got, want)
+ }
+}
+
+// toServerEmptyAuth is an implementation of Auth that only implements
+// the Start method, and returns "FOOAUTH", nil, nil. Notably, it returns
+// zero bytes for "toServer" so we can test that we don't send spaces at
+// the end of the line. See TestClientAuthTrimSpace.
+type toServerEmptyAuth struct{}
+
+func (toServerEmptyAuth) Start(server *ServerInfo) (proto string, toServer []byte, err error) {
+ return "FOOAUTH", nil, nil
+}
+
+func (toServerEmptyAuth) Next(fromServer []byte, more bool) (toServer []byte, err error) {
+ panic("unexpected call")
+}
+
type faker struct {
io.ReadWriter
}
@@ -716,23 +756,24 @@ func sendMail(hostPort string) error {
// generated from src/crypto/tls:
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
-bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
-bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
-IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
-AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
-EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
-AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
-Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+MIIBjjCCATigAwIBAgIQMon9v0s3pDFXvAMnPgelpzANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
+MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
+AM0u/mNXKkhAzNsFkwKZPSpC4lZZaePQ55IyaJv3ovMM2smvthnlqaUfVKVmz7FF
+wLP9csX6vGtvkZg1uWAtvfkCAwEAAaNoMGYwDgYDVR0PAQH/BAQDAgKkMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhh
+bXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQAD
+QQBOZsFVC7IwX+qibmSbt2IPHkUgXhfbq0a9MYhD6tHcj4gbDcTXh4kZCbgHCz22
+gfSj2/G2wxzopoISVDucuncj
-----END CERTIFICATE-----`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
-0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
-NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
-AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
-MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
-EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
-1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+MIIBOwIBAAJBAM0u/mNXKkhAzNsFkwKZPSpC4lZZaePQ55IyaJv3ovMM2smvthnl
+qaUfVKVmz7FFwLP9csX6vGtvkZg1uWAtvfkCAwEAAQJART2qkxODLUbQ2siSx7m2
+rmBLyR/7X+nLe8aPDrMOxj3heDNl4YlaAYLexbcY8d7VDfCRBKYoAOP0UCP1Vhuf
+UQIhAO6PEI55K3SpNIdc2k5f0xz+9rodJCYzu51EwWX7r8ufAiEA3C9EkLiU2NuK
+3L3DHCN5IlUSN1Nr/lw8NIt50Yorj2cCIQCDw1VbvCV6bDLtSSXzAA51B4ZzScE7
+sHtB5EYF9Dwm9QIhAJuCquuH4mDzVjUntXjXOQPdj7sRqVGCNWdrJwOukat7AiAy
+LXLEwb77DIPoI5ZuaXQC+MnyyJj1ExC9RFcGz+bexA==
-----END RSA PRIVATE KEY-----`)
diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go
index 6c37109f5e..4e0e9e01f2 100644
--- a/libgo/go/net/sock_bsd.go
+++ b/libgo/go/net/sock_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/sock_linux.go b/libgo/go/net/sock_linux.go
index cc5ce153b3..7bca37605e 100644
--- a/libgo/go/net/sock_linux.go
+++ b/libgo/go/net/sock_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -17,7 +17,7 @@ func maxListenerBacklog() int {
return syscall.SOMAXCONN
}
f := getFields(l)
- n, _, ok := dtoi(f[0], 0)
+ n, _, ok := dtoi(f[0])
if n == 0 || !ok {
return syscall.SOMAXCONN
}
diff --git a/libgo/go/net/sock_plan9.go b/libgo/go/net/sock_plan9.go
index 88d9ed15cf..9367ad8fa7 100644
--- a/libgo/go/net/sock_plan9.go
+++ b/libgo/go/net/sock_plan9.go
@@ -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.
diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go
index 4676721567..16351e1f14 100644
--- a/libgo/go/net/sock_posix.go
+++ b/libgo/go/net/sock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,9 +7,9 @@
package net
import (
+ "context"
"os"
"syscall"
- "time"
)
// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
@@ -30,11 +30,14 @@ type sockaddr interface {
// interface. It returns a nil interface when the address is
// nil.
sockaddr(family int) (syscall.Sockaddr, error)
+
+ // toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
+ toLocal(net string) sockaddr
}
// socket returns a network file descriptor that is ready for
// asynchronous I/O using the network poller.
-func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) (fd *netFD, err error) {
+func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr) (fd *netFD, err error) {
s, err := sysSocket(family, sotype, proto)
if err != nil {
return nil, err
@@ -86,7 +89,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
return fd, nil
}
}
- if err := fd.dial(laddr, raddr, deadline, cancel); err != nil {
+ if err := fd.dial(ctx, laddr, raddr); err != nil {
fd.Close()
return nil, err
}
@@ -117,7 +120,7 @@ func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
return func(syscall.Sockaddr) Addr { return nil }
}
-func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
var err error
var lsa syscall.Sockaddr
if laddr != nil {
@@ -134,7 +137,7 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan s
if rsa, err = raddr.sockaddr(fd.family); err != nil {
return err
}
- if err := fd.connect(lsa, rsa, deadline, cancel); err != nil {
+ if err := fd.connect(ctx, lsa, rsa); err != nil {
return err
}
fd.isConnected = true
diff --git a/libgo/go/net/sock_stub.go b/libgo/go/net/sock_stub.go
index ed6b089489..5ac1e864f7 100644
--- a/libgo/go/net/sock_stub.go
+++ b/libgo/go/net/sock_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go
index 888e70bb8e..89a3ca4258 100644
--- a/libgo/go/net/sock_windows.go
+++ b/libgo/go/net/sock_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go
index 52b2a5debc..734a1093d6 100644
--- a/libgo/go/net/sockopt_bsd.go
+++ b/libgo/go/net/sockopt_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -27,7 +27,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
}
if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
- // is otherwise. Note that some operating systems
+ // is otherwise. Note that some operating systems
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
diff --git a/libgo/go/net/sockopt_linux.go b/libgo/go/net/sockopt_linux.go
index 54c20b1409..0f70b12407 100644
--- a/libgo/go/net/sockopt_linux.go
+++ b/libgo/go/net/sockopt_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -12,7 +12,7 @@ import (
func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
- // is otherwise. Note that some operating systems
+ // is otherwise. Note that some operating systems
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
diff --git a/libgo/go/net/sockopt_plan9.go b/libgo/go/net/sockopt_plan9.go
index 8bc689b6c2..02468cda97 100644
--- a/libgo/go/net/sockopt_plan9.go
+++ b/libgo/go/net/sockopt_plan9.go
@@ -1,9 +1,11 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
+import "syscall"
+
func setKeepAlive(fd *netFD, keepalive bool) error {
if keepalive {
_, e := fd.ctl.WriteAt([]byte("keepalive"), 0)
@@ -11,3 +13,7 @@ func setKeepAlive(fd *netFD, keepalive bool) error {
}
return nil
}
+
+func setLinger(fd *netFD, sec int) error {
+ return syscall.EPLAN9
+}
diff --git a/libgo/go/net/sockopt_posix.go b/libgo/go/net/sockopt_posix.go
index 1654d1b85e..cd3d562289 100644
--- a/libgo/go/net/sockopt_posix.go
+++ b/libgo/go/net/sockopt_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/sockopt_solaris.go b/libgo/go/net/sockopt_solaris.go
index 54c20b1409..0f70b12407 100644
--- a/libgo/go/net/sockopt_solaris.go
+++ b/libgo/go/net/sockopt_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -12,7 +12,7 @@ import (
func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
- // is otherwise. Note that some operating systems
+ // is otherwise. Note that some operating systems
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
diff --git a/libgo/go/net/sockopt_stub.go b/libgo/go/net/sockopt_stub.go
index de5ee0bb63..7e9e560e05 100644
--- a/libgo/go/net/sockopt_stub.go
+++ b/libgo/go/net/sockopt_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sockopt_windows.go b/libgo/go/net/sockopt_windows.go
index cb64a40c69..8017426521 100644
--- a/libgo/go/net/sockopt_windows.go
+++ b/libgo/go/net/sockopt_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -12,7 +12,7 @@ import (
func setDefaultSockopts(s syscall.Handle, family, sotype int, ipv6only bool) error {
if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
- // is otherwise. Note that some operating systems
+ // is otherwise. Note that some operating systems
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
diff --git a/libgo/go/net/sockoptip_bsd.go b/libgo/go/net/sockoptip_bsd.go
index 2199e480d4..b15c6396ba 100644
--- a/libgo/go/net/sockoptip_bsd.go
+++ b/libgo/go/net/sockoptip_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sockoptip_linux.go b/libgo/go/net/sockoptip_linux.go
index a69b778e4d..c1dcc911c7 100644
--- a/libgo/go/net/sockoptip_linux.go
+++ b/libgo/go/net/sockoptip_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sockoptip_posix.go b/libgo/go/net/sockoptip_posix.go
index c2579be911..d50886003e 100644
--- a/libgo/go/net/sockoptip_posix.go
+++ b/libgo/go/net/sockoptip_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sockoptip_stub.go b/libgo/go/net/sockoptip_stub.go
index 32ec5ddb85..f698687514 100644
--- a/libgo/go/net/sockoptip_stub.go
+++ b/libgo/go/net/sockoptip_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/sockoptip_windows.go b/libgo/go/net/sockoptip_windows.go
index 7b11f207aa..916debebc6 100644
--- a/libgo/go/net/sockoptip_windows.go
+++ b/libgo/go/net/sockoptip_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
index 8765affd46..69731ebc91 100644
--- a/libgo/go/net/tcpsock.go
+++ b/libgo/go/net/tcpsock.go
@@ -1,9 +1,20 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
+import (
+ "context"
+ "io"
+ "os"
+ "syscall"
+ "time"
+)
+
+// BUG(mikio): On Windows, the File method of TCPListener is not
+// implemented.
+
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
@@ -45,6 +56,9 @@ func (a *TCPAddr) opAddr() Addr {
// "tcp6". A literal address or host name for IPv6 must be enclosed
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
switch net {
case "tcp", "tcp4", "tcp6":
@@ -53,9 +67,234 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(net, addr, noDeadline)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
if err != nil {
return nil, err
}
return addrs.first(isIPv4).(*TCPAddr), nil
}
+
+// TCPConn is an implementation of the Conn interface for TCP network
+// connections.
+type TCPConn struct {
+ conn
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.readFrom(r)
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "readfrom", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, err
+}
+
+// CloseRead shuts down the reading side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseRead() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := c.fd.closeRead(); err != nil {
+ return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// CloseWrite shuts down the writing side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseWrite() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := c.fd.closeWrite(); err != nil {
+ return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// SetLinger sets the behavior of Close on a connection which still
+// has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
+//
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
+//
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
+func (c *TCPConn) SetLinger(sec int) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := setLinger(c.fd, sec); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := setKeepAlive(c.fd, keepalive); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// SetKeepAlivePeriod sets period between keep alives.
+func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := setKeepAlivePeriod(c.fd, d); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets (Nagle's
+// algorithm). The default is true (no delay), meaning that data is
+// sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := setNoDelay(c.fd, noDelay); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+ c := &TCPConn{conn{fd}}
+ setNoDelay(c.fd, true)
+ return c
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is
+// used as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if raddr == nil {
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+ }
+ c, err := dialTCP(context.Background(), net, laddr, raddr)
+ if err != nil {
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
+
+// TCPListener is a TCP network listener. Clients should typically
+// use variables of type Listener instead of assuming TCP.
+type TCPListener struct {
+ fd *netFD
+}
+
+// AcceptTCP accepts the next incoming call and returns the new
+// connection.
+func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ c, err := l.accept()
+ if err != nil {
+ return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface; it
+// waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (Conn, error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ c, err := l.accept()
+ if err != nil {
+ return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return c, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() error {
+ if !l.ok() {
+ return syscall.EINVAL
+ }
+ if err := l.close(); err != nil {
+ return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return nil
+}
+
+// Addr returns the listener's network address, a *TCPAddr.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *TCPListener) SetDeadline(t time.Time) error {
+ if !l.ok() {
+ return syscall.EINVAL
+ }
+ if err := l.fd.setDeadline(t); err != nil {
+ return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return nil
+}
+
+// File returns a copy of the underlying os.File, set to blocking
+// mode. It is the caller's responsibility to close f when finished.
+// Closing l does not affect f, and closing f does not affect l.
+//
+// The returned os.File's file descriptor is different from the
+// connection's. Attempting to change properties of the original
+// using this duplicate may or may not have the desired effect.
+func (l *TCPListener) File() (f *os.File, err error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ f, err = l.file()
+ if err != nil {
+ return nil, &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP
+// listener. Net must be "tcp", "tcp4", or "tcp6". If laddr has a
+// port of 0, ListenTCP will choose an available port. The caller can
+// use the Addr method of TCPListener to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if laddr == nil {
+ laddr = &TCPAddr{}
+ }
+ ln, err := listenTCP(context.Background(), net, laddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+ }
+ return ln, nil
+}
diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go
index afccbfe8a7..d2860607f8 100644
--- a/libgo/go/net/tcpsock_plan9.go
+++ b/libgo/go/net/tcpsock_plan9.go
@@ -1,230 +1,73 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
+ "context"
"io"
"os"
- "syscall"
- "time"
)
-// TCPConn is an implementation of the Conn interface for TCP network
-// connections.
-type TCPConn struct {
- conn
+func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
+ return genericReadFrom(c, r)
}
-func newTCPConn(fd *netFD) *TCPConn {
- return &TCPConn{conn{fd}}
-}
-
-// ReadFrom implements the io.ReaderFrom ReadFrom method.
-func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
- n, err := genericReadFrom(c, r)
- if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return n, err
-}
-
-// CloseRead shuts down the reading side of the TCP connection.
-// Most callers should just use Close.
-func (c *TCPConn) CloseRead() error {
- if !c.ok() {
- return syscall.EINVAL
- }
- err := c.fd.closeRead()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+func dialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ if testHookDialTCP != nil {
+ return testHookDialTCP(ctx, net, laddr, raddr)
}
- return err
-}
-
-// CloseWrite shuts down the writing side of the TCP connection.
-// Most callers should just use Close.
-func (c *TCPConn) CloseWrite() error {
- if !c.ok() {
- return syscall.EINVAL
- }
- err := c.fd.closeWrite()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return err
-}
-
-// SetLinger sets the behavior of Close on a connection which still
-// has data waiting to be sent or to be acknowledged.
-//
-// If sec < 0 (the default), the operating system finishes sending the
-// data in the background.
-//
-// If sec == 0, the operating system discards any unsent or
-// unacknowledged data.
-//
-// If sec > 0, the data is sent in the background as with sec < 0. On
-// some operating systems after sec seconds have elapsed any remaining
-// unsent data may be discarded.
-func (c *TCPConn) SetLinger(sec int) error {
- return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
-}
-
-// SetKeepAlive sets whether the operating system should send
-// keepalive messages on the connection.
-func (c *TCPConn) SetKeepAlive(keepalive bool) error {
- if !c.ok() {
- return syscall.EPLAN9
- }
- if err := setKeepAlive(c.fd, keepalive); err != nil {
- return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// SetKeepAlivePeriod sets period between keep alives.
-func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
- if !c.ok() {
- return syscall.EPLAN9
- }
- if err := setKeepAlivePeriod(c.fd, d); err != nil {
- return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// SetNoDelay controls whether the operating system should delay
-// packet transmission in hopes of sending fewer packets (Nagle's
-// algorithm). The default is true (no delay), meaning that data is
-// sent as soon as possible after a Write.
-func (c *TCPConn) SetNoDelay(noDelay bool) error {
- return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
-}
-
-// DialTCP connects to the remote address raddr on the network net,
-// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is
-// used as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
- return dialTCP(net, laddr, raddr, noDeadline, noCancel)
+ return doDialTCP(ctx, net, laddr, raddr)
}
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
- if !deadline.IsZero() {
- panic("net.dialTCP: deadline not implemented on Plan 9")
- }
- // TODO(bradfitz,0intro): also use the cancel channel.
+func doDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+ return nil, UnknownNetworkError(net)
}
if raddr == nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+ return nil, errMissingAddress
}
- fd, err := dialPlan9(net, laddr, raddr)
+ fd, err := dialPlan9(ctx, net, laddr, raddr)
if err != nil {
return nil, err
}
return newTCPConn(fd), nil
}
-// TCPListener is a TCP network listener. Clients should typically
-// use variables of type Listener instead of assuming TCP.
-type TCPListener struct {
- fd *netFD
-}
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil && ln.fd.ctl != nil }
-// AcceptTCP accepts the next incoming call and returns the new
-// connection.
-func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
- if l == nil || l.fd == nil || l.fd.ctl == nil {
- return nil, syscall.EINVAL
- }
- fd, err := l.fd.acceptPlan9()
+func (ln *TCPListener) accept() (*TCPConn, error) {
+ fd, err := ln.fd.acceptPlan9()
if err != nil {
return nil, err
}
return newTCPConn(fd), nil
}
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *TCPListener) Accept() (Conn, error) {
- if l == nil || l.fd == nil || l.fd.ctl == nil {
- return nil, syscall.EINVAL
+func (ln *TCPListener) close() error {
+ if _, err := ln.fd.ctl.WriteString("hangup"); err != nil {
+ ln.fd.ctl.Close()
+ return err
}
- c, err := l.AcceptTCP()
- if err != nil {
- return nil, err
- }
- return c, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *TCPListener) Close() error {
- if l == nil || l.fd == nil || l.fd.ctl == nil {
- return syscall.EINVAL
- }
- if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
- l.fd.ctl.Close()
- return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
- }
- err := l.fd.ctl.Close()
- if err != nil {
- err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
- }
- return err
-}
-
-// Addr returns the listener's network address, a *TCPAddr.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
-func (l *TCPListener) Addr() Addr { return l.fd.laddr }
-
-// SetDeadline sets the deadline associated with the listener.
-// A zero time value disables the deadline.
-func (l *TCPListener) SetDeadline(t time.Time) error {
- if l == nil || l.fd == nil || l.fd.ctl == nil {
- return syscall.EINVAL
- }
- if err := l.fd.setDeadline(t); err != nil {
- return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+ if err := ln.fd.ctl.Close(); err != nil {
+ return err
}
return nil
}
-// File returns a copy of the underlying os.File, set to blocking
-// mode. It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// The returned os.File's file descriptor is different from the
-// connection's. Attempting to change properties of the original
-// using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) {
- f, err = l.dup()
+func (ln *TCPListener) file() (*os.File, error) {
+ f, err := ln.dup()
if err != nil {
- err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+ return nil, err
}
- return
+ return f, nil
}
-// ListenTCP announces on the TCP address laddr and returns a TCP
-// listener. Net must be "tcp", "tcp4", or "tcp6". If laddr has a
-// port of 0, ListenTCP will choose an available port. The caller can
-// use the Addr method of TCPListener to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
- switch net {
- case "tcp", "tcp4", "tcp6":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- laddr = &TCPAddr{}
- }
- fd, err := listenPlan9(net, laddr)
+func listenTCP(ctx context.Context, network string, laddr *TCPAddr) (*TCPListener, error) {
+ fd, err := listenPlan9(ctx, network, laddr)
if err != nil {
return nil, err
}
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index 0e12d54300..9641e5c028 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,10 +7,10 @@
package net
import (
+ "context"
"io"
"os"
"syscall"
- "time"
)
func sockaddrToTCP(sa syscall.Sockaddr) Addr {
@@ -40,151 +40,42 @@ func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
-// TCPConn is an implementation of the Conn interface for TCP network
-// connections.
-type TCPConn struct {
- conn
+func (a *TCPAddr) toLocal(net string) sockaddr {
+ return &TCPAddr{loopbackIP(net), a.Port, a.Zone}
}
-func newTCPConn(fd *netFD) *TCPConn {
- c := &TCPConn{conn{fd}}
- setNoDelay(c.fd, true)
- return c
-}
-
-// ReadFrom implements the io.ReaderFrom ReadFrom method.
-func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
+func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
if n, err, handled := sendFile(c.fd, r); handled {
- if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return n, err
}
- n, err := genericReadFrom(c, r)
- if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return n, err
+ return genericReadFrom(c, r)
}
-// CloseRead shuts down the reading side of the TCP connection.
-// Most callers should just use Close.
-func (c *TCPConn) CloseRead() error {
- if !c.ok() {
- return syscall.EINVAL
+func dialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ if testHookDialTCP != nil {
+ return testHookDialTCP(ctx, net, laddr, raddr)
}
- err := c.fd.closeRead()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return err
+ return doDialTCP(ctx, net, laddr, raddr)
}
-// CloseWrite shuts down the writing side of the TCP connection.
-// Most callers should just use Close.
-func (c *TCPConn) CloseWrite() error {
- if !c.ok() {
- return syscall.EINVAL
- }
- err := c.fd.closeWrite()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return err
-}
-
-// SetLinger sets the behavior of Close on a connection which still
-// has data waiting to be sent or to be acknowledged.
-//
-// If sec < 0 (the default), the operating system finishes sending the
-// data in the background.
-//
-// If sec == 0, the operating system discards any unsent or
-// unacknowledged data.
-//
-// If sec > 0, the data is sent in the background as with sec < 0. On
-// some operating systems after sec seconds have elapsed any remaining
-// unsent data may be discarded.
-func (c *TCPConn) SetLinger(sec int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- if err := setLinger(c.fd, sec); err != nil {
- return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// SetKeepAlive sets whether the operating system should send
-// keepalive messages on the connection.
-func (c *TCPConn) SetKeepAlive(keepalive bool) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- if err := setKeepAlive(c.fd, keepalive); err != nil {
- return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// SetKeepAlivePeriod sets period between keep alives.
-func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- if err := setKeepAlivePeriod(c.fd, d); err != nil {
- return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// SetNoDelay controls whether the operating system should delay
-// packet transmission in hopes of sending fewer packets (Nagle's
-// algorithm). The default is true (no delay), meaning that data is
-// sent as soon as possible after a Write.
-func (c *TCPConn) SetNoDelay(noDelay bool) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- if err := setNoDelay(c.fd, noDelay); err != nil {
- return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return nil
-}
-
-// DialTCP connects to the remote address raddr on the network net,
-// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is
-// used as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
- switch net {
- case "tcp", "tcp4", "tcp6":
- default:
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if raddr == nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
- }
- return dialTCP(net, laddr, raddr, noDeadline, noCancel)
-}
-
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
- fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
+func doDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ fd, err := internetSocket(ctx, net, laddr, raddr, syscall.SOCK_STREAM, 0, "dial")
// TCP has a rarely used mechanism called a 'simultaneous connection' in
// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
- // at addr2, without either machine executing Listen. If laddr == nil,
+ // at addr2, without either machine executing Listen. If laddr == nil,
// it means we want the kernel to pick an appropriate originating local
- // address. Some Linux kernels cycle blindly through a fixed range of
- // local ports, regardless of destination port. If a kernel happens to
+ // address. Some Linux kernels cycle blindly through a fixed range of
+ // local ports, regardless of destination port. If a kernel happens to
// pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
// then the Dial will succeed, having simultaneously connected to itself.
// This can only happen when we are letting the kernel pick a port (laddr == nil)
// and when there is no listener for the destination address.
- // It's hard to argue this is anything other than a kernel bug. If we
+ // It's hard to argue this is anything other than a kernel bug. If we
// see this happen, rather than expose the buggy effect to users, we
- // close the fd and try again. If it happens twice more, we relent and
- // use the result. See also:
+ // close the fd and try again. If it happens twice more, we relent and
+ // use the result. See also:
// https://golang.org/issue/2690
// http://stackoverflow.com/questions/4949858/
//
@@ -198,11 +89,11 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-cha
if err == nil {
fd.Close()
}
- fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
+ fd, err = internetSocket(ctx, net, laddr, raddr, syscall.SOCK_STREAM, 0, "dial")
}
if err != nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ return nil, err
}
return newTCPConn(fd), nil
}
@@ -239,96 +130,32 @@ func spuriousENOTAVAIL(err error) bool {
return err == syscall.EADDRNOTAVAIL
}
-// TCPListener is a TCP network listener. Clients should typically
-// use variables of type Listener instead of assuming TCP.
-type TCPListener struct {
- fd *netFD
-}
-
-// AcceptTCP accepts the next incoming call and returns the new
-// connection.
-func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
- if l == nil || l.fd == nil {
- return nil, syscall.EINVAL
- }
- fd, err := l.fd.accept()
- if err != nil {
- return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
- }
- return newTCPConn(fd), nil
-}
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *TCPListener) Accept() (Conn, error) {
- c, err := l.AcceptTCP()
+func (ln *TCPListener) accept() (*TCPConn, error) {
+ fd, err := ln.fd.accept()
if err != nil {
return nil, err
}
- return c, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *TCPListener) Close() error {
- if l == nil || l.fd == nil {
- return syscall.EINVAL
- }
- err := l.fd.Close()
- if err != nil {
- err = &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
- }
- return err
+ return newTCPConn(fd), nil
}
-// Addr returns the listener's network address, a *TCPAddr.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
-func (l *TCPListener) Addr() Addr { return l.fd.laddr }
-
-// SetDeadline sets the deadline associated with the listener.
-// A zero time value disables the deadline.
-func (l *TCPListener) SetDeadline(t time.Time) error {
- if l == nil || l.fd == nil {
- return syscall.EINVAL
- }
- if err := l.fd.setDeadline(t); err != nil {
- return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
- }
- return nil
+func (ln *TCPListener) close() error {
+ return ln.fd.Close()
}
-// File returns a copy of the underlying os.File, set to blocking
-// mode. It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// The returned os.File's file descriptor is different from the
-// connection's. Attempting to change properties of the original
-// using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) {
- f, err = l.fd.dup()
+func (ln *TCPListener) file() (*os.File, error) {
+ f, err := ln.fd.dup()
if err != nil {
- err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ return nil, err
}
- return
+ return f, nil
}
-// ListenTCP announces on the TCP address laddr and returns a TCP
-// listener. Net must be "tcp", "tcp4", or "tcp6". If laddr has a
-// port of 0, ListenTCP will choose an available port. The caller can
-// use the Addr method of TCPListener to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
- switch net {
- case "tcp", "tcp4", "tcp6":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- laddr = &TCPAddr{}
- }
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", noCancel)
+func listenTCP(ctx context.Context, network string, laddr *TCPAddr) (*TCPListener, error) {
+ fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_STREAM, 0, "listen")
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
return &TCPListener{fd}, nil
}
diff --git a/libgo/go/net/tcp_test.go b/libgo/go/net/tcpsock_test.go
index 9da6f6cdd0..51154221d0 100644
--- a/libgo/go/net/tcp_test.go
+++ b/libgo/go/net/tcpsock_test.go
@@ -5,6 +5,8 @@
package net
import (
+ "fmt"
+ "internal/testenv"
"io"
"reflect"
"runtime"
@@ -309,6 +311,17 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+
+ {"tcp", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 80}, nil},
+ {"tcp", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
+ {"tcp4", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp4", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp6", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
+
+ {"tcp4", "[2001:db8::1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+ {"tcp6", "127.0.0.1:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+ {"tcp6", "[::ffff:127.0.0.1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
}
func TestResolveTCPAddr(t *testing.T) {
@@ -316,21 +329,17 @@ func TestResolveTCPAddr(t *testing.T) {
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
- for i, tt := range resolveTCPAddrTests {
+ for _, tt := range resolveTCPAddrTests {
addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
- if err != tt.err {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(addr, tt.addr) {
- t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
- }
- if err != nil {
+ if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
continue
}
- rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
- if err != nil {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(rtaddr, addr) {
- t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+ if err == nil {
+ addr2, err := ResolveTCPAddr(addr.Network(), addr.String())
+ if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+ t.Errorf("(%q, %q): ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+ }
}
}
}
@@ -345,9 +354,7 @@ var tcpListenerNameTests = []struct {
}
func TestTCPListenerName(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
for _, tt := range tcpListenerNameTests {
ln, err := ListenTCP(tt.net, tt.laddr)
@@ -363,9 +370,8 @@ func TestTCPListenerName(t *testing.T) {
}
func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv6 {
t.Skip("IPv6 is not supported")
}
@@ -461,13 +467,19 @@ func TestTCPConcurrentAccept(t *testing.T) {
}
func TestTCPReadWriteAllocs(t *testing.T) {
- t.Skip("skipping test on gccgo until escape analysis is turned on")
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo until escape analysis is enabled")
+ }
+
switch runtime.GOOS {
- case "nacl", "windows":
+ case "plan9":
+ // The implementation of asynchronous cancelable
+ // I/O on Plan 9 allocates memory.
+ // See net/fd_io_plan9.go.
+ t.Skipf("not supported on %s", runtime.GOOS)
+ case "nacl":
// NaCl needs to allocate pseudo file descriptor
// stuff. See syscall/fd_nacl.go.
- // Windows uses closures and channels for IO
- // completion port-based netpoll. See fd_windows.go.
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -477,7 +489,7 @@ func TestTCPReadWriteAllocs(t *testing.T) {
}
defer ln.Close()
var server Conn
- errc := make(chan error)
+ errc := make(chan error, 1)
go func() {
var err error
server, err = ln.Accept()
@@ -492,6 +504,7 @@ func TestTCPReadWriteAllocs(t *testing.T) {
t.Fatal(err)
}
defer server.Close()
+
var buf [128]byte
allocs := testing.AllocsPerRun(1000, func() {
_, err := server.Write(buf[:])
@@ -503,6 +516,29 @@ func TestTCPReadWriteAllocs(t *testing.T) {
t.Fatal(err)
}
})
+ // For gccgo changed "> 0" to "> 7".
+ if allocs > 7 {
+ t.Fatalf("got %v; want 0", allocs)
+ }
+
+ var bufwrt [128]byte
+ ch := make(chan bool)
+ defer close(ch)
+ go func() {
+ for <-ch {
+ _, err := server.Write(bufwrt[:])
+ errc <- err
+ }
+ }()
+ allocs = testing.AllocsPerRun(1000, func() {
+ ch <- true
+ if _, err = io.ReadFull(client, buf[:]); err != nil {
+ t.Fatal(err)
+ }
+ if err := <-errc; err != nil {
+ t.Fatal(err)
+ }
+ })
if allocs > 0 {
t.Fatalf("got %v; want 0", allocs)
}
@@ -589,3 +625,105 @@ func TestTCPStress(t *testing.T) {
ln.Close()
<-done
}
+
+func TestTCPSelfConnect(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // TODO(brainman): do not know why it hangs.
+ t.Skip("known-broken test on windows")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var d Dialer
+ c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+ if err != nil {
+ ln.Close()
+ t.Fatal(err)
+ }
+ network := c.LocalAddr().Network()
+ laddr := *c.LocalAddr().(*TCPAddr)
+ c.Close()
+ ln.Close()
+
+ // Try to connect to that address repeatedly.
+ n := 100000
+ if testing.Short() {
+ n = 1000
+ }
+ switch runtime.GOOS {
+ case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
+ // Non-Linux systems take a long time to figure
+ // out that there is nothing listening on localhost.
+ n = 100
+ }
+ for i := 0; i < n; i++ {
+ d.Timeout = time.Millisecond
+ c, err := d.Dial(network, laddr.String())
+ if err == nil {
+ addr := c.LocalAddr().(*TCPAddr)
+ if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) {
+ t.Errorf("Dial %v should fail", addr)
+ } else {
+ t.Logf("Dial %v succeeded - possibly racing with other listener", addr)
+ }
+ c.Close()
+ }
+ }
+}
+
+// Test that >32-bit reads work on 64-bit systems.
+// On 32-bit systems this tests that maxint reads work.
+func TestTCPBig(t *testing.T) {
+ if !*testTCPBig {
+ t.Skip("test disabled; use -tcpbig to enable")
+ }
+
+ for _, writev := range []bool{false, true} {
+ t.Run(fmt.Sprintf("writev=%v", writev), func(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ x := int(1 << 30)
+ x = x*5 + 1<<20 // just over 5 GB on 64-bit, just over 1GB on 32-bit
+ done := make(chan int)
+ go func() {
+ defer close(done)
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ buf := make([]byte, x)
+ var n int
+ if writev {
+ var n64 int64
+ n64, err = (&Buffers{buf}).WriteTo(c)
+ n = int(n64)
+ } else {
+ n, err = c.Write(buf)
+ }
+ if n != len(buf) || err != nil {
+ t.Errorf("Write(buf) = %d, %v, want %d, nil", n, err, x)
+ }
+ c.Close()
+ }()
+
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf := make([]byte, x)
+ n, err := io.ReadFull(c, buf)
+ if n != len(buf) || err != nil {
+ t.Errorf("Read(buf) = %d, %v, want %d, nil", n, err, x)
+ }
+ c.Close()
+ <-done
+ })
+ }
+}
diff --git a/libgo/go/net/tcpsock_unix_test.go b/libgo/go/net/tcpsock_unix_test.go
new file mode 100644
index 0000000000..2375fe24dc
--- /dev/null
+++ b/libgo/go/net/tcpsock_unix_test.go
@@ -0,0 +1,79 @@
+// 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
+
+package net
+
+import (
+ "runtime"
+ "sync"
+ "syscall"
+ "testing"
+ "time"
+)
+
+// See golang.org/issue/14548.
+func TestTCPSpuriousConnSetupCompletion(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func(ln Listener) {
+ defer wg.Done()
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ wg.Add(1)
+ go func(c Conn) {
+ var b [1]byte
+ c.Read(b[:])
+ c.Close()
+ wg.Done()
+ }(c)
+ }
+ }(ln)
+
+ attempts := int(1e4) // larger is better
+ wg.Add(attempts)
+ throttle := make(chan struct{}, runtime.GOMAXPROCS(-1)*2)
+ for i := 0; i < attempts; i++ {
+ throttle <- struct{}{}
+ go func(i int) {
+ defer func() {
+ <-throttle
+ wg.Done()
+ }()
+ d := Dialer{Timeout: 50 * time.Millisecond}
+ c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+ if err != nil {
+ if perr := parseDialError(err); perr != nil {
+ t.Errorf("#%d: %v (original error: %v)", i, perr, err)
+ }
+ return
+ }
+ var b [1]byte
+ if _, err := c.Write(b[:]); err != nil {
+ if perr := parseWriteError(err); perr != nil {
+ t.Errorf("#%d: %v", i, err)
+ }
+ if samePlatformError(err, syscall.ENOTCONN) {
+ t.Errorf("#%d: %v", i, err)
+ }
+ }
+ c.Close()
+ }(i)
+ }
+
+ ln.Close()
+ wg.Wait()
+}
diff --git a/libgo/go/net/tcpsockopt_darwin.go b/libgo/go/net/tcpsockopt_darwin.go
index 1f1609088b..0d1310eaf9 100644
--- a/libgo/go/net/tcpsockopt_darwin.go
+++ b/libgo/go/net/tcpsockopt_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_dragonfly.go b/libgo/go/net/tcpsockopt_dragonfly.go
index 0aa213239d..7cc716bad1 100644
--- a/libgo/go/net/tcpsockopt_dragonfly.go
+++ b/libgo/go/net/tcpsockopt_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_openbsd.go b/libgo/go/net/tcpsockopt_openbsd.go
index 041e1786a9..10e1bef3e5 100644
--- a/libgo/go/net/tcpsockopt_openbsd.go
+++ b/libgo/go/net/tcpsockopt_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_plan9.go b/libgo/go/net/tcpsockopt_plan9.go
index 157282abd3..fb56871857 100644
--- a/libgo/go/net/tcpsockopt_plan9.go
+++ b/libgo/go/net/tcpsockopt_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,9 +7,14 @@
package net
import (
+ "syscall"
"time"
)
+func setNoDelay(fd *netFD, noDelay bool) error {
+ return syscall.EPLAN9
+}
+
// Set keep alive period.
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
cmd := "keepalive " + itoa(int(d/time.Millisecond))
diff --git a/libgo/go/net/tcpsockopt_posix.go b/libgo/go/net/tcpsockopt_posix.go
index 0abf3f97f6..805b56b5c7 100644
--- a/libgo/go/net/tcpsockopt_posix.go
+++ b/libgo/go/net/tcpsockopt_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_solaris.go b/libgo/go/net/tcpsockopt_solaris.go
index eaab6b6787..347c17d7e2 100644
--- a/libgo/go/net/tcpsockopt_solaris.go
+++ b/libgo/go/net/tcpsockopt_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/net/tcpsockopt_stub.go b/libgo/go/net/tcpsockopt_stub.go
index b413a764d8..19c83e6a5f 100644
--- a/libgo/go/net/tcpsockopt_stub.go
+++ b/libgo/go/net/tcpsockopt_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_unix.go b/libgo/go/net/tcpsockopt_unix.go
index c8970d1b57..8d44fb2095 100644
--- a/libgo/go/net/tcpsockopt_unix.go
+++ b/libgo/go/net/tcpsockopt_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/tcpsockopt_windows.go b/libgo/go/net/tcpsockopt_windows.go
index ae2d7c8f18..45a4dca525 100644
--- a/libgo/go/net/tcpsockopt_windows.go
+++ b/libgo/go/net/tcpsockopt_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/net/testdata/Mark.Twain-Tom.Sawyer.txt b/libgo/go/net/testdata/Mark.Twain-Tom.Sawyer.txt
new file mode 100644
index 0000000000..c9106fd522
--- /dev/null
+++ b/libgo/go/net/testdata/Mark.Twain-Tom.Sawyer.txt
@@ -0,0 +1,8465 @@
+Produced by David Widger. The previous edition was updated by Jose
+Menendez.
+
+
+
+
+
+ THE ADVENTURES OF TOM SAWYER
+ BY
+ MARK TWAIN
+ (Samuel Langhorne Clemens)
+
+
+
+
+ P R E F A C E
+
+MOST of the adventures recorded in this book really occurred; one or
+two were experiences of my own, the rest those of boys who were
+schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
+not from an individual--he is a combination of the characteristics of
+three boys whom I knew, and therefore belongs to the composite order of
+architecture.
+
+The odd superstitions touched upon were all prevalent among children
+and slaves in the West at the period of this story--that is to say,
+thirty or forty years ago.
+
+Although my book is intended mainly for the entertainment of boys and
+girls, I hope it will not be shunned by men and women on that account,
+for part of my plan has been to try to pleasantly remind adults of what
+they once were themselves, and of how they felt and thought and talked,
+and what queer enterprises they sometimes engaged in.
+
+ THE AUTHOR.
+
+HARTFORD, 1876.
+
+
+
+ T O M S A W Y E R
+
+
+
+CHAPTER I
+
+"TOM!"
+
+No answer.
+
+"TOM!"
+
+No answer.
+
+"What's gone with that boy, I wonder? You TOM!"
+
+No answer.
+
+The old lady pulled her spectacles down and looked over them about the
+room; then she put them up and looked out under them. She seldom or
+never looked THROUGH them for so small a thing as a boy; they were her
+state pair, the pride of her heart, and were built for "style," not
+service--she could have seen through a pair of stove-lids just as well.
+She looked perplexed for a moment, and then said, not fiercely, but
+still loud enough for the furniture to hear:
+
+"Well, I lay if I get hold of you I'll--"
+
+She did not finish, for by this time she was bending down and punching
+under the bed with the broom, and so she needed breath to punctuate the
+punches with. She resurrected nothing but the cat.
+
+"I never did see the beat of that boy!"
+
+She went to the open door and stood in it and looked out among the
+tomato vines and "jimpson" weeds that constituted the garden. No Tom.
+So she lifted up her voice at an angle calculated for distance and
+shouted:
+
+"Y-o-u-u TOM!"
+
+There was a slight noise behind her and she turned just in time to
+seize a small boy by the slack of his roundabout and arrest his flight.
+
+"There! I might 'a' thought of that closet. What you been doing in
+there?"
+
+"Nothing."
+
+"Nothing! Look at your hands. And look at your mouth. What IS that
+truck?"
+
+"I don't know, aunt."
+
+"Well, I know. It's jam--that's what it is. Forty times I've said if
+you didn't let that jam alone I'd skin you. Hand me that switch."
+
+The switch hovered in the air--the peril was desperate--
+
+"My! Look behind you, aunt!"
+
+The old lady whirled round, and snatched her skirts out of danger. The
+lad fled on the instant, scrambled up the high board-fence, and
+disappeared over it.
+
+His aunt Polly stood surprised a moment, and then broke into a gentle
+laugh.
+
+"Hang the boy, can't I never learn anything? Ain't he played me tricks
+enough like that for me to be looking out for him by this time? But old
+fools is the biggest fools there is. Can't learn an old dog new tricks,
+as the saying is. But my goodness, he never plays them alike, two days,
+and how is a body to know what's coming? He 'pears to know just how
+long he can torment me before I get my dander up, and he knows if he
+can make out to put me off for a minute or make me laugh, it's all down
+again and I can't hit him a lick. I ain't doing my duty by that boy,
+and that's the Lord's truth, goodness knows. Spare the rod and spile
+the child, as the Good Book says. I'm a laying up sin and suffering for
+us both, I know. He's full of the Old Scratch, but laws-a-me! he's my
+own dead sister's boy, poor thing, and I ain't got the heart to lash
+him, somehow. Every time I let him off, my conscience does hurt me so,
+and every time I hit him my old heart most breaks. Well-a-well, man
+that is born of woman is of few days and full of trouble, as the
+Scripture says, and I reckon it's so. He'll play hookey this evening, *
+and [* Southwestern for "afternoon"] I'll just be obleeged to make him
+work, to-morrow, to punish him. It's mighty hard to make him work
+Saturdays, when all the boys is having holiday, but he hates work more
+than he hates anything else, and I've GOT to do some of my duty by him,
+or I'll be the ruination of the child."
+
+Tom did play hookey, and he had a very good time. He got back home
+barely in season to help Jim, the small colored boy, saw next-day's
+wood and split the kindlings before supper--at least he was there in
+time to tell his adventures to Jim while Jim did three-fourths of the
+work. Tom's younger brother (or rather half-brother) Sid was already
+through with his part of the work (picking up chips), for he was a
+quiet boy, and had no adventurous, troublesome ways.
+
+While Tom was eating his supper, and stealing sugar as opportunity
+offered, Aunt Polly asked him questions that were full of guile, and
+very deep--for she wanted to trap him into damaging revealments. Like
+many other simple-hearted souls, it was her pet vanity to believe she
+was endowed with a talent for dark and mysterious diplomacy, and she
+loved to contemplate her most transparent devices as marvels of low
+cunning. Said she:
+
+"Tom, it was middling warm in school, warn't it?"
+
+"Yes'm."
+
+"Powerful warm, warn't it?"
+
+"Yes'm."
+
+"Didn't you want to go in a-swimming, Tom?"
+
+A bit of a scare shot through Tom--a touch of uncomfortable suspicion.
+He searched Aunt Polly's face, but it told him nothing. So he said:
+
+"No'm--well, not very much."
+
+The old lady reached out her hand and felt Tom's shirt, and said:
+
+"But you ain't too warm now, though." And it flattered her to reflect
+that she had discovered that the shirt was dry without anybody knowing
+that that was what she had in her mind. But in spite of her, Tom knew
+where the wind lay, now. So he forestalled what might be the next move:
+
+"Some of us pumped on our heads--mine's damp yet. See?"
+
+Aunt Polly was vexed to think she had overlooked that bit of
+circumstantial evidence, and missed a trick. Then she had a new
+inspiration:
+
+"Tom, you didn't have to undo your shirt collar where I sewed it, to
+pump on your head, did you? Unbutton your jacket!"
+
+The trouble vanished out of Tom's face. He opened his jacket. His
+shirt collar was securely sewed.
+
+"Bother! Well, go 'long with you. I'd made sure you'd played hookey
+and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a
+singed cat, as the saying is--better'n you look. THIS time."
+
+She was half sorry her sagacity had miscarried, and half glad that Tom
+had stumbled into obedient conduct for once.
+
+But Sidney said:
+
+"Well, now, if I didn't think you sewed his collar with white thread,
+but it's black."
+
+"Why, I did sew it with white! Tom!"
+
+But Tom did not wait for the rest. As he went out at the door he said:
+
+"Siddy, I'll lick you for that."
+
+In a safe place Tom examined two large needles which were thrust into
+the lapels of his jacket, and had thread bound about them--one needle
+carried white thread and the other black. He said:
+
+"She'd never noticed if it hadn't been for Sid. Confound it! sometimes
+she sews it with white, and sometimes she sews it with black. I wish to
+geeminy she'd stick to one or t'other--I can't keep the run of 'em. But
+I bet you I'll lam Sid for that. I'll learn him!"
+
+He was not the Model Boy of the village. He knew the model boy very
+well though--and loathed him.
+
+Within two minutes, or even less, he had forgotten all his troubles.
+Not because his troubles were one whit less heavy and bitter to him
+than a man's are to a man, but because a new and powerful interest bore
+them down and drove them out of his mind for the time--just as men's
+misfortunes are forgotten in the excitement of new enterprises. This
+new interest was a valued novelty in whistling, which he had just
+acquired from a negro, and he was suffering to practise it undisturbed.
+It consisted in a peculiar bird-like turn, a sort of liquid warble,
+produced by touching the tongue to the roof of the mouth at short
+intervals in the midst of the music--the reader probably remembers how
+to do it, if he has ever been a boy. Diligence and attention soon gave
+him the knack of it, and he strode down the street with his mouth full
+of harmony and his soul full of gratitude. He felt much as an
+astronomer feels who has discovered a new planet--no doubt, as far as
+strong, deep, unalloyed pleasure is concerned, the advantage was with
+the boy, not the astronomer.
+
+The summer evenings were long. It was not dark, yet. Presently Tom
+checked his whistle. A stranger was before him--a boy a shade larger
+than himself. A new-comer of any age or either sex was an impressive
+curiosity in the poor little shabby village of St. Petersburg. This boy
+was well dressed, too--well dressed on a week-day. This was simply
+astounding. His cap was a dainty thing, his close-buttoned blue cloth
+roundabout was new and natty, and so were his pantaloons. He had shoes
+on--and it was only Friday. He even wore a necktie, a bright bit of
+ribbon. He had a citified air about him that ate into Tom's vitals. The
+more Tom stared at the splendid marvel, the higher he turned up his
+nose at his finery and the shabbier and shabbier his own outfit seemed
+to him to grow. Neither boy spoke. If one moved, the other moved--but
+only sidewise, in a circle; they kept face to face and eye to eye all
+the time. Finally Tom said:
+
+"I can lick you!"
+
+"I'd like to see you try it."
+
+"Well, I can do it."
+
+"No you can't, either."
+
+"Yes I can."
+
+"No you can't."
+
+"I can."
+
+"You can't."
+
+"Can!"
+
+"Can't!"
+
+An uncomfortable pause. Then Tom said:
+
+"What's your name?"
+
+"'Tisn't any of your business, maybe."
+
+"Well I 'low I'll MAKE it my business."
+
+"Well why don't you?"
+
+"If you say much, I will."
+
+"Much--much--MUCH. There now."
+
+"Oh, you think you're mighty smart, DON'T you? I could lick you with
+one hand tied behind me, if I wanted to."
+
+"Well why don't you DO it? You SAY you can do it."
+
+"Well I WILL, if you fool with me."
+
+"Oh yes--I've seen whole families in the same fix."
+
+"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!"
+
+"You can lump that hat if you don't like it. I dare you to knock it
+off--and anybody that'll take a dare will suck eggs."
+
+"You're a liar!"
+
+"You're another."
+
+"You're a fighting liar and dasn't take it up."
+
+"Aw--take a walk!"
+
+"Say--if you give me much more of your sass I'll take and bounce a
+rock off'n your head."
+
+"Oh, of COURSE you will."
+
+"Well I WILL."
+
+"Well why don't you DO it then? What do you keep SAYING you will for?
+Why don't you DO it? It's because you're afraid."
+
+"I AIN'T afraid."
+
+"You are."
+
+"I ain't."
+
+"You are."
+
+Another pause, and more eying and sidling around each other. Presently
+they were shoulder to shoulder. Tom said:
+
+"Get away from here!"
+
+"Go away yourself!"
+
+"I won't."
+
+"I won't either."
+
+So they stood, each with a foot placed at an angle as a brace, and
+both shoving with might and main, and glowering at each other with
+hate. But neither could get an advantage. After struggling till both
+were hot and flushed, each relaxed his strain with watchful caution,
+and Tom said:
+
+"You're a coward and a pup. I'll tell my big brother on you, and he
+can thrash you with his little finger, and I'll make him do it, too."
+
+"What do I care for your big brother? I've got a brother that's bigger
+than he is--and what's more, he can throw him over that fence, too."
+[Both brothers were imaginary.]
+
+"That's a lie."
+
+"YOUR saying so don't make it so."
+
+Tom drew a line in the dust with his big toe, and said:
+
+"I dare you to step over that, and I'll lick you till you can't stand
+up. Anybody that'll take a dare will steal sheep."
+
+The new boy stepped over promptly, and said:
+
+"Now you said you'd do it, now let's see you do it."
+
+"Don't you crowd me now; you better look out."
+
+"Well, you SAID you'd do it--why don't you do it?"
+
+"By jingo! for two cents I WILL do it."
+
+The new boy took two broad coppers out of his pocket and held them out
+with derision. Tom struck them to the ground. In an instant both boys
+were rolling and tumbling in the dirt, gripped together like cats; and
+for the space of a minute they tugged and tore at each other's hair and
+clothes, punched and scratched each other's nose, and covered
+themselves with dust and glory. Presently the confusion took form, and
+through the fog of battle Tom appeared, seated astride the new boy, and
+pounding him with his fists. "Holler 'nuff!" said he.
+
+The boy only struggled to free himself. He was crying--mainly from rage.
+
+"Holler 'nuff!"--and the pounding went on.
+
+At last the stranger got out a smothered "'Nuff!" and Tom let him up
+and said:
+
+"Now that'll learn you. Better look out who you're fooling with next
+time."
+
+The new boy went off brushing the dust from his clothes, sobbing,
+snuffling, and occasionally looking back and shaking his head and
+threatening what he would do to Tom the "next time he caught him out."
+To which Tom responded with jeers, and started off in high feather, and
+as soon as his back was turned the new boy snatched up a stone, threw
+it and hit him between the shoulders and then turned tail and ran like
+an antelope. Tom chased the traitor home, and thus found out where he
+lived. He then held a position at the gate for some time, daring the
+enemy to come outside, but the enemy only made faces at him through the
+window and declined. At last the enemy's mother appeared, and called
+Tom a bad, vicious, vulgar child, and ordered him away. So he went
+away; but he said he "'lowed" to "lay" for that boy.
+
+He got home pretty late that night, and when he climbed cautiously in
+at the window, he uncovered an ambuscade, in the person of his aunt;
+and when she saw the state his clothes were in her resolution to turn
+his Saturday holiday into captivity at hard labor became adamantine in
+its firmness.
+
+
+
+CHAPTER II
+
+SATURDAY morning was come, and all the summer world was bright and
+fresh, and brimming with life. There was a song in every heart; and if
+the heart was young the music issued at the lips. There was cheer in
+every face and a spring in every step. The locust-trees were in bloom
+and the fragrance of the blossoms filled the air. Cardiff Hill, beyond
+the village and above it, was green with vegetation and it lay just far
+enough away to seem a Delectable Land, dreamy, reposeful, and inviting.
+
+Tom appeared on the sidewalk with a bucket of whitewash and a
+long-handled brush. He surveyed the fence, and all gladness left him and
+a deep melancholy settled down upon his spirit. Thirty yards of board
+fence nine feet high. Life to him seemed hollow, and existence but a
+burden. Sighing, he dipped his brush and passed it along the topmost
+plank; repeated the operation; did it again; compared the insignificant
+whitewashed streak with the far-reaching continent of unwhitewashed
+fence, and sat down on a tree-box discouraged. Jim came skipping out at
+the gate with a tin pail, and singing Buffalo Gals. Bringing water from
+the town pump had always been hateful work in Tom's eyes, before, but
+now it did not strike him so. He remembered that there was company at
+the pump. White, mulatto, and negro boys and girls were always there
+waiting their turns, resting, trading playthings, quarrelling,
+fighting, skylarking. And he remembered that although the pump was only
+a hundred and fifty yards off, Jim never got back with a bucket of
+water under an hour--and even then somebody generally had to go after
+him. Tom said:
+
+"Say, Jim, I'll fetch the water if you'll whitewash some."
+
+Jim shook his head and said:
+
+"Can't, Mars Tom. Ole missis, she tole me I got to go an' git dis
+water an' not stop foolin' roun' wid anybody. She say she spec' Mars
+Tom gwine to ax me to whitewash, an' so she tole me go 'long an' 'tend
+to my own business--she 'lowed SHE'D 'tend to de whitewashin'."
+
+"Oh, never you mind what she said, Jim. That's the way she always
+talks. Gimme the bucket--I won't be gone only a a minute. SHE won't
+ever know."
+
+"Oh, I dasn't, Mars Tom. Ole missis she'd take an' tar de head off'n
+me. 'Deed she would."
+
+"SHE! She never licks anybody--whacks 'em over the head with her
+thimble--and who cares for that, I'd like to know. She talks awful, but
+talk don't hurt--anyways it don't if she don't cry. Jim, I'll give you
+a marvel. I'll give you a white alley!"
+
+Jim began to waver.
+
+"White alley, Jim! And it's a bully taw."
+
+"My! Dat's a mighty gay marvel, I tell you! But Mars Tom I's powerful
+'fraid ole missis--"
+
+"And besides, if you will I'll show you my sore toe."
+
+Jim was only human--this attraction was too much for him. He put down
+his pail, took the white alley, and bent over the toe with absorbing
+interest while the bandage was being unwound. In another moment he was
+flying down the street with his pail and a tingling rear, Tom was
+whitewashing with vigor, and Aunt Polly was retiring from the field
+with a slipper in her hand and triumph in her eye.
+
+But Tom's energy did not last. He began to think of the fun he had
+planned for this day, and his sorrows multiplied. Soon the free boys
+would come tripping along on all sorts of delicious expeditions, and
+they would make a world of fun of him for having to work--the very
+thought of it burnt him like fire. He got out his worldly wealth and
+examined it--bits of toys, marbles, and trash; enough to buy an
+exchange of WORK, maybe, but not half enough to buy so much as half an
+hour of pure freedom. So he returned his straitened means to his
+pocket, and gave up the idea of trying to buy the boys. At this dark
+and hopeless moment an inspiration burst upon him! Nothing less than a
+great, magnificent inspiration.
+
+He took up his brush and went tranquilly to work. Ben Rogers hove in
+sight presently--the very boy, of all boys, whose ridicule he had been
+dreading. Ben's gait was the hop-skip-and-jump--proof enough that his
+heart was light and his anticipations high. He was eating an apple, and
+giving a long, melodious whoop, at intervals, followed by a deep-toned
+ding-dong-dong, ding-dong-dong, for he was personating a steamboat. As
+he drew near, he slackened speed, took the middle of the street, leaned
+far over to starboard and rounded to ponderously and with laborious
+pomp and circumstance--for he was personating the Big Missouri, and
+considered himself to be drawing nine feet of water. He was boat and
+captain and engine-bells combined, so he had to imagine himself
+standing on his own hurricane-deck giving the orders and executing them:
+
+"Stop her, sir! Ting-a-ling-ling!" The headway ran almost out, and he
+drew up slowly toward the sidewalk.
+
+"Ship up to back! Ting-a-ling-ling!" His arms straightened and
+stiffened down his sides.
+
+"Set her back on the stabboard! Ting-a-ling-ling! Chow! ch-chow-wow!
+Chow!" His right hand, meantime, describing stately circles--for it was
+representing a forty-foot wheel.
+
+"Let her go back on the labboard! Ting-a-lingling! Chow-ch-chow-chow!"
+The left hand began to describe circles.
+
+"Stop the stabboard! Ting-a-ling-ling! Stop the labboard! Come ahead
+on the stabboard! Stop her! Let your outside turn over slow!
+Ting-a-ling-ling! Chow-ow-ow! Get out that head-line! LIVELY now!
+Come--out with your spring-line--what're you about there! Take a turn
+round that stump with the bight of it! Stand by that stage, now--let her
+go! Done with the engines, sir! Ting-a-ling-ling! SH'T! S'H'T! SH'T!"
+(trying the gauge-cocks).
+
+Tom went on whitewashing--paid no attention to the steamboat. Ben
+stared a moment and then said: "Hi-YI! YOU'RE up a stump, ain't you!"
+
+No answer. Tom surveyed his last touch with the eye of an artist, then
+he gave his brush another gentle sweep and surveyed the result, as
+before. Ben ranged up alongside of him. Tom's mouth watered for the
+apple, but he stuck to his work. Ben said:
+
+"Hello, old chap, you got to work, hey?"
+
+Tom wheeled suddenly and said:
+
+"Why, it's you, Ben! I warn't noticing."
+
+"Say--I'm going in a-swimming, I am. Don't you wish you could? But of
+course you'd druther WORK--wouldn't you? Course you would!"
+
+Tom contemplated the boy a bit, and said:
+
+"What do you call work?"
+
+"Why, ain't THAT work?"
+
+Tom resumed his whitewashing, and answered carelessly:
+
+"Well, maybe it is, and maybe it ain't. All I know, is, it suits Tom
+Sawyer."
+
+"Oh come, now, you don't mean to let on that you LIKE it?"
+
+The brush continued to move.
+
+"Like it? Well, I don't see why I oughtn't to like it. Does a boy get
+a chance to whitewash a fence every day?"
+
+That put the thing in a new light. Ben stopped nibbling his apple. Tom
+swept his brush daintily back and forth--stepped back to note the
+effect--added a touch here and there--criticised the effect again--Ben
+watching every move and getting more and more interested, more and more
+absorbed. Presently he said:
+
+"Say, Tom, let ME whitewash a little."
+
+Tom considered, was about to consent; but he altered his mind:
+
+"No--no--I reckon it wouldn't hardly do, Ben. You see, Aunt Polly's
+awful particular about this fence--right here on the street, you know
+--but if it was the back fence I wouldn't mind and SHE wouldn't. Yes,
+she's awful particular about this fence; it's got to be done very
+careful; I reckon there ain't one boy in a thousand, maybe two
+thousand, that can do it the way it's got to be done."
+
+"No--is that so? Oh come, now--lemme just try. Only just a little--I'd
+let YOU, if you was me, Tom."
+
+"Ben, I'd like to, honest injun; but Aunt Polly--well, Jim wanted to
+do it, but she wouldn't let him; Sid wanted to do it, and she wouldn't
+let Sid. Now don't you see how I'm fixed? If you was to tackle this
+fence and anything was to happen to it--"
+
+"Oh, shucks, I'll be just as careful. Now lemme try. Say--I'll give
+you the core of my apple."
+
+"Well, here--No, Ben, now don't. I'm afeard--"
+
+"I'll give you ALL of it!"
+
+Tom gave up the brush with reluctance in his face, but alacrity in his
+heart. And while the late steamer Big Missouri worked and sweated in
+the sun, the retired artist sat on a barrel in the shade close by,
+dangled his legs, munched his apple, and planned the slaughter of more
+innocents. There was no lack of material; boys happened along every
+little while; they came to jeer, but remained to whitewash. By the time
+Ben was fagged out, Tom had traded the next chance to Billy Fisher for
+a kite, in good repair; and when he played out, Johnny Miller bought in
+for a dead rat and a string to swing it with--and so on, and so on,
+hour after hour. And when the middle of the afternoon came, from being
+a poor poverty-stricken boy in the morning, Tom was literally rolling
+in wealth. He had besides the things before mentioned, twelve marbles,
+part of a jews-harp, a piece of blue bottle-glass to look through, a
+spool cannon, a key that wouldn't unlock anything, a fragment of chalk,
+a glass stopper of a decanter, a tin soldier, a couple of tadpoles, six
+fire-crackers, a kitten with only one eye, a brass doorknob, a
+dog-collar--but no dog--the handle of a knife, four pieces of
+orange-peel, and a dilapidated old window sash.
+
+He had had a nice, good, idle time all the while--plenty of company
+--and the fence had three coats of whitewash on it! If he hadn't run out
+of whitewash he would have bankrupted every boy in the village.
+
+Tom said to himself that it was not such a hollow world, after all. He
+had discovered a great law of human action, without knowing it--namely,
+that in order to make a man or a boy covet a thing, it is only
+necessary to make the thing difficult to attain. If he had been a great
+and wise philosopher, like the writer of this book, he would now have
+comprehended that Work consists of whatever a body is OBLIGED to do,
+and that Play consists of whatever a body is not obliged to do. And
+this would help him to understand why constructing artificial flowers
+or performing on a tread-mill is work, while rolling ten-pins or
+climbing Mont Blanc is only amusement. There are wealthy gentlemen in
+England who drive four-horse passenger-coaches twenty or thirty miles
+on a daily line, in the summer, because the privilege costs them
+considerable money; but if they were offered wages for the service,
+that would turn it into work and then they would resign.
+
+The boy mused awhile over the substantial change which had taken place
+in his worldly circumstances, and then wended toward headquarters to
+report.
+
+
+
+CHAPTER III
+
+TOM presented himself before Aunt Polly, who was sitting by an open
+window in a pleasant rearward apartment, which was bedroom,
+breakfast-room, dining-room, and library, combined. The balmy summer
+air, the restful quiet, the odor of the flowers, and the drowsing murmur
+of the bees had had their effect, and she was nodding over her knitting
+--for she had no company but the cat, and it was asleep in her lap. Her
+spectacles were propped up on her gray head for safety. She had thought
+that of course Tom had deserted long ago, and she wondered at seeing him
+place himself in her power again in this intrepid way. He said: "Mayn't
+I go and play now, aunt?"
+
+"What, a'ready? How much have you done?"
+
+"It's all done, aunt."
+
+"Tom, don't lie to me--I can't bear it."
+
+"I ain't, aunt; it IS all done."
+
+Aunt Polly placed small trust in such evidence. She went out to see
+for herself; and she would have been content to find twenty per cent.
+of Tom's statement true. When she found the entire fence whitewashed,
+and not only whitewashed but elaborately coated and recoated, and even
+a streak added to the ground, her astonishment was almost unspeakable.
+She said:
+
+"Well, I never! There's no getting round it, you can work when you're
+a mind to, Tom." And then she diluted the compliment by adding, "But
+it's powerful seldom you're a mind to, I'm bound to say. Well, go 'long
+and play; but mind you get back some time in a week, or I'll tan you."
+
+She was so overcome by the splendor of his achievement that she took
+him into the closet and selected a choice apple and delivered it to
+him, along with an improving lecture upon the added value and flavor a
+treat took to itself when it came without sin through virtuous effort.
+And while she closed with a happy Scriptural flourish, he "hooked" a
+doughnut.
+
+Then he skipped out, and saw Sid just starting up the outside stairway
+that led to the back rooms on the second floor. Clods were handy and
+the air was full of them in a twinkling. They raged around Sid like a
+hail-storm; and before Aunt Polly could collect her surprised faculties
+and sally to the rescue, six or seven clods had taken personal effect,
+and Tom was over the fence and gone. There was a gate, but as a general
+thing he was too crowded for time to make use of it. His soul was at
+peace, now that he had settled with Sid for calling attention to his
+black thread and getting him into trouble.
+
+Tom skirted the block, and came round into a muddy alley that led by
+the back of his aunt's cow-stable. He presently got safely beyond the
+reach of capture and punishment, and hastened toward the public square
+of the village, where two "military" companies of boys had met for
+conflict, according to previous appointment. Tom was General of one of
+these armies, Joe Harper (a bosom friend) General of the other. These
+two great commanders did not condescend to fight in person--that being
+better suited to the still smaller fry--but sat together on an eminence
+and conducted the field operations by orders delivered through
+aides-de-camp. Tom's army won a great victory, after a long and
+hard-fought battle. Then the dead were counted, prisoners exchanged,
+the terms of the next disagreement agreed upon, and the day for the
+necessary battle appointed; after which the armies fell into line and
+marched away, and Tom turned homeward alone.
+
+As he was passing by the house where Jeff Thatcher lived, he saw a new
+girl in the garden--a lovely little blue-eyed creature with yellow hair
+plaited into two long-tails, white summer frock and embroidered
+pantalettes. The fresh-crowned hero fell without firing a shot. A
+certain Amy Lawrence vanished out of his heart and left not even a
+memory of herself behind. He had thought he loved her to distraction;
+he had regarded his passion as adoration; and behold it was only a poor
+little evanescent partiality. He had been months winning her; she had
+confessed hardly a week ago; he had been the happiest and the proudest
+boy in the world only seven short days, and here in one instant of time
+she had gone out of his heart like a casual stranger whose visit is
+done.
+
+He worshipped this new angel with furtive eye, till he saw that she
+had discovered him; then he pretended he did not know she was present,
+and began to "show off" in all sorts of absurd boyish ways, in order to
+win her admiration. He kept up this grotesque foolishness for some
+time; but by-and-by, while he was in the midst of some dangerous
+gymnastic performances, he glanced aside and saw that the little girl
+was wending her way toward the house. Tom came up to the fence and
+leaned on it, grieving, and hoping she would tarry yet awhile longer.
+She halted a moment on the steps and then moved toward the door. Tom
+heaved a great sigh as she put her foot on the threshold. But his face
+lit up, right away, for she tossed a pansy over the fence a moment
+before she disappeared.
+
+The boy ran around and stopped within a foot or two of the flower, and
+then shaded his eyes with his hand and began to look down street as if
+he had discovered something of interest going on in that direction.
+Presently he picked up a straw and began trying to balance it on his
+nose, with his head tilted far back; and as he moved from side to side,
+in his efforts, he edged nearer and nearer toward the pansy; finally
+his bare foot rested upon it, his pliant toes closed upon it, and he
+hopped away with the treasure and disappeared round the corner. But
+only for a minute--only while he could button the flower inside his
+jacket, next his heart--or next his stomach, possibly, for he was not
+much posted in anatomy, and not hypercritical, anyway.
+
+He returned, now, and hung about the fence till nightfall, "showing
+off," as before; but the girl never exhibited herself again, though Tom
+comforted himself a little with the hope that she had been near some
+window, meantime, and been aware of his attentions. Finally he strode
+home reluctantly, with his poor head full of visions.
+
+All through supper his spirits were so high that his aunt wondered
+"what had got into the child." He took a good scolding about clodding
+Sid, and did not seem to mind it in the least. He tried to steal sugar
+under his aunt's very nose, and got his knuckles rapped for it. He said:
+
+"Aunt, you don't whack Sid when he takes it."
+
+"Well, Sid don't torment a body the way you do. You'd be always into
+that sugar if I warn't watching you."
+
+Presently she stepped into the kitchen, and Sid, happy in his
+immunity, reached for the sugar-bowl--a sort of glorying over Tom which
+was wellnigh unbearable. But Sid's fingers slipped and the bowl dropped
+and broke. Tom was in ecstasies. In such ecstasies that he even
+controlled his tongue and was silent. He said to himself that he would
+not speak a word, even when his aunt came in, but would sit perfectly
+still till she asked who did the mischief; and then he would tell, and
+there would be nothing so good in the world as to see that pet model
+"catch it." He was so brimful of exultation that he could hardly hold
+himself when the old lady came back and stood above the wreck
+discharging lightnings of wrath from over her spectacles. He said to
+himself, "Now it's coming!" And the next instant he was sprawling on
+the floor! The potent palm was uplifted to strike again when Tom cried
+out:
+
+"Hold on, now, what 'er you belting ME for?--Sid broke it!"
+
+Aunt Polly paused, perplexed, and Tom looked for healing pity. But
+when she got her tongue again, she only said:
+
+"Umf! Well, you didn't get a lick amiss, I reckon. You been into some
+other audacious mischief when I wasn't around, like enough."
+
+Then her conscience reproached her, and she yearned to say something
+kind and loving; but she judged that this would be construed into a
+confession that she had been in the wrong, and discipline forbade that.
+So she kept silence, and went about her affairs with a troubled heart.
+Tom sulked in a corner and exalted his woes. He knew that in her heart
+his aunt was on her knees to him, and he was morosely gratified by the
+consciousness of it. He would hang out no signals, he would take notice
+of none. He knew that a yearning glance fell upon him, now and then,
+through a film of tears, but he refused recognition of it. He pictured
+himself lying sick unto death and his aunt bending over him beseeching
+one little forgiving word, but he would turn his face to the wall, and
+die with that word unsaid. Ah, how would she feel then? And he pictured
+himself brought home from the river, dead, with his curls all wet, and
+his sore heart at rest. How she would throw herself upon him, and how
+her tears would fall like rain, and her lips pray God to give her back
+her boy and she would never, never abuse him any more! But he would lie
+there cold and white and make no sign--a poor little sufferer, whose
+griefs were at an end. He so worked upon his feelings with the pathos
+of these dreams, that he had to keep swallowing, he was so like to
+choke; and his eyes swam in a blur of water, which overflowed when he
+winked, and ran down and trickled from the end of his nose. And such a
+luxury to him was this petting of his sorrows, that he could not bear
+to have any worldly cheeriness or any grating delight intrude upon it;
+it was too sacred for such contact; and so, presently, when his cousin
+Mary danced in, all alive with the joy of seeing home again after an
+age-long visit of one week to the country, he got up and moved in
+clouds and darkness out at one door as she brought song and sunshine in
+at the other.
+
+He wandered far from the accustomed haunts of boys, and sought
+desolate places that were in harmony with his spirit. A log raft in the
+river invited him, and he seated himself on its outer edge and
+contemplated the dreary vastness of the stream, wishing, the while,
+that he could only be drowned, all at once and unconsciously, without
+undergoing the uncomfortable routine devised by nature. Then he thought
+of his flower. He got it out, rumpled and wilted, and it mightily
+increased his dismal felicity. He wondered if she would pity him if she
+knew? Would she cry, and wish that she had a right to put her arms
+around his neck and comfort him? Or would she turn coldly away like all
+the hollow world? This picture brought such an agony of pleasurable
+suffering that he worked it over and over again in his mind and set it
+up in new and varied lights, till he wore it threadbare. At last he
+rose up sighing and departed in the darkness.
+
+About half-past nine or ten o'clock he came along the deserted street
+to where the Adored Unknown lived; he paused a moment; no sound fell
+upon his listening ear; a candle was casting a dull glow upon the
+curtain of a second-story window. Was the sacred presence there? He
+climbed the fence, threaded his stealthy way through the plants, till
+he stood under that window; he looked up at it long, and with emotion;
+then he laid him down on the ground under it, disposing himself upon
+his back, with his hands clasped upon his breast and holding his poor
+wilted flower. And thus he would die--out in the cold world, with no
+shelter over his homeless head, no friendly hand to wipe the
+death-damps from his brow, no loving face to bend pityingly over him
+when the great agony came. And thus SHE would see him when she looked
+out upon the glad morning, and oh! would she drop one little tear upon
+his poor, lifeless form, would she heave one little sigh to see a bright
+young life so rudely blighted, so untimely cut down?
+
+The window went up, a maid-servant's discordant voice profaned the
+holy calm, and a deluge of water drenched the prone martyr's remains!
+
+The strangling hero sprang up with a relieving snort. There was a whiz
+as of a missile in the air, mingled with the murmur of a curse, a sound
+as of shivering glass followed, and a small, vague form went over the
+fence and shot away in the gloom.
+
+Not long after, as Tom, all undressed for bed, was surveying his
+drenched garments by the light of a tallow dip, Sid woke up; but if he
+had any dim idea of making any "references to allusions," he thought
+better of it and held his peace, for there was danger in Tom's eye.
+
+Tom turned in without the added vexation of prayers, and Sid made
+mental note of the omission.
+
+
+
+CHAPTER IV
+
+THE sun rose upon a tranquil world, and beamed down upon the peaceful
+village like a benediction. Breakfast over, Aunt Polly had family
+worship: it began with a prayer built from the ground up of solid
+courses of Scriptural quotations, welded together with a thin mortar of
+originality; and from the summit of this she delivered a grim chapter
+of the Mosaic Law, as from Sinai.
+
+Then Tom girded up his loins, so to speak, and went to work to "get
+his verses." Sid had learned his lesson days before. Tom bent all his
+energies to the memorizing of five verses, and he chose part of the
+Sermon on the Mount, because he could find no verses that were shorter.
+At the end of half an hour Tom had a vague general idea of his lesson,
+but no more, for his mind was traversing the whole field of human
+thought, and his hands were busy with distracting recreations. Mary
+took his book to hear him recite, and he tried to find his way through
+the fog:
+
+"Blessed are the--a--a--"
+
+"Poor"--
+
+"Yes--poor; blessed are the poor--a--a--"
+
+"In spirit--"
+
+"In spirit; blessed are the poor in spirit, for they--they--"
+
+"THEIRS--"
+
+"For THEIRS. Blessed are the poor in spirit, for theirs is the kingdom
+of heaven. Blessed are they that mourn, for they--they--"
+
+"Sh--"
+
+"For they--a--"
+
+"S, H, A--"
+
+"For they S, H--Oh, I don't know what it is!"
+
+"SHALL!"
+
+"Oh, SHALL! for they shall--for they shall--a--a--shall mourn--a--a--
+blessed are they that shall--they that--a--they that shall mourn, for
+they shall--a--shall WHAT? Why don't you tell me, Mary?--what do you
+want to be so mean for?"
+
+"Oh, Tom, you poor thick-headed thing, I'm not teasing you. I wouldn't
+do that. You must go and learn it again. Don't you be discouraged, Tom,
+you'll manage it--and if you do, I'll give you something ever so nice.
+There, now, that's a good boy."
+
+"All right! What is it, Mary, tell me what it is."
+
+"Never you mind, Tom. You know if I say it's nice, it is nice."
+
+"You bet you that's so, Mary. All right, I'll tackle it again."
+
+And he did "tackle it again"--and under the double pressure of
+curiosity and prospective gain he did it with such spirit that he
+accomplished a shining success. Mary gave him a brand-new "Barlow"
+knife worth twelve and a half cents; and the convulsion of delight that
+swept his system shook him to his foundations. True, the knife would
+not cut anything, but it was a "sure-enough" Barlow, and there was
+inconceivable grandeur in that--though where the Western boys ever got
+the idea that such a weapon could possibly be counterfeited to its
+injury is an imposing mystery and will always remain so, perhaps. Tom
+contrived to scarify the cupboard with it, and was arranging to begin
+on the bureau, when he was called off to dress for Sunday-school.
+
+Mary gave him a tin basin of water and a piece of soap, and he went
+outside the door and set the basin on a little bench there; then he
+dipped the soap in the water and laid it down; turned up his sleeves;
+poured out the water on the ground, gently, and then entered the
+kitchen and began to wipe his face diligently on the towel behind the
+door. But Mary removed the towel and said:
+
+"Now ain't you ashamed, Tom. You mustn't be so bad. Water won't hurt
+you."
+
+Tom was a trifle disconcerted. The basin was refilled, and this time
+he stood over it a little while, gathering resolution; took in a big
+breath and began. When he entered the kitchen presently, with both eyes
+shut and groping for the towel with his hands, an honorable testimony
+of suds and water was dripping from his face. But when he emerged from
+the towel, he was not yet satisfactory, for the clean territory stopped
+short at his chin and his jaws, like a mask; below and beyond this line
+there was a dark expanse of unirrigated soil that spread downward in
+front and backward around his neck. Mary took him in hand, and when she
+was done with him he was a man and a brother, without distinction of
+color, and his saturated hair was neatly brushed, and its short curls
+wrought into a dainty and symmetrical general effect. [He privately
+smoothed out the curls, with labor and difficulty, and plastered his
+hair close down to his head; for he held curls to be effeminate, and
+his own filled his life with bitterness.] Then Mary got out a suit of
+his clothing that had been used only on Sundays during two years--they
+were simply called his "other clothes"--and so by that we know the
+size of his wardrobe. The girl "put him to rights" after he had dressed
+himself; she buttoned his neat roundabout up to his chin, turned his
+vast shirt collar down over his shoulders, brushed him off and crowned
+him with his speckled straw hat. He now looked exceedingly improved and
+uncomfortable. He was fully as uncomfortable as he looked; for there
+was a restraint about whole clothes and cleanliness that galled him. He
+hoped that Mary would forget his shoes, but the hope was blighted; she
+coated them thoroughly with tallow, as was the custom, and brought them
+out. He lost his temper and said he was always being made to do
+everything he didn't want to do. But Mary said, persuasively:
+
+"Please, Tom--that's a good boy."
+
+So he got into the shoes snarling. Mary was soon ready, and the three
+children set out for Sunday-school--a place that Tom hated with his
+whole heart; but Sid and Mary were fond of it.
+
+Sabbath-school hours were from nine to half-past ten; and then church
+service. Two of the children always remained for the sermon
+voluntarily, and the other always remained too--for stronger reasons.
+The church's high-backed, uncushioned pews would seat about three
+hundred persons; the edifice was but a small, plain affair, with a sort
+of pine board tree-box on top of it for a steeple. At the door Tom
+dropped back a step and accosted a Sunday-dressed comrade:
+
+"Say, Billy, got a yaller ticket?"
+
+"Yes."
+
+"What'll you take for her?"
+
+"What'll you give?"
+
+"Piece of lickrish and a fish-hook."
+
+"Less see 'em."
+
+Tom exhibited. They were satisfactory, and the property changed hands.
+Then Tom traded a couple of white alleys for three red tickets, and
+some small trifle or other for a couple of blue ones. He waylaid other
+boys as they came, and went on buying tickets of various colors ten or
+fifteen minutes longer. He entered the church, now, with a swarm of
+clean and noisy boys and girls, proceeded to his seat and started a
+quarrel with the first boy that came handy. The teacher, a grave,
+elderly man, interfered; then turned his back a moment and Tom pulled a
+boy's hair in the next bench, and was absorbed in his book when the boy
+turned around; stuck a pin in another boy, presently, in order to hear
+him say "Ouch!" and got a new reprimand from his teacher. Tom's whole
+class were of a pattern--restless, noisy, and troublesome. When they
+came to recite their lessons, not one of them knew his verses
+perfectly, but had to be prompted all along. However, they worried
+through, and each got his reward--in small blue tickets, each with a
+passage of Scripture on it; each blue ticket was pay for two verses of
+the recitation. Ten blue tickets equalled a red one, and could be
+exchanged for it; ten red tickets equalled a yellow one; for ten yellow
+tickets the superintendent gave a very plainly bound Bible (worth forty
+cents in those easy times) to the pupil. How many of my readers would
+have the industry and application to memorize two thousand verses, even
+for a Dore Bible? And yet Mary had acquired two Bibles in this way--it
+was the patient work of two years--and a boy of German parentage had
+won four or five. He once recited three thousand verses without
+stopping; but the strain upon his mental faculties was too great, and
+he was little better than an idiot from that day forth--a grievous
+misfortune for the school, for on great occasions, before company, the
+superintendent (as Tom expressed it) had always made this boy come out
+and "spread himself." Only the older pupils managed to keep their
+tickets and stick to their tedious work long enough to get a Bible, and
+so the delivery of one of these prizes was a rare and noteworthy
+circumstance; the successful pupil was so great and conspicuous for
+that day that on the spot every scholar's heart was fired with a fresh
+ambition that often lasted a couple of weeks. It is possible that Tom's
+mental stomach had never really hungered for one of those prizes, but
+unquestionably his entire being had for many a day longed for the glory
+and the eclat that came with it.
+
+In due course the superintendent stood up in front of the pulpit, with
+a closed hymn-book in his hand and his forefinger inserted between its
+leaves, and commanded attention. When a Sunday-school superintendent
+makes his customary little speech, a hymn-book in the hand is as
+necessary as is the inevitable sheet of music in the hand of a singer
+who stands forward on the platform and sings a solo at a concert
+--though why, is a mystery: for neither the hymn-book nor the sheet of
+music is ever referred to by the sufferer. This superintendent was a
+slim creature of thirty-five, with a sandy goatee and short sandy hair;
+he wore a stiff standing-collar whose upper edge almost reached his
+ears and whose sharp points curved forward abreast the corners of his
+mouth--a fence that compelled a straight lookout ahead, and a turning
+of the whole body when a side view was required; his chin was propped
+on a spreading cravat which was as broad and as long as a bank-note,
+and had fringed ends; his boot toes were turned sharply up, in the
+fashion of the day, like sleigh-runners--an effect patiently and
+laboriously produced by the young men by sitting with their toes
+pressed against a wall for hours together. Mr. Walters was very earnest
+of mien, and very sincere and honest at heart; and he held sacred
+things and places in such reverence, and so separated them from worldly
+matters, that unconsciously to himself his Sunday-school voice had
+acquired a peculiar intonation which was wholly absent on week-days. He
+began after this fashion:
+
+"Now, children, I want you all to sit up just as straight and pretty
+as you can and give me all your attention for a minute or two. There
+--that is it. That is the way good little boys and girls should do. I see
+one little girl who is looking out of the window--I am afraid she
+thinks I am out there somewhere--perhaps up in one of the trees making
+a speech to the little birds. [Applausive titter.] I want to tell you
+how good it makes me feel to see so many bright, clean little faces
+assembled in a place like this, learning to do right and be good." And
+so forth and so on. It is not necessary to set down the rest of the
+oration. It was of a pattern which does not vary, and so it is familiar
+to us all.
+
+The latter third of the speech was marred by the resumption of fights
+and other recreations among certain of the bad boys, and by fidgetings
+and whisperings that extended far and wide, washing even to the bases
+of isolated and incorruptible rocks like Sid and Mary. But now every
+sound ceased suddenly, with the subsidence of Mr. Walters' voice, and
+the conclusion of the speech was received with a burst of silent
+gratitude.
+
+A good part of the whispering had been occasioned by an event which
+was more or less rare--the entrance of visitors: lawyer Thatcher,
+accompanied by a very feeble and aged man; a fine, portly, middle-aged
+gentleman with iron-gray hair; and a dignified lady who was doubtless
+the latter's wife. The lady was leading a child. Tom had been restless
+and full of chafings and repinings; conscience-smitten, too--he could
+not meet Amy Lawrence's eye, he could not brook her loving gaze. But
+when he saw this small new-comer his soul was all ablaze with bliss in
+a moment. The next moment he was "showing off" with all his might
+--cuffing boys, pulling hair, making faces--in a word, using every art
+that seemed likely to fascinate a girl and win her applause. His
+exaltation had but one alloy--the memory of his humiliation in this
+angel's garden--and that record in sand was fast washing out, under
+the waves of happiness that were sweeping over it now.
+
+The visitors were given the highest seat of honor, and as soon as Mr.
+Walters' speech was finished, he introduced them to the school. The
+middle-aged man turned out to be a prodigious personage--no less a one
+than the county judge--altogether the most august creation these
+children had ever looked upon--and they wondered what kind of material
+he was made of--and they half wanted to hear him roar, and were half
+afraid he might, too. He was from Constantinople, twelve miles away--so
+he had travelled, and seen the world--these very eyes had looked upon
+the county court-house--which was said to have a tin roof. The awe
+which these reflections inspired was attested by the impressive silence
+and the ranks of staring eyes. This was the great Judge Thatcher,
+brother of their own lawyer. Jeff Thatcher immediately went forward, to
+be familiar with the great man and be envied by the school. It would
+have been music to his soul to hear the whisperings:
+
+"Look at him, Jim! He's a going up there. Say--look! he's a going to
+shake hands with him--he IS shaking hands with him! By jings, don't you
+wish you was Jeff?"
+
+Mr. Walters fell to "showing off," with all sorts of official
+bustlings and activities, giving orders, delivering judgments,
+discharging directions here, there, everywhere that he could find a
+target. The librarian "showed off"--running hither and thither with his
+arms full of books and making a deal of the splutter and fuss that
+insect authority delights in. The young lady teachers "showed off"
+--bending sweetly over pupils that were lately being boxed, lifting
+pretty warning fingers at bad little boys and patting good ones
+lovingly. The young gentlemen teachers "showed off" with small
+scoldings and other little displays of authority and fine attention to
+discipline--and most of the teachers, of both sexes, found business up
+at the library, by the pulpit; and it was business that frequently had
+to be done over again two or three times (with much seeming vexation).
+The little girls "showed off" in various ways, and the little boys
+"showed off" with such diligence that the air was thick with paper wads
+and the murmur of scufflings. And above it all the great man sat and
+beamed a majestic judicial smile upon all the house, and warmed himself
+in the sun of his own grandeur--for he was "showing off," too.
+
+There was only one thing wanting to make Mr. Walters' ecstasy
+complete, and that was a chance to deliver a Bible-prize and exhibit a
+prodigy. Several pupils had a few yellow tickets, but none had enough
+--he had been around among the star pupils inquiring. He would have given
+worlds, now, to have that German lad back again with a sound mind.
+
+And now at this moment, when hope was dead, Tom Sawyer came forward
+with nine yellow tickets, nine red tickets, and ten blue ones, and
+demanded a Bible. This was a thunderbolt out of a clear sky. Walters
+was not expecting an application from this source for the next ten
+years. But there was no getting around it--here were the certified
+checks, and they were good for their face. Tom was therefore elevated
+to a place with the Judge and the other elect, and the great news was
+announced from headquarters. It was the most stunning surprise of the
+decade, and so profound was the sensation that it lifted the new hero
+up to the judicial one's altitude, and the school had two marvels to
+gaze upon in place of one. The boys were all eaten up with envy--but
+those that suffered the bitterest pangs were those who perceived too
+late that they themselves had contributed to this hated splendor by
+trading tickets to Tom for the wealth he had amassed in selling
+whitewashing privileges. These despised themselves, as being the dupes
+of a wily fraud, a guileful snake in the grass.
+
+The prize was delivered to Tom with as much effusion as the
+superintendent could pump up under the circumstances; but it lacked
+somewhat of the true gush, for the poor fellow's instinct taught him
+that there was a mystery here that could not well bear the light,
+perhaps; it was simply preposterous that this boy had warehoused two
+thousand sheaves of Scriptural wisdom on his premises--a dozen would
+strain his capacity, without a doubt.
+
+Amy Lawrence was proud and glad, and she tried to make Tom see it in
+her face--but he wouldn't look. She wondered; then she was just a grain
+troubled; next a dim suspicion came and went--came again; she watched;
+a furtive glance told her worlds--and then her heart broke, and she was
+jealous, and angry, and the tears came and she hated everybody. Tom
+most of all (she thought).
+
+Tom was introduced to the Judge; but his tongue was tied, his breath
+would hardly come, his heart quaked--partly because of the awful
+greatness of the man, but mainly because he was her parent. He would
+have liked to fall down and worship him, if it were in the dark. The
+Judge put his hand on Tom's head and called him a fine little man, and
+asked him what his name was. The boy stammered, gasped, and got it out:
+
+"Tom."
+
+"Oh, no, not Tom--it is--"
+
+"Thomas."
+
+"Ah, that's it. I thought there was more to it, maybe. That's very
+well. But you've another one I daresay, and you'll tell it to me, won't
+you?"
+
+"Tell the gentleman your other name, Thomas," said Walters, "and say
+sir. You mustn't forget your manners."
+
+"Thomas Sawyer--sir."
+
+"That's it! That's a good boy. Fine boy. Fine, manly little fellow.
+Two thousand verses is a great many--very, very great many. And you
+never can be sorry for the trouble you took to learn them; for
+knowledge is worth more than anything there is in the world; it's what
+makes great men and good men; you'll be a great man and a good man
+yourself, some day, Thomas, and then you'll look back and say, It's all
+owing to the precious Sunday-school privileges of my boyhood--it's all
+owing to my dear teachers that taught me to learn--it's all owing to
+the good superintendent, who encouraged me, and watched over me, and
+gave me a beautiful Bible--a splendid elegant Bible--to keep and have
+it all for my own, always--it's all owing to right bringing up! That is
+what you will say, Thomas--and you wouldn't take any money for those
+two thousand verses--no indeed you wouldn't. And now you wouldn't mind
+telling me and this lady some of the things you've learned--no, I know
+you wouldn't--for we are proud of little boys that learn. Now, no
+doubt you know the names of all the twelve disciples. Won't you tell us
+the names of the first two that were appointed?"
+
+Tom was tugging at a button-hole and looking sheepish. He blushed,
+now, and his eyes fell. Mr. Walters' heart sank within him. He said to
+himself, it is not possible that the boy can answer the simplest
+question--why DID the Judge ask him? Yet he felt obliged to speak up
+and say:
+
+"Answer the gentleman, Thomas--don't be afraid."
+
+Tom still hung fire.
+
+"Now I know you'll tell me," said the lady. "The names of the first
+two disciples were--"
+
+"DAVID AND GOLIAH!"
+
+Let us draw the curtain of charity over the rest of the scene.
+
+
+
+CHAPTER V
+
+ABOUT half-past ten the cracked bell of the small church began to
+ring, and presently the people began to gather for the morning sermon.
+The Sunday-school children distributed themselves about the house and
+occupied pews with their parents, so as to be under supervision. Aunt
+Polly came, and Tom and Sid and Mary sat with her--Tom being placed
+next the aisle, in order that he might be as far away from the open
+window and the seductive outside summer scenes as possible. The crowd
+filed up the aisles: the aged and needy postmaster, who had seen better
+days; the mayor and his wife--for they had a mayor there, among other
+unnecessaries; the justice of the peace; the widow Douglass, fair,
+smart, and forty, a generous, good-hearted soul and well-to-do, her
+hill mansion the only palace in the town, and the most hospitable and
+much the most lavish in the matter of festivities that St. Petersburg
+could boast; the bent and venerable Major and Mrs. Ward; lawyer
+Riverson, the new notable from a distance; next the belle of the
+village, followed by a troop of lawn-clad and ribbon-decked young
+heart-breakers; then all the young clerks in town in a body--for they
+had stood in the vestibule sucking their cane-heads, a circling wall of
+oiled and simpering admirers, till the last girl had run their gantlet;
+and last of all came the Model Boy, Willie Mufferson, taking as heedful
+care of his mother as if she were cut glass. He always brought his
+mother to church, and was the pride of all the matrons. The boys all
+hated him, he was so good. And besides, he had been "thrown up to them"
+so much. His white handkerchief was hanging out of his pocket behind, as
+usual on Sundays--accidentally. Tom had no handkerchief, and he looked
+upon boys who had as snobs.
+
+The congregation being fully assembled, now, the bell rang once more,
+to warn laggards and stragglers, and then a solemn hush fell upon the
+church which was only broken by the tittering and whispering of the
+choir in the gallery. The choir always tittered and whispered all
+through service. There was once a church choir that was not ill-bred,
+but I have forgotten where it was, now. It was a great many years ago,
+and I can scarcely remember anything about it, but I think it was in
+some foreign country.
+
+The minister gave out the hymn, and read it through with a relish, in
+a peculiar style which was much admired in that part of the country.
+His voice began on a medium key and climbed steadily up till it reached
+a certain point, where it bore with strong emphasis upon the topmost
+word and then plunged down as if from a spring-board:
+
+ Shall I be car-ri-ed toe the skies, on flow'ry BEDS of ease,
+
+ Whilst others fight to win the prize, and sail thro' BLOODY seas?
+
+He was regarded as a wonderful reader. At church "sociables" he was
+always called upon to read poetry; and when he was through, the ladies
+would lift up their hands and let them fall helplessly in their laps,
+and "wall" their eyes, and shake their heads, as much as to say, "Words
+cannot express it; it is too beautiful, TOO beautiful for this mortal
+earth."
+
+After the hymn had been sung, the Rev. Mr. Sprague turned himself into
+a bulletin-board, and read off "notices" of meetings and societies and
+things till it seemed that the list would stretch out to the crack of
+doom--a queer custom which is still kept up in America, even in cities,
+away here in this age of abundant newspapers. Often, the less there is
+to justify a traditional custom, the harder it is to get rid of it.
+
+And now the minister prayed. A good, generous prayer it was, and went
+into details: it pleaded for the church, and the little children of the
+church; for the other churches of the village; for the village itself;
+for the county; for the State; for the State officers; for the United
+States; for the churches of the United States; for Congress; for the
+President; for the officers of the Government; for poor sailors, tossed
+by stormy seas; for the oppressed millions groaning under the heel of
+European monarchies and Oriental despotisms; for such as have the light
+and the good tidings, and yet have not eyes to see nor ears to hear
+withal; for the heathen in the far islands of the sea; and closed with
+a supplication that the words he was about to speak might find grace
+and favor, and be as seed sown in fertile ground, yielding in time a
+grateful harvest of good. Amen.
+
+There was a rustling of dresses, and the standing congregation sat
+down. The boy whose history this book relates did not enjoy the prayer,
+he only endured it--if he even did that much. He was restive all
+through it; he kept tally of the details of the prayer, unconsciously
+--for he was not listening, but he knew the ground of old, and the
+clergyman's regular route over it--and when a little trifle of new
+matter was interlarded, his ear detected it and his whole nature
+resented it; he considered additions unfair, and scoundrelly. In the
+midst of the prayer a fly had lit on the back of the pew in front of
+him and tortured his spirit by calmly rubbing its hands together,
+embracing its head with its arms, and polishing it so vigorously that
+it seemed to almost part company with the body, and the slender thread
+of a neck was exposed to view; scraping its wings with its hind legs
+and smoothing them to its body as if they had been coat-tails; going
+through its whole toilet as tranquilly as if it knew it was perfectly
+safe. As indeed it was; for as sorely as Tom's hands itched to grab for
+it they did not dare--he believed his soul would be instantly destroyed
+if he did such a thing while the prayer was going on. But with the
+closing sentence his hand began to curve and steal forward; and the
+instant the "Amen" was out the fly was a prisoner of war. His aunt
+detected the act and made him let it go.
+
+The minister gave out his text and droned along monotonously through
+an argument that was so prosy that many a head by and by began to nod
+--and yet it was an argument that dealt in limitless fire and brimstone
+and thinned the predestined elect down to a company so small as to be
+hardly worth the saving. Tom counted the pages of the sermon; after
+church he always knew how many pages there had been, but he seldom knew
+anything else about the discourse. However, this time he was really
+interested for a little while. The minister made a grand and moving
+picture of the assembling together of the world's hosts at the
+millennium when the lion and the lamb should lie down together and a
+little child should lead them. But the pathos, the lesson, the moral of
+the great spectacle were lost upon the boy; he only thought of the
+conspicuousness of the principal character before the on-looking
+nations; his face lit with the thought, and he said to himself that he
+wished he could be that child, if it was a tame lion.
+
+Now he lapsed into suffering again, as the dry argument was resumed.
+Presently he bethought him of a treasure he had and got it out. It was
+a large black beetle with formidable jaws--a "pinchbug," he called it.
+It was in a percussion-cap box. The first thing the beetle did was to
+take him by the finger. A natural fillip followed, the beetle went
+floundering into the aisle and lit on its back, and the hurt finger
+went into the boy's mouth. The beetle lay there working its helpless
+legs, unable to turn over. Tom eyed it, and longed for it; but it was
+safe out of his reach. Other people uninterested in the sermon found
+relief in the beetle, and they eyed it too. Presently a vagrant poodle
+dog came idling along, sad at heart, lazy with the summer softness and
+the quiet, weary of captivity, sighing for change. He spied the beetle;
+the drooping tail lifted and wagged. He surveyed the prize; walked
+around it; smelt at it from a safe distance; walked around it again;
+grew bolder, and took a closer smell; then lifted his lip and made a
+gingerly snatch at it, just missing it; made another, and another;
+began to enjoy the diversion; subsided to his stomach with the beetle
+between his paws, and continued his experiments; grew weary at last,
+and then indifferent and absent-minded. His head nodded, and little by
+little his chin descended and touched the enemy, who seized it. There
+was a sharp yelp, a flirt of the poodle's head, and the beetle fell a
+couple of yards away, and lit on its back once more. The neighboring
+spectators shook with a gentle inward joy, several faces went behind
+fans and handkerchiefs, and Tom was entirely happy. The dog looked
+foolish, and probably felt so; but there was resentment in his heart,
+too, and a craving for revenge. So he went to the beetle and began a
+wary attack on it again; jumping at it from every point of a circle,
+lighting with his fore-paws within an inch of the creature, making even
+closer snatches at it with his teeth, and jerking his head till his
+ears flapped again. But he grew tired once more, after a while; tried
+to amuse himself with a fly but found no relief; followed an ant
+around, with his nose close to the floor, and quickly wearied of that;
+yawned, sighed, forgot the beetle entirely, and sat down on it. Then
+there was a wild yelp of agony and the poodle went sailing up the
+aisle; the yelps continued, and so did the dog; he crossed the house in
+front of the altar; he flew down the other aisle; he crossed before the
+doors; he clamored up the home-stretch; his anguish grew with his
+progress, till presently he was but a woolly comet moving in its orbit
+with the gleam and the speed of light. At last the frantic sufferer
+sheered from its course, and sprang into its master's lap; he flung it
+out of the window, and the voice of distress quickly thinned away and
+died in the distance.
+
+By this time the whole church was red-faced and suffocating with
+suppressed laughter, and the sermon had come to a dead standstill. The
+discourse was resumed presently, but it went lame and halting, all
+possibility of impressiveness being at an end; for even the gravest
+sentiments were constantly being received with a smothered burst of
+unholy mirth, under cover of some remote pew-back, as if the poor
+parson had said a rarely facetious thing. It was a genuine relief to
+the whole congregation when the ordeal was over and the benediction
+pronounced.
+
+Tom Sawyer went home quite cheerful, thinking to himself that there
+was some satisfaction about divine service when there was a bit of
+variety in it. He had but one marring thought; he was willing that the
+dog should play with his pinchbug, but he did not think it was upright
+in him to carry it off.
+
+
+
+CHAPTER VI
+
+MONDAY morning found Tom Sawyer miserable. Monday morning always found
+him so--because it began another week's slow suffering in school. He
+generally began that day with wishing he had had no intervening
+holiday, it made the going into captivity and fetters again so much
+more odious.
+
+Tom lay thinking. Presently it occurred to him that he wished he was
+sick; then he could stay home from school. Here was a vague
+possibility. He canvassed his system. No ailment was found, and he
+investigated again. This time he thought he could detect colicky
+symptoms, and he began to encourage them with considerable hope. But
+they soon grew feeble, and presently died wholly away. He reflected
+further. Suddenly he discovered something. One of his upper front teeth
+was loose. This was lucky; he was about to begin to groan, as a
+"starter," as he called it, when it occurred to him that if he came
+into court with that argument, his aunt would pull it out, and that
+would hurt. So he thought he would hold the tooth in reserve for the
+present, and seek further. Nothing offered for some little time, and
+then he remembered hearing the doctor tell about a certain thing that
+laid up a patient for two or three weeks and threatened to make him
+lose a finger. So the boy eagerly drew his sore toe from under the
+sheet and held it up for inspection. But now he did not know the
+necessary symptoms. However, it seemed well worth while to chance it,
+so he fell to groaning with considerable spirit.
+
+But Sid slept on unconscious.
+
+Tom groaned louder, and fancied that he began to feel pain in the toe.
+
+No result from Sid.
+
+Tom was panting with his exertions by this time. He took a rest and
+then swelled himself up and fetched a succession of admirable groans.
+
+Sid snored on.
+
+Tom was aggravated. He said, "Sid, Sid!" and shook him. This course
+worked well, and Tom began to groan again. Sid yawned, stretched, then
+brought himself up on his elbow with a snort, and began to stare at
+Tom. Tom went on groaning. Sid said:
+
+"Tom! Say, Tom!" [No response.] "Here, Tom! TOM! What is the matter,
+Tom?" And he shook him and looked in his face anxiously.
+
+Tom moaned out:
+
+"Oh, don't, Sid. Don't joggle me."
+
+"Why, what's the matter, Tom? I must call auntie."
+
+"No--never mind. It'll be over by and by, maybe. Don't call anybody."
+
+"But I must! DON'T groan so, Tom, it's awful. How long you been this
+way?"
+
+"Hours. Ouch! Oh, don't stir so, Sid, you'll kill me."
+
+"Tom, why didn't you wake me sooner? Oh, Tom, DON'T! It makes my
+flesh crawl to hear you. Tom, what is the matter?"
+
+"I forgive you everything, Sid. [Groan.] Everything you've ever done
+to me. When I'm gone--"
+
+"Oh, Tom, you ain't dying, are you? Don't, Tom--oh, don't. Maybe--"
+
+"I forgive everybody, Sid. [Groan.] Tell 'em so, Sid. And Sid, you
+give my window-sash and my cat with one eye to that new girl that's
+come to town, and tell her--"
+
+But Sid had snatched his clothes and gone. Tom was suffering in
+reality, now, so handsomely was his imagination working, and so his
+groans had gathered quite a genuine tone.
+
+Sid flew down-stairs and said:
+
+"Oh, Aunt Polly, come! Tom's dying!"
+
+"Dying!"
+
+"Yes'm. Don't wait--come quick!"
+
+"Rubbage! I don't believe it!"
+
+But she fled up-stairs, nevertheless, with Sid and Mary at her heels.
+And her face grew white, too, and her lip trembled. When she reached
+the bedside she gasped out:
+
+"You, Tom! Tom, what's the matter with you?"
+
+"Oh, auntie, I'm--"
+
+"What's the matter with you--what is the matter with you, child?"
+
+"Oh, auntie, my sore toe's mortified!"
+
+The old lady sank down into a chair and laughed a little, then cried a
+little, then did both together. This restored her and she said:
+
+"Tom, what a turn you did give me. Now you shut up that nonsense and
+climb out of this."
+
+The groans ceased and the pain vanished from the toe. The boy felt a
+little foolish, and he said:
+
+"Aunt Polly, it SEEMED mortified, and it hurt so I never minded my
+tooth at all."
+
+"Your tooth, indeed! What's the matter with your tooth?"
+
+"One of them's loose, and it aches perfectly awful."
+
+"There, there, now, don't begin that groaning again. Open your mouth.
+Well--your tooth IS loose, but you're not going to die about that.
+Mary, get me a silk thread, and a chunk of fire out of the kitchen."
+
+Tom said:
+
+"Oh, please, auntie, don't pull it out. It don't hurt any more. I wish
+I may never stir if it does. Please don't, auntie. I don't want to stay
+home from school."
+
+"Oh, you don't, don't you? So all this row was because you thought
+you'd get to stay home from school and go a-fishing? Tom, Tom, I love
+you so, and you seem to try every way you can to break my old heart
+with your outrageousness." By this time the dental instruments were
+ready. The old lady made one end of the silk thread fast to Tom's tooth
+with a loop and tied the other to the bedpost. Then she seized the
+chunk of fire and suddenly thrust it almost into the boy's face. The
+tooth hung dangling by the bedpost, now.
+
+But all trials bring their compensations. As Tom wended to school
+after breakfast, he was the envy of every boy he met because the gap in
+his upper row of teeth enabled him to expectorate in a new and
+admirable way. He gathered quite a following of lads interested in the
+exhibition; and one that had cut his finger and had been a centre of
+fascination and homage up to this time, now found himself suddenly
+without an adherent, and shorn of his glory. His heart was heavy, and
+he said with a disdain which he did not feel that it wasn't anything to
+spit like Tom Sawyer; but another boy said, "Sour grapes!" and he
+wandered away a dismantled hero.
+
+Shortly Tom came upon the juvenile pariah of the village, Huckleberry
+Finn, son of the town drunkard. Huckleberry was cordially hated and
+dreaded by all the mothers of the town, because he was idle and lawless
+and vulgar and bad--and because all their children admired him so, and
+delighted in his forbidden society, and wished they dared to be like
+him. Tom was like the rest of the respectable boys, in that he envied
+Huckleberry his gaudy outcast condition, and was under strict orders
+not to play with him. So he played with him every time he got a chance.
+Huckleberry was always dressed in the cast-off clothes of full-grown
+men, and they were in perennial bloom and fluttering with rags. His hat
+was a vast ruin with a wide crescent lopped out of its brim; his coat,
+when he wore one, hung nearly to his heels and had the rearward buttons
+far down the back; but one suspender supported his trousers; the seat
+of the trousers bagged low and contained nothing, the fringed legs
+dragged in the dirt when not rolled up.
+
+Huckleberry came and went, at his own free will. He slept on doorsteps
+in fine weather and in empty hogsheads in wet; he did not have to go to
+school or to church, or call any being master or obey anybody; he could
+go fishing or swimming when and where he chose, and stay as long as it
+suited him; nobody forbade him to fight; he could sit up as late as he
+pleased; he was always the first boy that went barefoot in the spring
+and the last to resume leather in the fall; he never had to wash, nor
+put on clean clothes; he could swear wonderfully. In a word, everything
+that goes to make life precious that boy had. So thought every
+harassed, hampered, respectable boy in St. Petersburg.
+
+Tom hailed the romantic outcast:
+
+"Hello, Huckleberry!"
+
+"Hello yourself, and see how you like it."
+
+"What's that you got?"
+
+"Dead cat."
+
+"Lemme see him, Huck. My, he's pretty stiff. Where'd you get him?"
+
+"Bought him off'n a boy."
+
+"What did you give?"
+
+"I give a blue ticket and a bladder that I got at the slaughter-house."
+
+"Where'd you get the blue ticket?"
+
+"Bought it off'n Ben Rogers two weeks ago for a hoop-stick."
+
+"Say--what is dead cats good for, Huck?"
+
+"Good for? Cure warts with."
+
+"No! Is that so? I know something that's better."
+
+"I bet you don't. What is it?"
+
+"Why, spunk-water."
+
+"Spunk-water! I wouldn't give a dern for spunk-water."
+
+"You wouldn't, wouldn't you? D'you ever try it?"
+
+"No, I hain't. But Bob Tanner did."
+
+"Who told you so!"
+
+"Why, he told Jeff Thatcher, and Jeff told Johnny Baker, and Johnny
+told Jim Hollis, and Jim told Ben Rogers, and Ben told a nigger, and
+the nigger told me. There now!"
+
+"Well, what of it? They'll all lie. Leastways all but the nigger. I
+don't know HIM. But I never see a nigger that WOULDN'T lie. Shucks! Now
+you tell me how Bob Tanner done it, Huck."
+
+"Why, he took and dipped his hand in a rotten stump where the
+rain-water was."
+
+"In the daytime?"
+
+"Certainly."
+
+"With his face to the stump?"
+
+"Yes. Least I reckon so."
+
+"Did he say anything?"
+
+"I don't reckon he did. I don't know."
+
+"Aha! Talk about trying to cure warts with spunk-water such a blame
+fool way as that! Why, that ain't a-going to do any good. You got to go
+all by yourself, to the middle of the woods, where you know there's a
+spunk-water stump, and just as it's midnight you back up against the
+stump and jam your hand in and say:
+
+ 'Barley-corn, barley-corn, injun-meal shorts,
+ Spunk-water, spunk-water, swaller these warts,'
+
+and then walk away quick, eleven steps, with your eyes shut, and then
+turn around three times and walk home without speaking to anybody.
+Because if you speak the charm's busted."
+
+"Well, that sounds like a good way; but that ain't the way Bob Tanner
+done."
+
+"No, sir, you can bet he didn't, becuz he's the wartiest boy in this
+town; and he wouldn't have a wart on him if he'd knowed how to work
+spunk-water. I've took off thousands of warts off of my hands that way,
+Huck. I play with frogs so much that I've always got considerable many
+warts. Sometimes I take 'em off with a bean."
+
+"Yes, bean's good. I've done that."
+
+"Have you? What's your way?"
+
+"You take and split the bean, and cut the wart so as to get some
+blood, and then you put the blood on one piece of the bean and take and
+dig a hole and bury it 'bout midnight at the crossroads in the dark of
+the moon, and then you burn up the rest of the bean. You see that piece
+that's got the blood on it will keep drawing and drawing, trying to
+fetch the other piece to it, and so that helps the blood to draw the
+wart, and pretty soon off she comes."
+
+"Yes, that's it, Huck--that's it; though when you're burying it if you
+say 'Down bean; off wart; come no more to bother me!' it's better.
+That's the way Joe Harper does, and he's been nearly to Coonville and
+most everywheres. But say--how do you cure 'em with dead cats?"
+
+"Why, you take your cat and go and get in the graveyard 'long about
+midnight when somebody that was wicked has been buried; and when it's
+midnight a devil will come, or maybe two or three, but you can't see
+'em, you can only hear something like the wind, or maybe hear 'em talk;
+and when they're taking that feller away, you heave your cat after 'em
+and say, 'Devil follow corpse, cat follow devil, warts follow cat, I'm
+done with ye!' That'll fetch ANY wart."
+
+"Sounds right. D'you ever try it, Huck?"
+
+"No, but old Mother Hopkins told me."
+
+"Well, I reckon it's so, then. Becuz they say she's a witch."
+
+"Say! Why, Tom, I KNOW she is. She witched pap. Pap says so his own
+self. He come along one day, and he see she was a-witching him, so he
+took up a rock, and if she hadn't dodged, he'd a got her. Well, that
+very night he rolled off'n a shed wher' he was a layin drunk, and broke
+his arm."
+
+"Why, that's awful. How did he know she was a-witching him?"
+
+"Lord, pap can tell, easy. Pap says when they keep looking at you
+right stiddy, they're a-witching you. Specially if they mumble. Becuz
+when they mumble they're saying the Lord's Prayer backards."
+
+"Say, Hucky, when you going to try the cat?"
+
+"To-night. I reckon they'll come after old Hoss Williams to-night."
+
+"But they buried him Saturday. Didn't they get him Saturday night?"
+
+"Why, how you talk! How could their charms work till midnight?--and
+THEN it's Sunday. Devils don't slosh around much of a Sunday, I don't
+reckon."
+
+"I never thought of that. That's so. Lemme go with you?"
+
+"Of course--if you ain't afeard."
+
+"Afeard! 'Tain't likely. Will you meow?"
+
+"Yes--and you meow back, if you get a chance. Last time, you kep' me
+a-meowing around till old Hays went to throwing rocks at me and says
+'Dern that cat!' and so I hove a brick through his window--but don't
+you tell."
+
+"I won't. I couldn't meow that night, becuz auntie was watching me,
+but I'll meow this time. Say--what's that?"
+
+"Nothing but a tick."
+
+"Where'd you get him?"
+
+"Out in the woods."
+
+"What'll you take for him?"
+
+"I don't know. I don't want to sell him."
+
+"All right. It's a mighty small tick, anyway."
+
+"Oh, anybody can run a tick down that don't belong to them. I'm
+satisfied with it. It's a good enough tick for me."
+
+"Sho, there's ticks a plenty. I could have a thousand of 'em if I
+wanted to."
+
+"Well, why don't you? Becuz you know mighty well you can't. This is a
+pretty early tick, I reckon. It's the first one I've seen this year."
+
+"Say, Huck--I'll give you my tooth for him."
+
+"Less see it."
+
+Tom got out a bit of paper and carefully unrolled it. Huckleberry
+viewed it wistfully. The temptation was very strong. At last he said:
+
+"Is it genuwyne?"
+
+Tom lifted his lip and showed the vacancy.
+
+"Well, all right," said Huckleberry, "it's a trade."
+
+Tom enclosed the tick in the percussion-cap box that had lately been
+the pinchbug's prison, and the boys separated, each feeling wealthier
+than before.
+
+When Tom reached the little isolated frame schoolhouse, he strode in
+briskly, with the manner of one who had come with all honest speed.
+He hung his hat on a peg and flung himself into his seat with
+business-like alacrity. The master, throned on high in his great
+splint-bottom arm-chair, was dozing, lulled by the drowsy hum of study.
+The interruption roused him.
+
+"Thomas Sawyer!"
+
+Tom knew that when his name was pronounced in full, it meant trouble.
+
+"Sir!"
+
+"Come up here. Now, sir, why are you late again, as usual?"
+
+Tom was about to take refuge in a lie, when he saw two long tails of
+yellow hair hanging down a back that he recognized by the electric
+sympathy of love; and by that form was THE ONLY VACANT PLACE on the
+girls' side of the schoolhouse. He instantly said:
+
+"I STOPPED TO TALK WITH HUCKLEBERRY FINN!"
+
+The master's pulse stood still, and he stared helplessly. The buzz of
+study ceased. The pupils wondered if this foolhardy boy had lost his
+mind. The master said:
+
+"You--you did what?"
+
+"Stopped to talk with Huckleberry Finn."
+
+There was no mistaking the words.
+
+"Thomas Sawyer, this is the most astounding confession I have ever
+listened to. No mere ferule will answer for this offence. Take off your
+jacket."
+
+The master's arm performed until it was tired and the stock of
+switches notably diminished. Then the order followed:
+
+"Now, sir, go and sit with the girls! And let this be a warning to you."
+
+The titter that rippled around the room appeared to abash the boy, but
+in reality that result was caused rather more by his worshipful awe of
+his unknown idol and the dread pleasure that lay in his high good
+fortune. He sat down upon the end of the pine bench and the girl
+hitched herself away from him with a toss of her head. Nudges and winks
+and whispers traversed the room, but Tom sat still, with his arms upon
+the long, low desk before him, and seemed to study his book.
+
+By and by attention ceased from him, and the accustomed school murmur
+rose upon the dull air once more. Presently the boy began to steal
+furtive glances at the girl. She observed it, "made a mouth" at him and
+gave him the back of her head for the space of a minute. When she
+cautiously faced around again, a peach lay before her. She thrust it
+away. Tom gently put it back. She thrust it away again, but with less
+animosity. Tom patiently returned it to its place. Then she let it
+remain. Tom scrawled on his slate, "Please take it--I got more." The
+girl glanced at the words, but made no sign. Now the boy began to draw
+something on the slate, hiding his work with his left hand. For a time
+the girl refused to notice; but her human curiosity presently began to
+manifest itself by hardly perceptible signs. The boy worked on,
+apparently unconscious. The girl made a sort of noncommittal attempt to
+see, but the boy did not betray that he was aware of it. At last she
+gave in and hesitatingly whispered:
+
+"Let me see it."
+
+Tom partly uncovered a dismal caricature of a house with two gable
+ends to it and a corkscrew of smoke issuing from the chimney. Then the
+girl's interest began to fasten itself upon the work and she forgot
+everything else. When it was finished, she gazed a moment, then
+whispered:
+
+"It's nice--make a man."
+
+The artist erected a man in the front yard, that resembled a derrick.
+He could have stepped over the house; but the girl was not
+hypercritical; she was satisfied with the monster, and whispered:
+
+"It's a beautiful man--now make me coming along."
+
+Tom drew an hour-glass with a full moon and straw limbs to it and
+armed the spreading fingers with a portentous fan. The girl said:
+
+"It's ever so nice--I wish I could draw."
+
+"It's easy," whispered Tom, "I'll learn you."
+
+"Oh, will you? When?"
+
+"At noon. Do you go home to dinner?"
+
+"I'll stay if you will."
+
+"Good--that's a whack. What's your name?"
+
+"Becky Thatcher. What's yours? Oh, I know. It's Thomas Sawyer."
+
+"That's the name they lick me by. I'm Tom when I'm good. You call me
+Tom, will you?"
+
+"Yes."
+
+Now Tom began to scrawl something on the slate, hiding the words from
+the girl. But she was not backward this time. She begged to see. Tom
+said:
+
+"Oh, it ain't anything."
+
+"Yes it is."
+
+"No it ain't. You don't want to see."
+
+"Yes I do, indeed I do. Please let me."
+
+"You'll tell."
+
+"No I won't--deed and deed and double deed won't."
+
+"You won't tell anybody at all? Ever, as long as you live?"
+
+"No, I won't ever tell ANYbody. Now let me."
+
+"Oh, YOU don't want to see!"
+
+"Now that you treat me so, I WILL see." And she put her small hand
+upon his and a little scuffle ensued, Tom pretending to resist in
+earnest but letting his hand slip by degrees till these words were
+revealed: "I LOVE YOU."
+
+"Oh, you bad thing!" And she hit his hand a smart rap, but reddened
+and looked pleased, nevertheless.
+
+Just at this juncture the boy felt a slow, fateful grip closing on his
+ear, and a steady lifting impulse. In that wise he was borne across the
+house and deposited in his own seat, under a peppering fire of giggles
+from the whole school. Then the master stood over him during a few
+awful moments, and finally moved away to his throne without saying a
+word. But although Tom's ear tingled, his heart was jubilant.
+
+As the school quieted down Tom made an honest effort to study, but the
+turmoil within him was too great. In turn he took his place in the
+reading class and made a botch of it; then in the geography class and
+turned lakes into mountains, mountains into rivers, and rivers into
+continents, till chaos was come again; then in the spelling class, and
+got "turned down," by a succession of mere baby words, till he brought
+up at the foot and yielded up the pewter medal which he had worn with
+ostentation for months.
+
+
+
+CHAPTER VII
+
+THE harder Tom tried to fasten his mind on his book, the more his
+ideas wandered. So at last, with a sigh and a yawn, he gave it up. It
+seemed to him that the noon recess would never come. The air was
+utterly dead. There was not a breath stirring. It was the sleepiest of
+sleepy days. The drowsing murmur of the five and twenty studying
+scholars soothed the soul like the spell that is in the murmur of bees.
+Away off in the flaming sunshine, Cardiff Hill lifted its soft green
+sides through a shimmering veil of heat, tinted with the purple of
+distance; a few birds floated on lazy wing high in the air; no other
+living thing was visible but some cows, and they were asleep. Tom's
+heart ached to be free, or else to have something of interest to do to
+pass the dreary time. His hand wandered into his pocket and his face
+lit up with a glow of gratitude that was prayer, though he did not know
+it. Then furtively the percussion-cap box came out. He released the
+tick and put him on the long flat desk. The creature probably glowed
+with a gratitude that amounted to prayer, too, at this moment, but it
+was premature: for when he started thankfully to travel off, Tom turned
+him aside with a pin and made him take a new direction.
+
+Tom's bosom friend sat next him, suffering just as Tom had been, and
+now he was deeply and gratefully interested in this entertainment in an
+instant. This bosom friend was Joe Harper. The two boys were sworn
+friends all the week, and embattled enemies on Saturdays. Joe took a
+pin out of his lapel and began to assist in exercising the prisoner.
+The sport grew in interest momently. Soon Tom said that they were
+interfering with each other, and neither getting the fullest benefit of
+the tick. So he put Joe's slate on the desk and drew a line down the
+middle of it from top to bottom.
+
+"Now," said he, "as long as he is on your side you can stir him up and
+I'll let him alone; but if you let him get away and get on my side,
+you're to leave him alone as long as I can keep him from crossing over."
+
+"All right, go ahead; start him up."
+
+The tick escaped from Tom, presently, and crossed the equator. Joe
+harassed him awhile, and then he got away and crossed back again. This
+change of base occurred often. While one boy was worrying the tick with
+absorbing interest, the other would look on with interest as strong,
+the two heads bowed together over the slate, and the two souls dead to
+all things else. At last luck seemed to settle and abide with Joe. The
+tick tried this, that, and the other course, and got as excited and as
+anxious as the boys themselves, but time and again just as he would
+have victory in his very grasp, so to speak, and Tom's fingers would be
+twitching to begin, Joe's pin would deftly head him off, and keep
+possession. At last Tom could stand it no longer. The temptation was
+too strong. So he reached out and lent a hand with his pin. Joe was
+angry in a moment. Said he:
+
+"Tom, you let him alone."
+
+"I only just want to stir him up a little, Joe."
+
+"No, sir, it ain't fair; you just let him alone."
+
+"Blame it, I ain't going to stir him much."
+
+"Let him alone, I tell you."
+
+"I won't!"
+
+"You shall--he's on my side of the line."
+
+"Look here, Joe Harper, whose is that tick?"
+
+"I don't care whose tick he is--he's on my side of the line, and you
+sha'n't touch him."
+
+"Well, I'll just bet I will, though. He's my tick and I'll do what I
+blame please with him, or die!"
+
+A tremendous whack came down on Tom's shoulders, and its duplicate on
+Joe's; and for the space of two minutes the dust continued to fly from
+the two jackets and the whole school to enjoy it. The boys had been too
+absorbed to notice the hush that had stolen upon the school awhile
+before when the master came tiptoeing down the room and stood over
+them. He had contemplated a good part of the performance before he
+contributed his bit of variety to it.
+
+When school broke up at noon, Tom flew to Becky Thatcher, and
+whispered in her ear:
+
+"Put on your bonnet and let on you're going home; and when you get to
+the corner, give the rest of 'em the slip, and turn down through the
+lane and come back. I'll go the other way and come it over 'em the same
+way."
+
+So the one went off with one group of scholars, and the other with
+another. In a little while the two met at the bottom of the lane, and
+when they reached the school they had it all to themselves. Then they
+sat together, with a slate before them, and Tom gave Becky the pencil
+and held her hand in his, guiding it, and so created another surprising
+house. When the interest in art began to wane, the two fell to talking.
+Tom was swimming in bliss. He said:
+
+"Do you love rats?"
+
+"No! I hate them!"
+
+"Well, I do, too--LIVE ones. But I mean dead ones, to swing round your
+head with a string."
+
+"No, I don't care for rats much, anyway. What I like is chewing-gum."
+
+"Oh, I should say so! I wish I had some now."
+
+"Do you? I've got some. I'll let you chew it awhile, but you must give
+it back to me."
+
+That was agreeable, so they chewed it turn about, and dangled their
+legs against the bench in excess of contentment.
+
+"Was you ever at a circus?" said Tom.
+
+"Yes, and my pa's going to take me again some time, if I'm good."
+
+"I been to the circus three or four times--lots of times. Church ain't
+shucks to a circus. There's things going on at a circus all the time.
+I'm going to be a clown in a circus when I grow up."
+
+"Oh, are you! That will be nice. They're so lovely, all spotted up."
+
+"Yes, that's so. And they get slathers of money--most a dollar a day,
+Ben Rogers says. Say, Becky, was you ever engaged?"
+
+"What's that?"
+
+"Why, engaged to be married."
+
+"No."
+
+"Would you like to?"
+
+"I reckon so. I don't know. What is it like?"
+
+"Like? Why it ain't like anything. You only just tell a boy you won't
+ever have anybody but him, ever ever ever, and then you kiss and that's
+all. Anybody can do it."
+
+"Kiss? What do you kiss for?"
+
+"Why, that, you know, is to--well, they always do that."
+
+"Everybody?"
+
+"Why, yes, everybody that's in love with each other. Do you remember
+what I wrote on the slate?"
+
+"Ye--yes."
+
+"What was it?"
+
+"I sha'n't tell you."
+
+"Shall I tell YOU?"
+
+"Ye--yes--but some other time."
+
+"No, now."
+
+"No, not now--to-morrow."
+
+"Oh, no, NOW. Please, Becky--I'll whisper it, I'll whisper it ever so
+easy."
+
+Becky hesitating, Tom took silence for consent, and passed his arm
+about her waist and whispered the tale ever so softly, with his mouth
+close to her ear. And then he added:
+
+"Now you whisper it to me--just the same."
+
+She resisted, for a while, and then said:
+
+"You turn your face away so you can't see, and then I will. But you
+mustn't ever tell anybody--WILL you, Tom? Now you won't, WILL you?"
+
+"No, indeed, indeed I won't. Now, Becky."
+
+He turned his face away. She bent timidly around till her breath
+stirred his curls and whispered, "I--love--you!"
+
+Then she sprang away and ran around and around the desks and benches,
+with Tom after her, and took refuge in a corner at last, with her
+little white apron to her face. Tom clasped her about her neck and
+pleaded:
+
+"Now, Becky, it's all done--all over but the kiss. Don't you be afraid
+of that--it ain't anything at all. Please, Becky." And he tugged at her
+apron and the hands.
+
+By and by she gave up, and let her hands drop; her face, all glowing
+with the struggle, came up and submitted. Tom kissed the red lips and
+said:
+
+"Now it's all done, Becky. And always after this, you know, you ain't
+ever to love anybody but me, and you ain't ever to marry anybody but
+me, ever never and forever. Will you?"
+
+"No, I'll never love anybody but you, Tom, and I'll never marry
+anybody but you--and you ain't to ever marry anybody but me, either."
+
+"Certainly. Of course. That's PART of it. And always coming to school
+or when we're going home, you're to walk with me, when there ain't
+anybody looking--and you choose me and I choose you at parties, because
+that's the way you do when you're engaged."
+
+"It's so nice. I never heard of it before."
+
+"Oh, it's ever so gay! Why, me and Amy Lawrence--"
+
+The big eyes told Tom his blunder and he stopped, confused.
+
+"Oh, Tom! Then I ain't the first you've ever been engaged to!"
+
+The child began to cry. Tom said:
+
+"Oh, don't cry, Becky, I don't care for her any more."
+
+"Yes, you do, Tom--you know you do."
+
+Tom tried to put his arm about her neck, but she pushed him away and
+turned her face to the wall, and went on crying. Tom tried again, with
+soothing words in his mouth, and was repulsed again. Then his pride was
+up, and he strode away and went outside. He stood about, restless and
+uneasy, for a while, glancing at the door, every now and then, hoping
+she would repent and come to find him. But she did not. Then he began
+to feel badly and fear that he was in the wrong. It was a hard struggle
+with him to make new advances, now, but he nerved himself to it and
+entered. She was still standing back there in the corner, sobbing, with
+her face to the wall. Tom's heart smote him. He went to her and stood a
+moment, not knowing exactly how to proceed. Then he said hesitatingly:
+
+"Becky, I--I don't care for anybody but you."
+
+No reply--but sobs.
+
+"Becky"--pleadingly. "Becky, won't you say something?"
+
+More sobs.
+
+Tom got out his chiefest jewel, a brass knob from the top of an
+andiron, and passed it around her so that she could see it, and said:
+
+"Please, Becky, won't you take it?"
+
+She struck it to the floor. Then Tom marched out of the house and over
+the hills and far away, to return to school no more that day. Presently
+Becky began to suspect. She ran to the door; he was not in sight; she
+flew around to the play-yard; he was not there. Then she called:
+
+"Tom! Come back, Tom!"
+
+She listened intently, but there was no answer. She had no companions
+but silence and loneliness. So she sat down to cry again and upbraid
+herself; and by this time the scholars began to gather again, and she
+had to hide her griefs and still her broken heart and take up the cross
+of a long, dreary, aching afternoon, with none among the strangers
+about her to exchange sorrows with.
+
+
+
+CHAPTER VIII
+
+TOM dodged hither and thither through lanes until he was well out of
+the track of returning scholars, and then fell into a moody jog. He
+crossed a small "branch" two or three times, because of a prevailing
+juvenile superstition that to cross water baffled pursuit. Half an hour
+later he was disappearing behind the Douglas mansion on the summit of
+Cardiff Hill, and the schoolhouse was hardly distinguishable away off
+in the valley behind him. He entered a dense wood, picked his pathless
+way to the centre of it, and sat down on a mossy spot under a spreading
+oak. There was not even a zephyr stirring; the dead noonday heat had
+even stilled the songs of the birds; nature lay in a trance that was
+broken by no sound but the occasional far-off hammering of a
+woodpecker, and this seemed to render the pervading silence and sense
+of loneliness the more profound. The boy's soul was steeped in
+melancholy; his feelings were in happy accord with his surroundings. He
+sat long with his elbows on his knees and his chin in his hands,
+meditating. It seemed to him that life was but a trouble, at best, and
+he more than half envied Jimmy Hodges, so lately released; it must be
+very peaceful, he thought, to lie and slumber and dream forever and
+ever, with the wind whispering through the trees and caressing the
+grass and the flowers over the grave, and nothing to bother and grieve
+about, ever any more. If he only had a clean Sunday-school record he
+could be willing to go, and be done with it all. Now as to this girl.
+What had he done? Nothing. He had meant the best in the world, and been
+treated like a dog--like a very dog. She would be sorry some day--maybe
+when it was too late. Ah, if he could only die TEMPORARILY!
+
+But the elastic heart of youth cannot be compressed into one
+constrained shape long at a time. Tom presently began to drift
+insensibly back into the concerns of this life again. What if he turned
+his back, now, and disappeared mysteriously? What if he went away--ever
+so far away, into unknown countries beyond the seas--and never came
+back any more! How would she feel then! The idea of being a clown
+recurred to him now, only to fill him with disgust. For frivolity and
+jokes and spotted tights were an offense, when they intruded themselves
+upon a spirit that was exalted into the vague august realm of the
+romantic. No, he would be a soldier, and return after long years, all
+war-worn and illustrious. No--better still, he would join the Indians,
+and hunt buffaloes and go on the warpath in the mountain ranges and the
+trackless great plains of the Far West, and away in the future come
+back a great chief, bristling with feathers, hideous with paint, and
+prance into Sunday-school, some drowsy summer morning, with a
+bloodcurdling war-whoop, and sear the eyeballs of all his companions
+with unappeasable envy. But no, there was something gaudier even than
+this. He would be a pirate! That was it! NOW his future lay plain
+before him, and glowing with unimaginable splendor. How his name would
+fill the world, and make people shudder! How gloriously he would go
+plowing the dancing seas, in his long, low, black-hulled racer, the
+Spirit of the Storm, with his grisly flag flying at the fore! And at
+the zenith of his fame, how he would suddenly appear at the old village
+and stalk into church, brown and weather-beaten, in his black velvet
+doublet and trunks, his great jack-boots, his crimson sash, his belt
+bristling with horse-pistols, his crime-rusted cutlass at his side, his
+slouch hat with waving plumes, his black flag unfurled, with the skull
+and crossbones on it, and hear with swelling ecstasy the whisperings,
+"It's Tom Sawyer the Pirate!--the Black Avenger of the Spanish Main!"
+
+Yes, it was settled; his career was determined. He would run away from
+home and enter upon it. He would start the very next morning. Therefore
+he must now begin to get ready. He would collect his resources
+together. He went to a rotten log near at hand and began to dig under
+one end of it with his Barlow knife. He soon struck wood that sounded
+hollow. He put his hand there and uttered this incantation impressively:
+
+"What hasn't come here, come! What's here, stay here!"
+
+Then he scraped away the dirt, and exposed a pine shingle. He took it
+up and disclosed a shapely little treasure-house whose bottom and sides
+were of shingles. In it lay a marble. Tom's astonishment was boundless!
+He scratched his head with a perplexed air, and said:
+
+"Well, that beats anything!"
+
+Then he tossed the marble away pettishly, and stood cogitating. The
+truth was, that a superstition of his had failed, here, which he and
+all his comrades had always looked upon as infallible. If you buried a
+marble with certain necessary incantations, and left it alone a
+fortnight, and then opened the place with the incantation he had just
+used, you would find that all the marbles you had ever lost had
+gathered themselves together there, meantime, no matter how widely they
+had been separated. But now, this thing had actually and unquestionably
+failed. Tom's whole structure of faith was shaken to its foundations.
+He had many a time heard of this thing succeeding but never of its
+failing before. It did not occur to him that he had tried it several
+times before, himself, but could never find the hiding-places
+afterward. He puzzled over the matter some time, and finally decided
+that some witch had interfered and broken the charm. He thought he
+would satisfy himself on that point; so he searched around till he
+found a small sandy spot with a little funnel-shaped depression in it.
+He laid himself down and put his mouth close to this depression and
+called--
+
+"Doodle-bug, doodle-bug, tell me what I want to know! Doodle-bug,
+doodle-bug, tell me what I want to know!"
+
+The sand began to work, and presently a small black bug appeared for a
+second and then darted under again in a fright.
+
+"He dasn't tell! So it WAS a witch that done it. I just knowed it."
+
+He well knew the futility of trying to contend against witches, so he
+gave up discouraged. But it occurred to him that he might as well have
+the marble he had just thrown away, and therefore he went and made a
+patient search for it. But he could not find it. Now he went back to
+his treasure-house and carefully placed himself just as he had been
+standing when he tossed the marble away; then he took another marble
+from his pocket and tossed it in the same way, saying:
+
+"Brother, go find your brother!"
+
+He watched where it stopped, and went there and looked. But it must
+have fallen short or gone too far; so he tried twice more. The last
+repetition was successful. The two marbles lay within a foot of each
+other.
+
+Just here the blast of a toy tin trumpet came faintly down the green
+aisles of the forest. Tom flung off his jacket and trousers, turned a
+suspender into a belt, raked away some brush behind the rotten log,
+disclosing a rude bow and arrow, a lath sword and a tin trumpet, and in
+a moment had seized these things and bounded away, barelegged, with
+fluttering shirt. He presently halted under a great elm, blew an
+answering blast, and then began to tiptoe and look warily out, this way
+and that. He said cautiously--to an imaginary company:
+
+"Hold, my merry men! Keep hid till I blow."
+
+Now appeared Joe Harper, as airily clad and elaborately armed as Tom.
+Tom called:
+
+"Hold! Who comes here into Sherwood Forest without my pass?"
+
+"Guy of Guisborne wants no man's pass. Who art thou that--that--"
+
+"Dares to hold such language," said Tom, prompting--for they talked
+"by the book," from memory.
+
+"Who art thou that dares to hold such language?"
+
+"I, indeed! I am Robin Hood, as thy caitiff carcase soon shall know."
+
+"Then art thou indeed that famous outlaw? Right gladly will I dispute
+with thee the passes of the merry wood. Have at thee!"
+
+They took their lath swords, dumped their other traps on the ground,
+struck a fencing attitude, foot to foot, and began a grave, careful
+combat, "two up and two down." Presently Tom said:
+
+"Now, if you've got the hang, go it lively!"
+
+So they "went it lively," panting and perspiring with the work. By and
+by Tom shouted:
+
+"Fall! fall! Why don't you fall?"
+
+"I sha'n't! Why don't you fall yourself? You're getting the worst of
+it."
+
+"Why, that ain't anything. I can't fall; that ain't the way it is in
+the book. The book says, 'Then with one back-handed stroke he slew poor
+Guy of Guisborne.' You're to turn around and let me hit you in the
+back."
+
+There was no getting around the authorities, so Joe turned, received
+the whack and fell.
+
+"Now," said Joe, getting up, "you got to let me kill YOU. That's fair."
+
+"Why, I can't do that, it ain't in the book."
+
+"Well, it's blamed mean--that's all."
+
+"Well, say, Joe, you can be Friar Tuck or Much the miller's son, and
+lam me with a quarter-staff; or I'll be the Sheriff of Nottingham and
+you be Robin Hood a little while and kill me."
+
+This was satisfactory, and so these adventures were carried out. Then
+Tom became Robin Hood again, and was allowed by the treacherous nun to
+bleed his strength away through his neglected wound. And at last Joe,
+representing a whole tribe of weeping outlaws, dragged him sadly forth,
+gave his bow into his feeble hands, and Tom said, "Where this arrow
+falls, there bury poor Robin Hood under the greenwood tree." Then he
+shot the arrow and fell back and would have died, but he lit on a
+nettle and sprang up too gaily for a corpse.
+
+The boys dressed themselves, hid their accoutrements, and went off
+grieving that there were no outlaws any more, and wondering what modern
+civilization could claim to have done to compensate for their loss.
+They said they would rather be outlaws a year in Sherwood Forest than
+President of the United States forever.
+
+
+
+CHAPTER IX
+
+AT half-past nine, that night, Tom and Sid were sent to bed, as usual.
+They said their prayers, and Sid was soon asleep. Tom lay awake and
+waited, in restless impatience. When it seemed to him that it must be
+nearly daylight, he heard the clock strike ten! This was despair. He
+would have tossed and fidgeted, as his nerves demanded, but he was
+afraid he might wake Sid. So he lay still, and stared up into the dark.
+Everything was dismally still. By and by, out of the stillness, little,
+scarcely perceptible noises began to emphasize themselves. The ticking
+of the clock began to bring itself into notice. Old beams began to
+crack mysteriously. The stairs creaked faintly. Evidently spirits were
+abroad. A measured, muffled snore issued from Aunt Polly's chamber. And
+now the tiresome chirping of a cricket that no human ingenuity could
+locate, began. Next the ghastly ticking of a deathwatch in the wall at
+the bed's head made Tom shudder--it meant that somebody's days were
+numbered. Then the howl of a far-off dog rose on the night air, and was
+answered by a fainter howl from a remoter distance. Tom was in an
+agony. At last he was satisfied that time had ceased and eternity
+begun; he began to doze, in spite of himself; the clock chimed eleven,
+but he did not hear it. And then there came, mingling with his
+half-formed dreams, a most melancholy caterwauling. The raising of a
+neighboring window disturbed him. A cry of "Scat! you devil!" and the
+crash of an empty bottle against the back of his aunt's woodshed
+brought him wide awake, and a single minute later he was dressed and
+out of the window and creeping along the roof of the "ell" on all
+fours. He "meow'd" with caution once or twice, as he went; then jumped
+to the roof of the woodshed and thence to the ground. Huckleberry Finn
+was there, with his dead cat. The boys moved off and disappeared in the
+gloom. At the end of half an hour they were wading through the tall
+grass of the graveyard.
+
+It was a graveyard of the old-fashioned Western kind. It was on a
+hill, about a mile and a half from the village. It had a crazy board
+fence around it, which leaned inward in places, and outward the rest of
+the time, but stood upright nowhere. Grass and weeds grew rank over the
+whole cemetery. All the old graves were sunken in, there was not a
+tombstone on the place; round-topped, worm-eaten boards staggered over
+the graves, leaning for support and finding none. "Sacred to the memory
+of" So-and-So had been painted on them once, but it could no longer
+have been read, on the most of them, now, even if there had been light.
+
+A faint wind moaned through the trees, and Tom feared it might be the
+spirits of the dead, complaining at being disturbed. The boys talked
+little, and only under their breath, for the time and the place and the
+pervading solemnity and silence oppressed their spirits. They found the
+sharp new heap they were seeking, and ensconced themselves within the
+protection of three great elms that grew in a bunch within a few feet
+of the grave.
+
+Then they waited in silence for what seemed a long time. The hooting
+of a distant owl was all the sound that troubled the dead stillness.
+Tom's reflections grew oppressive. He must force some talk. So he said
+in a whisper:
+
+"Hucky, do you believe the dead people like it for us to be here?"
+
+Huckleberry whispered:
+
+"I wisht I knowed. It's awful solemn like, AIN'T it?"
+
+"I bet it is."
+
+There was a considerable pause, while the boys canvassed this matter
+inwardly. Then Tom whispered:
+
+"Say, Hucky--do you reckon Hoss Williams hears us talking?"
+
+"O' course he does. Least his sperrit does."
+
+Tom, after a pause:
+
+"I wish I'd said Mister Williams. But I never meant any harm.
+Everybody calls him Hoss."
+
+"A body can't be too partic'lar how they talk 'bout these-yer dead
+people, Tom."
+
+This was a damper, and conversation died again.
+
+Presently Tom seized his comrade's arm and said:
+
+"Sh!"
+
+"What is it, Tom?" And the two clung together with beating hearts.
+
+"Sh! There 'tis again! Didn't you hear it?"
+
+"I--"
+
+"There! Now you hear it."
+
+"Lord, Tom, they're coming! They're coming, sure. What'll we do?"
+
+"I dono. Think they'll see us?"
+
+"Oh, Tom, they can see in the dark, same as cats. I wisht I hadn't
+come."
+
+"Oh, don't be afeard. I don't believe they'll bother us. We ain't
+doing any harm. If we keep perfectly still, maybe they won't notice us
+at all."
+
+"I'll try to, Tom, but, Lord, I'm all of a shiver."
+
+"Listen!"
+
+The boys bent their heads together and scarcely breathed. A muffled
+sound of voices floated up from the far end of the graveyard.
+
+"Look! See there!" whispered Tom. "What is it?"
+
+"It's devil-fire. Oh, Tom, this is awful."
+
+Some vague figures approached through the gloom, swinging an
+old-fashioned tin lantern that freckled the ground with innumerable
+little spangles of light. Presently Huckleberry whispered with a
+shudder:
+
+"It's the devils sure enough. Three of 'em! Lordy, Tom, we're goners!
+Can you pray?"
+
+"I'll try, but don't you be afeard. They ain't going to hurt us. 'Now
+I lay me down to sleep, I--'"
+
+"Sh!"
+
+"What is it, Huck?"
+
+"They're HUMANS! One of 'em is, anyway. One of 'em's old Muff Potter's
+voice."
+
+"No--'tain't so, is it?"
+
+"I bet I know it. Don't you stir nor budge. He ain't sharp enough to
+notice us. Drunk, the same as usual, likely--blamed old rip!"
+
+"All right, I'll keep still. Now they're stuck. Can't find it. Here
+they come again. Now they're hot. Cold again. Hot again. Red hot!
+They're p'inted right, this time. Say, Huck, I know another o' them
+voices; it's Injun Joe."
+
+"That's so--that murderin' half-breed! I'd druther they was devils a
+dern sight. What kin they be up to?"
+
+The whisper died wholly out, now, for the three men had reached the
+grave and stood within a few feet of the boys' hiding-place.
+
+"Here it is," said the third voice; and the owner of it held the
+lantern up and revealed the face of young Doctor Robinson.
+
+Potter and Injun Joe were carrying a handbarrow with a rope and a
+couple of shovels on it. They cast down their load and began to open
+the grave. The doctor put the lantern at the head of the grave and came
+and sat down with his back against one of the elm trees. He was so
+close the boys could have touched him.
+
+"Hurry, men!" he said, in a low voice; "the moon might come out at any
+moment."
+
+They growled a response and went on digging. For some time there was
+no noise but the grating sound of the spades discharging their freight
+of mould and gravel. It was very monotonous. Finally a spade struck
+upon the coffin with a dull woody accent, and within another minute or
+two the men had hoisted it out on the ground. They pried off the lid
+with their shovels, got out the body and dumped it rudely on the
+ground. The moon drifted from behind the clouds and exposed the pallid
+face. The barrow was got ready and the corpse placed on it, covered
+with a blanket, and bound to its place with the rope. Potter took out a
+large spring-knife and cut off the dangling end of the rope and then
+said:
+
+"Now the cussed thing's ready, Sawbones, and you'll just out with
+another five, or here she stays."
+
+"That's the talk!" said Injun Joe.
+
+"Look here, what does this mean?" said the doctor. "You required your
+pay in advance, and I've paid you."
+
+"Yes, and you done more than that," said Injun Joe, approaching the
+doctor, who was now standing. "Five years ago you drove me away from
+your father's kitchen one night, when I come to ask for something to
+eat, and you said I warn't there for any good; and when I swore I'd get
+even with you if it took a hundred years, your father had me jailed for
+a vagrant. Did you think I'd forget? The Injun blood ain't in me for
+nothing. And now I've GOT you, and you got to SETTLE, you know!"
+
+He was threatening the doctor, with his fist in his face, by this
+time. The doctor struck out suddenly and stretched the ruffian on the
+ground. Potter dropped his knife, and exclaimed:
+
+"Here, now, don't you hit my pard!" and the next moment he had
+grappled with the doctor and the two were struggling with might and
+main, trampling the grass and tearing the ground with their heels.
+Injun Joe sprang to his feet, his eyes flaming with passion, snatched
+up Potter's knife, and went creeping, catlike and stooping, round and
+round about the combatants, seeking an opportunity. All at once the
+doctor flung himself free, seized the heavy headboard of Williams'
+grave and felled Potter to the earth with it--and in the same instant
+the half-breed saw his chance and drove the knife to the hilt in the
+young man's breast. He reeled and fell partly upon Potter, flooding him
+with his blood, and in the same moment the clouds blotted out the
+dreadful spectacle and the two frightened boys went speeding away in
+the dark.
+
+Presently, when the moon emerged again, Injun Joe was standing over
+the two forms, contemplating them. The doctor murmured inarticulately,
+gave a long gasp or two and was still. The half-breed muttered:
+
+"THAT score is settled--damn you."
+
+Then he robbed the body. After which he put the fatal knife in
+Potter's open right hand, and sat down on the dismantled coffin. Three
+--four--five minutes passed, and then Potter began to stir and moan. His
+hand closed upon the knife; he raised it, glanced at it, and let it
+fall, with a shudder. Then he sat up, pushing the body from him, and
+gazed at it, and then around him, confusedly. His eyes met Joe's.
+
+"Lord, how is this, Joe?" he said.
+
+"It's a dirty business," said Joe, without moving.
+
+"What did you do it for?"
+
+"I! I never done it!"
+
+"Look here! That kind of talk won't wash."
+
+Potter trembled and grew white.
+
+"I thought I'd got sober. I'd no business to drink to-night. But it's
+in my head yet--worse'n when we started here. I'm all in a muddle;
+can't recollect anything of it, hardly. Tell me, Joe--HONEST, now, old
+feller--did I do it? Joe, I never meant to--'pon my soul and honor, I
+never meant to, Joe. Tell me how it was, Joe. Oh, it's awful--and him
+so young and promising."
+
+"Why, you two was scuffling, and he fetched you one with the headboard
+and you fell flat; and then up you come, all reeling and staggering
+like, and snatched the knife and jammed it into him, just as he fetched
+you another awful clip--and here you've laid, as dead as a wedge til
+now."
+
+"Oh, I didn't know what I was a-doing. I wish I may die this minute if
+I did. It was all on account of the whiskey and the excitement, I
+reckon. I never used a weepon in my life before, Joe. I've fought, but
+never with weepons. They'll all say that. Joe, don't tell! Say you
+won't tell, Joe--that's a good feller. I always liked you, Joe, and
+stood up for you, too. Don't you remember? You WON'T tell, WILL you,
+Joe?" And the poor creature dropped on his knees before the stolid
+murderer, and clasped his appealing hands.
+
+"No, you've always been fair and square with me, Muff Potter, and I
+won't go back on you. There, now, that's as fair as a man can say."
+
+"Oh, Joe, you're an angel. I'll bless you for this the longest day I
+live." And Potter began to cry.
+
+"Come, now, that's enough of that. This ain't any time for blubbering.
+You be off yonder way and I'll go this. Move, now, and don't leave any
+tracks behind you."
+
+Potter started on a trot that quickly increased to a run. The
+half-breed stood looking after him. He muttered:
+
+"If he's as much stunned with the lick and fuddled with the rum as he
+had the look of being, he won't think of the knife till he's gone so
+far he'll be afraid to come back after it to such a place by himself
+--chicken-heart!"
+
+Two or three minutes later the murdered man, the blanketed corpse, the
+lidless coffin, and the open grave were under no inspection but the
+moon's. The stillness was complete again, too.
+
+
+
+CHAPTER X
+
+THE two boys flew on and on, toward the village, speechless with
+horror. They glanced backward over their shoulders from time to time,
+apprehensively, as if they feared they might be followed. Every stump
+that started up in their path seemed a man and an enemy, and made them
+catch their breath; and as they sped by some outlying cottages that lay
+near the village, the barking of the aroused watch-dogs seemed to give
+wings to their feet.
+
+"If we can only get to the old tannery before we break down!"
+whispered Tom, in short catches between breaths. "I can't stand it much
+longer."
+
+Huckleberry's hard pantings were his only reply, and the boys fixed
+their eyes on the goal of their hopes and bent to their work to win it.
+They gained steadily on it, and at last, breast to breast, they burst
+through the open door and fell grateful and exhausted in the sheltering
+shadows beyond. By and by their pulses slowed down, and Tom whispered:
+
+"Huckleberry, what do you reckon'll come of this?"
+
+"If Doctor Robinson dies, I reckon hanging'll come of it."
+
+"Do you though?"
+
+"Why, I KNOW it, Tom."
+
+Tom thought a while, then he said:
+
+"Who'll tell? We?"
+
+"What are you talking about? S'pose something happened and Injun Joe
+DIDN'T hang? Why, he'd kill us some time or other, just as dead sure as
+we're a laying here."
+
+"That's just what I was thinking to myself, Huck."
+
+"If anybody tells, let Muff Potter do it, if he's fool enough. He's
+generally drunk enough."
+
+Tom said nothing--went on thinking. Presently he whispered:
+
+"Huck, Muff Potter don't know it. How can he tell?"
+
+"What's the reason he don't know it?"
+
+"Because he'd just got that whack when Injun Joe done it. D'you reckon
+he could see anything? D'you reckon he knowed anything?"
+
+"By hokey, that's so, Tom!"
+
+"And besides, look-a-here--maybe that whack done for HIM!"
+
+"No, 'taint likely, Tom. He had liquor in him; I could see that; and
+besides, he always has. Well, when pap's full, you might take and belt
+him over the head with a church and you couldn't phase him. He says so,
+his own self. So it's the same with Muff Potter, of course. But if a
+man was dead sober, I reckon maybe that whack might fetch him; I dono."
+
+After another reflective silence, Tom said:
+
+"Hucky, you sure you can keep mum?"
+
+"Tom, we GOT to keep mum. You know that. That Injun devil wouldn't
+make any more of drownding us than a couple of cats, if we was to
+squeak 'bout this and they didn't hang him. Now, look-a-here, Tom, less
+take and swear to one another--that's what we got to do--swear to keep
+mum."
+
+"I'm agreed. It's the best thing. Would you just hold hands and swear
+that we--"
+
+"Oh no, that wouldn't do for this. That's good enough for little
+rubbishy common things--specially with gals, cuz THEY go back on you
+anyway, and blab if they get in a huff--but there orter be writing
+'bout a big thing like this. And blood."
+
+Tom's whole being applauded this idea. It was deep, and dark, and
+awful; the hour, the circumstances, the surroundings, were in keeping
+with it. He picked up a clean pine shingle that lay in the moonlight,
+took a little fragment of "red keel" out of his pocket, got the moon on
+his work, and painfully scrawled these lines, emphasizing each slow
+down-stroke by clamping his tongue between his teeth, and letting up
+the pressure on the up-strokes. [See next page.]
+
+ "Huck Finn and
+ Tom Sawyer swears
+ they will keep mum
+ about This and They
+ wish They may Drop
+ down dead in Their
+ Tracks if They ever
+ Tell and Rot."
+
+Huckleberry was filled with admiration of Tom's facility in writing,
+and the sublimity of his language. He at once took a pin from his lapel
+and was going to prick his flesh, but Tom said:
+
+"Hold on! Don't do that. A pin's brass. It might have verdigrease on
+it."
+
+"What's verdigrease?"
+
+"It's p'ison. That's what it is. You just swaller some of it once
+--you'll see."
+
+So Tom unwound the thread from one of his needles, and each boy
+pricked the ball of his thumb and squeezed out a drop of blood. In
+time, after many squeezes, Tom managed to sign his initials, using the
+ball of his little finger for a pen. Then he showed Huckleberry how to
+make an H and an F, and the oath was complete. They buried the shingle
+close to the wall, with some dismal ceremonies and incantations, and
+the fetters that bound their tongues were considered to be locked and
+the key thrown away.
+
+A figure crept stealthily through a break in the other end of the
+ruined building, now, but they did not notice it.
+
+"Tom," whispered Huckleberry, "does this keep us from EVER telling
+--ALWAYS?"
+
+"Of course it does. It don't make any difference WHAT happens, we got
+to keep mum. We'd drop down dead--don't YOU know that?"
+
+"Yes, I reckon that's so."
+
+They continued to whisper for some little time. Presently a dog set up
+a long, lugubrious howl just outside--within ten feet of them. The boys
+clasped each other suddenly, in an agony of fright.
+
+"Which of us does he mean?" gasped Huckleberry.
+
+"I dono--peep through the crack. Quick!"
+
+"No, YOU, Tom!"
+
+"I can't--I can't DO it, Huck!"
+
+"Please, Tom. There 'tis again!"
+
+"Oh, lordy, I'm thankful!" whispered Tom. "I know his voice. It's Bull
+Harbison." *
+
+[* If Mr. Harbison owned a slave named Bull, Tom would have spoken of
+him as "Harbison's Bull," but a son or a dog of that name was "Bull
+Harbison."]
+
+"Oh, that's good--I tell you, Tom, I was most scared to death; I'd a
+bet anything it was a STRAY dog."
+
+The dog howled again. The boys' hearts sank once more.
+
+"Oh, my! that ain't no Bull Harbison!" whispered Huckleberry. "DO, Tom!"
+
+Tom, quaking with fear, yielded, and put his eye to the crack. His
+whisper was hardly audible when he said:
+
+"Oh, Huck, IT S A STRAY DOG!"
+
+"Quick, Tom, quick! Who does he mean?"
+
+"Huck, he must mean us both--we're right together."
+
+"Oh, Tom, I reckon we're goners. I reckon there ain't no mistake 'bout
+where I'LL go to. I been so wicked."
+
+"Dad fetch it! This comes of playing hookey and doing everything a
+feller's told NOT to do. I might a been good, like Sid, if I'd a tried
+--but no, I wouldn't, of course. But if ever I get off this time, I lay
+I'll just WALLER in Sunday-schools!" And Tom began to snuffle a little.
+
+"YOU bad!" and Huckleberry began to snuffle too. "Consound it, Tom
+Sawyer, you're just old pie, 'longside o' what I am. Oh, LORDY, lordy,
+lordy, I wisht I only had half your chance."
+
+Tom choked off and whispered:
+
+"Look, Hucky, look! He's got his BACK to us!"
+
+Hucky looked, with joy in his heart.
+
+"Well, he has, by jingoes! Did he before?"
+
+"Yes, he did. But I, like a fool, never thought. Oh, this is bully,
+you know. NOW who can he mean?"
+
+The howling stopped. Tom pricked up his ears.
+
+"Sh! What's that?" he whispered.
+
+"Sounds like--like hogs grunting. No--it's somebody snoring, Tom."
+
+"That IS it! Where 'bouts is it, Huck?"
+
+"I bleeve it's down at 'tother end. Sounds so, anyway. Pap used to
+sleep there, sometimes, 'long with the hogs, but laws bless you, he
+just lifts things when HE snores. Besides, I reckon he ain't ever
+coming back to this town any more."
+
+The spirit of adventure rose in the boys' souls once more.
+
+"Hucky, do you das't to go if I lead?"
+
+"I don't like to, much. Tom, s'pose it's Injun Joe!"
+
+Tom quailed. But presently the temptation rose up strong again and the
+boys agreed to try, with the understanding that they would take to
+their heels if the snoring stopped. So they went tiptoeing stealthily
+down, the one behind the other. When they had got to within five steps
+of the snorer, Tom stepped on a stick, and it broke with a sharp snap.
+The man moaned, writhed a little, and his face came into the moonlight.
+It was Muff Potter. The boys' hearts had stood still, and their hopes
+too, when the man moved, but their fears passed away now. They tiptoed
+out, through the broken weather-boarding, and stopped at a little
+distance to exchange a parting word. That long, lugubrious howl rose on
+the night air again! They turned and saw the strange dog standing
+within a few feet of where Potter was lying, and FACING Potter, with
+his nose pointing heavenward.
+
+"Oh, geeminy, it's HIM!" exclaimed both boys, in a breath.
+
+"Say, Tom--they say a stray dog come howling around Johnny Miller's
+house, 'bout midnight, as much as two weeks ago; and a whippoorwill
+come in and lit on the banisters and sung, the very same evening; and
+there ain't anybody dead there yet."
+
+"Well, I know that. And suppose there ain't. Didn't Gracie Miller fall
+in the kitchen fire and burn herself terrible the very next Saturday?"
+
+"Yes, but she ain't DEAD. And what's more, she's getting better, too."
+
+"All right, you wait and see. She's a goner, just as dead sure as Muff
+Potter's a goner. That's what the niggers say, and they know all about
+these kind of things, Huck."
+
+Then they separated, cogitating. When Tom crept in at his bedroom
+window the night was almost spent. He undressed with excessive caution,
+and fell asleep congratulating himself that nobody knew of his
+escapade. He was not aware that the gently-snoring Sid was awake, and
+had been so for an hour.
+
+When Tom awoke, Sid was dressed and gone. There was a late look in the
+light, a late sense in the atmosphere. He was startled. Why had he not
+been called--persecuted till he was up, as usual? The thought filled
+him with bodings. Within five minutes he was dressed and down-stairs,
+feeling sore and drowsy. The family were still at table, but they had
+finished breakfast. There was no voice of rebuke; but there were
+averted eyes; there was a silence and an air of solemnity that struck a
+chill to the culprit's heart. He sat down and tried to seem gay, but it
+was up-hill work; it roused no smile, no response, and he lapsed into
+silence and let his heart sink down to the depths.
+
+After breakfast his aunt took him aside, and Tom almost brightened in
+the hope that he was going to be flogged; but it was not so. His aunt
+wept over him and asked him how he could go and break her old heart so;
+and finally told him to go on, and ruin himself and bring her gray
+hairs with sorrow to the grave, for it was no use for her to try any
+more. This was worse than a thousand whippings, and Tom's heart was
+sorer now than his body. He cried, he pleaded for forgiveness, promised
+to reform over and over again, and then received his dismissal, feeling
+that he had won but an imperfect forgiveness and established but a
+feeble confidence.
+
+He left the presence too miserable to even feel revengeful toward Sid;
+and so the latter's prompt retreat through the back gate was
+unnecessary. He moped to school gloomy and sad, and took his flogging,
+along with Joe Harper, for playing hookey the day before, with the air
+of one whose heart was busy with heavier woes and wholly dead to
+trifles. Then he betook himself to his seat, rested his elbows on his
+desk and his jaws in his hands, and stared at the wall with the stony
+stare of suffering that has reached the limit and can no further go.
+His elbow was pressing against some hard substance. After a long time
+he slowly and sadly changed his position, and took up this object with
+a sigh. It was in a paper. He unrolled it. A long, lingering, colossal
+sigh followed, and his heart broke. It was his brass andiron knob!
+
+This final feather broke the camel's back.
+
+
+
+CHAPTER XI
+
+CLOSE upon the hour of noon the whole village was suddenly electrified
+with the ghastly news. No need of the as yet undreamed-of telegraph;
+the tale flew from man to man, from group to group, from house to
+house, with little less than telegraphic speed. Of course the
+schoolmaster gave holiday for that afternoon; the town would have
+thought strangely of him if he had not.
+
+A gory knife had been found close to the murdered man, and it had been
+recognized by somebody as belonging to Muff Potter--so the story ran.
+And it was said that a belated citizen had come upon Potter washing
+himself in the "branch" about one or two o'clock in the morning, and
+that Potter had at once sneaked off--suspicious circumstances,
+especially the washing which was not a habit with Potter. It was also
+said that the town had been ransacked for this "murderer" (the public
+are not slow in the matter of sifting evidence and arriving at a
+verdict), but that he could not be found. Horsemen had departed down
+all the roads in every direction, and the Sheriff "was confident" that
+he would be captured before night.
+
+All the town was drifting toward the graveyard. Tom's heartbreak
+vanished and he joined the procession, not because he would not a
+thousand times rather go anywhere else, but because an awful,
+unaccountable fascination drew him on. Arrived at the dreadful place,
+he wormed his small body through the crowd and saw the dismal
+spectacle. It seemed to him an age since he was there before. Somebody
+pinched his arm. He turned, and his eyes met Huckleberry's. Then both
+looked elsewhere at once, and wondered if anybody had noticed anything
+in their mutual glance. But everybody was talking, and intent upon the
+grisly spectacle before them.
+
+"Poor fellow!" "Poor young fellow!" "This ought to be a lesson to
+grave robbers!" "Muff Potter'll hang for this if they catch him!" This
+was the drift of remark; and the minister said, "It was a judgment; His
+hand is here."
+
+Now Tom shivered from head to heel; for his eye fell upon the stolid
+face of Injun Joe. At this moment the crowd began to sway and struggle,
+and voices shouted, "It's him! it's him! he's coming himself!"
+
+"Who? Who?" from twenty voices.
+
+"Muff Potter!"
+
+"Hallo, he's stopped!--Look out, he's turning! Don't let him get away!"
+
+People in the branches of the trees over Tom's head said he wasn't
+trying to get away--he only looked doubtful and perplexed.
+
+"Infernal impudence!" said a bystander; "wanted to come and take a
+quiet look at his work, I reckon--didn't expect any company."
+
+The crowd fell apart, now, and the Sheriff came through,
+ostentatiously leading Potter by the arm. The poor fellow's face was
+haggard, and his eyes showed the fear that was upon him. When he stood
+before the murdered man, he shook as with a palsy, and he put his face
+in his hands and burst into tears.
+
+"I didn't do it, friends," he sobbed; "'pon my word and honor I never
+done it."
+
+"Who's accused you?" shouted a voice.
+
+This shot seemed to carry home. Potter lifted his face and looked
+around him with a pathetic hopelessness in his eyes. He saw Injun Joe,
+and exclaimed:
+
+"Oh, Injun Joe, you promised me you'd never--"
+
+"Is that your knife?" and it was thrust before him by the Sheriff.
+
+Potter would have fallen if they had not caught him and eased him to
+the ground. Then he said:
+
+"Something told me 't if I didn't come back and get--" He shuddered;
+then waved his nerveless hand with a vanquished gesture and said, "Tell
+'em, Joe, tell 'em--it ain't any use any more."
+
+Then Huckleberry and Tom stood dumb and staring, and heard the
+stony-hearted liar reel off his serene statement, they expecting every
+moment that the clear sky would deliver God's lightnings upon his head,
+and wondering to see how long the stroke was delayed. And when he had
+finished and still stood alive and whole, their wavering impulse to
+break their oath and save the poor betrayed prisoner's life faded and
+vanished away, for plainly this miscreant had sold himself to Satan and
+it would be fatal to meddle with the property of such a power as that.
+
+"Why didn't you leave? What did you want to come here for?" somebody
+said.
+
+"I couldn't help it--I couldn't help it," Potter moaned. "I wanted to
+run away, but I couldn't seem to come anywhere but here." And he fell
+to sobbing again.
+
+Injun Joe repeated his statement, just as calmly, a few minutes
+afterward on the inquest, under oath; and the boys, seeing that the
+lightnings were still withheld, were confirmed in their belief that Joe
+had sold himself to the devil. He was now become, to them, the most
+balefully interesting object they had ever looked upon, and they could
+not take their fascinated eyes from his face.
+
+They inwardly resolved to watch him nights, when opportunity should
+offer, in the hope of getting a glimpse of his dread master.
+
+Injun Joe helped to raise the body of the murdered man and put it in a
+wagon for removal; and it was whispered through the shuddering crowd
+that the wound bled a little! The boys thought that this happy
+circumstance would turn suspicion in the right direction; but they were
+disappointed, for more than one villager remarked:
+
+"It was within three feet of Muff Potter when it done it."
+
+Tom's fearful secret and gnawing conscience disturbed his sleep for as
+much as a week after this; and at breakfast one morning Sid said:
+
+"Tom, you pitch around and talk in your sleep so much that you keep me
+awake half the time."
+
+Tom blanched and dropped his eyes.
+
+"It's a bad sign," said Aunt Polly, gravely. "What you got on your
+mind, Tom?"
+
+"Nothing. Nothing 't I know of." But the boy's hand shook so that he
+spilled his coffee.
+
+"And you do talk such stuff," Sid said. "Last night you said, 'It's
+blood, it's blood, that's what it is!' You said that over and over. And
+you said, 'Don't torment me so--I'll tell!' Tell WHAT? What is it
+you'll tell?"
+
+Everything was swimming before Tom. There is no telling what might
+have happened, now, but luckily the concern passed out of Aunt Polly's
+face and she came to Tom's relief without knowing it. She said:
+
+"Sho! It's that dreadful murder. I dream about it most every night
+myself. Sometimes I dream it's me that done it."
+
+Mary said she had been affected much the same way. Sid seemed
+satisfied. Tom got out of the presence as quick as he plausibly could,
+and after that he complained of toothache for a week, and tied up his
+jaws every night. He never knew that Sid lay nightly watching, and
+frequently slipped the bandage free and then leaned on his elbow
+listening a good while at a time, and afterward slipped the bandage
+back to its place again. Tom's distress of mind wore off gradually and
+the toothache grew irksome and was discarded. If Sid really managed to
+make anything out of Tom's disjointed mutterings, he kept it to himself.
+
+It seemed to Tom that his schoolmates never would get done holding
+inquests on dead cats, and thus keeping his trouble present to his
+mind. Sid noticed that Tom never was coroner at one of these inquiries,
+though it had been his habit to take the lead in all new enterprises;
+he noticed, too, that Tom never acted as a witness--and that was
+strange; and Sid did not overlook the fact that Tom even showed a
+marked aversion to these inquests, and always avoided them when he
+could. Sid marvelled, but said nothing. However, even inquests went out
+of vogue at last, and ceased to torture Tom's conscience.
+
+Every day or two, during this time of sorrow, Tom watched his
+opportunity and went to the little grated jail-window and smuggled such
+small comforts through to the "murderer" as he could get hold of. The
+jail was a trifling little brick den that stood in a marsh at the edge
+of the village, and no guards were afforded for it; indeed, it was
+seldom occupied. These offerings greatly helped to ease Tom's
+conscience.
+
+The villagers had a strong desire to tar-and-feather Injun Joe and
+ride him on a rail, for body-snatching, but so formidable was his
+character that nobody could be found who was willing to take the lead
+in the matter, so it was dropped. He had been careful to begin both of
+his inquest-statements with the fight, without confessing the
+grave-robbery that preceded it; therefore it was deemed wisest not
+to try the case in the courts at present.
+
+
+
+CHAPTER XII
+
+ONE of the reasons why Tom's mind had drifted away from its secret
+troubles was, that it had found a new and weighty matter to interest
+itself about. Becky Thatcher had stopped coming to school. Tom had
+struggled with his pride a few days, and tried to "whistle her down the
+wind," but failed. He began to find himself hanging around her father's
+house, nights, and feeling very miserable. She was ill. What if she
+should die! There was distraction in the thought. He no longer took an
+interest in war, nor even in piracy. The charm of life was gone; there
+was nothing but dreariness left. He put his hoop away, and his bat;
+there was no joy in them any more. His aunt was concerned. She began to
+try all manner of remedies on him. She was one of those people who are
+infatuated with patent medicines and all new-fangled methods of
+producing health or mending it. She was an inveterate experimenter in
+these things. When something fresh in this line came out she was in a
+fever, right away, to try it; not on herself, for she was never ailing,
+but on anybody else that came handy. She was a subscriber for all the
+"Health" periodicals and phrenological frauds; and the solemn ignorance
+they were inflated with was breath to her nostrils. All the "rot" they
+contained about ventilation, and how to go to bed, and how to get up,
+and what to eat, and what to drink, and how much exercise to take, and
+what frame of mind to keep one's self in, and what sort of clothing to
+wear, was all gospel to her, and she never observed that her
+health-journals of the current month customarily upset everything they
+had recommended the month before. She was as simple-hearted and honest
+as the day was long, and so she was an easy victim. She gathered
+together her quack periodicals and her quack medicines, and thus armed
+with death, went about on her pale horse, metaphorically speaking, with
+"hell following after." But she never suspected that she was not an
+angel of healing and the balm of Gilead in disguise, to the suffering
+neighbors.
+
+The water treatment was new, now, and Tom's low condition was a
+windfall to her. She had him out at daylight every morning, stood him
+up in the woodshed and drowned him with a deluge of cold water; then
+she scrubbed him down with a towel like a file, and so brought him to;
+then she rolled him up in a wet sheet and put him away under blankets
+till she sweated his soul clean and "the yellow stains of it came
+through his pores"--as Tom said.
+
+Yet notwithstanding all this, the boy grew more and more melancholy
+and pale and dejected. She added hot baths, sitz baths, shower baths,
+and plunges. The boy remained as dismal as a hearse. She began to
+assist the water with a slim oatmeal diet and blister-plasters. She
+calculated his capacity as she would a jug's, and filled him up every
+day with quack cure-alls.
+
+Tom had become indifferent to persecution by this time. This phase
+filled the old lady's heart with consternation. This indifference must
+be broken up at any cost. Now she heard of Pain-killer for the first
+time. She ordered a lot at once. She tasted it and was filled with
+gratitude. It was simply fire in a liquid form. She dropped the water
+treatment and everything else, and pinned her faith to Pain-killer. She
+gave Tom a teaspoonful and watched with the deepest anxiety for the
+result. Her troubles were instantly at rest, her soul at peace again;
+for the "indifference" was broken up. The boy could not have shown a
+wilder, heartier interest, if she had built a fire under him.
+
+Tom felt that it was time to wake up; this sort of life might be
+romantic enough, in his blighted condition, but it was getting to have
+too little sentiment and too much distracting variety about it. So he
+thought over various plans for relief, and finally hit pon that of
+professing to be fond of Pain-killer. He asked for it so often that he
+became a nuisance, and his aunt ended by telling him to help himself
+and quit bothering her. If it had been Sid, she would have had no
+misgivings to alloy her delight; but since it was Tom, she watched the
+bottle clandestinely. She found that the medicine did really diminish,
+but it did not occur to her that the boy was mending the health of a
+crack in the sitting-room floor with it.
+
+One day Tom was in the act of dosing the crack when his aunt's yellow
+cat came along, purring, eying the teaspoon avariciously, and begging
+for a taste. Tom said:
+
+"Don't ask for it unless you want it, Peter."
+
+But Peter signified that he did want it.
+
+"You better make sure."
+
+Peter was sure.
+
+"Now you've asked for it, and I'll give it to you, because there ain't
+anything mean about me; but if you find you don't like it, you mustn't
+blame anybody but your own self."
+
+Peter was agreeable. So Tom pried his mouth open and poured down the
+Pain-killer. Peter sprang a couple of yards in the air, and then
+delivered a war-whoop and set off round and round the room, banging
+against furniture, upsetting flower-pots, and making general havoc.
+Next he rose on his hind feet and pranced around, in a frenzy of
+enjoyment, with his head over his shoulder and his voice proclaiming
+his unappeasable happiness. Then he went tearing around the house again
+spreading chaos and destruction in his path. Aunt Polly entered in time
+to see him throw a few double summersets, deliver a final mighty
+hurrah, and sail through the open window, carrying the rest of the
+flower-pots with him. The old lady stood petrified with astonishment,
+peering over her glasses; Tom lay on the floor expiring with laughter.
+
+"Tom, what on earth ails that cat?"
+
+"I don't know, aunt," gasped the boy.
+
+"Why, I never see anything like it. What did make him act so?"
+
+"Deed I don't know, Aunt Polly; cats always act so when they're having
+a good time."
+
+"They do, do they?" There was something in the tone that made Tom
+apprehensive.
+
+"Yes'm. That is, I believe they do."
+
+"You DO?"
+
+"Yes'm."
+
+The old lady was bending down, Tom watching, with interest emphasized
+by anxiety. Too late he divined her "drift." The handle of the telltale
+teaspoon was visible under the bed-valance. Aunt Polly took it, held it
+up. Tom winced, and dropped his eyes. Aunt Polly raised him by the
+usual handle--his ear--and cracked his head soundly with her thimble.
+
+"Now, sir, what did you want to treat that poor dumb beast so, for?"
+
+"I done it out of pity for him--because he hadn't any aunt."
+
+"Hadn't any aunt!--you numskull. What has that got to do with it?"
+
+"Heaps. Because if he'd had one she'd a burnt him out herself! She'd a
+roasted his bowels out of him 'thout any more feeling than if he was a
+human!"
+
+Aunt Polly felt a sudden pang of remorse. This was putting the thing
+in a new light; what was cruelty to a cat MIGHT be cruelty to a boy,
+too. She began to soften; she felt sorry. Her eyes watered a little,
+and she put her hand on Tom's head and said gently:
+
+"I was meaning for the best, Tom. And, Tom, it DID do you good."
+
+Tom looked up in her face with just a perceptible twinkle peeping
+through his gravity.
+
+"I know you was meaning for the best, aunty, and so was I with Peter.
+It done HIM good, too. I never see him get around so since--"
+
+"Oh, go 'long with you, Tom, before you aggravate me again. And you
+try and see if you can't be a good boy, for once, and you needn't take
+any more medicine."
+
+Tom reached school ahead of time. It was noticed that this strange
+thing had been occurring every day latterly. And now, as usual of late,
+he hung about the gate of the schoolyard instead of playing with his
+comrades. He was sick, he said, and he looked it. He tried to seem to
+be looking everywhere but whither he really was looking--down the road.
+Presently Jeff Thatcher hove in sight, and Tom's face lighted; he gazed
+a moment, and then turned sorrowfully away. When Jeff arrived, Tom
+accosted him; and "led up" warily to opportunities for remark about
+Becky, but the giddy lad never could see the bait. Tom watched and
+watched, hoping whenever a frisking frock came in sight, and hating the
+owner of it as soon as he saw she was not the right one. At last frocks
+ceased to appear, and he dropped hopelessly into the dumps; he entered
+the empty schoolhouse and sat down to suffer. Then one more frock
+passed in at the gate, and Tom's heart gave a great bound. The next
+instant he was out, and "going on" like an Indian; yelling, laughing,
+chasing boys, jumping over the fence at risk of life and limb, throwing
+handsprings, standing on his head--doing all the heroic things he could
+conceive of, and keeping a furtive eye out, all the while, to see if
+Becky Thatcher was noticing. But she seemed to be unconscious of it
+all; she never looked. Could it be possible that she was not aware that
+he was there? He carried his exploits to her immediate vicinity; came
+war-whooping around, snatched a boy's cap, hurled it to the roof of the
+schoolhouse, broke through a group of boys, tumbling them in every
+direction, and fell sprawling, himself, under Becky's nose, almost
+upsetting her--and she turned, with her nose in the air, and he heard
+her say: "Mf! some people think they're mighty smart--always showing
+off!"
+
+Tom's cheeks burned. He gathered himself up and sneaked off, crushed
+and crestfallen.
+
+
+
+CHAPTER XIII
+
+TOM'S mind was made up now. He was gloomy and desperate. He was a
+forsaken, friendless boy, he said; nobody loved him; when they found
+out what they had driven him to, perhaps they would be sorry; he had
+tried to do right and get along, but they would not let him; since
+nothing would do them but to be rid of him, let it be so; and let them
+blame HIM for the consequences--why shouldn't they? What right had the
+friendless to complain? Yes, they had forced him to it at last: he
+would lead a life of crime. There was no choice.
+
+By this time he was far down Meadow Lane, and the bell for school to
+"take up" tinkled faintly upon his ear. He sobbed, now, to think he
+should never, never hear that old familiar sound any more--it was very
+hard, but it was forced on him; since he was driven out into the cold
+world, he must submit--but he forgave them. Then the sobs came thick
+and fast.
+
+Just at this point he met his soul's sworn comrade, Joe Harper
+--hard-eyed, and with evidently a great and dismal purpose in his heart.
+Plainly here were "two souls with but a single thought." Tom, wiping
+his eyes with his sleeve, began to blubber out something about a
+resolution to escape from hard usage and lack of sympathy at home by
+roaming abroad into the great world never to return; and ended by
+hoping that Joe would not forget him.
+
+But it transpired that this was a request which Joe had just been
+going to make of Tom, and had come to hunt him up for that purpose. His
+mother had whipped him for drinking some cream which he had never
+tasted and knew nothing about; it was plain that she was tired of him
+and wished him to go; if she felt that way, there was nothing for him
+to do but succumb; he hoped she would be happy, and never regret having
+driven her poor boy out into the unfeeling world to suffer and die.
+
+As the two boys walked sorrowing along, they made a new compact to
+stand by each other and be brothers and never separate till death
+relieved them of their troubles. Then they began to lay their plans.
+Joe was for being a hermit, and living on crusts in a remote cave, and
+dying, some time, of cold and want and grief; but after listening to
+Tom, he conceded that there were some conspicuous advantages about a
+life of crime, and so he consented to be a pirate.
+
+Three miles below St. Petersburg, at a point where the Mississippi
+River was a trifle over a mile wide, there was a long, narrow, wooded
+island, with a shallow bar at the head of it, and this offered well as
+a rendezvous. It was not inhabited; it lay far over toward the further
+shore, abreast a dense and almost wholly unpeopled forest. So Jackson's
+Island was chosen. Who were to be the subjects of their piracies was a
+matter that did not occur to them. Then they hunted up Huckleberry
+Finn, and he joined them promptly, for all careers were one to him; he
+was indifferent. They presently separated to meet at a lonely spot on
+the river-bank two miles above the village at the favorite hour--which
+was midnight. There was a small log raft there which they meant to
+capture. Each would bring hooks and lines, and such provision as he
+could steal in the most dark and mysterious way--as became outlaws. And
+before the afternoon was done, they had all managed to enjoy the sweet
+glory of spreading the fact that pretty soon the town would "hear
+something." All who got this vague hint were cautioned to "be mum and
+wait."
+
+About midnight Tom arrived with a boiled ham and a few trifles,
+and stopped in a dense undergrowth on a small bluff overlooking the
+meeting-place. It was starlight, and very still. The mighty river lay
+like an ocean at rest. Tom listened a moment, but no sound disturbed the
+quiet. Then he gave a low, distinct whistle. It was answered from under
+the bluff. Tom whistled twice more; these signals were answered in the
+same way. Then a guarded voice said:
+
+"Who goes there?"
+
+"Tom Sawyer, the Black Avenger of the Spanish Main. Name your names."
+
+"Huck Finn the Red-Handed, and Joe Harper the Terror of the Seas." Tom
+had furnished these titles, from his favorite literature.
+
+"'Tis well. Give the countersign."
+
+Two hoarse whispers delivered the same awful word simultaneously to
+the brooding night:
+
+"BLOOD!"
+
+Then Tom tumbled his ham over the bluff and let himself down after it,
+tearing both skin and clothes to some extent in the effort. There was
+an easy, comfortable path along the shore under the bluff, but it
+lacked the advantages of difficulty and danger so valued by a pirate.
+
+The Terror of the Seas had brought a side of bacon, and had about worn
+himself out with getting it there. Finn the Red-Handed had stolen a
+skillet and a quantity of half-cured leaf tobacco, and had also brought
+a few corn-cobs to make pipes with. But none of the pirates smoked or
+"chewed" but himself. The Black Avenger of the Spanish Main said it
+would never do to start without some fire. That was a wise thought;
+matches were hardly known there in that day. They saw a fire
+smouldering upon a great raft a hundred yards above, and they went
+stealthily thither and helped themselves to a chunk. They made an
+imposing adventure of it, saying, "Hist!" every now and then, and
+suddenly halting with finger on lip; moving with hands on imaginary
+dagger-hilts; and giving orders in dismal whispers that if "the foe"
+stirred, to "let him have it to the hilt," because "dead men tell no
+tales." They knew well enough that the raftsmen were all down at the
+village laying in stores or having a spree, but still that was no
+excuse for their conducting this thing in an unpiratical way.
+
+They shoved off, presently, Tom in command, Huck at the after oar and
+Joe at the forward. Tom stood amidships, gloomy-browed, and with folded
+arms, and gave his orders in a low, stern whisper:
+
+"Luff, and bring her to the wind!"
+
+"Aye-aye, sir!"
+
+"Steady, steady-y-y-y!"
+
+"Steady it is, sir!"
+
+"Let her go off a point!"
+
+"Point it is, sir!"
+
+As the boys steadily and monotonously drove the raft toward mid-stream
+it was no doubt understood that these orders were given only for
+"style," and were not intended to mean anything in particular.
+
+"What sail's she carrying?"
+
+"Courses, tops'ls, and flying-jib, sir."
+
+"Send the r'yals up! Lay out aloft, there, half a dozen of ye
+--foretopmaststuns'l! Lively, now!"
+
+"Aye-aye, sir!"
+
+"Shake out that maintogalans'l! Sheets and braces! NOW my hearties!"
+
+"Aye-aye, sir!"
+
+"Hellum-a-lee--hard a port! Stand by to meet her when she comes! Port,
+port! NOW, men! With a will! Stead-y-y-y!"
+
+"Steady it is, sir!"
+
+The raft drew beyond the middle of the river; the boys pointed her
+head right, and then lay on their oars. The river was not high, so
+there was not more than a two or three mile current. Hardly a word was
+said during the next three-quarters of an hour. Now the raft was
+passing before the distant town. Two or three glimmering lights showed
+where it lay, peacefully sleeping, beyond the vague vast sweep of
+star-gemmed water, unconscious of the tremendous event that was happening.
+The Black Avenger stood still with folded arms, "looking his last" upon
+the scene of his former joys and his later sufferings, and wishing
+"she" could see him now, abroad on the wild sea, facing peril and death
+with dauntless heart, going to his doom with a grim smile on his lips.
+It was but a small strain on his imagination to remove Jackson's Island
+beyond eyeshot of the village, and so he "looked his last" with a
+broken and satisfied heart. The other pirates were looking their last,
+too; and they all looked so long that they came near letting the
+current drift them out of the range of the island. But they discovered
+the danger in time, and made shift to avert it. About two o'clock in
+the morning the raft grounded on the bar two hundred yards above the
+head of the island, and they waded back and forth until they had landed
+their freight. Part of the little raft's belongings consisted of an old
+sail, and this they spread over a nook in the bushes for a tent to
+shelter their provisions; but they themselves would sleep in the open
+air in good weather, as became outlaws.
+
+They built a fire against the side of a great log twenty or thirty
+steps within the sombre depths of the forest, and then cooked some
+bacon in the frying-pan for supper, and used up half of the corn "pone"
+stock they had brought. It seemed glorious sport to be feasting in that
+wild, free way in the virgin forest of an unexplored and uninhabited
+island, far from the haunts of men, and they said they never would
+return to civilization. The climbing fire lit up their faces and threw
+its ruddy glare upon the pillared tree-trunks of their forest temple,
+and upon the varnished foliage and festooning vines.
+
+When the last crisp slice of bacon was gone, and the last allowance of
+corn pone devoured, the boys stretched themselves out on the grass,
+filled with contentment. They could have found a cooler place, but they
+would not deny themselves such a romantic feature as the roasting
+camp-fire.
+
+"AIN'T it gay?" said Joe.
+
+"It's NUTS!" said Tom. "What would the boys say if they could see us?"
+
+"Say? Well, they'd just die to be here--hey, Hucky!"
+
+"I reckon so," said Huckleberry; "anyways, I'm suited. I don't want
+nothing better'n this. I don't ever get enough to eat, gen'ally--and
+here they can't come and pick at a feller and bullyrag him so."
+
+"It's just the life for me," said Tom. "You don't have to get up,
+mornings, and you don't have to go to school, and wash, and all that
+blame foolishness. You see a pirate don't have to do ANYTHING, Joe,
+when he's ashore, but a hermit HE has to be praying considerable, and
+then he don't have any fun, anyway, all by himself that way."
+
+"Oh yes, that's so," said Joe, "but I hadn't thought much about it,
+you know. I'd a good deal rather be a pirate, now that I've tried it."
+
+"You see," said Tom, "people don't go much on hermits, nowadays, like
+they used to in old times, but a pirate's always respected. And a
+hermit's got to sleep on the hardest place he can find, and put
+sackcloth and ashes on his head, and stand out in the rain, and--"
+
+"What does he put sackcloth and ashes on his head for?" inquired Huck.
+
+"I dono. But they've GOT to do it. Hermits always do. You'd have to do
+that if you was a hermit."
+
+"Dern'd if I would," said Huck.
+
+"Well, what would you do?"
+
+"I dono. But I wouldn't do that."
+
+"Why, Huck, you'd HAVE to. How'd you get around it?"
+
+"Why, I just wouldn't stand it. I'd run away."
+
+"Run away! Well, you WOULD be a nice old slouch of a hermit. You'd be
+a disgrace."
+
+The Red-Handed made no response, being better employed. He had
+finished gouging out a cob, and now he fitted a weed stem to it, loaded
+it with tobacco, and was pressing a coal to the charge and blowing a
+cloud of fragrant smoke--he was in the full bloom of luxurious
+contentment. The other pirates envied him this majestic vice, and
+secretly resolved to acquire it shortly. Presently Huck said:
+
+"What does pirates have to do?"
+
+Tom said:
+
+"Oh, they have just a bully time--take ships and burn them, and get
+the money and bury it in awful places in their island where there's
+ghosts and things to watch it, and kill everybody in the ships--make
+'em walk a plank."
+
+"And they carry the women to the island," said Joe; "they don't kill
+the women."
+
+"No," assented Tom, "they don't kill the women--they're too noble. And
+the women's always beautiful, too.
+
+"And don't they wear the bulliest clothes! Oh no! All gold and silver
+and di'monds," said Joe, with enthusiasm.
+
+"Who?" said Huck.
+
+"Why, the pirates."
+
+Huck scanned his own clothing forlornly.
+
+"I reckon I ain't dressed fitten for a pirate," said he, with a
+regretful pathos in his voice; "but I ain't got none but these."
+
+But the other boys told him the fine clothes would come fast enough,
+after they should have begun their adventures. They made him understand
+that his poor rags would do to begin with, though it was customary for
+wealthy pirates to start with a proper wardrobe.
+
+Gradually their talk died out and drowsiness began to steal upon the
+eyelids of the little waifs. The pipe dropped from the fingers of the
+Red-Handed, and he slept the sleep of the conscience-free and the
+weary. The Terror of the Seas and the Black Avenger of the Spanish Main
+had more difficulty in getting to sleep. They said their prayers
+inwardly, and lying down, since there was nobody there with authority
+to make them kneel and recite aloud; in truth, they had a mind not to
+say them at all, but they were afraid to proceed to such lengths as
+that, lest they might call down a sudden and special thunderbolt from
+heaven. Then at once they reached and hovered upon the imminent verge
+of sleep--but an intruder came, now, that would not "down." It was
+conscience. They began to feel a vague fear that they had been doing
+wrong to run away; and next they thought of the stolen meat, and then
+the real torture came. They tried to argue it away by reminding
+conscience that they had purloined sweetmeats and apples scores of
+times; but conscience was not to be appeased by such thin
+plausibilities; it seemed to them, in the end, that there was no
+getting around the stubborn fact that taking sweetmeats was only
+"hooking," while taking bacon and hams and such valuables was plain
+simple stealing--and there was a command against that in the Bible. So
+they inwardly resolved that so long as they remained in the business,
+their piracies should not again be sullied with the crime of stealing.
+Then conscience granted a truce, and these curiously inconsistent
+pirates fell peacefully to sleep.
+
+
+
+CHAPTER XIV
+
+WHEN Tom awoke in the morning, he wondered where he was. He sat up and
+rubbed his eyes and looked around. Then he comprehended. It was the
+cool gray dawn, and there was a delicious sense of repose and peace in
+the deep pervading calm and silence of the woods. Not a leaf stirred;
+not a sound obtruded upon great Nature's meditation. Beaded dewdrops
+stood upon the leaves and grasses. A white layer of ashes covered the
+fire, and a thin blue breath of smoke rose straight into the air. Joe
+and Huck still slept.
+
+Now, far away in the woods a bird called; another answered; presently
+the hammering of a woodpecker was heard. Gradually the cool dim gray of
+the morning whitened, and as gradually sounds multiplied and life
+manifested itself. The marvel of Nature shaking off sleep and going to
+work unfolded itself to the musing boy. A little green worm came
+crawling over a dewy leaf, lifting two-thirds of his body into the air
+from time to time and "sniffing around," then proceeding again--for he
+was measuring, Tom said; and when the worm approached him, of its own
+accord, he sat as still as a stone, with his hopes rising and falling,
+by turns, as the creature still came toward him or seemed inclined to
+go elsewhere; and when at last it considered a painful moment with its
+curved body in the air and then came decisively down upon Tom's leg and
+began a journey over him, his whole heart was glad--for that meant that
+he was going to have a new suit of clothes--without the shadow of a
+doubt a gaudy piratical uniform. Now a procession of ants appeared,
+from nowhere in particular, and went about their labors; one struggled
+manfully by with a dead spider five times as big as itself in its arms,
+and lugged it straight up a tree-trunk. A brown spotted lady-bug
+climbed the dizzy height of a grass blade, and Tom bent down close to
+it and said, "Lady-bug, lady-bug, fly away home, your house is on fire,
+your children's alone," and she took wing and went off to see about it
+--which did not surprise the boy, for he knew of old that this insect was
+credulous about conflagrations, and he had practised upon its
+simplicity more than once. A tumblebug came next, heaving sturdily at
+its ball, and Tom touched the creature, to see it shut its legs against
+its body and pretend to be dead. The birds were fairly rioting by this
+time. A catbird, the Northern mocker, lit in a tree over Tom's head,
+and trilled out her imitations of her neighbors in a rapture of
+enjoyment; then a shrill jay swept down, a flash of blue flame, and
+stopped on a twig almost within the boy's reach, cocked his head to one
+side and eyed the strangers with a consuming curiosity; a gray squirrel
+and a big fellow of the "fox" kind came skurrying along, sitting up at
+intervals to inspect and chatter at the boys, for the wild things had
+probably never seen a human being before and scarcely knew whether to
+be afraid or not. All Nature was wide awake and stirring, now; long
+lances of sunlight pierced down through the dense foliage far and near,
+and a few butterflies came fluttering upon the scene.
+
+Tom stirred up the other pirates and they all clattered away with a
+shout, and in a minute or two were stripped and chasing after and
+tumbling over each other in the shallow limpid water of the white
+sandbar. They felt no longing for the little village sleeping in the
+distance beyond the majestic waste of water. A vagrant current or a
+slight rise in the river had carried off their raft, but this only
+gratified them, since its going was something like burning the bridge
+between them and civilization.
+
+They came back to camp wonderfully refreshed, glad-hearted, and
+ravenous; and they soon had the camp-fire blazing up again. Huck found
+a spring of clear cold water close by, and the boys made cups of broad
+oak or hickory leaves, and felt that water, sweetened with such a
+wildwood charm as that, would be a good enough substitute for coffee.
+While Joe was slicing bacon for breakfast, Tom and Huck asked him to
+hold on a minute; they stepped to a promising nook in the river-bank
+and threw in their lines; almost immediately they had reward. Joe had
+not had time to get impatient before they were back again with some
+handsome bass, a couple of sun-perch and a small catfish--provisions
+enough for quite a family. They fried the fish with the bacon, and were
+astonished; for no fish had ever seemed so delicious before. They did
+not know that the quicker a fresh-water fish is on the fire after he is
+caught the better he is; and they reflected little upon what a sauce
+open-air sleeping, open-air exercise, bathing, and a large ingredient
+of hunger make, too.
+
+They lay around in the shade, after breakfast, while Huck had a smoke,
+and then went off through the woods on an exploring expedition. They
+tramped gayly along, over decaying logs, through tangled underbrush,
+among solemn monarchs of the forest, hung from their crowns to the
+ground with a drooping regalia of grape-vines. Now and then they came
+upon snug nooks carpeted with grass and jeweled with flowers.
+
+They found plenty of things to be delighted with, but nothing to be
+astonished at. They discovered that the island was about three miles
+long and a quarter of a mile wide, and that the shore it lay closest to
+was only separated from it by a narrow channel hardly two hundred yards
+wide. They took a swim about every hour, so it was close upon the
+middle of the afternoon when they got back to camp. They were too
+hungry to stop to fish, but they fared sumptuously upon cold ham, and
+then threw themselves down in the shade to talk. But the talk soon
+began to drag, and then died. The stillness, the solemnity that brooded
+in the woods, and the sense of loneliness, began to tell upon the
+spirits of the boys. They fell to thinking. A sort of undefined longing
+crept upon them. This took dim shape, presently--it was budding
+homesickness. Even Finn the Red-Handed was dreaming of his doorsteps
+and empty hogsheads. But they were all ashamed of their weakness, and
+none was brave enough to speak his thought.
+
+For some time, now, the boys had been dully conscious of a peculiar
+sound in the distance, just as one sometimes is of the ticking of a
+clock which he takes no distinct note of. But now this mysterious sound
+became more pronounced, and forced a recognition. The boys started,
+glanced at each other, and then each assumed a listening attitude.
+There was a long silence, profound and unbroken; then a deep, sullen
+boom came floating down out of the distance.
+
+"What is it!" exclaimed Joe, under his breath.
+
+"I wonder," said Tom in a whisper.
+
+"'Tain't thunder," said Huckleberry, in an awed tone, "becuz thunder--"
+
+"Hark!" said Tom. "Listen--don't talk."
+
+They waited a time that seemed an age, and then the same muffled boom
+troubled the solemn hush.
+
+"Let's go and see."
+
+They sprang to their feet and hurried to the shore toward the town.
+They parted the bushes on the bank and peered out over the water. The
+little steam ferryboat was about a mile below the village, drifting
+with the current. Her broad deck seemed crowded with people. There were
+a great many skiffs rowing about or floating with the stream in the
+neighborhood of the ferryboat, but the boys could not determine what
+the men in them were doing. Presently a great jet of white smoke burst
+from the ferryboat's side, and as it expanded and rose in a lazy cloud,
+that same dull throb of sound was borne to the listeners again.
+
+"I know now!" exclaimed Tom; "somebody's drownded!"
+
+"That's it!" said Huck; "they done that last summer, when Bill Turner
+got drownded; they shoot a cannon over the water, and that makes him
+come up to the top. Yes, and they take loaves of bread and put
+quicksilver in 'em and set 'em afloat, and wherever there's anybody
+that's drownded, they'll float right there and stop."
+
+"Yes, I've heard about that," said Joe. "I wonder what makes the bread
+do that."
+
+"Oh, it ain't the bread, so much," said Tom; "I reckon it's mostly
+what they SAY over it before they start it out."
+
+"But they don't say anything over it," said Huck. "I've seen 'em and
+they don't."
+
+"Well, that's funny," said Tom. "But maybe they say it to themselves.
+Of COURSE they do. Anybody might know that."
+
+The other boys agreed that there was reason in what Tom said, because
+an ignorant lump of bread, uninstructed by an incantation, could not be
+expected to act very intelligently when set upon an errand of such
+gravity.
+
+"By jings, I wish I was over there, now," said Joe.
+
+"I do too" said Huck "I'd give heaps to know who it is."
+
+The boys still listened and watched. Presently a revealing thought
+flashed through Tom's mind, and he exclaimed:
+
+"Boys, I know who's drownded--it's us!"
+
+They felt like heroes in an instant. Here was a gorgeous triumph; they
+were missed; they were mourned; hearts were breaking on their account;
+tears were being shed; accusing memories of unkindness to these poor
+lost lads were rising up, and unavailing regrets and remorse were being
+indulged; and best of all, the departed were the talk of the whole
+town, and the envy of all the boys, as far as this dazzling notoriety
+was concerned. This was fine. It was worth while to be a pirate, after
+all.
+
+As twilight drew on, the ferryboat went back to her accustomed
+business and the skiffs disappeared. The pirates returned to camp. They
+were jubilant with vanity over their new grandeur and the illustrious
+trouble they were making. They caught fish, cooked supper and ate it,
+and then fell to guessing at what the village was thinking and saying
+about them; and the pictures they drew of the public distress on their
+account were gratifying to look upon--from their point of view. But
+when the shadows of night closed them in, they gradually ceased to
+talk, and sat gazing into the fire, with their minds evidently
+wandering elsewhere. The excitement was gone, now, and Tom and Joe
+could not keep back thoughts of certain persons at home who were not
+enjoying this fine frolic as much as they were. Misgivings came; they
+grew troubled and unhappy; a sigh or two escaped, unawares. By and by
+Joe timidly ventured upon a roundabout "feeler" as to how the others
+might look upon a return to civilization--not right now, but--
+
+Tom withered him with derision! Huck, being uncommitted as yet, joined
+in with Tom, and the waverer quickly "explained," and was glad to get
+out of the scrape with as little taint of chicken-hearted homesickness
+clinging to his garments as he could. Mutiny was effectually laid to
+rest for the moment.
+
+As the night deepened, Huck began to nod, and presently to snore. Joe
+followed next. Tom lay upon his elbow motionless, for some time,
+watching the two intently. At last he got up cautiously, on his knees,
+and went searching among the grass and the flickering reflections flung
+by the camp-fire. He picked up and inspected several large
+semi-cylinders of the thin white bark of a sycamore, and finally chose
+two which seemed to suit him. Then he knelt by the fire and painfully
+wrote something upon each of these with his "red keel"; one he rolled up
+and put in his jacket pocket, and the other he put in Joe's hat and
+removed it to a little distance from the owner. And he also put into the
+hat certain schoolboy treasures of almost inestimable value--among them
+a lump of chalk, an India-rubber ball, three fishhooks, and one of that
+kind of marbles known as a "sure 'nough crystal." Then he tiptoed his
+way cautiously among the trees till he felt that he was out of hearing,
+and straightway broke into a keen run in the direction of the sandbar.
+
+
+
+CHAPTER XV
+
+A FEW minutes later Tom was in the shoal water of the bar, wading
+toward the Illinois shore. Before the depth reached his middle he was
+half-way over; the current would permit no more wading, now, so he
+struck out confidently to swim the remaining hundred yards. He swam
+quartering upstream, but still was swept downward rather faster than he
+had expected. However, he reached the shore finally, and drifted along
+till he found a low place and drew himself out. He put his hand on his
+jacket pocket, found his piece of bark safe, and then struck through
+the woods, following the shore, with streaming garments. Shortly before
+ten o'clock he came out into an open place opposite the village, and
+saw the ferryboat lying in the shadow of the trees and the high bank.
+Everything was quiet under the blinking stars. He crept down the bank,
+watching with all his eyes, slipped into the water, swam three or four
+strokes and climbed into the skiff that did "yawl" duty at the boat's
+stern. He laid himself down under the thwarts and waited, panting.
+
+Presently the cracked bell tapped and a voice gave the order to "cast
+off." A minute or two later the skiff's head was standing high up,
+against the boat's swell, and the voyage was begun. Tom felt happy in
+his success, for he knew it was the boat's last trip for the night. At
+the end of a long twelve or fifteen minutes the wheels stopped, and Tom
+slipped overboard and swam ashore in the dusk, landing fifty yards
+downstream, out of danger of possible stragglers.
+
+He flew along unfrequented alleys, and shortly found himself at his
+aunt's back fence. He climbed over, approached the "ell," and looked in
+at the sitting-room window, for a light was burning there. There sat
+Aunt Polly, Sid, Mary, and Joe Harper's mother, grouped together,
+talking. They were by the bed, and the bed was between them and the
+door. Tom went to the door and began to softly lift the latch; then he
+pressed gently and the door yielded a crack; he continued pushing
+cautiously, and quaking every time it creaked, till he judged he might
+squeeze through on his knees; so he put his head through and began,
+warily.
+
+"What makes the candle blow so?" said Aunt Polly. Tom hurried up.
+"Why, that door's open, I believe. Why, of course it is. No end of
+strange things now. Go 'long and shut it, Sid."
+
+Tom disappeared under the bed just in time. He lay and "breathed"
+himself for a time, and then crept to where he could almost touch his
+aunt's foot.
+
+"But as I was saying," said Aunt Polly, "he warn't BAD, so to say
+--only mischEEvous. Only just giddy, and harum-scarum, you know. He
+warn't any more responsible than a colt. HE never meant any harm, and
+he was the best-hearted boy that ever was"--and she began to cry.
+
+"It was just so with my Joe--always full of his devilment, and up to
+every kind of mischief, but he was just as unselfish and kind as he
+could be--and laws bless me, to think I went and whipped him for taking
+that cream, never once recollecting that I throwed it out myself
+because it was sour, and I never to see him again in this world, never,
+never, never, poor abused boy!" And Mrs. Harper sobbed as if her heart
+would break.
+
+"I hope Tom's better off where he is," said Sid, "but if he'd been
+better in some ways--"
+
+"SID!" Tom felt the glare of the old lady's eye, though he could not
+see it. "Not a word against my Tom, now that he's gone! God'll take
+care of HIM--never you trouble YOURself, sir! Oh, Mrs. Harper, I don't
+know how to give him up! I don't know how to give him up! He was such a
+comfort to me, although he tormented my old heart out of me, 'most."
+
+"The Lord giveth and the Lord hath taken away--Blessed be the name of
+the Lord! But it's so hard--Oh, it's so hard! Only last Saturday my
+Joe busted a firecracker right under my nose and I knocked him
+sprawling. Little did I know then, how soon--Oh, if it was to do over
+again I'd hug him and bless him for it."
+
+"Yes, yes, yes, I know just how you feel, Mrs. Harper, I know just
+exactly how you feel. No longer ago than yesterday noon, my Tom took
+and filled the cat full of Pain-killer, and I did think the cretur
+would tear the house down. And God forgive me, I cracked Tom's head
+with my thimble, poor boy, poor dead boy. But he's out of all his
+troubles now. And the last words I ever heard him say was to reproach--"
+
+But this memory was too much for the old lady, and she broke entirely
+down. Tom was snuffling, now, himself--and more in pity of himself than
+anybody else. He could hear Mary crying, and putting in a kindly word
+for him from time to time. He began to have a nobler opinion of himself
+than ever before. Still, he was sufficiently touched by his aunt's
+grief to long to rush out from under the bed and overwhelm her with
+joy--and the theatrical gorgeousness of the thing appealed strongly to
+his nature, too, but he resisted and lay still.
+
+He went on listening, and gathered by odds and ends that it was
+conjectured at first that the boys had got drowned while taking a swim;
+then the small raft had been missed; next, certain boys said the
+missing lads had promised that the village should "hear something"
+soon; the wise-heads had "put this and that together" and decided that
+the lads had gone off on that raft and would turn up at the next town
+below, presently; but toward noon the raft had been found, lodged
+against the Missouri shore some five or six miles below the village
+--and then hope perished; they must be drowned, else hunger would have
+driven them home by nightfall if not sooner. It was believed that the
+search for the bodies had been a fruitless effort merely because the
+drowning must have occurred in mid-channel, since the boys, being good
+swimmers, would otherwise have escaped to shore. This was Wednesday
+night. If the bodies continued missing until Sunday, all hope would be
+given over, and the funerals would be preached on that morning. Tom
+shuddered.
+
+Mrs. Harper gave a sobbing good-night and turned to go. Then with a
+mutual impulse the two bereaved women flung themselves into each
+other's arms and had a good, consoling cry, and then parted. Aunt Polly
+was tender far beyond her wont, in her good-night to Sid and Mary. Sid
+snuffled a bit and Mary went off crying with all her heart.
+
+Aunt Polly knelt down and prayed for Tom so touchingly, so
+appealingly, and with such measureless love in her words and her old
+trembling voice, that he was weltering in tears again, long before she
+was through.
+
+He had to keep still long after she went to bed, for she kept making
+broken-hearted ejaculations from time to time, tossing unrestfully, and
+turning over. But at last she was still, only moaning a little in her
+sleep. Now the boy stole out, rose gradually by the bedside, shaded the
+candle-light with his hand, and stood regarding her. His heart was full
+of pity for her. He took out his sycamore scroll and placed it by the
+candle. But something occurred to him, and he lingered considering. His
+face lighted with a happy solution of his thought; he put the bark
+hastily in his pocket. Then he bent over and kissed the faded lips, and
+straightway made his stealthy exit, latching the door behind him.
+
+He threaded his way back to the ferry landing, found nobody at large
+there, and walked boldly on board the boat, for he knew she was
+tenantless except that there was a watchman, who always turned in and
+slept like a graven image. He untied the skiff at the stern, slipped
+into it, and was soon rowing cautiously upstream. When he had pulled a
+mile above the village, he started quartering across and bent himself
+stoutly to his work. He hit the landing on the other side neatly, for
+this was a familiar bit of work to him. He was moved to capture the
+skiff, arguing that it might be considered a ship and therefore
+legitimate prey for a pirate, but he knew a thorough search would be
+made for it and that might end in revelations. So he stepped ashore and
+entered the woods.
+
+He sat down and took a long rest, torturing himself meanwhile to keep
+awake, and then started warily down the home-stretch. The night was far
+spent. It was broad daylight before he found himself fairly abreast the
+island bar. He rested again until the sun was well up and gilding the
+great river with its splendor, and then he plunged into the stream. A
+little later he paused, dripping, upon the threshold of the camp, and
+heard Joe say:
+
+"No, Tom's true-blue, Huck, and he'll come back. He won't desert. He
+knows that would be a disgrace to a pirate, and Tom's too proud for
+that sort of thing. He's up to something or other. Now I wonder what?"
+
+"Well, the things is ours, anyway, ain't they?"
+
+"Pretty near, but not yet, Huck. The writing says they are if he ain't
+back here to breakfast."
+
+"Which he is!" exclaimed Tom, with fine dramatic effect, stepping
+grandly into camp.
+
+A sumptuous breakfast of bacon and fish was shortly provided, and as
+the boys set to work upon it, Tom recounted (and adorned) his
+adventures. They were a vain and boastful company of heroes when the
+tale was done. Then Tom hid himself away in a shady nook to sleep till
+noon, and the other pirates got ready to fish and explore.
+
+
+
+CHAPTER XVI
+
+AFTER dinner all the gang turned out to hunt for turtle eggs on the
+bar. They went about poking sticks into the sand, and when they found a
+soft place they went down on their knees and dug with their hands.
+Sometimes they would take fifty or sixty eggs out of one hole. They
+were perfectly round white things a trifle smaller than an English
+walnut. They had a famous fried-egg feast that night, and another on
+Friday morning.
+
+After breakfast they went whooping and prancing out on the bar, and
+chased each other round and round, shedding clothes as they went, until
+they were naked, and then continued the frolic far away up the shoal
+water of the bar, against the stiff current, which latter tripped their
+legs from under them from time to time and greatly increased the fun.
+And now and then they stooped in a group and splashed water in each
+other's faces with their palms, gradually approaching each other, with
+averted faces to avoid the strangling sprays, and finally gripping and
+struggling till the best man ducked his neighbor, and then they all
+went under in a tangle of white legs and arms and came up blowing,
+sputtering, laughing, and gasping for breath at one and the same time.
+
+When they were well exhausted, they would run out and sprawl on the
+dry, hot sand, and lie there and cover themselves up with it, and by
+and by break for the water again and go through the original
+performance once more. Finally it occurred to them that their naked
+skin represented flesh-colored "tights" very fairly; so they drew a
+ring in the sand and had a circus--with three clowns in it, for none
+would yield this proudest post to his neighbor.
+
+Next they got their marbles and played "knucks" and "ring-taw" and
+"keeps" till that amusement grew stale. Then Joe and Huck had another
+swim, but Tom would not venture, because he found that in kicking off
+his trousers he had kicked his string of rattlesnake rattles off his
+ankle, and he wondered how he had escaped cramp so long without the
+protection of this mysterious charm. He did not venture again until he
+had found it, and by that time the other boys were tired and ready to
+rest. They gradually wandered apart, dropped into the "dumps," and fell
+to gazing longingly across the wide river to where the village lay
+drowsing in the sun. Tom found himself writing "BECKY" in the sand with
+his big toe; he scratched it out, and was angry with himself for his
+weakness. But he wrote it again, nevertheless; he could not help it. He
+erased it once more and then took himself out of temptation by driving
+the other boys together and joining them.
+
+But Joe's spirits had gone down almost beyond resurrection. He was so
+homesick that he could hardly endure the misery of it. The tears lay
+very near the surface. Huck was melancholy, too. Tom was downhearted,
+but tried hard not to show it. He had a secret which he was not ready
+to tell, yet, but if this mutinous depression was not broken up soon,
+he would have to bring it out. He said, with a great show of
+cheerfulness:
+
+"I bet there's been pirates on this island before, boys. We'll explore
+it again. They've hid treasures here somewhere. How'd you feel to light
+on a rotten chest full of gold and silver--hey?"
+
+But it roused only faint enthusiasm, which faded out, with no reply.
+Tom tried one or two other seductions; but they failed, too. It was
+discouraging work. Joe sat poking up the sand with a stick and looking
+very gloomy. Finally he said:
+
+"Oh, boys, let's give it up. I want to go home. It's so lonesome."
+
+"Oh no, Joe, you'll feel better by and by," said Tom. "Just think of
+the fishing that's here."
+
+"I don't care for fishing. I want to go home."
+
+"But, Joe, there ain't such another swimming-place anywhere."
+
+"Swimming's no good. I don't seem to care for it, somehow, when there
+ain't anybody to say I sha'n't go in. I mean to go home."
+
+"Oh, shucks! Baby! You want to see your mother, I reckon."
+
+"Yes, I DO want to see my mother--and you would, too, if you had one.
+I ain't any more baby than you are." And Joe snuffled a little.
+
+"Well, we'll let the cry-baby go home to his mother, won't we, Huck?
+Poor thing--does it want to see its mother? And so it shall. You like
+it here, don't you, Huck? We'll stay, won't we?"
+
+Huck said, "Y-e-s"--without any heart in it.
+
+"I'll never speak to you again as long as I live," said Joe, rising.
+"There now!" And he moved moodily away and began to dress himself.
+
+"Who cares!" said Tom. "Nobody wants you to. Go 'long home and get
+laughed at. Oh, you're a nice pirate. Huck and me ain't cry-babies.
+We'll stay, won't we, Huck? Let him go if he wants to. I reckon we can
+get along without him, per'aps."
+
+But Tom was uneasy, nevertheless, and was alarmed to see Joe go
+sullenly on with his dressing. And then it was discomforting to see
+Huck eying Joe's preparations so wistfully, and keeping up such an
+ominous silence. Presently, without a parting word, Joe began to wade
+off toward the Illinois shore. Tom's heart began to sink. He glanced at
+Huck. Huck could not bear the look, and dropped his eyes. Then he said:
+
+"I want to go, too, Tom. It was getting so lonesome anyway, and now
+it'll be worse. Let's us go, too, Tom."
+
+"I won't! You can all go, if you want to. I mean to stay."
+
+"Tom, I better go."
+
+"Well, go 'long--who's hendering you."
+
+Huck began to pick up his scattered clothes. He said:
+
+"Tom, I wisht you'd come, too. Now you think it over. We'll wait for
+you when we get to shore."
+
+"Well, you'll wait a blame long time, that's all."
+
+Huck started sorrowfully away, and Tom stood looking after him, with a
+strong desire tugging at his heart to yield his pride and go along too.
+He hoped the boys would stop, but they still waded slowly on. It
+suddenly dawned on Tom that it was become very lonely and still. He
+made one final struggle with his pride, and then darted after his
+comrades, yelling:
+
+"Wait! Wait! I want to tell you something!"
+
+They presently stopped and turned around. When he got to where they
+were, he began unfolding his secret, and they listened moodily till at
+last they saw the "point" he was driving at, and then they set up a
+war-whoop of applause and said it was "splendid!" and said if he had
+told them at first, they wouldn't have started away. He made a plausible
+excuse; but his real reason had been the fear that not even the secret
+would keep them with him any very great length of time, and so he had
+meant to hold it in reserve as a last seduction.
+
+The lads came gayly back and went at their sports again with a will,
+chattering all the time about Tom's stupendous plan and admiring the
+genius of it. After a dainty egg and fish dinner, Tom said he wanted to
+learn to smoke, now. Joe caught at the idea and said he would like to
+try, too. So Huck made pipes and filled them. These novices had never
+smoked anything before but cigars made of grape-vine, and they "bit"
+the tongue, and were not considered manly anyway.
+
+Now they stretched themselves out on their elbows and began to puff,
+charily, and with slender confidence. The smoke had an unpleasant
+taste, and they gagged a little, but Tom said:
+
+"Why, it's just as easy! If I'd a knowed this was all, I'd a learnt
+long ago."
+
+"So would I," said Joe. "It's just nothing."
+
+"Why, many a time I've looked at people smoking, and thought well I
+wish I could do that; but I never thought I could," said Tom.
+
+"That's just the way with me, hain't it, Huck? You've heard me talk
+just that way--haven't you, Huck? I'll leave it to Huck if I haven't."
+
+"Yes--heaps of times," said Huck.
+
+"Well, I have too," said Tom; "oh, hundreds of times. Once down by the
+slaughter-house. Don't you remember, Huck? Bob Tanner was there, and
+Johnny Miller, and Jeff Thatcher, when I said it. Don't you remember,
+Huck, 'bout me saying that?"
+
+"Yes, that's so," said Huck. "That was the day after I lost a white
+alley. No, 'twas the day before."
+
+"There--I told you so," said Tom. "Huck recollects it."
+
+"I bleeve I could smoke this pipe all day," said Joe. "I don't feel
+sick."
+
+"Neither do I," said Tom. "I could smoke it all day. But I bet you
+Jeff Thatcher couldn't."
+
+"Jeff Thatcher! Why, he'd keel over just with two draws. Just let him
+try it once. HE'D see!"
+
+"I bet he would. And Johnny Miller--I wish could see Johnny Miller
+tackle it once."
+
+"Oh, don't I!" said Joe. "Why, I bet you Johnny Miller couldn't any
+more do this than nothing. Just one little snifter would fetch HIM."
+
+"'Deed it would, Joe. Say--I wish the boys could see us now."
+
+"So do I."
+
+"Say--boys, don't say anything about it, and some time when they're
+around, I'll come up to you and say, 'Joe, got a pipe? I want a smoke.'
+And you'll say, kind of careless like, as if it warn't anything, you'll
+say, 'Yes, I got my OLD pipe, and another one, but my tobacker ain't
+very good.' And I'll say, 'Oh, that's all right, if it's STRONG
+enough.' And then you'll out with the pipes, and we'll light up just as
+ca'm, and then just see 'em look!"
+
+"By jings, that'll be gay, Tom! I wish it was NOW!"
+
+"So do I! And when we tell 'em we learned when we was off pirating,
+won't they wish they'd been along?"
+
+"Oh, I reckon not! I'll just BET they will!"
+
+So the talk ran on. But presently it began to flag a trifle, and grow
+disjointed. The silences widened; the expectoration marvellously
+increased. Every pore inside the boys' cheeks became a spouting
+fountain; they could scarcely bail out the cellars under their tongues
+fast enough to prevent an inundation; little overflowings down their
+throats occurred in spite of all they could do, and sudden retchings
+followed every time. Both boys were looking very pale and miserable,
+now. Joe's pipe dropped from his nerveless fingers. Tom's followed.
+Both fountains were going furiously and both pumps bailing with might
+and main. Joe said feebly:
+
+"I've lost my knife. I reckon I better go and find it."
+
+Tom said, with quivering lips and halting utterance:
+
+"I'll help you. You go over that way and I'll hunt around by the
+spring. No, you needn't come, Huck--we can find it."
+
+So Huck sat down again, and waited an hour. Then he found it lonesome,
+and went to find his comrades. They were wide apart in the woods, both
+very pale, both fast asleep. But something informed him that if they
+had had any trouble they had got rid of it.
+
+They were not talkative at supper that night. They had a humble look,
+and when Huck prepared his pipe after the meal and was going to prepare
+theirs, they said no, they were not feeling very well--something they
+ate at dinner had disagreed with them.
+
+About midnight Joe awoke, and called the boys. There was a brooding
+oppressiveness in the air that seemed to bode something. The boys
+huddled themselves together and sought the friendly companionship of
+the fire, though the dull dead heat of the breathless atmosphere was
+stifling. They sat still, intent and waiting. The solemn hush
+continued. Beyond the light of the fire everything was swallowed up in
+the blackness of darkness. Presently there came a quivering glow that
+vaguely revealed the foliage for a moment and then vanished. By and by
+another came, a little stronger. Then another. Then a faint moan came
+sighing through the branches of the forest and the boys felt a fleeting
+breath upon their cheeks, and shuddered with the fancy that the Spirit
+of the Night had gone by. There was a pause. Now a weird flash turned
+night into day and showed every little grass-blade, separate and
+distinct, that grew about their feet. And it showed three white,
+startled faces, too. A deep peal of thunder went rolling and tumbling
+down the heavens and lost itself in sullen rumblings in the distance. A
+sweep of chilly air passed by, rustling all the leaves and snowing the
+flaky ashes broadcast about the fire. Another fierce glare lit up the
+forest and an instant crash followed that seemed to rend the tree-tops
+right over the boys' heads. They clung together in terror, in the thick
+gloom that followed. A few big rain-drops fell pattering upon the
+leaves.
+
+"Quick! boys, go for the tent!" exclaimed Tom.
+
+They sprang away, stumbling over roots and among vines in the dark, no
+two plunging in the same direction. A furious blast roared through the
+trees, making everything sing as it went. One blinding flash after
+another came, and peal on peal of deafening thunder. And now a
+drenching rain poured down and the rising hurricane drove it in sheets
+along the ground. The boys cried out to each other, but the roaring
+wind and the booming thunder-blasts drowned their voices utterly.
+However, one by one they straggled in at last and took shelter under
+the tent, cold, scared, and streaming with water; but to have company
+in misery seemed something to be grateful for. They could not talk, the
+old sail flapped so furiously, even if the other noises would have
+allowed them. The tempest rose higher and higher, and presently the
+sail tore loose from its fastenings and went winging away on the blast.
+The boys seized each others' hands and fled, with many tumblings and
+bruises, to the shelter of a great oak that stood upon the river-bank.
+Now the battle was at its highest. Under the ceaseless conflagration of
+lightning that flamed in the skies, everything below stood out in
+clean-cut and shadowless distinctness: the bending trees, the billowy
+river, white with foam, the driving spray of spume-flakes, the dim
+outlines of the high bluffs on the other side, glimpsed through the
+drifting cloud-rack and the slanting veil of rain. Every little while
+some giant tree yielded the fight and fell crashing through the younger
+growth; and the unflagging thunder-peals came now in ear-splitting
+explosive bursts, keen and sharp, and unspeakably appalling. The storm
+culminated in one matchless effort that seemed likely to tear the island
+to pieces, burn it up, drown it to the tree-tops, blow it away, and
+deafen every creature in it, all at one and the same moment. It was a
+wild night for homeless young heads to be out in.
+
+But at last the battle was done, and the forces retired with weaker
+and weaker threatenings and grumblings, and peace resumed her sway. The
+boys went back to camp, a good deal awed; but they found there was
+still something to be thankful for, because the great sycamore, the
+shelter of their beds, was a ruin, now, blasted by the lightnings, and
+they were not under it when the catastrophe happened.
+
+Everything in camp was drenched, the camp-fire as well; for they were
+but heedless lads, like their generation, and had made no provision
+against rain. Here was matter for dismay, for they were soaked through
+and chilled. They were eloquent in their distress; but they presently
+discovered that the fire had eaten so far up under the great log it had
+been built against (where it curved upward and separated itself from
+the ground), that a handbreadth or so of it had escaped wetting; so
+they patiently wrought until, with shreds and bark gathered from the
+under sides of sheltered logs, they coaxed the fire to burn again. Then
+they piled on great dead boughs till they had a roaring furnace, and
+were glad-hearted once more. They dried their boiled ham and had a
+feast, and after that they sat by the fire and expanded and glorified
+their midnight adventure until morning, for there was not a dry spot to
+sleep on, anywhere around.
+
+As the sun began to steal in upon the boys, drowsiness came over them,
+and they went out on the sandbar and lay down to sleep. They got
+scorched out by and by, and drearily set about getting breakfast. After
+the meal they felt rusty, and stiff-jointed, and a little homesick once
+more. Tom saw the signs, and fell to cheering up the pirates as well as
+he could. But they cared nothing for marbles, or circus, or swimming,
+or anything. He reminded them of the imposing secret, and raised a ray
+of cheer. While it lasted, he got them interested in a new device. This
+was to knock off being pirates, for a while, and be Indians for a
+change. They were attracted by this idea; so it was not long before
+they were stripped, and striped from head to heel with black mud, like
+so many zebras--all of them chiefs, of course--and then they went
+tearing through the woods to attack an English settlement.
+
+By and by they separated into three hostile tribes, and darted upon
+each other from ambush with dreadful war-whoops, and killed and scalped
+each other by thousands. It was a gory day. Consequently it was an
+extremely satisfactory one.
+
+They assembled in camp toward supper-time, hungry and happy; but now a
+difficulty arose--hostile Indians could not break the bread of
+hospitality together without first making peace, and this was a simple
+impossibility without smoking a pipe of peace. There was no other
+process that ever they had heard of. Two of the savages almost wished
+they had remained pirates. However, there was no other way; so with
+such show of cheerfulness as they could muster they called for the pipe
+and took their whiff as it passed, in due form.
+
+And behold, they were glad they had gone into savagery, for they had
+gained something; they found that they could now smoke a little without
+having to go and hunt for a lost knife; they did not get sick enough to
+be seriously uncomfortable. They were not likely to fool away this high
+promise for lack of effort. No, they practised cautiously, after
+supper, with right fair success, and so they spent a jubilant evening.
+They were prouder and happier in their new acquirement than they would
+have been in the scalping and skinning of the Six Nations. We will
+leave them to smoke and chatter and brag, since we have no further use
+for them at present.
+
+
+
+CHAPTER XVII
+
+BUT there was no hilarity in the little town that same tranquil
+Saturday afternoon. The Harpers, and Aunt Polly's family, were being
+put into mourning, with great grief and many tears. An unusual quiet
+possessed the village, although it was ordinarily quiet enough, in all
+conscience. The villagers conducted their concerns with an absent air,
+and talked little; but they sighed often. The Saturday holiday seemed a
+burden to the children. They had no heart in their sports, and
+gradually gave them up.
+
+In the afternoon Becky Thatcher found herself moping about the
+deserted schoolhouse yard, and feeling very melancholy. But she found
+nothing there to comfort her. She soliloquized:
+
+"Oh, if I only had a brass andiron-knob again! But I haven't got
+anything now to remember him by." And she choked back a little sob.
+
+Presently she stopped, and said to herself:
+
+"It was right here. Oh, if it was to do over again, I wouldn't say
+that--I wouldn't say it for the whole world. But he's gone now; I'll
+never, never, never see him any more."
+
+This thought broke her down, and she wandered away, with tears rolling
+down her cheeks. Then quite a group of boys and girls--playmates of
+Tom's and Joe's--came by, and stood looking over the paling fence and
+talking in reverent tones of how Tom did so-and-so the last time they
+saw him, and how Joe said this and that small trifle (pregnant with
+awful prophecy, as they could easily see now!)--and each speaker
+pointed out the exact spot where the lost lads stood at the time, and
+then added something like "and I was a-standing just so--just as I am
+now, and as if you was him--I was as close as that--and he smiled, just
+this way--and then something seemed to go all over me, like--awful, you
+know--and I never thought what it meant, of course, but I can see now!"
+
+Then there was a dispute about who saw the dead boys last in life, and
+many claimed that dismal distinction, and offered evidences, more or
+less tampered with by the witness; and when it was ultimately decided
+who DID see the departed last, and exchanged the last words with them,
+the lucky parties took upon themselves a sort of sacred importance, and
+were gaped at and envied by all the rest. One poor chap, who had no
+other grandeur to offer, said with tolerably manifest pride in the
+remembrance:
+
+"Well, Tom Sawyer he licked me once."
+
+But that bid for glory was a failure. Most of the boys could say that,
+and so that cheapened the distinction too much. The group loitered
+away, still recalling memories of the lost heroes, in awed voices.
+
+When the Sunday-school hour was finished, the next morning, the bell
+began to toll, instead of ringing in the usual way. It was a very still
+Sabbath, and the mournful sound seemed in keeping with the musing hush
+that lay upon nature. The villagers began to gather, loitering a moment
+in the vestibule to converse in whispers about the sad event. But there
+was no whispering in the house; only the funereal rustling of dresses
+as the women gathered to their seats disturbed the silence there. None
+could remember when the little church had been so full before. There
+was finally a waiting pause, an expectant dumbness, and then Aunt Polly
+entered, followed by Sid and Mary, and they by the Harper family, all
+in deep black, and the whole congregation, the old minister as well,
+rose reverently and stood until the mourners were seated in the front
+pew. There was another communing silence, broken at intervals by
+muffled sobs, and then the minister spread his hands abroad and prayed.
+A moving hymn was sung, and the text followed: "I am the Resurrection
+and the Life."
+
+As the service proceeded, the clergyman drew such pictures of the
+graces, the winning ways, and the rare promise of the lost lads that
+every soul there, thinking he recognized these pictures, felt a pang in
+remembering that he had persistently blinded himself to them always
+before, and had as persistently seen only faults and flaws in the poor
+boys. The minister related many a touching incident in the lives of the
+departed, too, which illustrated their sweet, generous natures, and the
+people could easily see, now, how noble and beautiful those episodes
+were, and remembered with grief that at the time they occurred they had
+seemed rank rascalities, well deserving of the cowhide. The
+congregation became more and more moved, as the pathetic tale went on,
+till at last the whole company broke down and joined the weeping
+mourners in a chorus of anguished sobs, the preacher himself giving way
+to his feelings, and crying in the pulpit.
+
+There was a rustle in the gallery, which nobody noticed; a moment
+later the church door creaked; the minister raised his streaming eyes
+above his handkerchief, and stood transfixed! First one and then
+another pair of eyes followed the minister's, and then almost with one
+impulse the congregation rose and stared while the three dead boys came
+marching up the aisle, Tom in the lead, Joe next, and Huck, a ruin of
+drooping rags, sneaking sheepishly in the rear! They had been hid in
+the unused gallery listening to their own funeral sermon!
+
+Aunt Polly, Mary, and the Harpers threw themselves upon their restored
+ones, smothered them with kisses and poured out thanksgivings, while
+poor Huck stood abashed and uncomfortable, not knowing exactly what to
+do or where to hide from so many unwelcoming eyes. He wavered, and
+started to slink away, but Tom seized him and said:
+
+"Aunt Polly, it ain't fair. Somebody's got to be glad to see Huck."
+
+"And so they shall. I'm glad to see him, poor motherless thing!" And
+the loving attentions Aunt Polly lavished upon him were the one thing
+capable of making him more uncomfortable than he was before.
+
+Suddenly the minister shouted at the top of his voice: "Praise God
+from whom all blessings flow--SING!--and put your hearts in it!"
+
+And they did. Old Hundred swelled up with a triumphant burst, and
+while it shook the rafters Tom Sawyer the Pirate looked around upon the
+envying juveniles about him and confessed in his heart that this was
+the proudest moment of his life.
+
+As the "sold" congregation trooped out they said they would almost be
+willing to be made ridiculous again to hear Old Hundred sung like that
+once more.
+
+Tom got more cuffs and kisses that day--according to Aunt Polly's
+varying moods--than he had earned before in a year; and he hardly knew
+which expressed the most gratefulness to God and affection for himself.
+
+
+
+CHAPTER XVIII
+
+THAT was Tom's great secret--the scheme to return home with his
+brother pirates and attend their own funerals. They had paddled over to
+the Missouri shore on a log, at dusk on Saturday, landing five or six
+miles below the village; they had slept in the woods at the edge of the
+town till nearly daylight, and had then crept through back lanes and
+alleys and finished their sleep in the gallery of the church among a
+chaos of invalided benches.
+
+At breakfast, Monday morning, Aunt Polly and Mary were very loving to
+Tom, and very attentive to his wants. There was an unusual amount of
+talk. In the course of it Aunt Polly said:
+
+"Well, I don't say it wasn't a fine joke, Tom, to keep everybody
+suffering 'most a week so you boys had a good time, but it is a pity
+you could be so hard-hearted as to let me suffer so. If you could come
+over on a log to go to your funeral, you could have come over and give
+me a hint some way that you warn't dead, but only run off."
+
+"Yes, you could have done that, Tom," said Mary; "and I believe you
+would if you had thought of it."
+
+"Would you, Tom?" said Aunt Polly, her face lighting wistfully. "Say,
+now, would you, if you'd thought of it?"
+
+"I--well, I don't know. 'Twould 'a' spoiled everything."
+
+"Tom, I hoped you loved me that much," said Aunt Polly, with a grieved
+tone that discomforted the boy. "It would have been something if you'd
+cared enough to THINK of it, even if you didn't DO it."
+
+"Now, auntie, that ain't any harm," pleaded Mary; "it's only Tom's
+giddy way--he is always in such a rush that he never thinks of
+anything."
+
+"More's the pity. Sid would have thought. And Sid would have come and
+DONE it, too. Tom, you'll look back, some day, when it's too late, and
+wish you'd cared a little more for me when it would have cost you so
+little."
+
+"Now, auntie, you know I do care for you," said Tom.
+
+"I'd know it better if you acted more like it."
+
+"I wish now I'd thought," said Tom, with a repentant tone; "but I
+dreamt about you, anyway. That's something, ain't it?"
+
+"It ain't much--a cat does that much--but it's better than nothing.
+What did you dream?"
+
+"Why, Wednesday night I dreamt that you was sitting over there by the
+bed, and Sid was sitting by the woodbox, and Mary next to him."
+
+"Well, so we did. So we always do. I'm glad your dreams could take
+even that much trouble about us."
+
+"And I dreamt that Joe Harper's mother was here."
+
+"Why, she was here! Did you dream any more?"
+
+"Oh, lots. But it's so dim, now."
+
+"Well, try to recollect--can't you?"
+
+"Somehow it seems to me that the wind--the wind blowed the--the--"
+
+"Try harder, Tom! The wind did blow something. Come!"
+
+Tom pressed his fingers on his forehead an anxious minute, and then
+said:
+
+"I've got it now! I've got it now! It blowed the candle!"
+
+"Mercy on us! Go on, Tom--go on!"
+
+"And it seems to me that you said, 'Why, I believe that that door--'"
+
+"Go ON, Tom!"
+
+"Just let me study a moment--just a moment. Oh, yes--you said you
+believed the door was open."
+
+"As I'm sitting here, I did! Didn't I, Mary! Go on!"
+
+"And then--and then--well I won't be certain, but it seems like as if
+you made Sid go and--and--"
+
+"Well? Well? What did I make him do, Tom? What did I make him do?"
+
+"You made him--you--Oh, you made him shut it."
+
+"Well, for the land's sake! I never heard the beat of that in all my
+days! Don't tell ME there ain't anything in dreams, any more. Sereny
+Harper shall know of this before I'm an hour older. I'd like to see her
+get around THIS with her rubbage 'bout superstition. Go on, Tom!"
+
+"Oh, it's all getting just as bright as day, now. Next you said I
+warn't BAD, only mischeevous and harum-scarum, and not any more
+responsible than--than--I think it was a colt, or something."
+
+"And so it was! Well, goodness gracious! Go on, Tom!"
+
+"And then you began to cry."
+
+"So I did. So I did. Not the first time, neither. And then--"
+
+"Then Mrs. Harper she began to cry, and said Joe was just the same,
+and she wished she hadn't whipped him for taking cream when she'd
+throwed it out her own self--"
+
+"Tom! The sperrit was upon you! You was a prophesying--that's what you
+was doing! Land alive, go on, Tom!"
+
+"Then Sid he said--he said--"
+
+"I don't think I said anything," said Sid.
+
+"Yes you did, Sid," said Mary.
+
+"Shut your heads and let Tom go on! What did he say, Tom?"
+
+"He said--I THINK he said he hoped I was better off where I was gone
+to, but if I'd been better sometimes--"
+
+"THERE, d'you hear that! It was his very words!"
+
+"And you shut him up sharp."
+
+"I lay I did! There must 'a' been an angel there. There WAS an angel
+there, somewheres!"
+
+"And Mrs. Harper told about Joe scaring her with a firecracker, and
+you told about Peter and the Painkiller--"
+
+"Just as true as I live!"
+
+"And then there was a whole lot of talk 'bout dragging the river for
+us, and 'bout having the funeral Sunday, and then you and old Miss
+Harper hugged and cried, and she went."
+
+"It happened just so! It happened just so, as sure as I'm a-sitting in
+these very tracks. Tom, you couldn't told it more like if you'd 'a'
+seen it! And then what? Go on, Tom!"
+
+"Then I thought you prayed for me--and I could see you and hear every
+word you said. And you went to bed, and I was so sorry that I took and
+wrote on a piece of sycamore bark, 'We ain't dead--we are only off
+being pirates,' and put it on the table by the candle; and then you
+looked so good, laying there asleep, that I thought I went and leaned
+over and kissed you on the lips."
+
+"Did you, Tom, DID you! I just forgive you everything for that!" And
+she seized the boy in a crushing embrace that made him feel like the
+guiltiest of villains.
+
+"It was very kind, even though it was only a--dream," Sid soliloquized
+just audibly.
+
+"Shut up, Sid! A body does just the same in a dream as he'd do if he
+was awake. Here's a big Milum apple I've been saving for you, Tom, if
+you was ever found again--now go 'long to school. I'm thankful to the
+good God and Father of us all I've got you back, that's long-suffering
+and merciful to them that believe on Him and keep His word, though
+goodness knows I'm unworthy of it, but if only the worthy ones got His
+blessings and had His hand to help them over the rough places, there's
+few enough would smile here or ever enter into His rest when the long
+night comes. Go 'long Sid, Mary, Tom--take yourselves off--you've
+hendered me long enough."
+
+The children left for school, and the old lady to call on Mrs. Harper
+and vanquish her realism with Tom's marvellous dream. Sid had better
+judgment than to utter the thought that was in his mind as he left the
+house. It was this: "Pretty thin--as long a dream as that, without any
+mistakes in it!"
+
+What a hero Tom was become, now! He did not go skipping and prancing,
+but moved with a dignified swagger as became a pirate who felt that the
+public eye was on him. And indeed it was; he tried not to seem to see
+the looks or hear the remarks as he passed along, but they were food
+and drink to him. Smaller boys than himself flocked at his heels, as
+proud to be seen with him, and tolerated by him, as if he had been the
+drummer at the head of a procession or the elephant leading a menagerie
+into town. Boys of his own size pretended not to know he had been away
+at all; but they were consuming with envy, nevertheless. They would
+have given anything to have that swarthy suntanned skin of his, and his
+glittering notoriety; and Tom would not have parted with either for a
+circus.
+
+At school the children made so much of him and of Joe, and delivered
+such eloquent admiration from their eyes, that the two heroes were not
+long in becoming insufferably "stuck-up." They began to tell their
+adventures to hungry listeners--but they only began; it was not a thing
+likely to have an end, with imaginations like theirs to furnish
+material. And finally, when they got out their pipes and went serenely
+puffing around, the very summit of glory was reached.
+
+Tom decided that he could be independent of Becky Thatcher now. Glory
+was sufficient. He would live for glory. Now that he was distinguished,
+maybe she would be wanting to "make up." Well, let her--she should see
+that he could be as indifferent as some other people. Presently she
+arrived. Tom pretended not to see her. He moved away and joined a group
+of boys and girls and began to talk. Soon he observed that she was
+tripping gayly back and forth with flushed face and dancing eyes,
+pretending to be busy chasing schoolmates, and screaming with laughter
+when she made a capture; but he noticed that she always made her
+captures in his vicinity, and that she seemed to cast a conscious eye
+in his direction at such times, too. It gratified all the vicious
+vanity that was in him; and so, instead of winning him, it only "set
+him up" the more and made him the more diligent to avoid betraying that
+he knew she was about. Presently she gave over skylarking, and moved
+irresolutely about, sighing once or twice and glancing furtively and
+wistfully toward Tom. Then she observed that now Tom was talking more
+particularly to Amy Lawrence than to any one else. She felt a sharp
+pang and grew disturbed and uneasy at once. She tried to go away, but
+her feet were treacherous, and carried her to the group instead. She
+said to a girl almost at Tom's elbow--with sham vivacity:
+
+"Why, Mary Austin! you bad girl, why didn't you come to Sunday-school?"
+
+"I did come--didn't you see me?"
+
+"Why, no! Did you? Where did you sit?"
+
+"I was in Miss Peters' class, where I always go. I saw YOU."
+
+"Did you? Why, it's funny I didn't see you. I wanted to tell you about
+the picnic."
+
+"Oh, that's jolly. Who's going to give it?"
+
+"My ma's going to let me have one."
+
+"Oh, goody; I hope she'll let ME come."
+
+"Well, she will. The picnic's for me. She'll let anybody come that I
+want, and I want you."
+
+"That's ever so nice. When is it going to be?"
+
+"By and by. Maybe about vacation."
+
+"Oh, won't it be fun! You going to have all the girls and boys?"
+
+"Yes, every one that's friends to me--or wants to be"; and she glanced
+ever so furtively at Tom, but he talked right along to Amy Lawrence
+about the terrible storm on the island, and how the lightning tore the
+great sycamore tree "all to flinders" while he was "standing within
+three feet of it."
+
+"Oh, may I come?" said Grace Miller.
+
+"Yes."
+
+"And me?" said Sally Rogers.
+
+"Yes."
+
+"And me, too?" said Susy Harper. "And Joe?"
+
+"Yes."
+
+And so on, with clapping of joyful hands till all the group had begged
+for invitations but Tom and Amy. Then Tom turned coolly away, still
+talking, and took Amy with him. Becky's lips trembled and the tears
+came to her eyes; she hid these signs with a forced gayety and went on
+chattering, but the life had gone out of the picnic, now, and out of
+everything else; she got away as soon as she could and hid herself and
+had what her sex call "a good cry." Then she sat moody, with wounded
+pride, till the bell rang. She roused up, now, with a vindictive cast
+in her eye, and gave her plaited tails a shake and said she knew what
+SHE'D do.
+
+At recess Tom continued his flirtation with Amy with jubilant
+self-satisfaction. And he kept drifting about to find Becky and lacerate
+her with the performance. At last he spied her, but there was a sudden
+falling of his mercury. She was sitting cosily on a little bench behind
+the schoolhouse looking at a picture-book with Alfred Temple--and so
+absorbed were they, and their heads so close together over the book,
+that they did not seem to be conscious of anything in the world besides.
+Jealousy ran red-hot through Tom's veins. He began to hate himself for
+throwing away the chance Becky had offered for a reconciliation. He
+called himself a fool, and all the hard names he could think of. He
+wanted to cry with vexation. Amy chatted happily along, as they walked,
+for her heart was singing, but Tom's tongue had lost its function. He
+did not hear what Amy was saying, and whenever she paused expectantly he
+could only stammer an awkward assent, which was as often misplaced as
+otherwise. He kept drifting to the rear of the schoolhouse, again and
+again, to sear his eyeballs with the hateful spectacle there. He could
+not help it. And it maddened him to see, as he thought he saw, that
+Becky Thatcher never once suspected that he was even in the land of the
+living. But she did see, nevertheless; and she knew she was winning her
+fight, too, and was glad to see him suffer as she had suffered.
+
+Amy's happy prattle became intolerable. Tom hinted at things he had to
+attend to; things that must be done; and time was fleeting. But in
+vain--the girl chirped on. Tom thought, "Oh, hang her, ain't I ever
+going to get rid of her?" At last he must be attending to those
+things--and she said artlessly that she would be "around" when school
+let out. And he hastened away, hating her for it.
+
+"Any other boy!" Tom thought, grating his teeth. "Any boy in the whole
+town but that Saint Louis smarty that thinks he dresses so fine and is
+aristocracy! Oh, all right, I licked you the first day you ever saw
+this town, mister, and I'll lick you again! You just wait till I catch
+you out! I'll just take and--"
+
+And he went through the motions of thrashing an imaginary boy
+--pummelling the air, and kicking and gouging. "Oh, you do, do you? You
+holler 'nough, do you? Now, then, let that learn you!" And so the
+imaginary flogging was finished to his satisfaction.
+
+Tom fled home at noon. His conscience could not endure any more of
+Amy's grateful happiness, and his jealousy could bear no more of the
+other distress. Becky resumed her picture inspections with Alfred, but
+as the minutes dragged along and no Tom came to suffer, her triumph
+began to cloud and she lost interest; gravity and absent-mindedness
+followed, and then melancholy; two or three times she pricked up her
+ear at a footstep, but it was a false hope; no Tom came. At last she
+grew entirely miserable and wished she hadn't carried it so far. When
+poor Alfred, seeing that he was losing her, he did not know how, kept
+exclaiming: "Oh, here's a jolly one! look at this!" she lost patience
+at last, and said, "Oh, don't bother me! I don't care for them!" and
+burst into tears, and got up and walked away.
+
+Alfred dropped alongside and was going to try to comfort her, but she
+said:
+
+"Go away and leave me alone, can't you! I hate you!"
+
+So the boy halted, wondering what he could have done--for she had said
+she would look at pictures all through the nooning--and she walked on,
+crying. Then Alfred went musing into the deserted schoolhouse. He was
+humiliated and angry. He easily guessed his way to the truth--the girl
+had simply made a convenience of him to vent her spite upon Tom Sawyer.
+He was far from hating Tom the less when this thought occurred to him.
+He wished there was some way to get that boy into trouble without much
+risk to himself. Tom's spelling-book fell under his eye. Here was his
+opportunity. He gratefully opened to the lesson for the afternoon and
+poured ink upon the page.
+
+Becky, glancing in at a window behind him at the moment, saw the act,
+and moved on, without discovering herself. She started homeward, now,
+intending to find Tom and tell him; Tom would be thankful and their
+troubles would be healed. Before she was half way home, however, she
+had changed her mind. The thought of Tom's treatment of her when she
+was talking about her picnic came scorching back and filled her with
+shame. She resolved to let him get whipped on the damaged
+spelling-book's account, and to hate him forever, into the bargain.
+
+
+
+CHAPTER XIX
+
+TOM arrived at home in a dreary mood, and the first thing his aunt
+said to him showed him that he had brought his sorrows to an
+unpromising market:
+
+"Tom, I've a notion to skin you alive!"
+
+"Auntie, what have I done?"
+
+"Well, you've done enough. Here I go over to Sereny Harper, like an
+old softy, expecting I'm going to make her believe all that rubbage
+about that dream, when lo and behold you she'd found out from Joe that
+you was over here and heard all the talk we had that night. Tom, I
+don't know what is to become of a boy that will act like that. It makes
+me feel so bad to think you could let me go to Sereny Harper and make
+such a fool of myself and never say a word."
+
+This was a new aspect of the thing. His smartness of the morning had
+seemed to Tom a good joke before, and very ingenious. It merely looked
+mean and shabby now. He hung his head and could not think of anything
+to say for a moment. Then he said:
+
+"Auntie, I wish I hadn't done it--but I didn't think."
+
+"Oh, child, you never think. You never think of anything but your own
+selfishness. You could think to come all the way over here from
+Jackson's Island in the night to laugh at our troubles, and you could
+think to fool me with a lie about a dream; but you couldn't ever think
+to pity us and save us from sorrow."
+
+"Auntie, I know now it was mean, but I didn't mean to be mean. I
+didn't, honest. And besides, I didn't come over here to laugh at you
+that night."
+
+"What did you come for, then?"
+
+"It was to tell you not to be uneasy about us, because we hadn't got
+drownded."
+
+"Tom, Tom, I would be the thankfullest soul in this world if I could
+believe you ever had as good a thought as that, but you know you never
+did--and I know it, Tom."
+
+"Indeed and 'deed I did, auntie--I wish I may never stir if I didn't."
+
+"Oh, Tom, don't lie--don't do it. It only makes things a hundred times
+worse."
+
+"It ain't a lie, auntie; it's the truth. I wanted to keep you from
+grieving--that was all that made me come."
+
+"I'd give the whole world to believe that--it would cover up a power
+of sins, Tom. I'd 'most be glad you'd run off and acted so bad. But it
+ain't reasonable; because, why didn't you tell me, child?"
+
+"Why, you see, when you got to talking about the funeral, I just got
+all full of the idea of our coming and hiding in the church, and I
+couldn't somehow bear to spoil it. So I just put the bark back in my
+pocket and kept mum."
+
+"What bark?"
+
+"The bark I had wrote on to tell you we'd gone pirating. I wish, now,
+you'd waked up when I kissed you--I do, honest."
+
+The hard lines in his aunt's face relaxed and a sudden tenderness
+dawned in her eyes.
+
+"DID you kiss me, Tom?"
+
+"Why, yes, I did."
+
+"Are you sure you did, Tom?"
+
+"Why, yes, I did, auntie--certain sure."
+
+"What did you kiss me for, Tom?"
+
+"Because I loved you so, and you laid there moaning and I was so sorry."
+
+The words sounded like truth. The old lady could not hide a tremor in
+her voice when she said:
+
+"Kiss me again, Tom!--and be off with you to school, now, and don't
+bother me any more."
+
+The moment he was gone, she ran to a closet and got out the ruin of a
+jacket which Tom had gone pirating in. Then she stopped, with it in her
+hand, and said to herself:
+
+"No, I don't dare. Poor boy, I reckon he's lied about it--but it's a
+blessed, blessed lie, there's such a comfort come from it. I hope the
+Lord--I KNOW the Lord will forgive him, because it was such
+goodheartedness in him to tell it. But I don't want to find out it's a
+lie. I won't look."
+
+She put the jacket away, and stood by musing a minute. Twice she put
+out her hand to take the garment again, and twice she refrained. Once
+more she ventured, and this time she fortified herself with the
+thought: "It's a good lie--it's a good lie--I won't let it grieve me."
+So she sought the jacket pocket. A moment later she was reading Tom's
+piece of bark through flowing tears and saying: "I could forgive the
+boy, now, if he'd committed a million sins!"
+
+
+
+CHAPTER XX
+
+THERE was something about Aunt Polly's manner, when she kissed Tom,
+that swept away his low spirits and made him lighthearted and happy
+again. He started to school and had the luck of coming upon Becky
+Thatcher at the head of Meadow Lane. His mood always determined his
+manner. Without a moment's hesitation he ran to her and said:
+
+"I acted mighty mean to-day, Becky, and I'm so sorry. I won't ever,
+ever do that way again, as long as ever I live--please make up, won't
+you?"
+
+The girl stopped and looked him scornfully in the face:
+
+"I'll thank you to keep yourself TO yourself, Mr. Thomas Sawyer. I'll
+never speak to you again."
+
+She tossed her head and passed on. Tom was so stunned that he had not
+even presence of mind enough to say "Who cares, Miss Smarty?" until the
+right time to say it had gone by. So he said nothing. But he was in a
+fine rage, nevertheless. He moped into the schoolyard wishing she were
+a boy, and imagining how he would trounce her if she were. He presently
+encountered her and delivered a stinging remark as he passed. She
+hurled one in return, and the angry breach was complete. It seemed to
+Becky, in her hot resentment, that she could hardly wait for school to
+"take in," she was so impatient to see Tom flogged for the injured
+spelling-book. If she had had any lingering notion of exposing Alfred
+Temple, Tom's offensive fling had driven it entirely away.
+
+Poor girl, she did not know how fast she was nearing trouble herself.
+The master, Mr. Dobbins, had reached middle age with an unsatisfied
+ambition. The darling of his desires was, to be a doctor, but poverty
+had decreed that he should be nothing higher than a village
+schoolmaster. Every day he took a mysterious book out of his desk and
+absorbed himself in it at times when no classes were reciting. He kept
+that book under lock and key. There was not an urchin in school but was
+perishing to have a glimpse of it, but the chance never came. Every boy
+and girl had a theory about the nature of that book; but no two
+theories were alike, and there was no way of getting at the facts in
+the case. Now, as Becky was passing by the desk, which stood near the
+door, she noticed that the key was in the lock! It was a precious
+moment. She glanced around; found herself alone, and the next instant
+she had the book in her hands. The title-page--Professor Somebody's
+ANATOMY--carried no information to her mind; so she began to turn the
+leaves. She came at once upon a handsomely engraved and colored
+frontispiece--a human figure, stark naked. At that moment a shadow fell
+on the page and Tom Sawyer stepped in at the door and caught a glimpse
+of the picture. Becky snatched at the book to close it, and had the
+hard luck to tear the pictured page half down the middle. She thrust
+the volume into the desk, turned the key, and burst out crying with
+shame and vexation.
+
+"Tom Sawyer, you are just as mean as you can be, to sneak up on a
+person and look at what they're looking at."
+
+"How could I know you was looking at anything?"
+
+"You ought to be ashamed of yourself, Tom Sawyer; you know you're
+going to tell on me, and oh, what shall I do, what shall I do! I'll be
+whipped, and I never was whipped in school."
+
+Then she stamped her little foot and said:
+
+"BE so mean if you want to! I know something that's going to happen.
+You just wait and you'll see! Hateful, hateful, hateful!"--and she
+flung out of the house with a new explosion of crying.
+
+Tom stood still, rather flustered by this onslaught. Presently he said
+to himself:
+
+"What a curious kind of a fool a girl is! Never been licked in school!
+Shucks! What's a licking! That's just like a girl--they're so
+thin-skinned and chicken-hearted. Well, of course I ain't going to tell
+old Dobbins on this little fool, because there's other ways of getting
+even on her, that ain't so mean; but what of it? Old Dobbins will ask
+who it was tore his book. Nobody'll answer. Then he'll do just the way
+he always does--ask first one and then t'other, and when he comes to the
+right girl he'll know it, without any telling. Girls' faces always tell
+on them. They ain't got any backbone. She'll get licked. Well, it's a
+kind of a tight place for Becky Thatcher, because there ain't any way
+out of it." Tom conned the thing a moment longer, and then added: "All
+right, though; she'd like to see me in just such a fix--let her sweat it
+out!"
+
+Tom joined the mob of skylarking scholars outside. In a few moments
+the master arrived and school "took in." Tom did not feel a strong
+interest in his studies. Every time he stole a glance at the girls'
+side of the room Becky's face troubled him. Considering all things, he
+did not want to pity her, and yet it was all he could do to help it. He
+could get up no exultation that was really worthy the name. Presently
+the spelling-book discovery was made, and Tom's mind was entirely full
+of his own matters for a while after that. Becky roused up from her
+lethargy of distress and showed good interest in the proceedings. She
+did not expect that Tom could get out of his trouble by denying that he
+spilt the ink on the book himself; and she was right. The denial only
+seemed to make the thing worse for Tom. Becky supposed she would be
+glad of that, and she tried to believe she was glad of it, but she
+found she was not certain. When the worst came to the worst, she had an
+impulse to get up and tell on Alfred Temple, but she made an effort and
+forced herself to keep still--because, said she to herself, "he'll tell
+about me tearing the picture sure. I wouldn't say a word, not to save
+his life!"
+
+Tom took his whipping and went back to his seat not at all
+broken-hearted, for he thought it was possible that he had unknowingly
+upset the ink on the spelling-book himself, in some skylarking bout--he
+had denied it for form's sake and because it was custom, and had stuck
+to the denial from principle.
+
+A whole hour drifted by, the master sat nodding in his throne, the air
+was drowsy with the hum of study. By and by, Mr. Dobbins straightened
+himself up, yawned, then unlocked his desk, and reached for his book,
+but seemed undecided whether to take it out or leave it. Most of the
+pupils glanced up languidly, but there were two among them that watched
+his movements with intent eyes. Mr. Dobbins fingered his book absently
+for a while, then took it out and settled himself in his chair to read!
+Tom shot a glance at Becky. He had seen a hunted and helpless rabbit
+look as she did, with a gun levelled at its head. Instantly he forgot
+his quarrel with her. Quick--something must be done! done in a flash,
+too! But the very imminence of the emergency paralyzed his invention.
+Good!--he had an inspiration! He would run and snatch the book, spring
+through the door and fly. But his resolution shook for one little
+instant, and the chance was lost--the master opened the volume. If Tom
+only had the wasted opportunity back again! Too late. There was no help
+for Becky now, he said. The next moment the master faced the school.
+Every eye sank under his gaze. There was that in it which smote even
+the innocent with fear. There was silence while one might count ten
+--the master was gathering his wrath. Then he spoke: "Who tore this book?"
+
+There was not a sound. One could have heard a pin drop. The stillness
+continued; the master searched face after face for signs of guilt.
+
+"Benjamin Rogers, did you tear this book?"
+
+A denial. Another pause.
+
+"Joseph Harper, did you?"
+
+Another denial. Tom's uneasiness grew more and more intense under the
+slow torture of these proceedings. The master scanned the ranks of
+boys--considered a while, then turned to the girls:
+
+"Amy Lawrence?"
+
+A shake of the head.
+
+"Gracie Miller?"
+
+The same sign.
+
+"Susan Harper, did you do this?"
+
+Another negative. The next girl was Becky Thatcher. Tom was trembling
+from head to foot with excitement and a sense of the hopelessness of
+the situation.
+
+"Rebecca Thatcher" [Tom glanced at her face--it was white with terror]
+--"did you tear--no, look me in the face" [her hands rose in appeal]
+--"did you tear this book?"
+
+A thought shot like lightning through Tom's brain. He sprang to his
+feet and shouted--"I done it!"
+
+The school stared in perplexity at this incredible folly. Tom stood a
+moment, to gather his dismembered faculties; and when he stepped
+forward to go to his punishment the surprise, the gratitude, the
+adoration that shone upon him out of poor Becky's eyes seemed pay
+enough for a hundred floggings. Inspired by the splendor of his own
+act, he took without an outcry the most merciless flaying that even Mr.
+Dobbins had ever administered; and also received with indifference the
+added cruelty of a command to remain two hours after school should be
+dismissed--for he knew who would wait for him outside till his
+captivity was done, and not count the tedious time as loss, either.
+
+Tom went to bed that night planning vengeance against Alfred Temple;
+for with shame and repentance Becky had told him all, not forgetting
+her own treachery; but even the longing for vengeance had to give way,
+soon, to pleasanter musings, and he fell asleep at last with Becky's
+latest words lingering dreamily in his ear--
+
+"Tom, how COULD you be so noble!"
+
+
+
+CHAPTER XXI
+
+VACATION was approaching. The schoolmaster, always severe, grew
+severer and more exacting than ever, for he wanted the school to make a
+good showing on "Examination" day. His rod and his ferule were seldom
+idle now--at least among the smaller pupils. Only the biggest boys, and
+young ladies of eighteen and twenty, escaped lashing. Mr. Dobbins'
+lashings were very vigorous ones, too; for although he carried, under
+his wig, a perfectly bald and shiny head, he had only reached middle
+age, and there was no sign of feebleness in his muscle. As the great
+day approached, all the tyranny that was in him came to the surface; he
+seemed to take a vindictive pleasure in punishing the least
+shortcomings. The consequence was, that the smaller boys spent their
+days in terror and suffering and their nights in plotting revenge. They
+threw away no opportunity to do the master a mischief. But he kept
+ahead all the time. The retribution that followed every vengeful
+success was so sweeping and majestic that the boys always retired from
+the field badly worsted. At last they conspired together and hit upon a
+plan that promised a dazzling victory. They swore in the sign-painter's
+boy, told him the scheme, and asked his help. He had his own reasons
+for being delighted, for the master boarded in his father's family and
+had given the boy ample cause to hate him. The master's wife would go
+on a visit to the country in a few days, and there would be nothing to
+interfere with the plan; the master always prepared himself for great
+occasions by getting pretty well fuddled, and the sign-painter's boy
+said that when the dominie had reached the proper condition on
+Examination Evening he would "manage the thing" while he napped in his
+chair; then he would have him awakened at the right time and hurried
+away to school.
+
+In the fulness of time the interesting occasion arrived. At eight in
+the evening the schoolhouse was brilliantly lighted, and adorned with
+wreaths and festoons of foliage and flowers. The master sat throned in
+his great chair upon a raised platform, with his blackboard behind him.
+He was looking tolerably mellow. Three rows of benches on each side and
+six rows in front of him were occupied by the dignitaries of the town
+and by the parents of the pupils. To his left, back of the rows of
+citizens, was a spacious temporary platform upon which were seated the
+scholars who were to take part in the exercises of the evening; rows of
+small boys, washed and dressed to an intolerable state of discomfort;
+rows of gawky big boys; snowbanks of girls and young ladies clad in
+lawn and muslin and conspicuously conscious of their bare arms, their
+grandmothers' ancient trinkets, their bits of pink and blue ribbon and
+the flowers in their hair. All the rest of the house was filled with
+non-participating scholars.
+
+The exercises began. A very little boy stood up and sheepishly
+recited, "You'd scarce expect one of my age to speak in public on the
+stage," etc.--accompanying himself with the painfully exact and
+spasmodic gestures which a machine might have used--supposing the
+machine to be a trifle out of order. But he got through safely, though
+cruelly scared, and got a fine round of applause when he made his
+manufactured bow and retired.
+
+A little shamefaced girl lisped, "Mary had a little lamb," etc.,
+performed a compassion-inspiring curtsy, got her meed of applause, and
+sat down flushed and happy.
+
+Tom Sawyer stepped forward with conceited confidence and soared into
+the unquenchable and indestructible "Give me liberty or give me death"
+speech, with fine fury and frantic gesticulation, and broke down in the
+middle of it. A ghastly stage-fright seized him, his legs quaked under
+him and he was like to choke. True, he had the manifest sympathy of the
+house but he had the house's silence, too, which was even worse than
+its sympathy. The master frowned, and this completed the disaster. Tom
+struggled awhile and then retired, utterly defeated. There was a weak
+attempt at applause, but it died early.
+
+"The Boy Stood on the Burning Deck" followed; also "The Assyrian Came
+Down," and other declamatory gems. Then there were reading exercises,
+and a spelling fight. The meagre Latin class recited with honor. The
+prime feature of the evening was in order, now--original "compositions"
+by the young ladies. Each in her turn stepped forward to the edge of
+the platform, cleared her throat, held up her manuscript (tied with
+dainty ribbon), and proceeded to read, with labored attention to
+"expression" and punctuation. The themes were the same that had been
+illuminated upon similar occasions by their mothers before them, their
+grandmothers, and doubtless all their ancestors in the female line
+clear back to the Crusades. "Friendship" was one; "Memories of Other
+Days"; "Religion in History"; "Dream Land"; "The Advantages of
+Culture"; "Forms of Political Government Compared and Contrasted";
+"Melancholy"; "Filial Love"; "Heart Longings," etc., etc.
+
+A prevalent feature in these compositions was a nursed and petted
+melancholy; another was a wasteful and opulent gush of "fine language";
+another was a tendency to lug in by the ears particularly prized words
+and phrases until they were worn entirely out; and a peculiarity that
+conspicuously marked and marred them was the inveterate and intolerable
+sermon that wagged its crippled tail at the end of each and every one
+of them. No matter what the subject might be, a brain-racking effort
+was made to squirm it into some aspect or other that the moral and
+religious mind could contemplate with edification. The glaring
+insincerity of these sermons was not sufficient to compass the
+banishment of the fashion from the schools, and it is not sufficient
+to-day; it never will be sufficient while the world stands, perhaps.
+There is no school in all our land where the young ladies do not feel
+obliged to close their compositions with a sermon; and you will find
+that the sermon of the most frivolous and the least religious girl in
+the school is always the longest and the most relentlessly pious. But
+enough of this. Homely truth is unpalatable.
+
+Let us return to the "Examination." The first composition that was
+read was one entitled "Is this, then, Life?" Perhaps the reader can
+endure an extract from it:
+
+ "In the common walks of life, with what delightful
+ emotions does the youthful mind look forward to some
+ anticipated scene of festivity! Imagination is busy
+ sketching rose-tinted pictures of joy. In fancy, the
+ voluptuous votary of fashion sees herself amid the
+ festive throng, 'the observed of all observers.' Her
+ graceful form, arrayed in snowy robes, is whirling
+ through the mazes of the joyous dance; her eye is
+ brightest, her step is lightest in the gay assembly.
+
+ "In such delicious fancies time quickly glides by,
+ and the welcome hour arrives for her entrance into
+ the Elysian world, of which she has had such bright
+ dreams. How fairy-like does everything appear to
+ her enchanted vision! Each new scene is more charming
+ than the last. But after a while she finds that
+ beneath this goodly exterior, all is vanity, the
+ flattery which once charmed her soul, now grates
+ harshly upon her ear; the ball-room has lost its
+ charms; and with wasted health and imbittered heart,
+ she turns away with the conviction that earthly
+ pleasures cannot satisfy the longings of the soul!"
+
+And so forth and so on. There was a buzz of gratification from time to
+time during the reading, accompanied by whispered ejaculations of "How
+sweet!" "How eloquent!" "So true!" etc., and after the thing had closed
+with a peculiarly afflicting sermon the applause was enthusiastic.
+
+Then arose a slim, melancholy girl, whose face had the "interesting"
+paleness that comes of pills and indigestion, and read a "poem." Two
+stanzas of it will do:
+
+ "A MISSOURI MAIDEN'S FAREWELL TO ALABAMA
+
+ "Alabama, good-bye! I love thee well!
+ But yet for a while do I leave thee now!
+ Sad, yes, sad thoughts of thee my heart doth swell,
+ And burning recollections throng my brow!
+ For I have wandered through thy flowery woods;
+ Have roamed and read near Tallapoosa's stream;
+ Have listened to Tallassee's warring floods,
+ And wooed on Coosa's side Aurora's beam.
+
+ "Yet shame I not to bear an o'er-full heart,
+ Nor blush to turn behind my tearful eyes;
+ 'Tis from no stranger land I now must part,
+ 'Tis to no strangers left I yield these sighs.
+ Welcome and home were mine within this State,
+ Whose vales I leave--whose spires fade fast from me
+ And cold must be mine eyes, and heart, and tete,
+ When, dear Alabama! they turn cold on thee!"
+
+There were very few there who knew what "tete" meant, but the poem was
+very satisfactory, nevertheless.
+
+Next appeared a dark-complexioned, black-eyed, black-haired young
+lady, who paused an impressive moment, assumed a tragic expression, and
+began to read in a measured, solemn tone:
+
+ "A VISION
+
+ "Dark and tempestuous was night. Around the
+ throne on high not a single star quivered; but
+ the deep intonations of the heavy thunder
+ constantly vibrated upon the ear; whilst the
+ terrific lightning revelled in angry mood
+ through the cloudy chambers of heaven, seeming
+ to scorn the power exerted over its terror by
+ the illustrious Franklin! Even the boisterous
+ winds unanimously came forth from their mystic
+ homes, and blustered about as if to enhance by
+ their aid the wildness of the scene.
+
+ "At such a time, so dark, so dreary, for human
+ sympathy my very spirit sighed; but instead thereof,
+
+ "'My dearest friend, my counsellor, my comforter
+ and guide--My joy in grief, my second bliss
+ in joy,' came to my side. She moved like one of
+ those bright beings pictured in the sunny walks
+ of fancy's Eden by the romantic and young, a
+ queen of beauty unadorned save by her own
+ transcendent loveliness. So soft was her step, it
+ failed to make even a sound, and but for the
+ magical thrill imparted by her genial touch, as
+ other unobtrusive beauties, she would have glided
+ away un-perceived--unsought. A strange sadness
+ rested upon her features, like icy tears upon
+ the robe of December, as she pointed to the
+ contending elements without, and bade me contemplate
+ the two beings presented."
+
+This nightmare occupied some ten pages of manuscript and wound up with
+a sermon so destructive of all hope to non-Presbyterians that it took
+the first prize. This composition was considered to be the very finest
+effort of the evening. The mayor of the village, in delivering the
+prize to the author of it, made a warm speech in which he said that it
+was by far the most "eloquent" thing he had ever listened to, and that
+Daniel Webster himself might well be proud of it.
+
+It may be remarked, in passing, that the number of compositions in
+which the word "beauteous" was over-fondled, and human experience
+referred to as "life's page," was up to the usual average.
+
+Now the master, mellow almost to the verge of geniality, put his chair
+aside, turned his back to the audience, and began to draw a map of
+America on the blackboard, to exercise the geography class upon. But he
+made a sad business of it with his unsteady hand, and a smothered
+titter rippled over the house. He knew what the matter was, and set
+himself to right it. He sponged out lines and remade them; but he only
+distorted them more than ever, and the tittering was more pronounced.
+He threw his entire attention upon his work, now, as if determined not
+to be put down by the mirth. He felt that all eyes were fastened upon
+him; he imagined he was succeeding, and yet the tittering continued; it
+even manifestly increased. And well it might. There was a garret above,
+pierced with a scuttle over his head; and down through this scuttle
+came a cat, suspended around the haunches by a string; she had a rag
+tied about her head and jaws to keep her from mewing; as she slowly
+descended she curved upward and clawed at the string, she swung
+downward and clawed at the intangible air. The tittering rose higher
+and higher--the cat was within six inches of the absorbed teacher's
+head--down, down, a little lower, and she grabbed his wig with her
+desperate claws, clung to it, and was snatched up into the garret in an
+instant with her trophy still in her possession! And how the light did
+blaze abroad from the master's bald pate--for the sign-painter's boy
+had GILDED it!
+
+That broke up the meeting. The boys were avenged. Vacation had come.
+
+ NOTE:--The pretended "compositions" quoted in
+ this chapter are taken without alteration from a
+ volume entitled "Prose and Poetry, by a Western
+ Lady"--but they are exactly and precisely after
+ the schoolgirl pattern, and hence are much
+ happier than any mere imitations could be.
+
+
+
+CHAPTER XXII
+
+TOM joined the new order of Cadets of Temperance, being attracted by
+the showy character of their "regalia." He promised to abstain from
+smoking, chewing, and profanity as long as he remained a member. Now he
+found out a new thing--namely, that to promise not to do a thing is the
+surest way in the world to make a body want to go and do that very
+thing. Tom soon found himself tormented with a desire to drink and
+swear; the desire grew to be so intense that nothing but the hope of a
+chance to display himself in his red sash kept him from withdrawing
+from the order. Fourth of July was coming; but he soon gave that up
+--gave it up before he had worn his shackles over forty-eight hours--and
+fixed his hopes upon old Judge Frazer, justice of the peace, who was
+apparently on his deathbed and would have a big public funeral, since
+he was so high an official. During three days Tom was deeply concerned
+about the Judge's condition and hungry for news of it. Sometimes his
+hopes ran high--so high that he would venture to get out his regalia
+and practise before the looking-glass. But the Judge had a most
+discouraging way of fluctuating. At last he was pronounced upon the
+mend--and then convalescent. Tom was disgusted; and felt a sense of
+injury, too. He handed in his resignation at once--and that night the
+Judge suffered a relapse and died. Tom resolved that he would never
+trust a man like that again.
+
+The funeral was a fine thing. The Cadets paraded in a style calculated
+to kill the late member with envy. Tom was a free boy again, however
+--there was something in that. He could drink and swear, now--but found
+to his surprise that he did not want to. The simple fact that he could,
+took the desire away, and the charm of it.
+
+Tom presently wondered to find that his coveted vacation was beginning
+to hang a little heavily on his hands.
+
+He attempted a diary--but nothing happened during three days, and so
+he abandoned it.
+
+The first of all the negro minstrel shows came to town, and made a
+sensation. Tom and Joe Harper got up a band of performers and were
+happy for two days.
+
+Even the Glorious Fourth was in some sense a failure, for it rained
+hard, there was no procession in consequence, and the greatest man in
+the world (as Tom supposed), Mr. Benton, an actual United States
+Senator, proved an overwhelming disappointment--for he was not
+twenty-five feet high, nor even anywhere in the neighborhood of it.
+
+A circus came. The boys played circus for three days afterward in
+tents made of rag carpeting--admission, three pins for boys, two for
+girls--and then circusing was abandoned.
+
+A phrenologist and a mesmerizer came--and went again and left the
+village duller and drearier than ever.
+
+There were some boys-and-girls' parties, but they were so few and so
+delightful that they only made the aching voids between ache the harder.
+
+Becky Thatcher was gone to her Constantinople home to stay with her
+parents during vacation--so there was no bright side to life anywhere.
+
+The dreadful secret of the murder was a chronic misery. It was a very
+cancer for permanency and pain.
+
+Then came the measles.
+
+During two long weeks Tom lay a prisoner, dead to the world and its
+happenings. He was very ill, he was interested in nothing. When he got
+upon his feet at last and moved feebly down-town, a melancholy change
+had come over everything and every creature. There had been a
+"revival," and everybody had "got religion," not only the adults, but
+even the boys and girls. Tom went about, hoping against hope for the
+sight of one blessed sinful face, but disappointment crossed him
+everywhere. He found Joe Harper studying a Testament, and turned sadly
+away from the depressing spectacle. He sought Ben Rogers, and found him
+visiting the poor with a basket of tracts. He hunted up Jim Hollis, who
+called his attention to the precious blessing of his late measles as a
+warning. Every boy he encountered added another ton to his depression;
+and when, in desperation, he flew for refuge at last to the bosom of
+Huckleberry Finn and was received with a Scriptural quotation, his
+heart broke and he crept home and to bed realizing that he alone of all
+the town was lost, forever and forever.
+
+And that night there came on a terrific storm, with driving rain,
+awful claps of thunder and blinding sheets of lightning. He covered his
+head with the bedclothes and waited in a horror of suspense for his
+doom; for he had not the shadow of a doubt that all this hubbub was
+about him. He believed he had taxed the forbearance of the powers above
+to the extremity of endurance and that this was the result. It might
+have seemed to him a waste of pomp and ammunition to kill a bug with a
+battery of artillery, but there seemed nothing incongruous about the
+getting up such an expensive thunderstorm as this to knock the turf
+from under an insect like himself.
+
+By and by the tempest spent itself and died without accomplishing its
+object. The boy's first impulse was to be grateful, and reform. His
+second was to wait--for there might not be any more storms.
+
+The next day the doctors were back; Tom had relapsed. The three weeks
+he spent on his back this time seemed an entire age. When he got abroad
+at last he was hardly grateful that he had been spared, remembering how
+lonely was his estate, how companionless and forlorn he was. He drifted
+listlessly down the street and found Jim Hollis acting as judge in a
+juvenile court that was trying a cat for murder, in the presence of her
+victim, a bird. He found Joe Harper and Huck Finn up an alley eating a
+stolen melon. Poor lads! they--like Tom--had suffered a relapse.
+
+
+
+CHAPTER XXIII
+
+AT last the sleepy atmosphere was stirred--and vigorously: the murder
+trial came on in the court. It became the absorbing topic of village
+talk immediately. Tom could not get away from it. Every reference to
+the murder sent a shudder to his heart, for his troubled conscience and
+fears almost persuaded him that these remarks were put forth in his
+hearing as "feelers"; he did not see how he could be suspected of
+knowing anything about the murder, but still he could not be
+comfortable in the midst of this gossip. It kept him in a cold shiver
+all the time. He took Huck to a lonely place to have a talk with him.
+It would be some relief to unseal his tongue for a little while; to
+divide his burden of distress with another sufferer. Moreover, he
+wanted to assure himself that Huck had remained discreet.
+
+"Huck, have you ever told anybody about--that?"
+
+"'Bout what?"
+
+"You know what."
+
+"Oh--'course I haven't."
+
+"Never a word?"
+
+"Never a solitary word, so help me. What makes you ask?"
+
+"Well, I was afeard."
+
+"Why, Tom Sawyer, we wouldn't be alive two days if that got found out.
+YOU know that."
+
+Tom felt more comfortable. After a pause:
+
+"Huck, they couldn't anybody get you to tell, could they?"
+
+"Get me to tell? Why, if I wanted that half-breed devil to drownd me
+they could get me to tell. They ain't no different way."
+
+"Well, that's all right, then. I reckon we're safe as long as we keep
+mum. But let's swear again, anyway. It's more surer."
+
+"I'm agreed."
+
+So they swore again with dread solemnities.
+
+"What is the talk around, Huck? I've heard a power of it."
+
+"Talk? Well, it's just Muff Potter, Muff Potter, Muff Potter all the
+time. It keeps me in a sweat, constant, so's I want to hide som'ers."
+
+"That's just the same way they go on round me. I reckon he's a goner.
+Don't you feel sorry for him, sometimes?"
+
+"Most always--most always. He ain't no account; but then he hain't
+ever done anything to hurt anybody. Just fishes a little, to get money
+to get drunk on--and loafs around considerable; but lord, we all do
+that--leastways most of us--preachers and such like. But he's kind of
+good--he give me half a fish, once, when there warn't enough for two;
+and lots of times he's kind of stood by me when I was out of luck."
+
+"Well, he's mended kites for me, Huck, and knitted hooks on to my
+line. I wish we could get him out of there."
+
+"My! we couldn't get him out, Tom. And besides, 'twouldn't do any
+good; they'd ketch him again."
+
+"Yes--so they would. But I hate to hear 'em abuse him so like the
+dickens when he never done--that."
+
+"I do too, Tom. Lord, I hear 'em say he's the bloodiest looking
+villain in this country, and they wonder he wasn't ever hung before."
+
+"Yes, they talk like that, all the time. I've heard 'em say that if he
+was to get free they'd lynch him."
+
+"And they'd do it, too."
+
+The boys had a long talk, but it brought them little comfort. As the
+twilight drew on, they found themselves hanging about the neighborhood
+of the little isolated jail, perhaps with an undefined hope that
+something would happen that might clear away their difficulties. But
+nothing happened; there seemed to be no angels or fairies interested in
+this luckless captive.
+
+The boys did as they had often done before--went to the cell grating
+and gave Potter some tobacco and matches. He was on the ground floor
+and there were no guards.
+
+His gratitude for their gifts had always smote their consciences
+before--it cut deeper than ever, this time. They felt cowardly and
+treacherous to the last degree when Potter said:
+
+"You've been mighty good to me, boys--better'n anybody else in this
+town. And I don't forget it, I don't. Often I says to myself, says I,
+'I used to mend all the boys' kites and things, and show 'em where the
+good fishin' places was, and befriend 'em what I could, and now they've
+all forgot old Muff when he's in trouble; but Tom don't, and Huck
+don't--THEY don't forget him, says I, 'and I don't forget them.' Well,
+boys, I done an awful thing--drunk and crazy at the time--that's the
+only way I account for it--and now I got to swing for it, and it's
+right. Right, and BEST, too, I reckon--hope so, anyway. Well, we won't
+talk about that. I don't want to make YOU feel bad; you've befriended
+me. But what I want to say, is, don't YOU ever get drunk--then you won't
+ever get here. Stand a litter furder west--so--that's it; it's a prime
+comfort to see faces that's friendly when a body's in such a muck of
+trouble, and there don't none come here but yourn. Good friendly
+faces--good friendly faces. Git up on one another's backs and let me
+touch 'em. That's it. Shake hands--yourn'll come through the bars, but
+mine's too big. Little hands, and weak--but they've helped Muff Potter
+a power, and they'd help him more if they could."
+
+Tom went home miserable, and his dreams that night were full of
+horrors. The next day and the day after, he hung about the court-room,
+drawn by an almost irresistible impulse to go in, but forcing himself
+to stay out. Huck was having the same experience. They studiously
+avoided each other. Each wandered away, from time to time, but the same
+dismal fascination always brought them back presently. Tom kept his
+ears open when idlers sauntered out of the court-room, but invariably
+heard distressing news--the toils were closing more and more
+relentlessly around poor Potter. At the end of the second day the
+village talk was to the effect that Injun Joe's evidence stood firm and
+unshaken, and that there was not the slightest question as to what the
+jury's verdict would be.
+
+Tom was out late, that night, and came to bed through the window. He
+was in a tremendous state of excitement. It was hours before he got to
+sleep. All the village flocked to the court-house the next morning, for
+this was to be the great day. Both sexes were about equally represented
+in the packed audience. After a long wait the jury filed in and took
+their places; shortly afterward, Potter, pale and haggard, timid and
+hopeless, was brought in, with chains upon him, and seated where all
+the curious eyes could stare at him; no less conspicuous was Injun Joe,
+stolid as ever. There was another pause, and then the judge arrived and
+the sheriff proclaimed the opening of the court. The usual whisperings
+among the lawyers and gathering together of papers followed. These
+details and accompanying delays worked up an atmosphere of preparation
+that was as impressive as it was fascinating.
+
+Now a witness was called who testified that he found Muff Potter
+washing in the brook, at an early hour of the morning that the murder
+was discovered, and that he immediately sneaked away. After some
+further questioning, counsel for the prosecution said:
+
+"Take the witness."
+
+The prisoner raised his eyes for a moment, but dropped them again when
+his own counsel said:
+
+"I have no questions to ask him."
+
+The next witness proved the finding of the knife near the corpse.
+Counsel for the prosecution said:
+
+"Take the witness."
+
+"I have no questions to ask him," Potter's lawyer replied.
+
+A third witness swore he had often seen the knife in Potter's
+possession.
+
+"Take the witness."
+
+Counsel for Potter declined to question him. The faces of the audience
+began to betray annoyance. Did this attorney mean to throw away his
+client's life without an effort?
+
+Several witnesses deposed concerning Potter's guilty behavior when
+brought to the scene of the murder. They were allowed to leave the
+stand without being cross-questioned.
+
+Every detail of the damaging circumstances that occurred in the
+graveyard upon that morning which all present remembered so well was
+brought out by credible witnesses, but none of them were cross-examined
+by Potter's lawyer. The perplexity and dissatisfaction of the house
+expressed itself in murmurs and provoked a reproof from the bench.
+Counsel for the prosecution now said:
+
+"By the oaths of citizens whose simple word is above suspicion, we
+have fastened this awful crime, beyond all possibility of question,
+upon the unhappy prisoner at the bar. We rest our case here."
+
+A groan escaped from poor Potter, and he put his face in his hands and
+rocked his body softly to and fro, while a painful silence reigned in
+the court-room. Many men were moved, and many women's compassion
+testified itself in tears. Counsel for the defence rose and said:
+
+"Your honor, in our remarks at the opening of this trial, we
+foreshadowed our purpose to prove that our client did this fearful deed
+while under the influence of a blind and irresponsible delirium
+produced by drink. We have changed our mind. We shall not offer that
+plea." [Then to the clerk:] "Call Thomas Sawyer!"
+
+A puzzled amazement awoke in every face in the house, not even
+excepting Potter's. Every eye fastened itself with wondering interest
+upon Tom as he rose and took his place upon the stand. The boy looked
+wild enough, for he was badly scared. The oath was administered.
+
+"Thomas Sawyer, where were you on the seventeenth of June, about the
+hour of midnight?"
+
+Tom glanced at Injun Joe's iron face and his tongue failed him. The
+audience listened breathless, but the words refused to come. After a
+few moments, however, the boy got a little of his strength back, and
+managed to put enough of it into his voice to make part of the house
+hear:
+
+"In the graveyard!"
+
+"A little bit louder, please. Don't be afraid. You were--"
+
+"In the graveyard."
+
+A contemptuous smile flitted across Injun Joe's face.
+
+"Were you anywhere near Horse Williams' grave?"
+
+"Yes, sir."
+
+"Speak up--just a trifle louder. How near were you?"
+
+"Near as I am to you."
+
+"Were you hidden, or not?"
+
+"I was hid."
+
+"Where?"
+
+"Behind the elms that's on the edge of the grave."
+
+Injun Joe gave a barely perceptible start.
+
+"Any one with you?"
+
+"Yes, sir. I went there with--"
+
+"Wait--wait a moment. Never mind mentioning your companion's name. We
+will produce him at the proper time. Did you carry anything there with
+you."
+
+Tom hesitated and looked confused.
+
+"Speak out, my boy--don't be diffident. The truth is always
+respectable. What did you take there?"
+
+"Only a--a--dead cat."
+
+There was a ripple of mirth, which the court checked.
+
+"We will produce the skeleton of that cat. Now, my boy, tell us
+everything that occurred--tell it in your own way--don't skip anything,
+and don't be afraid."
+
+Tom began--hesitatingly at first, but as he warmed to his subject his
+words flowed more and more easily; in a little while every sound ceased
+but his own voice; every eye fixed itself upon him; with parted lips
+and bated breath the audience hung upon his words, taking no note of
+time, rapt in the ghastly fascinations of the tale. The strain upon
+pent emotion reached its climax when the boy said:
+
+"--and as the doctor fetched the board around and Muff Potter fell,
+Injun Joe jumped with the knife and--"
+
+Crash! Quick as lightning the half-breed sprang for a window, tore his
+way through all opposers, and was gone!
+
+
+
+CHAPTER XXIV
+
+TOM was a glittering hero once more--the pet of the old, the envy of
+the young. His name even went into immortal print, for the village
+paper magnified him. There were some that believed he would be
+President, yet, if he escaped hanging.
+
+As usual, the fickle, unreasoning world took Muff Potter to its bosom
+and fondled him as lavishly as it had abused him before. But that sort
+of conduct is to the world's credit; therefore it is not well to find
+fault with it.
+
+Tom's days were days of splendor and exultation to him, but his nights
+were seasons of horror. Injun Joe infested all his dreams, and always
+with doom in his eye. Hardly any temptation could persuade the boy to
+stir abroad after nightfall. Poor Huck was in the same state of
+wretchedness and terror, for Tom had told the whole story to the lawyer
+the night before the great day of the trial, and Huck was sore afraid
+that his share in the business might leak out, yet, notwithstanding
+Injun Joe's flight had saved him the suffering of testifying in court.
+The poor fellow had got the attorney to promise secrecy, but what of
+that? Since Tom's harassed conscience had managed to drive him to the
+lawyer's house by night and wring a dread tale from lips that had been
+sealed with the dismalest and most formidable of oaths, Huck's
+confidence in the human race was well-nigh obliterated.
+
+Daily Muff Potter's gratitude made Tom glad he had spoken; but nightly
+he wished he had sealed up his tongue.
+
+Half the time Tom was afraid Injun Joe would never be captured; the
+other half he was afraid he would be. He felt sure he never could draw
+a safe breath again until that man was dead and he had seen the corpse.
+
+Rewards had been offered, the country had been scoured, but no Injun
+Joe was found. One of those omniscient and awe-inspiring marvels, a
+detective, came up from St. Louis, moused around, shook his head,
+looked wise, and made that sort of astounding success which members of
+that craft usually achieve. That is to say, he "found a clew." But you
+can't hang a "clew" for murder, and so after that detective had got
+through and gone home, Tom felt just as insecure as he was before.
+
+The slow days drifted on, and each left behind it a slightly lightened
+weight of apprehension.
+
+
+
+CHAPTER XXV
+
+THERE comes a time in every rightly-constructed boy's life when he has
+a raging desire to go somewhere and dig for hidden treasure. This
+desire suddenly came upon Tom one day. He sallied out to find Joe
+Harper, but failed of success. Next he sought Ben Rogers; he had gone
+fishing. Presently he stumbled upon Huck Finn the Red-Handed. Huck
+would answer. Tom took him to a private place and opened the matter to
+him confidentially. Huck was willing. Huck was always willing to take a
+hand in any enterprise that offered entertainment and required no
+capital, for he had a troublesome superabundance of that sort of time
+which is not money. "Where'll we dig?" said Huck.
+
+"Oh, most anywhere."
+
+"Why, is it hid all around?"
+
+"No, indeed it ain't. It's hid in mighty particular places, Huck
+--sometimes on islands, sometimes in rotten chests under the end of a
+limb of an old dead tree, just where the shadow falls at midnight; but
+mostly under the floor in ha'nted houses."
+
+"Who hides it?"
+
+"Why, robbers, of course--who'd you reckon? Sunday-school
+sup'rintendents?"
+
+"I don't know. If 'twas mine I wouldn't hide it; I'd spend it and have
+a good time."
+
+"So would I. But robbers don't do that way. They always hide it and
+leave it there."
+
+"Don't they come after it any more?"
+
+"No, they think they will, but they generally forget the marks, or
+else they die. Anyway, it lays there a long time and gets rusty; and by
+and by somebody finds an old yellow paper that tells how to find the
+marks--a paper that's got to be ciphered over about a week because it's
+mostly signs and hy'roglyphics."
+
+"Hyro--which?"
+
+"Hy'roglyphics--pictures and things, you know, that don't seem to mean
+anything."
+
+"Have you got one of them papers, Tom?"
+
+"No."
+
+"Well then, how you going to find the marks?"
+
+"I don't want any marks. They always bury it under a ha'nted house or
+on an island, or under a dead tree that's got one limb sticking out.
+Well, we've tried Jackson's Island a little, and we can try it again
+some time; and there's the old ha'nted house up the Still-House branch,
+and there's lots of dead-limb trees--dead loads of 'em."
+
+"Is it under all of them?"
+
+"How you talk! No!"
+
+"Then how you going to know which one to go for?"
+
+"Go for all of 'em!"
+
+"Why, Tom, it'll take all summer."
+
+"Well, what of that? Suppose you find a brass pot with a hundred
+dollars in it, all rusty and gray, or rotten chest full of di'monds.
+How's that?"
+
+Huck's eyes glowed.
+
+"That's bully. Plenty bully enough for me. Just you gimme the hundred
+dollars and I don't want no di'monds."
+
+"All right. But I bet you I ain't going to throw off on di'monds. Some
+of 'em's worth twenty dollars apiece--there ain't any, hardly, but's
+worth six bits or a dollar."
+
+"No! Is that so?"
+
+"Cert'nly--anybody'll tell you so. Hain't you ever seen one, Huck?"
+
+"Not as I remember."
+
+"Oh, kings have slathers of them."
+
+"Well, I don' know no kings, Tom."
+
+"I reckon you don't. But if you was to go to Europe you'd see a raft
+of 'em hopping around."
+
+"Do they hop?"
+
+"Hop?--your granny! No!"
+
+"Well, what did you say they did, for?"
+
+"Shucks, I only meant you'd SEE 'em--not hopping, of course--what do
+they want to hop for?--but I mean you'd just see 'em--scattered around,
+you know, in a kind of a general way. Like that old humpbacked Richard."
+
+"Richard? What's his other name?"
+
+"He didn't have any other name. Kings don't have any but a given name."
+
+"No?"
+
+"But they don't."
+
+"Well, if they like it, Tom, all right; but I don't want to be a king
+and have only just a given name, like a nigger. But say--where you
+going to dig first?"
+
+"Well, I don't know. S'pose we tackle that old dead-limb tree on the
+hill t'other side of Still-House branch?"
+
+"I'm agreed."
+
+So they got a crippled pick and a shovel, and set out on their
+three-mile tramp. They arrived hot and panting, and threw themselves
+down in the shade of a neighboring elm to rest and have a smoke.
+
+"I like this," said Tom.
+
+"So do I."
+
+"Say, Huck, if we find a treasure here, what you going to do with your
+share?"
+
+"Well, I'll have pie and a glass of soda every day, and I'll go to
+every circus that comes along. I bet I'll have a gay time."
+
+"Well, ain't you going to save any of it?"
+
+"Save it? What for?"
+
+"Why, so as to have something to live on, by and by."
+
+"Oh, that ain't any use. Pap would come back to thish-yer town some
+day and get his claws on it if I didn't hurry up, and I tell you he'd
+clean it out pretty quick. What you going to do with yourn, Tom?"
+
+"I'm going to buy a new drum, and a sure-'nough sword, and a red
+necktie and a bull pup, and get married."
+
+"Married!"
+
+"That's it."
+
+"Tom, you--why, you ain't in your right mind."
+
+"Wait--you'll see."
+
+"Well, that's the foolishest thing you could do. Look at pap and my
+mother. Fight! Why, they used to fight all the time. I remember, mighty
+well."
+
+"That ain't anything. The girl I'm going to marry won't fight."
+
+"Tom, I reckon they're all alike. They'll all comb a body. Now you
+better think 'bout this awhile. I tell you you better. What's the name
+of the gal?"
+
+"It ain't a gal at all--it's a girl."
+
+"It's all the same, I reckon; some says gal, some says girl--both's
+right, like enough. Anyway, what's her name, Tom?"
+
+"I'll tell you some time--not now."
+
+"All right--that'll do. Only if you get married I'll be more lonesomer
+than ever."
+
+"No you won't. You'll come and live with me. Now stir out of this and
+we'll go to digging."
+
+They worked and sweated for half an hour. No result. They toiled
+another half-hour. Still no result. Huck said:
+
+"Do they always bury it as deep as this?"
+
+"Sometimes--not always. Not generally. I reckon we haven't got the
+right place."
+
+So they chose a new spot and began again. The labor dragged a little,
+but still they made progress. They pegged away in silence for some
+time. Finally Huck leaned on his shovel, swabbed the beaded drops from
+his brow with his sleeve, and said:
+
+"Where you going to dig next, after we get this one?"
+
+"I reckon maybe we'll tackle the old tree that's over yonder on
+Cardiff Hill back of the widow's."
+
+"I reckon that'll be a good one. But won't the widow take it away from
+us, Tom? It's on her land."
+
+"SHE take it away! Maybe she'd like to try it once. Whoever finds one
+of these hid treasures, it belongs to him. It don't make any difference
+whose land it's on."
+
+That was satisfactory. The work went on. By and by Huck said:
+
+"Blame it, we must be in the wrong place again. What do you think?"
+
+"It is mighty curious, Huck. I don't understand it. Sometimes witches
+interfere. I reckon maybe that's what's the trouble now."
+
+"Shucks! Witches ain't got no power in the daytime."
+
+"Well, that's so. I didn't think of that. Oh, I know what the matter
+is! What a blamed lot of fools we are! You got to find out where the
+shadow of the limb falls at midnight, and that's where you dig!"
+
+"Then consound it, we've fooled away all this work for nothing. Now
+hang it all, we got to come back in the night. It's an awful long way.
+Can you get out?"
+
+"I bet I will. We've got to do it to-night, too, because if somebody
+sees these holes they'll know in a minute what's here and they'll go
+for it."
+
+"Well, I'll come around and maow to-night."
+
+"All right. Let's hide the tools in the bushes."
+
+The boys were there that night, about the appointed time. They sat in
+the shadow waiting. It was a lonely place, and an hour made solemn by
+old traditions. Spirits whispered in the rustling leaves, ghosts lurked
+in the murky nooks, the deep baying of a hound floated up out of the
+distance, an owl answered with his sepulchral note. The boys were
+subdued by these solemnities, and talked little. By and by they judged
+that twelve had come; they marked where the shadow fell, and began to
+dig. Their hopes commenced to rise. Their interest grew stronger, and
+their industry kept pace with it. The hole deepened and still deepened,
+but every time their hearts jumped to hear the pick strike upon
+something, they only suffered a new disappointment. It was only a stone
+or a chunk. At last Tom said:
+
+"It ain't any use, Huck, we're wrong again."
+
+"Well, but we CAN'T be wrong. We spotted the shadder to a dot."
+
+"I know it, but then there's another thing."
+
+"What's that?".
+
+"Why, we only guessed at the time. Like enough it was too late or too
+early."
+
+Huck dropped his shovel.
+
+"That's it," said he. "That's the very trouble. We got to give this
+one up. We can't ever tell the right time, and besides this kind of
+thing's too awful, here this time of night with witches and ghosts
+a-fluttering around so. I feel as if something's behind me all the time;
+and I'm afeard to turn around, becuz maybe there's others in front
+a-waiting for a chance. I been creeping all over, ever since I got here."
+
+"Well, I've been pretty much so, too, Huck. They most always put in a
+dead man when they bury a treasure under a tree, to look out for it."
+
+"Lordy!"
+
+"Yes, they do. I've always heard that."
+
+"Tom, I don't like to fool around much where there's dead people. A
+body's bound to get into trouble with 'em, sure."
+
+"I don't like to stir 'em up, either. S'pose this one here was to
+stick his skull out and say something!"
+
+"Don't Tom! It's awful."
+
+"Well, it just is. Huck, I don't feel comfortable a bit."
+
+"Say, Tom, let's give this place up, and try somewheres else."
+
+"All right, I reckon we better."
+
+"What'll it be?"
+
+Tom considered awhile; and then said:
+
+"The ha'nted house. That's it!"
+
+"Blame it, I don't like ha'nted houses, Tom. Why, they're a dern sight
+worse'n dead people. Dead people might talk, maybe, but they don't come
+sliding around in a shroud, when you ain't noticing, and peep over your
+shoulder all of a sudden and grit their teeth, the way a ghost does. I
+couldn't stand such a thing as that, Tom--nobody could."
+
+"Yes, but, Huck, ghosts don't travel around only at night. They won't
+hender us from digging there in the daytime."
+
+"Well, that's so. But you know mighty well people don't go about that
+ha'nted house in the day nor the night."
+
+"Well, that's mostly because they don't like to go where a man's been
+murdered, anyway--but nothing's ever been seen around that house except
+in the night--just some blue lights slipping by the windows--no regular
+ghosts."
+
+"Well, where you see one of them blue lights flickering around, Tom,
+you can bet there's a ghost mighty close behind it. It stands to
+reason. Becuz you know that they don't anybody but ghosts use 'em."
+
+"Yes, that's so. But anyway they don't come around in the daytime, so
+what's the use of our being afeard?"
+
+"Well, all right. We'll tackle the ha'nted house if you say so--but I
+reckon it's taking chances."
+
+They had started down the hill by this time. There in the middle of
+the moonlit valley below them stood the "ha'nted" house, utterly
+isolated, its fences gone long ago, rank weeds smothering the very
+doorsteps, the chimney crumbled to ruin, the window-sashes vacant, a
+corner of the roof caved in. The boys gazed awhile, half expecting to
+see a blue light flit past a window; then talking in a low tone, as
+befitted the time and the circumstances, they struck far off to the
+right, to give the haunted house a wide berth, and took their way
+homeward through the woods that adorned the rearward side of Cardiff
+Hill.
+
+
+
+CHAPTER XXVI
+
+ABOUT noon the next day the boys arrived at the dead tree; they had
+come for their tools. Tom was impatient to go to the haunted house;
+Huck was measurably so, also--but suddenly said:
+
+"Lookyhere, Tom, do you know what day it is?"
+
+Tom mentally ran over the days of the week, and then quickly lifted
+his eyes with a startled look in them--
+
+"My! I never once thought of it, Huck!"
+
+"Well, I didn't neither, but all at once it popped onto me that it was
+Friday."
+
+"Blame it, a body can't be too careful, Huck. We might 'a' got into an
+awful scrape, tackling such a thing on a Friday."
+
+"MIGHT! Better say we WOULD! There's some lucky days, maybe, but
+Friday ain't."
+
+"Any fool knows that. I don't reckon YOU was the first that found it
+out, Huck."
+
+"Well, I never said I was, did I? And Friday ain't all, neither. I had
+a rotten bad dream last night--dreampt about rats."
+
+"No! Sure sign of trouble. Did they fight?"
+
+"No."
+
+"Well, that's good, Huck. When they don't fight it's only a sign that
+there's trouble around, you know. All we got to do is to look mighty
+sharp and keep out of it. We'll drop this thing for to-day, and play.
+Do you know Robin Hood, Huck?"
+
+"No. Who's Robin Hood?"
+
+"Why, he was one of the greatest men that was ever in England--and the
+best. He was a robber."
+
+"Cracky, I wisht I was. Who did he rob?"
+
+"Only sheriffs and bishops and rich people and kings, and such like.
+But he never bothered the poor. He loved 'em. He always divided up with
+'em perfectly square."
+
+"Well, he must 'a' been a brick."
+
+"I bet you he was, Huck. Oh, he was the noblest man that ever was.
+They ain't any such men now, I can tell you. He could lick any man in
+England, with one hand tied behind him; and he could take his yew bow
+and plug a ten-cent piece every time, a mile and a half."
+
+"What's a YEW bow?"
+
+"I don't know. It's some kind of a bow, of course. And if he hit that
+dime only on the edge he would set down and cry--and curse. But we'll
+play Robin Hood--it's nobby fun. I'll learn you."
+
+"I'm agreed."
+
+So they played Robin Hood all the afternoon, now and then casting a
+yearning eye down upon the haunted house and passing a remark about the
+morrow's prospects and possibilities there. As the sun began to sink
+into the west they took their way homeward athwart the long shadows of
+the trees and soon were buried from sight in the forests of Cardiff
+Hill.
+
+On Saturday, shortly after noon, the boys were at the dead tree again.
+They had a smoke and a chat in the shade, and then dug a little in
+their last hole, not with great hope, but merely because Tom said there
+were so many cases where people had given up a treasure after getting
+down within six inches of it, and then somebody else had come along and
+turned it up with a single thrust of a shovel. The thing failed this
+time, however, so the boys shouldered their tools and went away feeling
+that they had not trifled with fortune, but had fulfilled all the
+requirements that belong to the business of treasure-hunting.
+
+When they reached the haunted house there was something so weird and
+grisly about the dead silence that reigned there under the baking sun,
+and something so depressing about the loneliness and desolation of the
+place, that they were afraid, for a moment, to venture in. Then they
+crept to the door and took a trembling peep. They saw a weed-grown,
+floorless room, unplastered, an ancient fireplace, vacant windows, a
+ruinous staircase; and here, there, and everywhere hung ragged and
+abandoned cobwebs. They presently entered, softly, with quickened
+pulses, talking in whispers, ears alert to catch the slightest sound,
+and muscles tense and ready for instant retreat.
+
+In a little while familiarity modified their fears and they gave the
+place a critical and interested examination, rather admiring their own
+boldness, and wondering at it, too. Next they wanted to look up-stairs.
+This was something like cutting off retreat, but they got to daring
+each other, and of course there could be but one result--they threw
+their tools into a corner and made the ascent. Up there were the same
+signs of decay. In one corner they found a closet that promised
+mystery, but the promise was a fraud--there was nothing in it. Their
+courage was up now and well in hand. They were about to go down and
+begin work when--
+
+"Sh!" said Tom.
+
+"What is it?" whispered Huck, blanching with fright.
+
+"Sh!... There!... Hear it?"
+
+"Yes!... Oh, my! Let's run!"
+
+"Keep still! Don't you budge! They're coming right toward the door."
+
+The boys stretched themselves upon the floor with their eyes to
+knot-holes in the planking, and lay waiting, in a misery of fear.
+
+"They've stopped.... No--coming.... Here they are. Don't whisper
+another word, Huck. My goodness, I wish I was out of this!"
+
+Two men entered. Each boy said to himself: "There's the old deaf and
+dumb Spaniard that's been about town once or twice lately--never saw
+t'other man before."
+
+"T'other" was a ragged, unkempt creature, with nothing very pleasant
+in his face. The Spaniard was wrapped in a serape; he had bushy white
+whiskers; long white hair flowed from under his sombrero, and he wore
+green goggles. When they came in, "t'other" was talking in a low voice;
+they sat down on the ground, facing the door, with their backs to the
+wall, and the speaker continued his remarks. His manner became less
+guarded and his words more distinct as he proceeded:
+
+"No," said he, "I've thought it all over, and I don't like it. It's
+dangerous."
+
+"Dangerous!" grunted the "deaf and dumb" Spaniard--to the vast
+surprise of the boys. "Milksop!"
+
+This voice made the boys gasp and quake. It was Injun Joe's! There was
+silence for some time. Then Joe said:
+
+"What's any more dangerous than that job up yonder--but nothing's come
+of it."
+
+"That's different. Away up the river so, and not another house about.
+'Twon't ever be known that we tried, anyway, long as we didn't succeed."
+
+"Well, what's more dangerous than coming here in the daytime!--anybody
+would suspicion us that saw us."
+
+"I know that. But there warn't any other place as handy after that
+fool of a job. I want to quit this shanty. I wanted to yesterday, only
+it warn't any use trying to stir out of here, with those infernal boys
+playing over there on the hill right in full view."
+
+"Those infernal boys" quaked again under the inspiration of this
+remark, and thought how lucky it was that they had remembered it was
+Friday and concluded to wait a day. They wished in their hearts they
+had waited a year.
+
+The two men got out some food and made a luncheon. After a long and
+thoughtful silence, Injun Joe said:
+
+"Look here, lad--you go back up the river where you belong. Wait there
+till you hear from me. I'll take the chances on dropping into this town
+just once more, for a look. We'll do that 'dangerous' job after I've
+spied around a little and think things look well for it. Then for
+Texas! We'll leg it together!"
+
+This was satisfactory. Both men presently fell to yawning, and Injun
+Joe said:
+
+"I'm dead for sleep! It's your turn to watch."
+
+He curled down in the weeds and soon began to snore. His comrade
+stirred him once or twice and he became quiet. Presently the watcher
+began to nod; his head drooped lower and lower, both men began to snore
+now.
+
+The boys drew a long, grateful breath. Tom whispered:
+
+"Now's our chance--come!"
+
+Huck said:
+
+"I can't--I'd die if they was to wake."
+
+Tom urged--Huck held back. At last Tom rose slowly and softly, and
+started alone. But the first step he made wrung such a hideous creak
+from the crazy floor that he sank down almost dead with fright. He
+never made a second attempt. The boys lay there counting the dragging
+moments till it seemed to them that time must be done and eternity
+growing gray; and then they were grateful to note that at last the sun
+was setting.
+
+Now one snore ceased. Injun Joe sat up, stared around--smiled grimly
+upon his comrade, whose head was drooping upon his knees--stirred him
+up with his foot and said:
+
+"Here! YOU'RE a watchman, ain't you! All right, though--nothing's
+happened."
+
+"My! have I been asleep?"
+
+"Oh, partly, partly. Nearly time for us to be moving, pard. What'll we
+do with what little swag we've got left?"
+
+"I don't know--leave it here as we've always done, I reckon. No use to
+take it away till we start south. Six hundred and fifty in silver's
+something to carry."
+
+"Well--all right--it won't matter to come here once more."
+
+"No--but I'd say come in the night as we used to do--it's better."
+
+"Yes: but look here; it may be a good while before I get the right
+chance at that job; accidents might happen; 'tain't in such a very good
+place; we'll just regularly bury it--and bury it deep."
+
+"Good idea," said the comrade, who walked across the room, knelt down,
+raised one of the rearward hearth-stones and took out a bag that
+jingled pleasantly. He subtracted from it twenty or thirty dollars for
+himself and as much for Injun Joe, and passed the bag to the latter,
+who was on his knees in the corner, now, digging with his bowie-knife.
+
+The boys forgot all their fears, all their miseries in an instant.
+With gloating eyes they watched every movement. Luck!--the splendor of
+it was beyond all imagination! Six hundred dollars was money enough to
+make half a dozen boys rich! Here was treasure-hunting under the
+happiest auspices--there would not be any bothersome uncertainty as to
+where to dig. They nudged each other every moment--eloquent nudges and
+easily understood, for they simply meant--"Oh, but ain't you glad NOW
+we're here!"
+
+Joe's knife struck upon something.
+
+"Hello!" said he.
+
+"What is it?" said his comrade.
+
+"Half-rotten plank--no, it's a box, I believe. Here--bear a hand and
+we'll see what it's here for. Never mind, I've broke a hole."
+
+He reached his hand in and drew it out--
+
+"Man, it's money!"
+
+The two men examined the handful of coins. They were gold. The boys
+above were as excited as themselves, and as delighted.
+
+Joe's comrade said:
+
+"We'll make quick work of this. There's an old rusty pick over amongst
+the weeds in the corner the other side of the fireplace--I saw it a
+minute ago."
+
+He ran and brought the boys' pick and shovel. Injun Joe took the pick,
+looked it over critically, shook his head, muttered something to
+himself, and then began to use it. The box was soon unearthed. It was
+not very large; it was iron bound and had been very strong before the
+slow years had injured it. The men contemplated the treasure awhile in
+blissful silence.
+
+"Pard, there's thousands of dollars here," said Injun Joe.
+
+"'Twas always said that Murrel's gang used to be around here one
+summer," the stranger observed.
+
+"I know it," said Injun Joe; "and this looks like it, I should say."
+
+"Now you won't need to do that job."
+
+The half-breed frowned. Said he:
+
+"You don't know me. Least you don't know all about that thing. 'Tain't
+robbery altogether--it's REVENGE!" and a wicked light flamed in his
+eyes. "I'll need your help in it. When it's finished--then Texas. Go
+home to your Nance and your kids, and stand by till you hear from me."
+
+"Well--if you say so; what'll we do with this--bury it again?"
+
+"Yes. [Ravishing delight overhead.] NO! by the great Sachem, no!
+[Profound distress overhead.] I'd nearly forgot. That pick had fresh
+earth on it! [The boys were sick with terror in a moment.] What
+business has a pick and a shovel here? What business with fresh earth
+on them? Who brought them here--and where are they gone? Have you heard
+anybody?--seen anybody? What! bury it again and leave them to come and
+see the ground disturbed? Not exactly--not exactly. We'll take it to my
+den."
+
+"Why, of course! Might have thought of that before. You mean Number
+One?"
+
+"No--Number Two--under the cross. The other place is bad--too common."
+
+"All right. It's nearly dark enough to start."
+
+Injun Joe got up and went about from window to window cautiously
+peeping out. Presently he said:
+
+"Who could have brought those tools here? Do you reckon they can be
+up-stairs?"
+
+The boys' breath forsook them. Injun Joe put his hand on his knife,
+halted a moment, undecided, and then turned toward the stairway. The
+boys thought of the closet, but their strength was gone. The steps came
+creaking up the stairs--the intolerable distress of the situation woke
+the stricken resolution of the lads--they were about to spring for the
+closet, when there was a crash of rotten timbers and Injun Joe landed
+on the ground amid the debris of the ruined stairway. He gathered
+himself up cursing, and his comrade said:
+
+"Now what's the use of all that? If it's anybody, and they're up
+there, let them STAY there--who cares? If they want to jump down, now,
+and get into trouble, who objects? It will be dark in fifteen minutes
+--and then let them follow us if they want to. I'm willing. In my
+opinion, whoever hove those things in here caught a sight of us and
+took us for ghosts or devils or something. I'll bet they're running
+yet."
+
+Joe grumbled awhile; then he agreed with his friend that what daylight
+was left ought to be economized in getting things ready for leaving.
+Shortly afterward they slipped out of the house in the deepening
+twilight, and moved toward the river with their precious box.
+
+Tom and Huck rose up, weak but vastly relieved, and stared after them
+through the chinks between the logs of the house. Follow? Not they.
+They were content to reach ground again without broken necks, and take
+the townward track over the hill. They did not talk much. They were too
+much absorbed in hating themselves--hating the ill luck that made them
+take the spade and the pick there. But for that, Injun Joe never would
+have suspected. He would have hidden the silver with the gold to wait
+there till his "revenge" was satisfied, and then he would have had the
+misfortune to find that money turn up missing. Bitter, bitter luck that
+the tools were ever brought there!
+
+They resolved to keep a lookout for that Spaniard when he should come
+to town spying out for chances to do his revengeful job, and follow him
+to "Number Two," wherever that might be. Then a ghastly thought
+occurred to Tom.
+
+"Revenge? What if he means US, Huck!"
+
+"Oh, don't!" said Huck, nearly fainting.
+
+They talked it all over, and as they entered town they agreed to
+believe that he might possibly mean somebody else--at least that he
+might at least mean nobody but Tom, since only Tom had testified.
+
+Very, very small comfort it was to Tom to be alone in danger! Company
+would be a palpable improvement, he thought.
+
+
+
+CHAPTER XXVII
+
+THE adventure of the day mightily tormented Tom's dreams that night.
+Four times he had his hands on that rich treasure and four times it
+wasted to nothingness in his fingers as sleep forsook him and
+wakefulness brought back the hard reality of his misfortune. As he lay
+in the early morning recalling the incidents of his great adventure, he
+noticed that they seemed curiously subdued and far away--somewhat as if
+they had happened in another world, or in a time long gone by. Then it
+occurred to him that the great adventure itself must be a dream! There
+was one very strong argument in favor of this idea--namely, that the
+quantity of coin he had seen was too vast to be real. He had never seen
+as much as fifty dollars in one mass before, and he was like all boys
+of his age and station in life, in that he imagined that all references
+to "hundreds" and "thousands" were mere fanciful forms of speech, and
+that no such sums really existed in the world. He never had supposed
+for a moment that so large a sum as a hundred dollars was to be found
+in actual money in any one's possession. If his notions of hidden
+treasure had been analyzed, they would have been found to consist of a
+handful of real dimes and a bushel of vague, splendid, ungraspable
+dollars.
+
+But the incidents of his adventure grew sensibly sharper and clearer
+under the attrition of thinking them over, and so he presently found
+himself leaning to the impression that the thing might not have been a
+dream, after all. This uncertainty must be swept away. He would snatch
+a hurried breakfast and go and find Huck. Huck was sitting on the
+gunwale of a flatboat, listlessly dangling his feet in the water and
+looking very melancholy. Tom concluded to let Huck lead up to the
+subject. If he did not do it, then the adventure would be proved to
+have been only a dream.
+
+"Hello, Huck!"
+
+"Hello, yourself."
+
+Silence, for a minute.
+
+"Tom, if we'd 'a' left the blame tools at the dead tree, we'd 'a' got
+the money. Oh, ain't it awful!"
+
+"'Tain't a dream, then, 'tain't a dream! Somehow I most wish it was.
+Dog'd if I don't, Huck."
+
+"What ain't a dream?"
+
+"Oh, that thing yesterday. I been half thinking it was."
+
+"Dream! If them stairs hadn't broke down you'd 'a' seen how much dream
+it was! I've had dreams enough all night--with that patch-eyed Spanish
+devil going for me all through 'em--rot him!"
+
+"No, not rot him. FIND him! Track the money!"
+
+"Tom, we'll never find him. A feller don't have only one chance for
+such a pile--and that one's lost. I'd feel mighty shaky if I was to see
+him, anyway."
+
+"Well, so'd I; but I'd like to see him, anyway--and track him out--to
+his Number Two."
+
+"Number Two--yes, that's it. I been thinking 'bout that. But I can't
+make nothing out of it. What do you reckon it is?"
+
+"I dono. It's too deep. Say, Huck--maybe it's the number of a house!"
+
+"Goody!... No, Tom, that ain't it. If it is, it ain't in this
+one-horse town. They ain't no numbers here."
+
+"Well, that's so. Lemme think a minute. Here--it's the number of a
+room--in a tavern, you know!"
+
+"Oh, that's the trick! They ain't only two taverns. We can find out
+quick."
+
+"You stay here, Huck, till I come."
+
+Tom was off at once. He did not care to have Huck's company in public
+places. He was gone half an hour. He found that in the best tavern, No.
+2 had long been occupied by a young lawyer, and was still so occupied.
+In the less ostentatious house, No. 2 was a mystery. The
+tavern-keeper's young son said it was kept locked all the time, and he
+never saw anybody go into it or come out of it except at night; he did
+not know any particular reason for this state of things; had had some
+little curiosity, but it was rather feeble; had made the most of the
+mystery by entertaining himself with the idea that that room was
+"ha'nted"; had noticed that there was a light in there the night before.
+
+"That's what I've found out, Huck. I reckon that's the very No. 2
+we're after."
+
+"I reckon it is, Tom. Now what you going to do?"
+
+"Lemme think."
+
+Tom thought a long time. Then he said:
+
+"I'll tell you. The back door of that No. 2 is the door that comes out
+into that little close alley between the tavern and the old rattle trap
+of a brick store. Now you get hold of all the door-keys you can find,
+and I'll nip all of auntie's, and the first dark night we'll go there
+and try 'em. And mind you, keep a lookout for Injun Joe, because he
+said he was going to drop into town and spy around once more for a
+chance to get his revenge. If you see him, you just follow him; and if
+he don't go to that No. 2, that ain't the place."
+
+"Lordy, I don't want to foller him by myself!"
+
+"Why, it'll be night, sure. He mightn't ever see you--and if he did,
+maybe he'd never think anything."
+
+"Well, if it's pretty dark I reckon I'll track him. I dono--I dono.
+I'll try."
+
+"You bet I'll follow him, if it's dark, Huck. Why, he might 'a' found
+out he couldn't get his revenge, and be going right after that money."
+
+"It's so, Tom, it's so. I'll foller him; I will, by jingoes!"
+
+"Now you're TALKING! Don't you ever weaken, Huck, and I won't."
+
+
+
+CHAPTER XXVIII
+
+THAT night Tom and Huck were ready for their adventure. They hung
+about the neighborhood of the tavern until after nine, one watching the
+alley at a distance and the other the tavern door. Nobody entered the
+alley or left it; nobody resembling the Spaniard entered or left the
+tavern door. The night promised to be a fair one; so Tom went home with
+the understanding that if a considerable degree of darkness came on,
+Huck was to come and "maow," whereupon he would slip out and try the
+keys. But the night remained clear, and Huck closed his watch and
+retired to bed in an empty sugar hogshead about twelve.
+
+Tuesday the boys had the same ill luck. Also Wednesday. But Thursday
+night promised better. Tom slipped out in good season with his aunt's
+old tin lantern, and a large towel to blindfold it with. He hid the
+lantern in Huck's sugar hogshead and the watch began. An hour before
+midnight the tavern closed up and its lights (the only ones
+thereabouts) were put out. No Spaniard had been seen. Nobody had
+entered or left the alley. Everything was auspicious. The blackness of
+darkness reigned, the perfect stillness was interrupted only by
+occasional mutterings of distant thunder.
+
+Tom got his lantern, lit it in the hogshead, wrapped it closely in the
+towel, and the two adventurers crept in the gloom toward the tavern.
+Huck stood sentry and Tom felt his way into the alley. Then there was a
+season of waiting anxiety that weighed upon Huck's spirits like a
+mountain. He began to wish he could see a flash from the lantern--it
+would frighten him, but it would at least tell him that Tom was alive
+yet. It seemed hours since Tom had disappeared. Surely he must have
+fainted; maybe he was dead; maybe his heart had burst under terror and
+excitement. In his uneasiness Huck found himself drawing closer and
+closer to the alley; fearing all sorts of dreadful things, and
+momentarily expecting some catastrophe to happen that would take away
+his breath. There was not much to take away, for he seemed only able to
+inhale it by thimblefuls, and his heart would soon wear itself out, the
+way it was beating. Suddenly there was a flash of light and Tom came
+tearing by him: "Run!" said he; "run, for your life!"
+
+He needn't have repeated it; once was enough; Huck was making thirty
+or forty miles an hour before the repetition was uttered. The boys
+never stopped till they reached the shed of a deserted slaughter-house
+at the lower end of the village. Just as they got within its shelter
+the storm burst and the rain poured down. As soon as Tom got his breath
+he said:
+
+"Huck, it was awful! I tried two of the keys, just as soft as I could;
+but they seemed to make such a power of racket that I couldn't hardly
+get my breath I was so scared. They wouldn't turn in the lock, either.
+Well, without noticing what I was doing, I took hold of the knob, and
+open comes the door! It warn't locked! I hopped in, and shook off the
+towel, and, GREAT CAESAR'S GHOST!"
+
+"What!--what'd you see, Tom?"
+
+"Huck, I most stepped onto Injun Joe's hand!"
+
+"No!"
+
+"Yes! He was lying there, sound asleep on the floor, with his old
+patch on his eye and his arms spread out."
+
+"Lordy, what did you do? Did he wake up?"
+
+"No, never budged. Drunk, I reckon. I just grabbed that towel and
+started!"
+
+"I'd never 'a' thought of the towel, I bet!"
+
+"Well, I would. My aunt would make me mighty sick if I lost it."
+
+"Say, Tom, did you see that box?"
+
+"Huck, I didn't wait to look around. I didn't see the box, I didn't
+see the cross. I didn't see anything but a bottle and a tin cup on the
+floor by Injun Joe; yes, I saw two barrels and lots more bottles in the
+room. Don't you see, now, what's the matter with that ha'nted room?"
+
+"How?"
+
+"Why, it's ha'nted with whiskey! Maybe ALL the Temperance Taverns have
+got a ha'nted room, hey, Huck?"
+
+"Well, I reckon maybe that's so. Who'd 'a' thought such a thing? But
+say, Tom, now's a mighty good time to get that box, if Injun Joe's
+drunk."
+
+"It is, that! You try it!"
+
+Huck shuddered.
+
+"Well, no--I reckon not."
+
+"And I reckon not, Huck. Only one bottle alongside of Injun Joe ain't
+enough. If there'd been three, he'd be drunk enough and I'd do it."
+
+There was a long pause for reflection, and then Tom said:
+
+"Lookyhere, Huck, less not try that thing any more till we know Injun
+Joe's not in there. It's too scary. Now, if we watch every night, we'll
+be dead sure to see him go out, some time or other, and then we'll
+snatch that box quicker'n lightning."
+
+"Well, I'm agreed. I'll watch the whole night long, and I'll do it
+every night, too, if you'll do the other part of the job."
+
+"All right, I will. All you got to do is to trot up Hooper Street a
+block and maow--and if I'm asleep, you throw some gravel at the window
+and that'll fetch me."
+
+"Agreed, and good as wheat!"
+
+"Now, Huck, the storm's over, and I'll go home. It'll begin to be
+daylight in a couple of hours. You go back and watch that long, will
+you?"
+
+"I said I would, Tom, and I will. I'll ha'nt that tavern every night
+for a year! I'll sleep all day and I'll stand watch all night."
+
+"That's all right. Now, where you going to sleep?"
+
+"In Ben Rogers' hayloft. He lets me, and so does his pap's nigger man,
+Uncle Jake. I tote water for Uncle Jake whenever he wants me to, and
+any time I ask him he gives me a little something to eat if he can
+spare it. That's a mighty good nigger, Tom. He likes me, becuz I don't
+ever act as if I was above him. Sometime I've set right down and eat
+WITH him. But you needn't tell that. A body's got to do things when
+he's awful hungry he wouldn't want to do as a steady thing."
+
+"Well, if I don't want you in the daytime, I'll let you sleep. I won't
+come bothering around. Any time you see something's up, in the night,
+just skip right around and maow."
+
+
+
+CHAPTER XXIX
+
+THE first thing Tom heard on Friday morning was a glad piece of news
+--Judge Thatcher's family had come back to town the night before. Both
+Injun Joe and the treasure sunk into secondary importance for a moment,
+and Becky took the chief place in the boy's interest. He saw her and
+they had an exhausting good time playing "hi-spy" and "gully-keeper"
+with a crowd of their school-mates. The day was completed and crowned
+in a peculiarly satisfactory way: Becky teased her mother to appoint
+the next day for the long-promised and long-delayed picnic, and she
+consented. The child's delight was boundless; and Tom's not more
+moderate. The invitations were sent out before sunset, and straightway
+the young folks of the village were thrown into a fever of preparation
+and pleasurable anticipation. Tom's excitement enabled him to keep
+awake until a pretty late hour, and he had good hopes of hearing Huck's
+"maow," and of having his treasure to astonish Becky and the picnickers
+with, next day; but he was disappointed. No signal came that night.
+
+Morning came, eventually, and by ten or eleven o'clock a giddy and
+rollicking company were gathered at Judge Thatcher's, and everything
+was ready for a start. It was not the custom for elderly people to mar
+the picnics with their presence. The children were considered safe
+enough under the wings of a few young ladies of eighteen and a few
+young gentlemen of twenty-three or thereabouts. The old steam ferryboat
+was chartered for the occasion; presently the gay throng filed up the
+main street laden with provision-baskets. Sid was sick and had to miss
+the fun; Mary remained at home to entertain him. The last thing Mrs.
+Thatcher said to Becky, was:
+
+"You'll not get back till late. Perhaps you'd better stay all night
+with some of the girls that live near the ferry-landing, child."
+
+"Then I'll stay with Susy Harper, mamma."
+
+"Very well. And mind and behave yourself and don't be any trouble."
+
+Presently, as they tripped along, Tom said to Becky:
+
+"Say--I'll tell you what we'll do. 'Stead of going to Joe Harper's
+we'll climb right up the hill and stop at the Widow Douglas'. She'll
+have ice-cream! She has it most every day--dead loads of it. And she'll
+be awful glad to have us."
+
+"Oh, that will be fun!"
+
+Then Becky reflected a moment and said:
+
+"But what will mamma say?"
+
+"How'll she ever know?"
+
+The girl turned the idea over in her mind, and said reluctantly:
+
+"I reckon it's wrong--but--"
+
+"But shucks! Your mother won't know, and so what's the harm? All she
+wants is that you'll be safe; and I bet you she'd 'a' said go there if
+she'd 'a' thought of it. I know she would!"
+
+The Widow Douglas' splendid hospitality was a tempting bait. It and
+Tom's persuasions presently carried the day. So it was decided to say
+nothing anybody about the night's programme. Presently it occurred to
+Tom that maybe Huck might come this very night and give the signal. The
+thought took a deal of the spirit out of his anticipations. Still he
+could not bear to give up the fun at Widow Douglas'. And why should he
+give it up, he reasoned--the signal did not come the night before, so
+why should it be any more likely to come to-night? The sure fun of the
+evening outweighed the uncertain treasure; and, boy-like, he determined
+to yield to the stronger inclination and not allow himself to think of
+the box of money another time that day.
+
+Three miles below town the ferryboat stopped at the mouth of a woody
+hollow and tied up. The crowd swarmed ashore and soon the forest
+distances and craggy heights echoed far and near with shoutings and
+laughter. All the different ways of getting hot and tired were gone
+through with, and by-and-by the rovers straggled back to camp fortified
+with responsible appetites, and then the destruction of the good things
+began. After the feast there was a refreshing season of rest and chat
+in the shade of spreading oaks. By-and-by somebody shouted:
+
+"Who's ready for the cave?"
+
+Everybody was. Bundles of candles were procured, and straightway there
+was a general scamper up the hill. The mouth of the cave was up the
+hillside--an opening shaped like a letter A. Its massive oaken door
+stood unbarred. Within was a small chamber, chilly as an ice-house, and
+walled by Nature with solid limestone that was dewy with a cold sweat.
+It was romantic and mysterious to stand here in the deep gloom and look
+out upon the green valley shining in the sun. But the impressiveness of
+the situation quickly wore off, and the romping began again. The moment
+a candle was lighted there was a general rush upon the owner of it; a
+struggle and a gallant defence followed, but the candle was soon
+knocked down or blown out, and then there was a glad clamor of laughter
+and a new chase. But all things have an end. By-and-by the procession
+went filing down the steep descent of the main avenue, the flickering
+rank of lights dimly revealing the lofty walls of rock almost to their
+point of junction sixty feet overhead. This main avenue was not more
+than eight or ten feet wide. Every few steps other lofty and still
+narrower crevices branched from it on either hand--for McDougal's cave
+was but a vast labyrinth of crooked aisles that ran into each other and
+out again and led nowhere. It was said that one might wander days and
+nights together through its intricate tangle of rifts and chasms, and
+never find the end of the cave; and that he might go down, and down,
+and still down, into the earth, and it was just the same--labyrinth
+under labyrinth, and no end to any of them. No man "knew" the cave.
+That was an impossible thing. Most of the young men knew a portion of
+it, and it was not customary to venture much beyond this known portion.
+Tom Sawyer knew as much of the cave as any one.
+
+The procession moved along the main avenue some three-quarters of a
+mile, and then groups and couples began to slip aside into branch
+avenues, fly along the dismal corridors, and take each other by
+surprise at points where the corridors joined again. Parties were able
+to elude each other for the space of half an hour without going beyond
+the "known" ground.
+
+By-and-by, one group after another came straggling back to the mouth
+of the cave, panting, hilarious, smeared from head to foot with tallow
+drippings, daubed with clay, and entirely delighted with the success of
+the day. Then they were astonished to find that they had been taking no
+note of time and that night was about at hand. The clanging bell had
+been calling for half an hour. However, this sort of close to the day's
+adventures was romantic and therefore satisfactory. When the ferryboat
+with her wild freight pushed into the stream, nobody cared sixpence for
+the wasted time but the captain of the craft.
+
+Huck was already upon his watch when the ferryboat's lights went
+glinting past the wharf. He heard no noise on board, for the young
+people were as subdued and still as people usually are who are nearly
+tired to death. He wondered what boat it was, and why she did not stop
+at the wharf--and then he dropped her out of his mind and put his
+attention upon his business. The night was growing cloudy and dark. Ten
+o'clock came, and the noise of vehicles ceased, scattered lights began
+to wink out, all straggling foot-passengers disappeared, the village
+betook itself to its slumbers and left the small watcher alone with the
+silence and the ghosts. Eleven o'clock came, and the tavern lights were
+put out; darkness everywhere, now. Huck waited what seemed a weary long
+time, but nothing happened. His faith was weakening. Was there any use?
+Was there really any use? Why not give it up and turn in?
+
+A noise fell upon his ear. He was all attention in an instant. The
+alley door closed softly. He sprang to the corner of the brick store.
+The next moment two men brushed by him, and one seemed to have
+something under his arm. It must be that box! So they were going to
+remove the treasure. Why call Tom now? It would be absurd--the men
+would get away with the box and never be found again. No, he would
+stick to their wake and follow them; he would trust to the darkness for
+security from discovery. So communing with himself, Huck stepped out
+and glided along behind the men, cat-like, with bare feet, allowing
+them to keep just far enough ahead not to be invisible.
+
+They moved up the river street three blocks, then turned to the left
+up a cross-street. They went straight ahead, then, until they came to
+the path that led up Cardiff Hill; this they took. They passed by the
+old Welshman's house, half-way up the hill, without hesitating, and
+still climbed upward. Good, thought Huck, they will bury it in the old
+quarry. But they never stopped at the quarry. They passed on, up the
+summit. They plunged into the narrow path between the tall sumach
+bushes, and were at once hidden in the gloom. Huck closed up and
+shortened his distance, now, for they would never be able to see him.
+He trotted along awhile; then slackened his pace, fearing he was
+gaining too fast; moved on a piece, then stopped altogether; listened;
+no sound; none, save that he seemed to hear the beating of his own
+heart. The hooting of an owl came over the hill--ominous sound! But no
+footsteps. Heavens, was everything lost! He was about to spring with
+winged feet, when a man cleared his throat not four feet from him!
+Huck's heart shot into his throat, but he swallowed it again; and then
+he stood there shaking as if a dozen agues had taken charge of him at
+once, and so weak that he thought he must surely fall to the ground. He
+knew where he was. He knew he was within five steps of the stile
+leading into Widow Douglas' grounds. Very well, he thought, let them
+bury it there; it won't be hard to find.
+
+Now there was a voice--a very low voice--Injun Joe's:
+
+"Damn her, maybe she's got company--there's lights, late as it is."
+
+"I can't see any."
+
+This was that stranger's voice--the stranger of the haunted house. A
+deadly chill went to Huck's heart--this, then, was the "revenge" job!
+His thought was, to fly. Then he remembered that the Widow Douglas had
+been kind to him more than once, and maybe these men were going to
+murder her. He wished he dared venture to warn her; but he knew he
+didn't dare--they might come and catch him. He thought all this and
+more in the moment that elapsed between the stranger's remark and Injun
+Joe's next--which was--
+
+"Because the bush is in your way. Now--this way--now you see, don't
+you?"
+
+"Yes. Well, there IS company there, I reckon. Better give it up."
+
+"Give it up, and I just leaving this country forever! Give it up and
+maybe never have another chance. I tell you again, as I've told you
+before, I don't care for her swag--you may have it. But her husband was
+rough on me--many times he was rough on me--and mainly he was the
+justice of the peace that jugged me for a vagrant. And that ain't all.
+It ain't a millionth part of it! He had me HORSEWHIPPED!--horsewhipped
+in front of the jail, like a nigger!--with all the town looking on!
+HORSEWHIPPED!--do you understand? He took advantage of me and died. But
+I'll take it out of HER."
+
+"Oh, don't kill her! Don't do that!"
+
+"Kill? Who said anything about killing? I would kill HIM if he was
+here; but not her. When you want to get revenge on a woman you don't
+kill her--bosh! you go for her looks. You slit her nostrils--you notch
+her ears like a sow!"
+
+"By God, that's--"
+
+"Keep your opinion to yourself! It will be safest for you. I'll tie
+her to the bed. If she bleeds to death, is that my fault? I'll not cry,
+if she does. My friend, you'll help me in this thing--for MY sake
+--that's why you're here--I mightn't be able alone. If you flinch, I'll
+kill you. Do you understand that? And if I have to kill you, I'll kill
+her--and then I reckon nobody'll ever know much about who done this
+business."
+
+"Well, if it's got to be done, let's get at it. The quicker the
+better--I'm all in a shiver."
+
+"Do it NOW? And company there? Look here--I'll get suspicious of you,
+first thing you know. No--we'll wait till the lights are out--there's
+no hurry."
+
+Huck felt that a silence was going to ensue--a thing still more awful
+than any amount of murderous talk; so he held his breath and stepped
+gingerly back; planted his foot carefully and firmly, after balancing,
+one-legged, in a precarious way and almost toppling over, first on one
+side and then on the other. He took another step back, with the same
+elaboration and the same risks; then another and another, and--a twig
+snapped under his foot! His breath stopped and he listened. There was
+no sound--the stillness was perfect. His gratitude was measureless. Now
+he turned in his tracks, between the walls of sumach bushes--turned
+himself as carefully as if he were a ship--and then stepped quickly but
+cautiously along. When he emerged at the quarry he felt secure, and so
+he picked up his nimble heels and flew. Down, down he sped, till he
+reached the Welshman's. He banged at the door, and presently the heads
+of the old man and his two stalwart sons were thrust from windows.
+
+"What's the row there? Who's banging? What do you want?"
+
+"Let me in--quick! I'll tell everything."
+
+"Why, who are you?"
+
+"Huckleberry Finn--quick, let me in!"
+
+"Huckleberry Finn, indeed! It ain't a name to open many doors, I
+judge! But let him in, lads, and let's see what's the trouble."
+
+"Please don't ever tell I told you," were Huck's first words when he
+got in. "Please don't--I'd be killed, sure--but the widow's been good
+friends to me sometimes, and I want to tell--I WILL tell if you'll
+promise you won't ever say it was me."
+
+"By George, he HAS got something to tell, or he wouldn't act so!"
+exclaimed the old man; "out with it and nobody here'll ever tell, lad."
+
+Three minutes later the old man and his sons, well armed, were up the
+hill, and just entering the sumach path on tiptoe, their weapons in
+their hands. Huck accompanied them no further. He hid behind a great
+bowlder and fell to listening. There was a lagging, anxious silence,
+and then all of a sudden there was an explosion of firearms and a cry.
+
+Huck waited for no particulars. He sprang away and sped down the hill
+as fast as his legs could carry him.
+
+
+
+CHAPTER XXX
+
+AS the earliest suspicion of dawn appeared on Sunday morning, Huck
+came groping up the hill and rapped gently at the old Welshman's door.
+The inmates were asleep, but it was a sleep that was set on a
+hair-trigger, on account of the exciting episode of the night. A call
+came from a window:
+
+"Who's there!"
+
+Huck's scared voice answered in a low tone:
+
+"Please let me in! It's only Huck Finn!"
+
+"It's a name that can open this door night or day, lad!--and welcome!"
+
+These were strange words to the vagabond boy's ears, and the
+pleasantest he had ever heard. He could not recollect that the closing
+word had ever been applied in his case before. The door was quickly
+unlocked, and he entered. Huck was given a seat and the old man and his
+brace of tall sons speedily dressed themselves.
+
+"Now, my boy, I hope you're good and hungry, because breakfast will be
+ready as soon as the sun's up, and we'll have a piping hot one, too
+--make yourself easy about that! I and the boys hoped you'd turn up and
+stop here last night."
+
+"I was awful scared," said Huck, "and I run. I took out when the
+pistols went off, and I didn't stop for three mile. I've come now becuz
+I wanted to know about it, you know; and I come before daylight becuz I
+didn't want to run across them devils, even if they was dead."
+
+"Well, poor chap, you do look as if you'd had a hard night of it--but
+there's a bed here for you when you've had your breakfast. No, they
+ain't dead, lad--we are sorry enough for that. You see we knew right
+where to put our hands on them, by your description; so we crept along
+on tiptoe till we got within fifteen feet of them--dark as a cellar
+that sumach path was--and just then I found I was going to sneeze. It
+was the meanest kind of luck! I tried to keep it back, but no use
+--'twas bound to come, and it did come! I was in the lead with my pistol
+raised, and when the sneeze started those scoundrels a-rustling to get
+out of the path, I sung out, 'Fire boys!' and blazed away at the place
+where the rustling was. So did the boys. But they were off in a jiffy,
+those villains, and we after them, down through the woods. I judge we
+never touched them. They fired a shot apiece as they started, but their
+bullets whizzed by and didn't do us any harm. As soon as we lost the
+sound of their feet we quit chasing, and went down and stirred up the
+constables. They got a posse together, and went off to guard the river
+bank, and as soon as it is light the sheriff and a gang are going to
+beat up the woods. My boys will be with them presently. I wish we had
+some sort of description of those rascals--'twould help a good deal.
+But you couldn't see what they were like, in the dark, lad, I suppose?"
+
+"Oh yes; I saw them down-town and follered them."
+
+"Splendid! Describe them--describe them, my boy!"
+
+"One's the old deaf and dumb Spaniard that's ben around here once or
+twice, and t'other's a mean-looking, ragged--"
+
+"That's enough, lad, we know the men! Happened on them in the woods
+back of the widow's one day, and they slunk away. Off with you, boys,
+and tell the sheriff--get your breakfast to-morrow morning!"
+
+The Welshman's sons departed at once. As they were leaving the room
+Huck sprang up and exclaimed:
+
+"Oh, please don't tell ANYbody it was me that blowed on them! Oh,
+please!"
+
+"All right if you say it, Huck, but you ought to have the credit of
+what you did."
+
+"Oh no, no! Please don't tell!"
+
+When the young men were gone, the old Welshman said:
+
+"They won't tell--and I won't. But why don't you want it known?"
+
+Huck would not explain, further than to say that he already knew too
+much about one of those men and would not have the man know that he
+knew anything against him for the whole world--he would be killed for
+knowing it, sure.
+
+The old man promised secrecy once more, and said:
+
+"How did you come to follow these fellows, lad? Were they looking
+suspicious?"
+
+Huck was silent while he framed a duly cautious reply. Then he said:
+
+"Well, you see, I'm a kind of a hard lot,--least everybody says so,
+and I don't see nothing agin it--and sometimes I can't sleep much, on
+account of thinking about it and sort of trying to strike out a new way
+of doing. That was the way of it last night. I couldn't sleep, and so I
+come along up-street 'bout midnight, a-turning it all over, and when I
+got to that old shackly brick store by the Temperance Tavern, I backed
+up agin the wall to have another think. Well, just then along comes
+these two chaps slipping along close by me, with something under their
+arm, and I reckoned they'd stole it. One was a-smoking, and t'other one
+wanted a light; so they stopped right before me and the cigars lit up
+their faces and I see that the big one was the deaf and dumb Spaniard,
+by his white whiskers and the patch on his eye, and t'other one was a
+rusty, ragged-looking devil."
+
+"Could you see the rags by the light of the cigars?"
+
+This staggered Huck for a moment. Then he said:
+
+"Well, I don't know--but somehow it seems as if I did."
+
+"Then they went on, and you--"
+
+"Follered 'em--yes. That was it. I wanted to see what was up--they
+sneaked along so. I dogged 'em to the widder's stile, and stood in the
+dark and heard the ragged one beg for the widder, and the Spaniard
+swear he'd spile her looks just as I told you and your two--"
+
+"What! The DEAF AND DUMB man said all that!"
+
+Huck had made another terrible mistake! He was trying his best to keep
+the old man from getting the faintest hint of who the Spaniard might
+be, and yet his tongue seemed determined to get him into trouble in
+spite of all he could do. He made several efforts to creep out of his
+scrape, but the old man's eye was upon him and he made blunder after
+blunder. Presently the Welshman said:
+
+"My boy, don't be afraid of me. I wouldn't hurt a hair of your head
+for all the world. No--I'd protect you--I'd protect you. This Spaniard
+is not deaf and dumb; you've let that slip without intending it; you
+can't cover that up now. You know something about that Spaniard that
+you want to keep dark. Now trust me--tell me what it is, and trust me
+--I won't betray you."
+
+Huck looked into the old man's honest eyes a moment, then bent over
+and whispered in his ear:
+
+"'Tain't a Spaniard--it's Injun Joe!"
+
+The Welshman almost jumped out of his chair. In a moment he said:
+
+"It's all plain enough, now. When you talked about notching ears and
+slitting noses I judged that that was your own embellishment, because
+white men don't take that sort of revenge. But an Injun! That's a
+different matter altogether."
+
+During breakfast the talk went on, and in the course of it the old man
+said that the last thing which he and his sons had done, before going
+to bed, was to get a lantern and examine the stile and its vicinity for
+marks of blood. They found none, but captured a bulky bundle of--
+
+"Of WHAT?"
+
+If the words had been lightning they could not have leaped with a more
+stunning suddenness from Huck's blanched lips. His eyes were staring
+wide, now, and his breath suspended--waiting for the answer. The
+Welshman started--stared in return--three seconds--five seconds--ten
+--then replied:
+
+"Of burglar's tools. Why, what's the MATTER with you?"
+
+Huck sank back, panting gently, but deeply, unutterably grateful. The
+Welshman eyed him gravely, curiously--and presently said:
+
+"Yes, burglar's tools. That appears to relieve you a good deal. But
+what did give you that turn? What were YOU expecting we'd found?"
+
+Huck was in a close place--the inquiring eye was upon him--he would
+have given anything for material for a plausible answer--nothing
+suggested itself--the inquiring eye was boring deeper and deeper--a
+senseless reply offered--there was no time to weigh it, so at a venture
+he uttered it--feebly:
+
+"Sunday-school books, maybe."
+
+Poor Huck was too distressed to smile, but the old man laughed loud
+and joyously, shook up the details of his anatomy from head to foot,
+and ended by saying that such a laugh was money in a-man's pocket,
+because it cut down the doctor's bill like everything. Then he added:
+
+"Poor old chap, you're white and jaded--you ain't well a bit--no
+wonder you're a little flighty and off your balance. But you'll come
+out of it. Rest and sleep will fetch you out all right, I hope."
+
+Huck was irritated to think he had been such a goose and betrayed such
+a suspicious excitement, for he had dropped the idea that the parcel
+brought from the tavern was the treasure, as soon as he had heard the
+talk at the widow's stile. He had only thought it was not the treasure,
+however--he had not known that it wasn't--and so the suggestion of a
+captured bundle was too much for his self-possession. But on the whole
+he felt glad the little episode had happened, for now he knew beyond
+all question that that bundle was not THE bundle, and so his mind was
+at rest and exceedingly comfortable. In fact, everything seemed to be
+drifting just in the right direction, now; the treasure must be still
+in No. 2, the men would be captured and jailed that day, and he and Tom
+could seize the gold that night without any trouble or any fear of
+interruption.
+
+Just as breakfast was completed there was a knock at the door. Huck
+jumped for a hiding-place, for he had no mind to be connected even
+remotely with the late event. The Welshman admitted several ladies and
+gentlemen, among them the Widow Douglas, and noticed that groups of
+citizens were climbing up the hill--to stare at the stile. So the news
+had spread. The Welshman had to tell the story of the night to the
+visitors. The widow's gratitude for her preservation was outspoken.
+
+"Don't say a word about it, madam. There's another that you're more
+beholden to than you are to me and my boys, maybe, but he don't allow
+me to tell his name. We wouldn't have been there but for him."
+
+Of course this excited a curiosity so vast that it almost belittled
+the main matter--but the Welshman allowed it to eat into the vitals of
+his visitors, and through them be transmitted to the whole town, for he
+refused to part with his secret. When all else had been learned, the
+widow said:
+
+"I went to sleep reading in bed and slept straight through all that
+noise. Why didn't you come and wake me?"
+
+"We judged it warn't worth while. Those fellows warn't likely to come
+again--they hadn't any tools left to work with, and what was the use of
+waking you up and scaring you to death? My three negro men stood guard
+at your house all the rest of the night. They've just come back."
+
+More visitors came, and the story had to be told and retold for a
+couple of hours more.
+
+There was no Sabbath-school during day-school vacation, but everybody
+was early at church. The stirring event was well canvassed. News came
+that not a sign of the two villains had been yet discovered. When the
+sermon was finished, Judge Thatcher's wife dropped alongside of Mrs.
+Harper as she moved down the aisle with the crowd and said:
+
+"Is my Becky going to sleep all day? I just expected she would be
+tired to death."
+
+"Your Becky?"
+
+"Yes," with a startled look--"didn't she stay with you last night?"
+
+"Why, no."
+
+Mrs. Thatcher turned pale, and sank into a pew, just as Aunt Polly,
+talking briskly with a friend, passed by. Aunt Polly said:
+
+"Good-morning, Mrs. Thatcher. Good-morning, Mrs. Harper. I've got a
+boy that's turned up missing. I reckon my Tom stayed at your house last
+night--one of you. And now he's afraid to come to church. I've got to
+settle with him."
+
+Mrs. Thatcher shook her head feebly and turned paler than ever.
+
+"He didn't stay with us," said Mrs. Harper, beginning to look uneasy.
+A marked anxiety came into Aunt Polly's face.
+
+"Joe Harper, have you seen my Tom this morning?"
+
+"No'm."
+
+"When did you see him last?"
+
+Joe tried to remember, but was not sure he could say. The people had
+stopped moving out of church. Whispers passed along, and a boding
+uneasiness took possession of every countenance. Children were
+anxiously questioned, and young teachers. They all said they had not
+noticed whether Tom and Becky were on board the ferryboat on the
+homeward trip; it was dark; no one thought of inquiring if any one was
+missing. One young man finally blurted out his fear that they were
+still in the cave! Mrs. Thatcher swooned away. Aunt Polly fell to
+crying and wringing her hands.
+
+The alarm swept from lip to lip, from group to group, from street to
+street, and within five minutes the bells were wildly clanging and the
+whole town was up! The Cardiff Hill episode sank into instant
+insignificance, the burglars were forgotten, horses were saddled,
+skiffs were manned, the ferryboat ordered out, and before the horror
+was half an hour old, two hundred men were pouring down highroad and
+river toward the cave.
+
+All the long afternoon the village seemed empty and dead. Many women
+visited Aunt Polly and Mrs. Thatcher and tried to comfort them. They
+cried with them, too, and that was still better than words. All the
+tedious night the town waited for news; but when the morning dawned at
+last, all the word that came was, "Send more candles--and send food."
+Mrs. Thatcher was almost crazed; and Aunt Polly, also. Judge Thatcher
+sent messages of hope and encouragement from the cave, but they
+conveyed no real cheer.
+
+The old Welshman came home toward daylight, spattered with
+candle-grease, smeared with clay, and almost worn out. He found Huck
+still in the bed that had been provided for him, and delirious with
+fever. The physicians were all at the cave, so the Widow Douglas came
+and took charge of the patient. She said she would do her best by him,
+because, whether he was good, bad, or indifferent, he was the Lord's,
+and nothing that was the Lord's was a thing to be neglected. The
+Welshman said Huck had good spots in him, and the widow said:
+
+"You can depend on it. That's the Lord's mark. He don't leave it off.
+He never does. Puts it somewhere on every creature that comes from his
+hands."
+
+Early in the forenoon parties of jaded men began to straggle into the
+village, but the strongest of the citizens continued searching. All the
+news that could be gained was that remotenesses of the cavern were
+being ransacked that had never been visited before; that every corner
+and crevice was going to be thoroughly searched; that wherever one
+wandered through the maze of passages, lights were to be seen flitting
+hither and thither in the distance, and shoutings and pistol-shots sent
+their hollow reverberations to the ear down the sombre aisles. In one
+place, far from the section usually traversed by tourists, the names
+"BECKY & TOM" had been found traced upon the rocky wall with
+candle-smoke, and near at hand a grease-soiled bit of ribbon. Mrs.
+Thatcher recognized the ribbon and cried over it. She said it was the
+last relic she should ever have of her child; and that no other memorial
+of her could ever be so precious, because this one parted latest from
+the living body before the awful death came. Some said that now and
+then, in the cave, a far-away speck of light would glimmer, and then a
+glorious shout would burst forth and a score of men go trooping down the
+echoing aisle--and then a sickening disappointment always followed; the
+children were not there; it was only a searcher's light.
+
+Three dreadful days and nights dragged their tedious hours along, and
+the village sank into a hopeless stupor. No one had heart for anything.
+The accidental discovery, just made, that the proprietor of the
+Temperance Tavern kept liquor on his premises, scarcely fluttered the
+public pulse, tremendous as the fact was. In a lucid interval, Huck
+feebly led up to the subject of taverns, and finally asked--dimly
+dreading the worst--if anything had been discovered at the Temperance
+Tavern since he had been ill.
+
+"Yes," said the widow.
+
+Huck started up in bed, wild-eyed:
+
+"What? What was it?"
+
+"Liquor!--and the place has been shut up. Lie down, child--what a turn
+you did give me!"
+
+"Only tell me just one thing--only just one--please! Was it Tom Sawyer
+that found it?"
+
+The widow burst into tears. "Hush, hush, child, hush! I've told you
+before, you must NOT talk. You are very, very sick!"
+
+Then nothing but liquor had been found; there would have been a great
+powwow if it had been the gold. So the treasure was gone forever--gone
+forever! But what could she be crying about? Curious that she should
+cry.
+
+These thoughts worked their dim way through Huck's mind, and under the
+weariness they gave him he fell asleep. The widow said to herself:
+
+"There--he's asleep, poor wreck. Tom Sawyer find it! Pity but somebody
+could find Tom Sawyer! Ah, there ain't many left, now, that's got hope
+enough, or strength enough, either, to go on searching."
+
+
+
+CHAPTER XXXI
+
+NOW to return to Tom and Becky's share in the picnic. They tripped
+along the murky aisles with the rest of the company, visiting the
+familiar wonders of the cave--wonders dubbed with rather
+over-descriptive names, such as "The Drawing-Room," "The Cathedral,"
+"Aladdin's Palace," and so on. Presently the hide-and-seek frolicking
+began, and Tom and Becky engaged in it with zeal until the exertion
+began to grow a trifle wearisome; then they wandered down a sinuous
+avenue holding their candles aloft and reading the tangled web-work of
+names, dates, post-office addresses, and mottoes with which the rocky
+walls had been frescoed (in candle-smoke). Still drifting along and
+talking, they scarcely noticed that they were now in a part of the cave
+whose walls were not frescoed. They smoked their own names under an
+overhanging shelf and moved on. Presently they came to a place where a
+little stream of water, trickling over a ledge and carrying a limestone
+sediment with it, had, in the slow-dragging ages, formed a laced and
+ruffled Niagara in gleaming and imperishable stone. Tom squeezed his
+small body behind it in order to illuminate it for Becky's
+gratification. He found that it curtained a sort of steep natural
+stairway which was enclosed between narrow walls, and at once the
+ambition to be a discoverer seized him. Becky responded to his call,
+and they made a smoke-mark for future guidance, and started upon their
+quest. They wound this way and that, far down into the secret depths of
+the cave, made another mark, and branched off in search of novelties to
+tell the upper world about. In one place they found a spacious cavern,
+from whose ceiling depended a multitude of shining stalactites of the
+length and circumference of a man's leg; they walked all about it,
+wondering and admiring, and presently left it by one of the numerous
+passages that opened into it. This shortly brought them to a bewitching
+spring, whose basin was incrusted with a frostwork of glittering
+crystals; it was in the midst of a cavern whose walls were supported by
+many fantastic pillars which had been formed by the joining of great
+stalactites and stalagmites together, the result of the ceaseless
+water-drip of centuries. Under the roof vast knots of bats had packed
+themselves together, thousands in a bunch; the lights disturbed the
+creatures and they came flocking down by hundreds, squeaking and
+darting furiously at the candles. Tom knew their ways and the danger of
+this sort of conduct. He seized Becky's hand and hurried her into the
+first corridor that offered; and none too soon, for a bat struck
+Becky's light out with its wing while she was passing out of the
+cavern. The bats chased the children a good distance; but the fugitives
+plunged into every new passage that offered, and at last got rid of the
+perilous things. Tom found a subterranean lake, shortly, which
+stretched its dim length away until its shape was lost in the shadows.
+He wanted to explore its borders, but concluded that it would be best
+to sit down and rest awhile, first. Now, for the first time, the deep
+stillness of the place laid a clammy hand upon the spirits of the
+children. Becky said:
+
+"Why, I didn't notice, but it seems ever so long since I heard any of
+the others."
+
+"Come to think, Becky, we are away down below them--and I don't know
+how far away north, or south, or east, or whichever it is. We couldn't
+hear them here."
+
+Becky grew apprehensive.
+
+"I wonder how long we've been down here, Tom? We better start back."
+
+"Yes, I reckon we better. P'raps we better."
+
+"Can you find the way, Tom? It's all a mixed-up crookedness to me."
+
+"I reckon I could find it--but then the bats. If they put our candles
+out it will be an awful fix. Let's try some other way, so as not to go
+through there."
+
+"Well. But I hope we won't get lost. It would be so awful!" and the
+girl shuddered at the thought of the dreadful possibilities.
+
+They started through a corridor, and traversed it in silence a long
+way, glancing at each new opening, to see if there was anything
+familiar about the look of it; but they were all strange. Every time
+Tom made an examination, Becky would watch his face for an encouraging
+sign, and he would say cheerily:
+
+"Oh, it's all right. This ain't the one, but we'll come to it right
+away!"
+
+But he felt less and less hopeful with each failure, and presently
+began to turn off into diverging avenues at sheer random, in desperate
+hope of finding the one that was wanted. He still said it was "all
+right," but there was such a leaden dread at his heart that the words
+had lost their ring and sounded just as if he had said, "All is lost!"
+Becky clung to his side in an anguish of fear, and tried hard to keep
+back the tears, but they would come. At last she said:
+
+"Oh, Tom, never mind the bats, let's go back that way! We seem to get
+worse and worse off all the time."
+
+"Listen!" said he.
+
+Profound silence; silence so deep that even their breathings were
+conspicuous in the hush. Tom shouted. The call went echoing down the
+empty aisles and died out in the distance in a faint sound that
+resembled a ripple of mocking laughter.
+
+"Oh, don't do it again, Tom, it is too horrid," said Becky.
+
+"It is horrid, but I better, Becky; they might hear us, you know," and
+he shouted again.
+
+The "might" was even a chillier horror than the ghostly laughter, it
+so confessed a perishing hope. The children stood still and listened;
+but there was no result. Tom turned upon the back track at once, and
+hurried his steps. It was but a little while before a certain
+indecision in his manner revealed another fearful fact to Becky--he
+could not find his way back!
+
+"Oh, Tom, you didn't make any marks!"
+
+"Becky, I was such a fool! Such a fool! I never thought we might want
+to come back! No--I can't find the way. It's all mixed up."
+
+"Tom, Tom, we're lost! we're lost! We never can get out of this awful
+place! Oh, why DID we ever leave the others!"
+
+She sank to the ground and burst into such a frenzy of crying that Tom
+was appalled with the idea that she might die, or lose her reason. He
+sat down by her and put his arms around her; she buried her face in his
+bosom, she clung to him, she poured out her terrors, her unavailing
+regrets, and the far echoes turned them all to jeering laughter. Tom
+begged her to pluck up hope again, and she said she could not. He fell
+to blaming and abusing himself for getting her into this miserable
+situation; this had a better effect. She said she would try to hope
+again, she would get up and follow wherever he might lead if only he
+would not talk like that any more. For he was no more to blame than
+she, she said.
+
+So they moved on again--aimlessly--simply at random--all they could do
+was to move, keep moving. For a little while, hope made a show of
+reviving--not with any reason to back it, but only because it is its
+nature to revive when the spring has not been taken out of it by age
+and familiarity with failure.
+
+By-and-by Tom took Becky's candle and blew it out. This economy meant
+so much! Words were not needed. Becky understood, and her hope died
+again. She knew that Tom had a whole candle and three or four pieces in
+his pockets--yet he must economize.
+
+By-and-by, fatigue began to assert its claims; the children tried to
+pay attention, for it was dreadful to think of sitting down when time
+was grown to be so precious, moving, in some direction, in any
+direction, was at least progress and might bear fruit; but to sit down
+was to invite death and shorten its pursuit.
+
+At last Becky's frail limbs refused to carry her farther. She sat
+down. Tom rested with her, and they talked of home, and the friends
+there, and the comfortable beds and, above all, the light! Becky cried,
+and Tom tried to think of some way of comforting her, but all his
+encouragements were grown threadbare with use, and sounded like
+sarcasms. Fatigue bore so heavily upon Becky that she drowsed off to
+sleep. Tom was grateful. He sat looking into her drawn face and saw it
+grow smooth and natural under the influence of pleasant dreams; and
+by-and-by a smile dawned and rested there. The peaceful face reflected
+somewhat of peace and healing into his own spirit, and his thoughts
+wandered away to bygone times and dreamy memories. While he was deep in
+his musings, Becky woke up with a breezy little laugh--but it was
+stricken dead upon her lips, and a groan followed it.
+
+"Oh, how COULD I sleep! I wish I never, never had waked! No! No, I
+don't, Tom! Don't look so! I won't say it again."
+
+"I'm glad you've slept, Becky; you'll feel rested, now, and we'll find
+the way out."
+
+"We can try, Tom; but I've seen such a beautiful country in my dream.
+I reckon we are going there."
+
+"Maybe not, maybe not. Cheer up, Becky, and let's go on trying."
+
+They rose up and wandered along, hand in hand and hopeless. They tried
+to estimate how long they had been in the cave, but all they knew was
+that it seemed days and weeks, and yet it was plain that this could not
+be, for their candles were not gone yet. A long time after this--they
+could not tell how long--Tom said they must go softly and listen for
+dripping water--they must find a spring. They found one presently, and
+Tom said it was time to rest again. Both were cruelly tired, yet Becky
+said she thought she could go a little farther. She was surprised to
+hear Tom dissent. She could not understand it. They sat down, and Tom
+fastened his candle to the wall in front of them with some clay.
+Thought was soon busy; nothing was said for some time. Then Becky broke
+the silence:
+
+"Tom, I am so hungry!"
+
+Tom took something out of his pocket.
+
+"Do you remember this?" said he.
+
+Becky almost smiled.
+
+"It's our wedding-cake, Tom."
+
+"Yes--I wish it was as big as a barrel, for it's all we've got."
+
+"I saved it from the picnic for us to dream on, Tom, the way grown-up
+people do with wedding-cake--but it'll be our--"
+
+She dropped the sentence where it was. Tom divided the cake and Becky
+ate with good appetite, while Tom nibbled at his moiety. There was
+abundance of cold water to finish the feast with. By-and-by Becky
+suggested that they move on again. Tom was silent a moment. Then he
+said:
+
+"Becky, can you bear it if I tell you something?"
+
+Becky's face paled, but she thought she could.
+
+"Well, then, Becky, we must stay here, where there's water to drink.
+That little piece is our last candle!"
+
+Becky gave loose to tears and wailings. Tom did what he could to
+comfort her, but with little effect. At length Becky said:
+
+"Tom!"
+
+"Well, Becky?"
+
+"They'll miss us and hunt for us!"
+
+"Yes, they will! Certainly they will!"
+
+"Maybe they're hunting for us now, Tom."
+
+"Why, I reckon maybe they are. I hope they are."
+
+"When would they miss us, Tom?"
+
+"When they get back to the boat, I reckon."
+
+"Tom, it might be dark then--would they notice we hadn't come?"
+
+"I don't know. But anyway, your mother would miss you as soon as they
+got home."
+
+A frightened look in Becky's face brought Tom to his senses and he saw
+that he had made a blunder. Becky was not to have gone home that night!
+The children became silent and thoughtful. In a moment a new burst of
+grief from Becky showed Tom that the thing in his mind had struck hers
+also--that the Sabbath morning might be half spent before Mrs. Thatcher
+discovered that Becky was not at Mrs. Harper's.
+
+The children fastened their eyes upon their bit of candle and watched
+it melt slowly and pitilessly away; saw the half inch of wick stand
+alone at last; saw the feeble flame rise and fall, climb the thin
+column of smoke, linger at its top a moment, and then--the horror of
+utter darkness reigned!
+
+How long afterward it was that Becky came to a slow consciousness that
+she was crying in Tom's arms, neither could tell. All that they knew
+was, that after what seemed a mighty stretch of time, both awoke out of
+a dead stupor of sleep and resumed their miseries once more. Tom said
+it might be Sunday, now--maybe Monday. He tried to get Becky to talk,
+but her sorrows were too oppressive, all her hopes were gone. Tom said
+that they must have been missed long ago, and no doubt the search was
+going on. He would shout and maybe some one would come. He tried it;
+but in the darkness the distant echoes sounded so hideously that he
+tried it no more.
+
+The hours wasted away, and hunger came to torment the captives again.
+A portion of Tom's half of the cake was left; they divided and ate it.
+But they seemed hungrier than before. The poor morsel of food only
+whetted desire.
+
+By-and-by Tom said:
+
+"SH! Did you hear that?"
+
+Both held their breath and listened. There was a sound like the
+faintest, far-off shout. Instantly Tom answered it, and leading Becky
+by the hand, started groping down the corridor in its direction.
+Presently he listened again; again the sound was heard, and apparently
+a little nearer.
+
+"It's them!" said Tom; "they're coming! Come along, Becky--we're all
+right now!"
+
+The joy of the prisoners was almost overwhelming. Their speed was
+slow, however, because pitfalls were somewhat common, and had to be
+guarded against. They shortly came to one and had to stop. It might be
+three feet deep, it might be a hundred--there was no passing it at any
+rate. Tom got down on his breast and reached as far down as he could.
+No bottom. They must stay there and wait until the searchers came. They
+listened; evidently the distant shoutings were growing more distant! a
+moment or two more and they had gone altogether. The heart-sinking
+misery of it! Tom whooped until he was hoarse, but it was of no use. He
+talked hopefully to Becky; but an age of anxious waiting passed and no
+sounds came again.
+
+The children groped their way back to the spring. The weary time
+dragged on; they slept again, and awoke famished and woe-stricken. Tom
+believed it must be Tuesday by this time.
+
+Now an idea struck him. There were some side passages near at hand. It
+would be better to explore some of these than bear the weight of the
+heavy time in idleness. He took a kite-line from his pocket, tied it to
+a projection, and he and Becky started, Tom in the lead, unwinding the
+line as he groped along. At the end of twenty steps the corridor ended
+in a "jumping-off place." Tom got down on his knees and felt below, and
+then as far around the corner as he could reach with his hands
+conveniently; he made an effort to stretch yet a little farther to the
+right, and at that moment, not twenty yards away, a human hand, holding
+a candle, appeared from behind a rock! Tom lifted up a glorious shout,
+and instantly that hand was followed by the body it belonged to--Injun
+Joe's! Tom was paralyzed; he could not move. He was vastly gratified
+the next moment, to see the "Spaniard" take to his heels and get
+himself out of sight. Tom wondered that Joe had not recognized his
+voice and come over and killed him for testifying in court. But the
+echoes must have disguised the voice. Without doubt, that was it, he
+reasoned. Tom's fright weakened every muscle in his body. He said to
+himself that if he had strength enough to get back to the spring he
+would stay there, and nothing should tempt him to run the risk of
+meeting Injun Joe again. He was careful to keep from Becky what it was
+he had seen. He told her he had only shouted "for luck."
+
+But hunger and wretchedness rise superior to fears in the long run.
+Another tedious wait at the spring and another long sleep brought
+changes. The children awoke tortured with a raging hunger. Tom believed
+that it must be Wednesday or Thursday or even Friday or Saturday, now,
+and that the search had been given over. He proposed to explore another
+passage. He felt willing to risk Injun Joe and all other terrors. But
+Becky was very weak. She had sunk into a dreary apathy and would not be
+roused. She said she would wait, now, where she was, and die--it would
+not be long. She told Tom to go with the kite-line and explore if he
+chose; but she implored him to come back every little while and speak
+to her; and she made him promise that when the awful time came, he
+would stay by her and hold her hand until all was over.
+
+Tom kissed her, with a choking sensation in his throat, and made a
+show of being confident of finding the searchers or an escape from the
+cave; then he took the kite-line in his hand and went groping down one
+of the passages on his hands and knees, distressed with hunger and sick
+with bodings of coming doom.
+
+
+
+CHAPTER XXXII
+
+TUESDAY afternoon came, and waned to the twilight. The village of St.
+Petersburg still mourned. The lost children had not been found. Public
+prayers had been offered up for them, and many and many a private
+prayer that had the petitioner's whole heart in it; but still no good
+news came from the cave. The majority of the searchers had given up the
+quest and gone back to their daily avocations, saying that it was plain
+the children could never be found. Mrs. Thatcher was very ill, and a
+great part of the time delirious. People said it was heartbreaking to
+hear her call her child, and raise her head and listen a whole minute
+at a time, then lay it wearily down again with a moan. Aunt Polly had
+drooped into a settled melancholy, and her gray hair had grown almost
+white. The village went to its rest on Tuesday night, sad and forlorn.
+
+Away in the middle of the night a wild peal burst from the village
+bells, and in a moment the streets were swarming with frantic half-clad
+people, who shouted, "Turn out! turn out! they're found! they're
+found!" Tin pans and horns were added to the din, the population massed
+itself and moved toward the river, met the children coming in an open
+carriage drawn by shouting citizens, thronged around it, joined its
+homeward march, and swept magnificently up the main street roaring
+huzzah after huzzah!
+
+The village was illuminated; nobody went to bed again; it was the
+greatest night the little town had ever seen. During the first half-hour
+a procession of villagers filed through Judge Thatcher's house, seized
+the saved ones and kissed them, squeezed Mrs. Thatcher's hand, tried to
+speak but couldn't--and drifted out raining tears all over the place.
+
+Aunt Polly's happiness was complete, and Mrs. Thatcher's nearly so. It
+would be complete, however, as soon as the messenger dispatched with
+the great news to the cave should get the word to her husband. Tom lay
+upon a sofa with an eager auditory about him and told the history of
+the wonderful adventure, putting in many striking additions to adorn it
+withal; and closed with a description of how he left Becky and went on
+an exploring expedition; how he followed two avenues as far as his
+kite-line would reach; how he followed a third to the fullest stretch of
+the kite-line, and was about to turn back when he glimpsed a far-off
+speck that looked like daylight; dropped the line and groped toward it,
+pushed his head and shoulders through a small hole, and saw the broad
+Mississippi rolling by! And if it had only happened to be night he would
+not have seen that speck of daylight and would not have explored that
+passage any more! He told how he went back for Becky and broke the good
+news and she told him not to fret her with such stuff, for she was
+tired, and knew she was going to die, and wanted to. He described how he
+labored with her and convinced her; and how she almost died for joy when
+she had groped to where she actually saw the blue speck of daylight; how
+he pushed his way out at the hole and then helped her out; how they sat
+there and cried for gladness; how some men came along in a skiff and Tom
+hailed them and told them their situation and their famished condition;
+how the men didn't believe the wild tale at first, "because," said they,
+"you are five miles down the river below the valley the cave is in"
+--then took them aboard, rowed to a house, gave them supper, made them
+rest till two or three hours after dark and then brought them home.
+
+Before day-dawn, Judge Thatcher and the handful of searchers with him
+were tracked out, in the cave, by the twine clews they had strung
+behind them, and informed of the great news.
+
+Three days and nights of toil and hunger in the cave were not to be
+shaken off at once, as Tom and Becky soon discovered. They were
+bedridden all of Wednesday and Thursday, and seemed to grow more and
+more tired and worn, all the time. Tom got about, a little, on
+Thursday, was down-town Friday, and nearly as whole as ever Saturday;
+but Becky did not leave her room until Sunday, and then she looked as
+if she had passed through a wasting illness.
+
+Tom learned of Huck's sickness and went to see him on Friday, but
+could not be admitted to the bedroom; neither could he on Saturday or
+Sunday. He was admitted daily after that, but was warned to keep still
+about his adventure and introduce no exciting topic. The Widow Douglas
+stayed by to see that he obeyed. At home Tom learned of the Cardiff
+Hill event; also that the "ragged man's" body had eventually been found
+in the river near the ferry-landing; he had been drowned while trying
+to escape, perhaps.
+
+About a fortnight after Tom's rescue from the cave, he started off to
+visit Huck, who had grown plenty strong enough, now, to hear exciting
+talk, and Tom had some that would interest him, he thought. Judge
+Thatcher's house was on Tom's way, and he stopped to see Becky. The
+Judge and some friends set Tom to talking, and some one asked him
+ironically if he wouldn't like to go to the cave again. Tom said he
+thought he wouldn't mind it. The Judge said:
+
+"Well, there are others just like you, Tom, I've not the least doubt.
+But we have taken care of that. Nobody will get lost in that cave any
+more."
+
+"Why?"
+
+"Because I had its big door sheathed with boiler iron two weeks ago,
+and triple-locked--and I've got the keys."
+
+Tom turned as white as a sheet.
+
+"What's the matter, boy! Here, run, somebody! Fetch a glass of water!"
+
+The water was brought and thrown into Tom's face.
+
+"Ah, now you're all right. What was the matter with you, Tom?"
+
+"Oh, Judge, Injun Joe's in the cave!"
+
+
+
+CHAPTER XXXIII
+
+WITHIN a few minutes the news had spread, and a dozen skiff-loads of
+men were on their way to McDougal's cave, and the ferryboat, well
+filled with passengers, soon followed. Tom Sawyer was in the skiff that
+bore Judge Thatcher.
+
+When the cave door was unlocked, a sorrowful sight presented itself in
+the dim twilight of the place. Injun Joe lay stretched upon the ground,
+dead, with his face close to the crack of the door, as if his longing
+eyes had been fixed, to the latest moment, upon the light and the cheer
+of the free world outside. Tom was touched, for he knew by his own
+experience how this wretch had suffered. His pity was moved, but
+nevertheless he felt an abounding sense of relief and security, now,
+which revealed to him in a degree which he had not fully appreciated
+before how vast a weight of dread had been lying upon him since the day
+he lifted his voice against this bloody-minded outcast.
+
+Injun Joe's bowie-knife lay close by, its blade broken in two. The
+great foundation-beam of the door had been chipped and hacked through,
+with tedious labor; useless labor, too, it was, for the native rock
+formed a sill outside it, and upon that stubborn material the knife had
+wrought no effect; the only damage done was to the knife itself. But if
+there had been no stony obstruction there the labor would have been
+useless still, for if the beam had been wholly cut away Injun Joe could
+not have squeezed his body under the door, and he knew it. So he had
+only hacked that place in order to be doing something--in order to pass
+the weary time--in order to employ his tortured faculties. Ordinarily
+one could find half a dozen bits of candle stuck around in the crevices
+of this vestibule, left there by tourists; but there were none now. The
+prisoner had searched them out and eaten them. He had also contrived to
+catch a few bats, and these, also, he had eaten, leaving only their
+claws. The poor unfortunate had starved to death. In one place, near at
+hand, a stalagmite had been slowly growing up from the ground for ages,
+builded by the water-drip from a stalactite overhead. The captive had
+broken off the stalagmite, and upon the stump had placed a stone,
+wherein he had scooped a shallow hollow to catch the precious drop
+that fell once in every three minutes with the dreary regularity of a
+clock-tick--a dessertspoonful once in four and twenty hours. That drop
+was falling when the Pyramids were new; when Troy fell; when the
+foundations of Rome were laid; when Christ was crucified; when the
+Conqueror created the British empire; when Columbus sailed; when the
+massacre at Lexington was "news." It is falling now; it will still be
+falling when all these things shall have sunk down the afternoon of
+history, and the twilight of tradition, and been swallowed up in the
+thick night of oblivion. Has everything a purpose and a mission? Did
+this drop fall patiently during five thousand years to be ready for
+this flitting human insect's need? and has it another important object
+to accomplish ten thousand years to come? No matter. It is many and
+many a year since the hapless half-breed scooped out the stone to catch
+the priceless drops, but to this day the tourist stares longest at that
+pathetic stone and that slow-dropping water when he comes to see the
+wonders of McDougal's cave. Injun Joe's cup stands first in the list of
+the cavern's marvels; even "Aladdin's Palace" cannot rival it.
+
+Injun Joe was buried near the mouth of the cave; and people flocked
+there in boats and wagons from the towns and from all the farms and
+hamlets for seven miles around; they brought their children, and all
+sorts of provisions, and confessed that they had had almost as
+satisfactory a time at the funeral as they could have had at the
+hanging.
+
+This funeral stopped the further growth of one thing--the petition to
+the governor for Injun Joe's pardon. The petition had been largely
+signed; many tearful and eloquent meetings had been held, and a
+committee of sappy women been appointed to go in deep mourning and wail
+around the governor, and implore him to be a merciful ass and trample
+his duty under foot. Injun Joe was believed to have killed five
+citizens of the village, but what of that? If he had been Satan himself
+there would have been plenty of weaklings ready to scribble their names
+to a pardon-petition, and drip a tear on it from their permanently
+impaired and leaky water-works.
+
+The morning after the funeral Tom took Huck to a private place to have
+an important talk. Huck had learned all about Tom's adventure from the
+Welshman and the Widow Douglas, by this time, but Tom said he reckoned
+there was one thing they had not told him; that thing was what he
+wanted to talk about now. Huck's face saddened. He said:
+
+"I know what it is. You got into No. 2 and never found anything but
+whiskey. Nobody told me it was you; but I just knowed it must 'a' ben
+you, soon as I heard 'bout that whiskey business; and I knowed you
+hadn't got the money becuz you'd 'a' got at me some way or other and
+told me even if you was mum to everybody else. Tom, something's always
+told me we'd never get holt of that swag."
+
+"Why, Huck, I never told on that tavern-keeper. YOU know his tavern
+was all right the Saturday I went to the picnic. Don't you remember you
+was to watch there that night?"
+
+"Oh yes! Why, it seems 'bout a year ago. It was that very night that I
+follered Injun Joe to the widder's."
+
+"YOU followed him?"
+
+"Yes--but you keep mum. I reckon Injun Joe's left friends behind him,
+and I don't want 'em souring on me and doing me mean tricks. If it
+hadn't ben for me he'd be down in Texas now, all right."
+
+Then Huck told his entire adventure in confidence to Tom, who had only
+heard of the Welshman's part of it before.
+
+"Well," said Huck, presently, coming back to the main question,
+"whoever nipped the whiskey in No. 2, nipped the money, too, I reckon
+--anyways it's a goner for us, Tom."
+
+"Huck, that money wasn't ever in No. 2!"
+
+"What!" Huck searched his comrade's face keenly. "Tom, have you got on
+the track of that money again?"
+
+"Huck, it's in the cave!"
+
+Huck's eyes blazed.
+
+"Say it again, Tom."
+
+"The money's in the cave!"
+
+"Tom--honest injun, now--is it fun, or earnest?"
+
+"Earnest, Huck--just as earnest as ever I was in my life. Will you go
+in there with me and help get it out?"
+
+"I bet I will! I will if it's where we can blaze our way to it and not
+get lost."
+
+"Huck, we can do that without the least little bit of trouble in the
+world."
+
+"Good as wheat! What makes you think the money's--"
+
+"Huck, you just wait till we get in there. If we don't find it I'll
+agree to give you my drum and every thing I've got in the world. I
+will, by jings."
+
+"All right--it's a whiz. When do you say?"
+
+"Right now, if you say it. Are you strong enough?"
+
+"Is it far in the cave? I ben on my pins a little, three or four days,
+now, but I can't walk more'n a mile, Tom--least I don't think I could."
+
+"It's about five mile into there the way anybody but me would go,
+Huck, but there's a mighty short cut that they don't anybody but me
+know about. Huck, I'll take you right to it in a skiff. I'll float the
+skiff down there, and I'll pull it back again all by myself. You
+needn't ever turn your hand over."
+
+"Less start right off, Tom."
+
+"All right. We want some bread and meat, and our pipes, and a little
+bag or two, and two or three kite-strings, and some of these
+new-fangled things they call lucifer matches. I tell you, many's
+the time I wished I had some when I was in there before."
+
+A trifle after noon the boys borrowed a small skiff from a citizen who
+was absent, and got under way at once. When they were several miles
+below "Cave Hollow," Tom said:
+
+"Now you see this bluff here looks all alike all the way down from the
+cave hollow--no houses, no wood-yards, bushes all alike. But do you see
+that white place up yonder where there's been a landslide? Well, that's
+one of my marks. We'll get ashore, now."
+
+They landed.
+
+"Now, Huck, where we're a-standing you could touch that hole I got out
+of with a fishing-pole. See if you can find it."
+
+Huck searched all the place about, and found nothing. Tom proudly
+marched into a thick clump of sumach bushes and said:
+
+"Here you are! Look at it, Huck; it's the snuggest hole in this
+country. You just keep mum about it. All along I've been wanting to be
+a robber, but I knew I'd got to have a thing like this, and where to
+run across it was the bother. We've got it now, and we'll keep it
+quiet, only we'll let Joe Harper and Ben Rogers in--because of course
+there's got to be a Gang, or else there wouldn't be any style about it.
+Tom Sawyer's Gang--it sounds splendid, don't it, Huck?"
+
+"Well, it just does, Tom. And who'll we rob?"
+
+"Oh, most anybody. Waylay people--that's mostly the way."
+
+"And kill them?"
+
+"No, not always. Hive them in the cave till they raise a ransom."
+
+"What's a ransom?"
+
+"Money. You make them raise all they can, off'n their friends; and
+after you've kept them a year, if it ain't raised then you kill them.
+That's the general way. Only you don't kill the women. You shut up the
+women, but you don't kill them. They're always beautiful and rich, and
+awfully scared. You take their watches and things, but you always take
+your hat off and talk polite. They ain't anybody as polite as robbers
+--you'll see that in any book. Well, the women get to loving you, and
+after they've been in the cave a week or two weeks they stop crying and
+after that you couldn't get them to leave. If you drove them out they'd
+turn right around and come back. It's so in all the books."
+
+"Why, it's real bully, Tom. I believe it's better'n to be a pirate."
+
+"Yes, it's better in some ways, because it's close to home and
+circuses and all that."
+
+By this time everything was ready and the boys entered the hole, Tom
+in the lead. They toiled their way to the farther end of the tunnel,
+then made their spliced kite-strings fast and moved on. A few steps
+brought them to the spring, and Tom felt a shudder quiver all through
+him. He showed Huck the fragment of candle-wick perched on a lump of
+clay against the wall, and described how he and Becky had watched the
+flame struggle and expire.
+
+The boys began to quiet down to whispers, now, for the stillness and
+gloom of the place oppressed their spirits. They went on, and presently
+entered and followed Tom's other corridor until they reached the
+"jumping-off place." The candles revealed the fact that it was not
+really a precipice, but only a steep clay hill twenty or thirty feet
+high. Tom whispered:
+
+"Now I'll show you something, Huck."
+
+He held his candle aloft and said:
+
+"Look as far around the corner as you can. Do you see that? There--on
+the big rock over yonder--done with candle-smoke."
+
+"Tom, it's a CROSS!"
+
+"NOW where's your Number Two? 'UNDER THE CROSS,' hey? Right yonder's
+where I saw Injun Joe poke up his candle, Huck!"
+
+Huck stared at the mystic sign awhile, and then said with a shaky voice:
+
+"Tom, less git out of here!"
+
+"What! and leave the treasure?"
+
+"Yes--leave it. Injun Joe's ghost is round about there, certain."
+
+"No it ain't, Huck, no it ain't. It would ha'nt the place where he
+died--away out at the mouth of the cave--five mile from here."
+
+"No, Tom, it wouldn't. It would hang round the money. I know the ways
+of ghosts, and so do you."
+
+Tom began to fear that Huck was right. Misgivings gathered in his
+mind. But presently an idea occurred to him--
+
+"Lookyhere, Huck, what fools we're making of ourselves! Injun Joe's
+ghost ain't a going to come around where there's a cross!"
+
+The point was well taken. It had its effect.
+
+"Tom, I didn't think of that. But that's so. It's luck for us, that
+cross is. I reckon we'll climb down there and have a hunt for that box."
+
+Tom went first, cutting rude steps in the clay hill as he descended.
+Huck followed. Four avenues opened out of the small cavern which the
+great rock stood in. The boys examined three of them with no result.
+They found a small recess in the one nearest the base of the rock, with
+a pallet of blankets spread down in it; also an old suspender, some
+bacon rind, and the well-gnawed bones of two or three fowls. But there
+was no money-box. The lads searched and researched this place, but in
+vain. Tom said:
+
+"He said UNDER the cross. Well, this comes nearest to being under the
+cross. It can't be under the rock itself, because that sets solid on
+the ground."
+
+They searched everywhere once more, and then sat down discouraged.
+Huck could suggest nothing. By-and-by Tom said:
+
+"Lookyhere, Huck, there's footprints and some candle-grease on the
+clay about one side of this rock, but not on the other sides. Now,
+what's that for? I bet you the money IS under the rock. I'm going to
+dig in the clay."
+
+"That ain't no bad notion, Tom!" said Huck with animation.
+
+Tom's "real Barlow" was out at once, and he had not dug four inches
+before he struck wood.
+
+"Hey, Huck!--you hear that?"
+
+Huck began to dig and scratch now. Some boards were soon uncovered and
+removed. They had concealed a natural chasm which led under the rock.
+Tom got into this and held his candle as far under the rock as he
+could, but said he could not see to the end of the rift. He proposed to
+explore. He stooped and passed under; the narrow way descended
+gradually. He followed its winding course, first to the right, then to
+the left, Huck at his heels. Tom turned a short curve, by-and-by, and
+exclaimed:
+
+"My goodness, Huck, lookyhere!"
+
+It was the treasure-box, sure enough, occupying a snug little cavern,
+along with an empty powder-keg, a couple of guns in leather cases, two
+or three pairs of old moccasins, a leather belt, and some other rubbish
+well soaked with the water-drip.
+
+"Got it at last!" said Huck, ploughing among the tarnished coins with
+his hand. "My, but we're rich, Tom!"
+
+"Huck, I always reckoned we'd get it. It's just too good to believe,
+but we HAVE got it, sure! Say--let's not fool around here. Let's snake
+it out. Lemme see if I can lift the box."
+
+It weighed about fifty pounds. Tom could lift it, after an awkward
+fashion, but could not carry it conveniently.
+
+"I thought so," he said; "THEY carried it like it was heavy, that day
+at the ha'nted house. I noticed that. I reckon I was right to think of
+fetching the little bags along."
+
+The money was soon in the bags and the boys took it up to the cross
+rock.
+
+"Now less fetch the guns and things," said Huck.
+
+"No, Huck--leave them there. They're just the tricks to have when we
+go to robbing. We'll keep them there all the time, and we'll hold our
+orgies there, too. It's an awful snug place for orgies."
+
+"What orgies?"
+
+"I dono. But robbers always have orgies, and of course we've got to
+have them, too. Come along, Huck, we've been in here a long time. It's
+getting late, I reckon. I'm hungry, too. We'll eat and smoke when we
+get to the skiff."
+
+They presently emerged into the clump of sumach bushes, looked warily
+out, found the coast clear, and were soon lunching and smoking in the
+skiff. As the sun dipped toward the horizon they pushed out and got
+under way. Tom skimmed up the shore through the long twilight, chatting
+cheerily with Huck, and landed shortly after dark.
+
+"Now, Huck," said Tom, "we'll hide the money in the loft of the
+widow's woodshed, and I'll come up in the morning and we'll count it
+and divide, and then we'll hunt up a place out in the woods for it
+where it will be safe. Just you lay quiet here and watch the stuff till
+I run and hook Benny Taylor's little wagon; I won't be gone a minute."
+
+He disappeared, and presently returned with the wagon, put the two
+small sacks into it, threw some old rags on top of them, and started
+off, dragging his cargo behind him. When the boys reached the
+Welshman's house, they stopped to rest. Just as they were about to move
+on, the Welshman stepped out and said:
+
+"Hallo, who's that?"
+
+"Huck and Tom Sawyer."
+
+"Good! Come along with me, boys, you are keeping everybody waiting.
+Here--hurry up, trot ahead--I'll haul the wagon for you. Why, it's not
+as light as it might be. Got bricks in it?--or old metal?"
+
+"Old metal," said Tom.
+
+"I judged so; the boys in this town will take more trouble and fool
+away more time hunting up six bits' worth of old iron to sell to the
+foundry than they would to make twice the money at regular work. But
+that's human nature--hurry along, hurry along!"
+
+The boys wanted to know what the hurry was about.
+
+"Never mind; you'll see, when we get to the Widow Douglas'."
+
+Huck said with some apprehension--for he was long used to being
+falsely accused:
+
+"Mr. Jones, we haven't been doing nothing."
+
+The Welshman laughed.
+
+"Well, I don't know, Huck, my boy. I don't know about that. Ain't you
+and the widow good friends?"
+
+"Yes. Well, she's ben good friends to me, anyway."
+
+"All right, then. What do you want to be afraid for?"
+
+This question was not entirely answered in Huck's slow mind before he
+found himself pushed, along with Tom, into Mrs. Douglas' drawing-room.
+Mr. Jones left the wagon near the door and followed.
+
+The place was grandly lighted, and everybody that was of any
+consequence in the village was there. The Thatchers were there, the
+Harpers, the Rogerses, Aunt Polly, Sid, Mary, the minister, the editor,
+and a great many more, and all dressed in their best. The widow
+received the boys as heartily as any one could well receive two such
+looking beings. They were covered with clay and candle-grease. Aunt
+Polly blushed crimson with humiliation, and frowned and shook her head
+at Tom. Nobody suffered half as much as the two boys did, however. Mr.
+Jones said:
+
+"Tom wasn't at home, yet, so I gave him up; but I stumbled on him and
+Huck right at my door, and so I just brought them along in a hurry."
+
+"And you did just right," said the widow. "Come with me, boys."
+
+She took them to a bedchamber and said:
+
+"Now wash and dress yourselves. Here are two new suits of clothes
+--shirts, socks, everything complete. They're Huck's--no, no thanks,
+Huck--Mr. Jones bought one and I the other. But they'll fit both of you.
+Get into them. We'll wait--come down when you are slicked up enough."
+
+Then she left.
+
+
+
+CHAPTER XXXIV
+
+HUCK said: "Tom, we can slope, if we can find a rope. The window ain't
+high from the ground."
+
+"Shucks! what do you want to slope for?"
+
+"Well, I ain't used to that kind of a crowd. I can't stand it. I ain't
+going down there, Tom."
+
+"Oh, bother! It ain't anything. I don't mind it a bit. I'll take care
+of you."
+
+Sid appeared.
+
+"Tom," said he, "auntie has been waiting for you all the afternoon.
+Mary got your Sunday clothes ready, and everybody's been fretting about
+you. Say--ain't this grease and clay, on your clothes?"
+
+"Now, Mr. Siddy, you jist 'tend to your own business. What's all this
+blow-out about, anyway?"
+
+"It's one of the widow's parties that she's always having. This time
+it's for the Welshman and his sons, on account of that scrape they
+helped her out of the other night. And say--I can tell you something,
+if you want to know."
+
+"Well, what?"
+
+"Why, old Mr. Jones is going to try to spring something on the people
+here to-night, but I overheard him tell auntie to-day about it, as a
+secret, but I reckon it's not much of a secret now. Everybody knows
+--the widow, too, for all she tries to let on she don't. Mr. Jones was
+bound Huck should be here--couldn't get along with his grand secret
+without Huck, you know!"
+
+"Secret about what, Sid?"
+
+"About Huck tracking the robbers to the widow's. I reckon Mr. Jones
+was going to make a grand time over his surprise, but I bet you it will
+drop pretty flat."
+
+Sid chuckled in a very contented and satisfied way.
+
+"Sid, was it you that told?"
+
+"Oh, never mind who it was. SOMEBODY told--that's enough."
+
+"Sid, there's only one person in this town mean enough to do that, and
+that's you. If you had been in Huck's place you'd 'a' sneaked down the
+hill and never told anybody on the robbers. You can't do any but mean
+things, and you can't bear to see anybody praised for doing good ones.
+There--no thanks, as the widow says"--and Tom cuffed Sid's ears and
+helped him to the door with several kicks. "Now go and tell auntie if
+you dare--and to-morrow you'll catch it!"
+
+Some minutes later the widow's guests were at the supper-table, and a
+dozen children were propped up at little side-tables in the same room,
+after the fashion of that country and that day. At the proper time Mr.
+Jones made his little speech, in which he thanked the widow for the
+honor she was doing himself and his sons, but said that there was
+another person whose modesty--
+
+And so forth and so on. He sprung his secret about Huck's share in the
+adventure in the finest dramatic manner he was master of, but the
+surprise it occasioned was largely counterfeit and not as clamorous and
+effusive as it might have been under happier circumstances. However,
+the widow made a pretty fair show of astonishment, and heaped so many
+compliments and so much gratitude upon Huck that he almost forgot the
+nearly intolerable discomfort of his new clothes in the entirely
+intolerable discomfort of being set up as a target for everybody's gaze
+and everybody's laudations.
+
+The widow said she meant to give Huck a home under her roof and have
+him educated; and that when she could spare the money she would start
+him in business in a modest way. Tom's chance was come. He said:
+
+"Huck don't need it. Huck's rich."
+
+Nothing but a heavy strain upon the good manners of the company kept
+back the due and proper complimentary laugh at this pleasant joke. But
+the silence was a little awkward. Tom broke it:
+
+"Huck's got money. Maybe you don't believe it, but he's got lots of
+it. Oh, you needn't smile--I reckon I can show you. You just wait a
+minute."
+
+Tom ran out of doors. The company looked at each other with a
+perplexed interest--and inquiringly at Huck, who was tongue-tied.
+
+"Sid, what ails Tom?" said Aunt Polly. "He--well, there ain't ever any
+making of that boy out. I never--"
+
+Tom entered, struggling with the weight of his sacks, and Aunt Polly
+did not finish her sentence. Tom poured the mass of yellow coin upon
+the table and said:
+
+"There--what did I tell you? Half of it's Huck's and half of it's mine!"
+
+The spectacle took the general breath away. All gazed, nobody spoke
+for a moment. Then there was a unanimous call for an explanation. Tom
+said he could furnish it, and he did. The tale was long, but brimful of
+interest. There was scarcely an interruption from any one to break the
+charm of its flow. When he had finished, Mr. Jones said:
+
+"I thought I had fixed up a little surprise for this occasion, but it
+don't amount to anything now. This one makes it sing mighty small, I'm
+willing to allow."
+
+The money was counted. The sum amounted to a little over twelve
+thousand dollars. It was more than any one present had ever seen at one
+time before, though several persons were there who were worth
+considerably more than that in property.
+
+
+
+CHAPTER XXXV
+
+THE reader may rest satisfied that Tom's and Huck's windfall made a
+mighty stir in the poor little village of St. Petersburg. So vast a
+sum, all in actual cash, seemed next to incredible. It was talked
+about, gloated over, glorified, until the reason of many of the
+citizens tottered under the strain of the unhealthy excitement. Every
+"haunted" house in St. Petersburg and the neighboring villages was
+dissected, plank by plank, and its foundations dug up and ransacked for
+hidden treasure--and not by boys, but men--pretty grave, unromantic
+men, too, some of them. Wherever Tom and Huck appeared they were
+courted, admired, stared at. The boys were not able to remember that
+their remarks had possessed weight before; but now their sayings were
+treasured and repeated; everything they did seemed somehow to be
+regarded as remarkable; they had evidently lost the power of doing and
+saying commonplace things; moreover, their past history was raked up
+and discovered to bear marks of conspicuous originality. The village
+paper published biographical sketches of the boys.
+
+The Widow Douglas put Huck's money out at six per cent., and Judge
+Thatcher did the same with Tom's at Aunt Polly's request. Each lad had
+an income, now, that was simply prodigious--a dollar for every week-day
+in the year and half of the Sundays. It was just what the minister got
+--no, it was what he was promised--he generally couldn't collect it. A
+dollar and a quarter a week would board, lodge, and school a boy in
+those old simple days--and clothe him and wash him, too, for that
+matter.
+
+Judge Thatcher had conceived a great opinion of Tom. He said that no
+commonplace boy would ever have got his daughter out of the cave. When
+Becky told her father, in strict confidence, how Tom had taken her
+whipping at school, the Judge was visibly moved; and when she pleaded
+grace for the mighty lie which Tom had told in order to shift that
+whipping from her shoulders to his own, the Judge said with a fine
+outburst that it was a noble, a generous, a magnanimous lie--a lie that
+was worthy to hold up its head and march down through history breast to
+breast with George Washington's lauded Truth about the hatchet! Becky
+thought her father had never looked so tall and so superb as when he
+walked the floor and stamped his foot and said that. She went straight
+off and told Tom about it.
+
+Judge Thatcher hoped to see Tom a great lawyer or a great soldier some
+day. He said he meant to look to it that Tom should be admitted to the
+National Military Academy and afterward trained in the best law school
+in the country, in order that he might be ready for either career or
+both.
+
+Huck Finn's wealth and the fact that he was now under the Widow
+Douglas' protection introduced him into society--no, dragged him into
+it, hurled him into it--and his sufferings were almost more than he
+could bear. The widow's servants kept him clean and neat, combed and
+brushed, and they bedded him nightly in unsympathetic sheets that had
+not one little spot or stain which he could press to his heart and know
+for a friend. He had to eat with a knife and fork; he had to use
+napkin, cup, and plate; he had to learn his book, he had to go to
+church; he had to talk so properly that speech was become insipid in
+his mouth; whithersoever he turned, the bars and shackles of
+civilization shut him in and bound him hand and foot.
+
+He bravely bore his miseries three weeks, and then one day turned up
+missing. For forty-eight hours the widow hunted for him everywhere in
+great distress. The public were profoundly concerned; they searched
+high and low, they dragged the river for his body. Early the third
+morning Tom Sawyer wisely went poking among some old empty hogsheads
+down behind the abandoned slaughter-house, and in one of them he found
+the refugee. Huck had slept there; he had just breakfasted upon some
+stolen odds and ends of food, and was lying off, now, in comfort, with
+his pipe. He was unkempt, uncombed, and clad in the same old ruin of
+rags that had made him picturesque in the days when he was free and
+happy. Tom routed him out, told him the trouble he had been causing,
+and urged him to go home. Huck's face lost its tranquil content, and
+took a melancholy cast. He said:
+
+"Don't talk about it, Tom. I've tried it, and it don't work; it don't
+work, Tom. It ain't for me; I ain't used to it. The widder's good to
+me, and friendly; but I can't stand them ways. She makes me get up just
+at the same time every morning; she makes me wash, they comb me all to
+thunder; she won't let me sleep in the woodshed; I got to wear them
+blamed clothes that just smothers me, Tom; they don't seem to any air
+git through 'em, somehow; and they're so rotten nice that I can't set
+down, nor lay down, nor roll around anywher's; I hain't slid on a
+cellar-door for--well, it 'pears to be years; I got to go to church and
+sweat and sweat--I hate them ornery sermons! I can't ketch a fly in
+there, I can't chaw. I got to wear shoes all Sunday. The widder eats by
+a bell; she goes to bed by a bell; she gits up by a bell--everything's
+so awful reg'lar a body can't stand it."
+
+"Well, everybody does that way, Huck."
+
+"Tom, it don't make no difference. I ain't everybody, and I can't
+STAND it. It's awful to be tied up so. And grub comes too easy--I don't
+take no interest in vittles, that way. I got to ask to go a-fishing; I
+got to ask to go in a-swimming--dern'd if I hain't got to ask to do
+everything. Well, I'd got to talk so nice it wasn't no comfort--I'd got
+to go up in the attic and rip out awhile, every day, to git a taste in
+my mouth, or I'd a died, Tom. The widder wouldn't let me smoke; she
+wouldn't let me yell, she wouldn't let me gape, nor stretch, nor
+scratch, before folks--" [Then with a spasm of special irritation and
+injury]--"And dad fetch it, she prayed all the time! I never see such a
+woman! I HAD to shove, Tom--I just had to. And besides, that school's
+going to open, and I'd a had to go to it--well, I wouldn't stand THAT,
+Tom. Looky here, Tom, being rich ain't what it's cracked up to be. It's
+just worry and worry, and sweat and sweat, and a-wishing you was dead
+all the time. Now these clothes suits me, and this bar'l suits me, and
+I ain't ever going to shake 'em any more. Tom, I wouldn't ever got into
+all this trouble if it hadn't 'a' ben for that money; now you just take
+my sheer of it along with your'n, and gimme a ten-center sometimes--not
+many times, becuz I don't give a dern for a thing 'thout it's tollable
+hard to git--and you go and beg off for me with the widder."
+
+"Oh, Huck, you know I can't do that. 'Tain't fair; and besides if
+you'll try this thing just a while longer you'll come to like it."
+
+"Like it! Yes--the way I'd like a hot stove if I was to set on it long
+enough. No, Tom, I won't be rich, and I won't live in them cussed
+smothery houses. I like the woods, and the river, and hogsheads, and
+I'll stick to 'em, too. Blame it all! just as we'd got guns, and a
+cave, and all just fixed to rob, here this dern foolishness has got to
+come up and spile it all!"
+
+Tom saw his opportunity--
+
+"Lookyhere, Huck, being rich ain't going to keep me back from turning
+robber."
+
+"No! Oh, good-licks; are you in real dead-wood earnest, Tom?"
+
+"Just as dead earnest as I'm sitting here. But Huck, we can't let you
+into the gang if you ain't respectable, you know."
+
+Huck's joy was quenched.
+
+"Can't let me in, Tom? Didn't you let me go for a pirate?"
+
+"Yes, but that's different. A robber is more high-toned than what a
+pirate is--as a general thing. In most countries they're awful high up
+in the nobility--dukes and such."
+
+"Now, Tom, hain't you always ben friendly to me? You wouldn't shet me
+out, would you, Tom? You wouldn't do that, now, WOULD you, Tom?"
+
+"Huck, I wouldn't want to, and I DON'T want to--but what would people
+say? Why, they'd say, 'Mph! Tom Sawyer's Gang! pretty low characters in
+it!' They'd mean you, Huck. You wouldn't like that, and I wouldn't."
+
+Huck was silent for some time, engaged in a mental struggle. Finally
+he said:
+
+"Well, I'll go back to the widder for a month and tackle it and see if
+I can come to stand it, if you'll let me b'long to the gang, Tom."
+
+"All right, Huck, it's a whiz! Come along, old chap, and I'll ask the
+widow to let up on you a little, Huck."
+
+"Will you, Tom--now will you? That's good. If she'll let up on some of
+the roughest things, I'll smoke private and cuss private, and crowd
+through or bust. When you going to start the gang and turn robbers?"
+
+"Oh, right off. We'll get the boys together and have the initiation
+to-night, maybe."
+
+"Have the which?"
+
+"Have the initiation."
+
+"What's that?"
+
+"It's to swear to stand by one another, and never tell the gang's
+secrets, even if you're chopped all to flinders, and kill anybody and
+all his family that hurts one of the gang."
+
+"That's gay--that's mighty gay, Tom, I tell you."
+
+"Well, I bet it is. And all that swearing's got to be done at
+midnight, in the lonesomest, awfulest place you can find--a ha'nted
+house is the best, but they're all ripped up now."
+
+"Well, midnight's good, anyway, Tom."
+
+"Yes, so it is. And you've got to swear on a coffin, and sign it with
+blood."
+
+"Now, that's something LIKE! Why, it's a million times bullier than
+pirating. I'll stick to the widder till I rot, Tom; and if I git to be
+a reg'lar ripper of a robber, and everybody talking 'bout it, I reckon
+she'll be proud she snaked me in out of the wet."
+
+
+
+CONCLUSION
+
+SO endeth this chronicle. It being strictly a history of a BOY, it
+must stop here; the story could not go much further without becoming
+the history of a MAN. When one writes a novel about grown people, he
+knows exactly where to stop--that is, with a marriage; but when he
+writes of juveniles, he must stop where he best can.
+
+Most of the characters that perform in this book still live, and are
+prosperous and happy. Some day it may seem worth while to take up the
+story of the younger ones again and see what sort of men and women they
+turned out to be; therefore it will be wisest not to reveal any of that
+part of their lives at present.
diff --git a/libgo/go/net/testdata/invalid-ndots-resolv.conf b/libgo/go/net/testdata/invalid-ndots-resolv.conf
new file mode 100644
index 0000000000..084c1643de
--- /dev/null
+++ b/libgo/go/net/testdata/invalid-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:invalid \ No newline at end of file
diff --git a/libgo/go/net/testdata/large-ndots-resolv.conf b/libgo/go/net/testdata/large-ndots-resolv.conf
new file mode 100644
index 0000000000..72968eee91
--- /dev/null
+++ b/libgo/go/net/testdata/large-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:16 \ No newline at end of file
diff --git a/libgo/go/net/testdata/negative-ndots-resolv.conf b/libgo/go/net/testdata/negative-ndots-resolv.conf
new file mode 100644
index 0000000000..c11e0cc403
--- /dev/null
+++ b/libgo/go/net/testdata/negative-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:-1 \ No newline at end of file
diff --git a/libgo/go/net/textproto/header.go b/libgo/go/net/textproto/header.go
index 7fb32f8045..ed096d9a3c 100644
--- a/libgo/go/net/textproto/header.go
+++ b/libgo/go/net/textproto/header.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -16,15 +16,17 @@ func (h MIMEHeader) Add(key, value string) {
}
// Set sets the header entries associated with key to
-// the single element value. It replaces any existing
+// the single element value. It replaces any existing
// values associated with key.
func (h MIMEHeader) Set(key, value string) {
h[CanonicalMIMEHeaderKey(key)] = []string{value}
}
// Get gets the first value associated with the given key.
+// It is case insensitive; CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
-// Get is a convenience method. For more complex queries,
+// To access multiple values of a key, or to use non-canonical keys,
// access the map directly.
func (h MIMEHeader) Get(key string) string {
if h == nil {
diff --git a/libgo/go/net/textproto/pipeline.go b/libgo/go/net/textproto/pipeline.go
index ca50eddac3..2e283218b5 100644
--- a/libgo/go/net/textproto/pipeline.go
+++ b/libgo/go/net/textproto/pipeline.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -66,8 +66,8 @@ func (p *Pipeline) EndResponse(id uint) {
}
// A sequencer schedules a sequence of numbered events that must
-// happen in order, one after the other. The event numbering must start
-// at 0 and increment without skipping. The event number wraps around
+// happen in order, one after the other. The event numbering must start
+// at 0 and increment without skipping. The event number wraps around
// safely as long as there are not 2^32 simultaneous events pending.
type sequencer struct {
mu sync.Mutex
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
index 91bbb57304..e07d1d62e0 100644
--- a/libgo/go/net/textproto/reader.go
+++ b/libgo/go/net/textproto/reader.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -71,7 +71,7 @@ func (r *Reader) readLineSlice() ([]byte, error) {
// ReadContinuedLine reads a possibly continued line from r,
// eliding the final trailing ASCII white space.
// Lines after the first are considered continuations if they
-// begin with a space or tab character. In the returned data,
+// begin with a space or tab character. In the returned data,
// continuation lines are separated from the previous line
// only by a single space: the newline and leading white space
// are removed.
@@ -204,7 +204,7 @@ func parseCodeLine(line string, expectCode int) (code int, continued bool, messa
// ReadCodeLine reads a response code line of the form
// code message
// where code is a three-digit status code and the message
-// extends to the rest of the line. An example of such a line is:
+// extends to the rest of the line. An example of such a line is:
// 220 plan9.bell-labs.com ESMTP
//
// If the prefix of the status does not match the digits in expectCode,
@@ -366,7 +366,7 @@ func (d *dotReader) Read(b []byte) (n int, err error) {
d.state = stateBeginLine
break
}
- // Not part of \r\n. Emit saved \r
+ // Not part of \r\n. Emit saved \r
br.UnreadByte()
c = '\r'
d.state = stateData
@@ -552,9 +552,9 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
}
// CanonicalMIMEHeaderKey returns the canonical format of the
-// MIME header key s. The canonicalization converts the first
+// MIME header key s. The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
-// the rest are converted to lowercase. For example, the
+// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
// MIME header keys are assumed to be ASCII only.
// If s contains a space or invalid header field bytes, it is
@@ -581,18 +581,14 @@ func CanonicalMIMEHeaderKey(s string) string {
const toLower = 'a' - 'A'
// validHeaderFieldByte reports whether b is a valid byte in a header
-// field key. This is actually stricter than RFC 7230, which says:
+// field name. RFC 7230 says:
+// header-field = field-name ":" OWS field-value OWS
+// field-name = token
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// token = 1*tchar
-// TODO: revisit in Go 1.6+ and possibly expand this. But note that many
-// servers have historically dropped '_' to prevent ambiguities when mapping
-// to CGI environment variables.
func validHeaderFieldByte(b byte) bool {
- return ('A' <= b && b <= 'Z') ||
- ('a' <= b && b <= 'z') ||
- ('0' <= b && b <= '9') ||
- b == '-'
+ return int(b) < len(isTokenTable) && isTokenTable[b]
}
// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
@@ -682,3 +678,85 @@ func init() {
commonHeader[v] = v
}
}
+
+// isTokenTable is a copy of net/http/lex.go's isTokenTable.
+// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
+var isTokenTable = [127]bool{
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
+}
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
index 93d7939bb5..0c53d48b74 100644
--- a/libgo/go/net/textproto/reader_test.go
+++ b/libgo/go/net/textproto/reader_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -25,6 +25,12 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
{"user-agent", "User-Agent"},
{"USER-AGENT", "User-Agent"},
+ // Other valid tchar bytes in tokens:
+ {"foo-bar_baz", "Foo-Bar_baz"},
+ {"foo-bar$baz", "Foo-Bar$baz"},
+ {"foo-bar~baz", "Foo-Bar~baz"},
+ {"foo-bar*baz", "Foo-Bar*baz"},
+
// Non-ASCII or anything with spaces or non-token chars is unchanged:
{"üser-agenT", "üser-agenT"},
{"a B", "a B"},
diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go
index 026eb026b1..8fd781e777 100644
--- a/libgo/go/net/textproto/textproto.go
+++ b/libgo/go/net/textproto/textproto.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -87,7 +87,7 @@ func Dial(network, addr string) (*Conn, error) {
}
// Cmd is a convenience method that sends a command after
-// waiting its turn in the pipeline. The command text is the
+// waiting its turn in the pipeline. The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
diff --git a/libgo/go/net/textproto/writer.go b/libgo/go/net/textproto/writer.go
index 03e2fd658e..1bc5974c6c 100644
--- a/libgo/go/net/textproto/writer.go
+++ b/libgo/go/net/textproto/writer.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -36,7 +36,7 @@ func (w *Writer) PrintfLine(format string, args ...interface{}) error {
// DotWriter returns a writer that can be used to write a dot-encoding to w.
// It takes care of inserting leading dots when necessary,
// translating line-ending \n into \r\n, and adding the final .\r\n line
-// when the DotWriter is closed. The caller should close the
+// when the DotWriter is closed. The caller should close the
// DotWriter before the next call to a method on w.
//
// See the documentation for Reader's DotReader method for details about dot-encoding.
diff --git a/libgo/go/net/textproto/writer_test.go b/libgo/go/net/textproto/writer_test.go
index e03ab5e15f..ac03669fa2 100644
--- a/libgo/go/net/textproto/writer_test.go
+++ b/libgo/go/net/textproto/writer_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index 98e3164fb9..55bbf4402d 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -6,6 +6,7 @@ package net
import (
"fmt"
+ "internal/testenv"
"io"
"io/ioutil"
"net/internal/socktest"
@@ -26,6 +27,8 @@ var dialTimeoutTests = []struct {
{-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
{0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
{-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
+ {-1 << 63, 0, time.Second, 100 * time.Millisecond},
+ {0, -1 << 63, time.Second, 100 * time.Millisecond},
{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
@@ -38,19 +41,6 @@ func TestDialTimeout(t *testing.T) {
defer func() { testHookDialChannel = origTestHookDialChannel }()
defer sw.Set(socktest.FilterConnect, nil)
- // Avoid tracking open-close jitterbugs between netFD and
- // socket that leads to confusion of information inside
- // socktest.Switch.
- // It may happen when the Dial call bumps against TCP
- // simultaneous open. See selfConnect in tcpsock_posix.go.
- defer func() {
- sw.Set(socktest.FilterClose, nil)
- forceCloseSockets()
- }()
- sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
- return nil, errTimedout
- })
-
for i, tt := range dialTimeoutTests {
switch runtime.GOOS {
case "plan9", "windows":
@@ -99,6 +89,56 @@ func TestDialTimeout(t *testing.T) {
}
}
+var dialTimeoutMaxDurationTests = []struct {
+ timeout time.Duration
+ delta time.Duration // for deadline
+}{
+ // Large timeouts that will overflow an int64 unix nanos.
+ {1<<63 - 1, 0},
+ {0, 1<<63 - 1},
+}
+
+func TestDialTimeoutMaxDuration(t *testing.T) {
+ if runtime.GOOS == "openbsd" {
+ testenv.SkipFlaky(t, 15157)
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ for i, tt := range dialTimeoutMaxDurationTests {
+ ch := make(chan error)
+ max := time.NewTimer(250 * time.Millisecond)
+ defer max.Stop()
+ go func() {
+ d := Dialer{Timeout: tt.timeout}
+ if tt.delta != 0 {
+ d.Deadline = time.Now().Add(tt.delta)
+ }
+ c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+ if err == nil {
+ c.Close()
+ }
+ ch <- err
+ }()
+
+ select {
+ case <-max.C:
+ t.Fatalf("#%d: Dial didn't return in an expected time", i)
+ case err := <-ch:
+ if perr := parseDialError(err); perr != nil {
+ t.Error(perr)
+ }
+ if err != nil {
+ t.Errorf("#%d: %v", i, err)
+ }
+ }
+ }
+}
+
var acceptTimeoutTests = []struct {
timeout time.Duration
xerrs [2]error // expected errors in transition
@@ -111,6 +151,7 @@ var acceptTimeoutTests = []struct {
}
func TestAcceptTimeout(t *testing.T) {
+ testenv.SkipFlaky(t, 17948)
t.Parallel()
switch runtime.GOOS {
@@ -124,16 +165,18 @@ func TestAcceptTimeout(t *testing.T) {
}
defer ln.Close()
+ var wg sync.WaitGroup
for i, tt := range acceptTimeoutTests {
if tt.timeout < 0 {
+ wg.Add(1)
go func() {
- c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+ defer wg.Done()
+ d := Dialer{Timeout: 100 * time.Millisecond}
+ c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
if err != nil {
t.Error(err)
return
}
- var b [1]byte
- c.Read(b[:])
c.Close()
}()
}
@@ -154,13 +197,14 @@ func TestAcceptTimeout(t *testing.T) {
}
if err == nil {
c.Close()
- time.Sleep(tt.timeout / 3)
+ time.Sleep(10 * time.Millisecond)
continue
}
break
}
}
}
+ wg.Wait()
}
func TestAcceptTimeoutMustReturn(t *testing.T) {
@@ -261,13 +305,6 @@ var readTimeoutTests = []struct {
}
func TestReadTimeout(t *testing.T) {
- t.Parallel()
-
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
handler := func(ls *localServer, ln Listener) {
c, err := ln.Accept()
if err != nil {
@@ -393,7 +430,7 @@ var readFromTimeoutTests = []struct {
func TestReadFromTimeout(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
}
@@ -467,11 +504,6 @@ var writeTimeoutTests = []struct {
func TestWriteTimeout(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -587,7 +619,7 @@ func TestWriteToTimeout(t *testing.T) {
t.Parallel()
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -639,11 +671,6 @@ func TestWriteToTimeout(t *testing.T) {
func TestReadTimeoutFluctuation(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -677,11 +704,6 @@ func TestReadTimeoutFluctuation(t *testing.T) {
func TestReadFromTimeoutFluctuation(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
c1, err := newLocalPacketListener("udp")
if err != nil {
t.Fatal(err)
@@ -787,11 +809,6 @@ func (b neverEnding) Read(p []byte) (int, error) {
}
func testVariousDeadlines(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
type result struct {
n int64
err error
@@ -988,7 +1005,7 @@ func TestReadWriteDeadlineRace(t *testing.T) {
t.Parallel()
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index 9292133aeb..841ef53359 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -1,9 +1,23 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
+import (
+ "context"
+ "syscall"
+)
+
+// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgUDP and
+// WriteMsgUDP methods of UDPConn are not implemented.
+
+// BUG(mikio): On Windows, the File method of UDPConn is not
+// implemented.
+
+// BUG(mikio): On NaCl, the ListenMulticastUDP function is not
+// implemented.
+
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
@@ -45,6 +59,9 @@ func (a *UDPAddr) opAddr() Addr {
// "udp6". A literal address or host name for IPv6 must be enclosed
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
switch net {
case "udp", "udp4", "udp6":
@@ -53,9 +70,185 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(net, addr, noDeadline)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
if err != nil {
return nil, err
}
return addrs.first(isIPv4).(*UDPAddr), nil
}
+
+// UDPConn is the implementation of the Conn and PacketConn interfaces
+// for UDP network connections.
+type UDPConn struct {
+ conn
+}
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
+func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, addr, err
+}
+
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
+}
+
+// ReadMsgUDP reads a packet from c, copying the payload into b and
+// the associated out-of-band data into oob. It returns the number
+// of bytes copied into b, the number of bytes copied into oob, the
+// flags that were set on the packet and the source address of the
+// packet.
+func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, syscall.EINVAL
+ }
+ n, oobn, flags, addr, err = c.readMsg(b, oob)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload
+// from b.
+//
+// WriteToUDP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetWriteDeadline. On packet-oriented connections, write timeouts
+// are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.writeTo(b, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+ }
+ n, err := c.writeTo(b, a)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
+// to c's remote destination address if c is connected (in which case
+// addr must be nil). The payload is copied from b and the associated
+// out-of-band data is copied from oob. It returns the number of
+// payload and out-of-band bytes written.
+func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
+ if !c.ok() {
+ return 0, 0, syscall.EINVAL
+ }
+ n, oobn, err = c.writeMsg(b, oob, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
+// used as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if raddr == nil {
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+ }
+ c, err := dialUDP(context.Background(), net, laddr, raddr)
+ if err != nil {
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the local
+// address laddr. Net must be "udp", "udp4", or "udp6". If laddr has
+// a port of 0, ListenUDP will choose an available port.
+// The LocalAddr method of the returned UDPConn can be used to
+// discover the port. The returned connection's ReadFrom and WriteTo
+// methods can be used to receive and send UDP packets with per-packet
+// addressing.
+func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if laddr == nil {
+ laddr = &UDPAddr{}
+ }
+ c, err := listenUDP(context.Background(), net, laddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
+
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// addressed to the group address gaddr on the interface ifi.
+// Network must be "udp", "udp4" or "udp6".
+// ListenMulticastUDP uses the system-assigned multicast interface
+// when ifi is nil, although this is not recommended because the
+// assignment depends on platforms and sometimes it might require
+// routing configuration.
+//
+// ListenMulticastUDP is just for convenience of simple, small
+// applications. There are golang.org/x/net/ipv4 and
+// golang.org/x/net/ipv6 packages for general purpose uses.
+func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ switch network {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
+ }
+ if gaddr == nil || gaddr.IP == nil {
+ return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
+ }
+ c, err := listenMulticastUDP(context.Background(), network, ifi, gaddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
index 1ba57a227e..1ce7f88c62 100644
--- a/libgo/go/net/udpsock_plan9.go
+++ b/libgo/go/net/udpsock_plan9.go
@@ -1,42 +1,24 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
+ "context"
"errors"
"os"
"syscall"
- "time"
)
-// UDPConn is the implementation of the Conn and PacketConn interfaces
-// for UDP network connections.
-type UDPConn struct {
- conn
-}
-
-func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
-
-// ReadFromUDP reads a UDP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
- if !c.ok() || c.fd.data == nil {
- return 0, nil, syscall.EINVAL
- }
+func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
buf := make([]byte, udpHeaderSize+len(b))
- m, err := c.fd.data.Read(buf)
+ m, err := c.fd.Read(buf)
if err != nil {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ return 0, nil, err
}
if m < udpHeaderSize {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")}
+ return 0, nil, errors.New("short read reading UDP header")
}
buf = buf[:m]
@@ -45,36 +27,13 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
}
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
- return c.ReadFromUDP(b)
-}
-
-// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob. It returns the number
-// of bytes copied into b, the number of bytes copied into oob, the
-// flags that were set on the packet and the source address of the
-// packet.
-func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
- return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+ return 0, 0, 0, nil, syscall.EPLAN9
}
-// WriteToUDP writes a UDP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
- if !c.ok() || c.fd.data == nil {
- return 0, syscall.EINVAL
- }
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
if addr == nil {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+ return 0, errMissingAddress
}
h := new(udpHeader)
h.raddr = addr.IP.To16()
@@ -86,53 +45,18 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
buf := make([]byte, udpHeaderSize+len(b))
i := copy(buf, h.Bytes())
copy(buf[i:], b)
- if _, err := c.fd.data.Write(buf); err != nil {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ if _, err := c.fd.Write(buf); err != nil {
+ return 0, err
}
return len(b), nil
}
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- a, ok := addr.(*UDPAddr)
- if !ok {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
- }
- return c.WriteToUDP(b, a)
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
+ return 0, 0, syscall.EPLAN9
}
-// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
-// to c's remote destination address if c is connected (in which case
-// addr must be nil). The payload is copied from b and the associated
-// out-of-band data is copied from oob. It returns the number of
-// payload and out-of-band bytes written.
-func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
- return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
-}
-
-// DialUDP connects to the remote address raddr on the network net,
-// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
-// used as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
- return dialUDP(net, laddr, raddr, noDeadline)
-}
-
-func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
- if !deadline.IsZero() {
- panic("net.dialUDP: deadline not implemented on Plan 9")
- }
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if raddr == nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
- }
- fd, err := dialPlan9(net, laddr, raddr)
+func dialUDP(ctx context.Context, net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+ fd, err := dialPlan9(ctx, net, laddr, raddr)
if err != nil {
return nil, err
}
@@ -167,49 +91,59 @@ func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
return h, b
}
-// ListenUDP listens for incoming UDP packets addressed to the local
-// address laddr. Net must be "udp", "udp4", or "udp6". If laddr has
-// a port of 0, ListenUDP will choose an available port.
-// The LocalAddr method of the returned UDPConn can be used to
-// discover the port. The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send UDP packets with per-packet
-// addressing.
-func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- laddr = &UDPAddr{}
- }
- l, err := listenPlan9(net, laddr)
+func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) {
+ l, err := listenPlan9(ctx, network, laddr)
if err != nil {
return nil, err
}
_, err = l.ctl.WriteString("headers")
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
fd, err := l.netFD()
return newUDPConn(fd), err
}
-// ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on the interface ifi.
-// Network must be "udp", "udp4" or "udp6".
-// ListenMulticastUDP uses the system-assigned multicast interface
-// when ifi is nil, although this is not recommended because the
-// assignment depends on platforms and sometimes it might require
-// routing configuration.
-//
-// ListenMulticastUDP is just for convenience of simple, small
-// applications. There are golang.org/x/net/ipv4 and
-// golang.org/x/net/ipv6 packages for general purpose uses.
-func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
- return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9}
+func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ l, err := listenPlan9(ctx, network, gaddr)
+ if err != nil {
+ return nil, err
+ }
+ _, err = l.ctl.WriteString("headers")
+ if err != nil {
+ return nil, err
+ }
+ var addrs []Addr
+ if ifi != nil {
+ addrs, err = ifi.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ addrs, err = InterfaceAddrs()
+ if err != nil {
+ return nil, err
+ }
+ }
+ for _, addr := range addrs {
+ if ipnet, ok := addr.(*IPNet); ok {
+ _, err = l.ctl.WriteString("addmulti " + ipnet.IP.String() + " " + gaddr.IP.String())
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return nil, err
+ }
+ fd, err := l.netFD()
+ if err != nil {
+ return nil, err
+ }
+ return newUDPConn(fd), nil
}
diff --git a/libgo/go/net/udpsock_plan9_test.go b/libgo/go/net/udpsock_plan9_test.go
new file mode 100644
index 0000000000..09f5a5dc65
--- /dev/null
+++ b/libgo/go/net/udpsock_plan9_test.go
@@ -0,0 +1,69 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+func TestListenMulticastUDP(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ ifcs, err := Interfaces()
+ if err != nil {
+ t.Skip(err.Error())
+ }
+ if len(ifcs) == 0 {
+ t.Skip("no network interfaces found")
+ }
+
+ var mifc *Interface
+ for _, ifc := range ifcs {
+ if ifc.Flags&FlagUp|FlagMulticast != FlagUp|FlagMulticast {
+ continue
+ }
+ mifc = &ifc
+ break
+ }
+
+ if mifc == nil {
+ t.Skipf("no multicast interfaces found")
+ }
+
+ c1, err := ListenMulticastUDP("udp4", mifc, &UDPAddr{IP: ParseIP("224.0.0.254")})
+ if err != nil {
+ t.Fatalf("multicast not working on %s", runtime.GOOS)
+ }
+ c1addr := c1.LocalAddr().(*UDPAddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c1.Close()
+
+ c2, err := ListenUDP("udp4", &UDPAddr{IP: IPv4zero, Port: 0})
+ c2addr := c2.LocalAddr().(*UDPAddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c2.Close()
+
+ n, err := c2.WriteToUDP([]byte("data"), c1addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 4 {
+ t.Fatalf("got %d; want 4", n)
+ }
+
+ n, err = c1.WriteToUDP([]byte("data"), c2addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 4 {
+ t.Fatalf("got %d; want 4", n)
+ }
+}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index 932c6ce713..72aadca5dc 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,8 +7,8 @@
package net
import (
+ "context"
"syscall"
- "time"
)
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
@@ -38,25 +38,11 @@ func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
-// UDPConn is the implementation of the Conn and PacketConn interfaces
-// for UDP network connections.
-type UDPConn struct {
- conn
+func (a *UDPAddr) toLocal(net string) sockaddr {
+ return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
}
-func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
-
-// ReadFromUDP reads a UDP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
+func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
var addr *UDPAddr
n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
@@ -65,33 +51,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
case *syscall.SockaddrInet6:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return n, addr, err
}
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
- n, addr, err := c.ReadFromUDP(b)
- if addr == nil {
- return n, nil, err
- }
- return n, addr, err
-}
-
-// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob. It returns the number
-// of bytes copied into b, the number of bytes copied into oob, the
-// flags that were set on the packet and the source address of the
-// packet.
-func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
- if !c.ok() {
- return 0, 0, 0, nil, syscall.EINVAL
- }
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
var sa syscall.Sockaddr
n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
@@ -100,159 +63,68 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
case *syscall.SockaddrInet6:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return
}
-// WriteToUDP writes a UDP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
if c.fd.isConnected {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, ErrWriteToConnected
}
if addr == nil {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+ return 0, errMissingAddress
}
sa, err := addr.sockaddr(c.fd.family)
if err != nil {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- n, err := c.fd.writeTo(b, sa)
- if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- return n, err
-}
-
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- a, ok := addr.(*UDPAddr)
- if !ok {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+ return 0, err
}
- return c.WriteToUDP(b, a)
+ return c.fd.writeTo(b, sa)
}
-// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
-// to c's remote destination address if c is connected (in which case
-// addr must be nil). The payload is copied from b and the associated
-// out-of-band data is copied from oob. It returns the number of
-// payload and out-of-band bytes written.
-func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
- if !c.ok() {
- return 0, 0, syscall.EINVAL
- }
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
if c.fd.isConnected && addr != nil {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, 0, ErrWriteToConnected
}
if !c.fd.isConnected && addr == nil {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: errMissingAddress}
+ return 0, 0, errMissingAddress
}
- var sa syscall.Sockaddr
- sa, err = addr.sockaddr(c.fd.family)
- if err != nil {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- n, oobn, err = c.fd.writeMsg(b, oob, sa)
+ sa, err := addr.sockaddr(c.fd.family)
if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ return 0, 0, err
}
- return
+ return c.fd.writeMsg(b, oob, sa)
}
-// DialUDP connects to the remote address raddr on the network net,
-// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
-// used as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if raddr == nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
- }
- return dialUDP(net, laddr, raddr, noDeadline)
-}
-
-func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
- fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial", noCancel)
+func dialUDP(ctx context.Context, net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+ fd, err := internetSocket(ctx, net, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial")
if err != nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ return nil, err
}
return newUDPConn(fd), nil
}
-// ListenUDP listens for incoming UDP packets addressed to the local
-// address laddr. Net must be "udp", "udp4", or "udp6". If laddr has
-// a port of 0, ListenUDP will choose an available port.
-// The LocalAddr method of the returned UDPConn can be used to
-// discover the port. The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send UDP packets with per-packet
-// addressing.
-func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- laddr = &UDPAddr{}
- }
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", noCancel)
+func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) {
+ fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_DGRAM, 0, "listen")
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+ return nil, err
}
return newUDPConn(fd), nil
}
-// ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on the interface ifi.
-// Network must be "udp", "udp4" or "udp6".
-// ListenMulticastUDP uses the system-assigned multicast interface
-// when ifi is nil, although this is not recommended because the
-// assignment depends on platforms and sometimes it might require
-// routing configuration.
-//
-// ListenMulticastUDP is just for convenience of simple, small
-// applications. There are golang.org/x/net/ipv4 and
-// golang.org/x/net/ipv6 packages for general purpose uses.
-func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
- switch network {
- case "udp", "udp4", "udp6":
- default:
- return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
- }
- if gaddr == nil || gaddr.IP == nil {
- return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
- }
- fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", noCancel)
+func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ fd, err := internetSocket(ctx, network, gaddr, nil, syscall.SOCK_DGRAM, 0, "listen")
if err != nil {
- return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
+ return nil, err
}
c := newUDPConn(fd)
if ip4 := gaddr.IP.To4(); ip4 != nil {
if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
c.Close()
- return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
+ return nil, err
}
} else {
if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
c.Close()
- return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+ return nil, err
}
}
return c, nil
diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udpsock_test.go
index b25f96a3fd..708cc10120 100644
--- a/libgo/go/net/udp_test.go
+++ b/libgo/go/net/udpsock_test.go
@@ -1,16 +1,54 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
+ "internal/testenv"
"reflect"
"runtime"
"testing"
"time"
)
+func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
+ testHookUninstaller.Do(uninstallTestHooks)
+
+ if !supportsIPv6 {
+ b.Skip("IPv6 is not supported")
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ b.Skip("loopback interface not found")
+ }
+ lla := ipv6LinkLocalUnicastAddr(ifi)
+ if lla == "" {
+ b.Skip("IPv6 link-local unicast address not found")
+ }
+
+ c1, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer c1.Close()
+ c2, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer c2.Close()
+
+ var buf [1]byte
+ for i := 0; i < b.N; i++ {
+ if _, err := c1.WriteTo(buf[:], c2.LocalAddr()); err != nil {
+ b.Fatal(err)
+ }
+ if _, _, err := c2.ReadFrom(buf[:]); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
type resolveUDPAddrTest struct {
network string
litAddrOrName string
@@ -34,6 +72,17 @@ var resolveUDPAddrTests = []resolveUDPAddrTest{
{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+
+ {"udp", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+ {"udp", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 53}, nil},
+ {"udp", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
+ {"udp4", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+ {"udp4", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+ {"udp6", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
+
+ {"udp4", "[2001:db8::1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+ {"udp6", "127.0.0.1:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+ {"udp6", "[::ffff:127.0.0.1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
}
func TestResolveUDPAddr(t *testing.T) {
@@ -41,21 +90,17 @@ func TestResolveUDPAddr(t *testing.T) {
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
- for i, tt := range resolveUDPAddrTests {
+ for _, tt := range resolveUDPAddrTests {
addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
- if err != tt.err {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(addr, tt.addr) {
- t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
- }
- if err != nil {
+ if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
continue
}
- rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
- if err != nil {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(rtaddr, addr) {
- t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+ if err == nil {
+ addr2, err := ResolveUDPAddr(addr.Network(), addr.String())
+ if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+ t.Errorf("(%q, %q): ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+ }
}
}
}
@@ -178,9 +223,7 @@ var udpConnLocalNameTests = []struct {
}
func TestUDPConnLocalName(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
for _, tt := range udpConnLocalNameTests {
c, err := ListenUDP(tt.net, tt.laddr)
@@ -234,9 +277,8 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
}
func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("avoid external network")
- }
+ testenv.MustHaveExternalNetwork(t)
+
if !supportsIPv6 {
t.Skip("IPv6 is not supported")
}
@@ -356,7 +398,7 @@ func TestUDPZeroByteBuffer(t *testing.T) {
switch err {
case nil: // ReadFrom succeeds
default: // Read may timeout, it depends on the platform
- if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ
+ if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZ
t.Fatal(err)
}
}
diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go
index eb91d0d630..b25d492f59 100644
--- a/libgo/go/net/unixsock.go
+++ b/libgo/go/net/unixsock.go
@@ -1,9 +1,17 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
+import (
+ "context"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+)
+
// UnixAddr represents the address of a Unix domain socket end point.
type UnixAddr struct {
Name string
@@ -45,3 +53,275 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
return nil, UnknownNetworkError(net)
}
}
+
+// UnixConn is an implementation of the Conn interface for connections
+// to Unix domain sockets.
+type UnixConn struct {
+ conn
+}
+
+// CloseRead shuts down the reading side of the Unix domain connection.
+// Most callers should just use Close.
+func (c *UnixConn) CloseRead() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := c.fd.closeRead(); err != nil {
+ return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// CloseWrite shuts down the writing side of the Unix domain connection.
+// Most callers should just use Close.
+func (c *UnixConn) CloseWrite() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ if err := c.fd.closeWrite(); err != nil {
+ return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return nil
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b. It
+// returns the number of bytes copied into b and the source address of
+// the packet.
+//
+// ReadFromUnix can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
+func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, addr, err
+}
+
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
+ if !c.ok() {
+ return 0, nil, syscall.EINVAL
+ }
+ n, addr, err := c.readFrom(b)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
+}
+
+// ReadMsgUnix reads a packet from c, copying the payload into b and
+// the associated out-of-band data into oob. It returns the number of
+// bytes copied into b, the number of bytes copied into oob, the flags
+// that were set on the packet, and the source address of the packet.
+//
+// Note that if len(b) == 0 and len(oob) > 0, this function will still
+// read (and discard) 1 byte from the connection.
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, syscall.EINVAL
+ }
+ n, oobn, flags, addr, err = c.readMsg(b, oob)
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetWriteDeadline. On packet-oriented connections, write timeouts
+// are rare.
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.writeTo(b, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ a, ok := addr.(*UnixAddr)
+ if !ok {
+ return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+ }
+ n, err := c.writeTo(b, a)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+ }
+ return n, err
+}
+
+// WriteMsgUnix writes a packet to addr via c, copying the payload
+// from b and the associated out-of-band data from oob. It returns
+// the number of payload and out-of-band bytes written.
+//
+// Note that if len(b) == 0 and len(oob) > 0, this function will still
+// write 1 byte to the connection.
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
+ if !c.ok() {
+ return 0, 0, syscall.EINVAL
+ }
+ n, oobn, err = c.writeMsg(b, oob, addr)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+ }
+ return
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix", "unixgram" or "unixpacket". If laddr is not
+// nil, it is used as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+ switch net {
+ case "unix", "unixgram", "unixpacket":
+ default:
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ c, err := dialUnix(context.Background(), net, laddr, raddr)
+ if err != nil {
+ return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
+
+// UnixListener is a Unix domain socket listener. Clients should
+// typically use variables of type Listener instead of assuming Unix
+// domain sockets.
+type UnixListener struct {
+ fd *netFD
+ path string
+ unlink bool
+ unlinkOnce sync.Once
+}
+
+func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
+
+// AcceptUnix accepts the next incoming call and returns the new
+// connection.
+func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ c, err := l.accept()
+ if err != nil {
+ return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface.
+// Returned connections will be of type *UnixConn.
+func (l *UnixListener) Accept() (Conn, error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ c, err := l.accept()
+ if err != nil {
+ return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return c, nil
+}
+
+// Close stops listening on the Unix address. Already accepted
+// connections are not closed.
+func (l *UnixListener) Close() error {
+ if !l.ok() {
+ return syscall.EINVAL
+ }
+ if err := l.close(); err != nil {
+ return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return nil
+}
+
+// Addr returns the listener's network address.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
+func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *UnixListener) SetDeadline(t time.Time) error {
+ if !l.ok() {
+ return syscall.EINVAL
+ }
+ if err := l.fd.setDeadline(t); err != nil {
+ return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return nil
+}
+
+// File returns a copy of the underlying os.File, set to blocking
+// mode. It is the caller's responsibility to close f when finished.
+// Closing l does not affect f, and closing f does not affect l.
+//
+// The returned os.File's file descriptor is different from the
+// connection's. Attempting to change properties of the original
+// using this duplicate may or may not have the desired effect.
+func (l *UnixListener) File() (f *os.File, err error) {
+ if !l.ok() {
+ return nil, syscall.EINVAL
+ }
+ f, err = l.file()
+ if err != nil {
+ err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ }
+ return
+}
+
+// ListenUnix announces on the Unix domain socket laddr and returns a
+// Unix listener. The network net must be "unix" or "unixpacket".
+func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
+ switch net {
+ case "unix", "unixpacket":
+ default:
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if laddr == nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
+ }
+ ln, err := listenUnix(context.Background(), net, laddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+ }
+ return ln, nil
+}
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed
+// to the local address laddr. The network net must be "unixgram".
+// The returned connection's ReadFrom and WriteTo methods can be used
+// to receive and send packets with per-packet addressing.
+func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
+ switch net {
+ case "unixgram":
+ default:
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+ }
+ if laddr == nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
+ }
+ c, err := listenUnixgram(context.Background(), net, laddr)
+ if err != nil {
+ return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+ }
+ return c, nil
+}
diff --git a/libgo/go/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go
index 84b6b600f6..e70eb211bb 100644
--- a/libgo/go/net/unixsock_plan9.go
+++ b/libgo/go/net/unixsock_plan9.go
@@ -1,147 +1,51 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
+ "context"
"os"
"syscall"
- "time"
)
-// UnixConn is an implementation of the Conn interface for connections
-// to Unix domain sockets.
-type UnixConn struct {
- conn
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
+ return 0, nil, syscall.EPLAN9
}
-// ReadFromUnix reads a packet from c, copying the payload into b. It
-// returns the number of bytes copied into b and the source address of
-// the packet.
-//
-// ReadFromUnix can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+ return 0, 0, 0, nil, syscall.EPLAN9
}
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
- return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
+ return 0, syscall.EPLAN9
}
-// ReadMsgUnix reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob. It returns the number of
-// bytes copied into b, the number of bytes copied into oob, the flags
-// that were set on the packet, and the source address of the packet.
-func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
- return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
+ return 0, 0, syscall.EPLAN9
}
-// WriteToUnix writes a packet to addr via c, copying the payload from b.
-//
-// WriteToUnix can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func dialUnix(ctx context.Context, network string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+ return nil, syscall.EPLAN9
}
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
- return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
+func (ln *UnixListener) accept() (*UnixConn, error) {
+ return nil, syscall.EPLAN9
}
-// WriteMsgUnix writes a packet to addr via c, copying the payload
-// from b and the associated out-of-band data from oob. It returns
-// the number of payload and out-of-band bytes written.
-func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
- return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func (ln *UnixListener) close() error {
+ return syscall.EPLAN9
}
-// CloseRead shuts down the reading side of the Unix domain connection.
-// Most callers should just use Close.
-func (c *UnixConn) CloseRead() error {
- return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (ln *UnixListener) file() (*os.File, error) {
+ return nil, syscall.EPLAN9
}
-// CloseWrite shuts down the writing side of the Unix domain connection.
-// Most callers should just use Close.
-func (c *UnixConn) CloseWrite() error {
- return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
+ return nil, syscall.EPLAN9
}
-// DialUnix connects to the remote address raddr on the network net,
-// which must be "unix", "unixgram" or "unixpacket". If laddr is not
-// nil, it is used as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
- return dialUnix(net, laddr, raddr, noDeadline)
-}
-
-func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
-}
-
-// UnixListener is a Unix domain socket listener. Clients should
-// typically use variables of type Listener instead of assuming Unix
-// domain sockets.
-type UnixListener struct {
- fd *netFD
-}
-
-// ListenUnix announces on the Unix domain socket laddr and returns a
-// Unix listener. The network net must be "unix" or "unixpacket".
-func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
-}
-
-// AcceptUnix accepts the next incoming call and returns the new
-// connection.
-func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
- return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
-}
-
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *UnixListener) Accept() (Conn, error) {
- return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
-}
-
-// Close stops listening on the Unix address. Already accepted
-// connections are not closed.
-func (l *UnixListener) Close() error {
- return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
-}
-
-// Addr returns the listener's network address.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
-func (l *UnixListener) Addr() Addr { return nil }
-
-// SetDeadline sets the deadline associated with the listener.
-// A zero time value disables the deadline.
-func (l *UnixListener) SetDeadline(t time.Time) error {
- return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
-}
-
-// File returns a copy of the underlying os.File, set to blocking
-// mode. It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// The returned os.File's file descriptor is different from the
-// connection's. Attempting to change properties of the original
-// using this duplicate may or may not have the desired effect.
-func (l *UnixListener) File() (*os.File, error) {
- return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
-}
-
-// ListenUnixgram listens for incoming Unix datagram packets addressed
-// to the local address laddr. The network net must be "unixgram".
-// The returned connection's ReadFrom and WriteTo methods can be used
-// to receive and send packets with per-packet addressing.
-func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) {
+ return nil, syscall.EPLAN9
}
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index fb2397e26f..a8f892e6c4 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,13 +7,13 @@
package net
import (
+ "context"
"errors"
"os"
"syscall"
- "time"
)
-func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Time) (*netFD, error) {
+func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string) (*netFD, error) {
var sotype int
switch net {
case "unix":
@@ -42,7 +42,7 @@ func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Ti
return nil, errors.New("unknown mode: " + mode)
}
- fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline, noCancel)
+ fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr)
if err != nil {
return nil, err
}
@@ -94,25 +94,11 @@ func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return &syscall.SockaddrUnix{Name: a.Name}, nil
}
-// UnixConn is an implementation of the Conn interface for connections
-// to Unix domain sockets.
-type UnixConn struct {
- conn
+func (a *UnixAddr) toLocal(net string) sockaddr {
+ return a
}
-func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
-
-// ReadFromUnix reads a packet from c, copying the payload into b. It
-// returns the number of bytes copied into b and the source address of
-// the packet.
-//
-// ReadFromUnix can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
var addr *UnixAddr
n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
@@ -121,211 +107,66 @@ func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return n, addr, err
-}
-
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
- n, addr, err := c.ReadFromUnix(b)
- if addr == nil {
- return n, nil, err
- }
return n, addr, err
}
-// ReadMsgUnix reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob. It returns the number of
-// bytes copied into b, the number of bytes copied into oob, the flags
-// that were set on the packet, and the source address of the packet.
-func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
- if !c.ok() {
- return 0, 0, 0, nil, syscall.EINVAL
- }
- n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+ var sa syscall.Sockaddr
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
return
}
-// WriteToUnix writes a packet to addr via c, copying the payload from b.
-//
-// WriteToUnix can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline. On packet-oriented connections, write timeouts
-// are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
if c.fd.isConnected {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, ErrWriteToConnected
}
if addr == nil {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+ return 0, errMissingAddress
}
if addr.Net != sotypeToNet(c.fd.sotype) {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+ return 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
- n, err := c.fd.writeTo(b, sa)
- if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- return n, err
-}
-
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- a, ok := addr.(*UnixAddr)
- if !ok {
- return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
- }
- return c.WriteToUnix(b, a)
+ return c.fd.writeTo(b, sa)
}
-// WriteMsgUnix writes a packet to addr via c, copying the payload
-// from b and the associated out-of-band data from oob. It returns
-// the number of payload and out-of-band bytes written.
-func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
- if !c.ok() {
- return 0, 0, syscall.EINVAL
- }
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+ return 0, 0, ErrWriteToConnected
}
var sa syscall.Sockaddr
if addr != nil {
if addr.Net != sotypeToNet(c.fd.sotype) {
- return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+ return 0, 0, syscall.EAFNOSUPPORT
}
sa = &syscall.SockaddrUnix{Name: addr.Name}
}
- n, oobn, err = c.fd.writeMsg(b, oob, sa)
- if err != nil {
- err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
- }
- return
-}
-
-// CloseRead shuts down the reading side of the Unix domain connection.
-// Most callers should just use Close.
-func (c *UnixConn) CloseRead() error {
- if !c.ok() {
- return syscall.EINVAL
- }
- err := c.fd.closeRead()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return err
-}
-
-// CloseWrite shuts down the writing side of the Unix domain connection.
-// Most callers should just use Close.
-func (c *UnixConn) CloseWrite() error {
- if !c.ok() {
- return syscall.EINVAL
- }
- err := c.fd.closeWrite()
- if err != nil {
- err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
- return err
-}
-
-// DialUnix connects to the remote address raddr on the network net,
-// which must be "unix", "unixgram" or "unixpacket". If laddr is not
-// nil, it is used as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
- switch net {
- case "unix", "unixgram", "unixpacket":
- default:
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- return dialUnix(net, laddr, raddr, noDeadline)
+ return c.fd.writeMsg(b, oob, sa)
}
-func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
- fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
+func dialUnix(ctx context.Context, net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+ fd, err := unixSocket(ctx, net, laddr, raddr, "dial")
if err != nil {
- return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
- }
- return newUnixConn(fd), nil
-}
-
-// UnixListener is a Unix domain socket listener. Clients should
-// typically use variables of type Listener instead of assuming Unix
-// domain sockets.
-type UnixListener struct {
- fd *netFD
- path string
- unlink bool
-}
-
-// ListenUnix announces on the Unix domain socket laddr and returns a
-// Unix listener. The network net must be "unix" or "unixpacket".
-func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
- switch net {
- case "unix", "unixpacket":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
- }
- fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
- if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
- }
- return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
-}
-
-// AcceptUnix accepts the next incoming call and returns the new
-// connection.
-func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
- if l == nil || l.fd == nil {
- return nil, syscall.EINVAL
- }
- fd, err := l.fd.accept()
- if err != nil {
- return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ return nil, err
}
return newUnixConn(fd), nil
}
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *UnixListener) Accept() (c Conn, err error) {
- c1, err := l.AcceptUnix()
+func (ln *UnixListener) accept() (*UnixConn, error) {
+ fd, err := ln.fd.accept()
if err != nil {
return nil, err
}
- return c1, nil
+ return newUnixConn(fd), nil
}
-// Close stops listening on the Unix address. Already accepted
-// connections are not closed.
-func (l *UnixListener) Close() error {
- if l == nil || l.fd == nil {
- return syscall.EINVAL
- }
-
+func (ln *UnixListener) close() error {
// The operating system doesn't clean up
// the file that announcing created, so
// we have to clean it up ourselves.
@@ -334,66 +175,49 @@ func (l *UnixListener) Close() error {
// and replaced our socket name already--
// but this sequence (remove then close)
// is at least compatible with the auto-remove
- // sequence in ListenUnix. It's only non-Go
+ // sequence in ListenUnix. It's only non-Go
// programs that can mess us up.
- if l.path[0] != '@' && l.unlink {
- syscall.Unlink(l.path)
- }
- err := l.fd.Close()
- if err != nil {
- err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err}
- }
- return err
+ // Even if there are racy calls to Close, we want to unlink only for the first one.
+ ln.unlinkOnce.Do(func() {
+ if ln.path[0] != '@' && ln.unlink {
+ syscall.Unlink(ln.path)
+ }
+ })
+ return ln.fd.Close()
}
-// Addr returns the listener's network address.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
-func (l *UnixListener) Addr() Addr { return l.fd.laddr }
-
-// SetDeadline sets the deadline associated with the listener.
-// A zero time value disables the deadline.
-func (l *UnixListener) SetDeadline(t time.Time) error {
- if l == nil || l.fd == nil {
- return syscall.EINVAL
- }
- if err := l.fd.setDeadline(t); err != nil {
- return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+func (ln *UnixListener) file() (*os.File, error) {
+ f, err := ln.fd.dup()
+ if err != nil {
+ return nil, err
}
- return nil
+ return f, nil
}
-// File returns a copy of the underlying os.File, set to blocking
-// mode. It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
+// SetUnlinkOnClose sets whether the underlying socket file should be removed
+// from the file system when the listener is closed.
//
-// The returned os.File's file descriptor is different from the
-// connection's. Attempting to change properties of the original
-// using this duplicate may or may not have the desired effect.
-func (l *UnixListener) File() (f *os.File, err error) {
- f, err = l.fd.dup()
+// The default behavior is to unlink the socket file only when package net created it.
+// That is, when the listener and the underlying socket file were created by a call to
+// Listen or ListenUnix, then by default closing the listener will remove the socket file.
+// but if the listener was created by a call to FileListener to use an already existing
+// socket file, then by default closing the listener will not remove the socket file.
+func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
+ l.unlink = unlink
+}
+
+func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
+ fd, err := unixSocket(ctx, network, laddr, nil, "listen")
if err != nil {
- err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+ return nil, err
}
- return
+ return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
}
-// ListenUnixgram listens for incoming Unix datagram packets addressed
-// to the local address laddr. The network net must be "unixgram".
-// The returned connection's ReadFrom and WriteTo methods can be used
-// to receive and send packets with per-packet addressing.
-func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
- switch net {
- case "unixgram":
- default:
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
- }
- if laddr == nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
- }
- fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
+func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) {
+ fd, err := unixSocket(ctx, network, laddr, nil, "listen")
if err != nil {
- return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+ return nil, err
}
return newUnixConn(fd), nil
}
diff --git a/libgo/go/net/unix_test.go b/libgo/go/net/unixsock_test.go
index f0c583068e..489a29bc7d 100644
--- a/libgo/go/net/unix_test.go
+++ b/libgo/go/net/unixsock_test.go
@@ -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.
@@ -8,6 +8,8 @@ package net
import (
"bytes"
+ "internal/testenv"
+ "io/ioutil"
"os"
"reflect"
"runtime"
@@ -20,6 +22,9 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
if !testableNetwork("unixgram") {
t.Skip("unixgram test")
}
+ if runtime.GOOS == "openbsd" {
+ testenv.SkipFlaky(t, 15157)
+ }
addr := testUnixAddr()
la, err := ResolveUnixAddr("unixgram", addr)
@@ -410,64 +415,104 @@ func TestUnixUnlink(t *testing.T) {
t.Skip("unix test")
}
name := testUnixAddr()
- l, err := Listen("unix", name)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
- }
- f, _ := l.(*UnixListener).File()
- l1, err := FileListener(f)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after FileListener: %v", err)
- }
- if err := l1.Close(); err != nil {
- t.Fatalf("closing file listener: %v", err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
+
+ listen := func(t *testing.T) *UnixListener {
+ l, err := Listen("unix", name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return l.(*UnixListener)
}
- f.Close()
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
+ checkExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err != nil {
+ t.Fatalf("unix socket does not exist %s: %v", desc, err)
+ }
}
- l.Close()
- if _, err := os.Stat(name); err == nil {
- t.Fatal("closing unix listener did not remove unix socket")
+ checkNotExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err == nil {
+ t.Fatalf("unix socket does exist %s: %v", desc, err)
+ }
}
-}
-// forceGoDNS forces the resolver configuration to use the pure Go resolver
-// and returns a fixup function to restore the old settings.
-func forceGoDNS() func() {
- c := systemConf()
- oldGo := c.netGo
- oldCgo := c.netCgo
- fixup := func() {
- c.netGo = oldGo
- c.netCgo = oldCgo
- }
- c.netGo = true
- c.netCgo = false
- return fixup
-}
-
-// forceCgoDNS forces the resolver configuration to use the cgo resolver
-// and returns a fixup function to restore the old settings.
-// (On non-Unix systems forceCgoDNS returns nil.)
-func forceCgoDNS() func() {
- c := systemConf()
- oldGo := c.netGo
- oldCgo := c.netCgo
- fixup := func() {
- c.netGo = oldGo
- c.netCgo = oldCgo
- }
- c.netGo = false
- c.netCgo = true
- return fixup
+ // Listener should remove on close.
+ t.Run("Listen", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // FileListener should not.
+ t.Run("FileListener", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // Only first call to l.Close should remove.
+ t.Run("SecondClose", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ if err := ioutil.WriteFile(name, []byte("hello world"), 0666); err != nil {
+ t.Fatalf("cannot recreate socket file: %v", err)
+ }
+ checkExists(t, "after writing temp file")
+ l.Close()
+ checkExists(t, "after second Listener close")
+ os.Remove(name)
+ })
+
+ // SetUnlinkOnClose should do what it says.
+
+ t.Run("Listen/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(true)
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ t.Run("Listen/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(false)
+ l.Close()
+ checkExists(t, "after Listener close")
+ os.Remove(name)
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(true)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkNotExists(t, "after FileListener close")
+ l.Close()
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(false)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ })
}
diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go
index 1a93e3496e..42a514bbc1 100644
--- a/libgo/go/net/url/url.go
+++ b/libgo/go/net/url/url.go
@@ -3,9 +3,13 @@
// license that can be found in the LICENSE file.
// Package url parses URLs and implements query escaping.
-// See RFC 3986.
package url
+// See RFC 3986. This package generally follows RFC 3986, except where
+// it deviates for compatibility reasons. When sending changes, first
+// search old issues for history on decisions. Unit tests should also
+// contain references to issue numbers with details.
+
import (
"bytes"
"errors"
@@ -70,6 +74,7 @@ type encoding int
const (
encodePath encoding = 1 + iota
+ encodePathSegment
encodeHost
encodeZone
encodeUserPassword
@@ -128,9 +133,14 @@ func shouldEscape(c byte, mode encoding) bool {
// The RFC allows : @ & = + $ but saves / ; , for assigning
// meaning to individual path segments. This package
// only manipulates the path as a whole, so we allow those
- // last two as well. That leaves only ? to escape.
+ // last three as well. That leaves only ? to escape.
return c == '?'
+ case encodePathSegment: // §3.3
+ // The RFC allows : @ & = + $ but saves / ; , for assigning
+ // meaning to individual path segments.
+ return c == '/' || c == ';' || c == ',' || c == '?'
+
case encodeUserPassword: // §3.2.1
// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
// userinfo, so we must escape only '@', '/', and '?'.
@@ -160,6 +170,15 @@ func QueryUnescape(s string) (string, error) {
return unescape(s, encodeQueryComponent)
}
+// PathUnescape does the inverse transformation of PathEscape, converting
+// %AB into the byte 0xAB. It returns an error if any % is not followed by
+// two hexadecimal digits.
+//
+// PathUnescape is identical to QueryUnescape except that it does not unescape '+' to ' ' (space).
+func PathUnescape(s string) (string, error) {
+ return unescape(s, encodePathSegment)
+}
+
// unescape unescapes a string; the mode specifies
// which section of the URL string is being unescaped.
func unescape(s string, mode encoding) (string, error) {
@@ -246,6 +265,12 @@ func QueryEscape(s string) string {
return escape(s, encodeQueryComponent)
}
+// PathEscape escapes the string so it can be safely placed
+// inside a URL path segment.
+func PathEscape(s string) string {
+ return escape(s, encodePathSegment)
+}
+
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
@@ -307,14 +332,15 @@ func escape(s string, mode encoding) string {
// construct a URL struct directly and set the Opaque field instead of Path.
// These still work as well.
type URL struct {
- Scheme string
- Opaque string // encoded opaque data
- User *Userinfo // username and password information
- Host string // host or host:port
- Path string
- RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
- RawQuery string // encoded query values, without '?'
- Fragment string // fragment for references, without '#'
+ Scheme string
+ Opaque string // encoded opaque data
+ User *Userinfo // username and password information
+ Host string // host or host:port
+ Path string
+ RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
+ ForceQuery bool // append a query ('?') even if RawQuery is empty
+ RawQuery string // encoded query values, without '?'
+ Fragment string // fragment for references, without '#'
}
// User returns a Userinfo containing the provided username
@@ -351,10 +377,7 @@ func (u *Userinfo) Username() string {
// Password returns the password in case it is set, and whether it is set.
func (u *Userinfo) Password() (string, bool) {
- if u.passwordSet {
- return u.password, true
- }
- return "", false
+ return u.password, u.passwordSet
}
// String returns the encoded userinfo information in the standard form
@@ -410,11 +433,12 @@ func split(s string, c string, cutc bool) (string, string) {
// Parse parses rawurl into a URL structure.
// The rawurl may be relative or absolute.
-func Parse(rawurl string) (url *URL, err error) {
+func Parse(rawurl string) (*URL, error) {
// Cut off #frag
u, frag := split(rawurl, "#", true)
- if url, err = parse(u, false); err != nil {
- return nil, err
+ url, err := parse(u, false)
+ if err != nil {
+ return nil, &Error{"parse", u, err}
}
if frag == "" {
return url, nil
@@ -425,41 +449,50 @@ func Parse(rawurl string) (url *URL, err error) {
return url, nil
}
-// ParseRequestURI parses rawurl into a URL structure. It assumes that
+// ParseRequestURI parses rawurl into a URL structure. It assumes that
// rawurl was received in an HTTP request, so the rawurl is interpreted
// only as an absolute URI or an absolute path.
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
-func ParseRequestURI(rawurl string) (url *URL, err error) {
- return parse(rawurl, true)
+func ParseRequestURI(rawurl string) (*URL, error) {
+ url, err := parse(rawurl, true)
+ if err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ return url, nil
}
-// parse parses a URL from a string in one of two contexts. If
+// parse parses a URL from a string in one of two contexts. If
// viaRequest is true, the URL is assumed to have arrived via an HTTP request,
// in which case only absolute URLs or path-absolute relative URLs are allowed.
// If viaRequest is false, all forms of relative URLs are allowed.
-func parse(rawurl string, viaRequest bool) (url *URL, err error) {
+func parse(rawurl string, viaRequest bool) (*URL, error) {
var rest string
+ var err error
if rawurl == "" && viaRequest {
- err = errors.New("empty url")
- goto Error
+ return nil, errors.New("empty url")
}
- url = new(URL)
+ url := new(URL)
if rawurl == "*" {
url.Path = "*"
- return
+ return url, nil
}
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
if url.Scheme, rest, err = getscheme(rawurl); err != nil {
- goto Error
+ return nil, err
}
url.Scheme = strings.ToLower(url.Scheme)
- rest, url.RawQuery = split(rest, "?", true)
+ if strings.HasSuffix(rest, "?") && strings.Count(rest, "?") == 1 {
+ url.ForceQuery = true
+ rest = rest[:len(rest)-1]
+ } else {
+ rest, url.RawQuery = split(rest, "?", true)
+ }
if !strings.HasPrefix(rest, "/") {
if url.Scheme != "" {
@@ -468,8 +501,20 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
return url, nil
}
if viaRequest {
- err = errors.New("invalid URI for request")
- goto Error
+ return nil, errors.New("invalid URI for request")
+ }
+
+ // Avoid confusion with malformed schemes, like cache_object:foo/bar.
+ // See golang.org/issue/16822.
+ //
+ // RFC 3986, §3.3:
+ // In addition, a URI reference (Section 4.1) may be a relative-path reference,
+ // in which case the first path segment cannot contain a colon (":") character.
+ colon := strings.Index(rest, ":")
+ slash := strings.Index(rest, "/")
+ if colon >= 0 && (slash < 0 || colon < slash) {
+ // First path segment has colon. Not allowed in relative URL.
+ return nil, errors.New("first path segment in URL cannot contain colon")
}
}
@@ -478,23 +523,17 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
authority, rest = split(rest[2:], "/", false)
url.User, url.Host, err = parseAuthority(authority)
if err != nil {
- goto Error
+ return nil, err
}
}
- if url.Path, err = unescape(rest, encodePath); err != nil {
- goto Error
- }
- // RawPath is a hint as to the encoding of Path to use
- // in url.EscapedPath. If that method already gets the
- // right answer without RawPath, leave it empty.
- // This will help make sure that people don't rely on it in general.
- if url.EscapedPath() != rest && validEncodedPath(rest) {
- url.RawPath = rest
+ // Set Path and, optionally, RawPath.
+ // RawPath is a hint of the encoding of Path. We don't want to set it if
+ // the default escaping of Path is equivalent, to help make sure that people
+ // don't rely on it in general.
+ if err := url.setPath(rest); err != nil {
+ return nil, err
}
return url, nil
-
-Error:
- return nil, &Error{"parse", rawurl, err}
}
func parseAuthority(authority string) (user *Userinfo, host string, err error) {
@@ -511,7 +550,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
return nil, host, nil
}
userinfo := authority[:i]
- if strings.Index(userinfo, ":") < 0 {
+ if !strings.Contains(userinfo, ":") {
if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
return nil, "", err
}
@@ -575,6 +614,29 @@ func parseHost(host string) (string, error) {
return host, nil
}
+// setPath sets the Path and RawPath fields of the URL based on the provided
+// escaped path p. It maintains the invariant that RawPath is only specified
+// when it differs from the default encoding of the path.
+// For example:
+// - setPath("/foo/bar") will set Path="/foo/bar" and RawPath=""
+// - setPath("/foo%2fbar") will set Path="/foo/bar" and RawPath="/foo%2fbar"
+// setPath will return an error only if the provided path contains an invalid
+// escaping.
+func (u *URL) setPath(p string) error {
+ path, err := unescape(p, encodePath)
+ if err != nil {
+ return err
+ }
+ u.Path = path
+ if escp := escape(path, encodePath); p == escp {
+ // Default encoding is fine.
+ u.RawPath = ""
+ } else {
+ u.RawPath = p
+ }
+ return nil
+}
+
// EscapedPath returns the escaped form of u.Path.
// In general there are multiple possible escaped forms of any path.
// EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
@@ -682,9 +744,20 @@ func (u *URL) String() string {
if path != "" && path[0] != '/' && u.Host != "" {
buf.WriteByte('/')
}
+ if buf.Len() == 0 {
+ // RFC 3986 §4.2
+ // A path segment that contains a colon character (e.g., "this:that")
+ // cannot be used as the first segment of a relative-path reference, as
+ // it would be mistaken for a scheme name. Such a segment must be
+ // preceded by a dot-segment (e.g., "./this:that") to make a relative-
+ // path reference.
+ if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
+ buf.WriteString("./")
+ }
+ }
buf.WriteString(path)
}
- if u.RawQuery != "" {
+ if u.ForceQuery || u.RawQuery != "" {
buf.WriteByte('?')
buf.WriteString(u.RawQuery)
}
@@ -709,8 +782,8 @@ func (v Values) Get(key string) string {
if v == nil {
return ""
}
- vs, ok := v[key]
- if !ok || len(vs) == 0 {
+ vs := v[key]
+ if len(vs) == 0 {
return ""
}
return vs[0]
@@ -738,10 +811,14 @@ func (v Values) Del(key string) {
// ParseQuery always returns a non-nil map containing all the
// valid query parameters found; err describes the first decoding error
// encountered, if any.
-func ParseQuery(query string) (m Values, err error) {
- m = make(Values)
- err = parseQuery(m, query)
- return
+//
+// Query is expected to be a list of key=value settings separated by
+// ampersands or semicolons. A setting without an equals sign is
+// interpreted as a key set to an empty value.
+func ParseQuery(query string) (Values, error) {
+ m := make(Values)
+ err := parseQuery(m, query)
+ return m, err
}
func parseQuery(m Values, query string) (err error) {
@@ -841,12 +918,13 @@ func resolvePath(base, ref string) string {
}
// IsAbs reports whether the URL is absolute.
+// Absolute means that it has a non-empty scheme.
func (u *URL) IsAbs() bool {
return u.Scheme != ""
}
-// Parse parses a URL in the context of the receiver. The provided URL
-// may be relative or absolute. Parse returns nil, err on parse
+// Parse parses a URL in the context of the receiver. The provided URL
+// may be relative or absolute. Parse returns nil, err on parse
// failure, otherwise its return value is the same as ResolveReference.
func (u *URL) Parse(ref string) (*URL, error) {
refurl, err := Parse(ref)
@@ -858,7 +936,7 @@ func (u *URL) Parse(ref string) (*URL, error) {
// ResolveReference resolves a URI reference to an absolute URI from
// an absolute base URI, per RFC 3986 Section 5.2. The URI reference
-// may be relative or absolute. ResolveReference always returns a new
+// may be relative or absolute. ResolveReference always returns a new
// URL instance, even if the returned URL is identical to either the
// base or reference. If ref is an absolute URL, then ResolveReference
// ignores base and returns a copy of ref.
@@ -869,7 +947,9 @@ func (u *URL) ResolveReference(ref *URL) *URL {
}
if ref.Scheme != "" || ref.Host != "" || ref.User != nil {
// The "absoluteURI" or "net_path" cases.
- url.Path = resolvePath(ref.Path, "")
+ // We can ignore the error from setPath since we know we provided a
+ // validly-escaped path.
+ url.setPath(resolvePath(ref.EscapedPath(), ""))
return &url
}
if ref.Opaque != "" {
@@ -889,7 +969,7 @@ func (u *URL) ResolveReference(ref *URL) *URL {
// The "abs_path" or "rel_path" cases.
url.Host = u.Host
url.User = u.User
- url.Path = resolvePath(u.Path, ref.Path)
+ url.setPath(resolvePath(u.EscapedPath(), ref.EscapedPath()))
return &url
}
@@ -913,8 +993,64 @@ func (u *URL) RequestURI() string {
result = u.Scheme + ":" + result
}
}
- if u.RawQuery != "" {
+ if u.ForceQuery || u.RawQuery != "" {
result += "?" + u.RawQuery
}
return result
}
+
+// Hostname returns u.Host, without any port number.
+//
+// If Host is an IPv6 literal with a port number, Hostname returns the
+// IPv6 literal without the square brackets. IPv6 literals may include
+// a zone identifier.
+func (u *URL) Hostname() string {
+ return stripPort(u.Host)
+}
+
+// Port returns the port part of u.Host, without the leading colon.
+// If u.Host doesn't contain a port, Port returns an empty string.
+func (u *URL) Port() string {
+ return portOnly(u.Host)
+}
+
+func stripPort(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return hostport
+ }
+ if i := strings.IndexByte(hostport, ']'); i != -1 {
+ return strings.TrimPrefix(hostport[:i], "[")
+ }
+ return hostport[:colon]
+}
+
+func portOnly(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return ""
+ }
+ if i := strings.Index(hostport, "]:"); i != -1 {
+ return hostport[i+len("]:"):]
+ }
+ if strings.Contains(hostport, "]") {
+ return ""
+ }
+ return hostport[colon+len(":"):]
+}
+
+// Marshaling interface implementations.
+// Would like to implement MarshalText/UnmarshalText but that will change the JSON representation of URLs.
+
+func (u *URL) MarshalBinary() (text []byte, err error) {
+ return []byte(u.String()), nil
+}
+
+func (u *URL) UnmarshalBinary(text []byte) error {
+ u1, err := Parse(string(text))
+ if err != nil {
+ return err
+ }
+ *u = *u1
+ return nil
+}
diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go
index d3f8487bd7..6c3bb21d20 100644
--- a/libgo/go/net/url/url_test.go
+++ b/libgo/go/net/url/url_test.go
@@ -5,6 +5,10 @@
package url
import (
+ "bytes"
+ encodingPkg "encoding"
+ "encoding/gob"
+ "encoding/json"
"fmt"
"io"
"net"
@@ -72,6 +76,28 @@ var urltests = []URLTest{
},
"ftp://john%20doe@www.google.com/",
},
+ // empty query
+ {
+ "http://www.google.com/?",
+ &URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ ForceQuery: true,
+ },
+ "",
+ },
+ // query ending in question mark (Issue 14573)
+ {
+ "http://www.google.com/?foo=bar?",
+ &URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "foo=bar?",
+ },
+ "",
+ },
// query
{
"http://www.google.com/?q=go+language",
@@ -553,22 +579,8 @@ func ufmt(u *URL) string {
pass = p
}
}
- return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q",
- u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment)
-}
-
-func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
- for _, tt := range tests {
- u, err := parse(tt.in)
- if err != nil {
- t.Errorf("%s(%q) returned error %s", name, tt.in, err)
- continue
- }
- if !reflect.DeepEqual(u, tt.out) {
- t.Errorf("%s(%q):\n\thave %v\n\twant %v\n",
- name, tt.in, ufmt(u), ufmt(tt.out))
- }
- }
+ return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q, forcequery=%v",
+ u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment, u.ForceQuery)
}
func BenchmarkString(b *testing.B) {
@@ -589,14 +601,23 @@ func BenchmarkString(b *testing.B) {
g = u.String()
}
b.StopTimer()
- if w := tt.roundtrip; g != w {
+ if w := tt.roundtrip; b.N > 0 && g != w {
b.Errorf("Parse(%q).String() == %q, want %q", tt.in, g, w)
}
}
}
func TestParse(t *testing.T) {
- DoTest(t, Parse, "Parse", urltests)
+ for _, tt := range urltests {
+ u, err := Parse(tt.in)
+ if err != nil {
+ t.Errorf("Parse(%q) returned error %v", tt.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(u, tt.out) {
+ t.Errorf("Parse(%q):\n\tgot %v\n\twant %v\n", tt.in, ufmt(u), ufmt(tt.out))
+ }
+ }
}
const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path"
@@ -643,9 +664,10 @@ var parseRequestURLTests = []struct {
func TestParseRequestURI(t *testing.T) {
for _, test := range parseRequestURLTests {
_, err := ParseRequestURI(test.url)
- valid := err == nil
- if valid != test.expectedValid {
- t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid)
+ if test.expectedValid && err != nil {
+ t.Errorf("ParseRequestURI(%q) gave err %v; want no error", test.url, err)
+ } else if !test.expectedValid && err == nil {
+ t.Errorf("ParseRequestURI(%q) gave nil error; want some error", test.url)
}
}
@@ -654,45 +676,69 @@ func TestParseRequestURI(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
if url.Path != pathThatLooksSchemeRelative {
- t.Errorf("Expected path %q; got %q", pathThatLooksSchemeRelative, url.Path)
+ t.Errorf("ParseRequestURI path:\ngot %q\nwant %q", url.Path, pathThatLooksSchemeRelative)
}
}
-func DoTestString(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
- for _, tt := range tests {
- u, err := parse(tt.in)
+var stringURLTests = []struct {
+ url URL
+ want string
+}{
+ // No leading slash on path should prepend slash on String() call
+ {
+ url: URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "search",
+ },
+ want: "http://www.google.com/search",
+ },
+ // Relative path with first element containing ":" should be prepended with "./", golang.org/issue/17184
+ {
+ url: URL{
+ Path: "this:that",
+ },
+ want: "./this:that",
+ },
+ // Relative path with second element containing ":" should not be prepended with "./"
+ {
+ url: URL{
+ Path: "here/this:that",
+ },
+ want: "here/this:that",
+ },
+ // Non-relative path with first element containing ":" should not be prepended with "./"
+ {
+ url: URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "this:that",
+ },
+ want: "http://www.google.com/this:that",
+ },
+}
+
+func TestURLString(t *testing.T) {
+ for _, tt := range urltests {
+ u, err := Parse(tt.in)
if err != nil {
- t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ t.Errorf("Parse(%q) returned error %s", tt.in, err)
continue
}
expected := tt.in
- if len(tt.roundtrip) > 0 {
+ if tt.roundtrip != "" {
expected = tt.roundtrip
}
s := u.String()
if s != expected {
- t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
+ t.Errorf("Parse(%q).String() == %q (expected %q)", tt.in, s, expected)
}
}
-}
-func TestURLString(t *testing.T) {
- DoTestString(t, Parse, "Parse", urltests)
-
- // no leading slash on path should prepend
- // slash on String() call
- noslash := URLTest{
- "http://www.google.com/search",
- &URL{
- Scheme: "http",
- Host: "www.google.com",
- Path: "search",
- },
- "",
- }
- s := noslash.out.String()
- if s != noslash.in {
- t.Errorf("Expected %s; go %s", noslash.in, s)
+ for _, tt := range stringURLTests {
+ if got := tt.url.String(); got != tt.want {
+ t.Errorf("%+v.String() = %q; want %q", tt.url, got, tt.want)
+ }
}
}
@@ -758,6 +804,16 @@ var unescapeTests = []EscapeTest{
"",
EscapeError("%zz"),
},
+ {
+ "a+b",
+ "a b",
+ nil,
+ },
+ {
+ "a%20b",
+ "a b",
+ nil,
+ },
}
func TestUnescape(t *testing.T) {
@@ -766,10 +822,33 @@ func TestUnescape(t *testing.T) {
if actual != tt.out || (err != nil) != (tt.err != nil) {
t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
}
+
+ in := tt.in
+ out := tt.out
+ if strings.Contains(tt.in, "+") {
+ in = strings.Replace(tt.in, "+", "%20", -1)
+ actual, err := PathUnescape(in)
+ if actual != tt.out || (err != nil) != (tt.err != nil) {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", in, actual, err, tt.out, tt.err)
+ }
+ if tt.err == nil {
+ s, err := QueryUnescape(strings.Replace(tt.in, "+", "XXX", -1))
+ if err != nil {
+ continue
+ }
+ in = tt.in
+ out = strings.Replace(s, "XXX", "+", -1)
+ }
+ }
+
+ actual, err = PathUnescape(in)
+ if actual != out || (err != nil) != (tt.err != nil) {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", in, actual, err, out, tt.err)
+ }
}
}
-var escapeTests = []EscapeTest{
+var queryEscapeTests = []EscapeTest{
{
"",
"",
@@ -797,8 +876,8 @@ var escapeTests = []EscapeTest{
},
}
-func TestEscape(t *testing.T) {
- for _, tt := range escapeTests {
+func TestQueryEscape(t *testing.T) {
+ for _, tt := range queryEscapeTests {
actual := QueryEscape(tt.in)
if tt.out != actual {
t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
@@ -812,6 +891,54 @@ func TestEscape(t *testing.T) {
}
}
+var pathEscapeTests = []EscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "abc+def",
+ "abc+def",
+ nil,
+ },
+ {
+ "one two",
+ "one%20two",
+ nil,
+ },
+ {
+ "10%",
+ "10%25",
+ nil,
+ },
+ {
+ " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
+ "%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B",
+ nil,
+ },
+}
+
+func TestPathEscape(t *testing.T) {
+ for _, tt := range pathEscapeTests {
+ actual := PathEscape(tt.in)
+ if tt.out != actual {
+ t.Errorf("PathEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ }
+
+ // for bonus points, verify that escape:unescape is an identity.
+ roundtrip, err := PathUnescape(actual)
+ if roundtrip != tt.in || err != nil {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ }
+ }
+}
+
//var userinfoTests = []UserinfoTest{
// {"user", "password", "user:password"},
// {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
@@ -874,11 +1001,13 @@ var resolveReferenceTests = []struct {
// Absolute URL references
{"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
{"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+ {"http://foo.com/", "https://bar.com/?", "https://bar.com/?"},
{"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
// Path-absolute references
{"http://foo.com/bar", "/baz", "http://foo.com/baz"},
{"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b", "/baz?", "http://foo.com/baz?"},
{"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
// Scheme-relative
@@ -921,6 +1050,15 @@ var resolveReferenceTests = []struct {
// Fragment
{"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+ // Paths with escaping (issue 16947).
+ {"http://foo.com/foo%2fbar/", "../baz", "http://foo.com/baz"},
+ {"http://foo.com/1/2%2f/3%2f4/5", "../../a/b/c", "http://foo.com/1/a/b/c"},
+ {"http://foo.com/1/2/3", "./a%2f../../b/..%2fc", "http://foo.com/1/2/b/..%2fc"},
+ {"http://foo.com/1/2%2f/3%2f4/5", "./a%2f../b/../c", "http://foo.com/1/2%2f/3%2f4/a%2f../c"},
+ {"http://foo.com/foo%20bar/", "../baz", "http://foo.com/baz"},
+ {"http://foo.com/foo", "../bar%2fbaz", "http://foo.com/bar%2fbaz"},
+ {"http://foo.com/foo%2dbar/", "./baz-quux", "http://foo.com/foo%2dbar/baz-quux"},
+
// RFC 3986: Normal Examples
// http://tools.ietf.org/html/rfc3986#section-5.4.1
{"http://a/b/c/d;p?q", "g:h", "g:h"},
@@ -980,7 +1118,7 @@ func TestResolveReference(t *testing.T) {
mustParse := func(url string) *URL {
u, err := Parse(url)
if err != nil {
- t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ t.Fatalf("Parse(%q) got err %v", url, err)
}
return u
}
@@ -989,8 +1127,8 @@ func TestResolveReference(t *testing.T) {
base := mustParse(test.base)
rel := mustParse(test.rel)
url := base.ResolveReference(rel)
- if url.String() != test.expected {
- t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, url.String())
+ if got := url.String(); got != test.expected {
+ t.Errorf("URL(%q).ResolveReference(%q)\ngot %q\nwant %q", test.base, test.rel, got, test.expected)
}
// Ensure that new instances are returned.
if base == url {
@@ -1000,8 +1138,8 @@ func TestResolveReference(t *testing.T) {
url, err := base.Parse(test.rel)
if err != nil {
t.Errorf("URL(%q).Parse(%q) failed: %v", test.base, test.rel, err)
- } else if url.String() != test.expected {
- t.Errorf("URL(%q).Parse(%q) == %q, got %q", test.base, test.rel, test.expected, url.String())
+ } else if got := url.String(); got != test.expected {
+ t.Errorf("URL(%q).Parse(%q)\ngot %q\nwant %q", test.base, test.rel, got, test.expected)
} else if base == url {
// Ensure that new instances are returned for the wrapper too.
t.Errorf("Expected URL.Parse to return new URL instance.")
@@ -1009,14 +1147,14 @@ func TestResolveReference(t *testing.T) {
// Ensure Opaque resets the URL.
url = base.ResolveReference(opaque)
if *url != *opaque {
- t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ t.Errorf("ResolveReference failed to resolve opaque URL:\ngot %#v\nwant %#v", url, opaque)
}
// Test the convenience wrapper with an opaque URL too.
url, err = base.Parse("scheme:opaque")
if err != nil {
t.Errorf(`URL(%q).Parse("scheme:opaque") failed: %v`, test.base, err)
} else if *url != *opaque {
- t.Errorf("Parse failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ t.Errorf("Parse failed to resolve opaque URL:\ngot %#v\nwant %#v", opaque, url)
} else if base == url {
// Ensure that new instances are returned, again.
t.Errorf("Expected URL.Parse to return new URL instance.")
@@ -1217,6 +1355,15 @@ var requritests = []RequestURITest{
},
"//foo",
},
+ {
+ &URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "/foo",
+ ForceQuery: true,
+ },
+ "/foo?",
+ },
}
func TestRequestURI(t *testing.T) {
@@ -1238,7 +1385,7 @@ func TestParseFailure(t *testing.T) {
}
}
-func TestParseAuthority(t *testing.T) {
+func TestParseErrors(t *testing.T) {
tests := []struct {
in string
wantErr bool
@@ -1258,9 +1405,13 @@ func TestParseAuthority(t *testing.T) {
{"http://%41:8080/", true}, // not allowed: % encoding only for non-ASCII
{"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
{"mysql://x@y(1.2.3.4:123)/foo", false},
- {"mysql://x@y([2001:db8::1]:123)/foo", false},
+
{"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
{"http://a b.com/", true}, // no space in host name please
+ {"cache_object://foo", true}, // scheme cannot have _, relative path cannot have : in first segment
+ {"cache_object:foo", true},
+ {"cache_object:foo/bar", true},
+ {"cache_object/:foo/bar", false},
}
for _, tt := range tests {
u, err := Parse(tt.in)
@@ -1429,11 +1580,106 @@ func TestURLErrorImplementsNetError(t *testing.T) {
continue
}
if err.Timeout() != tt.timeout {
- t.Errorf("%d: err.Timeout(): want %v, have %v", i+1, tt.timeout, err.Timeout())
+ t.Errorf("%d: err.Timeout(): got %v, want %v", i+1, err.Timeout(), tt.timeout)
continue
}
if err.Temporary() != tt.temporary {
- t.Errorf("%d: err.Temporary(): want %v, have %v", i+1, tt.temporary, err.Temporary())
+ t.Errorf("%d: err.Temporary(): got %v, want %v", i+1, err.Temporary(), tt.temporary)
+ }
+ }
+}
+
+func TestURLHostname(t *testing.T) {
+ tests := []struct {
+ host string // URL.Host field
+ want string
+ }{
+ {"foo.com:80", "foo.com"},
+ {"foo.com", "foo.com"},
+ {"FOO.COM", "FOO.COM"}, // no canonicalization (yet?)
+ {"1.2.3.4", "1.2.3.4"},
+ {"1.2.3.4:80", "1.2.3.4"},
+ {"[1:2:3:4]", "1:2:3:4"},
+ {"[1:2:3:4]:80", "1:2:3:4"},
+ {"[::1]:80", "::1"},
+ }
+ for _, tt := range tests {
+ u := &URL{Host: tt.host}
+ got := u.Hostname()
+ if got != tt.want {
+ t.Errorf("Hostname for Host %q = %q; want %q", tt.host, got, tt.want)
}
}
}
+
+func TestURLPort(t *testing.T) {
+ tests := []struct {
+ host string // URL.Host field
+ want string
+ }{
+ {"foo.com", ""},
+ {"foo.com:80", "80"},
+ {"1.2.3.4", ""},
+ {"1.2.3.4:80", "80"},
+ {"[1:2:3:4]", ""},
+ {"[1:2:3:4]:80", "80"},
+ }
+ for _, tt := range tests {
+ u := &URL{Host: tt.host}
+ got := u.Port()
+ if got != tt.want {
+ t.Errorf("Port for Host %q = %q; want %q", tt.host, got, tt.want)
+ }
+ }
+}
+
+var _ encodingPkg.BinaryMarshaler = (*URL)(nil)
+var _ encodingPkg.BinaryUnmarshaler = (*URL)(nil)
+
+func TestJSON(t *testing.T) {
+ u, err := Parse("https://www.google.com/x?y=z")
+ if err != nil {
+ t.Fatal(err)
+ }
+ js, err := json.Marshal(u)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // If only we could implement TextMarshaler/TextUnmarshaler,
+ // this would work:
+ //
+ // if string(js) != strconv.Quote(u.String()) {
+ // t.Errorf("json encoding: %s\nwant: %s\n", js, strconv.Quote(u.String()))
+ // }
+
+ u1 := new(URL)
+ err = json.Unmarshal(js, u1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if u1.String() != u.String() {
+ t.Errorf("json decoded to: %s\nwant: %s\n", u1, u)
+ }
+}
+
+func TestGob(t *testing.T) {
+ u, err := Parse("https://www.google.com/x?y=z")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var w bytes.Buffer
+ err = gob.NewEncoder(&w).Encode(u)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ u1 := new(URL)
+ err = gob.NewDecoder(&w).Decode(u1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if u1.String() != u.String() {
+ t.Errorf("json decoded to: %s\nwant: %s\n", u1, u)
+ }
+}
diff --git a/libgo/go/net/writev_test.go b/libgo/go/net/writev_test.go
new file mode 100644
index 0000000000..7160d28c3a
--- /dev/null
+++ b/libgo/go/net/writev_test.go
@@ -0,0 +1,225 @@
+// 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 net
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "reflect"
+ "runtime"
+ "sync"
+ "testing"
+)
+
+func TestBuffers_read(t *testing.T) {
+ const story = "once upon a time in Gopherland ... "
+ buffers := Buffers{
+ []byte("once "),
+ []byte("upon "),
+ []byte("a "),
+ []byte("time "),
+ []byte("in "),
+ []byte("Gopherland ... "),
+ }
+ got, err := ioutil.ReadAll(&buffers)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != story {
+ t.Errorf("read %q; want %q", got, story)
+ }
+ if len(buffers) != 0 {
+ t.Errorf("len(buffers) = %d; want 0", len(buffers))
+ }
+}
+
+func TestBuffers_consume(t *testing.T) {
+ tests := []struct {
+ in Buffers
+ consume int64
+ want Buffers
+ }{
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 0,
+ want: Buffers{[]byte("foo"), []byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 2,
+ want: Buffers{[]byte("o"), []byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 3,
+ want: Buffers{[]byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 4,
+ want: Buffers{[]byte("ar")},
+ },
+ {
+ in: Buffers{nil, nil, nil, []byte("bar")},
+ consume: 1,
+ want: Buffers{[]byte("ar")},
+ },
+ {
+ in: Buffers{nil, nil, nil, []byte("foo")},
+ consume: 0,
+ want: Buffers{[]byte("foo")},
+ },
+ {
+ in: Buffers{nil, nil, nil},
+ consume: 0,
+ want: Buffers{},
+ },
+ }
+ for i, tt := range tests {
+ in := tt.in
+ in.consume(tt.consume)
+ if !reflect.DeepEqual(in, tt.want) {
+ t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
+ }
+ }
+}
+
+func TestBuffers_WriteTo(t *testing.T) {
+ for _, name := range []string{"WriteTo", "Copy"} {
+ for _, size := range []int{0, 10, 1023, 1024, 1025} {
+ t.Run(fmt.Sprintf("%s/%d", name, size), func(t *testing.T) {
+ testBuffer_writeTo(t, size, name == "Copy")
+ })
+ }
+ }
+}
+
+func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
+ oldHook := testHookDidWritev
+ defer func() { testHookDidWritev = oldHook }()
+ var writeLog struct {
+ sync.Mutex
+ log []int
+ }
+ testHookDidWritev = func(size int) {
+ writeLog.Lock()
+ writeLog.log = append(writeLog.log, size)
+ writeLog.Unlock()
+ }
+ var want bytes.Buffer
+ for i := 0; i < chunks; i++ {
+ want.WriteByte(byte(i))
+ }
+
+ withTCPConnPair(t, func(c *TCPConn) error {
+ buffers := make(Buffers, chunks)
+ for i := range buffers {
+ buffers[i] = want.Bytes()[i : i+1]
+ }
+ var n int64
+ var err error
+ if useCopy {
+ n, err = io.Copy(c, &buffers)
+ } else {
+ n, err = buffers.WriteTo(c)
+ }
+ if err != nil {
+ return err
+ }
+ if len(buffers) != 0 {
+ return fmt.Errorf("len(buffers) = %d; want 0", len(buffers))
+ }
+ if n != int64(want.Len()) {
+ return fmt.Errorf("Buffers.WriteTo returned %d; want %d", n, want.Len())
+ }
+ return nil
+ }, func(c *TCPConn) error {
+ all, err := ioutil.ReadAll(c)
+ if !bytes.Equal(all, want.Bytes()) || err != nil {
+ return fmt.Errorf("client read %q, %v; want %q, nil", all, err, want.Bytes())
+ }
+
+ writeLog.Lock() // no need to unlock
+ var gotSum int
+ for _, v := range writeLog.log {
+ gotSum += v
+ }
+
+ var wantSum int
+ switch runtime.GOOS {
+ case "android", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
+ var wantMinCalls int
+ wantSum = want.Len()
+ v := chunks
+ for v > 0 {
+ wantMinCalls++
+ v -= 1024
+ }
+ if len(writeLog.log) < wantMinCalls {
+ t.Errorf("write calls = %v < wanted min %v", len(writeLog.log), wantMinCalls)
+ }
+ case "windows":
+ var wantCalls int
+ wantSum = want.Len()
+ if wantSum > 0 {
+ wantCalls = 1 // windows will always do 1 syscall, unless sending empty buffer
+ }
+ if len(writeLog.log) != wantCalls {
+ t.Errorf("write calls = %v; want %v", len(writeLog.log), wantCalls)
+ }
+ }
+ if gotSum != wantSum {
+ t.Errorf("writev call sum = %v; want %v", gotSum, wantSum)
+ }
+ return nil
+ })
+}
+
+func TestWritevError(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ ch := make(chan Conn, 1)
+ go func() {
+ defer close(ch)
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ ch <- c
+ }()
+ c1, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c1.Close()
+ c2 := <-ch
+ if c2 == nil {
+ t.Fatal("no server side connection")
+ }
+ c2.Close()
+
+ // 1 GB of data should be enough to notice the connection is gone.
+ // Just a few bytes is not enough.
+ // Arrange to reuse the same 1 MB buffer so that we don't allocate much.
+ buf := make([]byte, 1<<20)
+ buffers := make(Buffers, 1<<10)
+ for i := range buffers {
+ buffers[i] = buf
+ }
+ if _, err := buffers.WriteTo(c1); err == nil {
+ t.Fatal("Buffers.WriteTo(closed conn) succeeded, want error")
+ }
+}
diff --git a/libgo/go/net/writev_unix.go b/libgo/go/net/writev_unix.go
new file mode 100644
index 0000000000..174e6bc51e
--- /dev/null
+++ b/libgo/go/net/writev_unix.go
@@ -0,0 +1,95 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func (c *conn) writeBuffers(v *Buffers) (int64, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.fd.writeBuffers(v)
+ if err != nil {
+ return n, &OpError{Op: "writev", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, nil
+}
+
+func (fd *netFD) writeBuffers(v *Buffers) (n int64, err error) {
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
+ if err := fd.pd.prepareWrite(); err != nil {
+ return 0, err
+ }
+
+ var iovecs []syscall.Iovec
+ if fd.iovecs != nil {
+ iovecs = *fd.iovecs
+ }
+ // TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
+ // 1024 and this seems conservative enough for now. Darwin's
+ // UIO_MAXIOV also seems to be 1024.
+ maxVec := 1024
+
+ for len(*v) > 0 {
+ iovecs = iovecs[:0]
+ for _, chunk := range *v {
+ if len(chunk) == 0 {
+ continue
+ }
+ iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
+ if fd.isStream && len(chunk) > 1<<30 {
+ iovecs[len(iovecs)-1].SetLen(1 << 30)
+ break // continue chunk on next writev
+ }
+ iovecs[len(iovecs)-1].SetLen(len(chunk))
+ if len(iovecs) == maxVec {
+ break
+ }
+ }
+ if len(iovecs) == 0 {
+ break
+ }
+ fd.iovecs = &iovecs // cache
+
+ wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
+ uintptr(fd.sysfd),
+ uintptr(unsafe.Pointer(&iovecs[0])),
+ uintptr(len(iovecs)))
+ if wrote == ^uintptr(0) {
+ wrote = 0
+ }
+ testHookDidWritev(int(wrote))
+ n += int64(wrote)
+ v.consume(int64(wrote))
+ if e0 == syscall.EAGAIN {
+ if err = fd.pd.waitWrite(); err == nil {
+ continue
+ }
+ } else if e0 != 0 {
+ err = syscall.Errno(e0)
+ }
+ if err != nil {
+ break
+ }
+ if n == 0 {
+ err = io.ErrUnexpectedEOF
+ break
+ }
+ }
+ if _, ok := err.(syscall.Errno); ok {
+ err = os.NewSyscallError("writev", err)
+ }
+ return n, err
+}
diff --git a/libgo/go/old/regexp/all_test.go b/libgo/go/old/regexp/all_test.go
deleted file mode 100644
index 180dac4d45..0000000000
--- a/libgo/go/old/regexp/all_test.go
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package regexp
-
-import (
- "strings"
- "testing"
-)
-
-var good_re = []string{
- ``,
- `.`,
- `^.$`,
- `a`,
- `a*`,
- `a+`,
- `a?`,
- `a|b`,
- `a*|b*`,
- `(a*|b)(c*|d)`,
- `[a-z]`,
- `[a-abc-c\-\]\[]`,
- `[a-z]+`,
- `[]`,
- `[abc]`,
- `[^1234]`,
- `[^\n]`,
- `\!\\`,
-}
-
-type stringError struct {
- re string
- err error
-}
-
-var bad_re = []stringError{
- {`*`, ErrBareClosure},
- {`+`, ErrBareClosure},
- {`?`, ErrBareClosure},
- {`(abc`, ErrUnmatchedLpar},
- {`abc)`, ErrUnmatchedRpar},
- {`x[a-z`, ErrUnmatchedLbkt},
- {`abc]`, ErrUnmatchedRbkt},
- {`[z-a]`, ErrBadRange},
- {`abc\`, ErrExtraneousBackslash},
- {`a**`, ErrBadClosure},
- {`a*+`, ErrBadClosure},
- {`a??`, ErrBadClosure},
- {`\x`, ErrBadBackslash},
-}
-
-func compileTest(t *testing.T, expr string, error error) *Regexp {
- re, err := Compile(expr)
- if err != error {
- t.Error("compiling `", expr, "`; unexpected error: ", err.Error())
- }
- return re
-}
-
-func TestGoodCompile(t *testing.T) {
- for i := 0; i < len(good_re); i++ {
- compileTest(t, good_re[i], nil)
- }
-}
-
-func TestBadCompile(t *testing.T) {
- for i := 0; i < len(bad_re); i++ {
- compileTest(t, bad_re[i].re, bad_re[i].err)
- }
-}
-
-func matchTest(t *testing.T, test *FindTest) {
- re := compileTest(t, test.pat, nil)
- if re == nil {
- return
- }
- m := re.MatchString(test.text)
- if m != (len(test.matches) > 0) {
- t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
- }
- // now try bytes
- m = re.Match([]byte(test.text))
- if m != (len(test.matches) > 0) {
- t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
- }
-}
-
-func TestMatch(t *testing.T) {
- for _, test := range findTests {
- matchTest(t, &test)
- }
-}
-
-func matchFunctionTest(t *testing.T, test *FindTest) {
- m, err := MatchString(test.pat, test.text)
- if err == nil {
- return
- }
- if m != (len(test.matches) > 0) {
- t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
- }
-}
-
-func TestMatchFunction(t *testing.T) {
- for _, test := range findTests {
- matchFunctionTest(t, &test)
- }
-}
-
-type ReplaceTest struct {
- pattern, replacement, input, output string
-}
-
-var replaceTests = []ReplaceTest{
- // Test empty input and/or replacement, with pattern that matches the empty string.
- {"", "", "", ""},
- {"", "x", "", "x"},
- {"", "", "abc", "abc"},
- {"", "x", "abc", "xaxbxcx"},
-
- // Test empty input and/or replacement, with pattern that does not match the empty string.
- {"b", "", "", ""},
- {"b", "x", "", ""},
- {"b", "", "abc", "ac"},
- {"b", "x", "abc", "axc"},
- {"y", "", "", ""},
- {"y", "x", "", ""},
- {"y", "", "abc", "abc"},
- {"y", "x", "abc", "abc"},
-
- // Multibyte characters -- verify that we don't try to match in the middle
- // of a character.
- {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
- {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
-
- // Start and end of a string.
- {"^[a-c]*", "x", "abcdabc", "xdabc"},
- {"[a-c]*$", "x", "abcdabc", "abcdx"},
- {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
- {"^[a-c]*", "x", "abc", "x"},
- {"[a-c]*$", "x", "abc", "x"},
- {"^[a-c]*$", "x", "abc", "x"},
- {"^[a-c]*", "x", "dabce", "xdabce"},
- {"[a-c]*$", "x", "dabce", "dabcex"},
- {"^[a-c]*$", "x", "dabce", "dabce"},
- {"^[a-c]*", "x", "", "x"},
- {"[a-c]*$", "x", "", "x"},
- {"^[a-c]*$", "x", "", "x"},
-
- {"^[a-c]+", "x", "abcdabc", "xdabc"},
- {"[a-c]+$", "x", "abcdabc", "abcdx"},
- {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
- {"^[a-c]+", "x", "abc", "x"},
- {"[a-c]+$", "x", "abc", "x"},
- {"^[a-c]+$", "x", "abc", "x"},
- {"^[a-c]+", "x", "dabce", "dabce"},
- {"[a-c]+$", "x", "dabce", "dabce"},
- {"^[a-c]+$", "x", "dabce", "dabce"},
- {"^[a-c]+", "x", "", ""},
- {"[a-c]+$", "x", "", ""},
- {"^[a-c]+$", "x", "", ""},
-
- // Other cases.
- {"abc", "def", "abcdefg", "defdefg"},
- {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
- {"abc", "", "abcdabc", "d"},
- {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
- {"abc", "d", "", ""},
- {"abc", "d", "abc", "d"},
- {".+", "x", "abc", "x"},
- {"[a-c]*", "x", "def", "xdxexfx"},
- {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
- {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
-}
-
-type ReplaceFuncTest struct {
- pattern string
- replacement func(string) string
- input, output string
-}
-
-var replaceFuncTests = []ReplaceFuncTest{
- {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
- {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
- {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
-}
-
-func TestReplaceAll(t *testing.T) {
- for _, tc := range replaceTests {
- re, err := Compile(tc.pattern)
- if err != nil {
- t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
- continue
- }
- actual := re.ReplaceAllString(tc.input, tc.replacement)
- if actual != tc.output {
- t.Errorf("%q.Replace(%q,%q) = %q; want %q",
- tc.pattern, tc.input, tc.replacement, actual, tc.output)
- }
- // now try bytes
- actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
- if actual != tc.output {
- t.Errorf("%q.Replace(%q,%q) = %q; want %q",
- tc.pattern, tc.input, tc.replacement, actual, tc.output)
- }
- }
-}
-
-func TestReplaceAllFunc(t *testing.T) {
- for _, tc := range replaceFuncTests {
- re, err := Compile(tc.pattern)
- if err != nil {
- t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
- continue
- }
- actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
- if actual != tc.output {
- t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
- tc.pattern, tc.input, tc.replacement, actual, tc.output)
- }
- // now try bytes
- actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
- if actual != tc.output {
- t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
- tc.pattern, tc.input, tc.replacement, actual, tc.output)
- }
- }
-}
-
-type MetaTest struct {
- pattern, output, literal string
- isLiteral bool
-}
-
-var metaTests = []MetaTest{
- {``, ``, ``, true},
- {`foo`, `foo`, `foo`, true},
- {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
- {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators
- {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`, `!@#`, false},
-}
-
-func TestQuoteMeta(t *testing.T) {
- for _, tc := range metaTests {
- // Verify that QuoteMeta returns the expected string.
- quoted := QuoteMeta(tc.pattern)
- if quoted != tc.output {
- t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
- tc.pattern, quoted, tc.output)
- continue
- }
-
- // Verify that the quoted string is in fact treated as expected
- // by Compile -- i.e. that it matches the original, unquoted string.
- if tc.pattern != "" {
- re, err := Compile(quoted)
- if err != nil {
- t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
- continue
- }
- src := "abc" + tc.pattern + "def"
- repl := "xyz"
- replaced := re.ReplaceAllString(src, repl)
- expected := "abcxyzdef"
- if replaced != expected {
- t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
- tc.pattern, src, repl, replaced, expected)
- }
- }
- }
-}
-
-func TestLiteralPrefix(t *testing.T) {
- for _, tc := range metaTests {
- // Literal method needs to scan the pattern.
- re := MustCompile(tc.pattern)
- str, complete := re.LiteralPrefix()
- if complete != tc.isLiteral {
- t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
- }
- if str != tc.literal {
- t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
- }
- }
-}
-
-type numSubexpCase struct {
- input string
- expected int
-}
-
-var numSubexpCases = []numSubexpCase{
- {``, 0},
- {`.*`, 0},
- {`abba`, 0},
- {`ab(b)a`, 1},
- {`ab(.*)a`, 1},
- {`(.*)ab(.*)a`, 2},
- {`(.*)(ab)(.*)a`, 3},
- {`(.*)((a)b)(.*)a`, 4},
- {`(.*)(\(ab)(.*)a`, 3},
- {`(.*)(\(a\)b)(.*)a`, 3},
-}
-
-func TestNumSubexp(t *testing.T) {
- for _, c := range numSubexpCases {
- re := MustCompile(c.input)
- n := re.NumSubexp()
- if n != c.expected {
- t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
- }
- }
-}
-
-func BenchmarkLiteral(b *testing.B) {
- x := strings.Repeat("x", 50) + "y"
- b.StopTimer()
- re := MustCompile("y")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- if !re.MatchString(x) {
- b.Fatal("no match!")
- }
- }
-}
-
-func BenchmarkNotLiteral(b *testing.B) {
- x := strings.Repeat("x", 50) + "y"
- b.StopTimer()
- re := MustCompile(".y")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- if !re.MatchString(x) {
- b.Fatal("no match!")
- }
- }
-}
-
-func BenchmarkMatchClass(b *testing.B) {
- b.StopTimer()
- x := strings.Repeat("xxxx", 20) + "w"
- re := MustCompile("[abcdw]")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- if !re.MatchString(x) {
- b.Fatal("no match!")
- }
- }
-}
-
-func BenchmarkMatchClass_InRange(b *testing.B) {
- b.StopTimer()
- // 'b' is between 'a' and 'c', so the charclass
- // range checking is no help here.
- x := strings.Repeat("bbbb", 20) + "c"
- re := MustCompile("[ac]")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- if !re.MatchString(x) {
- b.Fatal("no match!")
- }
- }
-}
-
-func BenchmarkReplaceAll(b *testing.B) {
- x := "abcdefghijklmnopqrstuvwxyz"
- b.StopTimer()
- re := MustCompile("[cjrw]")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- re.ReplaceAllString(x, "")
- }
-}
-
-func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
- b.StopTimer()
- x := []byte("abcdefghijklmnopqrstuvwxyz")
- re := MustCompile("^zbc(d|e)")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- re.Match(x)
- }
-}
-
-func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
- b.StopTimer()
- x := []byte("abcdefghijklmnopqrstuvwxyz")
- for i := 0; i < 15; i++ {
- x = append(x, x...)
- }
- re := MustCompile("^zbc(d|e)")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- re.Match(x)
- }
-}
-
-func BenchmarkAnchoredShortMatch(b *testing.B) {
- b.StopTimer()
- x := []byte("abcdefghijklmnopqrstuvwxyz")
- re := MustCompile("^.bc(d|e)")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- re.Match(x)
- }
-}
-
-func BenchmarkAnchoredLongMatch(b *testing.B) {
- b.StopTimer()
- x := []byte("abcdefghijklmnopqrstuvwxyz")
- for i := 0; i < 15; i++ {
- x = append(x, x...)
- }
- re := MustCompile("^.bc(d|e)")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- re.Match(x)
- }
-}
diff --git a/libgo/go/old/regexp/find_test.go b/libgo/go/old/regexp/find_test.go
deleted file mode 100644
index 83b249e3ce..0000000000
--- a/libgo/go/old/regexp/find_test.go
+++ /dev/null
@@ -1,472 +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 regexp
-
-import (
- "fmt"
- "strings"
- "testing"
-)
-
-// For each pattern/text pair, what is the expected output of each function?
-// We can derive the textual results from the indexed results, the non-submatch
-// results from the submatched results, the single results from the 'all' results,
-// and the byte results from the string results. Therefore the table includes
-// only the FindAllStringSubmatchIndex result.
-type FindTest struct {
- pat string
- text string
- matches [][]int
-}
-
-func (t FindTest) String() string {
- return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
-}
-
-var findTests = []FindTest{
- {``, ``, build(1, 0, 0)},
- {`^abcdefg`, "abcdefg", build(1, 0, 7)},
- {`a+`, "baaab", build(1, 1, 4)},
- {"abcd..", "abcdef", build(1, 0, 6)},
- {`a`, "a", build(1, 0, 1)},
- {`x`, "y", nil},
- {`b`, "abc", build(1, 1, 2)},
- {`.`, "a", build(1, 0, 1)},
- {`.*`, "abcdef", build(1, 0, 6)},
- {`^`, "abcde", build(1, 0, 0)},
- {`$`, "abcde", build(1, 5, 5)},
- {`^abcd$`, "abcd", build(1, 0, 4)},
- {`^bcd'`, "abcdef", nil},
- {`^abcd$`, "abcde", nil},
- {`a+`, "baaab", build(1, 1, 4)},
- {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
- {`[a-z]+`, "abcd", build(1, 0, 4)},
- {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
- {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
- {`[^\n]+`, "abcd\n", build(1, 0, 4)},
- {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
- {`日本語+`, "日本語", build(1, 0, 9)},
- {`日本語+`, "日本語語語語", build(1, 0, 18)},
- {`()`, "", build(1, 0, 0, 0, 0)},
- {`(a)`, "a", build(1, 0, 1, 0, 1)},
- {`(.)(.)`, "æ—¥a", build(1, 0, 4, 0, 3, 3, 4)},
- {`(.*)`, "", build(1, 0, 0, 0, 0)},
- {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
- {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
- {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
- {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
- {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
- {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
- {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
-
- {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
- {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
- {`[.]`, ".", build(1, 0, 1)},
- {`/$`, "/abc/", build(1, 4, 5)},
- {`/$`, "/abc", nil},
-
- // multiple matches
- {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
- {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
- {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
- {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
- {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
-
- // fixed bugs
- {`ab$`, "cab", build(1, 1, 3)},
- {`axxb$`, "axxcb", nil},
- {`data`, "daXY data", build(1, 5, 9)},
- {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
- {`zx+`, "zzx", build(1, 1, 3)},
-
- // can backslash-escape any punctuation
- {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
- `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
- {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
- `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
- {"\\`", "`", build(1, 0, 1)},
- {"[\\`]+", "`", build(1, 0, 1)},
-
- // long set of matches (longer than startSize)
- {
- ".",
- "qwertyuiopasdfghjklzxcvbnm1234567890",
- build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
- 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
- 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
- 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
- },
-}
-
-// build is a helper to construct a [][]int by extracting n sequences from x.
-// This represents n matches with len(x)/n submatches each.
-func build(n int, x ...int) [][]int {
- ret := make([][]int, n)
- runLength := len(x) / n
- j := 0
- for i := range ret {
- ret[i] = make([]int, runLength)
- copy(ret[i], x[j:])
- j += runLength
- if j > len(x) {
- panic("invalid build entry")
- }
- }
- return ret
-}
-
-// First the simple cases.
-
-func TestFind(t *testing.T) {
- for _, test := range findTests {
- re := MustCompile(test.pat)
- if re.String() != test.pat {
- t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
- }
- result := re.Find([]byte(test.text))
- switch {
- case len(test.matches) == 0 && len(result) == 0:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- expect := test.text[test.matches[0][0]:test.matches[0][1]]
- if expect != string(result) {
- t.Errorf("expected %q got %q: %s", expect, result, test)
- }
- }
- }
-}
-
-func TestFindString(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindString(test.text)
- switch {
- case len(test.matches) == 0 && len(result) == 0:
- // ok
- case test.matches == nil && result != "":
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == "":
- // Tricky because an empty result has two meanings: no match or empty match.
- if test.matches[0][0] != test.matches[0][1] {
- t.Errorf("expected match; got none: %s", test)
- }
- case test.matches != nil && result != "":
- expect := test.text[test.matches[0][0]:test.matches[0][1]]
- if expect != result {
- t.Errorf("expected %q got %q: %s", expect, result, test)
- }
- }
- }
-}
-
-func testFindIndex(test *FindTest, result []int, t *testing.T) {
- switch {
- case len(test.matches) == 0 && len(result) == 0:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- expect := test.matches[0]
- if expect[0] != result[0] || expect[1] != result[1] {
- t.Errorf("expected %v got %v: %s", expect, result, test)
- }
- }
-}
-
-func TestFindIndex(t *testing.T) {
- for _, test := range findTests {
- testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
- }
-}
-
-func TestFindStringIndex(t *testing.T) {
- for _, test := range findTests {
- testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
- }
-}
-
-func TestFindReaderIndex(t *testing.T) {
- for _, test := range findTests {
- testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
- }
-}
-
-// Now come the simple All cases.
-
-func TestFindAll(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- if len(test.matches) != len(result) {
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- continue
- }
- for k, e := range test.matches {
- expect := test.text[e[0]:e[1]]
- if expect != string(result[k]) {
- t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
- }
- }
- }
- }
-}
-
-func TestFindAllString(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindAllString(test.text, -1)
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- if len(test.matches) != len(result) {
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- continue
- }
- for k, e := range test.matches {
- expect := test.text[e[0]:e[1]]
- if expect != result[k] {
- t.Errorf("expected %q got %q: %s", expect, result, test)
- }
- }
- }
- }
-}
-
-func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- if len(test.matches) != len(result) {
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- return
- }
- for k, e := range test.matches {
- if e[0] != result[k][0] || e[1] != result[k][1] {
- t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
- }
- }
- }
-}
-
-func TestFindAllIndex(t *testing.T) {
- for _, test := range findTests {
- testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
- }
-}
-
-func TestFindAllStringIndex(t *testing.T) {
- for _, test := range findTests {
- testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
- }
-}
-
-// Now come the Submatch cases.
-
-func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
- if len(submatches) != len(result)*2 {
- t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
- return
- }
- for k := 0; k < len(submatches); k += 2 {
- if submatches[k] == -1 {
- if result[k/2] != nil {
- t.Errorf("match %d: expected nil got %q: %s", n, result, test)
- }
- continue
- }
- expect := test.text[submatches[k]:submatches[k+1]]
- if expect != string(result[k/2]) {
- t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
- return
- }
- }
-}
-
-func TestFindSubmatch(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- testSubmatchBytes(&test, 0, test.matches[0], result, t)
- }
- }
-}
-
-func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
- if len(submatches) != len(result)*2 {
- t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
- return
- }
- for k := 0; k < len(submatches); k += 2 {
- if submatches[k] == -1 {
- if result[k/2] != "" {
- t.Errorf("match %d: expected nil got %q: %s", n, result, test)
- }
- continue
- }
- expect := test.text[submatches[k]:submatches[k+1]]
- if expect != result[k/2] {
- t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
- return
- }
- }
-}
-
-func TestFindStringSubmatch(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindStringSubmatch(test.text)
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- testSubmatchString(&test, 0, test.matches[0], result, t)
- }
- }
-}
-
-func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
- if len(expect) != len(result) {
- t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
- return
- }
- for k, e := range expect {
- if e != result[k] {
- t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
- }
- }
-}
-
-func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case test.matches != nil && result != nil:
- testSubmatchIndices(test, 0, test.matches[0], result, t)
- }
-}
-
-func TestFindSubmatchIndex(t *testing.T) {
- for _, test := range findTests {
- testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
- }
-}
-
-func TestFindStringSubmatchIndex(t *testing.T) {
- for _, test := range findTests {
- testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
- }
-}
-
-func TestFindReaderSubmatchIndex(t *testing.T) {
- for _, test := range findTests {
- testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
- }
-}
-
-// Now come the monster AllSubmatch cases.
-
-func TestFindAllSubmatch(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case len(test.matches) != len(result):
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- case test.matches != nil && result != nil:
- for k, match := range test.matches {
- testSubmatchBytes(&test, k, match, result[k], t)
- }
- }
- }
-}
-
-func TestFindAllStringSubmatch(t *testing.T) {
- for _, test := range findTests {
- result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case len(test.matches) != len(result):
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- case test.matches != nil && result != nil:
- for k, match := range test.matches {
- testSubmatchString(&test, k, match, result[k], t)
- }
- }
- }
-}
-
-func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
- switch {
- case test.matches == nil && result == nil:
- // ok
- case test.matches == nil && result != nil:
- t.Errorf("expected no match; got one: %s", test)
- case test.matches != nil && result == nil:
- t.Errorf("expected match; got none: %s", test)
- case len(test.matches) != len(result):
- t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
- case test.matches != nil && result != nil:
- for k, match := range test.matches {
- testSubmatchIndices(test, k, match, result[k], t)
- }
- }
-}
-
-func TestFindAllSubmatchIndex(t *testing.T) {
- for _, test := range findTests {
- testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
- }
-}
-
-func TestFindAllStringSubmatchIndex(t *testing.T) {
- for _, test := range findTests {
- testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
- }
-}
diff --git a/libgo/go/old/regexp/regexp.go b/libgo/go/old/regexp/regexp.go
deleted file mode 100644
index d3044d0c1d..0000000000
--- a/libgo/go/old/regexp/regexp.go
+++ /dev/null
@@ -1,1488 +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 regexp implements a simple regular expression library.
-//
-// The syntax of the regular expressions accepted is:
-//
-// regexp:
-// concatenation { '|' concatenation }
-// concatenation:
-// { closure }
-// closure:
-// term [ '*' | '+' | '?' ]
-// term:
-// '^'
-// '$'
-// '.'
-// character
-// '[' [ '^' ] { character-range } ']'
-// '(' regexp ')'
-// character-range:
-// character [ '-' character ]
-//
-// All characters are UTF-8-encoded code points. Backslashes escape special
-// characters, including inside character classes. The standard Go character
-// escapes are also recognized: \a \b \f \n \r \t \v.
-//
-// There are 16 methods of Regexp that match a regular expression and identify
-// the matched text. Their names are matched by this regular expression:
-//
-// Find(All)?(String)?(Submatch)?(Index)?
-//
-// If 'All' is present, the routine matches successive non-overlapping
-// matches of the entire expression. Empty matches abutting a preceding
-// match are ignored. The return value is a slice containing the successive
-// return values of the corresponding non-'All' routine. These routines take
-// an extra integer argument, n; if n >= 0, the function returns at most n
-// matches/submatches.
-//
-// If 'String' is present, the argument is a string; otherwise it is a slice
-// of bytes; return values are adjusted as appropriate.
-//
-// If 'Submatch' is present, the return value is a slice identifying the
-// successive submatches of the expression. Submatches are matches of
-// parenthesized subexpressions within the regular expression, numbered from
-// left to right in order of opening parenthesis. Submatch 0 is the match of
-// the entire expression, submatch 1 the match of the first parenthesized
-// subexpression, and so on.
-//
-// If 'Index' is present, matches and submatches are identified by byte index
-// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
-// the nth submatch. The pair for n==0 identifies the match of the entire
-// expression. If 'Index' is not present, the match is identified by the
-// text of the match/submatch. If an index is negative, it means that
-// subexpression did not match any string in the input.
-//
-// There is also a subset of the methods that can be applied to text read
-// from a RuneReader:
-//
-// MatchReader, FindReaderIndex, FindReaderSubmatchIndex
-//
-// This set may grow. Note that regular expression matches may need to
-// examine text beyond the text returned by a match, so the methods that
-// match text from a RuneReader may read arbitrarily far into the input
-// before returning.
-//
-// (There are a few other methods that do not match this pattern.)
-//
-package regexp
-
-import (
- "bytes"
- "io"
- "strings"
- "unicode/utf8"
-)
-
-var debug = false
-
-// Error is the local type for a parsing error.
-type Error string
-
-func (e Error) Error() string {
- return string(e)
-}
-
-// Error codes returned by failures to parse an expression.
-var (
- ErrInternal = Error("regexp: internal error")
- ErrUnmatchedLpar = Error("regexp: unmatched '('")
- ErrUnmatchedRpar = Error("regexp: unmatched ')'")
- ErrUnmatchedLbkt = Error("regexp: unmatched '['")
- ErrUnmatchedRbkt = Error("regexp: unmatched ']'")
- ErrBadRange = Error("regexp: bad range in character class")
- ErrExtraneousBackslash = Error("regexp: extraneous backslash")
- ErrBadClosure = Error("regexp: repeated closure (**, ++, etc.)")
- ErrBareClosure = Error("regexp: closure applies to nothing")
- ErrBadBackslash = Error("regexp: illegal backslash escape")
-)
-
-const (
- iStart = iota // beginning of program
- iEnd // end of program: success
- iBOT // '^' beginning of text
- iEOT // '$' end of text
- iChar // 'a' regular character
- iCharClass // [a-z] character class
- iAny // '.' any character including newline
- iNotNL // [^\n] special case: any character but newline
- iBra // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right
- iAlt // '|' alternation
- iNop // do nothing; makes it easy to link without patching
-)
-
-// An instruction executed by the NFA
-type instr struct {
- kind int // the type of this instruction: iChar, iAny, etc.
- index int // used only in debugging; could be eliminated
- next *instr // the instruction to execute after this one
- // Special fields valid only for some items.
- char rune // iChar
- braNum int // iBra, iEbra
- cclass *charClass // iCharClass
- left *instr // iAlt, other branch
-}
-
-func (i *instr) print() {
- switch i.kind {
- case iStart:
- print("start")
- case iEnd:
- print("end")
- case iBOT:
- print("bot")
- case iEOT:
- print("eot")
- case iChar:
- print("char ", string(i.char))
- case iCharClass:
- i.cclass.print()
- case iAny:
- print("any")
- case iNotNL:
- print("notnl")
- case iBra:
- if i.braNum&1 == 0 {
- print("bra", i.braNum/2)
- } else {
- print("ebra", i.braNum/2)
- }
- case iAlt:
- print("alt(", i.left.index, ")")
- case iNop:
- print("nop")
- }
-}
-
-// Regexp is the representation of a compiled regular expression.
-// The public interface is entirely through methods.
-// A Regexp is safe for concurrent use by multiple goroutines.
-type Regexp struct {
- expr string // the original expression
- prefix string // initial plain text string
- prefixBytes []byte // initial plain text bytes
- inst []*instr
- start *instr // first instruction of machine
- prefixStart *instr // where to start if there is a prefix
- nbra int // number of brackets in expression, for subexpressions
-}
-
-type charClass struct {
- negate bool // is character class negated? ([^a-z])
- // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
- ranges []rune
- cmin, cmax rune
-}
-
-func (cclass *charClass) print() {
- print("charclass")
- if cclass.negate {
- print(" (negated)")
- }
- for i := 0; i < len(cclass.ranges); i += 2 {
- l := cclass.ranges[i]
- r := cclass.ranges[i+1]
- if l == r {
- print(" [", string(l), "]")
- } else {
- print(" [", string(l), "-", string(r), "]")
- }
- }
-}
-
-func (cclass *charClass) addRange(a, b rune) {
- // range is a through b inclusive
- cclass.ranges = append(cclass.ranges, a, b)
- if a < cclass.cmin {
- cclass.cmin = a
- }
- if b > cclass.cmax {
- cclass.cmax = b
- }
-}
-
-func (cclass *charClass) matches(c rune) bool {
- if c < cclass.cmin || c > cclass.cmax {
- return cclass.negate
- }
- ranges := cclass.ranges
- for i := 0; i < len(ranges); i = i + 2 {
- if ranges[i] <= c && c <= ranges[i+1] {
- return !cclass.negate
- }
- }
- return cclass.negate
-}
-
-func newCharClass() *instr {
- i := &instr{kind: iCharClass}
- i.cclass = new(charClass)
- i.cclass.ranges = make([]rune, 0, 4)
- i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1
- i.cclass.cmax = -1
- return i
-}
-
-func (re *Regexp) add(i *instr) *instr {
- i.index = len(re.inst)
- re.inst = append(re.inst, i)
- return i
-}
-
-type parser struct {
- re *Regexp
- nlpar int // number of unclosed lpars
- pos int
- ch rune
-}
-
-func (p *parser) error(err Error) {
- panic(err)
-}
-
-const endOfText = -1
-
-func (p *parser) c() rune { return p.ch }
-
-func (p *parser) nextc() rune {
- if p.pos >= len(p.re.expr) {
- p.ch = endOfText
- } else {
- c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
- p.ch = c
- p.pos += w
- }
- return p.ch
-}
-
-func newParser(re *Regexp) *parser {
- p := new(parser)
- p.re = re
- p.nextc() // load p.ch
- return p
-}
-
-func special(c rune) bool {
- for _, r := range `\.+*?()|[]^$` {
- if c == r {
- return true
- }
- }
- return false
-}
-
-func ispunct(c rune) bool {
- for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
- if c == r {
- return true
- }
- }
- return false
-}
-
-var escapes = []byte("abfnrtv")
-var escaped = []byte("\a\b\f\n\r\t\v")
-
-func escape(c rune) int {
- for i, b := range escapes {
- if rune(b) == c {
- return i
- }
- }
- return -1
-}
-
-func (p *parser) checkBackslash() rune {
- c := p.c()
- if c == '\\' {
- c = p.nextc()
- switch {
- case c == endOfText:
- p.error(ErrExtraneousBackslash)
- case ispunct(c):
- // c is as delivered
- case escape(c) >= 0:
- c = rune(escaped[escape(c)])
- default:
- p.error(ErrBadBackslash)
- }
- }
- return c
-}
-
-func (p *parser) charClass() *instr {
- i := newCharClass()
- cc := i.cclass
- if p.c() == '^' {
- cc.negate = true
- p.nextc()
- }
- left := rune(-1)
- for {
- switch c := p.c(); c {
- case ']', endOfText:
- if left >= 0 {
- p.error(ErrBadRange)
- }
- // Is it [^\n]?
- if cc.negate && len(cc.ranges) == 2 &&
- cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
- nl := &instr{kind: iNotNL}
- p.re.add(nl)
- return nl
- }
- // Special common case: "[a]" -> "a"
- if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
- c := &instr{kind: iChar, char: cc.ranges[0]}
- p.re.add(c)
- return c
- }
- p.re.add(i)
- return i
- case '-': // do this before backslash processing
- p.error(ErrBadRange)
- default:
- c = p.checkBackslash()
- p.nextc()
- switch {
- case left < 0: // first of pair
- if p.c() == '-' { // range
- p.nextc()
- left = c
- } else { // single char
- cc.addRange(c, c)
- }
- case left <= c: // second of pair
- cc.addRange(left, c)
- left = -1
- default:
- p.error(ErrBadRange)
- }
- }
- }
- panic("unreachable")
-}
-
-func (p *parser) term() (start, end *instr) {
- switch c := p.c(); c {
- case '|', endOfText:
- return nil, nil
- case '*', '+', '?':
- p.error(ErrBareClosure)
- case ')':
- if p.nlpar == 0 {
- p.error(ErrUnmatchedRpar)
- }
- return nil, nil
- case ']':
- p.error(ErrUnmatchedRbkt)
- case '^':
- p.nextc()
- start = p.re.add(&instr{kind: iBOT})
- return start, start
- case '$':
- p.nextc()
- start = p.re.add(&instr{kind: iEOT})
- return start, start
- case '.':
- p.nextc()
- start = p.re.add(&instr{kind: iAny})
- return start, start
- case '[':
- p.nextc()
- start = p.charClass()
- if p.c() != ']' {
- p.error(ErrUnmatchedLbkt)
- }
- p.nextc()
- return start, start
- case '(':
- p.nextc()
- p.nlpar++
- p.re.nbra++ // increment first so first subexpr is \1
- nbra := p.re.nbra
- start, end = p.regexp()
- if p.c() != ')' {
- p.error(ErrUnmatchedLpar)
- }
- p.nlpar--
- p.nextc()
- bra := &instr{kind: iBra, braNum: 2 * nbra}
- p.re.add(bra)
- ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
- p.re.add(ebra)
- if start == nil {
- if end == nil {
- p.error(ErrInternal)
- return
- }
- start = ebra
- } else {
- end.next = ebra
- }
- bra.next = start
- return bra, ebra
- default:
- c = p.checkBackslash()
- p.nextc()
- start = &instr{kind: iChar, char: c}
- p.re.add(start)
- return start, start
- }
- panic("unreachable")
-}
-
-func (p *parser) closure() (start, end *instr) {
- start, end = p.term()
- if start == nil {
- return
- }
- switch p.c() {
- case '*':
- // (start,end)*:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- end.next = alt // after end, do alt
- alt.left = start // alternate brach: return to start
- start = alt // alt becomes new (start, end)
- end = alt
- case '+':
- // (start,end)+:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- end.next = alt // after end, do alt
- alt.left = start // alternate brach: return to start
- end = alt // start is unchanged; end is alt
- case '?':
- // (start,end)?:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- nop := &instr{kind: iNop}
- p.re.add(nop)
- alt.left = start // alternate branch is start
- alt.next = nop // follow on to nop
- end.next = nop // after end, go to nop
- start = alt // start is now alt
- end = nop // end is nop pointed to by both branches
- default:
- return
- }
- switch p.nextc() {
- case '*', '+', '?':
- p.error(ErrBadClosure)
- }
- return
-}
-
-func (p *parser) concatenation() (start, end *instr) {
- for {
- nstart, nend := p.closure()
- switch {
- case nstart == nil: // end of this concatenation
- if start == nil { // this is the empty string
- nop := p.re.add(&instr{kind: iNop})
- return nop, nop
- }
- return
- case start == nil: // this is first element of concatenation
- start, end = nstart, nend
- default:
- end.next = nstart
- end = nend
- }
- }
- panic("unreachable")
-}
-
-func (p *parser) regexp() (start, end *instr) {
- start, end = p.concatenation()
- for {
- switch p.c() {
- default:
- return
- case '|':
- p.nextc()
- nstart, nend := p.concatenation()
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- alt.left = start
- alt.next = nstart
- nop := &instr{kind: iNop}
- p.re.add(nop)
- end.next = nop
- nend.next = nop
- start, end = alt, nop
- }
- }
- panic("unreachable")
-}
-
-func unNop(i *instr) *instr {
- for i.kind == iNop {
- i = i.next
- }
- return i
-}
-
-func (re *Regexp) eliminateNops() {
- for _, inst := range re.inst {
- if inst.kind == iEnd {
- continue
- }
- inst.next = unNop(inst.next)
- if inst.kind == iAlt {
- inst.left = unNop(inst.left)
- }
- }
-}
-
-func (re *Regexp) dump() {
- print("prefix <", re.prefix, ">\n")
- for _, inst := range re.inst {
- print(inst.index, ": ")
- inst.print()
- if inst.kind != iEnd {
- print(" -> ", inst.next.index)
- }
- print("\n")
- }
-}
-
-func (re *Regexp) doParse() {
- p := newParser(re)
- start := &instr{kind: iStart}
- re.add(start)
- s, e := p.regexp()
- start.next = s
- re.start = start
- e.next = re.add(&instr{kind: iEnd})
-
- if debug {
- re.dump()
- println()
- }
-
- re.eliminateNops()
- if debug {
- re.dump()
- println()
- }
- re.setPrefix()
- if debug {
- re.dump()
- println()
- }
-}
-
-// Extract regular text from the beginning of the pattern,
-// possibly after a leading iBOT.
-// That text can be used by doExecute to speed up matching.
-func (re *Regexp) setPrefix() {
- var b []byte
- var utf = make([]byte, utf8.UTFMax)
- var inst *instr
- // First instruction is start; skip that. Also skip any initial iBOT.
- inst = re.inst[0].next
- for inst.kind == iBOT {
- inst = inst.next
- }
-Loop:
- for ; inst.kind != iEnd; inst = inst.next {
- // stop if this is not a char
- if inst.kind != iChar {
- break
- }
- // stop if this char can be followed by a match for an empty string,
- // which includes closures, ^, and $.
- switch inst.next.kind {
- case iBOT, iEOT, iAlt:
- break Loop
- }
- n := utf8.EncodeRune(utf, inst.char)
- b = append(b, utf[0:n]...)
- }
- // point prefixStart instruction to first non-CHAR after prefix
- re.prefixStart = inst
- re.prefixBytes = b
- re.prefix = string(b)
-}
-
-// String returns the source text used to compile the regular expression.
-func (re *Regexp) String() string {
- return re.expr
-}
-
-// Compile parses a regular expression and returns, if successful, a Regexp
-// object that can be used to match against text.
-func Compile(str string) (regexp *Regexp, error error) {
- regexp = new(Regexp)
- // doParse will panic if there is a parse error.
- defer func() {
- if e := recover(); e != nil {
- regexp = nil
- error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
- }
- }()
- regexp.expr = str
- regexp.inst = make([]*instr, 0, 10)
- regexp.doParse()
- return
-}
-
-// MustCompile is like Compile but panics if the expression cannot be parsed.
-// It simplifies safe initialization of global variables holding compiled regular
-// expressions.
-func MustCompile(str string) *Regexp {
- regexp, error := Compile(str)
- if error != nil {
- panic(`regexp: compiling "` + str + `": ` + error.Error())
- }
- return regexp
-}
-
-// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
-func (re *Regexp) NumSubexp() int { return re.nbra }
-
-// The match arena allows us to reduce the garbage generated by tossing
-// match vectors away as we execute. Matches are ref counted and returned
-// to a free list when no longer active. Increases a simple benchmark by 22X.
-type matchArena struct {
- head *matchVec
- len int // length of match vector
- pos int
- atBOT bool // whether we're at beginning of text
- atEOT bool // whether we're at end of text
-}
-
-type matchVec struct {
- m []int // pairs of bracketing submatches. 0th is start,end
- ref int
- next *matchVec
-}
-
-func (a *matchArena) new() *matchVec {
- if a.head == nil {
- const N = 10
- block := make([]matchVec, N)
- for i := 0; i < N; i++ {
- b := &block[i]
- b.next = a.head
- a.head = b
- }
- }
- m := a.head
- a.head = m.next
- m.ref = 0
- if m.m == nil {
- m.m = make([]int, a.len)
- }
- return m
-}
-
-func (a *matchArena) free(m *matchVec) {
- m.ref--
- if m.ref == 0 {
- m.next = a.head
- a.head = m
- }
-}
-
-func (a *matchArena) copy(m *matchVec) *matchVec {
- m1 := a.new()
- copy(m1.m, m.m)
- return m1
-}
-
-func (a *matchArena) noMatch() *matchVec {
- m := a.new()
- for i := range m.m {
- m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
- }
- m.ref = 1
- return m
-}
-
-type state struct {
- inst *instr // next instruction to execute
- prefixed bool // this match began with a fixed prefix
- match *matchVec
-}
-
-// Append new state to to-do list. Leftmost-longest wins so avoid
-// adding a state that's already active. The matchVec will be inc-ref'ed
-// if it is assigned to a state.
-func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec) []state {
- switch inst.kind {
- case iBOT:
- if a.atBOT {
- s = a.addState(s, inst.next, prefixed, match)
- }
- return s
- case iEOT:
- if a.atEOT {
- s = a.addState(s, inst.next, prefixed, match)
- }
- return s
- case iBra:
- match.m[inst.braNum] = a.pos
- s = a.addState(s, inst.next, prefixed, match)
- return s
- }
- l := len(s)
- // States are inserted in order so it's sufficient to see if we have the same
- // instruction; no need to see if existing match is earlier (it is).
- for i := 0; i < l; i++ {
- if s[i].inst == inst {
- return s
- }
- }
- s = append(s, state{inst, prefixed, match})
- match.ref++
- if inst.kind == iAlt {
- s = a.addState(s, inst.left, prefixed, a.copy(match))
- // give other branch a copy of this match vector
- s = a.addState(s, inst.next, prefixed, a.copy(match))
- }
- return s
-}
-
-// input abstracts different representations of the input text. It provides
-// one-character lookahead.
-type input interface {
- step(pos int) (r rune, width int) // advance one rune
- canCheckPrefix() bool // can we look ahead without losing info?
- hasPrefix(re *Regexp) bool
- index(re *Regexp, pos int) int
-}
-
-// inputString scans a string.
-type inputString struct {
- str string
-}
-
-func newInputString(str string) *inputString {
- return &inputString{str: str}
-}
-
-func (i *inputString) step(pos int) (rune, int) {
- if pos < len(i.str) {
- return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
- }
- return endOfText, 0
-}
-
-func (i *inputString) canCheckPrefix() bool {
- return true
-}
-
-func (i *inputString) hasPrefix(re *Regexp) bool {
- return strings.HasPrefix(i.str, re.prefix)
-}
-
-func (i *inputString) index(re *Regexp, pos int) int {
- return strings.Index(i.str[pos:], re.prefix)
-}
-
-// inputBytes scans a byte slice.
-type inputBytes struct {
- str []byte
-}
-
-func newInputBytes(str []byte) *inputBytes {
- return &inputBytes{str: str}
-}
-
-func (i *inputBytes) step(pos int) (rune, int) {
- if pos < len(i.str) {
- return utf8.DecodeRune(i.str[pos:len(i.str)])
- }
- return endOfText, 0
-}
-
-func (i *inputBytes) canCheckPrefix() bool {
- return true
-}
-
-func (i *inputBytes) hasPrefix(re *Regexp) bool {
- return bytes.HasPrefix(i.str, re.prefixBytes)
-}
-
-func (i *inputBytes) index(re *Regexp, pos int) int {
- return bytes.Index(i.str[pos:], re.prefixBytes)
-}
-
-// inputReader scans a RuneReader.
-type inputReader struct {
- r io.RuneReader
- atEOT bool
- pos int
-}
-
-func newInputReader(r io.RuneReader) *inputReader {
- return &inputReader{r: r}
-}
-
-func (i *inputReader) step(pos int) (rune, int) {
- if !i.atEOT && pos != i.pos {
- return endOfText, 0
-
- }
- r, w, err := i.r.ReadRune()
- if err != nil {
- i.atEOT = true
- return endOfText, 0
- }
- i.pos += w
- return r, w
-}
-
-func (i *inputReader) canCheckPrefix() bool {
- return false
-}
-
-func (i *inputReader) hasPrefix(re *Regexp) bool {
- return false
-}
-
-func (i *inputReader) index(re *Regexp, pos int) int {
- return -1
-}
-
-// Search match starting from pos bytes into the input.
-func (re *Regexp) doExecute(i input, pos int) []int {
- var s [2][]state
- s[0] = make([]state, 0, 10)
- s[1] = make([]state, 0, 10)
- in, out := 0, 1
- var final state
- found := false
- anchored := re.inst[0].next.kind == iBOT
- if anchored && pos > 0 {
- return nil
- }
- // fast check for initial plain substring
- if i.canCheckPrefix() && re.prefix != "" {
- advance := 0
- if anchored {
- if !i.hasPrefix(re) {
- return nil
- }
- } else {
- advance = i.index(re, pos)
- if advance == -1 {
- return nil
- }
- }
- pos += advance
- }
- // We look one character ahead so we can match $, which checks whether
- // we are at EOT.
- nextChar, nextWidth := i.step(pos)
- arena := &matchArena{
- len: 2 * (re.nbra + 1),
- pos: pos,
- atBOT: pos == 0,
- atEOT: nextChar == endOfText,
- }
- for c, startPos := rune(0), pos; c != endOfText; {
- if !found && (pos == startPos || !anchored) {
- // prime the pump if we haven't seen a match yet
- match := arena.noMatch()
- match.m[0] = pos
- s[out] = arena.addState(s[out], re.start.next, false, match)
- arena.free(match) // if addState saved it, ref was incremented
- } else if len(s[out]) == 0 {
- // machine has completed
- break
- }
- in, out = out, in // old out state is new in state
- // clear out old state
- old := s[out]
- for _, state := range old {
- arena.free(state.match)
- }
- s[out] = old[0:0] // truncate state vector
- c = nextChar
- thisPos := pos
- pos += nextWidth
- nextChar, nextWidth = i.step(pos)
- arena.atEOT = nextChar == endOfText
- arena.atBOT = false
- arena.pos = pos
- for _, st := range s[in] {
- switch st.inst.kind {
- case iBOT:
- case iEOT:
- case iChar:
- if c == st.inst.char {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iCharClass:
- if st.inst.cclass.matches(c) {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iAny:
- if c != endOfText {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iNotNL:
- if c != endOfText && c != '\n' {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iBra:
- case iAlt:
- case iEnd:
- // choose leftmost longest
- if !found || // first
- st.match.m[0] < final.match.m[0] || // leftmost
- (st.match.m[0] == final.match.m[0] && thisPos > final.match.m[1]) { // longest
- if final.match != nil {
- arena.free(final.match)
- }
- final = st
- final.match.ref++
- final.match.m[1] = thisPos
- }
- found = true
- default:
- st.inst.print()
- panic("unknown instruction in execute")
- }
- }
- }
- if final.match == nil {
- return nil
- }
- // if match found, back up start of match by width of prefix.
- if final.prefixed && len(final.match.m) > 0 {
- final.match.m[0] -= len(re.prefix)
- }
- return final.match.m
-}
-
-// LiteralPrefix returns a literal string that must begin any match
-// of the regular expression re. It returns the boolean true if the
-// literal string comprises the entire regular expression.
-func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
- c := make([]rune, len(re.inst)-2) // minus start and end.
- // First instruction is start; skip that.
- i := 0
- for inst := re.inst[0].next; inst.kind != iEnd; inst = inst.next {
- // stop if this is not a char
- if inst.kind != iChar {
- return string(c[:i]), false
- }
- c[i] = inst.char
- i++
- }
- return string(c[:i]), true
-}
-
-// MatchReader returns whether the Regexp matches the text read by the
-// RuneReader. The return value is a boolean: true for match, false for no
-// match.
-func (re *Regexp) MatchReader(r io.RuneReader) bool {
- return len(re.doExecute(newInputReader(r), 0)) > 0
-}
-
-// MatchString returns whether the Regexp matches the string s.
-// The return value is a boolean: true for match, false for no match.
-func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(newInputString(s), 0)) > 0 }
-
-// Match returns whether the Regexp matches the byte slice b.
-// The return value is a boolean: true for match, false for no match.
-func (re *Regexp) Match(b []byte) bool { return len(re.doExecute(newInputBytes(b), 0)) > 0 }
-
-// MatchReader checks whether a textual regular expression matches the text
-// read by the RuneReader. More complicated queries need to use Compile and
-// the full Regexp interface.
-func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) {
- re, err := Compile(pattern)
- if err != nil {
- return false, err
- }
- return re.MatchReader(r), nil
-}
-
-// MatchString checks whether a textual regular expression
-// matches a string. More complicated queries need
-// to use Compile and the full Regexp interface.
-func MatchString(pattern string, s string) (matched bool, error error) {
- re, err := Compile(pattern)
- if err != nil {
- return false, err
- }
- return re.MatchString(s), nil
-}
-
-// Match checks whether a textual regular expression
-// matches a byte slice. More complicated queries need
-// to use Compile and the full Regexp interface.
-func Match(pattern string, b []byte) (matched bool, error error) {
- re, err := Compile(pattern)
- if err != nil {
- return false, err
- }
- return re.Match(b), nil
-}
-
-// ReplaceAllString returns a copy of src in which all matches for the Regexp
-// have been replaced by repl. No support is provided for expressions
-// (e.g. \1 or $1) in the replacement string.
-func (re *Regexp) ReplaceAllString(src, repl string) string {
- return re.ReplaceAllStringFunc(src, func(string) string { return repl })
-}
-
-// ReplaceAllStringFunc returns a copy of src in which all matches for the
-// Regexp have been replaced by the return value of of function repl (whose
-// first argument is the matched string). No support is provided for
-// expressions (e.g. \1 or $1) in the replacement string.
-func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
- lastMatchEnd := 0 // end position of the most recent match
- searchPos := 0 // position where we next look for a match
- buf := new(bytes.Buffer)
- for searchPos <= len(src) {
- a := re.doExecute(newInputString(src), searchPos)
- if len(a) == 0 {
- break // no more matches
- }
-
- // Copy the unmatched characters before this match.
- io.WriteString(buf, src[lastMatchEnd:a[0]])
-
- // Now insert a copy of the replacement string, but not for a
- // match of the empty string immediately after another match.
- // (Otherwise, we get double replacement for patterns that
- // match both empty and nonempty strings.)
- if a[1] > lastMatchEnd || a[0] == 0 {
- io.WriteString(buf, repl(src[a[0]:a[1]]))
- }
- lastMatchEnd = a[1]
-
- // Advance past this match; always advance at least one character.
- _, width := utf8.DecodeRuneInString(src[searchPos:])
- if searchPos+width > a[1] {
- searchPos += width
- } else if searchPos+1 > a[1] {
- // This clause is only needed at the end of the input
- // string. In that case, DecodeRuneInString returns width=0.
- searchPos++
- } else {
- searchPos = a[1]
- }
- }
-
- // Copy the unmatched characters after the last match.
- io.WriteString(buf, src[lastMatchEnd:])
-
- return buf.String()
-}
-
-// ReplaceAll returns a copy of src in which all matches for the Regexp
-// have been replaced by repl. No support is provided for expressions
-// (e.g. \1 or $1) in the replacement text.
-func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
- return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
-}
-
-// ReplaceAllFunc returns a copy of src in which all matches for the
-// Regexp have been replaced by the return value of of function repl (whose
-// first argument is the matched []byte). No support is provided for
-// expressions (e.g. \1 or $1) in the replacement string.
-func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
- lastMatchEnd := 0 // end position of the most recent match
- searchPos := 0 // position where we next look for a match
- buf := new(bytes.Buffer)
- for searchPos <= len(src) {
- a := re.doExecute(newInputBytes(src), searchPos)
- if len(a) == 0 {
- break // no more matches
- }
-
- // Copy the unmatched characters before this match.
- buf.Write(src[lastMatchEnd:a[0]])
-
- // Now insert a copy of the replacement string, but not for a
- // match of the empty string immediately after another match.
- // (Otherwise, we get double replacement for patterns that
- // match both empty and nonempty strings.)
- if a[1] > lastMatchEnd || a[0] == 0 {
- buf.Write(repl(src[a[0]:a[1]]))
- }
- lastMatchEnd = a[1]
-
- // Advance past this match; always advance at least one character.
- _, width := utf8.DecodeRune(src[searchPos:])
- if searchPos+width > a[1] {
- searchPos += width
- } else if searchPos+1 > a[1] {
- // This clause is only needed at the end of the input
- // string. In that case, DecodeRuneInString returns width=0.
- searchPos++
- } else {
- searchPos = a[1]
- }
- }
-
- // Copy the unmatched characters after the last match.
- buf.Write(src[lastMatchEnd:])
-
- return buf.Bytes()
-}
-
-// QuoteMeta returns a string that quotes all regular expression metacharacters
-// inside the argument text; the returned string is a regular expression matching
-// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
-func QuoteMeta(s string) string {
- b := make([]byte, 2*len(s))
-
- // A byte loop is correct because all metacharacters are ASCII.
- j := 0
- for i := 0; i < len(s); i++ {
- if special(rune(s[i])) {
- b[j] = '\\'
- j++
- }
- b[j] = s[i]
- j++
- }
- return string(b[0:j])
-}
-
-// Find matches in slice b if b is non-nil, otherwise find matches in string s.
-func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
- var end int
- if b == nil {
- end = len(s)
- } else {
- end = len(b)
- }
-
- for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
- var in input
- if b == nil {
- in = newInputString(s)
- } else {
- in = newInputBytes(b)
- }
- matches := re.doExecute(in, pos)
- if len(matches) == 0 {
- break
- }
-
- accept := true
- if matches[1] == pos {
- // We've found an empty match.
- if matches[0] == prevMatchEnd {
- // We don't allow an empty match right
- // after a previous match, so ignore it.
- accept = false
- }
- var width int
- // TODO: use step()
- if b == nil {
- _, width = utf8.DecodeRuneInString(s[pos:end])
- } else {
- _, width = utf8.DecodeRune(b[pos:end])
- }
- if width > 0 {
- pos += width
- } else {
- pos = end + 1
- }
- } else {
- pos = matches[1]
- }
- prevMatchEnd = matches[1]
-
- if accept {
- deliver(matches)
- i++
- }
- }
-}
-
-// Find returns a slice holding the text of the leftmost match in b of the regular expression.
-// A return value of nil indicates no match.
-func (re *Regexp) Find(b []byte) []byte {
- a := re.doExecute(newInputBytes(b), 0)
- if a == nil {
- return nil
- }
- return b[a[0]:a[1]]
-}
-
-// FindIndex returns a two-element slice of integers defining the location of
-// the leftmost match in b of the regular expression. The match itself is at
-// b[loc[0]:loc[1]].
-// A return value of nil indicates no match.
-func (re *Regexp) FindIndex(b []byte) (loc []int) {
- a := re.doExecute(newInputBytes(b), 0)
- if a == nil {
- return nil
- }
- return a[0:2]
-}
-
-// FindString returns a string holding the text of the leftmost match in s of the regular
-// expression. If there is no match, the return value is an empty string,
-// but it will also be empty if the regular expression successfully matches
-// an empty string. Use FindStringIndex or FindStringSubmatch if it is
-// necessary to distinguish these cases.
-func (re *Regexp) FindString(s string) string {
- a := re.doExecute(newInputString(s), 0)
- if a == nil {
- return ""
- }
- return s[a[0]:a[1]]
-}
-
-// FindStringIndex returns a two-element slice of integers defining the
-// location of the leftmost match in s of the regular expression. The match
-// itself is at s[loc[0]:loc[1]].
-// A return value of nil indicates no match.
-func (re *Regexp) FindStringIndex(s string) []int {
- a := re.doExecute(newInputString(s), 0)
- if a == nil {
- return nil
- }
- return a[0:2]
-}
-
-// FindReaderIndex returns a two-element slice of integers defining the
-// location of the leftmost match of the regular expression in text read from
-// the RuneReader. The match itself is at s[loc[0]:loc[1]]. A return
-// value of nil indicates no match.
-func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
- a := re.doExecute(newInputReader(r), 0)
- if a == nil {
- return nil
- }
- return a[0:2]
-}
-
-// FindSubmatch returns a slice of slices holding the text of the leftmost
-// match of the regular expression in b and the matches, if any, of its
-// subexpressions, as defined by the 'Submatch' descriptions in the package
-// comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindSubmatch(b []byte) [][]byte {
- a := re.doExecute(newInputBytes(b), 0)
- if a == nil {
- return nil
- }
- ret := make([][]byte, len(a)/2)
- for i := range ret {
- if a[2*i] >= 0 {
- ret[i] = b[a[2*i]:a[2*i+1]]
- }
- }
- return ret
-}
-
-// FindSubmatchIndex returns a slice holding the index pairs identifying the
-// leftmost match of the regular expression in b and the matches, if any, of
-// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
-// in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindSubmatchIndex(b []byte) []int {
- return re.doExecute(newInputBytes(b), 0)
-}
-
-// FindStringSubmatch returns a slice of strings holding the text of the
-// leftmost match of the regular expression in s and the matches, if any, of
-// its subexpressions, as defined by the 'Submatch' description in the
-// package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindStringSubmatch(s string) []string {
- a := re.doExecute(newInputString(s), 0)
- if a == nil {
- return nil
- }
- ret := make([]string, len(a)/2)
- for i := range ret {
- if a[2*i] >= 0 {
- ret[i] = s[a[2*i]:a[2*i+1]]
- }
- }
- return ret
-}
-
-// FindStringSubmatchIndex returns a slice holding the index pairs
-// identifying the leftmost match of the regular expression in s and the
-// matches, if any, of its subexpressions, as defined by the 'Submatch' and
-// 'Index' descriptions in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindStringSubmatchIndex(s string) []int {
- return re.doExecute(newInputString(s), 0)
-}
-
-// FindReaderSubmatchIndex returns a slice holding the index pairs
-// identifying the leftmost match of the regular expression of text read by
-// the RuneReader, and the matches, if any, of its subexpressions, as defined
-// by the 'Submatch' and 'Index' descriptions in the package comment. A
-// return value of nil indicates no match.
-func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
- return re.doExecute(newInputReader(r), 0)
-}
-
-const startSize = 10 // The size at which to start a slice in the 'All' routines.
-
-// FindAll is the 'All' version of Find; it returns a slice of all successive
-// matches of the expression, as defined by the 'All' description in the
-// package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAll(b []byte, n int) [][]byte {
- if n < 0 {
- n = len(b) + 1
- }
- result := make([][]byte, 0, startSize)
- re.allMatches("", b, n, func(match []int) {
- result = append(result, b[match[0]:match[1]])
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
-// successive matches of the expression, as defined by the 'All' description
-// in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
- if n < 0 {
- n = len(b) + 1
- }
- result := make([][]int, 0, startSize)
- re.allMatches("", b, n, func(match []int) {
- result = append(result, match[0:2])
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllString is the 'All' version of FindString; it returns a slice of all
-// successive matches of the expression, as defined by the 'All' description
-// in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllString(s string, n int) []string {
- if n < 0 {
- n = len(s) + 1
- }
- result := make([]string, 0, startSize)
- re.allMatches(s, nil, n, func(match []int) {
- result = append(result, s[match[0]:match[1]])
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
-// slice of all successive matches of the expression, as defined by the 'All'
-// description in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
- if n < 0 {
- n = len(s) + 1
- }
- result := make([][]int, 0, startSize)
- re.allMatches(s, nil, n, func(match []int) {
- result = append(result, match[0:2])
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
-// of all successive matches of the expression, as defined by the 'All'
-// description in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
- if n < 0 {
- n = len(b) + 1
- }
- result := make([][][]byte, 0, startSize)
- re.allMatches("", b, n, func(match []int) {
- slice := make([][]byte, len(match)/2)
- for j := range slice {
- if match[2*j] >= 0 {
- slice[j] = b[match[2*j]:match[2*j+1]]
- }
- }
- result = append(result, slice)
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
-// a slice of all successive matches of the expression, as defined by the
-// 'All' description in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
- if n < 0 {
- n = len(b) + 1
- }
- result := make([][]int, 0, startSize)
- re.allMatches("", b, n, func(match []int) {
- result = append(result, match)
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
-// returns a slice of all successive matches of the expression, as defined by
-// the 'All' description in the package comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
- if n < 0 {
- n = len(s) + 1
- }
- result := make([][]string, 0, startSize)
- re.allMatches(s, nil, n, func(match []int) {
- slice := make([]string, len(match)/2)
- for j := range slice {
- if match[2*j] >= 0 {
- slice[j] = s[match[2*j]:match[2*j+1]]
- }
- }
- result = append(result, slice)
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
-
-// FindAllStringSubmatchIndex is the 'All' version of
-// FindStringSubmatchIndex; it returns a slice of all successive matches of
-// the expression, as defined by the 'All' description in the package
-// comment.
-// A return value of nil indicates no match.
-func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
- if n < 0 {
- n = len(s) + 1
- }
- result := make([][]int, 0, startSize)
- re.allMatches(s, nil, n, func(match []int) {
- result = append(result, match)
- })
- if len(result) == 0 {
- return nil
- }
- return result
-}
diff --git a/libgo/go/old/template/doc.go b/libgo/go/old/template/doc.go
deleted file mode 100644
index e778d801da..0000000000
--- a/libgo/go/old/template/doc.go
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- Package template implements data-driven templates for generating textual
- output such as HTML.
-
- Templates are executed by applying them to a data structure.
- Annotations in the template refer to elements of the data
- structure (typically a field of a struct or a key in a map)
- to control execution and derive values to be displayed.
- The template walks the structure as it executes and the
- "cursor" @ represents the value at the current location
- in the structure.
-
- Data items may be values or pointers; the interface hides the
- indirection.
-
- In the following, 'Field' is one of several things, according to the data.
-
- - The name of a field of a struct (result = data.Field),
- - The value stored in a map under that key (result = data["Field"]), or
- - The result of invoking a niladic single-valued method with that name
- (result = data.Field())
-
- If Field is a struct field or method name, it must be an exported
- (capitalized) name.
-
- Major constructs ({} are the default delimiters for template actions;
- [] are the notation in this comment for optional elements):
-
- {# comment }
-
- A one-line comment.
-
- {.section field} XXX [ {.or} YYY ] {.end}
-
- Set @ to the value of the field. It may be an explicit @
- to stay at the same point in the data. If the field is nil
- or empty, execute YYY; otherwise execute XXX.
-
- {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
-
- Like .section, but field must be an array or slice. XXX
- is executed for each element. If the array is nil or empty,
- YYY is executed instead. If the {.alternates with} marker
- is present, ZZZ is executed between iterations of XXX.
-
- {field}
- {field1 field2 ...}
- {field|formatter}
- {field1 field2...|formatter}
- {field|formatter1|formatter2}
-
- Insert the value of the fields into the output. Each field is
- first looked for in the cursor, as in .section and .repeated.
- If it is not found, the search continues in outer sections
- until the top level is reached.
-
- If the field value is a pointer, leading asterisks indicate
- that the value to be inserted should be evaluated through the
- pointer. For example, if x.p is of type *int, {x.p} will
- insert the value of the pointer but {*x.p} will insert the
- value of the underlying integer. If the value is nil or not a
- pointer, asterisks have no effect.
-
- If a formatter is specified, it must be named in the formatter
- map passed to the template set up routines or in the default
- set ("html","str","") and is used to process the data for
- output. The formatter function has signature
- func(wr io.Writer, formatter string, data ...interface{})
- where wr is the destination for output, data holds the field
- values at the instantiation, and formatter is its name at
- the invocation site. The default formatter just concatenates
- the string representations of the fields.
-
- Multiple formatters separated by the pipeline character | are
- executed sequentially, with each formatter receiving the bytes
- emitted by the one to its left.
-
- As well as field names, one may use literals with Go syntax.
- Integer, floating-point, and string literals are supported.
- Raw strings may not span newlines.
-
- The delimiter strings get their default value, "{" and "}", from
- JSON-template. They may be set to any non-empty, space-free
- string using the SetDelims method. Their value can be printed
- in the output using {.meta-left} and {.meta-right}.
-*/
-package template
diff --git a/libgo/go/old/template/execute.go b/libgo/go/old/template/execute.go
deleted file mode 100644
index 464b620c98..0000000000
--- a/libgo/go/old/template/execute.go
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Code to execute a parsed template.
-
-package template
-
-import (
- "bytes"
- "io"
- "reflect"
- "strings"
-)
-
-// Internal state for executing a Template. As we evaluate the struct,
-// the data item descends into the fields associated with sections, etc.
-// Parent is used to walk upwards to find variables higher in the tree.
-type state struct {
- parent *state // parent in hierarchy
- data reflect.Value // the driver data for this section etc.
- wr io.Writer // where to send output
- buf [2]bytes.Buffer // alternating buffers used when chaining formatters
-}
-
-func (parent *state) clone(data reflect.Value) *state {
- return &state{parent: parent, data: data, wr: parent.wr}
-}
-
-// Evaluate interfaces and pointers looking for a value that can look up the name, via a
-// struct field, method, or map key, and return the result of the lookup.
-func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
- for v.IsValid() {
- typ := v.Type()
- if n := v.Type().NumMethod(); n > 0 {
- for i := 0; i < n; i++ {
- m := typ.Method(i)
- mtyp := m.Type
- if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return v.Method(i).Call(nil)[0]
- }
- }
- }
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- case reflect.Struct:
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return av.FieldByName(name)
- case reflect.Map:
- if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
- return v
- }
- return reflect.Zero(typ.Elem())
- default:
- return reflect.Value{}
- }
- }
- return v
-}
-
-// indirectPtr returns the item numLevels levels of indirection below the value.
-// It is forgiving: if the value is not a pointer, it returns it rather than giving
-// an error. If the pointer is nil, it is returned as is.
-func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
- for i := numLevels; v.IsValid() && i > 0; i++ {
- if p := v; p.Kind() == reflect.Ptr {
- if p.IsNil() {
- return v
- }
- v = p.Elem()
- } else {
- break
- }
- }
- return v
-}
-
-// Walk v through pointers and interfaces, extracting the elements within.
-func indirect(v reflect.Value) reflect.Value {
-loop:
- for v.IsValid() {
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- default:
- break loop
- }
- }
- return v
-}
-
-// If the data for this template is a struct, find the named variable.
-// Names of the form a.b.c are walked down the data tree.
-// The special name "@" (the "cursor") denotes the current data.
-// The value coming in (st.data) might need indirecting to reach
-// a struct while the return value is not indirected - that is,
-// it represents the actual named field. Leading stars indicate
-// levels of indirection to be applied to the value.
-func (t *Template) findVar(st *state, s string) reflect.Value {
- data := st.data
- flattenedName := strings.TrimLeft(s, "*")
- numStars := len(s) - len(flattenedName)
- s = flattenedName
- if s == "@" {
- return indirectPtr(data, numStars)
- }
- for _, elem := range strings.Split(s, ".") {
- // Look up field; data must be a struct or map.
- data = t.lookup(st, data, elem)
- if !data.IsValid() {
- return reflect.Value{}
- }
- }
- return indirectPtr(data, numStars)
-}
-
-// Is there no data to look at?
-func empty(v reflect.Value) bool {
- v = indirect(v)
- if !v.IsValid() {
- return true
- }
- switch v.Kind() {
- case reflect.Bool:
- return v.Bool() == false
- case reflect.String:
- return v.String() == ""
- case reflect.Struct:
- return false
- case reflect.Map:
- return false
- case reflect.Array:
- return v.Len() == 0
- case reflect.Slice:
- return v.Len() == 0
- }
- return false
-}
-
-// Look up a variable or method, up through the parent if necessary.
-func (t *Template) varValue(name string, st *state) reflect.Value {
- field := t.findVar(st, name)
- if !field.IsValid() {
- if st.parent == nil {
- t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
- }
- return t.varValue(name, st.parent)
- }
- return field
-}
-
-func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
- fn := t.formatter(fmt)
- if fn == nil {
- t.execError(st, v.linenum, "missing formatter %s for variable", fmt)
- }
- fn(wr, fmt, val...)
-}
-
-// Evaluate a variable, looking up through the parent if necessary.
-// If it has a formatter attached ({var|formatter}) run that too.
-func (t *Template) writeVariable(v *variableElement, st *state) {
- // Resolve field names
- val := make([]interface{}, len(v.args))
- for i, arg := range v.args {
- if name, ok := arg.(fieldName); ok {
- val[i] = t.varValue(string(name), st).Interface()
- } else {
- val[i] = arg
- }
- }
- for i, fmt := range v.fmts[:len(v.fmts)-1] {
- b := &st.buf[i&1]
- b.Reset()
- t.format(b, fmt, val, v, st)
- val = val[0:1]
- val[0] = b.Bytes()
- }
- t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
-}
-
-// Execute element i. Return next index to execute.
-func (t *Template) executeElement(i int, st *state) int {
- switch elem := t.elems[i].(type) {
- case *textElement:
- st.wr.Write(elem.text)
- return i + 1
- case *literalElement:
- st.wr.Write(elem.text)
- return i + 1
- case *variableElement:
- t.writeVariable(elem, st)
- return i + 1
- case *sectionElement:
- t.executeSection(elem, st)
- return elem.end
- case *repeatedElement:
- t.executeRepeated(elem, st)
- return elem.end
- }
- e := t.elems[i]
- t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
- return 0
-}
-
-// Execute the template.
-func (t *Template) execute(start, end int, st *state) {
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Execute a .section
-func (t *Template) executeSection(s *sectionElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(s.field, st)
- if !field.IsValid() {
- t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
- }
- st = st.clone(field)
- start, end := s.start, s.or
- if !empty(field) {
- // Execute the normal block.
- if end < 0 {
- end = s.end
- }
- } else {
- // Execute the .or block. If it's missing, do nothing.
- start, end = s.or, s.end
- if start < 0 {
- return
- }
- }
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Return the result of calling the Iter method on v, or nil.
-func iter(v reflect.Value) reflect.Value {
- for j := 0; j < v.Type().NumMethod(); j++ {
- mth := v.Type().Method(j)
- fv := v.Method(j)
- ft := fv.Type()
- // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
- if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
- continue
- }
- ct := ft.Out(0)
- if ct.Kind() != reflect.Chan ||
- ct.ChanDir()&reflect.RecvDir == 0 {
- continue
- }
- return fv.Call(nil)[0]
- }
- return reflect.Value{}
-}
-
-// Execute a .repeated section
-func (t *Template) executeRepeated(r *repeatedElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(r.field, st)
- if !field.IsValid() {
- t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
- }
- field = indirect(field)
-
- start, end := r.start, r.or
- if end < 0 {
- end = r.end
- }
- if r.altstart >= 0 {
- end = r.altstart
- }
- first := true
-
- // Code common to all the loops.
- loopBody := func(newst *state) {
- // .alternates between elements
- if !first && r.altstart >= 0 {
- for i := r.altstart; i < r.altend; {
- i = t.executeElement(i, newst)
- }
- }
- first = false
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
-
- if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
- for j := 0; j < array.Len(); j++ {
- loopBody(st.clone(array.Index(j)))
- }
- } else if m := field; m.Kind() == reflect.Map {
- for _, key := range m.MapKeys() {
- loopBody(st.clone(m.MapIndex(key)))
- }
- } else if ch := iter(field); ch.IsValid() {
- for {
- e, ok := ch.Recv()
- if !ok {
- break
- }
- loopBody(st.clone(e))
- }
- } else {
- t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
- r.field, field.Type())
- }
-
- if first {
- // Empty. Execute the .or block, once. If it's missing, do nothing.
- start, end := r.or, r.end
- if start >= 0 {
- newst := st.clone(field)
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
- return
- }
-}
-
-// A valid delimiter must contain no space and be non-empty.
-func validDelim(d []byte) bool {
- if len(d) == 0 {
- return false
- }
- for _, c := range d {
- if isSpace(c) {
- return false
- }
- }
- return true
-}
diff --git a/libgo/go/old/template/format.go b/libgo/go/old/template/format.go
deleted file mode 100644
index 9156b08081..0000000000
--- a/libgo/go/old/template/format.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Template library: default formatters
-
-package template
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-// StringFormatter formats into the default string representation.
-// It is stored under the name "str" and is the default formatter.
-// You can override the default formatter by storing your default
-// under the name "" in your custom formatter map.
-func StringFormatter(w io.Writer, format string, value ...interface{}) {
- if len(value) == 1 {
- if b, ok := value[0].([]byte); ok {
- w.Write(b)
- return
- }
- }
- fmt.Fprint(w, value...)
-}
-
-var (
- esc_quot = []byte("&#34;") // shorter than "&quot;"
- esc_apos = []byte("&#39;") // shorter than "&apos;"
- esc_amp = []byte("&amp;")
- esc_lt = []byte("&lt;")
- esc_gt = []byte("&gt;")
-)
-
-// HTMLEscape writes to w the properly escaped HTML equivalent
-// of the plain text data s.
-func HTMLEscape(w io.Writer, s []byte) {
- var esc []byte
- last := 0
- for i, c := range s {
- switch c {
- case '"':
- esc = esc_quot
- case '\'':
- esc = esc_apos
- case '&':
- esc = esc_amp
- case '<':
- esc = esc_lt
- case '>':
- esc = esc_gt
- default:
- continue
- }
- w.Write(s[last:i])
- w.Write(esc)
- last = i + 1
- }
- w.Write(s[last:])
-}
-
-// HTMLFormatter formats arbitrary values for HTML
-func HTMLFormatter(w io.Writer, format string, value ...interface{}) {
- ok := false
- var b []byte
- if len(value) == 1 {
- b, ok = value[0].([]byte)
- }
- if !ok {
- var buf bytes.Buffer
- fmt.Fprint(&buf, value...)
- b = buf.Bytes()
- }
- HTMLEscape(w, b)
-}
diff --git a/libgo/go/old/template/parse.go b/libgo/go/old/template/parse.go
deleted file mode 100644
index e1bfa47249..0000000000
--- a/libgo/go/old/template/parse.go
+++ /dev/null
@@ -1,742 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Code to parse a template.
-
-package template
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-// Errors returned during parsing and execution. Users may extract the information and reformat
-// if they desire.
-type Error struct {
- Line int
- Msg string
-}
-
-func (e *Error) Error() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
-
-// checkError is a deferred function to turn a panic with type *Error into a plain error return.
-// Other panics are unexpected and so are re-enabled.
-func checkError(error *error) {
- if v := recover(); v != nil {
- if e, ok := v.(*Error); ok {
- *error = e
- } else {
- // runtime errors should crash
- panic(v)
- }
- }
-}
-
-// Most of the literals are aces.
-var lbrace = []byte{'{'}
-var rbrace = []byte{'}'}
-var space = []byte{' '}
-var tab = []byte{'\t'}
-
-// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
-const (
- tokAlternates = iota
- tokComment
- tokEnd
- tokLiteral
- tokOr
- tokRepeated
- tokSection
- tokText
- tokVariable
-)
-
-// FormatterMap is the type describing the mapping from formatter
-// names to the functions that implement them.
-type FormatterMap map[string]func(io.Writer, string, ...interface{})
-
-// Built-in formatters.
-var builtins = FormatterMap{
- "html": HTMLFormatter,
- "str": StringFormatter,
- "": StringFormatter,
-}
-
-// The parsed state of a template is a vector of xxxElement structs.
-// Sections have line numbers so errors can be reported better during execution.
-
-// Plain text.
-type textElement struct {
- text []byte
-}
-
-// A literal such as .meta-left or .meta-right
-type literalElement struct {
- text []byte
-}
-
-// A variable invocation to be evaluated
-type variableElement struct {
- linenum int
- args []interface{} // The fields and literals in the invocation.
- fmts []string // Names of formatters to apply. len(fmts) > 0
-}
-
-// A variableElement arg to be evaluated as a field name
-type fieldName string
-
-// A .section block, possibly with a .or
-type sectionElement struct {
- linenum int // of .section itself
- field string // cursor field for this block
- start int // first element
- or int // first element of .or block
- end int // one beyond last element
-}
-
-// A .repeated block, possibly with a .or and a .alternates
-type repeatedElement struct {
- sectionElement // It has the same structure...
- altstart int // ... except for alternates
- altend int
-}
-
-// Template is the type that represents a template definition.
-// It is unchanged after parsing.
-type Template struct {
- fmap FormatterMap // formatters for variables
- // Used during parsing:
- ldelim, rdelim []byte // delimiters; default {}
- buf []byte // input text to process
- p int // position in buf
- linenum int // position in input
- // Parsed results:
- elems []interface{}
-}
-
-// New creates a new template with the specified formatter map (which
-// may be nil) to define auxiliary functions for formatting variables.
-func New(fmap FormatterMap) *Template {
- t := new(Template)
- t.fmap = fmap
- t.ldelim = lbrace
- t.rdelim = rbrace
- t.elems = make([]interface{}, 0, 16)
- return t
-}
-
-// Report error and stop executing. The line number must be provided explicitly.
-func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
- panic(&Error{line, fmt.Sprintf(err, args...)})
-}
-
-// Report error, panic to terminate parsing.
-// The line number comes from the template state.
-func (t *Template) parseError(err string, args ...interface{}) {
- panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
-}
-
-// Is this an exported - upper case - name?
-func isExported(name string) bool {
- r, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(r)
-}
-
-// -- Lexical analysis
-
-// Is c a space character?
-func isSpace(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
-
-// Safely, does s[n:n+len(t)] == t?
-func equal(s []byte, n int, t []byte) bool {
- b := s[n:]
- if len(t) > len(b) { // not enough space left for a match.
- return false
- }
- for i, c := range t {
- if c != b[i] {
- return false
- }
- }
- return true
-}
-
-// isQuote returns true if c is a string- or character-delimiting quote character.
-func isQuote(c byte) bool {
- return c == '"' || c == '`' || c == '\''
-}
-
-// endQuote returns the end quote index for the quoted string that
-// starts at n, or -1 if no matching end quote is found before the end
-// of the line.
-func endQuote(s []byte, n int) int {
- quote := s[n]
- for n++; n < len(s); n++ {
- switch s[n] {
- case '\\':
- if quote == '"' || quote == '\'' {
- n++
- }
- case '\n':
- return -1
- case quote:
- return n
- }
- }
- return -1
-}
-
-// nextItem returns the next item from the input buffer. If the returned
-// item is empty, we are at EOF. The item will be either a
-// delimited string or a non-empty string between delimited
-// strings. Tokens stop at (but include, if plain text) a newline.
-// Action tokens on a line by themselves drop any space on
-// either side, up to and including the newline.
-func (t *Template) nextItem() []byte {
- startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
- start := t.p
- var i int
- newline := func() {
- t.linenum++
- i++
- }
- // Leading space up to but not including newline
- for i = start; i < len(t.buf); i++ {
- if t.buf[i] == '\n' || !isSpace(t.buf[i]) {
- break
- }
- }
- leadingSpace := i > start
- // What's left is nothing, newline, delimited string, or plain text
- switch {
- case i == len(t.buf):
- // EOF; nothing to do
- case t.buf[i] == '\n':
- newline()
- case equal(t.buf, i, t.ldelim):
- left := i // Start of left delimiter.
- right := -1 // Will be (immediately after) right delimiter.
- haveText := false // Delimiters contain text.
- i += len(t.ldelim)
- // Find the end of the action.
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- break
- }
- if isQuote(t.buf[i]) {
- i = endQuote(t.buf, i)
- if i == -1 {
- t.parseError("unmatched quote")
- return nil
- }
- continue
- }
- if equal(t.buf, i, t.rdelim) {
- i += len(t.rdelim)
- right = i
- break
- }
- haveText = true
- }
- if right < 0 {
- t.parseError("unmatched opening delimiter")
- return nil
- }
- // Is this a special action (starts with '.' or '#') and the only thing on the line?
- if startOfLine && haveText {
- firstChar := t.buf[left+len(t.ldelim)]
- if firstChar == '.' || firstChar == '#' {
- // It's special and the first thing on the line. Is it the last?
- for j := right; j < len(t.buf) && isSpace(t.buf[j]); j++ {
- if t.buf[j] == '\n' {
- // Yes it is. Drop the surrounding space and return the {.foo}
- t.linenum++
- t.p = j + 1
- return t.buf[left:right]
- }
- }
- }
- }
- // No it's not. If there's leading space, return that.
- if leadingSpace {
- // not trimming space: return leading space if there is some.
- t.p = left
- return t.buf[start:left]
- }
- // Return the word, leave the trailing space.
- start = left
- break
- default:
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- newline()
- break
- }
- if equal(t.buf, i, t.ldelim) {
- break
- }
- }
- }
- item := t.buf[start:i]
- t.p = i
- return item
-}
-
-// Turn a byte array into a space-split array of strings,
-// taking into account quoted strings.
-func words(buf []byte) []string {
- s := make([]string, 0, 5)
- for i := 0; i < len(buf); {
- // One word per loop
- for i < len(buf) && isSpace(buf[i]) {
- i++
- }
- if i == len(buf) {
- break
- }
- // Got a word
- start := i
- if isQuote(buf[i]) {
- i = endQuote(buf, i)
- if i < 0 {
- i = len(buf)
- } else {
- i++
- }
- }
- // Even with quotes, break on space only. This handles input
- // such as {""|} and catches quoting mistakes.
- for i < len(buf) && !isSpace(buf[i]) {
- i++
- }
- s = append(s, string(buf[start:i]))
- }
- return s
-}
-
-// Analyze an item and return its token type and, if it's an action item, an array of
-// its constituent words.
-func (t *Template) analyze(item []byte) (tok int, w []string) {
- // item is known to be non-empty
- if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
- tok = tokText
- return
- }
- if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
- t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
- return
- }
- if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
- t.parseError("empty directive")
- return
- }
- // Comment
- if item[len(t.ldelim)] == '#' {
- tok = tokComment
- return
- }
- // Split into words
- w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
- if len(w) == 0 {
- t.parseError("empty directive")
- return
- }
- first := w[0]
- if first[0] != '.' {
- tok = tokVariable
- return
- }
- if len(first) > 1 && first[1] >= '0' && first[1] <= '9' {
- // Must be a float.
- tok = tokVariable
- return
- }
- switch first {
- case ".meta-left", ".meta-right", ".space", ".tab":
- tok = tokLiteral
- return
- case ".or":
- tok = tokOr
- return
- case ".end":
- tok = tokEnd
- return
- case ".section":
- if len(w) != 2 {
- t.parseError("incorrect fields for .section: %s", item)
- return
- }
- tok = tokSection
- return
- case ".repeated":
- if len(w) != 3 || w[1] != "section" {
- t.parseError("incorrect fields for .repeated: %s", item)
- return
- }
- tok = tokRepeated
- return
- case ".alternates":
- if len(w) != 2 || w[1] != "with" {
- t.parseError("incorrect fields for .alternates: %s", item)
- return
- }
- tok = tokAlternates
- return
- }
- t.parseError("bad directive: %s", item)
- return
-}
-
-// formatter returns the Formatter with the given name in the Template, or nil if none exists.
-func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
- if t.fmap != nil {
- if fn := t.fmap[name]; fn != nil {
- return fn
- }
- }
- return builtins[name]
-}
-
-// -- Parsing
-
-// newVariable allocates a new variable-evaluation element.
-func (t *Template) newVariable(words []string) *variableElement {
- formatters := extractFormatters(words)
- args := make([]interface{}, len(words))
-
- // Build argument list, processing any literals
- for i, word := range words {
- var lerr error
- switch word[0] {
- case '"', '`', '\'':
- v, err := strconv.Unquote(word)
- if err == nil && word[0] == '\'' {
- args[i], _ = utf8.DecodeRuneInString(v)
- } else {
- args[i], lerr = v, err
- }
-
- case '.', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- v, err := strconv.ParseInt(word, 0, 64)
- if err == nil {
- args[i] = v
- } else {
- v, err := strconv.ParseFloat(word, 64)
- args[i], lerr = v, err
- }
-
- default:
- args[i] = fieldName(word)
- }
- if lerr != nil {
- t.parseError("invalid literal: %q: %s", word, lerr)
- }
- }
-
- // We could remember the function address here and avoid the lookup later,
- // but it's more dynamic to let the user change the map contents underfoot.
- // We do require the name to be present, though.
-
- // Is it in user-supplied map?
- for _, f := range formatters {
- if t.formatter(f) == nil {
- t.parseError("unknown formatter: %q", f)
- }
- }
-
- return &variableElement{t.linenum, args, formatters}
-}
-
-// extractFormatters extracts a list of formatters from words.
-// After the final space-separated argument in a variable, formatters may be
-// specified separated by pipe symbols. For example: {a b c|d|e}
-// The words parameter still has the formatters joined by '|' in the last word.
-// extractFormatters splits formatters, replaces the last word with the content
-// found before the first '|' within it, and returns the formatters obtained.
-// If no formatters are found in words, the default formatter is returned.
-func extractFormatters(words []string) (formatters []string) {
- // "" is the default formatter.
- formatters = []string{""}
- if len(words) == 0 {
- return
- }
- var bar int
- lastWord := words[len(words)-1]
- if isQuote(lastWord[0]) {
- end := endQuote([]byte(lastWord), 0)
- if end < 0 || end+1 == len(lastWord) || lastWord[end+1] != '|' {
- return
- }
- bar = end + 1
- } else {
- bar = strings.IndexRune(lastWord, '|')
- if bar < 0 {
- return
- }
- }
- words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|")
- return
-}
-
-// Grab the next item. If it's simple, just append it to the template.
-// Otherwise return its details.
-func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
- tok, w = t.analyze(item)
- done = true // assume for simplicity
- switch tok {
- case tokComment:
- return
- case tokText:
- t.elems = append(t.elems, &textElement{item})
- return
- case tokLiteral:
- switch w[0] {
- case ".meta-left":
- t.elems = append(t.elems, &literalElement{t.ldelim})
- case ".meta-right":
- t.elems = append(t.elems, &literalElement{t.rdelim})
- case ".space":
- t.elems = append(t.elems, &literalElement{space})
- case ".tab":
- t.elems = append(t.elems, &literalElement{tab})
- default:
- t.parseError("internal error: unknown literal: %s", w[0])
- }
- return
- case tokVariable:
- t.elems = append(t.elems, t.newVariable(w))
- return
- }
- return false, tok, w
-}
-
-// parseRepeated and parseSection are mutually recursive
-
-func (t *Template) parseRepeated(words []string) *repeatedElement {
- r := new(repeatedElement)
- t.elems = append(t.elems, r)
- r.linenum = t.linenum
- r.field = words[2]
- // Scan section, collecting true and false (.or) blocks.
- r.start = len(t.elems)
- r.or = -1
- r.altstart = -1
- r.altend = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .repeated section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if r.or >= 0 {
- t.parseError("extra .or in .repeated section")
- break Loop
- }
- r.altend = len(t.elems)
- r.or = len(t.elems)
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- if r.altstart >= 0 {
- t.parseError("extra .alternates in .repeated section")
- break Loop
- }
- if r.or >= 0 {
- t.parseError(".alternates inside .or block in .repeated section")
- break Loop
- }
- r.altstart = len(t.elems)
- default:
- t.parseError("internal error: unknown repeated section item: %s", item)
- break Loop
- }
- }
- if r.altend < 0 {
- r.altend = len(t.elems)
- }
- r.end = len(t.elems)
- return r
-}
-
-func (t *Template) parseSection(words []string) *sectionElement {
- s := new(sectionElement)
- t.elems = append(t.elems, s)
- s.linenum = t.linenum
- s.field = words[1]
- // Scan section, collecting true and false (.or) blocks.
- s.start = len(t.elems)
- s.or = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if s.or >= 0 {
- t.parseError("extra .or in .section")
- break Loop
- }
- s.or = len(t.elems)
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- t.parseError(".alternates not in .repeated")
- default:
- t.parseError("internal error: unknown section item: %s", item)
- }
- }
- s.end = len(t.elems)
- return s
-}
-
-func (t *Template) parse() {
- for {
- item := t.nextItem()
- if len(item) == 0 {
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokOr, tokEnd, tokAlternates:
- t.parseError("unexpected %s", w[0])
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- default:
- t.parseError("internal error: bad directive in parse: %s", item)
- }
- }
-}
-
-// -- Execution
-
-// -- Public interface
-
-// Parse initializes a Template by parsing its definition. The string
-// s contains the template text. If any errors occur, Parse returns
-// the error.
-func (t *Template) Parse(s string) (err error) {
- if t.elems == nil {
- return &Error{1, "template not allocated with New"}
- }
- if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
- return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
- }
- defer checkError(&err)
- t.buf = []byte(s)
- t.p = 0
- t.linenum = 1
- t.parse()
- return nil
-}
-
-// ParseFile is like Parse but reads the template definition from the
-// named file.
-func (t *Template) ParseFile(filename string) (err error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return t.Parse(string(b))
-}
-
-// Execute applies a parsed template to the specified data object,
-// generating output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
- // Extract the driver data.
- val := reflect.ValueOf(data)
- defer checkError(&err)
- t.p = 0
- t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
- return nil
-}
-
-// SetDelims sets the left and right delimiters for operations in the
-// template. They are validated during parsing. They could be
-// validated here but it's better to keep the routine simple. The
-// delimiters are very rarely invalid and Parse has the necessary
-// error-handling interface already.
-func (t *Template) SetDelims(left, right string) {
- t.ldelim = []byte(left)
- t.rdelim = []byte(right)
-}
-
-// Parse creates a Template with default parameters (such as {} for
-// metacharacters). The string s contains the template text while
-// the formatter map fmap, which may be nil, defines auxiliary functions
-// for formatting variables. The template is returned. If any errors
-// occur, err will be non-nil.
-func Parse(s string, fmap FormatterMap) (t *Template, err error) {
- t = New(fmap)
- err = t.Parse(s)
- if err != nil {
- t = nil
- }
- return
-}
-
-// ParseFile is a wrapper function that creates a Template with default
-// parameters (such as {} for metacharacters). The filename identifies
-// a file containing the template text, while the formatter map fmap, which
-// may be nil, defines auxiliary functions for formatting variables.
-// The template is returned. If any errors occur, err will be non-nil.
-func ParseFile(filename string, fmap FormatterMap) (t *Template, err error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return Parse(string(b), fmap)
-}
-
-// MustParse is like Parse but panics if the template cannot be parsed.
-func MustParse(s string, fmap FormatterMap) *Template {
- t, err := Parse(s, fmap)
- if err != nil {
- panic("template.MustParse error: " + err.Error())
- }
- return t
-}
-
-// MustParseFile is like ParseFile but panics if the file cannot be read
-// or the template cannot be parsed.
-func MustParseFile(filename string, fmap FormatterMap) *Template {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- panic("template.MustParseFile error: " + err.Error())
- }
- return MustParse(string(b), fmap)
-}
diff --git a/libgo/go/old/template/template_test.go b/libgo/go/old/template/template_test.go
deleted file mode 100644
index 854a548e5a..0000000000
--- a/libgo/go/old/template/template_test.go
+++ /dev/null
@@ -1,810 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package template
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "testing"
-)
-
-type Test struct {
- in, out, err string
-}
-
-type T struct {
- Item string
- Value string
-}
-
-type U struct {
- Mp map[string]int
-}
-
-type S struct {
- Header string
- HeaderPtr *string
- Integer int
- IntegerPtr *int
- NilPtr *int
- InnerT T
- InnerPointerT *T
- Data []T
- Pdata []*T
- Empty []*T
- Emptystring string
- Null []*T
- Vec []interface{}
- True bool
- False bool
- Mp map[string]string
- JSON interface{}
- Innermap U
- Stringmap map[string]string
- Ptrmap map[string]*string
- Iface interface{}
- Ifaceptr interface{}
-}
-
-func (s *S) PointerMethod() string { return "ptrmethod!" }
-
-func (s S) ValueMethod() string { return "valmethod!" }
-
-var t1 = T{"ItemNumber1", "ValueNumber1"}
-var t2 = T{"ItemNumber2", "ValueNumber2"}
-
-func uppercase(v interface{}) string {
- s := v.(string)
- t := ""
- for i := 0; i < len(s); i++ {
- c := s[i]
- if 'a' <= c && c <= 'z' {
- c = c + 'A' - 'a'
- }
- t += string(c)
- }
- return t
-}
-
-func plus1(v interface{}) string {
- i := v.(int)
- return fmt.Sprint(i + 1)
-}
-
-func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
- return func(w io.Writer, format string, v ...interface{}) {
- if len(v) != 1 {
- panic("test writer expected one arg")
- }
- io.WriteString(w, f(v[0]))
- }
-}
-
-func multiword(w io.Writer, format string, value ...interface{}) {
- for _, v := range value {
- fmt.Fprintf(w, "<%v>", v)
- }
-}
-
-func printf(w io.Writer, format string, v ...interface{}) {
- io.WriteString(w, fmt.Sprintf(v[0].(string), v[1:]...))
-}
-
-var formatters = FormatterMap{
- "uppercase": writer(uppercase),
- "+1": writer(plus1),
- "multiword": multiword,
- "printf": printf,
-}
-
-var tests = []*Test{
- // Simple
- {"", "", ""},
- {"abc", "abc", ""},
- {"abc\ndef\n", "abc\ndef\n", ""},
- {" {.meta-left} \n", "{", ""},
- {" {.meta-right} \n", "}", ""},
- {" {.space} \n", " ", ""},
- {" {.tab} \n", "\t", ""},
- {" {#comment} \n", "", ""},
- {"\tSome Text\t\n", "\tSome Text\t\n", ""},
- {" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
-
- // Variables at top level
- {
- in: "{Header}={Integer}\n",
-
- out: "Header=77\n",
- },
-
- {
- in: "Pointers: {*HeaderPtr}={*IntegerPtr}\n",
-
- out: "Pointers: Header=77\n",
- },
-
- {
- in: "Stars but not pointers: {*Header}={*Integer}\n",
-
- out: "Stars but not pointers: Header=77\n",
- },
-
- {
- in: "nil pointer: {*NilPtr}={*Integer}\n",
-
- out: "nil pointer: <nil>=77\n",
- },
-
- {
- in: `{"Strings" ":"} {""} {"|"} {"\t\u0123 \x23\\"} {"\"}{\\"}`,
-
- out: "Strings: | \t\u0123 \x23\\ \"}{\\",
- },
-
- {
- in: "{`Raw strings` `:`} {``} {`|`} {`\\t\\u0123 \\x23\\`} {`}{\\`}",
-
- out: "Raw strings: | \\t\\u0123 \\x23\\ }{\\",
- },
-
- {
- in: "Characters: {'a'} {'\\u0123'} {' '} {'{'} {'|'} {'}'}",
-
- out: "Characters: 97 291 32 123 124 125",
- },
-
- {
- in: "Integers: {1} {-2} {+42} {0777} {0x0a}",
-
- out: "Integers: 1 -2 42 511 10",
- },
-
- {
- in: "Floats: {.5} {-.5} {1.1} {-2.2} {+42.1} {1e10} {1.2e-3} {1.2e3} {-1.2e3}",
-
- out: "Floats: 0.5 -0.5 1.1 -2.2 42.1 1e+10 0.0012 1200 -1200",
- },
-
- // Method at top level
- {
- in: "ptrmethod={PointerMethod}\n",
-
- out: "ptrmethod=ptrmethod!\n",
- },
-
- {
- in: "valmethod={ValueMethod}\n",
-
- out: "valmethod=valmethod!\n",
- },
-
- // Section
- {
- in: "{.section Data }\n" +
- "some text for the section\n" +
- "{.end}\n",
-
- out: "some text for the section\n",
- },
- {
- in: "{.section Data }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n",
-
- out: "Header=77\n",
- },
- {
- in: "{.section Pdata }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n",
-
- out: "Header=77\n",
- },
- {
- in: "{.section Pdata }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data present\n",
- },
- {
- in: "{.section Empty }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data not present\n",
- },
- {
- in: "{.section Null }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data not present\n",
- },
- {
- in: "{.section Pdata }\n" +
- "{Header}={Integer}\n" +
- "{.section @ }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "Header=77\n" +
- "Header=77\n",
- },
-
- {
- in: "{.section Data}{.end} {Header}\n",
-
- out: " Header\n",
- },
-
- {
- in: "{.section Integer}{@}{.end}",
-
- out: "77",
- },
-
- // Repeated
- {
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- {
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.or}\n" +
- "this should not appear\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- {
- in: "{.section @ }\n" +
- "{.repeated section Empty }\n" +
- "{Item}={Value}\n" +
- "{.or}\n" +
- "this should appear: empty field\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "this should appear: empty field\n",
- },
- {
- in: "{.repeated section Pdata }\n" +
- "{Item}\n" +
- "{.alternates with}\n" +
- "is\nover\nmultiple\nlines\n" +
- "{.end}\n",
-
- out: "ItemNumber1\n" +
- "is\nover\nmultiple\nlines\n" +
- "ItemNumber2\n",
- },
- {
- in: "{.repeated section Pdata }\n" +
- "{Item}\n" +
- "{.alternates with}\n" +
- "is\nover\nmultiple\nlines\n" +
- " {.end}\n",
-
- out: "ItemNumber1\n" +
- "is\nover\nmultiple\nlines\n" +
- "ItemNumber2\n",
- },
- {
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.alternates with}DIVIDER\n" +
- "{.or}\n" +
- "this should not appear\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "DIVIDER\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- {
- in: "{.repeated section Vec }\n" +
- "{@}\n" +
- "{.end}\n",
-
- out: "elt1\n" +
- "elt2\n",
- },
- // Same but with a space before {.end}: was a bug.
- {
- in: "{.repeated section Vec }\n" +
- "{@} {.end}\n",
-
- out: "elt1 elt2 \n",
- },
- {
- in: "{.repeated section Integer}{.end}",
-
- err: "line 1: .repeated: cannot repeat Integer (type int)",
- },
-
- // Nested names
- {
- in: "{.section @ }\n" +
- "{InnerT.Item}={InnerT.Value}\n" +
- "{.end}",
-
- out: "ItemNumber1=ValueNumber1\n",
- },
- {
- in: "{.section @ }\n" +
- "{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
- "{.end}",
-
- out: "ItemNumber1=ValueNumber1\n",
- },
-
- {
- in: "{.section Emptystring}emptystring{.end}\n" +
- "{.section Header}header{.end}\n",
-
- out: "\nheader\n",
- },
-
- {
- in: "{.section True}1{.or}2{.end}\n" +
- "{.section False}3{.or}4{.end}\n",
-
- out: "1\n4\n",
- },
-
- // Maps
-
- {
- in: "{Mp.mapkey}\n",
-
- out: "Ahoy!\n",
- },
- {
- in: "{Innermap.Mp.innerkey}\n",
-
- out: "55\n",
- },
- {
- in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
-
- out: "55\n",
- },
- {
- in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
-
- out: "1234\n",
- },
- {
- in: "{Stringmap.stringkey1}\n",
-
- out: "stringresult\n",
- },
- {
- in: "{.repeated section Stringmap}\n" +
- "{@}\n" +
- "{.end}",
-
- out: "stringresult\n" +
- "stringresult\n",
- },
- {
- in: "{.repeated section Stringmap}\n" +
- "\t{@}\n" +
- "{.end}",
-
- out: "\tstringresult\n" +
- "\tstringresult\n",
- },
- {
- in: "{*Ptrmap.stringkey1}\n",
-
- out: "pointedToString\n",
- },
- {
- in: "{.repeated section Ptrmap}\n" +
- "{*@}\n" +
- "{.end}",
-
- out: "pointedToString\n" +
- "pointedToString\n",
- },
-
- // Interface values
-
- {
- in: "{Iface}",
-
- out: "[1 2 3]",
- },
- {
- in: "{.repeated section Iface}{@}{.alternates with} {.end}",
-
- out: "1 2 3",
- },
- {
- in: "{.section Iface}{@}{.end}",
-
- out: "[1 2 3]",
- },
- {
- in: "{.section Ifaceptr}{Item} {Value}{.end}",
-
- out: "Item Value",
- },
-}
-
-func TestAll(t *testing.T) {
- // Parse
- testAll(t, func(test *Test) (*Template, error) { return Parse(test.in, formatters) })
- // ParseFile
- f, err := ioutil.TempFile("", "template-test")
- if err != nil {
- t.Fatal(err)
- }
- defer func() {
- name := f.Name()
- f.Close()
- os.Remove(name)
- }()
- testAll(t, func(test *Test) (*Template, error) {
- err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
- if err != nil {
- t.Error("unexpected write error:", err)
- return nil, err
- }
- return ParseFile(f.Name(), formatters)
- })
- // tmpl.ParseFile
- testAll(t, func(test *Test) (*Template, error) {
- err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
- if err != nil {
- t.Error("unexpected write error:", err)
- return nil, err
- }
- tmpl := New(formatters)
- return tmpl, tmpl.ParseFile(f.Name())
- })
-}
-
-func testAll(t *testing.T, parseFunc func(*Test) (*Template, error)) {
- s := new(S)
- // initialized by hand for clarity.
- s.Header = "Header"
- s.HeaderPtr = &s.Header
- s.Integer = 77
- s.IntegerPtr = &s.Integer
- s.InnerT = t1
- s.Data = []T{t1, t2}
- s.Pdata = []*T{&t1, &t2}
- s.Empty = []*T{}
- s.Null = nil
- s.Vec = []interface{}{"elt1", "elt2"}
- s.True = true
- s.False = false
- s.Mp = make(map[string]string)
- s.Mp["mapkey"] = "Ahoy!"
- json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON)
- s.Innermap.Mp = make(map[string]int)
- s.Innermap.Mp["innerkey"] = 55
- s.Stringmap = make(map[string]string)
- s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
- s.Stringmap["stringkey2"] = "stringresult"
- s.Ptrmap = make(map[string]*string)
- x := "pointedToString"
- s.Ptrmap["stringkey1"] = &x // the same value so repeated section is order-independent
- s.Ptrmap["stringkey2"] = &x
- s.Iface = []int{1, 2, 3}
- s.Ifaceptr = &T{"Item", "Value"}
-
- var buf bytes.Buffer
- for _, test := range tests {
- buf.Reset()
- tmpl, err := parseFunc(test)
- if err != nil {
- t.Error("unexpected parse error: ", err)
- continue
- }
- err = tmpl.Execute(&buf, s)
- if test.err == "" {
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- } else {
- if err == nil {
- t.Errorf("expected execute error %q, got nil", test.err)
- } else if err.Error() != test.err {
- t.Errorf("expected execute error %q, got %q", test.err, err.Error())
- }
- }
- if buf.String() != test.out {
- t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
- }
- }
-}
-
-func TestMapDriverType(t *testing.T) {
- mp := map[string]string{"footer": "Ahoy!"}
- tmpl, err := Parse("template: {footer}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, mp)
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: Ahoy!"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestMapNoEntry(t *testing.T) {
- mp := make(map[string]int)
- tmpl, err := Parse("template: {notthere}!", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, mp)
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: 0!"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestStringDriverType(t *testing.T) {
- tmpl, err := Parse("template: {@}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: hello"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestTwice(t *testing.T) {
- tmpl, err := Parse("template: {@}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- s := b.String()
- expect := "template: hello"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- s = b.String()
- expect += expect
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestCustomDelims(t *testing.T) {
- // try various lengths. zero should catch error.
- for i := 0; i < 7; i++ {
- for j := 0; j < 7; j++ {
- tmpl := New(nil)
- // first two chars deliberately the same to test equal left and right delims
- ldelim := "$!#$%^&"[0:i]
- rdelim := "$*&^%$!"[0:j]
- tmpl.SetDelims(ldelim, rdelim)
- // if braces, this would be template: {@}{.meta-left}{.meta-right}
- text := "template: " +
- ldelim + "@" + rdelim +
- ldelim + ".meta-left" + rdelim +
- ldelim + ".meta-right" + rdelim
- err := tmpl.Parse(text)
- if err != nil {
- if i == 0 || j == 0 { // expected
- continue
- }
- t.Error("unexpected parse error:", err)
- } else if i == 0 || j == 0 {
- t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
- continue
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- s := b.String()
- if s != "template: hello"+ldelim+rdelim {
- t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
- }
- }
- }
-}
-
-// Test that a variable evaluates to the field itself and does not further indirection
-func TestVarIndirection(t *testing.T) {
- s := new(S)
- // initialized by hand for clarity.
- s.InnerPointerT = &t1
-
- var buf bytes.Buffer
- input := "{.section @}{InnerPointerT}{.end}"
- tmpl, err := Parse(input, nil)
- if err != nil {
- t.Fatal("unexpected parse error:", err)
- }
- err = tmpl.Execute(&buf, s)
- if err != nil {
- t.Fatal("unexpected execute error:", err)
- }
- expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
- if buf.String() != expect {
- t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
- }
-}
-
-func TestHTMLFormatterWithByte(t *testing.T) {
- s := "Test string."
- b := []byte(s)
- var buf bytes.Buffer
- HTMLFormatter(&buf, "", b)
- bs := buf.String()
- if bs != s {
- t.Errorf("munged []byte, expected: %s got: %s", s, bs)
- }
-}
-
-type UF struct {
- I int
- s string
-}
-
-func TestReferenceToUnexported(t *testing.T) {
- u := &UF{3, "hello"}
- var buf bytes.Buffer
- input := "{.section @}{I}{s}{.end}"
- tmpl, err := Parse(input, nil)
- if err != nil {
- t.Fatal("unexpected parse error:", err)
- }
- err = tmpl.Execute(&buf, u)
- if err == nil {
- t.Fatal("expected execute error, got none")
- }
- if strings.Index(err.Error(), "not exported") < 0 {
- t.Fatal("expected unexported error; got", err)
- }
-}
-
-var formatterTests = []Test{
- {
- in: "{Header|uppercase}={Integer|+1}\n" +
- "{Header|html}={Integer|str}\n",
-
- out: "HEADER=78\n" +
- "Header=77\n",
- },
-
- {
- in: "{Header|uppercase}={Integer Header|multiword}\n" +
- "{Header|html}={Header Integer|multiword}\n" +
- "{Header|html}={Header Integer}\n",
-
- out: "HEADER=<77><Header>\n" +
- "Header=<Header><77>\n" +
- "Header=Header77\n",
- },
- {
- in: "{Raw}\n" +
- "{Raw|html}\n",
-
- out: "a <&> b\n" +
- "a &lt;&amp;&gt; b\n",
- },
- {
- in: "{Bytes}",
- out: "hello",
- },
- {
- in: "{Raw|uppercase|html|html}",
- out: "A &amp;lt;&amp;amp;&amp;gt; B",
- },
- {
- in: "{Header Integer|multiword|html}",
- out: "&lt;Header&gt;&lt;77&gt;",
- },
- {
- in: "{Integer|no_formatter|html}",
- err: `unknown formatter: "no_formatter"`,
- },
- {
- in: "{Integer|||||}", // empty string is a valid formatter
- out: "77",
- },
- {
- in: `{"%.02f 0x%02X" 1.1 10|printf}`,
- out: "1.10 0x0A",
- },
- {
- in: `{""|}{""||}{""|printf}`, // Issue #1896.
- out: "",
- },
-}
-
-func TestFormatters(t *testing.T) {
- data := map[string]interface{}{
- "Header": "Header",
- "Integer": 77,
- "Raw": "a <&> b",
- "Bytes": []byte("hello"),
- }
- for _, c := range formatterTests {
- tmpl, err := Parse(c.in, formatters)
- if err != nil {
- if c.err == "" {
- t.Error("unexpected parse error:", err)
- continue
- }
- if strings.Index(err.Error(), c.err) < 0 {
- t.Errorf("unexpected error: expected %q, got %q", c.err, err.Error())
- continue
- }
- } else {
- if c.err != "" {
- t.Errorf("For %q, expected error, got none.", c.in)
- continue
- }
- var buf bytes.Buffer
- err = tmpl.Execute(&buf, data)
- if err != nil {
- t.Error("unexpected Execute error: ", err)
- continue
- }
- actual := buf.String()
- if actual != c.out {
- t.Errorf("for %q: expected %q but got %q.", c.in, c.out, actual)
- }
- }
- }
-}
diff --git a/libgo/go/os/dir.go b/libgo/go/os/dir.go
index d811c9fdd8..6c54456a21 100644
--- a/libgo/go/os/dir.go
+++ b/libgo/go/os/dir.go
@@ -1,102 +1,46 @@
-// 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 os
-import (
- "io"
- "sync/atomic"
- "syscall"
- "unsafe"
-)
-
-//extern opendir
-func libc_opendir(*byte) *syscall.DIR
-
-//extern closedir
-func libc_closedir(*syscall.DIR) int
-
-// FIXME: pathconf returns long, not int.
-//extern pathconf
-func libc_pathconf(*byte, int) int
-
-func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
- if n[i] == 0 {
- return i
- }
+// Readdir reads the contents of the directory associated with file and
+// returns a slice of up to n FileInfo values, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdir returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is io.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (f *File) Readdir(n int) ([]FileInfo, error) {
+ if f == nil {
+ return nil, ErrInvalid
}
- return len(n)
+ return f.readdir(n)
}
-var nameMax int32
-
-func (file *File) readdirnames(n int) (names []string, err error) {
- if file.dirinfo == nil {
- p, err := syscall.BytePtrFromString(file.name)
- if err != nil {
- return nil, err
- }
-
- elen := int(atomic.LoadInt32(&nameMax))
- if elen == 0 {
- syscall.Entersyscall()
- plen := libc_pathconf(p, syscall.PC_NAME_MAX)
- syscall.Exitsyscall()
- if plen < 1024 {
- plen = 1024
- }
- var dummy syscall.Dirent
- elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
- atomic.StoreInt32(&nameMax, int32(elen))
- }
-
- syscall.Entersyscall()
- r := libc_opendir(p)
- errno := syscall.GetErrno()
- syscall.Exitsyscall()
- if r == nil {
- return nil, &PathError{"opendir", file.name, errno}
- }
-
- file.dirinfo = new(dirInfo)
- file.dirinfo.buf = make([]byte, elen)
- file.dirinfo.dir = r
- }
-
- entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
-
- size := n
- if size <= 0 {
- size = 100
- n = -1
- }
-
- names = make([]string, 0, size) // Empty with room to grow.
-
- for n != 0 {
- var dirent *syscall.Dirent
- pr := &dirent
- syscall.Entersyscall()
- i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
- syscall.Exitsyscall()
- if i != 0 {
- return names, NewSyscallError("readdir_r", i)
- }
- if dirent == nil {
- break // EOF
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes[:])])
- if name == "." || name == ".." { // Useless names
- continue
- }
- names = append(names, name)
- n--
- }
- if n >= 0 && len(names) == 0 {
- return names, io.EOF
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is io.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (f *File) Readdirnames(n int) (names []string, err error) {
+ if f == nil {
+ return nil, ErrInvalid
}
- return names, nil
+ return f.readdirnames(n)
}
diff --git a/libgo/go/os/dir_gccgo.go b/libgo/go/os/dir_gccgo.go
new file mode 100644
index 0000000000..d811c9fdd8
--- /dev/null
+++ b/libgo/go/os/dir_gccgo.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "io"
+ "sync/atomic"
+ "syscall"
+ "unsafe"
+)
+
+//extern opendir
+func libc_opendir(*byte) *syscall.DIR
+
+//extern closedir
+func libc_closedir(*syscall.DIR) int
+
+// FIXME: pathconf returns long, not int.
+//extern pathconf
+func libc_pathconf(*byte, int) int
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+var nameMax int32
+
+func (file *File) readdirnames(n int) (names []string, err error) {
+ if file.dirinfo == nil {
+ p, err := syscall.BytePtrFromString(file.name)
+ if err != nil {
+ return nil, err
+ }
+
+ elen := int(atomic.LoadInt32(&nameMax))
+ if elen == 0 {
+ syscall.Entersyscall()
+ plen := libc_pathconf(p, syscall.PC_NAME_MAX)
+ syscall.Exitsyscall()
+ if plen < 1024 {
+ plen = 1024
+ }
+ var dummy syscall.Dirent
+ elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
+ atomic.StoreInt32(&nameMax, int32(elen))
+ }
+
+ syscall.Entersyscall()
+ r := libc_opendir(p)
+ errno := syscall.GetErrno()
+ syscall.Exitsyscall()
+ if r == nil {
+ return nil, &PathError{"opendir", file.name, errno}
+ }
+
+ file.dirinfo = new(dirInfo)
+ file.dirinfo.buf = make([]byte, elen)
+ file.dirinfo.dir = r
+ }
+
+ entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
+
+ size := n
+ if size <= 0 {
+ size = 100
+ n = -1
+ }
+
+ names = make([]string, 0, size) // Empty with room to grow.
+
+ for n != 0 {
+ var dirent *syscall.Dirent
+ pr := &dirent
+ syscall.Entersyscall()
+ i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
+ syscall.Exitsyscall()
+ if i != 0 {
+ return names, NewSyscallError("readdir_r", i)
+ }
+ if dirent == nil {
+ break // EOF
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ names = append(names, name)
+ n--
+ }
+ if n >= 0 && len(names) == 0 {
+ return names, io.EOF
+ }
+ return names, nil
+}
diff --git a/libgo/go/os/dir_largefile.go b/libgo/go/os/dir_largefile.go
index 2555c7ba33..28733428fd 100644
--- a/libgo/go/os/dir_largefile.go
+++ b/libgo/go/os/dir_largefile.go
@@ -5,6 +5,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux solaris,386 solaris,sparc
+
package os
import "syscall"
diff --git a/libgo/go/os/dir_regfile.go b/libgo/go/os/dir_regfile.go
index e5f7c5745d..8b17f387f1 100644
--- a/libgo/go/os/dir_regfile.go
+++ b/libgo/go/os/dir_regfile.go
@@ -5,6 +5,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !linux
+// +build !solaris !386
+// +build !solaris !sparc
+
package os
import "syscall"
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
index 589db85274..cd42f59e01 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_unix.go
@@ -8,51 +8,31 @@ package os
import (
"io"
- "syscall"
)
-const (
- blockSize = 4096
-)
-
-func (f *File) readdirnames(n int) (names []string, err error) {
- // If this file has no dirinfo, create one.
- if f.dirinfo == nil {
- f.dirinfo = new(dirInfo)
- // The buffer must be at least a block long.
- f.dirinfo.buf = make([]byte, blockSize)
- }
- d := f.dirinfo
-
- size := n
- if size <= 0 {
- size = 100
- n = -1
+func (f *File) readdir(n int) (fi []FileInfo, err error) {
+ dirname := f.name
+ if dirname == "" {
+ dirname = "."
}
-
- names = make([]string, 0, size) // Empty with room to grow.
- for n != 0 {
- // Refill the buffer if necessary
- if d.bufp >= d.nbuf {
- d.bufp = 0
- var errno error
- d.nbuf, errno = fixCount(syscall.ReadDirent(f.fd, d.buf))
- if errno != nil {
- return names, NewSyscallError("readdirent", errno)
- }
- if d.nbuf <= 0 {
- break // EOF
- }
+ names, err := f.Readdirnames(n)
+ fi = make([]FileInfo, 0, len(names))
+ for _, filename := range names {
+ fip, lerr := lstat(dirname + "/" + filename)
+ if IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
+ continue
}
-
- // Drain the buffer
- var nb, nc int
- nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names)
- d.bufp += nb
- n -= nc
+ if lerr != nil {
+ return fi, lerr
+ }
+ fi = append(fi, fip)
}
- if n >= 0 && len(names) == 0 {
- return names, io.EOF
+ if len(fi) == 0 && err == nil && n > 0 {
+ // Per File.Readdir, the slice must be non-empty or err
+ // must be non-nil if n > 0.
+ err = io.EOF
}
- return names, nil
+ return fi, err
}
diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go
deleted file mode 100644
index 869a28a8a4..0000000000
--- a/libgo/go/os/doc.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package os
-
-import "time"
-
-// FindProcess looks for a running process by its pid.
-//
-// The Process it returns can be used to obtain information
-// about the underlying operating system process.
-//
-// On Unix systems, FindProcess always succeeds and returns a Process
-// for the given pid, regardless of whether the process exists.
-func FindProcess(pid int) (*Process, error) {
- return findProcess(pid)
-}
-
-// StartProcess starts a new process with the program, arguments and attributes
-// specified by name, argv and attr.
-//
-// StartProcess is a low-level interface. The os/exec package provides
-// higher-level interfaces.
-//
-// If there is an error, it will be of type *PathError.
-func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
- return startProcess(name, argv, attr)
-}
-
-// Release releases any resources associated with the Process p,
-// rendering it unusable in the future.
-// Release only needs to be called if Wait is not.
-func (p *Process) Release() error {
- return p.release()
-}
-
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() error {
- return p.kill()
-}
-
-// Wait waits for the Process to exit, and then returns a
-// ProcessState describing its status and an error, if any.
-// Wait releases any resources associated with the Process.
-// On most operating systems, the Process must be a child
-// of the current process or an error will be returned.
-func (p *Process) Wait() (*ProcessState, error) {
- return p.wait()
-}
-
-// Signal sends a signal to the Process.
-// Sending Interrupt on Windows is not implemented.
-func (p *Process) Signal(sig Signal) error {
- return p.signal(sig)
-}
-
-// UserTime returns the user CPU time of the exited process and its children.
-func (p *ProcessState) UserTime() time.Duration {
- return p.userTime()
-}
-
-// SystemTime returns the system CPU time of the exited process and its children.
-func (p *ProcessState) SystemTime() time.Duration {
- return p.systemTime()
-}
-
-// Exited reports whether the program has exited.
-func (p *ProcessState) Exited() bool {
- return p.exited()
-}
-
-// Success reports whether the program exited successfully,
-// such as with exit status 0 on Unix.
-func (p *ProcessState) Success() bool {
- return p.success()
-}
-
-// Sys returns system-dependent exit information about
-// the process. Convert it to the appropriate underlying
-// type, such as syscall.WaitStatus on Unix, to access its contents.
-func (p *ProcessState) Sys() interface{} {
- return p.sys()
-}
-
-// SysUsage returns system-dependent resource usage information about
-// the exited process. Convert it to the appropriate underlying
-// type, such as *syscall.Rusage on Unix, to access its contents.
-// (On Unix, *syscall.Rusage matches struct rusage as defined in the
-// getrusage(2) manual page.)
-func (p *ProcessState) SysUsage() interface{} {
- return p.sysUsage()
-}
-
-// Hostname returns the host name reported by the kernel.
-func Hostname() (name string, err error) {
- return hostname()
-}
-
-// Readdir reads the contents of the directory associated with file and
-// returns a slice of up to n FileInfo values, as would be returned
-// by Lstat, in directory order. Subsequent calls on the same file will yield
-// further FileInfos.
-//
-// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
-// Readdir returns an empty slice, it will return a non-nil error
-// explaining why. At the end of a directory, the error is io.EOF.
-//
-// If n <= 0, Readdir returns all the FileInfo from the directory in
-// a single slice. In this case, if Readdir succeeds (reads all
-// the way to the end of the directory), it returns the slice and a
-// nil error. If it encounters an error before the end of the
-// directory, Readdir returns the FileInfo read until that point
-// and a non-nil error.
-func (f *File) Readdir(n int) (fi []FileInfo, err error) {
- if f == nil {
- return nil, ErrInvalid
- }
- return f.readdir(n)
-}
-
-// Readdirnames reads and returns a slice of names from the directory f.
-//
-// If n > 0, Readdirnames returns at most n names. In this case, if
-// Readdirnames returns an empty slice, it will return a non-nil error
-// explaining why. At the end of a directory, the error is io.EOF.
-//
-// If n <= 0, Readdirnames returns all the names from the directory in
-// a single slice. In this case, if Readdirnames succeeds (reads all
-// the way to the end of the directory), it returns the slice and a
-// nil error. If it encounters an error before the end of the
-// directory, Readdirnames returns the names read until that point and
-// a non-nil error.
-func (f *File) Readdirnames(n int) (names []string, err error) {
- if f == nil {
- return nil, ErrInvalid
- }
- return f.readdirnames(n)
-}
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
index a4ede15e61..a03b8f68f5 100644
--- a/libgo/go/os/env.go
+++ b/libgo/go/os/env.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -27,7 +27,7 @@ func Expand(s string, mapping func(string) string) string {
}
// ExpandEnv replaces ${var} or $var in the string according to the values
-// of the current environment variables. References to undefined
+// of the current environment variables. References to undefined
// variables are replaced by the empty string.
func ExpandEnv(s string) string {
return Expand(s, Getenv)
@@ -37,7 +37,7 @@ func ExpandEnv(s string) string {
// shell variable such as $*.
func isShellSpecialVar(c uint8) bool {
switch c {
- case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ case '*', '#', '$', '@', '!', '?', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
@@ -49,7 +49,7 @@ func isAlphaNum(c uint8) bool {
}
// getShellName returns the name that begins the string and the number of bytes
-// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
+// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
// expansion and two more bytes are needed than the length of the name.
func getShellName(s string) (string, int) {
switch {
@@ -76,6 +76,7 @@ func getShellName(s string) (string, int) {
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
+// To distinguish between an empty value and an unset value, use LookupEnv.
func Getenv(key string) string {
v, _ := syscall.Getenv(key)
return v
diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go
index d1074cdc60..e5749f0e89 100644
--- a/libgo/go/os/env_test.go
+++ b/libgo/go/os/env_test.go
@@ -95,6 +95,34 @@ func TestUnsetenv(t *testing.T) {
}
}
+func TestClearenv(t *testing.T) {
+ const testKey = "GO_TEST_CLEARENV"
+ const testValue = "1"
+
+ // reset env
+ defer func(origEnv []string) {
+ for _, pair := range origEnv {
+ // Environment variables on Windows can begin with =
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ i := strings.Index(pair[1:], "=") + 1
+ if err := Setenv(pair[:i], pair[i+1:]); err != nil {
+ t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)
+ }
+ }
+ }(Environ())
+
+ if err := Setenv(testKey, testValue); err != nil {
+ t.Fatalf("Setenv(%q, %q) failed: %v", testKey, testValue, err)
+ }
+ if _, ok := LookupEnv(testKey); !ok {
+ t.Errorf("Setenv(%q, %q) didn't set $%s", testKey, testValue, testKey)
+ }
+ Clearenv()
+ if val, ok := LookupEnv(testKey); ok {
+ t.Errorf("Clearenv() didn't clear $%s, remained with value %q", testKey, val)
+ }
+}
+
func TestLookupEnv(t *testing.T) {
const smallpox = "SMALLPOX" // No one has smallpox.
value, ok := LookupEnv(smallpox) // Should not exist.
diff --git a/libgo/go/os/env_unix_test.go b/libgo/go/os/env_unix_test.go
index 5ec07ee1b1..f7b67ebbb8 100644
--- a/libgo/go/os/env_unix_test.go
+++ b/libgo/go/os/env_unix_test.go
@@ -7,6 +7,7 @@
package os_test
import (
+ "fmt"
. "os"
"testing"
)
@@ -28,3 +29,28 @@ func TestSetenvUnixEinval(t *testing.T) {
}
}
}
+
+var shellSpecialVarTests = []struct {
+ k, v string
+}{
+ {"*", "asterisk"},
+ {"#", "pound"},
+ {"$", "dollar"},
+ {"@", "at"},
+ {"!", "exclamation mark"},
+ {"?", "question mark"},
+ {"-", "dash"},
+}
+
+func TestExpandEnvShellSpecialVar(t *testing.T) {
+ for _, tt := range shellSpecialVarTests {
+ Setenv(tt.k, tt.v)
+ defer Unsetenv(tt.k)
+
+ argRaw := fmt.Sprintf("$%s", tt.k)
+ argWithBrace := fmt.Sprintf("${%s}", tt.k)
+ if gotRaw, gotBrace := ExpandEnv(argRaw), ExpandEnv(argWithBrace); gotRaw != gotBrace {
+ t.Errorf("ExpandEnv(%q) = %q, ExpandEnv(%q) = %q; expect them to be equal", argRaw, gotRaw, argWithBrace, gotBrace)
+ }
+ }
+}
diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go
index e26ce27970..7235bfb6d6 100644
--- a/libgo/go/os/error.go
+++ b/libgo/go/os/error.go
@@ -14,6 +14,7 @@ var (
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
+ ErrClosed = errors.New("file already closed")
)
// PathError records an error and the operation and file path that caused it.
@@ -63,3 +64,16 @@ func IsNotExist(err error) bool {
func IsPermission(err error) bool {
return isPermission(err)
}
+
+// underlyingError returns the underlying error for known os error types.
+func underlyingError(err error) error {
+ switch err := err.(type) {
+ case *PathError:
+ return err.Err
+ case *LinkError:
+ return err.Err
+ case *SyscallError:
+ return err.Err
+ }
+ return err
+}
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index 2dc6b39c39..a67343981e 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -5,46 +5,30 @@
package os
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
- return contains(err.Error(), " exists")
+ return checkErrMessageContent(err, " exists")
}
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
- return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
- contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
+ return checkErrMessageContent(err, "does not exist", "not found",
+ "has been removed", "no parent")
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
+ return checkErrMessageContent(err, "permission denied")
+}
+
+// checkErrMessageContent checks if err message contains one of msgs.
+func checkErrMessageContent(err error, msgs ...string) bool {
+ if err == nil {
return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
}
- return contains(err.Error(), "permission denied")
+ err = underlyingError(err)
+ for _, msg := range msgs {
+ if contains(err.Error(), msg) {
+ return true
+ }
+ }
+ return false
}
// contains is a local version of strings.Contains. It knows len(sep) > 1.
diff --git a/libgo/go/os/error_test.go b/libgo/go/os/error_test.go
index 5477e7ecbd..3499ceec95 100644
--- a/libgo/go/os/error_test.go
+++ b/libgo/go/os/error_test.go
@@ -80,19 +80,23 @@ func checkErrorPredicate(predName string, pred func(error) bool, err error) stri
return ""
}
-var isExistTests = []struct {
+type isExistTest struct {
err error
is bool
isnot bool
-}{
+}
+
+var isExistTests = []isExistTest{
{&os.PathError{Err: os.ErrInvalid}, false, false},
{&os.PathError{Err: os.ErrPermission}, false, false},
{&os.PathError{Err: os.ErrExist}, true, false},
{&os.PathError{Err: os.ErrNotExist}, false, true},
+ {&os.PathError{Err: os.ErrClosed}, false, false},
{&os.LinkError{Err: os.ErrInvalid}, false, false},
{&os.LinkError{Err: os.ErrPermission}, false, false},
{&os.LinkError{Err: os.ErrExist}, true, false},
{&os.LinkError{Err: os.ErrNotExist}, false, true},
+ {&os.LinkError{Err: os.ErrClosed}, false, false},
{&os.SyscallError{Err: os.ErrNotExist}, false, true},
{&os.SyscallError{Err: os.ErrExist}, true, false},
{nil, false, false},
@@ -109,10 +113,12 @@ func TestIsExist(t *testing.T) {
}
}
-var isPermissionTests = []struct {
+type isPermissionTest struct {
err error
want bool
-}{
+}
+
+var isPermissionTests = []isPermissionTest{
{nil, false},
{&os.PathError{Err: os.ErrPermission}, true},
{&os.SyscallError{Err: os.ErrPermission}, true},
diff --git a/libgo/go/os/error_unix.go b/libgo/go/os/error_unix.go
index c6002279da..be1440cacb 100644
--- a/libgo/go/os/error_unix.go
+++ b/libgo/go/os/error_unix.go
@@ -9,43 +9,16 @@ package os
import "syscall"
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
- return err == syscall.EEXIST || err == ErrExist
+ err = underlyingError(err)
+ return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
}
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ENOENT || err == ErrNotExist
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
}
diff --git a/libgo/go/os/error_unix_test.go b/libgo/go/os/error_unix_test.go
new file mode 100644
index 0000000000..76fe015b22
--- /dev/null
+++ b/libgo/go/os/error_unix_test.go
@@ -0,0 +1,39 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package os_test
+
+import (
+ "os"
+ "syscall"
+)
+
+func init() {
+ isExistTests = append(isExistTests,
+ isExistTest{err: &os.PathError{Err: syscall.EEXIST}, is: true, isnot: false},
+ isExistTest{err: &os.PathError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+
+ isExistTest{err: &os.LinkError{Err: syscall.EEXIST}, is: true, isnot: false},
+ isExistTest{err: &os.LinkError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+
+ isExistTest{err: &os.SyscallError{Err: syscall.EEXIST}, is: true, isnot: false},
+ isExistTest{err: &os.SyscallError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+ )
+ isPermissionTests = append(isPermissionTests,
+ isPermissionTest{err: &os.PathError{Err: syscall.EACCES}, want: true},
+ isPermissionTest{err: &os.PathError{Err: syscall.EPERM}, want: true},
+ isPermissionTest{err: &os.PathError{Err: syscall.EEXIST}, want: false},
+
+ isPermissionTest{err: &os.LinkError{Err: syscall.EACCES}, want: true},
+ isPermissionTest{err: &os.LinkError{Err: syscall.EPERM}, want: true},
+ isPermissionTest{err: &os.LinkError{Err: syscall.EEXIST}, want: false},
+
+ isPermissionTest{err: &os.SyscallError{Err: syscall.EACCES}, want: true},
+ isPermissionTest{err: &os.SyscallError{Err: syscall.EPERM}, want: true},
+ isPermissionTest{err: &os.SyscallError{Err: syscall.EEXIST}, want: false},
+ )
+
+}
diff --git a/libgo/go/os/error_windows.go b/libgo/go/os/error_windows.go
index 2c1c39c414..02593b53fe 100644
--- a/libgo/go/os/error_windows.go
+++ b/libgo/go/os/error_windows.go
@@ -7,48 +7,22 @@ package os
import "syscall"
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_ALREADY_EXISTS ||
+ err == syscall.ERROR_DIR_NOT_EMPTY ||
err == syscall.ERROR_FILE_EXISTS || err == ErrExist
}
const _ERROR_BAD_NETPATH = syscall.Errno(53)
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_FILE_NOT_FOUND ||
err == _ERROR_BAD_NETPATH ||
err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
}
diff --git a/libgo/go/os/error_windows_test.go b/libgo/go/os/error_windows_test.go
new file mode 100644
index 0000000000..1635c1088e
--- /dev/null
+++ b/libgo/go/os/error_windows_test.go
@@ -0,0 +1,39 @@
+// 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 windows
+
+package os_test
+
+import (
+ "os"
+ "syscall"
+)
+
+func init() {
+ const _ERROR_BAD_NETPATH = syscall.Errno(53)
+
+ isExistTests = append(isExistTests,
+ isExistTest{err: &os.PathError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+ isExistTest{err: &os.LinkError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+ isExistTest{err: &os.SyscallError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+
+ isExistTest{err: &os.PathError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+ isExistTest{err: &os.LinkError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+ isExistTest{err: &os.SyscallError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+
+ isExistTest{err: &os.PathError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+ isExistTest{err: &os.LinkError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+ isExistTest{err: &os.SyscallError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+
+ isExistTest{err: &os.PathError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
+ isExistTest{err: &os.LinkError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
+ isExistTest{err: &os.SyscallError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
+ )
+ isPermissionTests = append(isPermissionTests,
+ isPermissionTest{err: &os.PathError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+ isPermissionTest{err: &os.LinkError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+ isPermissionTest{err: &os.SyscallError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+ )
+}
diff --git a/libgo/go/os/example_test.go b/libgo/go/os/example_test.go
new file mode 100644
index 0000000000..07f9c76959
--- /dev/null
+++ b/libgo/go/os/example_test.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "time"
+)
+
+func ExampleOpenFile() {
+ f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleChmod() {
+ if err := os.Chmod("some-filename", 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleChtimes() {
+ mtime := time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC)
+ atime := time.Date(2007, time.March, 2, 4, 5, 6, 0, time.UTC)
+ if err := os.Chtimes("some-filename", atime, mtime); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleFileMode() {
+ fi, err := os.Stat("some-filename")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ switch mode := fi.Mode(); {
+ case mode.IsRegular():
+ fmt.Println("regular file")
+ case mode.IsDir():
+ fmt.Println("directory")
+ case mode&os.ModeSymlink != 0:
+ fmt.Println("symbolic link")
+ case mode&os.ModeNamedPipe != 0:
+ fmt.Println("named pipe")
+ }
+}
+
+func ExampleIsNotExist() {
+ filename := "a-nonexistent-file"
+ if _, err := os.Stat(filename); os.IsNotExist(err) {
+ fmt.Printf("file does not exist")
+ }
+ // Output:
+ // file does not exist
+}
+
+func init() {
+ os.Setenv("USER", "gopher")
+ os.Setenv("HOME", "/usr/gopher")
+ os.Unsetenv("GOPATH")
+}
+
+func ExampleExpandEnv() {
+ fmt.Println(os.ExpandEnv("$USER lives in ${HOME}."))
+
+ // Output:
+ // gopher lives in /usr/gopher.
+}
+
+func ExampleLookupEnv() {
+ show := func(key string) {
+ val, ok := os.LookupEnv(key)
+ if !ok {
+ fmt.Printf("%s not set\n", key)
+ } else {
+ fmt.Printf("%s=%s\n", key, val)
+ }
+ }
+
+ show("USER")
+ show("GOPATH")
+
+ // Output:
+ // USER=gopher
+ // GOPATH not set
+}
+
+func ExampleGetenv() {
+ fmt.Printf("%s lives in %s.\n", os.Getenv("USER"), os.Getenv("HOME"))
+
+ // Output:
+ // gopher lives in /usr/gopher.
+}
+
+func ExampleUnsetenv() {
+ os.Setenv("TMPDIR", "/my/tmp")
+ defer os.Unsetenv("TMPDIR")
+}
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
index 15e95b9172..8a53e5dd1e 100644
--- a/libgo/go/os/exec.go
+++ b/libgo/go/os/exec.go
@@ -6,15 +6,18 @@ package os
import (
"runtime"
+ "sync"
"sync/atomic"
"syscall"
+ "time"
)
// Process stores the information about a process created by StartProcess.
type Process struct {
Pid int
- handle uintptr // handle is accessed atomically on Windows
- isdone uint32 // process has been successfully waited on, non zero if true
+ handle uintptr // handle is accessed atomically on Windows
+ isdone uint32 // process has been successfully waited on, non zero if true
+ sigMu sync.RWMutex // avoid race between wait and signal
}
func newProcess(pid int, handle uintptr) *Process {
@@ -41,10 +44,10 @@ type ProcAttr struct {
// new process in the form returned by Environ.
// If it is nil, the result of Environ will be used.
Env []string
- // Files specifies the open files inherited by the new process. The
+ // Files specifies the open files inherited by the new process. The
// first three entries correspond to standard input, standard output, and
- // standard error. An implementation may support additional entries,
- // depending on the underlying operating system. A nil entry corresponds
+ // standard error. An implementation may support additional entries,
+ // depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts.
Files []*File
@@ -68,3 +71,89 @@ func Getpid() int { return syscall.Getpid() }
// Getppid returns the process id of the caller's parent.
func Getppid() int { return syscall.Getppid() }
+
+// FindProcess looks for a running process by its pid.
+//
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+//
+// On Unix systems, FindProcess always succeeds and returns a Process
+// for the given pid, regardless of whether the process exists.
+func FindProcess(pid int) (*Process, error) {
+ return findProcess(pid)
+}
+
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The os/exec package provides
+// higher-level interfaces.
+//
+// If there is an error, it will be of type *PathError.
+func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
+ return startProcess(name, argv, attr)
+}
+
+// Release releases any resources associated with the Process p,
+// rendering it unusable in the future.
+// Release only needs to be called if Wait is not.
+func (p *Process) Release() error {
+ return p.release()
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() error {
+ return p.kill()
+}
+
+// Wait waits for the Process to exit, and then returns a
+// ProcessState describing its status and an error, if any.
+// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
+func (p *Process) Wait() (*ProcessState, error) {
+ return p.wait()
+}
+
+// Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
+func (p *Process) Signal(sig Signal) error {
+ return p.signal(sig)
+}
+
+// UserTime returns the user CPU time of the exited process and its children.
+func (p *ProcessState) UserTime() time.Duration {
+ return p.userTime()
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+func (p *ProcessState) SystemTime() time.Duration {
+ return p.systemTime()
+}
+
+// Exited reports whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.success()
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as syscall.WaitStatus on Unix, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.sys()
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Rusage on Unix, to access its contents.
+// (On Unix, *syscall.Rusage matches struct rusage as defined in the
+// getrusage(2) manual page.)
+func (p *ProcessState) SysUsage() interface{} {
+ return p.sysUsage()
+}
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index 340ebd498b..c4c5168b98 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -13,6 +13,7 @@ package exec
import (
"bytes"
+ "context"
"errors"
"io"
"os"
@@ -102,13 +103,15 @@ 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
goroutine []func() error
errch chan error // one send per goroutine
+ waitDone chan struct{}
}
// Command returns the Cmd struct to execute the named program with
@@ -117,12 +120,13 @@ type Cmd struct {
// It sets only the Path and Args in the returned structure.
//
// If name contains no path separators, Command uses LookPath to
-// resolve the path to a complete name if possible. Otherwise it uses
-// name directly.
+// resolve name to a complete path if possible. Otherwise it uses name
+// directly as Path.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
-// command name itself. For example, Command("echo", "hello")
+// command name itself. For example, Command("echo", "hello").
+// Args[0] is always name, not the possibly resolved Path.
func Command(name string, arg ...string) *Cmd {
cmd := &Cmd{
Path: name,
@@ -138,6 +142,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 {
@@ -310,6 +328,15 @@ func (c *Cmd) Start() error {
if c.Process != nil {
return errors.New("exec: already started")
}
+ if c.ctx != nil {
+ select {
+ case <-c.ctx.Done():
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return c.ctx.Err()
+ default:
+ }
+ }
type F func(*Cmd) (*os.File, error)
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
@@ -345,6 +372,17 @@ func (c *Cmd) Start() error {
}(fn)
}
+ if c.ctx != nil {
+ c.waitDone = make(chan struct{})
+ go func() {
+ select {
+ case <-c.ctx.Done():
+ c.Process.Kill()
+ case <-c.waitDone:
+ }
+ }()
+ }
+
return nil
}
@@ -393,7 +431,11 @@ func (c *Cmd) Wait() error {
return errors.New("exec: Wait was already called")
}
c.finished = true
+
state, err := c.Process.Wait()
+ if c.waitDone != nil {
+ close(c.waitDone)
+ }
c.ProcessState = state
var copyError error
@@ -474,15 +516,16 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
c.Stdin = pr
c.closeAfterStart = append(c.closeAfterStart, pr)
wc := &closeOnce{File: pw}
- c.closeAfterWait = append(c.closeAfterWait, wc)
+ c.closeAfterWait = append(c.closeAfterWait, closerFunc(wc.safeClose))
return wc, nil
}
type closeOnce struct {
*os.File
- once sync.Once
- err error
+ writers sync.RWMutex // coordinate safeClose and Write
+ once sync.Once
+ err error
}
func (c *closeOnce) Close() error {
@@ -494,6 +537,55 @@ func (c *closeOnce) close() {
c.err = c.File.Close()
}
+type closerFunc func() error
+
+func (f closerFunc) Close() error { return f() }
+
+// safeClose closes c being careful not to race with any calls to c.Write.
+// See golang.org/issue/9307 and TestEchoFileRace in exec_test.go.
+// In theory other calls could also be excluded (by writing appropriate
+// wrappers like c.Write's implementation below), but since c is most
+// commonly used as a WriteCloser, Write is the main one to worry about.
+// See also #7970, for which this is a partial fix for this specific instance.
+// The idea is that we return a WriteCloser, and so the caller can be
+// relied upon not to call Write and Close simultaneously, but it's less
+// obvious that cmd.Wait calls Close and that the caller must not call
+// Write and cmd.Wait simultaneously. In fact that seems too onerous.
+// So we change the use of Close in cmd.Wait to use safeClose, which will
+// synchronize with any Write.
+//
+// It's important that we know this won't block forever waiting for the
+// operations being excluded. At the point where this is called,
+// the invoked command has exited and the parent copy of the read side
+// of the pipe has also been closed, so there should really be no read side
+// of the pipe left. Any active writes should return very shortly with an EPIPE,
+// making it reasonable to wait for them.
+// Technically it is possible that the child forked a sub-process or otherwise
+// handed off the read side of the pipe before exiting and the current holder
+// is not reading from the pipe, and the pipe is full, in which case the close here
+// might block waiting for the write to complete. That's probably OK.
+// It's a small enough problem to be outweighed by eliminating the race here.
+func (c *closeOnce) safeClose() error {
+ c.writers.Lock()
+ err := c.Close()
+ c.writers.Unlock()
+ return err
+}
+
+func (c *closeOnce) Write(b []byte) (int, error) {
+ c.writers.RLock()
+ n, err := c.File.Write(b)
+ c.writers.RUnlock()
+ return n, err
+}
+
+func (c *closeOnce) WriteString(s string) (int, error) {
+ c.writers.RLock()
+ n, err := c.File.WriteString(s)
+ c.writers.RUnlock()
+ return n, err
+}
+
// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
//
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index 1576e8f156..f13635138a 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -10,6 +10,7 @@ package exec_test
import (
"bufio"
"bytes"
+ "context"
"fmt"
"internal/testenv"
"io"
@@ -28,12 +29,16 @@ 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"}
path := os.Getenv("LD_LIBRARY_PATH")
if path != "" {
@@ -42,6 +47,10 @@ func helperCommand(t *testing.T, s ...string) *exec.Cmd {
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 {
@@ -96,6 +105,26 @@ func TestCatStdin(t *testing.T) {
}
}
+func TestEchoFileRace(t *testing.T) {
+ cmd := helperCommand(t, "echo")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe: %v", err)
+ }
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("Start: %v", err)
+ }
+ wrote := make(chan bool)
+ go func() {
+ defer close(wrote)
+ fmt.Fprint(stdin, "echo\n")
+ }()
+ if err := cmd.Wait(); err != nil {
+ t.Fatalf("Wait: %v", err)
+ }
+ <-wrote
+}
+
func TestCatGoodAndBadFile(t *testing.T) {
// Testing combined output and error values.
bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
@@ -221,6 +250,46 @@ func TestStdinClose(t *testing.T) {
check("Wait", cmd.Wait())
}
+// Issue 17647.
+// It used to be the case that TestStdinClose, above, would fail when
+// run under the race detector. This test is a variant of TestStdinClose
+// that also used to fail when run under the race detector.
+// This test is run by cmd/dist under the race detector to verify that
+// the race detector no longer reports any problems.
+func TestStdinCloseRace(t *testing.T) {
+ cmd := helperCommand(t, "stdinClose")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe: %v", err)
+ }
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("Start: %v", err)
+ }
+ go func() {
+ // We don't check the error return of Kill. It is
+ // possible that the process has already exited, in
+ // which case Kill will return an error "process
+ // already finished". The purpose of this test is to
+ // see whether the race detector reports an error; it
+ // doesn't matter whether this Kill succeeds or not.
+ cmd.Process.Kill()
+ }()
+ go func() {
+ // Send the wrong string, so that the child fails even
+ // if the other goroutine doesn't manage to kill it first.
+ // This test is to check that the race detector does not
+ // falsely report an error, so it doesn't matter how the
+ // child process fails.
+ io.Copy(stdin, strings.NewReader("unexpected string"))
+ if err := stdin.Close(); err != nil {
+ t.Errorf("stdin.Close: %v", err)
+ }
+ }()
+ if err := cmd.Wait(); err == nil {
+ t.Fatalf("Wait: succeeded unexpectedly")
+ }
+}
+
// Issue 5071
func TestPipeLookPathLeak(t *testing.T) {
fd0, lsof0 := numOpenFDS(t)
@@ -345,7 +414,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
//
// We want to test that FDs in the child do not get overwritten
// by one another as this shuffle occurs. The original implementation
- // was buggy in that in some data dependent cases it would ovewrite
+ // was buggy in that in some data dependent cases it would overwrite
// stderr in the child with one of the ExtraFile members.
// Testing for this case is difficult because it relies on using
// the same FD values as that case. In particular, an FD of 3
@@ -407,7 +476,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
buf := make([]byte, 512)
n, err := stderr.Read(buf)
if err != nil {
- t.Fatalf("Read: %s", err)
+ t.Errorf("Read: %s", err)
ch <- err.Error()
} else {
ch <- string(buf[:n])
@@ -483,7 +552,7 @@ func TestExtraFiles(t *testing.T) {
if err != nil {
t.Fatalf("Write: %v", err)
}
- _, err = tf.Seek(0, os.SEEK_SET)
+ _, err = tf.Seek(0, io.SeekStart)
if err != nil {
t.Fatalf("Seek: %v", err)
}
@@ -663,10 +732,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,
@@ -701,7 +766,7 @@ func TestHelperProcess(*testing.T) {
}
// Referring to fd3 here ensures that it is not
// garbage collected, and therefore closed, while
- // executing the wantfd loop above. It doesn't matter
+ // executing the wantfd loop above. It doesn't matter
// what we do with fd3 as long as we refer to it;
// closing it is the easy choice.
fd3.Close()
@@ -839,3 +904,111 @@ func TestOutputStderrCapture(t *testing.T) {
t.Errorf("ExitError.Stderr = %q; want %q", got, want)
}
}
+
+func TestContext(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ c := helperCommandContext(t, ctx, "pipetest")
+ stdin, err := c.StdinPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ stdout, err := c.StdoutPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.Start(); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := stdin.Write([]byte("O:hi\n")); err != nil {
+ t.Fatal(err)
+ }
+ buf := make([]byte, 5)
+ n, err := io.ReadFull(stdout, buf)
+ if n != len(buf) || err != nil || string(buf) != "O:hi\n" {
+ t.Fatalf("ReadFull = %d, %v, %q", n, err, buf[:n])
+ }
+ waitErr := make(chan error, 1)
+ go func() {
+ waitErr <- c.Wait()
+ }()
+ cancel()
+ select {
+ case err := <-waitErr:
+ if err == nil {
+ t.Fatal("expected Wait failure")
+ }
+ case <-time.After(3 * time.Second):
+ t.Fatal("timeout waiting for child process death")
+ }
+}
+
+func TestContextCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ c := helperCommandContext(t, ctx, "cat")
+
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Stdin = r
+
+ stdout, err := c.StdoutPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ readDone := make(chan struct{})
+ go func() {
+ defer close(readDone)
+ var a [1024]byte
+ for {
+ n, err := stdout.Read(a[:])
+ if err != nil {
+ if err != io.EOF {
+ t.Errorf("unexpected read error: %v", err)
+ }
+ return
+ }
+ t.Logf("%s", a[:n])
+ }
+ }()
+
+ if err := c.Start(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := r.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := io.WriteString(w, "echo"); err != nil {
+ t.Fatal(err)
+ }
+
+ cancel()
+
+ // Calling cancel should have killed the process, so writes
+ // should now fail. Give the process a little while to die.
+ start := time.Now()
+ for {
+ if _, err := io.WriteString(w, "echo"); err != nil {
+ break
+ }
+ if time.Since(start) > time.Second {
+ t.Fatal("canceling context did not stop program")
+ }
+ time.Sleep(time.Millisecond)
+ }
+
+ if err := w.Close(); err != nil {
+ t.Errorf("error closing write end of pipe: %v", err)
+ }
+ <-readDone
+
+ if err := c.Wait(); err == nil {
+ t.Error("program unexpectedly exited successfully")
+ } else {
+ t.Logf("exit status: %v", err)
+ }
+}
diff --git a/libgo/go/os/exec/lp_plan9.go b/libgo/go/os/exec/lp_plan9.go
index 5aa8a54ed8..142f87ed32 100644
--- a/libgo/go/os/exec/lp_plan9.go
+++ b/libgo/go/os/exec/lp_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -7,6 +7,7 @@ package exec
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
@@ -44,9 +45,10 @@ func LookPath(file string) (string, error) {
}
path := os.Getenv("path")
- for _, dir := range strings.Split(path, "\000") {
- if err := findExecutable(dir + "/" + file); err == nil {
- return dir + "/" + file, nil
+ for _, dir := range filepath.SplitList(path) {
+ path := filepath.Join(dir, file)
+ if err := findExecutable(path); err == nil {
+ return path, nil
}
}
return "", &Error{file, ErrNotFound}
diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go
index 3f895d5b3b..7a302752a8 100644
--- a/libgo/go/os/exec/lp_unix.go
+++ b/libgo/go/os/exec/lp_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -9,6 +9,7 @@ package exec
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
@@ -42,16 +43,13 @@ func LookPath(file string) (string, error) {
}
return "", &Error{file, err}
}
- pathenv := os.Getenv("PATH")
- if pathenv == "" {
- return "", &Error{file, ErrNotFound}
- }
- for _, dir := range strings.Split(pathenv, ":") {
+ path := os.Getenv("PATH")
+ for _, dir := range filepath.SplitList(path) {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
- path := dir + "/" + file
+ path := filepath.Join(dir, file)
if err := findExecutable(path); err == nil {
return path, nil
}
diff --git a/libgo/go/os/exec/lp_unix_test.go b/libgo/go/os/exec/lp_unix_test.go
index 051db664a8..d467acf5db 100644
--- a/libgo/go/os/exec/lp_unix_test.go
+++ b/libgo/go/os/exec/lp_unix_test.go
@@ -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.
diff --git a/libgo/go/os/exec/lp_windows.go b/libgo/go/os/exec/lp_windows.go
index c3efd67e9e..793d4d98b3 100644
--- a/libgo/go/os/exec/lp_windows.go
+++ b/libgo/go/os/exec/lp_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -7,6 +7,7 @@ package exec
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
@@ -46,7 +47,7 @@ func findExecutable(file string, exts []string) (string, error) {
return f, nil
}
}
- return ``, os.ErrNotExist
+ return "", os.ErrNotExist
}
// LookPath searches for an executable binary named file
@@ -55,69 +56,38 @@ func findExecutable(file string, exts []string) (string, error) {
// LookPath also uses PATHEXT environment variable to match
// a suitable candidate.
// The result may be an absolute path or a path relative to the current directory.
-func LookPath(file string) (f string, err error) {
+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
- }
- exts = append(exts, e)
- }
- if strings.IndexAny(file, `:\/`) != -1 {
- if f, err = findExecutable(file, exts); err == nil {
- return
- }
- return ``, &Error{file, err}
- }
- if f, err = findExecutable(`.\`+file, exts); err == nil {
- return
- }
- if pathenv := os.Getenv(`PATH`); pathenv != `` {
- for _, dir := range splitList(pathenv) {
- if f, err = findExecutable(dir+`\`+file, exts); err == nil {
- return
+ if x != "" {
+ for _, e := range strings.Split(strings.ToLower(x), `;`) {
+ if e == "" {
+ continue
}
+ if e[0] != '.' {
+ e = "." + e
+ }
+ exts = append(exts, e)
}
+ } else {
+ exts = []string{".com", ".exe", ".bat", ".cmd"}
}
- 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
+ if strings.ContainsAny(file, `:\/`) {
+ if f, err := findExecutable(file, exts); err == nil {
+ return f, nil
+ } else {
+ return "", &Error{file, err}
}
}
- list = append(list, path[start:])
-
- // Remove quotes.
- for i, s := range list {
- if strings.Contains(s, `"`) {
- list[i] = strings.Replace(s, `"`, ``, -1)
+ if f, err := findExecutable(filepath.Join(".", 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 list
+ return "", &Error{file, ErrNotFound}
}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 94dd04beb2..3cf38b68ad 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -21,7 +21,7 @@ var (
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
// If there is no SysProcAttr (ie. no Chroot or changed
// UID/GID), double-check existence of the directory we want
- // to chdir into. We can make the error clearer this way.
+ // to chdir into. We can make the error clearer this way.
if attr != nil && attr.Sys == nil && attr.Dir != "" {
if _, err := Stat(attr.Dir); err != nil {
pe := err.(*PathError)
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index ed97f85e22..c4999db57f 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -17,6 +17,22 @@ func (p *Process) wait() (ps *ProcessState, err error) {
if p.Pid == -1 {
return nil, syscall.EINVAL
}
+
+ // If we can block until Wait4 will succeed immediately, do so.
+ ready, err := p.blockUntilWaitable()
+ if err != nil {
+ return nil, err
+ }
+ if ready {
+ // Mark the process done now, before the call to Wait4,
+ // so that Process.signal will not send a signal.
+ p.setDone()
+ // Acquire a write lock on sigMu to wait for any
+ // active call to the signal method to complete.
+ p.sigMu.Lock()
+ p.sigMu.Unlock()
+ }
+
var status syscall.WaitStatus
var rusage syscall.Rusage
pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
@@ -43,6 +59,8 @@ func (p *Process) signal(sig Signal) error {
if p.Pid == 0 {
return errors.New("os: process not initialized")
}
+ p.sigMu.RLock()
+ defer p.sigMu.RUnlock()
if p.done() {
return errFinished
}
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index 3264271b2e..d89db2022c 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -63,7 +63,9 @@ func (p *Process) signal(sig Signal) error {
return errors.New("os: process already finished")
}
if sig == Kill {
- return terminateProcess(p.Pid, 1)
+ err := terminateProcess(p.Pid, 1)
+ runtime.KeepAlive(p)
+ return err
}
// TODO(rsc): Handle Interrupt too?
return syscall.Errno(syscall.EWINDOWS)
@@ -104,7 +106,7 @@ func init() {
defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
Args = make([]string, argc)
for i, v := range (*argv)[:argc] {
- Args[i] = string(syscall.UTF16ToString((*v)[:]))
+ Args[i] = syscall.UTF16ToString((*v)[:])
}
}
diff --git a/libgo/go/os/executable.go b/libgo/go/os/executable.go
new file mode 100644
index 0000000000..8c21246f5a
--- /dev/null
+++ b/libgo/go/os/executable.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Executable returns the path name for the executable that started
+// the current process. There is no guarantee that the path is still
+// pointing to the correct executable. If a symlink was used to start
+// the process, depending on the operating system, the result might
+// be the symlink or the path it pointed to. If a stable result is
+// needed, path/filepath.EvalSymlinks might help.
+//
+// Executable returns an absolute path unless an error occurred.
+//
+// The main use case is finding resources located relative to an
+// executable.
+//
+// Executable is not supported on nacl or OpenBSD (unless procfs is
+// mounted.)
+func Executable() (string, error) {
+ return executable()
+}
diff --git a/libgo/go/os/executable_darwin.go b/libgo/go/os/executable_darwin.go
new file mode 100644
index 0000000000..ce5b8140a4
--- /dev/null
+++ b/libgo/go/os/executable_darwin.go
@@ -0,0 +1,24 @@
+// 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 os
+
+var executablePath string // set by ../runtime/os_darwin.go
+
+var initCwd, initCwdErr = Getwd()
+
+func executable() (string, error) {
+ ep := executablePath
+ if ep[0] != '/' {
+ if initCwdErr != nil {
+ return ep, initCwdErr
+ }
+ if len(ep) > 2 && ep[0:2] == "./" {
+ // skip "./"
+ ep = ep[2:]
+ }
+ ep = initCwd + "/" + ep
+ }
+ return ep, nil
+}
diff --git a/libgo/go/os/executable_freebsd.go b/libgo/go/os/executable_freebsd.go
new file mode 100644
index 0000000000..ccaf8e6dd4
--- /dev/null
+++ b/libgo/go/os/executable_freebsd.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func executable() (string, error) {
+ mib := [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
+
+ n := uintptr(0)
+ // get length
+ _, _, err := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
+ if err != 0 {
+ return "", err
+ }
+ if n == 0 { // shouldn't happen
+ return "", nil
+ }
+ buf := make([]byte, n)
+ _, _, err = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
+ if err != 0 {
+ return "", err
+ }
+ if n == 0 { // shouldn't happen
+ return "", nil
+ }
+ return string(buf[:n-1]), nil
+}
diff --git a/libgo/go/os/executable_plan9.go b/libgo/go/os/executable_plan9.go
new file mode 100644
index 0000000000..a5947eaae1
--- /dev/null
+++ b/libgo/go/os/executable_plan9.go
@@ -0,0 +1,19 @@
+// 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 plan9
+
+package os
+
+import "syscall"
+
+func executable() (string, error) {
+ fn := "/proc/" + itoa(Getpid()) + "/text"
+ f, err := Open(fn)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ return syscall.Fd2path(int(f.Fd()))
+}
diff --git a/libgo/go/os/executable_procfs.go b/libgo/go/os/executable_procfs.go
new file mode 100644
index 0000000000..69a70e18df
--- /dev/null
+++ b/libgo/go/os/executable_procfs.go
@@ -0,0 +1,36 @@
+// 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 linux netbsd openbsd dragonfly nacl
+
+package os
+
+import (
+ "errors"
+ "runtime"
+)
+
+// We query the executable path at init time to avoid the problem of
+// readlink returns a path appended with " (deleted)" when the original
+// binary gets deleted.
+var executablePath, executablePathErr = func() (string, error) {
+ var procfn string
+ switch runtime.GOOS {
+ default:
+ return "", errors.New("Executable not implemented for " + runtime.GOOS)
+ case "linux", "android":
+ procfn = "/proc/self/exe"
+ case "netbsd":
+ procfn = "/proc/curproc/exe"
+ case "openbsd":
+ procfn = "/proc/curproc/file"
+ case "dragonfly":
+ procfn = "/proc/curproc/file"
+ }
+ return Readlink(procfn)
+}()
+
+func executable() (string, error) {
+ return executablePath, executablePathErr
+}
diff --git a/libgo/go/os/executable_solaris.go b/libgo/go/os/executable_solaris.go
new file mode 100644
index 0000000000..80f937201a
--- /dev/null
+++ b/libgo/go/os/executable_solaris.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+var initCwd, initCwdErr = Getwd()
+
+func executable() (string, error) {
+ path, err := syscall.Getexecname()
+ if err != nil {
+ return path, err
+ }
+ if len(path) > 0 && path[0] != '/' {
+ if initCwdErr != nil {
+ return path, initCwdErr
+ }
+ if len(path) > 2 && path[0:2] == "./" {
+ // skip "./"
+ path = path[2:]
+ }
+ return initCwd + "/" + path, nil
+ }
+ return path, nil
+}
diff --git a/libgo/go/os/executable_test.go b/libgo/go/os/executable_test.go
new file mode 100644
index 0000000000..a4d89092ac
--- /dev/null
+++ b/libgo/go/os/executable_test.go
@@ -0,0 +1,87 @@
+// 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 os_test
+
+import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ osexec "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+const executable_EnvVar = "OSTEST_OUTPUT_EXECPATH"
+
+func TestExecutable(t *testing.T) {
+ testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway
+ ep, err := os.Executable()
+ if err != nil {
+ switch goos := runtime.GOOS; goos {
+ case "openbsd": // procfs is not mounted by default
+ t.Skipf("Executable failed on %s: %v, expected", goos, err)
+ }
+ t.Fatalf("Executable failed: %v", err)
+ }
+ // we want fn to be of the form "dir/prog"
+ dir := filepath.Dir(filepath.Dir(ep))
+ fn, err := filepath.Rel(dir, ep)
+ if err != nil {
+ t.Fatalf("filepath.Rel: %v", err)
+ }
+ cmd := &osexec.Cmd{}
+ // make child start with a relative program path
+ cmd.Dir = dir
+ cmd.Path = fn
+ // forge argv[0] for child, so that we can verify we could correctly
+ // get real path of the executable without influenced by argv[0].
+ cmd.Args = []string{"-", "-test.run=XXXX"}
+ cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar))
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("exec(self) failed: %v", err)
+ }
+ outs := string(out)
+ if !filepath.IsAbs(outs) {
+ t.Fatalf("Child returned %q, want an absolute path", out)
+ }
+ if !sameFile(outs, ep) {
+ t.Fatalf("Child returned %q, not the same file as %q", out, ep)
+ }
+}
+
+func sameFile(fn1, fn2 string) bool {
+ fi1, err := os.Stat(fn1)
+ if err != nil {
+ return false
+ }
+ fi2, err := os.Stat(fn2)
+ if err != nil {
+ return false
+ }
+ return os.SameFile(fi1, fi2)
+}
+
+func init() {
+ if e := os.Getenv(executable_EnvVar); e != "" {
+ // first chdir to another path
+ dir := "/"
+ if runtime.GOOS == "windows" {
+ cwd, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ dir = filepath.VolumeName(cwd)
+ }
+ os.Chdir(dir)
+ if ep, err := os.Executable(); err != nil {
+ fmt.Fprint(os.Stderr, "ERROR: ", err)
+ } else {
+ fmt.Fprint(os.Stderr, ep)
+ }
+ os.Exit(0)
+ }
+}
diff --git a/libgo/go/os/executable_windows.go b/libgo/go/os/executable_windows.go
new file mode 100644
index 0000000000..fc5cf86005
--- /dev/null
+++ b/libgo/go/os/executable_windows.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "internal/syscall/windows"
+ "syscall"
+)
+
+func getModuleFileName(handle syscall.Handle) (string, error) {
+ n := uint32(1024)
+ var buf []uint16
+ for {
+ buf = make([]uint16, n)
+ r, err := windows.GetModuleFileName(handle, &buf[0], n)
+ if err != nil {
+ return "", err
+ }
+ if r < n {
+ break
+ }
+ // r == n means n not big enough
+ n += 1024
+ }
+ return syscall.UTF16ToString(buf), nil
+}
+
+func executable() (string, error) {
+ return getModuleFileName(0)
+}
diff --git a/libgo/go/os/export_test.go b/libgo/go/os/export_test.go
index 9fa7936ae6..d735aeea61 100644
--- a/libgo/go/os/export_test.go
+++ b/libgo/go/os/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/os/export_windows_test.go b/libgo/go/os/export_windows_test.go
new file mode 100644
index 0000000000..3bb2d2015f
--- /dev/null
+++ b/libgo/go/os/export_windows_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Export for testing.
+
+var (
+ FixLongPath = fixLongPath
+ NewConsoleFile = newConsoleFile
+ ReadConsoleFunc = &readConsole
+)
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 4f8e3f3450..d45a00b123 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -46,6 +46,10 @@ func (f *File) Name() string { return f.name }
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
// standard output, and standard error file descriptors.
+//
+// Note that the Go runtime writes to standard error for panics and crashes;
+// closing Stderr may cause those messages to go elsewhere, perhaps
+// to a file opened later.
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
@@ -66,6 +70,8 @@ const (
)
// Seek whence values.
+//
+// Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
const (
SEEK_SET int = 0 // seek relative to the origin of the file
SEEK_CUR int = 1 // seek relative to the current offset
@@ -86,11 +92,11 @@ func (e *LinkError) Error() string {
}
// Read reads up to len(b) bytes from the File.
-// It returns the number of bytes read and an error, if any.
-// EOF is signaled by a zero count with err set to io.EOF.
+// It returns the number of bytes read and any error encountered.
+// At end of file, Read returns 0, io.EOF.
func (f *File) Read(b []byte) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("read"); err != nil {
+ return 0, err
}
n, e := f.read(b)
if n == 0 && len(b) > 0 && e == nil {
@@ -107,8 +113,8 @@ func (f *File) Read(b []byte) (n int, err error) {
// ReadAt always returns a non-nil error when n < len(b).
// At end of file, that error is io.EOF.
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("read"); err != nil {
+ return 0, err
}
for len(b) > 0 {
m, e := f.pread(b, off)
@@ -130,8 +136,8 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("write"); err != nil {
+ return 0, err
}
n, e := f.write(b)
if n < 0 {
@@ -153,8 +159,8 @@ func (f *File) Write(b []byte) (n int, err error) {
// It returns the number of bytes written and an error, if any.
// WriteAt returns a non-nil error when n != len(b).
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("write"); err != nil {
+ return 0, err
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
@@ -175,8 +181,8 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
// It returns the new offset and an error, if any.
// The behavior of Seek on a file opened with O_APPEND is not specified.
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("seek"); err != nil {
+ return 0, err
}
r, e := f.seek(offset, whence)
if e == nil && f.dirinfo != nil && r != 0 {
@@ -191,16 +197,13 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
// WriteString is like Write, but writes the contents of string s rather than
// a slice of bytes.
func (f *File) WriteString(s string) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
- }
return f.Write([]byte(s))
}
// Mkdir creates a new directory with the specified name and permission bits.
// If there is an error, it will be of type *PathError.
func Mkdir(name string, perm FileMode) error {
- e := syscall.Mkdir(name, syscallMode(perm))
+ e := syscall.Mkdir(fixLongPath(name), syscallMode(perm))
if e != nil {
return &PathError{"mkdir", name, e}
@@ -227,8 +230,8 @@ func Chdir(dir string) error {
// which must be a directory.
// If there is an error, it will be of type *PathError.
func (f *File) Chdir() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("chdir"); err != nil {
+ return err
}
if e := syscall.Fchdir(f.fd); e != nil {
return &PathError{"chdir", f.name, e}
@@ -236,7 +239,7 @@ func (f *File) Chdir() error {
return nil
}
-// Open opens the named file for reading. If successful, methods on
+// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
@@ -257,7 +260,7 @@ func Create(name string) (*File, error) {
var lstat = Lstat
// Rename renames (moves) oldpath to newpath.
-// If newpath already exists, Rename replaces it.
+// If newpath already exists and is not a directory, Rename replaces it.
// OS-specific restrictions may apply when oldpath and newpath are in different directories.
// If there is an error, it will be of type *LinkError.
func Rename(oldpath, newpath string) error {
@@ -272,3 +275,15 @@ func fixCount(n int, err error) (int, error) {
}
return n, err
}
+
+// checkValid checks whether f is valid for use.
+// If not, it returns an appropriate error, perhaps incorporating the operation name op.
+func (f *File) checkValid(op string) error {
+ if f == nil {
+ return ErrInvalid
+ }
+ if f.fd == badFd {
+ return &PathError{op, f.name, ErrClosed}
+ }
+ return nil
+}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index c83fa028b9..5276a7ec54 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -5,14 +5,15 @@
package os
import (
+ "io"
"runtime"
"syscall"
"time"
)
-// File represents an open file descriptor.
-type File struct {
- *file
+// fixLongPath is a noop on non-Windows platforms.
+func fixLongPath(path string) string {
+ return path
}
// file is the real representation of *File.
@@ -75,8 +76,8 @@ func syscallMode(i FileMode) (o uint32) {
}
// OpenFile is the generalized open call; most users will use Open
-// or Create instead. It opens the named file with specified flag
-// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// If there is an error, it will be of type *PathError.
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
@@ -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}
}
}
@@ -134,23 +135,21 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
// Close closes the File, rendering it unusable for I/O.
// It returns an error, if any.
func (f *File) Close() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("close"); err != nil {
+ return err
}
return f.file.close()
}
func (file *file) close() error {
- if file == nil || file.fd < 0 {
+ if file == nil || file.fd == badFd {
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
+ file.fd = badFd // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
@@ -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
}
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index 6d8076fdf5..d817f34b1d 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -18,7 +18,7 @@ func sigpipe() // implemented in package runtime
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
- n, e := fixCount(syscall.Readlink(name, b))
+ n, e := fixCount(syscall.Readlink(fixLongPath(name), b))
if e != nil {
return "", &PathError{"readlink", name, e}
}
@@ -57,8 +57,8 @@ func Chmod(name string, mode FileMode) error {
// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("chmod"); err != nil {
+ return err
}
if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
return &PathError{"chmod", f.name, e}
@@ -89,8 +89,8 @@ func Lchown(name string, uid, gid int) error {
// Chown changes the numeric uid and gid of the named file.
// If there is an error, it will be of type *PathError.
func (f *File) Chown(uid, gid int) error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("chown"); err != nil {
+ return err
}
if e := syscall.Fchown(f.fd, uid, gid); e != nil {
return &PathError{"chown", f.name, e}
@@ -102,8 +102,8 @@ func (f *File) Chown(uid, gid int) error {
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
func (f *File) Truncate(size int64) error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("truncate"); err != nil {
+ return err
}
if e := syscall.Ftruncate(f.fd, size); e != nil {
return &PathError{"truncate", f.name, e}
@@ -115,11 +115,11 @@ func (f *File) Truncate(size int64) error {
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("sync"); err != nil {
+ return err
}
if e := syscall.Fsync(f.fd); e != nil {
- return NewSyscallError("fsync", e)
+ return &PathError{"sync", f.name, e}
}
return nil
}
@@ -134,7 +134,7 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
var utimes [2]syscall.Timespec
utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
- if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
+ if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
return &PathError{"chtimes", name, e}
}
return nil
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index c3119cd459..54b5dfd128 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -11,11 +11,16 @@ import (
"syscall"
)
-func sameFile(fs1, fs2 *fileStat) bool {
- return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
+// fixLongPath is a noop on non-Windows platforms.
+func fixLongPath(path string) string {
+ return path
}
func rename(oldname, newname string) error {
+ fi, err := Lstat(newname)
+ if err == nil && fi.IsDir() {
+ return &LinkError{"rename", oldname, newname, syscall.EEXIST}
+ }
e := syscall.Rename(oldname, newname)
if e != nil {
return &LinkError{"rename", oldname, newname, e}
@@ -23,11 +28,6 @@ func rename(oldname, newname string) error {
return nil
}
-// File represents an open file descriptor.
-type File struct {
- *file
-}
-
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
@@ -78,8 +78,8 @@ func epipecheck(file *File, e error) {
const DevNull = "/dev/null"
// OpenFile is the generalized open call; most users will use Open
-// or Create instead. It opens the named file with specified flag
-// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// If there is an error, it will be of type *PathError.
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
@@ -114,7 +114,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
}
// There's a race here with fork/exec, which we are
- // content to live with. See ../syscall/exec_unix.go.
+ // content to live with. See ../syscall/exec_unix.go.
if !supportsCloseOnExec {
syscall.CloseOnExec(r)
}
@@ -132,7 +132,7 @@ func (f *File) Close() error {
}
func (file *file) close() error {
- if file == nil || file.fd < 0 {
+ if file == nil || file.fd == badFd {
return syscall.EINVAL
}
var err error
@@ -158,69 +158,6 @@ func (file *file) close() error {
return err
}
-// Stat returns the FileInfo structure describing file.
-// If there is an error, it will be of type *PathError.
-func (f *File) Stat() (FileInfo, error) {
- if f == nil {
- return nil, ErrInvalid
- }
- var fs fileStat
- err := syscall.Fstat(f.fd, &fs.sys)
- if err != nil {
- return nil, &PathError{"stat", f.name, err}
- }
- fillFileStatFromSys(&fs, f.name)
- return &fs, nil
-}
-
-// Stat returns a FileInfo describing the named file.
-// If there is an error, it will be of type *PathError.
-func Stat(name string) (FileInfo, error) {
- var fs fileStat
- err := syscall.Stat(name, &fs.sys)
- if err != nil {
- return nil, &PathError{"stat", name, err}
- }
- fillFileStatFromSys(&fs, name)
- return &fs, nil
-}
-
-// Lstat returns a FileInfo describing the named file.
-// If the file is a symbolic link, the returned FileInfo
-// describes the symbolic link. Lstat makes no attempt to follow the link.
-// If there is an error, it will be of type *PathError.
-func Lstat(name string) (FileInfo, error) {
- var fs fileStat
- err := syscall.Lstat(name, &fs.sys)
- if err != nil {
- return nil, &PathError{"lstat", name, err}
- }
- fillFileStatFromSys(&fs, name)
- return &fs, nil
-}
-
-func (f *File) readdir(n int) (fi []FileInfo, err error) {
- dirname := f.name
- if dirname == "" {
- dirname = "."
- }
- names, err := f.Readdirnames(n)
- fi = make([]FileInfo, 0, len(names))
- for _, filename := range names {
- fip, lerr := lstat(dirname + "/" + filename)
- if IsNotExist(lerr) {
- // File disappeared between readdir + stat.
- // Just treat it as if it didn't exist.
- continue
- }
- if lerr != nil {
- return fi, lerr
- }
- fi = append(fi, fip)
- }
- return fi, err
-}
-
// Darwin and FreeBSD can't read or write 2GB+ at a time,
// even on 64-bit systems. See golang.org/issue/7812.
// Use 1GB instead of, say, 2GB-1, to keep subsequent
@@ -322,7 +259,7 @@ func Remove(name string) error {
// Both failed: figure out which error to return.
// OS X and Linux differ on whether unlink(dir)
- // returns EISDIR, so can't use that. However,
+ // returns EISDIR, so can't use that. However,
// both agree that rmdir(file) returns ENOTDIR,
// so we can use that to decide which error is real.
// Rmdir might also return ENOTDIR if given a bad
@@ -335,24 +272,6 @@ func Remove(name string) error {
return &PathError{"remove", name, e}
}
-// basename removes trailing slashes and the leading directory name from path name
-func basename(name string) string {
- i := len(name) - 1
- // Remove trailing slashes
- for ; i > 0 && name[i] == '/'; i-- {
- name = name[:i]
- }
- // Remove leading directory name
- for i--; i >= 0; i-- {
- if name[i] == '/' {
- name = name[i+1:]
- break
- }
- }
-
- return name
-}
-
// TempDir returns the default directory to use for temporary files.
func TempDir() string {
dir := Getenv("TMPDIR")
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index d5da53b34b..4c3c0d94cb 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -20,7 +20,7 @@ var getwdCache struct {
var useSyscallwd = func(error) bool { return true }
// Getwd returns a rooted path name corresponding to the
-// current directory. If the current directory can be
+// current directory. If the current directory can be
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
func Getwd() (dir string, err error) {
@@ -74,7 +74,7 @@ func Getwd() (dir string, err error) {
}
// General algorithm: find name in parent
- // and then find name of parent. Each iteration
+ // and then find name of parent. Each iteration
// adds /name to the beginning of dir.
dir = ""
for parent := ".."; ; parent = "../" + parent {
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 5497704e16..dcc8d762bf 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -25,10 +25,8 @@ import (
"time"
)
-var supportsSymlinks = true
-
var dot = []string{
- "dir_unix.go",
+ "dir.go",
"env.go",
"error.go",
"file.go",
@@ -45,21 +43,24 @@ var sysdir = func() *sysDir {
switch runtime.GOOS {
case "android":
return &sysDir{
- "/system/framework",
+ "/system/lib",
[]string{
- "ext.jar",
- "framework.jar",
+ "libmedia.so",
+ "libpowermanager.so",
},
}
case "darwin":
switch runtime.GOARCH {
case "arm", "arm64":
+ /// At this point the test harness has not had a chance
+ // to move us into the ./src/os directory, so the
+ // current working directory is the root of the app.
wd, err := syscall.Getwd()
if err != nil {
wd = err.Error()
}
return &sysDir{
- filepath.Join(wd, "..", ".."),
+ wd,
[]string{
"ResourceRules.plist",
"Info.plist",
@@ -229,6 +230,28 @@ func TestRead0(t *testing.T) {
}
}
+// Reading a closed file should should return ErrClosed error
+func TestReadClosed(t *testing.T) {
+ path := sfdir + "/" + sfname
+ file, err := Open(path)
+ if err != nil {
+ t.Fatal("open failed:", err)
+ }
+ file.Close() // close immediately
+
+ b := make([]byte, 100)
+ _, err = file.Read(b)
+
+ e, ok := err.(*PathError)
+ if !ok {
+ t.Fatalf("Read: %T(%v), want PathError", e, e)
+ }
+
+ if e.Err != ErrClosed {
+ t.Errorf("Read: %v, want PathError(ErrClosed)", e)
+ }
+}
+
func testReaddirnames(dir string, contents []string, t *testing.T) {
file, err := Open(dir)
if err != nil {
@@ -536,7 +559,7 @@ func TestReaddirStatFailures(t *testing.T) {
return s
}
- if got, want := names(mustReadDir("inital readdir")),
+ if got, want := names(mustReadDir("initial readdir")),
[]string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
t.Errorf("initial readdir got %q; want %q", got, want)
}
@@ -578,15 +601,8 @@ func TestReaddirOfFile(t *testing.T) {
}
func TestHardLink(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping on plan9, hardlinks not supported")
- }
- // From Android release M (Marshmallow), hard linking files is blocked
- // and an attempt to call link() on a file will return EACCES.
- // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
- if runtime.GOOS == "android" {
- t.Skip("skipping on android, hardlinks not supported")
- }
+ testenv.MustHaveLink(t)
+
defer chtmpdir(t)()
from, to := "hardlinktestfrom", "hardlinktestto"
Remove(from) // Just in case.
@@ -650,14 +666,8 @@ func chtmpdir(t *testing.T) func() {
}
func TestSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
+
defer chtmpdir(t)()
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -717,14 +727,8 @@ func TestSymlink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "plan9", "nacl":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
+
defer chtmpdir(t)()
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -840,6 +844,39 @@ func TestRenameFailed(t *testing.T) {
}
}
+func TestRenameToDirFailed(t *testing.T) {
+ defer chtmpdir(t)()
+ from, to := "renamefrom", "renameto"
+
+ Remove(from)
+ Remove(to)
+ Mkdir(from, 0777)
+ Mkdir(to, 0777)
+ defer Remove(from)
+ defer Remove(to)
+
+ err := Rename(from, to)
+ switch err := err.(type) {
+ case *LinkError:
+ if err.Op != "rename" {
+ t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
+ }
+ if err.Old != from {
+ t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
+ }
+ if err.New != to {
+ t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
+ }
+ case nil:
+ t.Errorf("rename %q, %q: expected error, got nil", from, to)
+
+ // cleanup whatever was placed in "renameto"
+ Remove(to)
+ default:
+ t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
+ }
+}
+
func exec(t *testing.T, dir, cmd string, args []string, expect string) {
r, w, err := Pipe()
if err != nil {
@@ -1028,7 +1065,7 @@ func testChtimes(t *testing.T, name string) {
}
if !pmt.Before(mt) {
- t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
+ t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt)
}
}
@@ -1180,14 +1217,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)
@@ -1273,15 +1310,19 @@ func TestOpenNoName(t *testing.T) {
}
}
-func run(t *testing.T, cmd []string) string {
+func runBinHostname(t *testing.T) string {
// Run /bin/hostname and collect output.
r, w, err := Pipe()
if err != nil {
t.Fatal(err)
}
defer r.Close()
- p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
+ const path = "/bin/hostname"
+ p, err := StartProcess(path, []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
if err != nil {
+ if _, err := Stat(path); IsNotExist(err) {
+ t.Skipf("skipping test; test requires %s but it does not exist", path)
+ }
t.Fatal(err)
}
w.Close()
@@ -1301,7 +1342,7 @@ func run(t *testing.T, cmd []string) string {
output = output[0 : n-1]
}
if output == "" {
- t.Fatalf("%v produced no output", cmd)
+ t.Fatalf("/bin/hostname produced no output")
}
return output
@@ -1343,7 +1384,7 @@ func TestHostname(t *testing.T) {
if err != nil {
t.Fatalf("%v", err)
}
- want := run(t, []string{"/bin/hostname"})
+ want := runBinHostname(t)
if hostname != want {
i := strings.Index(hostname, ".")
if i < 0 || hostname[0:i] != want {
@@ -1370,6 +1411,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())
@@ -1577,6 +1650,42 @@ func TestStatDirModeExec(t *testing.T) {
}
}
+func TestStatStdin(t *testing.T) {
+ switch runtime.GOOS {
+ case "android", "plan9":
+ t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
+ }
+
+ testenv.MustHaveExec(t)
+
+ if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+ st, err := Stdin.Stat()
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ fmt.Println(st.Mode() & ModeNamedPipe)
+ Exit(0)
+ }
+
+ var cmd *osexec.Cmd
+ if runtime.GOOS == "windows" {
+ cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
+ } else {
+ cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
+ }
+ cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
+
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
+ }
+
+ // result will be like "prw-rw-rw"
+ if len(output) < 1 || output[0] != 'p' {
+ t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
+ }
+}
+
func TestReadAtEOF(t *testing.T) {
f := newFile("TestReadAtEOF", t)
defer Remove(f.Name())
@@ -1593,6 +1702,72 @@ func TestReadAtEOF(t *testing.T) {
}
}
+func TestLongPath(t *testing.T) {
+ tmpdir := newDir("TestLongPath", t)
+ defer func(d string) {
+ if err := RemoveAll(d); err != nil {
+ t.Fatalf("RemoveAll failed: %v", err)
+ }
+ }(tmpdir)
+
+ // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted).
+ sizes := []int{247, 248, 249, 400}
+ for len(tmpdir) < 400 {
+ tmpdir += "/dir3456789"
+ }
+ for _, sz := range sizes {
+ t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
+ sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash.
+
+ // The various sized runs are for this call to trigger the boundary
+ // condition.
+ if err := MkdirAll(sizedTempDir, 0755); err != nil {
+ t.Fatalf("MkdirAll failed: %v", err)
+ }
+ data := []byte("hello world\n")
+ if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
+ t.Fatalf("ioutil.WriteFile() failed: %v", err)
+ }
+ if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
+ t.Fatalf("Rename failed: %v", err)
+ }
+ mtime := time.Now().Truncate(time.Minute)
+ if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
+ t.Fatalf("Chtimes failed: %v", err)
+ }
+ names := []string{"bar.txt"}
+ if testenv.HasSymlink() {
+ if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
+ t.Fatalf("Symlink failed: %v", err)
+ }
+ names = append(names, "symlink.txt")
+ }
+ if testenv.HasLink() {
+ if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
+ t.Fatalf("Link failed: %v", err)
+ }
+ names = append(names, "link.txt")
+ }
+ for _, wantSize := range []int64{int64(len(data)), 0} {
+ for _, name := range names {
+ path := sizedTempDir + "/" + name
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat(%q) failed: %v", path, err)
+ }
+ filesize := size(path, t)
+ if dir.Size() != filesize || filesize != wantSize {
+ t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
+ }
+ }
+ if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
+ t.Fatalf("Truncate failed: %v", err)
+ }
+ }
+ })
+ }
+}
+
func testKillProcess(t *testing.T, processKiller func(p *Process)) {
testenv.MustHaveExec(t)
@@ -1684,7 +1859,7 @@ var nilFileMethodTests = []struct {
{"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
{"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
{"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
- {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+ {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
{"Stat", func(f *File) error { _, err := f.Stat(); return err }},
{"Sync", func(f *File) error { return f.Sync() }},
{"Truncate", func(f *File) error { return f.Truncate(0) }},
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
index d02e07b478..e239835c6a 100644
--- a/libgo/go/os/os_unix_test.go
+++ b/libgo/go/os/os_unix_test.go
@@ -7,8 +7,12 @@
package os_test
import (
+ "io"
+ "io/ioutil"
. "os"
+ "path/filepath"
"runtime"
+ "strings"
"syscall"
"testing"
)
@@ -39,7 +43,7 @@ func TestChown(t *testing.T) {
}
// Use TempDir() to make sure we're on a local file system,
// so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
+ // on the file. On NFS, the Getgroups groups are
// basically useless.
f := newFile("TestChown", t)
defer Remove(f.Name())
@@ -50,7 +54,7 @@ func TestChown(t *testing.T) {
}
// Can't change uid unless root, but can try
- // changing the group id. First try our current group.
+ // changing the group id. First try our current group.
gid := Getgid()
t.Log("gid:", gid)
if err = Chown(f.Name(), -1, gid); err != nil {
@@ -86,7 +90,7 @@ func TestFileChown(t *testing.T) {
}
// Use TempDir() to make sure we're on a local file system,
// so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
+ // on the file. On NFS, the Getgroups groups are
// basically useless.
f := newFile("TestFileChown", t)
defer Remove(f.Name())
@@ -97,7 +101,7 @@ func TestFileChown(t *testing.T) {
}
// Can't change uid unless root, but can try
- // changing the group id. First try our current group.
+ // changing the group id. First try our current group.
gid := Getgid()
t.Log("gid:", gid)
if err = f.Chown(-1, gid); err != nil {
@@ -133,7 +137,7 @@ func TestLchown(t *testing.T) {
}
// Use TempDir() to make sure we're on a local file system,
// so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
+ // on the file. On NFS, the Getgroups groups are
// basically useless.
f := newFile("TestLchown", t)
defer Remove(f.Name())
@@ -145,12 +149,15 @@ 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)
// Can't change uid unless root, but can try
- // changing the group id. First try our current group.
+ // changing the group id. First try our current group.
gid := Getgid()
t.Log("gid:", gid)
if err = Lchown(linkname, -1, gid); err != nil {
@@ -175,3 +182,38 @@ func TestLchown(t *testing.T) {
checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid))
}
}
+
+// Issue 16919: Readdir must return a non-empty slice or an error.
+func TestReaddirRemoveRace(t *testing.T) {
+ oldStat := *LstatP
+ defer func() { *LstatP = oldStat }()
+ *LstatP = func(name string) (FileInfo, error) {
+ if strings.HasSuffix(name, "some-file") {
+ // Act like it's been deleted.
+ return nil, ErrNotExist
+ }
+ return oldStat(name)
+ }
+ dir := newDir("TestReaddirRemoveRace", t)
+ defer RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil {
+ t.Fatal(err)
+ }
+ d, err := Open(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer d.Close()
+ fis, err := d.Readdir(2) // notably, greater than zero
+ if len(fis) == 0 && err == nil {
+ // This is what used to happen (Issue 16919)
+ t.Fatal("Readdir = empty slice & err == nil")
+ }
+ if len(fis) != 0 || err != io.EOF {
+ t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err)
+ for i, fi := range fis {
+ t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode())
+ }
+ t.FailNow()
+ }
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index 84a3be3348..146d7b6954 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -61,7 +61,7 @@ func MkdirAll(path string, perm FileMode) error {
// RemoveAll removes path and any children it contains.
// It removes everything it can but returns the first error
-// it encounters. If the path does not exist, RemoveAll
+// it encounters. If the path does not exist, RemoveAll
// returns nil (no error).
func RemoveAll(path string) error {
// Simple case: if Remove works, we're done.
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index b4531314d0..6f5bfa54f8 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -5,6 +5,7 @@
package os_test
import (
+ "internal/testenv"
"io/ioutil"
. "os"
"path/filepath"
@@ -147,7 +148,7 @@ func TestRemoveAll(t *testing.T) {
// No error checking here: either RemoveAll
// will or won't be able to remove dpath;
// either way we want to see if it removes fpath
- // and path/zzz. Reasons why RemoveAll might
+ // and path/zzz. Reasons why RemoveAll might
// succeed in removing dpath as well include:
// * running as root
// * running on a file system without permissions (FAT)
@@ -169,14 +170,7 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
if err != nil {
diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go
index 36f8e61bf9..ecf098c461 100644
--- a/libgo/go/os/path_unix.go
+++ b/libgo/go/os/path_unix.go
@@ -15,3 +15,21 @@ const (
func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
+
+// basename removes trailing slashes and the leading directory name from path name
+func basename(name string) string {
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && name[i] == '/'; i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
+ if name[i] == '/' {
+ name = name[i+1:]
+ break
+ }
+ }
+
+ return name
+}
diff --git a/libgo/go/os/path_windows.go b/libgo/go/os/path_windows.go
index c96f137686..101b026dc9 100644
--- a/libgo/go/os/path_windows.go
+++ b/libgo/go/os/path_windows.go
@@ -14,3 +14,196 @@ func IsPathSeparator(c uint8) bool {
// NOTE: Windows accept / as path separator.
return c == '\\' || c == '/'
}
+
+// basename removes trailing slashes and the leading
+// directory name and drive letter from path name.
+func basename(name string) string {
+ // Remove drive letter
+ if len(name) == 2 && name[1] == ':' {
+ name = "."
+ } else if len(name) > 2 && name[1] == ':' {
+ name = name[2:]
+ }
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
+ if name[i] == '/' || name[i] == '\\' {
+ name = name[i+1:]
+ break
+ }
+ }
+ return name
+}
+
+func isAbs(path string) (b bool) {
+ v := volumeName(path)
+ if v == "" {
+ return false
+ }
+ path = path[len(v):]
+ if path == "" {
+ return false
+ }
+ return IsPathSeparator(path[0])
+}
+
+func volumeName(path string) (v string) {
+ if len(path) < 2 {
+ return ""
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' &&
+ ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z') {
+ return path[:2]
+ }
+ // is it UNC
+ if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
+ !IsPathSeparator(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if IsPathSeparator(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !IsPathSeparator(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if IsPathSeparator(path[n]) {
+ break
+ }
+ }
+ return path[:n]
+ }
+ break
+ }
+ }
+ }
+ return ""
+}
+
+func fromSlash(path string) string {
+ // Replace each '/' with '\\' if present
+ var pathbuf []byte
+ var lastSlash int
+ for i, b := range path {
+ if b == '/' {
+ if pathbuf == nil {
+ pathbuf = make([]byte, len(path))
+ }
+ copy(pathbuf[lastSlash:], path[lastSlash:i])
+ pathbuf[i] = '\\'
+ lastSlash = i + 1
+ }
+ }
+ if pathbuf == nil {
+ return path
+ }
+
+ copy(pathbuf[lastSlash:], path[lastSlash:])
+ return string(pathbuf)
+}
+
+func dirname(path string) string {
+ vol := volumeName(path)
+ i := len(path) - 1
+ for i >= len(vol) && !IsPathSeparator(path[i]) {
+ i--
+ }
+ dir := path[len(vol) : i+1]
+ last := len(dir) - 1
+ if last > 0 && IsPathSeparator(dir[last]) {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return vol + dir
+}
+
+// fixLongPath returns the extended-length (\\?\-prefixed) form of
+// path when needed, in order to avoid the default 260 character file
+// path limit imposed by Windows. If path is not easily converted to
+// the extended-length form (for example, if path is a relative path
+// or contains .. elements), or is short enough, fixLongPath returns
+// path unmodified.
+//
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
+func fixLongPath(path string) string {
+ // Do nothing (and don't allocate) if the path is "short".
+ // Empirically (at least on the Windows Server 2013 builder),
+ // the kernel is arbitrarily okay with < 248 bytes. That
+ // matches what the docs above say:
+ // "When using an API to create a directory, the specified
+ // path cannot be so long that you cannot append an 8.3 file
+ // name (that is, the directory name cannot exceed MAX_PATH
+ // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
+ //
+ // The MSDN docs appear to say that a normal path that is 248 bytes long
+ // will work; empirically the path must be less then 248 bytes long.
+ if len(path) < 248 {
+ // Don't fix. (This is how Go 1.7 and earlier worked,
+ // not automatically generating the \\?\ form)
+ return path
+ }
+
+ // The extended form begins with \\?\, as in
+ // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
+ // The extended form disables evaluation of . and .. path
+ // elements and disables the interpretation of / as equivalent
+ // to \. The conversion here rewrites / to \ and elides
+ // . elements as well as trailing or duplicate separators. For
+ // simplicity it avoids the conversion entirely for relative
+ // paths or paths containing .. elements. For now,
+ // \\server\share paths are not converted to
+ // \\?\UNC\server\share paths because the rules for doing so
+ // are less well-specified.
+ if len(path) >= 2 && path[:2] == `\\` {
+ // Don't canonicalize UNC paths.
+ return path
+ }
+ if !isAbs(path) {
+ // Relative path
+ return path
+ }
+
+ const prefix = `\\?`
+
+ pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
+ copy(pathbuf, prefix)
+ n := len(path)
+ r, w := 0, len(prefix)
+ for r < n {
+ switch {
+ case IsPathSeparator(path[r]):
+ // empty block
+ r++
+ case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
+ // /./
+ r++
+ case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
+ // /../ is currently unhandled
+ return path
+ default:
+ pathbuf[w] = '\\'
+ w++
+ for ; r < n && !IsPathSeparator(path[r]); r++ {
+ pathbuf[w] = path[r]
+ w++
+ }
+ }
+ }
+ // A drive's root directory needs a trailing \
+ if w == len(`\\?\c:`) {
+ pathbuf[w] = '\\'
+ w++
+ }
+ return string(pathbuf[:w])
+}
diff --git a/libgo/go/os/path_windows_test.go b/libgo/go/os/path_windows_test.go
new file mode 100644
index 0000000000..cce0bdd522
--- /dev/null
+++ b/libgo/go/os/path_windows_test.go
@@ -0,0 +1,46 @@
+// 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 os_test
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestFixLongPath(t *testing.T) {
+ // 248 is long enough to trigger the longer-than-248 checks in
+ // fixLongPath, but short enough not to make a path component
+ // longer than 255, which is illegal on Windows. (which
+ // doesn't really matter anyway, since this is purely a string
+ // function we're testing, and it's not actually being used to
+ // do a system call)
+ veryLong := "l" + strings.Repeat("o", 248) + "ng"
+ for _, test := range []struct{ in, want string }{
+ // Short; unchanged:
+ {`C:\short.txt`, `C:\short.txt`},
+ {`C:\`, `C:\`},
+ {`C:`, `C:`},
+ // The "long" substring is replaced by a looooooong
+ // string which triggers the rewriting. Except in the
+ // cases below where it doesn't.
+ {`C:\long\foo.txt`, `\\?\C:\long\foo.txt`},
+ {`C:/long/foo.txt`, `\\?\C:\long\foo.txt`},
+ {`C:\long\foo\\bar\.\baz\\`, `\\?\C:\long\foo\bar\baz`},
+ {`\\unc\path`, `\\unc\path`},
+ {`long.txt`, `long.txt`},
+ {`C:long.txt`, `C:long.txt`},
+ {`c:\long\..\bar\baz`, `c:\long\..\bar\baz`},
+ {`\\?\c:\long\foo.txt`, `\\?\c:\long\foo.txt`},
+ {`\\?\c:\long/foo.txt`, `\\?\c:\long/foo.txt`},
+ } {
+ in := strings.Replace(test.in, "long", veryLong, -1)
+ want := strings.Replace(test.want, "long", veryLong, -1)
+ if got := os.FixLongPath(in); got != want {
+ got = strings.Replace(got, veryLong, "long", -1)
+ t.Errorf("fixLongPath(%q) = %q; want %q", test.in, got, test.want)
+ }
+ }
+}
diff --git a/libgo/go/os/pipe_test.go b/libgo/go/os/pipe_test.go
index 82b792eac4..74cce80ee4 100644
--- a/libgo/go/os/pipe_test.go
+++ b/libgo/go/os/pipe_test.go
@@ -88,7 +88,7 @@ func TestStdPipe(t *testing.T) {
}
}
-// This is a helper for TestStdPipe. It's not a test in itself.
+// This is a helper for TestStdPipe. It's not a test in itself.
func TestStdPipeHelper(t *testing.T) {
if os.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" {
signal.Notify(make(chan os.Signal, 1), syscall.SIGPIPE)
diff --git a/libgo/go/os/signal/doc.go b/libgo/go/os/signal/doc.go
index 80e66cffe5..73b01a2764 100644
--- a/libgo/go/os/signal/doc.go
+++ b/libgo/go/os/signal/doc.go
@@ -11,7 +11,7 @@ package on Windows and Plan 9, see below.
Types of signals
The signals SIGKILL and SIGSTOP may not be caught by a program, and
-therefore can not be affected by this package.
+therefore cannot be affected by this package.
Synchronous signals are signals triggered by errors in program
execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered
@@ -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.
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
index 2e6f186658..c1376daaea 100644
--- a/libgo/go/os/signal/signal.go
+++ b/libgo/go/os/signal/signal.go
@@ -79,7 +79,7 @@ func Ignore(sig ...os.Signal) {
//
// Package signal will not block sending to c: the caller must ensure
// that c has sufficient buffer space to keep up with the expected
-// signal rate. For a channel used for notification of just one signal value,
+// signal rate. For a channel used for notification of just one signal value,
// a buffer of size 1 is sufficient.
//
// It is allowed to call Notify multiple times with the same channel:
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
index 56d786e501..406102c663 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.go
@@ -139,6 +139,19 @@ func testCancel(t *testing.T, ignore bool) {
Reset(syscall.SIGWINCH, syscall.SIGHUP)
}
+ // At this point we do not expect any further signals on c1.
+ // However, it is just barely possible that the initial SIGWINCH
+ // at the start of this function was delivered after we called
+ // Notify on c1. In that case the waitSig for SIGWINCH may have
+ // picked up that initial SIGWINCH, and the second SIGWINCH may
+ // then have been delivered on the channel. This sequence of events
+ // may have caused issue 15661.
+ // So, read any possible signal from the channel now.
+ select {
+ case <-c1:
+ default:
+ }
+
// Send this process a SIGWINCH. It should be ignored.
syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go
index 9758d33496..59cac9c7ce 100644
--- a/libgo/go/os/stat.go
+++ b/libgo/go/os/stat.go
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !darwin
+// +build !freebsd
+// +build !linux
+// +build !netbsd
+// +build !openbsd
+// +build !solaris
+
package os
import (
diff --git a/libgo/go/os/stat_atim.go b/libgo/go/os/stat_atim.go
index 69e63230eb..ef8a574e7b 100644
--- a/libgo/go/os/stat_atim.go
+++ b/libgo/go/os/stat_atim.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux openbsd solaristag
+
package os
import (
diff --git a/libgo/go/os/stat_atimespec.go b/libgo/go/os/stat_atimespec.go
index 9dc7a99fb7..c6ce2bc8f4 100644
--- a/libgo/go/os/stat_atimespec.go
+++ b/libgo/go/os/stat_atimespec.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd netbsd
+
package os
import (
diff --git a/libgo/go/os/stat_dragonfly.go b/libgo/go/os/stat_dragonfly.go
index 69e63230eb..217bc6726d 100644
--- a/libgo/go/os/stat_dragonfly.go
+++ b/libgo/go/os/stat_dragonfly.go
@@ -11,7 +11,7 @@ import (
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
- fs.size = int64(fs.sys.Size)
+ fs.size = fs.sys.Size
fs.modTime = timespecToTime(fs.sys.Mtim)
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
@@ -42,7 +42,7 @@ func fillFileStatFromSys(fs *fileStat, name string) {
}
func timespecToTime(ts syscall.Timespec) time.Time {
- return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+ return time.Unix(ts.Sec, ts.Nsec)
}
// For testing.
diff --git a/libgo/go/os/stat_nacl.go b/libgo/go/os/stat_nacl.go
index d3bed14e43..0c53f2faa4 100644
--- a/libgo/go/os/stat_nacl.go
+++ b/libgo/go/os/stat_nacl.go
@@ -11,7 +11,7 @@ import (
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
- fs.size = int64(fs.sys.Size)
+ fs.size = fs.sys.Size
fs.modTime = timespecToTime(fs.sys.Mtime, fs.sys.MtimeNsec)
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go
index fa4bd83aef..274d0d86f3 100644
--- a/libgo/go/os/stat_plan9.go
+++ b/libgo/go/os/stat_plan9.go
@@ -11,16 +11,10 @@ import (
const _BIT16SZ = 2
-func sameFile(fs1, fs2 *fileStat) bool {
- a := fs1.sys.(*syscall.Dir)
- b := fs2.sys.(*syscall.Dir)
- return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
-}
-
func fileInfoFromStat(d *syscall.Dir) FileInfo {
fs := &fileStat{
name: d.Name,
- size: int64(d.Length),
+ size: d.Length,
modTime: time.Unix(int64(d.Mtime), 0),
sys: d,
}
@@ -37,6 +31,10 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo {
if d.Mode&syscall.DMTMP != 0 {
fs.mode |= ModeTemporary
}
+ // Consider all files not served by #M as device files.
+ if d.Type != 'M' {
+ fs.mode |= ModeDevice
+ }
return fs
}
@@ -100,7 +98,7 @@ func Stat(name string) (FileInfo, error) {
// Lstat returns a FileInfo describing the named file.
// If the file is a symbolic link, the returned FileInfo
-// describes the symbolic link. Lstat makes no attempt to follow the link.
+// describes the symbolic link. Lstat makes no attempt to follow the link.
// If there is an error, it will be of type *PathError.
func Lstat(name string) (FileInfo, error) {
return Stat(name)
diff --git a/libgo/go/os/stat_solaris.go b/libgo/go/os/stat_solaris.go
index aad429dcb9..1f1b4ab825 100644
--- a/libgo/go/os/stat_solaris.go
+++ b/libgo/go/os/stat_solaris.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !solaristag
+
package os
import (
diff --git a/libgo/go/os/stat_unix.go b/libgo/go/os/stat_unix.go
new file mode 100644
index 0000000000..1733d3f132
--- /dev/null
+++ b/libgo/go/os/stat_unix.go
@@ -0,0 +1,52 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package os
+
+import (
+ "syscall"
+)
+
+// Stat returns the FileInfo structure describing file.
+// If there is an error, it will be of type *PathError.
+func (f *File) Stat() (FileInfo, error) {
+ if f == nil {
+ return nil, ErrInvalid
+ }
+ var fs fileStat
+ err := syscall.Fstat(f.fd, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"stat", f.name, err}
+ }
+ fillFileStatFromSys(&fs, f.name)
+ return &fs, nil
+}
+
+// Stat returns a FileInfo describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(name string) (FileInfo, error) {
+ var fs fileStat
+ err := syscall.Stat(name, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"stat", name, err}
+ }
+ fillFileStatFromSys(&fs, name)
+ return &fs, nil
+}
+
+// Lstat returns a FileInfo describing the named file.
+// If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+// If there is an error, it will be of type *PathError.
+func Lstat(name string) (FileInfo, error) {
+ var fs fileStat
+ err := syscall.Lstat(name, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"lstat", name, err}
+ }
+ fillFileStatFromSys(&fs, name)
+ return &fs, nil
+}
diff --git a/libgo/go/os/str.go b/libgo/go/os/str.go
index d3e03e9849..cba9fa3e8d 100644
--- a/libgo/go/os/str.go
+++ b/libgo/go/os/str.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Simple converions to avoid depending on strconv.
+// Simple conversions to avoid depending on strconv.
package os
diff --git a/libgo/go/os/sys.go b/libgo/go/os/sys.go
new file mode 100644
index 0000000000..28b0f6bab0
--- /dev/null
+++ b/libgo/go/os/sys.go
@@ -0,0 +1,10 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err error) {
+ return hostname()
+}
diff --git a/libgo/go/os/sys_uname.go b/libgo/go/os/sys_uname.go
index 16568b69f4..71fa867595 100644
--- a/libgo/go/os/sys_uname.go
+++ b/libgo/go/os/sys_uname.go
@@ -4,6 +4,8 @@
// For systems which only store the hostname in uname (Solaris).
+// +build solaris irix rtems
+
package os
import "syscall"
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
index 9d6f8e13d6..c56548353f 100644
--- a/libgo/go/os/types.go
+++ b/libgo/go/os/types.go
@@ -12,6 +12,11 @@ import (
// Getpagesize returns the underlying system's memory page size.
func Getpagesize() int { return syscall.Getpagesize() }
+// File represents an open file descriptor.
+type File struct {
+ *file // os specific
+}
+
// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
Name() string // base name of the file
@@ -25,7 +30,7 @@ type FileInfo interface {
// A FileMode represents a file's mode and permission bits.
// The bits have the same definition on all systems, so that
// information about files can be moved from one system
-// to another portably. Not all bits apply to all systems.
+// to another portably. Not all bits apply to all systems.
// The only required bit is ModeDir for directories.
type FileMode uint32
diff --git a/libgo/go/os/types_plan9.go b/libgo/go/os/types_plan9.go
index 6d46ca9dd3..125da661b7 100644
--- a/libgo/go/os/types_plan9.go
+++ b/libgo/go/os/types_plan9.go
@@ -4,7 +4,10 @@
package os
-import "time"
+import (
+ "syscall"
+ "time"
+)
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
type fileStat struct {
@@ -19,3 +22,11 @@ func (fs *fileStat) Size() int64 { return fs.size }
func (fs *fileStat) Mode() FileMode { return fs.mode }
func (fs *fileStat) ModTime() time.Time { return fs.modTime }
func (fs *fileStat) Sys() interface{} { return fs.sys }
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ a := fs1.sys.(*syscall.Dir)
+ b := fs2.sys.(*syscall.Dir)
+ return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
+}
+
+const badFd = -1
diff --git a/libgo/go/os/types_unix.go b/libgo/go/os/types_unix.go
index 056220c09b..1f614812fd 100644
--- a/libgo/go/os/types_unix.go
+++ b/libgo/go/os/types_unix.go
@@ -25,3 +25,9 @@ func (fs *fileStat) Size() int64 { return fs.size }
func (fs *fileStat) Mode() FileMode { return fs.mode }
func (fs *fileStat) ModTime() time.Time { return fs.modTime }
func (fs *fileStat) Sys() interface{} { return &fs.sys }
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
+}
+
+const badFd = -1
diff --git a/libgo/go/os/types_windows.go b/libgo/go/os/types_windows.go
index 7b2e54698c..ad4e863fcb 100644
--- a/libgo/go/os/types_windows.go
+++ b/libgo/go/os/types_windows.go
@@ -14,6 +14,7 @@ import (
type fileStat struct {
name string
sys syscall.Win32FileAttributeData
+ pipe bool
// used to implement SameFile
sync.Mutex
@@ -42,6 +43,9 @@ func (fs *fileStat) Mode() (m FileMode) {
if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
m |= ModeSymlink
}
+ if fs.pipe {
+ m |= ModeNamedPipe
+ }
return m
}
@@ -69,7 +73,7 @@ func (fs *fileStat) loadFileId() error {
}
defer syscall.CloseHandle(h)
var i syscall.ByHandleFileInformation
- err = syscall.GetFileInformationByHandle(syscall.Handle(h), &i)
+ err = syscall.GetFileInformationByHandle(h, &i)
if err != nil {
return err
}
diff --git a/libgo/go/os/user/decls_solaris.go b/libgo/go/os/user/decls_solaris.go
index 788a00f066..ccdf36b13d 100644
--- a/libgo/go/os/user/decls_solaris.go
+++ b/libgo/go/os/user/decls_solaris.go
@@ -16,3 +16,9 @@ func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.
//extern __posix_getpwuid_r
func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
+
+//extern __posix_getgrnam_r
+func libc_getgrnam_r(name *byte, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
+
+//extern __posix_getgrgid_r
+func libc_getgrgid_r(gid syscall.Gid_t, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
diff --git a/libgo/go/os/user/decls_unix.go b/libgo/go/os/user/decls_unix.go
index f76e4c9bdf..c2eb51e5bb 100644
--- a/libgo/go/os/user/decls_unix.go
+++ b/libgo/go/os/user/decls_unix.go
@@ -16,3 +16,12 @@ func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.
//extern getpwuid_r
func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
+
+//extern getgrnam_r
+func libc_getgrnam_r(name *byte, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
+
+//extern getgrgid_r
+func libc_getgrgid_r(gid syscall.Gid_t, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
+
+//extern getgrouplist
+func libc_getgrouplist(user *byte, group syscall.Gid_t, groups *syscall.Gid_t, ngroups *int32) int
diff --git a/libgo/go/os/user/listgroups_solaris.go b/libgo/go/os/user/listgroups_solaris.go
new file mode 100644
index 0000000000..28a8a78dbb
--- /dev/null
+++ b/libgo/go/os/user/listgroups_solaris.go
@@ -0,0 +1,17 @@
+// 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 cgo
+
+// Even though this file requires no C, it is used to provide a
+// listGroup stub because all the other Solaris calls work. Otherwise,
+// this stub will conflict with the lookup_stubs.go fallback.
+
+package user
+
+import "fmt"
+
+func listGroups(u *User) ([]string, error) {
+ return nil, fmt.Errorf("user: list groups for %s: not supported on Solaris", u.Username)
+}
diff --git a/libgo/go/os/user/listgroups_unix.go b/libgo/go/os/user/listgroups_unix.go
new file mode 100644
index 0000000000..8b2b13d563
--- /dev/null
+++ b/libgo/go/os/user/listgroups_unix.go
@@ -0,0 +1,57 @@
+// 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 darwin freebsd !android,linux netbsd openbsd
+
+package user
+
+import (
+ "fmt"
+ "strconv"
+ "syscall"
+)
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+*/
+
+func listGroups(u *User) ([]string, error) {
+ ug, err := strconv.Atoi(u.Gid)
+ if err != nil {
+ return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
+ }
+ userGID := syscall.Gid_t(ug)
+ nameC, err := syscall.BytePtrFromString(u.Username)
+ if err != nil {
+ return nil, fmt.Errorf("user: invalid user name %q: %v", strconv.Quote(u.Username), err)
+ }
+
+ n := int32(256)
+ gidsC := make([]syscall.Gid_t, n)
+ syscall.Entersyscall()
+ rv := libc_getgrouplist(nameC, userGID, &gidsC[0], &n)
+ syscall.Exitsyscall()
+ if rv == -1 {
+ // More than initial buffer, but now n contains the correct size.
+ const maxGroups = 2048
+ if n > maxGroups {
+ return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
+ }
+ gidsC = make([]syscall.Gid_t, n)
+ syscall.Entersyscall()
+ rv := libc_getgrouplist(nameC, userGID, &gidsC[0], &n)
+ syscall.Exitsyscall()
+ if rv == -1 {
+ return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
+ }
+ }
+ gidsC = gidsC[:n]
+ gids := make([]string, 0, n)
+ for _, g := range gidsC[:n] {
+ gids = append(gids, strconv.Itoa(int(g)))
+ }
+ return gids, nil
+}
diff --git a/libgo/go/os/user/lookup.go b/libgo/go/os/user/lookup.go
index 09f00c7bdb..3b4421badd 100644
--- a/libgo/go/os/user/lookup.go
+++ b/libgo/go/os/user/lookup.go
@@ -12,11 +12,28 @@ func Current() (*User, error) {
// Lookup looks up a user by username. If the user cannot be found, the
// returned error is of type UnknownUserError.
func Lookup(username string) (*User, error) {
- return lookup(username)
+ return lookupUser(username)
}
// LookupId looks up a user by userid. If the user cannot be found, the
// returned error is of type UnknownUserIdError.
func LookupId(uid string) (*User, error) {
- return lookupId(uid)
+ return lookupUserId(uid)
+}
+
+// LookupGroup looks up a group by name. If the group cannot be found, the
+// returned error is of type UnknownGroupError.
+func LookupGroup(name string) (*Group, error) {
+ return lookupGroup(name)
+}
+
+// LookupGroupId looks up a group by groupid. If the group cannot be found, the
+// returned error is of type UnknownGroupIdError.
+func LookupGroupId(gid string) (*Group, error) {
+ return lookupGroupId(gid)
+}
+
+// GroupIds returns the list of group IDs that the user is a member of.
+func (u *User) GroupIds() ([]string, error) {
+ return listGroups(u)
}
diff --git a/libgo/go/os/user/lookup_android.go b/libgo/go/os/user/lookup_android.go
new file mode 100644
index 0000000000..b1be3dc193
--- /dev/null
+++ b/libgo/go/os/user/lookup_android.go
@@ -0,0 +1,38 @@
+// 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 android
+
+package user
+
+import "errors"
+
+func init() {
+ userImplemented = false
+ groupImplemented = false
+}
+
+func current() (*User, error) {
+ return nil, errors.New("user: Current not implemented on android")
+}
+
+func lookupUser(string) (*User, error) {
+ return nil, errors.New("user: Lookup not implemented on android")
+}
+
+func lookupUserId(string) (*User, error) {
+ return nil, errors.New("user: LookupId not implemented on android")
+}
+
+func lookupGroup(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroup not implemented on android")
+}
+
+func lookupGroupId(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroupId not implemented on android")
+}
+
+func listGroups(*User) ([]string, error) {
+ return nil, errors.New("user: GroupIds not implemented on android")
+}
diff --git a/libgo/go/os/user/lookup_plan9.go b/libgo/go/os/user/lookup_plan9.go
index f7ef3482b7..ea3ce0bc7c 100644
--- a/libgo/go/os/user/lookup_plan9.go
+++ b/libgo/go/os/user/lookup_plan9.go
@@ -18,6 +18,10 @@ const (
userFile = "/dev/user"
)
+func init() {
+ groupImplemented = false
+}
+
func current() (*User, error) {
ubytes, err := ioutil.ReadFile(userFile)
if err != nil {
@@ -37,10 +41,22 @@ func current() (*User, error) {
return u, nil
}
-func lookup(username string) (*User, error) {
+func lookupUser(username string) (*User, error) {
+ return nil, syscall.EPLAN9
+}
+
+func lookupUserId(uid string) (*User, error) {
+ return nil, syscall.EPLAN9
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+ return nil, syscall.EPLAN9
+}
+
+func lookupGroupId(string) (*Group, error) {
return nil, syscall.EPLAN9
}
-func lookupId(uid string) (*User, error) {
+func listGroups(*User) ([]string, error) {
return nil, syscall.EPLAN9
}
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index 4fb0e3c6ed..ebf24f79de 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.go
@@ -2,27 +2,83 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo,!windows,!plan9 android
+// +build !cgo,!windows,!plan9,!android
package user
import (
+ "errors"
"fmt"
+ "os"
"runtime"
+ "strconv"
)
func init() {
- implemented = false
+ userImplemented = false
+ groupImplemented = false
}
func current() (*User, error) {
- return nil, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+ u := &User{
+ Uid: currentUID(),
+ Gid: currentGID(),
+ Username: os.Getenv("USER"),
+ Name: "", // ignored
+ HomeDir: os.Getenv("HOME"),
+ }
+ if runtime.GOOS == "nacl" {
+ if u.Uid == "" {
+ u.Uid = "1"
+ }
+ if u.Username == "" {
+ u.Username = "nacl"
+ }
+ if u.HomeDir == "" {
+ u.HomeDir = "/home/nacl"
+ }
+ }
+ // cgo isn't available, but if we found the minimum information
+ // without it, use it:
+ if u.Uid != "" && u.Username != "" && u.HomeDir != "" {
+ return u, nil
+ }
+ return u, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
-func lookup(username string) (*User, error) {
- return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+func lookupUser(username string) (*User, error) {
+ return nil, errors.New("user: Lookup requires cgo")
}
-func lookupId(uid string) (*User, error) {
- return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+func lookupUserId(uid string) (*User, error) {
+ return nil, errors.New("user: LookupId requires cgo")
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+ return nil, errors.New("user: LookupGroup requires cgo")
+}
+
+func lookupGroupId(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroupId requires cgo")
+}
+
+func listGroups(*User) ([]string, error) {
+ return nil, errors.New("user: GroupIds requires cgo")
+}
+
+func currentUID() string {
+ if id := os.Getuid(); id >= 0 {
+ return strconv.Itoa(id)
+ }
+ // Note: Windows returns -1, but this file isn't used on
+ // Windows anyway, so this empty return path shouldn't be
+ // used.
+ return ""
+}
+
+func currentGID() string {
+ if id := os.Getgid(); id >= 0 {
+ return strconv.Itoa(id)
+ }
+ return ""
}
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index bebb9e8f2b..8881366cf9 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -15,24 +15,6 @@ import (
"unsafe"
)
-/*
-#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
-#include <unistd.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <stdlib.h>
-
-static int mygetpwuid_r(int uid, struct passwd *pwd,
- char *buf, size_t buflen, struct passwd **result) {
- return getpwuid_r(uid, pwd, buf, buflen, result);
-}
-
-static int mygetpwnam_r(const char *name, struct passwd *pwd,
- char *buf, size_t buflen, struct passwd **result) {
- return getpwnam_r(name, pwd, buf, buflen, result);
-}
-*/
-
// bytePtrToString takes a NUL-terminated array of bytes and convert
// it to a Go string.
func bytePtrToString(p *byte) string {
@@ -45,58 +27,77 @@ func bytePtrToString(p *byte) string {
}
func current() (*User, error) {
- return lookupUnix(syscall.Getuid(), "", false)
+ return lookupUnixUid(syscall.Getuid())
}
-func lookup(username string) (*User, error) {
- return lookupUnix(-1, username, true)
+func lookupUser(username string) (*User, error) {
+ var pwd syscall.Passwd
+ var result *syscall.Passwd
+ p := syscall.StringBytePtr(username)
+
+ buf := alloc(userBuffer)
+ defer buf.free()
+
+ err := retryWithBuffer(buf, func() syscall.Errno {
+ syscall.Entersyscall()
+ rv := libc_getpwnam_r(p,
+ &pwd,
+ buf.ptr,
+ buf.size,
+ &result)
+ syscall.Exitsyscall()
+ if rv != 0 {
+ return syscall.GetErrno()
+ }
+ return 0
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
+ }
+ if result == nil {
+ return nil, UnknownUserError(username)
+ }
+ return buildUser(&pwd), err
}
-func lookupId(uid string) (*User, error) {
+func lookupUserId(uid string) (*User, error) {
i, e := strconv.Atoi(uid)
if e != nil {
return nil, e
}
- return lookupUnix(i, "", false)
+ return lookupUnixUid(i)
}
-func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
+func lookupUnixUid(uid int) (*User, error) {
var pwd syscall.Passwd
var result *syscall.Passwd
- // FIXME: Should let buf grow if necessary.
- const bufSize = 1024
- buf := make([]byte, bufSize)
- if lookupByName {
- nameC := syscall.StringBytePtr(username)
- syscall.Entersyscall()
- rv := libc_getpwnam_r(nameC,
- &pwd,
- &buf[0],
- bufSize,
- &result)
- syscall.Exitsyscall()
- if rv != 0 {
- return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
- }
- if result == nil {
- return nil, UnknownUserError(username)
- }
- } else {
+ buf := alloc(userBuffer)
+ defer buf.free()
+
+ err := retryWithBuffer(buf, func() syscall.Errno {
syscall.Entersyscall()
rv := libc_getpwuid_r(syscall.Uid_t(uid),
&pwd,
- &buf[0],
- bufSize,
+ buf.ptr,
+ buf.size,
&result)
syscall.Exitsyscall()
if rv != 0 {
- return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
- }
- if result == nil {
- return nil, UnknownUserIdError(uid)
+ return syscall.GetErrno()
}
+ return 0
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
+ }
+ if result == nil {
+ return nil, UnknownUserIdError(uid)
}
+ return buildUser(&pwd), nil
+}
+
+func buildUser(pwd *syscall.Passwd) *User {
u := &User{
Uid: strconv.Itoa(int(pwd.Pw_uid)),
Gid: strconv.Itoa(int(pwd.Pw_gid)),
@@ -104,12 +105,162 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
Name: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
HomeDir: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
}
- // The pw_gecos field isn't quite standardized. Some docs
+ // The pw_gecos field isn't quite standardized. Some docs
// say: "It is expected to be a comma separated list of
// personal data where the first item is the full name of the
// user."
if i := strings.Index(u.Name, ","); i >= 0 {
u.Name = u.Name[:i]
}
- return u, nil
+ return u
+}
+
+func currentGroup() (*Group, error) {
+ return lookupUnixGid(syscall.Getgid())
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+ var grp syscall.Group
+ var result *syscall.Group
+
+ buf := alloc(groupBuffer)
+ defer buf.free()
+ p := syscall.StringBytePtr(groupname)
+
+ err := retryWithBuffer(buf, func() syscall.Errno {
+ syscall.Entersyscall()
+ rv := libc_getgrnam_r(p,
+ &grp,
+ buf.ptr,
+ buf.size,
+ &result)
+ syscall.Exitsyscall()
+ if rv != 0 {
+ return syscall.GetErrno()
+ }
+ return 0
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
+ }
+ if result == nil {
+ return nil, UnknownGroupError(groupname)
+ }
+ return buildGroup(&grp), nil
+}
+
+func lookupGroupId(gid string) (*Group, error) {
+ i, e := strconv.Atoi(gid)
+ if e != nil {
+ return nil, e
+ }
+ return lookupUnixGid(i)
+}
+
+func lookupUnixGid(gid int) (*Group, error) {
+ var grp syscall.Group
+ var result *syscall.Group
+
+ buf := alloc(groupBuffer)
+ defer buf.free()
+
+ err := retryWithBuffer(buf, func() syscall.Errno {
+ syscall.Entersyscall()
+ rv := libc_getgrgid_r(syscall.Gid_t(gid),
+ &grp,
+ buf.ptr,
+ buf.size,
+ &result)
+ syscall.Exitsyscall()
+ if rv != 0 {
+ return syscall.GetErrno()
+ }
+ return 0
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
+ }
+ if result == nil {
+ return nil, UnknownGroupIdError(strconv.Itoa(gid))
+ }
+ return buildGroup(&grp), nil
+}
+
+func buildGroup(grp *syscall.Group) *Group {
+ g := &Group{
+ Gid: strconv.Itoa(int(grp.Gr_gid)),
+ Name: bytePtrToString((*byte)(unsafe.Pointer(grp.Gr_name))),
+ }
+ return g
+}
+
+type bufferKind int
+
+const (
+ userBuffer = bufferKind(syscall.SC_GETPW_R_SIZE_MAX)
+ groupBuffer = bufferKind(syscall.SC_GETGR_R_SIZE_MAX)
+)
+
+func (k bufferKind) initialSize() syscall.Size_t {
+ sz, _ := syscall.Sysconf(int(k))
+ if sz == -1 {
+ // DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
+ // Additionally, not all Linux systems have it, either. For
+ // example, the musl libc returns -1.
+ return 1024
+ }
+ if !isSizeReasonable(int64(sz)) {
+ // Truncate. If this truly isn't enough, retryWithBuffer will error on the first run.
+ return maxBufferSize
+ }
+ return syscall.Size_t(sz)
+}
+
+type memBuffer struct {
+ ptr *byte
+ size syscall.Size_t
+}
+
+func alloc(kind bufferKind) *memBuffer {
+ sz := kind.initialSize()
+ b := make([]byte, sz)
+ return &memBuffer{
+ ptr: &b[0],
+ size: sz,
+ }
+}
+
+func (mb *memBuffer) resize(newSize syscall.Size_t) {
+ b := make([]byte, newSize)
+ mb.ptr = &b[0]
+ mb.size = newSize
+}
+
+func (mb *memBuffer) free() {
+ mb.ptr = nil
+}
+
+// retryWithBuffer repeatedly calls f(), increasing the size of the
+// buffer each time, until f succeeds, fails with a non-ERANGE error,
+// or the buffer exceeds a reasonable limit.
+func retryWithBuffer(buf *memBuffer, f func() syscall.Errno) error {
+ for {
+ errno := f()
+ if errno == 0 {
+ return nil
+ } else if errno != syscall.ERANGE {
+ return errno
+ }
+ newSize := buf.size * 2
+ if !isSizeReasonable(int64(newSize)) {
+ return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize)
+ }
+ buf.resize(newSize)
+ }
+}
+
+const maxBufferSize = 1 << 20
+
+func isSizeReasonable(sz int64) bool {
+ return sz > 0 && sz <= maxBufferSize
}
diff --git a/libgo/go/os/user/lookup_windows.go b/libgo/go/os/user/lookup_windows.go
index 99c325ff01..4e36a5c2bf 100644
--- a/libgo/go/os/user/lookup_windows.go
+++ b/libgo/go/os/user/lookup_windows.go
@@ -5,11 +5,16 @@
package user
import (
+ "errors"
"fmt"
"syscall"
"unsafe"
)
+func init() {
+ groupImplemented = false
+}
+
func isDomainJoined() (bool, error) {
var domain *uint16
var status uint32
@@ -61,7 +66,7 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) {
if err == nil {
return name, nil
}
- // domain worked neigher as a domain nor as a server
+ // domain worked neither as a domain nor as a server
// could be domain server unavailable
// pretend username is fullname
return username, nil
@@ -129,7 +134,7 @@ func newUserFromSid(usid *syscall.SID) (*User, error) {
return newUser(usid, gid, dir)
}
-func lookup(username string) (*User, error) {
+func lookupUser(username string) (*User, error) {
sid, _, t, e := syscall.LookupSID("", username)
if e != nil {
return nil, e
@@ -140,10 +145,22 @@ func lookup(username string) (*User, error) {
return newUserFromSid(sid)
}
-func lookupId(uid string) (*User, error) {
+func lookupUserId(uid string) (*User, error) {
sid, e := syscall.StringToSid(uid)
if e != nil {
return nil, e
}
return newUserFromSid(sid)
}
+
+func lookupGroup(groupname string) (*Group, error) {
+ return nil, errors.New("user: LookupGroup not implemented on windows")
+}
+
+func lookupGroupId(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroupId not implemented on windows")
+}
+
+func listGroups(*User) ([]string, error) {
+ return nil, errors.New("user: GroupIds not implemented on windows")
+}
diff --git a/libgo/go/os/user/user.go b/libgo/go/os/user/user.go
index e8680fe546..ad61992ad3 100644
--- a/libgo/go/os/user/user.go
+++ b/libgo/go/os/user/user.go
@@ -9,25 +9,45 @@ import (
"strconv"
)
-var implemented = true // set to false by lookup_stubs.go's init
+var (
+ userImplemented = true // set to false by lookup_stubs.go's init
+ groupImplemented = true // set to false by lookup_stubs.go's init
+)
// User represents a user account.
-//
-// On posix systems Uid and Gid contain a decimal number
-// representing uid and gid. On windows Uid and Gid
-// contain security identifier (SID) in a string format.
-// On Plan 9, Uid, Gid, Username, and Name will be the
-// contents of /dev/user.
type User struct {
- Uid string // user id
- Gid string // primary group id
+ // Uid is the user ID.
+ // On POSIX systems, this is a decimal number representing the uid.
+ // On Windows, this is a security identifier (SID) in a string format.
+ // On Plan 9, this is the contents of /dev/user.
+ Uid string
+ // Gid is the primary group ID.
+ // On POSIX systems, this is a decimal number representing the gid.
+ // On Windows, this is a SID in a string format.
+ // On Plan 9, this is the contents of /dev/user.
+ Gid string
+ // Username is the login name.
Username string
- Name string
- HomeDir string
+ // Name is the user's real or display name.
+ // It might be blank.
+ // On POSIX systems, this is the first (or only) entry in the GECOS field
+ // list.
+ // On Windows, this is the user's display name.
+ // On Plan 9, this is the contents of /dev/user.
+ Name string
+ // HomeDir is the path to the user's home directory (if they have one).
+ HomeDir string
}
-// UnknownUserIdError is returned by LookupId when
-// a user cannot be found.
+// Group represents a grouping of users.
+//
+// On POSIX systems Gid contains a decimal number representing the group ID.
+type Group struct {
+ Gid string // group ID
+ Name string // group name
+}
+
+// UnknownUserIdError is returned by LookupId when a user cannot be found.
type UnknownUserIdError int
func (e UnknownUserIdError) Error() string {
@@ -41,3 +61,19 @@ type UnknownUserError string
func (e UnknownUserError) Error() string {
return "user: unknown user " + string(e)
}
+
+// UnknownGroupIdError is returned by LookupGroupId when
+// a group cannot be found.
+type UnknownGroupIdError string
+
+func (e UnknownGroupIdError) Error() string {
+ return "group: unknown groupid " + string(e)
+}
+
+// UnknownGroupError is returned by LookupGroup when
+// a group cannot be found.
+type UnknownGroupError string
+
+func (e UnknownGroupError) Error() string {
+ return "group: unknown group " + string(e)
+}
diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go
index 9d9420e809..9d8d94d8da 100644
--- a/libgo/go/os/user/user_test.go
+++ b/libgo/go/os/user/user_test.go
@@ -9,18 +9,19 @@ import (
"testing"
)
-func check(t *testing.T) {
- if !implemented {
+func checkUser(t *testing.T) {
+ if !userImplemented {
t.Skip("user: not implemented; skipping tests")
}
}
func TestCurrent(t *testing.T) {
- check(t)
-
+ if runtime.GOOS == "android" {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
u, err := Current()
if err != nil {
- t.Fatalf("Current: %v", err)
+ t.Fatalf("Current: %v (got %#v)", err, u)
}
if u.HomeDir == "" {
t.Errorf("didn't get a HomeDir")
@@ -53,7 +54,7 @@ func compare(t *testing.T, want, got *User) {
}
func TestLookup(t *testing.T) {
- check(t)
+ checkUser(t)
if runtime.GOOS == "plan9" {
t.Skipf("Lookup not implemented on %q", runtime.GOOS)
@@ -71,7 +72,7 @@ func TestLookup(t *testing.T) {
}
func TestLookupId(t *testing.T) {
- check(t)
+ checkUser(t)
if runtime.GOOS == "plan9" {
t.Skipf("LookupId not implemented on %q", runtime.GOOS)
@@ -87,3 +88,64 @@ func TestLookupId(t *testing.T) {
}
compare(t, want, got)
}
+
+func checkGroup(t *testing.T) {
+ if !groupImplemented {
+ t.Skip("user: group not implemented; skipping test")
+ }
+}
+
+func TestLookupGroup(t *testing.T) {
+ checkGroup(t)
+ user, err := Current()
+ if err != nil {
+ t.Fatalf("Current(): %v", err)
+ }
+
+ g1, err := LookupGroupId(user.Gid)
+ if err != nil {
+ // NOTE(rsc): Maybe the group isn't defined. That's fine.
+ // On my OS X laptop, rsc logs in with group 5000 even
+ // though there's no name for group 5000. Such is Unix.
+ t.Logf("LookupGroupId(%q): %v", user.Gid, err)
+ return
+ }
+ if g1.Gid != user.Gid {
+ t.Errorf("LookupGroupId(%q).Gid = %s; want %s", user.Gid, g1.Gid, user.Gid)
+ }
+
+ g2, err := LookupGroup(g1.Name)
+ if err != nil {
+ t.Fatalf("LookupGroup(%q): %v", g1.Name, err)
+ }
+ if g1.Gid != g2.Gid || g1.Name != g2.Name {
+ t.Errorf("LookupGroup(%q) = %+v; want %+v", g1.Name, g2, g1)
+ }
+}
+
+func TestGroupIds(t *testing.T) {
+ checkGroup(t)
+ if runtime.GOOS == "solaris" {
+ t.Skip("skipping GroupIds, see golang.org/issue/14709")
+ }
+ user, err := Current()
+ if err != nil {
+ t.Fatalf("Current(): %v", err)
+ }
+ gids, err := user.GroupIds()
+ if err != nil {
+ t.Fatalf("%+v.GroupIds(): %v", user, err)
+ }
+ if !containsID(gids, user.Gid) {
+ t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid)
+ }
+}
+
+func containsID(ids []string, id string) bool {
+ for _, x := range ids {
+ if x == id {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/os/wait_unimp.go b/libgo/go/os/wait_unimp.go
new file mode 100644
index 0000000000..7059e59ab2
--- /dev/null
+++ b/libgo/go/os/wait_unimp.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly nacl netbsd openbsd solaris
+
+package os
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+// This version is used on systems that do not implement waitid,
+// or where we have not implemented it yet.
+func (p *Process) blockUntilWaitable() (bool, error) {
+ return false, nil
+}
diff --git a/libgo/go/os/wait_wait6.go b/libgo/go/os/wait_wait6.go
new file mode 100644
index 0000000000..b30981199e
--- /dev/null
+++ b/libgo/go/os/wait_wait6.go
@@ -0,0 +1,41 @@
+// 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 freebsd
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+const _P_PID = 0
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+func (p *Process) blockUntilWaitable() (bool, error) {
+ var errno syscall.Errno
+ // The arguments on 32-bit FreeBSD look like the following:
+ // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
+ // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
+ if runtime.GOARCH == "386" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
+ } else if runtime.GOARCH == "arm" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
+ } else {
+ _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ }
+ runtime.KeepAlive(p)
+ if errno != 0 {
+ // The wait6 system call is supported only on FreeBSD
+ // 9.3 and above, so it may return an ENOSYS error.
+ if errno == syscall.ENOSYS {
+ return false, nil
+ }
+ return false, NewSyscallError("wait6", errno)
+ }
+ return true, nil
+}
diff --git a/libgo/go/os/wait_waitid.go b/libgo/go/os/wait_waitid.go
new file mode 100644
index 0000000000..653fce9253
--- /dev/null
+++ b/libgo/go/os/wait_waitid.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin linux
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+const _P_PID = 1
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+func (p *Process) blockUntilWaitable() (bool, error) {
+ // The waitid system call expects a pointer to a siginfo_t,
+ // which is 128 bytes on all GNU/Linux systems.
+ // On Darwin, it requires greater than or equal to 64 bytes
+ // for darwin/{386,arm} and 104 bytes for darwin/amd64.
+ // We don't care about the values it returns.
+ var siginfo [128]byte
+ psig := &siginfo[0]
+ _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ runtime.KeepAlive(p)
+ if e != 0 {
+ // waitid has been available since Linux 2.6.9, but
+ // reportedly is not available in Ubuntu on Windows.
+ // See issue 16610.
+ if e == syscall.ENOSYS {
+ return false, nil
+ }
+ return false, NewSyscallError("waitid", e)
+ }
+ return true, nil
+}
diff --git a/libgo/go/path/example_test.go b/libgo/go/path/example_test.go
index ca18b32305..88b76557f2 100644
--- a/libgo/go/path/example_test.go
+++ b/libgo/go/path/example_test.go
@@ -56,7 +56,14 @@ func ExampleIsAbs() {
func ExampleJoin() {
fmt.Println(path.Join("a", "b", "c"))
- // Output: a/b/c
+ fmt.Println(path.Join("a", "b/c"))
+ fmt.Println(path.Join("a/b", "c"))
+ fmt.Println(path.Join("a/b", "/c"))
+ // Output:
+ // a/b/c
+ // a/b/c
+ // a/b/c
+ // a/b/c
}
func ExampleSplit() {
diff --git a/libgo/go/path/filepath/example_unix_test.go b/libgo/go/path/filepath/example_unix_test.go
index 893be1b198..cd8233ceb6 100644
--- a/libgo/go/path/filepath/example_unix_test.go
+++ b/libgo/go/path/filepath/example_unix_test.go
@@ -65,3 +65,17 @@ func ExampleSplit() {
// dir: "/usr/local//"
// file: "go"
}
+
+func ExampleJoin() {
+ fmt.Println("On Unix:")
+ fmt.Println(filepath.Join("a", "b", "c"))
+ fmt.Println(filepath.Join("a", "b/c"))
+ fmt.Println(filepath.Join("a/b", "c"))
+ fmt.Println(filepath.Join("a/b", "/c"))
+ // Output:
+ // On Unix:
+ // a/b/c
+ // a/b/c
+ // a/b/c
+ // a/b/c
+}
diff --git a/libgo/go/path/filepath/export_windows_test.go b/libgo/go/path/filepath/export_windows_test.go
new file mode 100644
index 0000000000..a7e2e6422b
--- /dev/null
+++ b/libgo/go/path/filepath/export_windows_test.go
@@ -0,0 +1,10 @@
+// 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 filepath
+
+var (
+ ToNorm = toNorm
+ NormBase = normBase
+)
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go
index 89f16de355..5168e037b5 100644
--- a/libgo/go/path/filepath/match.go
+++ b/libgo/go/path/filepath/match.go
@@ -49,7 +49,7 @@ Pattern:
star, chunk, pattern = scanChunk(pattern)
if star && chunk == "" {
// Trailing * matches rest of string unless it has a /.
- return strings.Index(name, string(Separator)) < 0, nil
+ return !strings.Contains(name, string(Separator)), nil
}
// Look for match at current position.
t, ok, err := matchChunk(chunk, name)
@@ -240,19 +240,22 @@ 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
+ volumeLen := 0
+ if runtime.GOOS == "windows" {
+ volumeLen, dir = cleanGlobPathWindows(dir)
+ } else {
+ dir = cleanGlobPath(dir)
}
- if !hasMeta(dir) {
+ if !hasMeta(dir[volumeLen:]) {
return glob(dir, file, nil)
}
+ // Prevent infinite recursion. See issue 15879.
+ if dir == pattern {
+ return nil, ErrBadPattern
+ }
+
var m []string
m, err = Glob(dir)
if err != nil {
@@ -267,6 +270,38 @@ 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) (prefixLen int, cleaned string) {
+ vollen := volumeNameLen(path)
+ switch {
+ case path == "":
+ return 0, "."
+ case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
+ // do nothing to the path
+ return vollen + 1, path
+ case vollen == len(path) && len(path) == 2: // C:
+ return vollen, path + "." // convert C: into C:.
+ default:
+ if vollen >= len(path) {
+ vollen = len(path) - 1
+ }
+ return vollen, 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
@@ -305,5 +340,5 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
// recognized by Match.
func hasMeta(path string) bool {
// TODO(niemeyer): Should other magic characters be added here?
- return strings.IndexAny(path, "*?[") >= 0
+ return strings.ContainsAny(path, "*?[")
}
diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go
index 209c67f30f..ae7ca1c228 100644
--- a/libgo/go/path/filepath/match_test.go
+++ b/libgo/go/path/filepath/match_test.go
@@ -5,10 +5,13 @@
package filepath_test
import (
+ "fmt"
+ "internal/testenv"
"io/ioutil"
"os"
. "path/filepath"
"runtime"
+ "sort"
"strings"
"testing"
)
@@ -88,7 +91,7 @@ func TestMatch(t *testing.T) {
pattern := tt.pattern
s := tt.s
if runtime.GOOS == "windows" {
- if strings.Index(pattern, "\\") >= 0 {
+ if strings.Contains(pattern, "\\") {
// no escape allowed on windows.
continue
}
@@ -158,6 +161,12 @@ func TestGlobError(t *testing.T) {
}
}
+func TestGlobUNC(t *testing.T) {
+ // Just make sure this runs without crashing for now.
+ // See issue 15879.
+ Glob(`\\?\C:\*`)
+}
+
var globSymlinkTests = []struct {
path, dest string
brokenLink bool
@@ -167,15 +176,7 @@ var globSymlinkTests = []struct {
}
func TestGlobSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
-
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "globsymlink")
if err != nil {
@@ -210,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)
+ }
+ }
+}
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index dd6f3e7a99..1d8e35c969 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -4,9 +4,6 @@
// Package filepath implements utility routines for manipulating filename paths
// in a way compatible with the target operating system-defined file paths.
-//
-// Functions in this package replace any occurrences of the slash ('/') character
-// with os.PathSeparator when returning paths unless otherwise specified.
package filepath
import (
@@ -61,7 +58,7 @@ const (
)
// Clean returns the shortest path name equivalent to path
-// by purely lexical processing. It applies the following rules
+// by purely lexical processing. It applies the following rules
// iteratively until no further processing can be done:
//
// 1. Replace multiple Separator elements with a single one.
@@ -75,12 +72,14 @@ const (
// The returned path ends in a slash only if it represents a root directory,
// such as "/" on Unix or `C:\` on Windows.
//
+// Finally, any occurrences of slash are replaced by Separator.
+//
// If the result of this process is an empty string, Clean
// returns the string ".".
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
// Getting Dot-Dot Right,''
-// http://plan9.bell-labs.com/sys/doc/lexnames.html
+// https://9p.io/sys/doc/lexnames.html
func Clean(path string) string {
originalPath := path
volLen := volumeNameLen(path)
@@ -178,7 +177,7 @@ func FromSlash(path string) string {
// SplitList splits a list of paths joined by the OS-specific ListSeparator,
// usually found in PATH or GOPATH environment variables.
// Unlike strings.Split, SplitList returns an empty slice when passed an empty
-// string. SplitList does not replace slash characters in the returned paths.
+// string.
func SplitList(path string) []string {
return splitList(path)
}
@@ -198,7 +197,7 @@ func Split(path string) (dir, file string) {
}
// Join joins any number of path elements into a single path, adding
-// a Separator if necessary. The result is Cleaned, in particular
+// a Separator if necessary. Join calls Clean on the result; in particular,
// all empty strings are ignored.
// On Windows, the result is a UNC path if and only if the first path
// element is a UNC path.
@@ -223,14 +222,16 @@ func Ext(path string) string {
// links.
// If path is relative the result will be relative to the current directory,
// unless one of the components is an absolute symbolic link.
+// EvalSymlinks calls Clean on the result.
func EvalSymlinks(path string) (string, error) {
return evalSymlinks(path)
}
// Abs returns an absolute representation of path.
// If the path is not absolute it will be joined with the current
-// working directory to turn it into an absolute path. The absolute
+// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
+// Abs calls Clean on the result.
func Abs(path string) (string, error) {
return abs(path)
}
@@ -253,6 +254,7 @@ func unixAbs(path string) (string, error) {
// even if basepath and targpath share no elements.
// An error is returned if targpath can't be made relative to basepath or if
// knowing the current working directory would be necessary to compute it.
+// Rel calls Clean on the result.
func Rel(basepath, targpath string) (string, error) {
baseVol := VolumeName(basepath)
targVol := VolumeName(targpath)
@@ -391,9 +393,14 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
func Walk(root string, walkFn WalkFunc) error {
info, err := os.Lstat(root)
if err != nil {
- return walkFn(root, nil, err)
+ err = walkFn(root, nil, err)
+ } else {
+ err = walk(root, info, walkFn)
+ }
+ if err == SkipDir {
+ return nil
}
- return walk(root, info, walkFn)
+ return err
}
// readDirNames reads the directory named by dirname and returns
@@ -442,7 +449,7 @@ func Base(path string) string {
}
// Dir returns all but the last element of path, typically the path's directory.
-// After dropping the final element, the path is Cleaned and trailing
+// After dropping the final element, Dir calls Clean on the path and trailing
// slashes are removed.
// If the path is empty, Dir returns ".".
// If the path consists entirely of separators, Dir returns a single separator.
diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go
index 60d46d9d42..ec792fc831 100644
--- a/libgo/go/path/filepath/path_plan9.go
+++ b/libgo/go/path/filepath/path_plan9.go
@@ -18,6 +18,9 @@ func volumeNameLen(path string) int {
}
// HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index 10ea795e90..7389ea29a4 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -6,6 +6,7 @@ package filepath_test
import (
"errors"
+ "internal/testenv"
"io/ioutil"
"os"
"path/filepath"
@@ -15,8 +16,6 @@ import (
"testing"
)
-var supportsSymlinks = true
-
type PathTest struct {
path, result string
}
@@ -452,7 +451,7 @@ func TestWalk(t *testing.T) {
checkMarks(t, true)
errors = errors[0:0]
- // Test permission errors. Only possible if we're not root
+ // Test permission errors. Only possible if we're not root
// and only on some file systems (AFS, FAT). To avoid errors during
// all.bash on those file systems, skip during go test -short.
if os.Getuid() > 0 && !testing.Short() {
@@ -532,7 +531,7 @@ func TestWalkSkipDirOnFile(t *testing.T) {
touch(t, filepath.Join(td, "dir/foo2"))
sawFoo2 := false
- filepath.Walk(td, func(path string, info os.FileInfo, err error) error {
+ walker := func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, "foo2") {
sawFoo2 = true
}
@@ -540,8 +539,20 @@ func TestWalkSkipDirOnFile(t *testing.T) {
return filepath.SkipDir
}
return nil
- })
+ }
+ err = filepath.Walk(td, walker)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if sawFoo2 {
+ t.Errorf("SkipDir on file foo1 did not block processing of foo2")
+ }
+
+ err = filepath.Walk(filepath.Join(td, "dir"), walker)
+ if err != nil {
+ t.Fatal(err)
+ }
if sawFoo2 {
t.Errorf("SkipDir on file foo1 did not block processing of foo2")
}
@@ -779,13 +790,7 @@ func simpleJoin(dir, path string) string {
}
func TestEvalSymlinks(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- if !supportsSymlinks {
- t.Skip("skipping because symlinks are not supported")
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "evalsymlink")
if err != nil {
@@ -843,7 +848,7 @@ func TestEvalSymlinks(t *testing.T) {
if p, err := filepath.EvalSymlinks(path); err != nil {
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if filepath.Clean(p) != filepath.Clean(dest) {
- t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
+ t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
}
// test EvalSymlinks(".")
@@ -875,6 +880,68 @@ func TestEvalSymlinks(t *testing.T) {
t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want)
}()
+ // test EvalSymlinks("C:.") on Windows
+ if runtime.GOOS == "windows" {
+ func() {
+ defer func() {
+ err := os.Chdir(wd)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ err := os.Chdir(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ volDot := filepath.VolumeName(tmpDir) + "."
+
+ p, err := filepath.EvalSymlinks(volDot)
+ if err != nil {
+ t.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot, d.path, err)
+ return
+ }
+ if p == volDot {
+ return
+ }
+ want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path))
+ if p == want {
+ return
+ }
+ t.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot, d.path, p, volDot, want)
+ }()
+ }
+
+ // test EvalSymlinks(".."+path)
+ func() {
+ defer func() {
+ err := os.Chdir(wd)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ err := os.Chdir(simpleJoin(tmpDir, "test"))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ path := simpleJoin("..", d.path)
+ dest := simpleJoin("..", d.dest)
+ if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) {
+ dest = d.dest
+ }
+
+ if p, err := filepath.EvalSymlinks(path); err != nil {
+ t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+ } else if filepath.Clean(p) != filepath.Clean(dest) {
+ t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
+ }
+ }()
+
// test EvalSymlinks where parameter is relative path
func() {
defer func() {
@@ -892,20 +959,36 @@ func TestEvalSymlinks(t *testing.T) {
if p, err := filepath.EvalSymlinks(d.path); err != nil {
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if filepath.Clean(p) != filepath.Clean(d.dest) {
- t.Errorf("Clean(%q)=%q, want %q", d.path, p, d.dest)
+ t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
}
}()
}
}
-func TestIssue13582(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
+func TestEvalSymlinksIsNotExist(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ defer chtmpdir(t)()
+
+ _, err := filepath.EvalSymlinks("notexist")
+ if !os.IsNotExist(err) {
+ t.Errorf("expected the file is not found, got %v\n", err)
+ }
+
+ err = os.Symlink("notexist", "link")
+ if err != nil {
+ t.Fatal(err)
}
- if !supportsSymlinks {
- t.Skip("skipping because symlinks are not supported")
+ defer os.Remove("link")
+
+ _, err = filepath.EvalSymlinks("link")
+ if !os.IsNotExist(err) {
+ t.Errorf("expected the file is not found, got %v\n", err)
}
+}
+
+func TestIssue13582(t *testing.T) {
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "issue13582")
if err != nil {
@@ -981,13 +1064,16 @@ var absTestDirs = []string{
var absTests = []string{
".",
"b",
+ "b/",
"../a",
"../a/b",
"../a/b/./c/../../.././a",
+ "../a/b/./c/../../.././a/",
"$",
"$/.",
"$/a/../a/b",
"$/a/b/c/../../.././a",
+ "$/a/b/c/../../.././a/",
}
func TestAbs(t *testing.T) {
@@ -1018,7 +1104,7 @@ func TestAbs(t *testing.T) {
vol := filepath.VolumeName(root)
var extra []string
for _, path := range absTests {
- if strings.Index(path, "$") != -1 {
+ if strings.Contains(path, "$") {
continue
}
path = vol + path
@@ -1052,7 +1138,7 @@ func TestAbs(t *testing.T) {
if !filepath.IsAbs(abspath) {
t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
}
- if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
+ if filepath.IsAbs(abspath) && abspath != filepath.Clean(abspath) {
t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
}
}
@@ -1216,11 +1302,11 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
if err != nil {
t.Fatal(err)
}
- bugs := filepath.Join(root, "bugs")
+ bugs := filepath.Join(root, "fixedbugs")
ken := filepath.Join(root, "ken")
seenBugs := false
seenKen := false
- filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
+ err = filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
@@ -1231,12 +1317,15 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
return filepath.SkipDir
case ken:
if !seenBugs {
- t.Fatal("filepath.Walk out of order - ken before bugs")
+ t.Fatal("filepath.Walk out of order - ken before fixedbugs")
}
seenKen = true
}
return nil
})
+ if err != nil {
+ t.Fatal(err)
+ }
if !seenKen {
t.Fatalf("%q not seen", ken)
}
diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go
index 2d242cc0b5..d77ff24cdc 100644
--- a/libgo/go/path/filepath/path_unix.go
+++ b/libgo/go/path/filepath/path_unix.go
@@ -20,6 +20,9 @@ func volumeNameLen(path string) int {
}
// HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go
index ef6e7ca93f..0d8b62015c 100644
--- a/libgo/go/path/filepath/path_windows.go
+++ b/libgo/go/path/filepath/path_windows.go
@@ -37,7 +37,7 @@ func volumeNameLen(path string) int {
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
return 2
}
- // is it UNC
+ // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
!isSlash(path[2]) && path[2] != '.' {
// first, leading `\\` and next shouldn't be `\`. its server name.
@@ -65,6 +65,9 @@ func volumeNameLen(path string) int {
}
// HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
func HasPrefix(p, prefix string) bool {
if strings.HasPrefix(p, prefix) {
return true
@@ -106,7 +109,11 @@ func splitList(path string) []string {
}
func abs(path string) (string, error) {
- return syscall.FullPath(path)
+ fullPath, err := syscall.FullPath(path)
+ if err != nil {
+ return "", err
+ }
+ return Clean(fullPath), nil
}
func join(elem []string) string {
@@ -121,7 +128,7 @@ func join(elem []string) string {
// joinNonEmpty is like join, but it assumes that the first element is non-empty.
func joinNonEmpty(elem []string) string {
if len(elem[0]) == 2 && elem[0][1] == ':' {
- // First element is drive leter without terminating slash.
+ // First element is drive letter without terminating slash.
// Keep path relative to current directory on that drive.
return Clean(elem[0] + strings.Join(elem[1:], string(Separator)))
}
diff --git a/libgo/go/path/filepath/symlink.go b/libgo/go/path/filepath/symlink.go
index bc287c5ecb..824aee4e49 100644
--- a/libgo/go/path/filepath/symlink.go
+++ b/libgo/go/path/filepath/symlink.go
@@ -100,13 +100,14 @@ func walkSymlinks(path string) (string, error) {
return "", err
}
if runtime.GOOS == "windows" {
- // walkLinks(".", ...) always retuns "." on unix.
+ // walkLinks(".", ...) always returns "." on unix.
// But on windows it returns symlink target, if current
// directory is a symlink. Stop the walk, if symlink
// target is not absolute path, and return "."
// to the caller (just like unix does).
- if path == "." && !IsAbs(newpath) {
- return ".", nil
+ // Same for "C:.".
+ if path[volumeNameLen(path):] == "." && !IsAbs(newpath) {
+ return path, nil
}
}
if i == linksWalked {
diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go
index eb48367ec2..f771fe3a8a 100644
--- a/libgo/go/path/filepath/symlink_windows.go
+++ b/libgo/go/path/filepath/symlink_windows.go
@@ -5,45 +5,105 @@
package filepath
import (
+ "strings"
"syscall"
)
-func toShort(path string) (string, error) {
- p, err := syscall.UTF16FromString(path)
+// normVolumeName is like VolumeName, but makes drive letter upper case.
+// result of EvalSymlinks must be unique, so we have
+// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
+func normVolumeName(path string) string {
+ volume := VolumeName(path)
+
+ if len(volume) > 2 { // isUNC
+ return volume
+ }
+
+ return strings.ToUpper(volume)
+}
+
+// normBase returns the last element of path with correct case.
+func normBase(path string) (string, error) {
+ p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return "", err
}
- b := p // GetShortPathName says we can reuse buffer
- n := uint32(len(b))
- for {
- n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
- if err != nil {
- return "", err
- }
- if n <= uint32(len(b)) {
- return syscall.UTF16ToString(b[:n]), nil
- }
- b = make([]uint16, n)
- }
-}
-func toLong(path string) (string, error) {
- p, err := syscall.UTF16FromString(path)
+ var data syscall.Win32finddata
+
+ h, err := syscall.FindFirstFile(p, &data)
if err != nil {
return "", err
}
- b := p // GetLongPathName says we can reuse buffer
- n := uint32(len(b))
+ syscall.FindClose(h)
+
+ return syscall.UTF16ToString(data.FileName[:]), nil
+}
+
+// baseIsDotDot returns whether the last element of path is "..".
+// The given path should be 'Clean'-ed in advance.
+func baseIsDotDot(path string) bool {
+ i := strings.LastIndexByte(path, Separator)
+ return path[i+1:] == ".."
+}
+
+// toNorm returns the normalized path that is guaranteed to be unique.
+// It should accept the following formats:
+// * UNC paths (e.g \\server\share\foo\bar)
+// * absolute paths (e.g C:\foo\bar)
+// * relative paths begin with drive letter (e.g C:foo\bar, C:..\foo\bar, C:.., C:.)
+// * relative paths begin with '\' (e.g \foo\bar)
+// * relative paths begin without '\' (e.g foo\bar, ..\foo\bar, .., .)
+// The returned normalized path will be in the same form (of 5 listed above) as the input path.
+// If two paths A and B are indicating the same file with the same format, toNorm(A) should be equal to toNorm(B).
+// The normBase parameter should be equal to the normBase func, except for in tests. See docs on the normBase func.
+func toNorm(path string, normBase func(string) (string, error)) (string, error) {
+ if path == "" {
+ return path, nil
+ }
+
+ path = Clean(path)
+
+ volume := normVolumeName(path)
+ path = path[len(volume):]
+
+ // skip special cases
+ if path == "." || path == `\` {
+ return volume + path, nil
+ }
+
+ var normPath string
+
for {
- n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+ if baseIsDotDot(path) {
+ normPath = path + `\` + normPath
+
+ break
+ }
+
+ name, err := normBase(volume + path)
if err != nil {
return "", err
}
- if n <= uint32(len(b)) {
- return syscall.UTF16ToString(b[:n]), nil
+
+ normPath = name + `\` + normPath
+
+ i := strings.LastIndexByte(path, Separator)
+ if i == -1 {
+ break
+ }
+ if i == 0 { // `\Go` or `C:\Go`
+ normPath = `\` + normPath
+
+ break
}
- b = make([]uint16, n)
+
+ path = path[:i]
}
+
+ normPath = normPath[:len(normPath)-1] // remove trailing '\'
+
+ return volume + normPath, nil
}
func evalSymlinks(path string) (string, error) {
@@ -51,20 +111,5 @@ func evalSymlinks(path string) (string, error) {
if err != nil {
return "", err
}
- p, err := toShort(path)
- if err != nil {
- return "", err
- }
- p, err = toLong(p)
- if err != nil {
- return "", err
- }
- // syscall.GetLongPathName does not change the case of the drive letter,
- // but the result of EvalSymlinks must be unique, so we have
- // EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
- // Make drive letter upper case.
- if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
- p = string(p[0]+'A'-'a') + p[1:]
- }
- return Clean(p), nil
+ return toNorm(path, normBase)
}
diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go
index 75dd3b38e7..8d9aa513b1 100644
--- a/libgo/go/path/match.go
+++ b/libgo/go/path/match.go
@@ -43,7 +43,7 @@ Pattern:
star, chunk, pattern = scanChunk(pattern)
if star && chunk == "" {
// Trailing * matches rest of string unless it has a /.
- return strings.Index(name, "/") < 0, nil
+ return !strings.Contains(name, "/"), nil
}
// Look for match at current position.
t, ok, err := matchChunk(chunk, name)
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
index 01071a9a82..76c7814c59 100644
--- a/libgo/go/path/path.go
+++ b/libgo/go/path/path.go
@@ -4,6 +4,8 @@
// Package path implements utility routines for manipulating slash-separated
// paths.
+//
+// To manipulate operating system paths, use the path/filepath package.
package path
import (
@@ -48,7 +50,7 @@ func (b *lazybuf) string() string {
}
// Clean returns the shortest path name equivalent to path
-// by purely lexical processing. It applies the following rules
+// by purely lexical processing. It applies the following rules
// iteratively until no further processing can be done:
//
// 1. Replace multiple slashes with a single slash.
@@ -65,7 +67,7 @@ func (b *lazybuf) string() string {
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
// Getting Dot-Dot Right,''
-// http://plan9.bell-labs.com/sys/doc/lexnames.html
+// https://9p.io/sys/doc/lexnames.html
func Clean(path string) string {
if path == "" {
return "."
diff --git a/libgo/go/path/path_test.go b/libgo/go/path/path_test.go
index 512d936e45..600ff08797 100644
--- a/libgo/go/path/path_test.go
+++ b/libgo/go/path/path_test.go
@@ -138,15 +138,9 @@ var jointests = []JoinTest{
{[]string{"", ""}, ""},
}
-// join takes a []string and passes it to Join.
-func join(elem []string, args ...string) string {
- args = elem
- return Join(args...)
-}
-
func TestJoin(t *testing.T) {
for _, test := range jointests {
- if p := join(test.elem); p != test.path {
+ if p := Join(test.elem...); p != test.path {
t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
}
}
diff --git a/libgo/go/plugin/plugin.go b/libgo/go/plugin/plugin.go
new file mode 100644
index 0000000000..b86099a4f6
--- /dev/null
+++ b/libgo/go/plugin/plugin.go
@@ -0,0 +1,73 @@
+// 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 plugin implements loading and symbol resolution of Go plugins.
+//
+// Currently plugins only work on Linux.
+//
+// A plugin is a Go main package with exported functions and variables that
+// has been built with:
+//
+// go build -buildmode=plugin
+//
+// When a plugin is first opened, the init functions of all packages not
+// already part of the program are called. The main function is not run.
+// A plugin is only initialized once, and cannot be closed.
+package plugin
+
+// Plugin is a loaded Go plugin.
+type Plugin struct {
+ pluginpath string
+ loaded chan struct{} // closed when loaded
+ syms map[string]interface{}
+}
+
+// Open opens a Go plugin.
+// If a path has already been opened, then the existing *Plugin is returned.
+// It is safe for concurrent use by multiple goroutines.
+func Open(path string) (*Plugin, error) {
+ return open(path)
+}
+
+// Lookup searches for a symbol named symName in plugin p.
+// A symbol is any exported variable or function.
+// It reports an error if the symbol is not found.
+// It is safe for concurrent use by multiple goroutines.
+func (p *Plugin) Lookup(symName string) (Symbol, error) {
+ return lookup(p, symName)
+}
+
+// A Symbol is a pointer to a variable or function.
+//
+// For example, a plugin defined as
+//
+// package main
+//
+// // // No C code needed.
+// import "C"
+//
+// import "fmt"
+//
+// var V int
+//
+// func F() { fmt.Printf("Hello, number %d\n", V) }
+//
+// may be loaded with the Open function and then the exported package
+// symbols V and F can be accessed
+//
+// p, err := plugin.Open("plugin_name.so")
+// if err != nil {
+// panic(err)
+// }
+// v, err := p.Lookup("V")
+// if err != nil {
+// panic(err)
+// }
+// f, err := p.Lookup("F")
+// if err != nil {
+// panic(err)
+// }
+// *v.(*int) = 7
+// f.(func())() // prints "Hello, number 7"
+type Symbol interface{}
diff --git a/libgo/go/plugin/plugin_dlopen.go b/libgo/go/plugin/plugin_dlopen.go
new file mode 100644
index 0000000000..c5b0a4721c
--- /dev/null
+++ b/libgo/go/plugin/plugin_dlopen.go
@@ -0,0 +1,138 @@
+// 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 linux,cgo darwin,cgo
+
+package plugin
+
+/*
+#cgo linux LDFLAGS: -ldl
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <stdio.h>
+
+static uintptr_t pluginOpen(const char* path, char** err) {
+ void* h = dlopen(path, RTLD_NOW|RTLD_GLOBAL);
+ if (h == NULL) {
+ *err = (char*)dlerror();
+ }
+ return (uintptr_t)h;
+}
+
+static void* pluginLookup(uintptr_t h, const char* name, char** err) {
+ void* r = dlsym((void*)h, name);
+ if (r == NULL) {
+ *err = (char*)dlerror();
+ }
+ return r;
+}
+*/
+import "C"
+
+import (
+ "errors"
+ "sync"
+ "unsafe"
+)
+
+func open(name string) (*Plugin, error) {
+ cPath := (*C.char)(C.malloc(C.PATH_MAX + 1))
+ defer C.free(unsafe.Pointer(cPath))
+
+ cRelName := C.CString(name)
+ defer C.free(unsafe.Pointer(cRelName))
+ if C.realpath(cRelName, cPath) == nil {
+ return nil, errors.New("plugin.Open(" + name + "): realpath failed")
+ }
+
+ filepath := C.GoString(cPath)
+
+ pluginsMu.Lock()
+ if p := plugins[filepath]; p != nil {
+ pluginsMu.Unlock()
+ <-p.loaded
+ return p, nil
+ }
+ var cErr *C.char
+ h := C.pluginOpen(cPath, &cErr)
+ if h == 0 {
+ pluginsMu.Unlock()
+ return nil, errors.New("plugin.Open: " + C.GoString(cErr))
+ }
+ // TODO(crawshaw): look for plugin note, confirm it is a Go plugin
+ // and it was built with the correct toolchain.
+ if len(name) > 3 && name[len(name)-3:] == ".so" {
+ name = name[:len(name)-3]
+ }
+
+ pluginpath, syms, mismatchpkg := lastmoduleinit()
+ if mismatchpkg != "" {
+ pluginsMu.Unlock()
+ return nil, errors.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg)
+ }
+ if plugins == nil {
+ plugins = make(map[string]*Plugin)
+ }
+ // This function can be called from the init function of a plugin.
+ // Drop a placeholder in the map so subsequent opens can wait on it.
+ p := &Plugin{
+ pluginpath: pluginpath,
+ loaded: make(chan struct{}),
+ syms: syms,
+ }
+ plugins[filepath] = p
+ pluginsMu.Unlock()
+
+ initStr := C.CString(pluginpath + ".init")
+ initFuncPC := C.pluginLookup(h, initStr, &cErr)
+ C.free(unsafe.Pointer(initStr))
+ if initFuncPC != nil {
+ initFuncP := &initFuncPC
+ initFunc := *(*func())(unsafe.Pointer(&initFuncP))
+ initFunc()
+ }
+
+ // Fill out the value of each plugin symbol.
+ for symName, sym := range syms {
+ isFunc := symName[0] == '.'
+ if isFunc {
+ delete(syms, symName)
+ symName = symName[1:]
+ }
+
+ cname := C.CString(pluginpath + "." + symName)
+ p := C.pluginLookup(h, cname, &cErr)
+ C.free(unsafe.Pointer(cname))
+ if p == nil {
+ return nil, errors.New("plugin.Open: could not find symbol " + symName + ": " + C.GoString(cErr))
+ }
+ valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym))
+ if isFunc {
+ (*valp)[1] = unsafe.Pointer(&p)
+ } else {
+ (*valp)[1] = p
+ }
+ syms[symName] = sym
+ }
+ close(p.loaded)
+ return p, nil
+}
+
+func lookup(p *Plugin, symName string) (Symbol, error) {
+ if s := p.syms[symName]; s != nil {
+ return s, nil
+ }
+ return nil, errors.New("plugin: symbol " + symName + " not found in plugin " + p.pluginpath)
+}
+
+var (
+ pluginsMu sync.Mutex
+ plugins map[string]*Plugin
+)
+
+// lastmoduleinit is defined in package runtime
+func lastmoduleinit() (pluginpath string, syms map[string]interface{}, mismatchpkg string)
diff --git a/libgo/go/plugin/plugin_stubs.go b/libgo/go/plugin/plugin_stubs.go
new file mode 100644
index 0000000000..f0bcb4a3bd
--- /dev/null
+++ b/libgo/go/plugin/plugin_stubs.go
@@ -0,0 +1,17 @@
+// 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 !linux,!darwin !cgo
+
+package plugin
+
+import "errors"
+
+func lookup(p *Plugin, symName string) (interface{}, error) {
+ return nil, errors.New("plugin: not implemented")
+}
+
+func open(name string) (*Plugin, error) {
+ return nil, errors.New("plugin: not implemented")
+}
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index b8e7cd883c..3686167ed4 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -21,9 +21,13 @@ import (
"sync"
"testing"
"time"
+ "unicode"
+ "unicode/utf8"
"unsafe"
)
+var sink interface{}
+
func TestBool(t *testing.T) {
v := ValueOf(true)
if v.Bool() != true {
@@ -44,16 +48,12 @@ type pair struct {
s string
}
-func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
-
func assert(t *testing.T, s, want string) {
if s != want {
t.Errorf("have %#q want %#q", s, want)
}
}
-func typestring(i interface{}) string { return TypeOf(i).String() }
-
var typeTests = []pair{
{struct{ x int }{}, "int"},
{struct{ x int8 }{}, "int8"},
@@ -650,6 +650,20 @@ var (
type self struct{}
+type Loop *Loop
+type Loopy interface{}
+
+var loop1, loop2 Loop
+var loopy1, loopy2 Loopy
+
+func init() {
+ loop1 = &loop2
+ loop2 = &loop1
+
+ loopy1 = &loopy2
+ loopy2 = &loopy1
+}
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{nil, nil, true},
@@ -708,6 +722,12 @@ var deepEqualTests = []DeepEqualTest{
{&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
{Basic{1, 0.5}, NotBasic{1, 0.5}, false},
{map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+
+ // Possible loops.
+ {&loop1, &loop1, true},
+ {&loop1, &loop2, true},
+ {&loopy1, &loopy1, true},
+ {&loopy1, &loopy2, true},
}
func TestDeepEqual(t *testing.T) {
@@ -1537,6 +1557,34 @@ func BenchmarkCall(b *testing.B) {
})
}
+func BenchmarkCallArgCopy(b *testing.B) {
+ byteArray := func(n int) Value {
+ return Zero(ArrayOf(n, TypeOf(byte(0))))
+ }
+ sizes := [...]struct {
+ fv Value
+ arg Value
+ }{
+ {ValueOf(func(a [128]byte) {}), byteArray(128)},
+ {ValueOf(func(a [256]byte) {}), byteArray(256)},
+ {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
+ {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
+ {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
+ }
+ for _, size := range sizes {
+ bench := func(b *testing.B) {
+ args := []Value{size.arg}
+ b.SetBytes(int64(size.arg.Len()))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ size.fv.Call(args)
+ }
+ }
+ name := fmt.Sprintf("size=%v", size.arg.Len())
+ b.Run(name, bench)
+ }
+}
+
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -1633,6 +1681,11 @@ func (p Point) GCMethod(k int) int {
}
// This will be index 3.
+func (p Point) NoArgs() {
+ // Exercise no-argument/no-result paths.
+}
+
+// This will be index 4.
func (p Point) TotalDist(points ...Point) int {
tot := 0
for _, q := range points {
@@ -1661,6 +1714,15 @@ func TestMethod(t *testing.T) {
t.Errorf("Type MethodByName returned %d; want 275", i)
}
+ m, ok = TypeOf(p).MethodByName("NoArgs")
+ if !ok {
+ t.Fatalf("method by name failed")
+ }
+ n := len(m.Func.Call([]Value{ValueOf(p)}))
+ if n != 0 {
+ t.Errorf("NoArgs returned %d values; want 0", n)
+ }
+
i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(12)})[0].Int()
if i != 300 {
t.Errorf("Pointer Type Method returned %d; want 300", i)
@@ -1675,6 +1737,15 @@ func TestMethod(t *testing.T) {
t.Errorf("Pointer Type MethodByName returned %d; want 325", i)
}
+ m, ok = TypeOf(&p).MethodByName("NoArgs")
+ if !ok {
+ t.Fatalf("method by name failed")
+ }
+ n = len(m.Func.Call([]Value{ValueOf(&p)}))
+ if n != 0 {
+ t.Errorf("NoArgs returned %d values; want 0", n)
+ }
+
// Curried method of value.
tfunc := TypeOf((func(int) int)(nil))
v := ValueOf(p).Method(1)
@@ -1693,6 +1764,8 @@ func TestMethod(t *testing.T) {
if i != 375 {
t.Errorf("Value MethodByName returned %d; want 375", i)
}
+ v = ValueOf(p).MethodByName("NoArgs")
+ v.Call(nil)
// Curried method of pointer.
v = ValueOf(&p).Method(1)
@@ -1711,6 +1784,8 @@ func TestMethod(t *testing.T) {
if i != 425 {
t.Errorf("Pointer Value MethodByName returned %d; want 425", i)
}
+ v = ValueOf(&p).MethodByName("NoArgs")
+ v.Call(nil)
// Curried method of interface value.
// Have to wrap interface value in a struct to get at it.
@@ -1760,6 +1835,9 @@ func TestMethodValue(t *testing.T) {
if i != 275 {
t.Errorf("Value MethodByName returned %d; want 275", i)
}
+ v = ValueOf(p).MethodByName("NoArgs")
+ ValueOf(v.Interface()).Call(nil)
+ v.Interface().(func())()
// Curried method of pointer.
v = ValueOf(&p).Method(1)
@@ -1778,6 +1856,9 @@ func TestMethodValue(t *testing.T) {
if i != 325 {
t.Errorf("Pointer Value MethodByName returned %d; want 325", i)
}
+ v = ValueOf(&p).MethodByName("NoArgs")
+ ValueOf(v.Interface()).Call(nil)
+ v.Interface().(func())()
// Curried method of pointer to pointer.
pp := &p
@@ -1833,7 +1914,7 @@ func TestVariadicMethodValue(t *testing.T) {
// Curried method of value.
tfunc := TypeOf((func(...Point) int)(nil))
- v := ValueOf(p).Method(3)
+ v := ValueOf(p).Method(4)
if tt := v.Type(); tt != tfunc {
t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc)
}
@@ -1891,32 +1972,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)
}
@@ -1960,7 +2015,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)
@@ -2002,39 +2056,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) })
@@ -2323,6 +2344,8 @@ func TestImportPath(t *testing.T) {
{TypeOf((*int64)(nil)), ""},
{TypeOf(map[string]int{}), ""},
{TypeOf((*error)(nil)).Elem(), ""},
+ {TypeOf((*Point)(nil)), ""},
+ {TypeOf((*Point)(nil)).Elem(), "reflect_test"},
}
for _, test := range tests {
if path := test.t.PkgPath(); path != test.path {
@@ -2331,6 +2354,47 @@ func TestImportPath(t *testing.T) {
}
}
+func TestFieldPkgPath(t *testing.T) {
+ typ := TypeOf(struct {
+ Exported string
+ unexported string
+ OtherPkgFields
+ }{})
+
+ type pkgpathTest struct {
+ index []int
+ pkgPath string
+ anonymous bool
+ }
+
+ checkPkgPath := func(name string, s []pkgpathTest) {
+ for _, test := range s {
+ f := typ.FieldByIndex(test.index)
+ if got, want := f.PkgPath, test.pkgPath; got != want {
+ t.Errorf("%s: Field(%d).PkgPath = %q, want %q", name, test.index, got, want)
+ }
+ if got, want := f.Anonymous, test.anonymous; got != want {
+ t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want)
+ }
+ }
+ }
+
+ checkPkgPath("testStruct", []pkgpathTest{
+ {[]int{0}, "", false}, // Exported
+ {[]int{1}, "reflect_test", false}, // unexported
+ {[]int{2}, "", true}, // OtherPkgFields
+ {[]int{2, 0}, "", false}, // OtherExported
+ {[]int{2, 1}, "reflect", false}, // otherUnexported
+ })
+
+ type localOtherPkgFields OtherPkgFields
+ typ = TypeOf(localOtherPkgFields{})
+ checkPkgPath("localOtherPkgFields", []pkgpathTest{
+ {[]int{0}, "", false}, // OtherExported
+ {[]int{1}, "reflect", false}, // otherUnexported
+ })
+}
+
func TestVariadicType(t *testing.T) {
// Test example from Type documentation.
var f func(x int, y ...float64)
@@ -2363,14 +2427,14 @@ type outer struct {
inner
}
-func (*inner) m() {}
-func (*outer) m() {}
+func (*inner) M() {}
+func (*outer) M() {}
func TestNestedMethods(t *testing.T) {
t.Skip("fails on gccgo due to function wrappers")
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())
@@ -2378,6 +2442,25 @@ func TestNestedMethods(t *testing.T) {
}
}
+type unexp struct{}
+
+func (*unexp) f() (int32, int8) { return 7, 7 }
+func (*unexp) g() (int64, int8) { return 8, 8 }
+
+type unexpI interface {
+ f() (int32, int8)
+}
+
+var unexpi unexpI = new(unexp)
+
+func TestUnexportedMethods(t *testing.T) {
+ typ := TypeOf(unexpi)
+
+ if got := typ.NumMethod(); got != 0 {
+ t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
+ }
+}
+
type InnerInt struct {
X int
}
@@ -2419,18 +2502,36 @@ func TestEmbeddedMethods(t *testing.T) {
}
}
+type FuncDDD func(...interface{}) error
+
+func (f FuncDDD) M() {}
+
+func TestNumMethodOnDDD(t *testing.T) {
+ rv := ValueOf((FuncDDD)(nil))
+ if n := rv.NumMethod(); n != 1 {
+ t.Fatalf("NumMethod()=%d, want 1", n)
+ }
+}
+
func TestPtrTo(t *testing.T) {
+ // This block of code means that the ptrToThis field of the
+ // reflect data for *unsafe.Pointer is non zero, see
+ // https://golang.org/issue/19003
+ var x unsafe.Pointer
+ var y = &x
+ var z = &y
+
var i int
- typ := TypeOf(i)
+ typ := TypeOf(z)
for i = 0; i < 100; i++ {
typ = PtrTo(typ)
}
for i = 0; i < 100; i++ {
typ = typ.Elem()
}
- if typ != TypeOf(i) {
- t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i))
+ if typ != TypeOf(z) {
+ t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z))
}
}
@@ -2861,12 +2962,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) {
@@ -3081,6 +3181,9 @@ func ReadWriterV(x io.ReadWriter) Value {
}
type Empty struct{}
+type MyStruct struct {
+ x int `some:"tag"`
+}
type MyString string
type MyBytes []byte
type MyRunes []int32
@@ -3392,6 +3495,35 @@ var convertTests = []struct {
{V((func())(nil)), V(MyFunc(nil))},
{V((MyFunc)(nil)), V((func())(nil))},
+ // structs with different tags
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(MyStruct{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(MyStruct{})},
+
// can convert *byte and *MyByte
{V((*byte)(nil)), V((*MyByte)(nil))},
{V((*MyByte)(nil)), V((*byte)(nil))},
@@ -3846,6 +3978,9 @@ func TestSliceOf(t *testing.T) {
// check construction and use of type not in binary
type T int
st := SliceOf(TypeOf(T(1)))
+ if got, want := st.String(), "[]reflect_test.T"; got != want {
+ t.Errorf("SliceOf(T(1)).String()=%q, want %q", got, want)
+ }
v := MakeSlice(st, 10, 10)
runtime.GC()
for i := 0; i < v.Len(); i++ {
@@ -3910,6 +4045,624 @@ func TestSliceOfGC(t *testing.T) {
}
}
+func TestStructOf(t *testing.T) {
+ // check construction and use of type not in binary
+ fields := []StructField{
+ StructField{
+ Name: "S",
+ Tag: "s",
+ Type: TypeOf(""),
+ },
+ StructField{
+ Name: "X",
+ Tag: "x",
+ Type: TypeOf(byte(0)),
+ },
+ StructField{
+ Name: "Y",
+ Type: TypeOf(uint64(0)),
+ },
+ StructField{
+ Name: "Z",
+ Type: TypeOf([3]uint16{}),
+ },
+ }
+
+ st := StructOf(fields)
+ v := New(st).Elem()
+ runtime.GC()
+ v.FieldByName("X").Set(ValueOf(byte(2)))
+ v.FieldByIndex([]int{1}).Set(ValueOf(byte(1)))
+ runtime.GC()
+
+ s := fmt.Sprint(v.Interface())
+ want := `{ 1 0 [0 0 0]}`
+ if s != want {
+ t.Errorf("constructed struct = %s, want %s", s, want)
+ }
+ const stStr = `struct { S string "s"; X uint8 "x"; Y uint64; Z [3]uint16 }`
+ if got, want := st.String(), stStr; got != want {
+ t.Errorf("StructOf(fields).String()=%q, want %q", got, want)
+ }
+
+ // check the size, alignment and field offsets
+ stt := TypeOf(struct {
+ String string
+ X byte
+ Y uint64
+ Z [3]uint16
+ }{})
+ if st.Size() != stt.Size() {
+ t.Errorf("constructed struct size = %v, want %v", st.Size(), stt.Size())
+ }
+ if st.Align() != stt.Align() {
+ t.Errorf("constructed struct align = %v, want %v", st.Align(), stt.Align())
+ }
+ if st.FieldAlign() != stt.FieldAlign() {
+ t.Errorf("constructed struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+ }
+ for i := 0; i < st.NumField(); i++ {
+ o1 := st.Field(i).Offset
+ o2 := stt.Field(i).Offset
+ if o1 != o2 {
+ t.Errorf("constructed struct field %v offset = %v, want %v", i, o1, o2)
+ }
+ }
+
+ // Check size and alignment with a trailing zero-sized field.
+ st = StructOf([]StructField{
+ {
+ Name: "F1",
+ Type: TypeOf(byte(0)),
+ },
+ {
+ Name: "F2",
+ Type: TypeOf([0]*byte{}),
+ },
+ })
+ stt = TypeOf(struct {
+ G1 byte
+ G2 [0]*byte
+ }{})
+ // Broken with gccgo for now--gccgo does not pad structs yet.
+ // if st.Size() != stt.Size() {
+ // t.Errorf("constructed zero-padded struct size = %v, want %v", st.Size(), stt.Size())
+ // }
+ if st.Align() != stt.Align() {
+ t.Errorf("constructed zero-padded struct align = %v, want %v", st.Align(), stt.Align())
+ }
+ if st.FieldAlign() != stt.FieldAlign() {
+ t.Errorf("constructed zero-padded struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+ }
+ for i := 0; i < st.NumField(); i++ {
+ o1 := st.Field(i).Offset
+ o2 := stt.Field(i).Offset
+ if o1 != o2 {
+ t.Errorf("constructed zero-padded struct field %v offset = %v, want %v", i, o1, o2)
+ }
+ }
+
+ // check duplicate names
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Name: "string", Type: TypeOf("")},
+ StructField{Name: "string", Type: TypeOf("")},
+ })
+ })
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Type: TypeOf("")},
+ StructField{Name: "string", Type: TypeOf("")},
+ })
+ })
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Type: TypeOf("")},
+ StructField{Type: TypeOf("")},
+ })
+ })
+ // check that type already in binary is found
+ checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{})
+}
+
+func TestStructOfExportRules(t *testing.T) {
+ type S1 struct{}
+ type s2 struct{}
+ type ΦType struct{}
+ type φType struct{}
+
+ testPanic := func(i int, mustPanic bool, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil && mustPanic {
+ t.Errorf("test-%d did not panic", i)
+ }
+ if err != nil && !mustPanic {
+ t.Errorf("test-%d panicked: %v\n", i, err)
+ }
+ }()
+ f()
+ }
+
+ for i, test := range []struct {
+ field StructField
+ mustPanic bool
+ exported bool
+ }{
+ {
+ field: StructField{Name: "", Type: TypeOf(S1{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*S1)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(s2{})},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*s2)(nil))},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf(S1{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf(s2{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(S1{})},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*S1)(nil))},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(s2{})},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*s2)(nil))},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(ΦType{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(φType{})},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "Φ", Type: TypeOf(0)},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "φ", Type: TypeOf(0)},
+ mustPanic: false,
+ exported: false,
+ },
+ } {
+ testPanic(i, test.mustPanic, func() {
+ typ := StructOf([]StructField{test.field})
+ if typ == nil {
+ t.Errorf("test-%d: error creating struct type", i)
+ return
+ }
+ field := typ.Field(0)
+ n := field.Name
+ if n == "" {
+ n = field.Type.Name()
+ }
+ exported := isExported(n)
+ if exported != test.exported {
+ t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported)
+ }
+ })
+ }
+}
+
+// isExported reports whether name is an exported Go symbol
+// (that is, whether it begins with an upper-case letter).
+//
+func isExported(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(ch)
+}
+
+func TestStructOfGC(t *testing.T) {
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ fields := []StructField{
+ {Name: "X", Type: tt},
+ {Name: "Y", Type: tt},
+ }
+ st := StructOf(fields)
+
+ const n = 10000
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := New(st).Elem()
+ for j := 0; j < v.NumField(); j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.Field(j).Set(ValueOf(p).Convert(tt))
+ }
+ x = append(x, v.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ v := ValueOf(xi)
+ for j := 0; j < v.NumField(); j++ {
+ k := v.Field(j).Elem().Interface()
+ if k != uintptr(i*n+j) {
+ t.Errorf("lost x[%d].%c = %d, want %d", i, "XY"[j], k, i*n+j)
+ }
+ }
+ }
+}
+
+func TestStructOfAlg(t *testing.T) {
+ st := StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf(int(0))}})
+ v1 := New(st).Elem()
+ v2 := New(st).Elem()
+ if !DeepEqual(v1.Interface(), v1.Interface()) {
+ t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+ }
+ v1.FieldByName("X").Set(ValueOf(int(1)))
+ if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+ }
+
+ st = StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf([]int(nil))}})
+ v1 = New(st).Elem()
+ shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
+}
+
+func TestStructOfGenericAlg(t *testing.T) {
+ st1 := StructOf([]StructField{
+ {Name: "X", Tag: "x", Type: TypeOf(int64(0))},
+ {Name: "Y", Type: TypeOf(string(""))},
+ })
+ st := StructOf([]StructField{
+ {Name: "S0", Type: st1},
+ {Name: "S1", Type: st1},
+ })
+
+ for _, table := range []struct {
+ rt Type
+ idx []int
+ }{
+ {
+ rt: st,
+ idx: []int{0, 1},
+ },
+ {
+ rt: st1,
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([0]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([0]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([2]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([1]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([1]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([1]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([2]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([2]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf(int64(0))},
+ {Name: "YY", Type: TypeOf(byte(0))},
+ {Name: "ZZ", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{2},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf(int64(0))},
+ {Name: "YY", Type: TypeOf(int64(0))},
+ {Name: "ZZ", Type: TypeOf("")},
+ {Name: "AA", Type: TypeOf([1]int64{})},
+ },
+ ),
+ idx: []int{2},
+ },
+ } {
+ v1 := New(table.rt).Elem()
+ v2 := New(table.rt).Elem()
+
+ if !DeepEqual(v1.Interface(), v1.Interface()) {
+ t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+ }
+
+ v1.FieldByIndex(table.idx).Set(ValueOf("abc"))
+ v2.FieldByIndex(table.idx).Set(ValueOf("def"))
+ if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+ }
+
+ abc := "abc"
+ v1.FieldByIndex(table.idx).Set(ValueOf(abc))
+ val := "+" + abc + "-"
+ v2.FieldByIndex(table.idx).Set(ValueOf(val[1:4]))
+ if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+ }
+
+ // Test hash
+ m := MakeMap(MapOf(table.rt, TypeOf(int(0))))
+ m.SetMapIndex(v1, ValueOf(1))
+ if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+ t.Errorf("constructed structs %#v and %#v have different hashes", i1, i2)
+ }
+
+ v2.FieldByIndex(table.idx).Set(ValueOf("abc"))
+ if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+ }
+
+ if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+ t.Errorf("constructed structs %v and %v have different hashes", i1, i2)
+ }
+ }
+}
+
+/*
+gccgo does not use the same directiface settings as gc.
+
+func TestStructOfDirectIface(t *testing.T) {
+ {
+ type T struct{ X [1]*byte }
+ i1 := Zero(TypeOf(T{})).Interface()
+ v1 := ValueOf(&i1).Elem()
+ p1 := v1.InterfaceData()[1]
+
+ i2 := Zero(StructOf([]StructField{
+ {
+ Name: "X",
+ Type: ArrayOf(1, TypeOf((*int8)(nil))),
+ },
+ })).Interface()
+ v2 := ValueOf(&i2).Elem()
+ p2 := v2.InterfaceData()[1]
+
+ if p1 != 0 {
+ t.Errorf("got p1=%v. want=%v", p1, nil)
+ }
+
+ if p2 != 0 {
+ t.Errorf("got p2=%v. want=%v", p2, nil)
+ }
+ }
+ {
+ type T struct{ X [0]*byte }
+ i1 := Zero(TypeOf(T{})).Interface()
+ v1 := ValueOf(&i1).Elem()
+ p1 := v1.InterfaceData()[1]
+
+ i2 := Zero(StructOf([]StructField{
+ {
+ Name: "X",
+ Type: ArrayOf(0, TypeOf((*int8)(nil))),
+ },
+ })).Interface()
+ v2 := ValueOf(&i2).Elem()
+ p2 := v2.InterfaceData()[1]
+
+ if p1 == 0 {
+ t.Errorf("got p1=%v. want=not-%v", p1, nil)
+ }
+
+ if p2 == 0 {
+ t.Errorf("got p2=%v. want=not-%v", p2, nil)
+ }
+ }
+}
+*/
+
+type StructI int
+
+func (i StructI) Get() int { return int(i) }
+
+type StructIPtr int
+
+func (i *StructIPtr) Get() int { return int(*i) }
+
+/*
+gccgo does not yet support StructOf with methods.
+
+func TestStructOfWithInterface(t *testing.T) {
+ const want = 42
+ type Iface interface {
+ Get() int
+ }
+ for i, table := range []struct {
+ typ Type
+ val Value
+ impl bool
+ }{
+ {
+ typ: TypeOf(StructI(want)),
+ val: ValueOf(StructI(want)),
+ impl: true,
+ },
+ {
+ typ: PtrTo(TypeOf(StructI(want))),
+ val: ValueOf(func() interface{} {
+ v := StructI(want)
+ return &v
+ }()),
+ impl: true,
+ },
+ {
+ typ: PtrTo(TypeOf(StructIPtr(want))),
+ val: ValueOf(func() interface{} {
+ v := StructIPtr(want)
+ return &v
+ }()),
+ impl: true,
+ },
+ {
+ typ: TypeOf(StructIPtr(want)),
+ val: ValueOf(StructIPtr(want)),
+ impl: false,
+ },
+ // {
+ // typ: TypeOf((*Iface)(nil)).Elem(), // FIXME(sbinet): fix method.ifn/tfn
+ // val: ValueOf(StructI(want)),
+ // impl: true,
+ // },
+ } {
+ rt := StructOf(
+ []StructField{
+ {
+ Name: "",
+ PkgPath: "",
+ Type: table.typ,
+ },
+ },
+ )
+ rv := New(rt).Elem()
+ rv.Field(0).Set(table.val)
+
+ if _, ok := rv.Interface().(Iface); ok != table.impl {
+ 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", i, table.typ)
+ }
+ continue
+ }
+
+ if !table.impl {
+ continue
+ }
+
+ v := rv.Interface().(Iface).Get()
+ if v != want {
+ t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, v, want)
+ }
+
+ fct := rv.MethodByName("Get")
+ out := fct.Call(nil)
+ if !DeepEqual(out[0].Interface(), want) {
+ t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, out[0].Interface(), want)
+ }
+ }
+}
+*/
+
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
@@ -4116,7 +4869,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")
}
@@ -4128,7 +4881,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 {
@@ -4479,7 +5232,7 @@ func TestFieldByIndexNil(t *testing.T) {
// off the stack into the frame will store an *Inner there, and then if a garbage collection
// happens to scan that argument frame before it is discarded, it will scan the *Inner
// memory as if it were an *Outer. If the two have different memory layouts, the
-// collection will intepret the memory incorrectly.
+// collection will interpret the memory incorrectly.
//
// One such possible incorrect interpretation is to treat two arbitrary memory words
// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
@@ -4555,7 +5308,7 @@ func useStack(n int) {
type Impl struct{}
-func (Impl) f() {}
+func (Impl) F() {}
func TestValueString(t *testing.T) {
rv := ValueOf(Impl{})
@@ -4589,6 +5342,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) {
@@ -4602,6 +5390,72 @@ func TestCallGC(t *testing.T) {
f2("four", "five5", "six666", "seven77", "eight888")
}
+// Issue 18635 (function version).
+func TestKeepFuncLive(t *testing.T) {
+ // Test that we keep makeFuncImpl live as long as it is
+ // referenced on the stack.
+ typ := TypeOf(func(i int) {})
+ var f, g func(in []Value) []Value
+ f = func(in []Value) []Value {
+ clobber()
+ i := int(in[0].Int())
+ if i > 0 {
+ // We can't use Value.Call here because
+ // runtime.call* will keep the makeFuncImpl
+ // alive. However, by converting it to an
+ // interface value and calling that,
+ // reflect.callReflect is the only thing that
+ // can keep the makeFuncImpl live.
+ //
+ // Alternate between f and g so that if we do
+ // reuse the memory prematurely it's more
+ // likely to get obviously corrupted.
+ MakeFunc(typ, g).Interface().(func(i int))(i - 1)
+ }
+ return nil
+ }
+ g = func(in []Value) []Value {
+ clobber()
+ i := int(in[0].Int())
+ MakeFunc(typ, f).Interface().(func(i int))(i)
+ return nil
+ }
+ MakeFunc(typ, f).Call([]Value{ValueOf(10)})
+}
+
+// Issue 18635 (method version).
+type KeepMethodLive struct{}
+
+func (k KeepMethodLive) Method1(i int) {
+ clobber()
+ if i > 0 {
+ ValueOf(k).MethodByName("Method2").Interface().(func(i int))(i - 1)
+ }
+}
+
+func (k KeepMethodLive) Method2(i int) {
+ clobber()
+ ValueOf(k).MethodByName("Method1").Interface().(func(i int))(i)
+}
+
+func TestKeepMethodLive(t *testing.T) {
+ // Test that we keep methodValue live as long as it is
+ // referenced on the stack.
+ KeepMethodLive{}.Method1(10)
+}
+
+// clobber tries to clobber unreachable memory.
+func clobber() {
+ runtime.GC()
+ for i := 1; i < 32; i++ {
+ for j := 0; j < 10; j++ {
+ obj := make([]*byte, i)
+ sink = obj
+ }
+ }
+ runtime.GC()
+}
+
type funcLayoutTest struct {
rcvr, t Type
size, argsize, retOffset uintptr
@@ -4716,7 +5570,7 @@ func init() {
2 * PtrSize,
[]byte{1},
[]byte{1},
- // Note: this one is tricky, as the receiver is not a pointer. But we
+ // Note: this one is tricky, as the receiver is not a pointer. But we
// pass the receiver by reference to the autogenerated pointer-receiver
// version of the function.
})
@@ -4768,6 +5622,9 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
for len(bits) > 2 && bits[len(bits)-1] == 0 {
bits = bits[:len(bits)-1]
}
+ if len(bits) == 2 && bits[0] == 0 && bits[1] == 0 {
+ bits = bits[:0]
+ }
if !bytes.Equal(heapBits, bits) {
t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
}
@@ -5027,6 +5884,240 @@ func TestChanAlloc(t *testing.T) {
t.Errorf("allocs per chan send/recv: want 1 got %f", allocs)
}
// Note: there is one allocation in reflect.recv which seems to be
- // a limitation of escape analysis. If that is ever fixed the
+ // a limitation of escape analysis. If that is ever fixed the
// allocs < 0.5 condition will trigger and this test should be fixed.
}
+
+type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int
+
+type nameTest struct {
+ v interface{}
+ want string
+}
+
+var nameTests = []nameTest{
+ {(*int32)(nil), "int32"},
+ {(*D1)(nil), "D1"},
+ {(*[]D1)(nil), ""},
+ {(*chan D1)(nil), ""},
+ {(*func() D1)(nil), ""},
+ {(*<-chan D1)(nil), ""},
+ {(*chan<- D1)(nil), ""},
+ {(*interface{})(nil), ""},
+ {(*interface {
+ F()
+ })(nil), ""},
+ {(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"},
+}
+
+func TestNames(t *testing.T) {
+ for _, test := range nameTests {
+ typ := TypeOf(test.v).Elem()
+ if got := typ.Name(); got != test.want {
+ t.Errorf("%v Name()=%q, want %q", typ, got, test.want)
+ }
+ }
+}
+
+/*
+gccgo doesn't really record whether a type is exported.
+It's not in the reflect API anyhow.
+
+func TestExported(t *testing.T) {
+ type ΦExported struct{}
+ type φUnexported struct{}
+ type BigP *big
+ type P int
+ type p *P
+ type P2 p
+ type p3 p
+
+ type exportTest struct {
+ v interface{}
+ want bool
+ }
+ exportTests := []exportTest{
+ {D1{}, true},
+ {(*D1)(nil), true},
+ {big{}, false},
+ {(*big)(nil), false},
+ {(BigP)(nil), true},
+ {(*BigP)(nil), true},
+ {ΦExported{}, true},
+ {φUnexported{}, false},
+ {P(0), true},
+ {(p)(nil), false},
+ {(P2)(nil), true},
+ {(p3)(nil), false},
+ }
+
+ for i, test := range exportTests {
+ typ := TypeOf(test.v)
+ if got := IsExported(typ); got != test.want {
+ t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want)
+ }
+ }
+}
+*/
+
+type embed struct {
+ EmbedWithUnexpMeth
+}
+
+/*
+func TestNameBytesAreAligned(t *testing.T) {
+ typ := TypeOf(embed{})
+ b := FirstMethodNameBytes(typ)
+ v := uintptr(unsafe.Pointer(b))
+ if v%unsafe.Alignof((*byte)(nil)) != 0 {
+ t.Errorf("reflect.name.bytes pointer is not aligned: %x", v)
+ }
+}
+*/
+
+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"},
+ {ChanOf(3, TypeOf(XM{})), "chan reflect_test.XM"},
+ {MapOf(TypeOf(int(0)), TypeOf(XM{})), "map[int]reflect_test.XM"},
+ }
+
+ 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)
+ }
+ }
+}
+
+/*
+gccgo does not have resolveReflectName.
+
+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()
+}
+*/
+
+func BenchmarkNew(b *testing.B) {
+ v := TypeOf(XM{})
+ for i := 0; i < b.N; i++ {
+ New(v)
+ }
+}
+
+func TestSwapper(t *testing.T) {
+ type I int
+ var a, b, c I
+ type pair struct {
+ x, y int
+ }
+ type pairPtr struct {
+ x, y int
+ p *I
+ }
+ type S string
+
+ tests := []struct {
+ in interface{}
+ i, j int
+ want interface{}
+ }{
+ {
+ in: []int{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int{300, 20, 1},
+ },
+ {
+ in: []uintptr{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []uintptr{300, 20, 1},
+ },
+ {
+ in: []int16{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int16{300, 20, 1},
+ },
+ {
+ in: []int8{1, 20, 100},
+ i: 0,
+ j: 2,
+ want: []int8{100, 20, 1},
+ },
+ {
+ in: []*I{&a, &b, &c},
+ i: 0,
+ j: 2,
+ want: []*I{&c, &b, &a},
+ },
+ {
+ in: []string{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []string{"larry", "sergey", "eric"},
+ },
+ {
+ in: []S{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []S{"larry", "sergey", "eric"},
+ },
+ {
+ in: []pair{{1, 2}, {3, 4}, {5, 6}},
+ i: 0,
+ j: 2,
+ want: []pair{{5, 6}, {3, 4}, {1, 2}},
+ },
+ {
+ in: []pairPtr{{1, 2, &a}, {3, 4, &b}, {5, 6, &c}},
+ i: 0,
+ j: 2,
+ want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
+ },
+ }
+ for i, tt := range tests {
+ inStr := fmt.Sprint(tt.in)
+ Swapper(tt.in)(tt.i, tt.j)
+ if !DeepEqual(tt.in, tt.want) {
+ t.Errorf("%d. swapping %v and %v of %v = %v; want %v", i, tt.i, tt.j, inStr, tt.in, tt.want)
+ }
+ }
+}
+
+// TestUnaddressableField tests that the reflect package will not allow
+// a type from another package to be used as a named type with an
+// unexported field.
+//
+// This ensures that unexported fields cannot be modified by other packages.
+func TestUnaddressableField(t *testing.T) {
+ var b Buffer // type defined in reflect, a different package
+ var localBuffer struct {
+ buf []byte
+ }
+ lv := ValueOf(&localBuffer).Elem()
+ rv := ValueOf(b)
+ shouldPanic(func() {
+ lv.Set(rv)
+ })
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index 3743e8042d..f3fd7043e5 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -9,7 +9,7 @@ package reflect
import "unsafe"
// During deepValueEqual, must keep track of checks that are
-// in progress. The comparison algorithm assumes that all
+// in progress. The comparison algorithm assumes that all
// checks in progress are true when it reencounters them.
// Visited comparisons are stored in a map indexed by visit.
type visit struct {
@@ -30,9 +30,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
}
// if depth > 10 { panic("deepValueEqual") } // for debugging
+
+ // We want to avoid putting more in the visited map than we need to.
+ // For any possible reference cycle that might be encountered,
+ // hard(t) needs to return true for at least one of the types in the cycle.
hard := func(k Kind) bool {
switch k {
- case Array, Map, Slice, Struct:
+ case Map, Slice, Ptr, Interface:
return true
}
return false
@@ -142,8 +146,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
//
// Interface values are deeply equal if they hold deeply equal concrete values.
//
-// Map values are deeply equal if they are the same map object
-// or if they have the same length and their corresponding keys
+// Map values are deeply equal when all of the following are true:
+// they are both nil or both non-nil, they have the same length,
+// and either they are the same map object or their corresponding keys
// (matched using Go equality) map to deeply equal values.
//
// Pointer values are deeply equal if they are equal using Go's == operator
diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go
index 8ebf9765b8..f959b95846 100644
--- a/libgo/go/reflect/example_test.go
+++ b/libgo/go/reflect/example_test.go
@@ -1,10 +1,12 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflect_test
import (
+ "bytes"
+ "encoding/json"
"fmt"
"io"
"os"
@@ -67,6 +69,34 @@ func ExampleStructTag() {
// blue gopher
}
+func ExampleStructTag_Lookup() {
+ type S struct {
+ F0 string `alias:"field_0"`
+ F1 string `alias:""`
+ F2 string
+ }
+
+ s := S{}
+ st := reflect.TypeOf(s)
+ for i := 0; i < st.NumField(); i++ {
+ field := st.Field(i)
+ if alias, ok := field.Tag.Lookup("alias"); ok {
+ if alias == "" {
+ fmt.Println("(blank)")
+ } else {
+ fmt.Println(alias)
+ }
+ } else {
+ fmt.Println("(not specified)")
+ }
+ }
+
+ // Output:
+ // field_0
+ // (blank)
+ // (not specified)
+}
+
func ExampleTypeOf() {
// As interface types are only used for static typing, a
// common idiom to find the reflection Type for an interface
@@ -79,3 +109,42 @@ func ExampleTypeOf() {
// Output:
// true
}
+
+func ExampleStructOf() {
+ typ := reflect.StructOf([]reflect.StructField{
+ {
+ Name: "Height",
+ Type: reflect.TypeOf(float64(0)),
+ Tag: `json:"height"`,
+ },
+ {
+ Name: "Age",
+ Type: reflect.TypeOf(int(0)),
+ Tag: `json:"age"`,
+ },
+ })
+
+ v := reflect.New(typ).Elem()
+ v.Field(0).SetFloat(0.4)
+ v.Field(1).SetInt(2)
+ s := v.Addr().Interface()
+
+ w := new(bytes.Buffer)
+ if err := json.NewEncoder(w).Encode(s); err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("value: %+v\n", s)
+ fmt.Printf("json: %s", w.Bytes())
+
+ r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
+ if err := json.NewDecoder(r).Decode(s); err != nil {
+ panic(err)
+ }
+ fmt.Printf("value: %+v\n", s)
+
+ // Output:
+ // value: &{Height:0.4 Age:2}
+ // json: {"height":0.4,"age":2}
+ // value: &{Height:1.5 Age:10}
+}
diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go
index bdbd60074a..92b1302538 100644
--- a/libgo/go/reflect/export_test.go
+++ b/libgo/go/reflect/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -41,3 +41,49 @@ func MapBucketOf(x, y Type) Type {
func CachedBucketOf(m Type) Type {
return nil
}
+
+type EmbedWithUnexpMeth struct{}
+
+func (EmbedWithUnexpMeth) f() {}
+
+type pinUnexpMeth interface {
+ f()
+}
+
+var pinUnexpMethI = pinUnexpMeth(EmbedWithUnexpMeth{})
+
+/*
+func FirstMethodNameBytes(t Type) *byte {
+ _ = pinUnexpMethI
+
+ ut := t.uncommon()
+ if ut == nil {
+ panic("type has no methods")
+ }
+ m := ut.methods()[0]
+ mname := t.(*rtype).nameOff(m.name)
+ if *mname.data(0)&(1<<2) == 0 {
+ panic("method name does not have pkgPath *string")
+ }
+ return mname.bytes
+}
+*/
+
+type OtherPkgFields struct {
+ OtherExported int
+ otherUnexported int
+}
+
+func IsExported(t Type) bool {
+ return t.PkgPath() == ""
+}
+
+/*
+func ResolveReflectName(s string) {
+ resolveReflectName(newName(s, "", "", false))
+}
+*/
+
+type Buffer struct {
+ buf []byte
+}
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 7ec277b864..91df32839c 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -12,8 +12,8 @@ import (
// makeFuncImpl is the closure value implementing the function
// returned by MakeFunc.
+// The first three words are layed out like ffi_go_closure.
type makeFuncImpl struct {
- // These first three words are layed out like ffi_go_closure.
code uintptr
ffi_cif unsafe.Pointer
ffi_fun func(unsafe.Pointer, unsafe.Pointer)
@@ -63,7 +63,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
method: -1,
}
- makeFuncFFI(ftyp, unsafe.Pointer(impl))
+ makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl))
return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir}
}
@@ -102,7 +102,7 @@ func makeMethodValue(op string, v Value) Value {
rcvr: rcvr,
}
- makeFuncFFI(ftyp, unsafe.Pointer(fv))
+ makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(fv))
return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir}
}
@@ -128,7 +128,7 @@ func makeValueMethod(v Value) Value {
rcvr: v,
}
- makeFuncFFI(ftyp, unsafe.Pointer(impl))
+ makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl))
return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir}
}
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
index c821131bab..2acf7bb887 100644
--- a/libgo/go/reflect/makefunc_ffi.go
+++ b/libgo/go/reflect/makefunc_ffi.go
@@ -10,7 +10,10 @@ import (
// The makeFuncFFI function, written in C, fills in an FFI closure.
// It arranges for ffiCall to be invoked directly from FFI.
-func makeFuncFFI(ftyp *funcType, impl unsafe.Pointer)
+func makeFuncFFI(cif unsafe.Pointer, impl unsafe.Pointer)
+
+// The makeCIF function, implemented in the runtime package, allocates a CIF.
+func makeCIF(ft *funcType) unsafe.Pointer
// FFICallbackGo implements the Go side of the libffi callback.
// It is exported so that C code can call it.
diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c
index 06a41ef2ec..ef5fb9f083 100644
--- a/libgo/go/reflect/makefunc_ffi_c.c
+++ b/libgo/go/reflect/makefunc_ffi_c.c
@@ -4,11 +4,10 @@
#include "runtime.h"
#include "go-type.h"
-#include "go-panic.h"
#ifdef USE_LIBFFI
-#include "go-ffi.h"
+#include "ffi.h"
#if FFI_GO_CLOSURES
#define USE_LIBFFI_CLOSURES
@@ -18,7 +17,7 @@
/* Declare C functions with the names used to call from Go. */
-void makeFuncFFI(const struct __go_func_type *ftyp, void *impl)
+void makeFuncFFI(void *cif, void *impl)
__asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");
#ifdef USE_LIBFFI_CLOSURES
@@ -27,9 +26,15 @@ void makeFuncFFI(const struct __go_func_type *ftyp, void *impl)
function ffiCall with the pointer to the arguments, the results area,
and the closure structure. */
-void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
+extern void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
__asm__ (GOSYM_PREFIX "reflect.FFICallbackGo");
+extern void makefuncfficanrecover(Slice)
+ __asm__ (GOSYM_PREFIX "runtime.makefuncfficanrecover");
+
+extern void makefuncreturning(void)
+ __asm__ (GOSYM_PREFIX "runtime.makefuncreturning");
+
static void ffi_callback (ffi_cif *, void *, void **, void *)
__asm__ ("reflect.ffi_callback");
@@ -59,31 +64,33 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
break;
}
if (i < n)
- __go_makefunc_ffi_can_recover (locs + i, n - i);
+ {
+ Slice s;
+
+ s.__values = (void *) &locs[i];
+ s.__count = n - i;
+ s.__capacity = n - i;
+ makefuncfficanrecover (s);
+ }
FFICallbackGo(results, args, closure);
if (i < n)
- __go_makefunc_returning ();
+ makefuncreturning ();
}
/* Allocate an FFI closure and arrange to call ffi_callback. */
void
-makeFuncFFI(const struct __go_func_type *ftyp, void *impl)
+makeFuncFFI(void *cif, void *impl)
{
- ffi_cif *cif;
-
- cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif));
- __go_func_to_cif (ftyp, 0, 0, cif);
-
- ffi_prep_go_closure(impl, cif, ffi_callback);
+ ffi_prep_go_closure(impl, (ffi_cif*)cif, ffi_callback);
}
#else /* !defined(USE_LIBFFI_CLOSURES) */
void
-makeFuncFFI(const struct __go_func_type *ftyp __attribute__ ((unused)),
+makeFuncFFI(void *cif __attribute__ ((unused)),
void *impl __attribute__ ((unused)))
{
runtime_panicstring ("libgo built without FFI does not support "
diff --git a/libgo/go/reflect/set_test.go b/libgo/go/reflect/set_test.go
index 85dc55e681..bc35c78e1b 100644
--- a/libgo/go/reflect/set_test.go
+++ b/libgo/go/reflect/set_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -194,11 +194,13 @@ var assignableTests = []struct {
{new(*int), new(IntPtr), true},
{new(IntPtr), new(*int), true},
{new(IntPtr), new(IntPtr1), false},
+ {new(Ch), new(<-chan interface{}), true},
// test runs implementsTests too
}
type IntPtr *int
type IntPtr1 *int
+type Ch <-chan interface{}
func TestAssignableTo(t *testing.T) {
for _, tt := range append(assignableTests, implementsTests...) {
diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go
new file mode 100644
index 0000000000..5441cb0315
--- /dev/null
+++ b/libgo/go/reflect/swapper.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+
+import "unsafe"
+
+// Swapper returns a function that swaps the elements in the provided
+// slice.
+//
+// Swapper panics if the provided interface is not a slice.
+func Swapper(slice interface{}) func(i, j int) {
+ v := ValueOf(slice)
+ if v.Kind() != Slice {
+ panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
+ }
+ // Fast path for slices of size 0 and 1. Nothing to swap.
+ switch v.Len() {
+ case 0:
+ return func(i, j int) { panic("reflect: slice index out of range") }
+ case 1:
+ return func(i, j int) {
+ if i != 0 || j != 0 {
+ panic("reflect: slice index out of range")
+ }
+ }
+ }
+
+ typ := v.Type().Elem().(*rtype)
+ size := typ.Size()
+ hasPtr := typ.kind&kindNoPointers == 0
+
+ // Some common & small cases, without using memmove:
+ if hasPtr {
+ if size == ptrSize {
+ ps := *(*[]unsafe.Pointer)(v.ptr)
+ return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
+ }
+ if typ.Kind() == String {
+ ss := *(*[]string)(v.ptr)
+ return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
+ }
+ } else {
+ switch size {
+ case 8:
+ is := *(*[]int64)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 4:
+ is := *(*[]int32)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 2:
+ is := *(*[]int16)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 1:
+ is := *(*[]int8)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ }
+ }
+
+ s := (*sliceHeader)(v.ptr)
+ tmp := unsafe_New(typ) // swap scratch space
+
+ return func(i, j int) {
+ if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
+ panic("reflect: slice index out of range")
+ }
+ val1 := arrayAt(s.Data, i, size)
+ val2 := arrayAt(s.Data, j, size)
+ typedmemmove(typ, tmp, val1)
+ typedmemmove(typ, val1, val2)
+ typedmemmove(typ, val2, tmp)
+ }
+}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 88da632584..0325260455 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package reflect implements run-time reflection, allowing a program to
-// manipulate objects with arbitrary types. The typical use is to take a value
+// manipulate objects with arbitrary types. The typical use is to take a value
// with static type interface{} and extract its dynamic type information by
// calling TypeOf, which returns a Type.
//
@@ -16,7 +16,6 @@
package reflect
import (
- "runtime"
"strconv"
"sync"
"unsafe"
@@ -24,11 +23,14 @@ import (
// Type is the representation of a Go type.
//
-// Not all methods apply to all kinds of types. Restrictions,
+// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of type before
-// calling kind-specific methods. Calling a method
+// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
+//
+// Type values are comparable, such as with the == operator.
+// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.
@@ -60,7 +62,7 @@ type Type interface {
// method signature, without a receiver, and the Func field is nil.
MethodByName(string) (Method, bool)
- // NumMethod returns the number of methods in the type's method set.
+ // NumMethod returns the number of exported methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package.
@@ -80,7 +82,7 @@ type Type interface {
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
- // guaranteed to be unique among types. To test for equality,
+ // guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
@@ -124,7 +126,7 @@ type Type interface {
ChanDir() ChanDir
// IsVariadic reports whether a function type's final input parameter
- // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
+ // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
@@ -147,7 +149,7 @@ type Type interface {
Field(i int) StructField
// FieldByIndex returns the nested field corresponding
- // to the index sequence. It is equivalent to calling Field
+ // to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField
@@ -156,9 +158,18 @@ type Type interface {
// and a boolean indicating if the field was found.
FieldByName(name string) (StructField, bool)
- // FieldByNameFunc returns the first struct field with a name
+ // FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
+ //
+ // FieldByNameFunc considers the fields in the struct itself
+ // and then the fields in any anonymous structs, in breadth first order,
+ // stopping at the shallowest nesting depth containing one or more
+ // fields satisfying the match function. If multiple fields at that depth
+ // satisfy the match function, they cancel each other
+ // and FieldByNameFunc returns no match.
+ // This behavior mirrors Go's handling of name lookup in
+ // structs containing anonymous fields.
FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter.
@@ -255,8 +266,8 @@ type rtype struct {
size uintptr
hash uint32 // hash of type; avoids computation in hash tables
- hashfn func(unsafe.Pointer, uintptr) uintptr // hash function
- equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function
+ hashfn func(unsafe.Pointer, uintptr) uintptr // hash function
+ equalfn func(unsafe.Pointer, unsafe.Pointer) bool // equality function
gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful
@@ -330,9 +341,18 @@ type interfaceType struct {
// mapType represents a map type.
type mapType struct {
- rtype `reflect:"map"`
- key *rtype // map key type
- elem *rtype // map element (value) type
+ rtype `reflect:"map"`
+ key *rtype // map key type
+ elem *rtype // map element (value) type
+ bucket *rtype // internal bucket structure
+ hmap *rtype // internal map header
+ keysize uint8 // size of key slot
+ indirectkey uint8 // store ptr to key instead of key itself
+ valuesize uint8 // size of value slot
+ indirectvalue uint8 // store ptr to value instead of value itself
+ bucketsize uint16 // size of bucket
+ reflexivekey bool // true if k==k for all keys
+ needkeyupdate bool // true if we need to update key on an overwrite
}
// ptrType represents a pointer type.
@@ -389,7 +409,7 @@ const (
type Method struct {
// Name is the method name.
// PkgPath is the package path that qualifies a lower case (unexported)
- // method name. It is empty for upper case (exported) method names.
+ // method name. It is empty for upper case (exported) method names.
// The combination of PkgPath and Name uniquely identifies a method
// in a method set.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
@@ -509,6 +529,21 @@ func (t *uncommonType) Method(i int) (m Method) {
if t == nil || i < 0 || i >= len(t.methods) {
panic("reflect: Method index out of range")
}
+ found := false
+ for mi := range t.methods {
+ if t.methods[mi].pkgPath == nil {
+ if i == 0 {
+ i = mi
+ found = true
+ break
+ }
+ i--
+ }
+ }
+ if !found {
+ panic("reflect: Method index out of range")
+ }
+
p := &t.methods[i]
if p.name != nil {
m.Name = *p.name
@@ -531,7 +566,13 @@ func (t *uncommonType) NumMethod() int {
if t == nil {
return 0
}
- return len(t.methods)
+ c := 0
+ for i := range t.methods {
+ if t.methods[i].pkgPath == nil {
+ c++
+ }
+ }
+ return c
}
func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
@@ -541,7 +582,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
var p *method
for i := range t.methods {
p = &t.methods[i]
- if p.name != nil && *p.name == name {
+ if p.pkgPath == nil && p.name != nil && *p.name == name {
return t.Method(i), true
}
}
@@ -758,7 +799,7 @@ type StructField struct {
// Name is the field name.
Name string
// PkgPath is the package path that qualifies a lower case (unexported)
- // field name. It is empty for upper case (exported) field names.
+ // field name. It is empty for upper case (exported) field names.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
@@ -782,10 +823,22 @@ type StructTag string
// Get returns the value associated with key in the tag string.
// If there is no such key in the tag, Get returns the empty string.
// If the tag does not have the conventional format, the value
-// returned by Get is unspecified.
+// returned by Get is unspecified. To determine whether a tag is
+// explicitly set to the empty string, use Lookup.
func (tag StructTag) Get(key string) string {
+ v, _ := tag.Lookup(key)
+ return v
+}
+
+// Lookup returns the value associated with key in the tag string.
+// If the key is present in the tag the value (which may be empty)
+// is returned. Otherwise the returned value will be the empty string.
+// The ok return value reports whether the value was explicitly set in
+// the tag string. If the tag does not have the conventional format,
+// the value returned by Lookup is unspecified.
+func (tag StructTag) Lookup(key string) (value string, ok bool) {
// When modifying this code, also update the validateStructTag code
- // in golang.org/x/tools/cmd/vet/structtag.go.
+ // in cmd/vet/structtag.go.
for tag != "" {
// Skip leading space.
@@ -831,16 +884,16 @@ func (tag StructTag) Get(key string) string {
if err != nil {
break
}
- return value
+ return value, true
}
}
- return ""
+ return "", false
}
// 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)
@@ -863,12 +916,12 @@ func (t *structType) Field(i int) (f StructField) {
f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface
- // presented by a reflect.Type. It would be nice to avoid,
+ // presented by a reflect.Type. It would be nice to avoid,
// at least in the common cases, but we need to make sure
// that misbehaving clients of reflect cannot affect other
- // uses of reflect. One possibility is CL 5371098, but we
+ // uses of reflect. One possibility is CL 5371098, but we
// postponed that ugliness until there is a demonstrated
- // need for the performance. This is issue 2320.
+ // need for the performance. This is issue 2320.
f.Index = []int{i}
return
}
@@ -1082,11 +1135,7 @@ func (t *rtype) ptrTo() *rtype {
return p
}
- // Otherwise, synthesize one.
- // This only happens for pointers with no methods.
- // We keep the mapping in a map on the side, because
- // this operation is rare and a separate map lets us keep
- // the type structures in read-only memory.
+ // Check the cache.
ptrMap.RLock()
if m := ptrMap.m; m != nil {
if p := m[t]; p != nil {
@@ -1095,6 +1144,7 @@ func (t *rtype) ptrTo() *rtype {
}
}
ptrMap.RUnlock()
+
ptrMap.Lock()
if ptrMap.m == nil {
ptrMap.m = make(map[*rtype]*ptrType)
@@ -1119,12 +1169,12 @@ func (t *rtype) ptrTo() *rtype {
// Create a new ptrType starting with the description
// of an *unsafe.Pointer.
- p = new(ptrType)
var iptr interface{} = (*unsafe.Pointer)(nil)
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
- *p = *prototype
+ pp := *prototype
- p.string = &s
+ pp.string = &s
+ pp.ptrToThis = nil
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
@@ -1133,17 +1183,17 @@ func (t *rtype) ptrTo() *rtype {
// old hash and the new "*".
// p.hash = fnv1(t.hash, '*')
// This is the gccgo version.
- p.hash = (t.hash << 4) + 9
+ pp.hash = (t.hash << 4) + 9
- p.uncommonType = nil
- p.ptrToThis = nil
- p.elem = t
+ pp.uncommonType = nil
+ pp.ptrToThis = nil
+ pp.elem = t
if t.kind&kindNoPointers != 0 {
- p.gc = unsafe.Pointer(&ptrDataGCProg)
+ pp.gc = unsafe.Pointer(&ptrDataGCProg)
} else {
- p.gc = unsafe.Pointer(&ptrGC{
- width: p.size,
+ pp.gc = unsafe.Pointer(&ptrGC{
+ width: pp.size,
op: _GC_PTR,
off: 0,
elemgc: t.gc,
@@ -1151,7 +1201,7 @@ func (t *rtype) ptrTo() *rtype {
})
}
- q := canonicalize(&p.rtype)
+ q := canonicalize(&pp.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
ptrMap.m[t] = p
@@ -1293,10 +1343,22 @@ func directlyAssignable(T, V *rtype) bool {
}
// x's type T and V must have identical underlying types.
- return haveIdenticalUnderlyingType(T, V)
+ return haveIdenticalUnderlyingType(T, V, true)
}
-func haveIdenticalUnderlyingType(T, V *rtype) bool {
+func haveIdenticalType(T, V Type, cmpTags bool) bool {
+ if cmpTags {
+ return T == V
+ }
+
+ if T.Name() != V.Name() || T.Kind() != V.Kind() {
+ return false
+ }
+
+ return haveIdenticalUnderlyingType(T.common(), V.common(), false)
+}
+
+func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if T == V {
return true
}
@@ -1315,18 +1377,18 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
// Composite types.
switch kind {
case Array:
- return T.Elem() == V.Elem() && T.Len() == V.Len()
+ return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// and x's type V and T have identical element types.
- if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
+ if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
return true
}
// Otherwise continue test for identical underlying type.
- return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
+ return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Func:
t := (*funcType)(unsafe.Pointer(T))
@@ -1335,12 +1397,12 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
}
for i, typ := range t.in {
- if typ != v.in[i] {
+ if !haveIdenticalType(typ, v.in[i], cmpTags) {
return false
}
}
for i, typ := range t.out {
- if typ != v.out[i] {
+ if !haveIdenticalType(typ, v.out[i], cmpTags) {
return false
}
}
@@ -1357,10 +1419,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
case Map:
- return T.Key() == V.Key() && T.Elem() == V.Elem()
+ return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Ptr, Slice:
- return T.Elem() == V.Elem()
+ return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Struct:
t := (*structType)(unsafe.Pointer(T))
@@ -1377,10 +1439,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) {
return false
}
- if tf.typ != vf.typ {
+ if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
return false
}
- if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
+ if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
return false
}
if tf.offset != vf.offset {
@@ -1501,8 +1563,7 @@ func ChanOf(dir ChanDir, t Type) Type {
// Make a channel type.
var ichan interface{} = (chan unsafe.Pointer)(nil)
prototype := *(**chanType)(unsafe.Pointer(&ichan))
- ch := new(chanType)
- *ch = *prototype
+ ch := *prototype
ch.dir = uintptr(dir)
ch.string = &s
@@ -1564,8 +1625,7 @@ func MapOf(key, elem Type) Type {
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
- mt := new(mapType)
- *mt = **(**mapType)(unsafe.Pointer(&imap))
+ mt := **(**mapType)(unsafe.Pointer(&imap))
mt.string = &s
// gccgo uses a different hash
@@ -1576,20 +1636,25 @@ func MapOf(key, elem Type) Type {
mt.elem = etyp
mt.uncommonType = nil
mt.ptrToThis = nil
- // mt.gc = unsafe.Pointer(&ptrGC{
- // width: unsafe.Sizeof(uintptr(0)),
- // op: _GC_PTR,
- // off: 0,
- // elemgc: nil,
- // end: _GC_END,
- // })
-
- // TODO(cmang): Generate GC data for Map elements.
- mt.gc = unsafe.Pointer(&ptrDataGCProg)
- // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
- // fail when mt.gc is wrong.
- //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
+ mt.bucket = bucketOf(ktyp, etyp)
+ if ktyp.size > maxKeySize {
+ mt.keysize = uint8(ptrSize)
+ mt.indirectkey = 1
+ } else {
+ mt.keysize = uint8(ktyp.size)
+ mt.indirectkey = 0
+ }
+ if etyp.size > maxValSize {
+ mt.valuesize = uint8(ptrSize)
+ mt.indirectvalue = 1
+ } else {
+ mt.valuesize = uint8(etyp.size)
+ mt.indirectvalue = 0
+ }
+ mt.bucketsize = uint16(mt.bucket.size)
+ mt.reflexivekey = isReflexive(ktyp)
+ mt.needkeyupdate = needKeyUpdate(ktyp)
return cachePut(ckey, &mt.rtype)
}
@@ -1613,7 +1678,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
*ft = *prototype
// Build a hash and minimally populate ft.
- var hash uint32 = 8
+ var hash uint32
var fin, fout []*rtype
shift := uint(1)
for _, in := range in {
@@ -1633,6 +1698,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
hash++
}
hash <<= 4
+ hash += 8
ft.hash = hash
ft.in = fin
ft.out = fout
@@ -1641,7 +1707,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Look in cache.
funcLookupCache.RLock()
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
funcLookupCache.RUnlock()
return t
}
@@ -1655,7 +1721,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
funcLookupCache.m = make(map[uint32][]*rtype)
}
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
return t
}
}
@@ -1762,7 +1828,7 @@ func needKeyUpdate(t *rtype) bool {
// Make sure these routines stay in sync with ../../runtime/hashmap.go!
// These types exist only for GC, so we only fill out GC relevant info.
-// Currently, that's just size and the GC program. We also fill in string
+// Currently, that's just size and the GC program. We also fill in string
// for possible debugging use.
const (
bucketSize uintptr = 8
@@ -1794,79 +1860,68 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
// Note that since the key and value are known to be <= 128 bytes,
// they're guaranteed to have bitmaps instead of GC programs.
// var gcdata *byte
- var ptrdata uintptr
- var overflowPad uintptr
+ // var ptrdata uintptr
+
+ size := bucketSize
+ size = align(size, uintptr(ktyp.fieldAlign))
+ size += bucketSize * ktyp.size
+ size = align(size, uintptr(etyp.fieldAlign))
+ size += bucketSize * etyp.size
- // On NaCl, pad if needed to make overflow end at the proper struct alignment.
- // On other systems, align > ptrSize is not possible.
- if runtime.GOARCH == "amd64p32" && (ktyp.align > ptrSize || etyp.align > ptrSize) {
- overflowPad = ptrSize
+ maxAlign := uintptr(ktyp.fieldAlign)
+ if maxAlign < uintptr(etyp.fieldAlign) {
+ maxAlign = uintptr(etyp.fieldAlign)
}
- size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize
- if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
- panic("reflect: bad size computation in MapOf")
+ if maxAlign > ptrSize {
+ size = align(size, maxAlign)
+ size += align(ptrSize, maxAlign) - ptrSize
}
- if kind != kindNoPointers {
- nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize
- mask := make([]byte, (nptr+7)/8)
- base := bucketSize / ptrSize
+ ovoff := size
+ size += ptrSize
+ if maxAlign < ptrSize {
+ maxAlign = ptrSize
+ }
+ var gcPtr unsafe.Pointer
+ if kind != kindNoPointers {
+ gc := []uintptr{size}
+ base := bucketSize
+ base = align(base, uintptr(ktyp.fieldAlign))
if ktyp.kind&kindNoPointers == 0 {
- if ktyp.kind&kindGCProg != 0 {
- panic("reflect: unexpected GC program in MapOf")
- }
- kmask := (*[16]byte)(unsafe.Pointer( /*ktyp.gcdata*/ nil))
- for i := uintptr(0); i < ktyp.size/ptrSize; i++ {
- if (kmask[i/8]>>(i%8))&1 != 0 {
- for j := uintptr(0); j < bucketSize; j++ {
- word := base + j*ktyp.size/ptrSize + i
- mask[word/8] |= 1 << (word % 8)
- }
- }
- }
+ gc = append(gc, _GC_ARRAY_START, base, bucketSize, ktyp.size)
+ gc = appendGCProgram(gc, ktyp, 0)
+ gc = append(gc, _GC_ARRAY_NEXT)
}
- base += bucketSize * ktyp.size / ptrSize
-
+ base += ktyp.size * bucketSize
+ base = align(base, uintptr(etyp.fieldAlign))
if etyp.kind&kindNoPointers == 0 {
- if etyp.kind&kindGCProg != 0 {
- panic("reflect: unexpected GC program in MapOf")
- }
- emask := (*[16]byte)(unsafe.Pointer( /*etyp.gcdata*/ nil))
- for i := uintptr(0); i < etyp.size/ptrSize; i++ {
- if (emask[i/8]>>(i%8))&1 != 0 {
- for j := uintptr(0); j < bucketSize; j++ {
- word := base + j*etyp.size/ptrSize + i
- mask[word/8] |= 1 << (word % 8)
- }
- }
- }
- }
- base += bucketSize * etyp.size / ptrSize
- base += overflowPad / ptrSize
-
- word := base
- mask[word/8] |= 1 << (word % 8)
- // gcdata = &mask[0]
- ptrdata = (word + 1) * ptrSize
-
- // overflow word must be last
- if ptrdata != size {
- panic("reflect: bad layout computation in MapOf")
+ gc = append(gc, _GC_ARRAY_START, base, bucketSize, etyp.size)
+ gc = appendGCProgram(gc, etyp, 0)
+ gc = append(gc, _GC_ARRAY_NEXT)
}
+ gc = append(gc, _GC_APTR, ovoff, _GC_END)
+ gcPtr = unsafe.Pointer(&gc[0])
+ } else {
+ // No pointers in bucket.
+ gc := [...]uintptr{size, _GC_END}
+ gcPtr = unsafe.Pointer(&gc[0])
}
- b := new(rtype)
- // b.size = gc.size
- // b.gc[0], _ = gc.finalize()
- b.kind |= kindGCProg
+ b := &rtype{
+ align: int8(maxAlign),
+ fieldAlign: uint8(maxAlign),
+ size: size,
+ kind: kind,
+ gc: gcPtr,
+ }
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
}
// Take the GC program for "t" and append it to the GC program "gc".
-func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
+func appendGCProgram(gc []uintptr, t *rtype, offset uintptr) []uintptr {
p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
@@ -1888,7 +1943,11 @@ loop:
panic("unknown GC program op for " + *t.string + ": " + strconv.FormatUint(*(*uint64)(p), 10))
}
for i := 0; i < argcnt+1; i++ {
- gc = append(gc, *(*uintptr)(p))
+ v := *(*uintptr)(p)
+ if i == 1 {
+ v += offset
+ }
+ gc = append(gc, v)
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0)))
}
}
@@ -1967,8 +2026,7 @@ func SliceOf(t Type) Type {
// Make a slice type.
var islice interface{} = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
- slice := new(sliceType)
- *slice = *prototype
+ slice := *prototype
slice.string = &s
// gccgo uses a different hash.
@@ -1997,8 +2055,258 @@ func SliceOf(t Type) Type {
return cachePut(ckey, &slice.rtype)
}
-// See cmd/compile/internal/gc/reflect.go for derivation of constant.
-const maxPtrmaskBytes = 2048
+// The structLookupCache caches StructOf lookups.
+// StructOf does not share the common lookupCache since we need to pin
+// the memory associated with *structTypeFixedN.
+var structLookupCache struct {
+ sync.RWMutex
+ m map[uint32][]interface {
+ common() *rtype
+ } // keyed by hash calculated in StructOf
+}
+
+// StructOf returns the struct type containing fields.
+// The Offset and Index fields are ignored and computed as they would be
+// by the compiler.
+//
+// StructOf currently does not generate wrapper methods for embedded fields.
+// This limitation may be lifted in a future version.
+func StructOf(fields []StructField) Type {
+ var (
+ hash = uint32(0)
+ size uintptr
+ typalign int8
+
+ fs = make([]structField, len(fields))
+ repr = make([]byte, 0, 64)
+ fset = map[string]struct{}{} // fields' names
+
+ hasPtr = false // records whether at least one struct-field is a pointer
+ )
+
+ lastzero := uintptr(0)
+ repr = append(repr, "struct {"...)
+ for i, field := range fields {
+ if field.Type == nil {
+ panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
+ }
+ f := runtimeStructField(field)
+ ft := f.typ
+ if ft.pointers() {
+ hasPtr = true
+ }
+
+ name := ""
+ // Update string and hash
+ hash = (hash << 1) + ft.hash
+ if f.name != nil {
+ name = *f.name
+ repr = append(repr, (" " + name)...)
+ } else {
+ // Embedded field
+ repr = append(repr, " ?"...)
+ if f.typ.Kind() == Ptr {
+ // Embedded ** and *interface{} are illegal
+ elem := ft.Elem()
+ if k := elem.Kind(); k == Ptr || k == Interface {
+ panic("reflect.StructOf: illegal anonymous field type " + ft.String())
+ }
+ name = elem.String()
+ } else {
+ name = ft.String()
+ }
+ // TODO(sbinet) check for syntactically impossible type names?
+
+ switch f.typ.Kind() {
+ case Interface:
+ ift := (*interfaceType)(unsafe.Pointer(ft))
+ if len(ift.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ case Ptr:
+ ptr := (*ptrType)(unsafe.Pointer(ft))
+ if unt := ptr.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ if unt := ptr.elem.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ default:
+ if unt := ft.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ }
+ }
+ if _, dup := fset[name]; dup {
+ panic("reflect.StructOf: duplicate field " + name)
+ }
+ fset[name] = struct{}{}
+
+ repr = append(repr, (" " + ft.String())...)
+ if f.tag != nil {
+ repr = append(repr, (" " + strconv.Quote(*f.tag))...)
+ }
+ if i < len(fields)-1 {
+ repr = append(repr, ';')
+ }
+
+ f.offset = align(size, uintptr(ft.fieldAlign))
+ if int8(ft.fieldAlign) > typalign {
+ typalign = int8(ft.fieldAlign)
+ }
+ size = f.offset + ft.size
+
+ if ft.size == 0 {
+ lastzero = size
+ }
+
+ fs[i] = f
+ }
+
+ if size > 0 && lastzero == size {
+ // This is a non-zero sized struct that ends in a
+ // zero-sized field. We add an extra byte of padding,
+ // to ensure that taking the address of the final
+ // zero-sized field can't manufacture a pointer to the
+ // next object in the heap. See issue 9401.
+ size++
+ }
+
+ if len(fs) > 0 {
+ repr = append(repr, ' ')
+ }
+ repr = append(repr, '}')
+ hash <<= 2
+ str := string(repr)
+
+ // Round the size up to be a multiple of the alignment.
+ size = align(size, uintptr(typalign))
+
+ // Make the struct type.
+ var istruct interface{} = struct{}{}
+ prototype := *(**structType)(unsafe.Pointer(&istruct))
+ typ := new(structType)
+ *typ = *prototype
+ typ.fields = fs
+
+ // Look in cache
+ structLookupCache.RLock()
+ for _, st := range structLookupCache.m[hash] {
+ t := st.common()
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
+ structLookupCache.RUnlock()
+ return t
+ }
+ }
+ structLookupCache.RUnlock()
+
+ // not in cache, lock and retry
+ structLookupCache.Lock()
+ defer structLookupCache.Unlock()
+ if structLookupCache.m == nil {
+ structLookupCache.m = make(map[uint32][]interface {
+ common() *rtype
+ })
+ }
+ for _, st := range structLookupCache.m[hash] {
+ t := st.common()
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
+ return t
+ }
+ }
+
+ typ.string = &str
+ typ.hash = hash
+ typ.size = size
+ typ.align = typalign
+ typ.fieldAlign = uint8(typalign)
+ if !hasPtr {
+ typ.kind |= kindNoPointers
+ gc := [...]uintptr{size, _GC_END}
+ typ.gc = unsafe.Pointer(&gc[0])
+ } else {
+ typ.kind &^= kindNoPointers
+ gc := []uintptr{size}
+ for _, ft := range fs {
+ gc = appendGCProgram(gc, ft.typ, ft.offset)
+ }
+ gc = append(gc, _GC_END)
+ typ.gc = unsafe.Pointer(&gc[0])
+ }
+
+ typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
+ ret := seed
+ for _, ft := range typ.fields {
+ o := unsafe.Pointer(uintptr(p) + ft.offset)
+ ret = ft.typ.hashfn(o, ret)
+ }
+ return ret
+ }
+
+ typ.equalfn = func(p, q unsafe.Pointer) bool {
+ for _, ft := range typ.fields {
+ pi := unsafe.Pointer(uintptr(p) + ft.offset)
+ qi := unsafe.Pointer(uintptr(q) + ft.offset)
+ if !ft.typ.equalfn(pi, qi) {
+ return false
+ }
+ }
+ return true
+ }
+
+ typ.kind &^= kindDirectIface
+ typ.uncommonType = nil
+ typ.ptrToThis = nil
+
+ structLookupCache.m[hash] = append(structLookupCache.m[hash], typ)
+ return &typ.rtype
+}
+
+func runtimeStructField(field StructField) structField {
+ var name *string
+ if field.Name == "" {
+ t := field.Type.(*rtype)
+ if t.Kind() == Ptr {
+ t = t.Elem().(*rtype)
+ }
+ } else if field.PkgPath == "" {
+ s := field.Name
+ name = &s
+ b0 := s[0]
+ if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
+ panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
+ }
+ }
+
+ var pkgPath *string
+ if field.PkgPath != "" {
+ s := field.PkgPath
+ pkgPath = &s
+ // This could work with gccgo but we panic to be
+ // compatible with gc.
+ panic("reflect: creating a name with a package path is not supported")
+ }
+
+ var tag *string
+ if field.Tag != "" {
+ s := string(field.Tag)
+ tag = &s
+ }
+
+ return structField{
+ name: name,
+ pkgPath: pkgPath,
+ typ: field.Type.common(),
+ tag: tag,
+ offset: 0,
+ }
+}
// ArrayOf returns the array type with the given count and element type.
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
@@ -2024,8 +2332,7 @@ func ArrayOf(count int, elem Type) Type {
// Make an array type.
var iarray interface{} = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
- array := new(arrayType)
- *array = *prototype
+ array := *prototype
array.string = &s
// gccgo uses a different hash.
@@ -2037,6 +2344,7 @@ func ArrayOf(count int, elem Type) Type {
array.hash = typ.hash + 1 + 13
array.elem = typ
+ array.ptrToThis = nil
max := ^uintptr(0) / typ.size
if uintptr(count) > max {
panic("reflect.ArrayOf: array size would exceed virtual address space")
@@ -2048,7 +2356,6 @@ func ArrayOf(count int, elem Type) Type {
array.align = typ.align
array.fieldAlign = typ.fieldAlign
array.uncommonType = nil
- array.ptrToThis = nil
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -2067,26 +2374,25 @@ func ArrayOf(count int, elem Type) Type {
default:
gc := []uintptr{array.size, _GC_ARRAY_START, 0, uintptr(count), typ.size}
- gc = appendGCProgram(gc, typ)
+ gc = appendGCProgram(gc, typ, 0)
gc = append(gc, _GC_ARRAY_NEXT, _GC_END)
array.gc = unsafe.Pointer(&gc[0])
}
array.kind &^= kindDirectIface
- array.hashfn = func(p unsafe.Pointer, size uintptr) uintptr {
- ret := uintptr(0)
+ array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
+ ret := seed
for i := 0; i < count; i++ {
- ret *= 33
- ret += typ.hashfn(p, typ.size)
+ ret = typ.hashfn(p, ret)
p = unsafe.Pointer(uintptr(p) + typ.size)
}
return ret
}
- array.equalfn = func(p1, p2 unsafe.Pointer, size uintptr) bool {
+ array.equalfn = func(p1, p2 unsafe.Pointer) bool {
for i := 0; i < count; i++ {
- if !typ.equalfn(p1, p2, typ.size) {
+ if !typ.equalfn(p1, p2) {
return false
}
p1 = unsafe.Pointer(uintptr(p1) + typ.size)
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 75944a6e53..1b4c5407e5 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -11,14 +11,13 @@ import (
)
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
-const cannotSet = "cannot set value obtained from unexported struct field"
// Value is the reflection interface to a Go value.
//
-// Not all methods apply to all kinds of values. Restrictions,
+// Not all methods apply to all kinds of values. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of value before
-// calling kind-specific methods. Calling a method
+// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
//
// The zero Value represents no value.
@@ -57,7 +56,7 @@ type Value struct {
flag
// A method value represents a curried method invocation
- // like r.Read for some receiver r. The typ+val+flag bits describe
+ // like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
@@ -116,14 +115,14 @@ func packEface(v Value) interface{} {
}
e.word = ptr
case v.flag&flagIndir != 0:
- // Value is indirect, but interface is direct. We need
+ // Value is indirect, but interface is direct. We need
// to load the data at v.ptr into the interface data word.
e.word = *(*unsafe.Pointer)(v.ptr)
default:
// Value is direct, and so is the interface.
e.word = v.ptr
}
- // Now, fill in the type portion. We're very careful here not
+ // Now, fill in the type portion. We're very careful here not
// to have any operation between the e.word and e.typ assignments
// that would let the garbage collector observe the partially-built
// interface value.
@@ -147,7 +146,7 @@ func unpackEface(i interface{}) Value {
}
// A ValueError occurs when a Value method is invoked on
-// a Value that does not support it. Such cases are documented
+// a Value that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
Method string
@@ -269,7 +268,7 @@ func (v Value) runes() []rune {
}
// CanAddr reports whether the value's address can be obtained with Addr.
-// Such values are called addressable. A value is addressable if it is
+// Such values are called addressable. A value is addressable if it is
// an element of a slice, an element of an addressable array,
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
@@ -500,7 +499,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
return
}
-// v is a method receiver. Store at p the word which is used to
+// v is a method receiver. Store at p the word which is used to
// encode that receiver at the start of the argument list.
// Reflect uses the "interface" calling convention for
// methods, which always uses one word to record the receiver.
@@ -541,7 +540,7 @@ func (v Value) Cap() int {
case Array:
return v.typ.Len()
case Chan:
- return int(chancap(v.pointer()))
+ return chancap(v.pointer())
case Slice:
// Slice is always bigger than a word; assume flagIndir.
return (*sliceHeader)(v.ptr).Cap
@@ -760,7 +759,7 @@ func (v Value) Int() int64 {
case Int32:
return int64(*(*int32)(p))
case Int64:
- return int64(*(*int64)(p))
+ return *(*int64)(p)
}
panic(&ValueError{"reflect.Value.Int", v.kind()})
}
@@ -909,9 +908,9 @@ func (v Value) MapIndex(key Value) Value {
// Do not require key to be exported, so that DeepEqual
// and other programs can use all the keys returned by
- // MapKeys as arguments to MapIndex. If either the map
+ // MapKeys as arguments to MapIndex. If either the map
// or the key is unexported, though, the result will be
- // considered unexported. This is consistent with the
+ // considered unexported. This is consistent with the
// behavior for structs, which allow read but not write
// of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
@@ -963,7 +962,7 @@ func (v Value) MapKeys() []Value {
key := mapiterkey(it)
if key == nil {
// Someone deleted an entry from the map since we
- // called maplen above. It's a data race, but nothing
+ // called maplen above. It's a data race, but nothing
// we can do about it.
break
}
@@ -1110,7 +1109,7 @@ func (v Value) OverflowUint(x uint64) bool {
// result is zero if and only if v is a nil func Value.
//
// If v's Kind is Slice, the returned pointer is to the first
-// element of the slice. If the slice is nil the returned value
+// element of the slice. If the slice is nil the returned value
// is 0. If the slice is empty but non-nil the return value is non-zero.
func (v Value) Pointer() uintptr {
// TODO: deprecate
@@ -1311,7 +1310,7 @@ func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
s := (*sliceHeader)(v.ptr)
- if n < int(s.Len) || n > int(s.Cap) {
+ if n < s.Len || n > s.Cap {
panic("reflect: slice capacity out of range in SetCap")
}
s.Cap = n
@@ -1413,7 +1412,7 @@ func (v Value) Slice(i, j int) Value {
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
s := (*sliceHeader)(v.ptr)
- base = unsafe.Pointer(s.Data)
+ base = s.Data
cap = s.Cap
case String:
@@ -1585,7 +1584,7 @@ func (v Value) Uint() uint64 {
case Uint32:
return uint64(*(*uint32)(p))
case Uint64:
- return uint64(*(*uint64)(p))
+ return *(*uint64)(p)
case Uintptr:
return uint64(*(*uintptr)(p))
}
@@ -1751,13 +1750,13 @@ func Copy(dst, src Value) int {
// A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/select.go:/runtimeSelect
type runtimeSelect struct {
- dir uintptr // 0, SendDir, or RecvDir
+ dir SelectDir // SelectSend, SelectRecv or SelectDefault
typ *rtype // channel type
ch unsafe.Pointer // channel
val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
}
-// rselect runs a select. It returns the index of the chosen case.
+// rselect runs a select. It returns the index of the chosen case.
// If the case was a receive, val is filled in with the received value.
// The conventional OK bool indicates whether the receive corresponds
// to a sent value.
@@ -1814,7 +1813,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
haveDefault := false
for i, c := range cases {
rc := &runcases[i]
- rc.dir = uintptr(c.Dir)
+ rc.dir = c.Dir
switch c.Dir {
default:
panic("reflect.Select: invalid Dir")
@@ -1877,7 +1876,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
}
chosen, recvOK = rselect(runcases)
- if runcases[chosen].dir == uintptr(SelectRecv) {
+ if runcases[chosen].dir == SelectRecv {
tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
t := tt.elem
p := runcases[chosen].val
@@ -1954,14 +1953,14 @@ func Indirect(v Value) Value {
}
// ValueOf returns a new Value initialized to the concrete value
-// stored in the interface i. ValueOf(nil) returns the zero Value.
+// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {
if i == nil {
return Value{}
}
// TODO: Maybe allow contents of a Value to live on the stack.
- // For now we make the contents always escape to the heap. It
+ // For now we make the contents always escape to the heap. It
// makes life easier in a few places (see chanrecv/mapassign
// comment below).
escapes(i)
@@ -1987,7 +1986,7 @@ func Zero(typ Type) Value {
}
// New returns a Value representing a pointer to a new zero value
-// for the specified type. That is, the returned Value's Type is PtrTo(typ).
+// for the specified type. That is, the returned Value's Type is PtrTo(typ).
func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
@@ -2114,14 +2113,14 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
}
// dst and src have same underlying type.
- if haveIdenticalUnderlyingType(dst, src) {
+ if haveIdenticalUnderlyingType(dst, src, false) {
return cvtDirect
}
// dst and src are unnamed pointer types with same underlying base type.
if dst.Kind() == Ptr && dst.Name() == "" &&
src.Kind() == Ptr && src.Name() == "" &&
- haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) {
+ haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) {
return cvtDirect
}
@@ -2142,13 +2141,13 @@ func makeInt(f flag, bits uint64, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
+ *(*uint8)(ptr) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
+ *(*uint16)(ptr) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
+ *(*uint32)(ptr) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(ptr)) = bits
+ *(*uint64)(ptr) = bits
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2160,9 +2159,9 @@ func makeFloat(f flag, v float64, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(ptr)) = float32(v)
+ *(*float32)(ptr) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(ptr)) = v
+ *(*float64)(ptr) = v
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2174,9 +2173,9 @@ func makeComplex(f flag, v complex128, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 8:
- *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
+ *(*complex64)(ptr) = complex64(v)
case 16:
- *(*complex128)(unsafe.Pointer(ptr)) = v
+ *(*complex128)(ptr) = v
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2320,7 +2319,7 @@ func chanclose(ch unsafe.Pointer)
func chanlen(ch unsafe.Pointer) int
// Note: some of the noescape annotations below are technically a lie,
-// but safe in the context of this package. Functions like chansend
+// but safe in the context of this package. Functions like chansend
// and mapassign don't escape the referent, but may escape anything
// the referent points to (they do shallow copies of the referent).
// It is safe in this package because the referent may only point
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
index 88391ff47d..beb46e7099 100644
--- a/libgo/go/regexp/all_test.go
+++ b/libgo/go/regexp/all_test.go
@@ -11,7 +11,7 @@ import (
"testing"
)
-var good_re = []string{
+var goodRe = []string{
``,
`.`,
`^.$`,
@@ -36,7 +36,7 @@ type stringError struct {
err string
}
-var bad_re = []stringError{
+var badRe = []stringError{
{`*`, "missing argument to repetition operator: `*`"},
{`+`, "missing argument to repetition operator: `+`"},
{`?`, "missing argument to repetition operator: `?`"},
@@ -64,14 +64,14 @@ func compileTest(t *testing.T, expr string, error string) *Regexp {
}
func TestGoodCompile(t *testing.T) {
- for i := 0; i < len(good_re); i++ {
- compileTest(t, good_re[i], "")
+ for i := 0; i < len(goodRe); i++ {
+ compileTest(t, goodRe[i], "")
}
}
func TestBadCompile(t *testing.T) {
- for i := 0; i < len(bad_re); i++ {
- compileTest(t, bad_re[i].re, bad_re[i].err)
+ for i := 0; i < len(badRe); i++ {
+ compileTest(t, badRe[i].re, badRe[i].err)
}
}
@@ -512,6 +512,32 @@ func TestSplit(t *testing.T) {
}
}
+// The following sequence of Match calls used to panic. See issue #12980.
+func TestParseAndCompile(t *testing.T) {
+ expr := "a$"
+ s := "a\nb"
+
+ for i, tc := range []struct {
+ reFlags syntax.Flags
+ expMatch bool
+ }{
+ {syntax.Perl | syntax.OneLine, false},
+ {syntax.Perl &^ syntax.OneLine, true},
+ } {
+ parsed, err := syntax.Parse(expr, tc.reFlags)
+ if err != nil {
+ t.Fatalf("%d: parse: %v", i, err)
+ }
+ re, err := Compile(parsed.String())
+ if err != nil {
+ t.Fatalf("%d: compile: %v", i, err)
+ }
+ if match := re.MatchString(s); match != tc.expMatch {
+ t.Errorf("%d: %q.MatchString(%q)=%t; expected=%t", i, re, s, match, tc.expMatch)
+ }
+ }
+}
+
// Check that one-pass cutoff does trigger.
func TestOnePassCutoff(t *testing.T) {
re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl)
@@ -538,6 +564,72 @@ func TestSwitchBacktrack(t *testing.T) {
re.Match(long[:1]) // triggers backtracker
}
+func BenchmarkFind(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a+b+")
+ wantSubs := "aaabb"
+ s := []byte("acbb" + wantSubs + "dd")
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.Find(s)
+ if string(subs) != wantSubs {
+ b.Fatalf("Find(%q) = %q; want %q", s, subs, wantSubs)
+ }
+ }
+}
+
+func BenchmarkFindString(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a+b+")
+ wantSubs := "aaabb"
+ s := "acbb" + wantSubs + "dd"
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindString(s)
+ if subs != wantSubs {
+ b.Fatalf("FindString(%q) = %q; want %q", s, subs, wantSubs)
+ }
+ }
+}
+
+func BenchmarkFindSubmatch(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a(a+b+)b")
+ wantSubs := "aaabb"
+ s := []byte("acbb" + wantSubs + "dd")
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindSubmatch(s)
+ if string(subs[0]) != wantSubs {
+ b.Fatalf("FindSubmatch(%q)[0] = %q; want %q", s, subs[0], wantSubs)
+ }
+ if string(subs[1]) != "aab" {
+ b.Fatalf("FindSubmatch(%q)[1] = %q; want %q", s, subs[1], "aab")
+ }
+ }
+}
+
+func BenchmarkFindStringSubmatch(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a(a+b+)b")
+ wantSubs := "aaabb"
+ s := "acbb" + wantSubs + "dd"
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindStringSubmatch(s)
+ if subs[0] != wantSubs {
+ b.Fatalf("FindStringSubmatch(%q)[0] = %q; want %q", s, subs[0], wantSubs)
+ }
+ if subs[1] != "aab" {
+ b.Fatalf("FindStringSubmatch(%q)[1] = %q; want %q", s, subs[1], "aab")
+ }
+ }
+}
+
func BenchmarkLiteral(b *testing.B) {
x := strings.Repeat("x", 50) + "y"
b.StopTimer()
@@ -726,3 +818,23 @@ func BenchmarkMatchParallelCopied(b *testing.B) {
}
})
}
+
+var sink string
+
+func BenchmarkQuoteMetaAll(b *testing.B) {
+ s := string(specialBytes)
+ b.SetBytes(int64(len(s)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sink = QuoteMeta(s)
+ }
+}
+
+func BenchmarkQuoteMetaNone(b *testing.B) {
+ s := "abcdefghijklmnopqrstuvwxyz"
+ b.SetBytes(int64(len(s)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sink = QuoteMeta(s)
+ }
+}
diff --git a/libgo/go/regexp/backtrack.go b/libgo/go/regexp/backtrack.go
index fd95604fe4..29f624b54c 100644
--- a/libgo/go/regexp/backtrack.go
+++ b/libgo/go/regexp/backtrack.go
@@ -36,7 +36,6 @@ type bitState struct {
end int
cap []int
- input input
jobs []job
visited []uint32
}
@@ -146,7 +145,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
// Optimization: rather than push and pop,
// code that is going to Push and continue
// the loop simply updates ip, p, and arg
- // and jumps to CheckAndLoop. We have to
+ // and jumps to CheckAndLoop. We have to
// do the ShouldVisit check that Push
// would have, but we avoid the stack
// manipulation.
@@ -254,7 +253,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
}
panic("bad arg in InstCapture")
- continue
case syntax.InstEmptyWidth:
if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 {
@@ -299,7 +297,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
// Otherwise, continue on in hope of a longer match.
continue
}
- panic("unreachable")
}
return m.matched
diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go
index 518272092a..977619cb28 100644
--- a/libgo/go/regexp/exec.go
+++ b/libgo/go/regexp/exec.go
@@ -19,7 +19,7 @@ type queue struct {
// A entry is an entry on a queue.
// It holds both the instruction pc and the actual thread.
// Some queue entries are just place holders so that the machine
-// knows it has considered that pc. Such entries have t == nil.
+// knows it has considered that pc. Such entries have t == nil.
type entry struct {
pc uint32
t *thread
@@ -107,14 +107,6 @@ func (m *machine) alloc(i *syntax.Inst) *thread {
return t
}
-// free returns t to the free pool.
-func (m *machine) free(t *thread) {
- m.inputBytes.str = nil
- m.inputString.str = ""
- m.inputReader.r = nil
- m.pool = append(m.pool, t)
-}
-
// match runs the machine over the input starting at pos.
// It reports whether a match was found.
// If so, m.matchcap holds the submatch information.
@@ -192,7 +184,6 @@ func (m *machine) match(i input, pos int) bool {
func (m *machine) clear(q *queue) {
for _, d := range q.dense {
if d.t != nil {
- // m.free(d.t)
m.pool = append(m.pool, d.t)
}
}
@@ -213,7 +204,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
continue
}
if longest && m.matched && len(t.cap) > 0 && m.matchcap[0] < t.cap[0] {
- // m.free(t)
m.pool = append(m.pool, t)
continue
}
@@ -232,7 +222,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
// First-match mode: cut off all lower-priority threads.
for _, d := range runq.dense[j+1:] {
if d.t != nil {
- // m.free(d.t)
m.pool = append(m.pool, d.t)
}
}
@@ -253,7 +242,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
t = m.add(nextq, i.Out, nextPos, t.cap, nextCond, t)
}
if t != nil {
- // m.free(t)
m.pool = append(m.pool, t)
}
}
@@ -417,14 +405,16 @@ func (m *machine) onepass(i input, pos int) bool {
return m.matched
}
-// empty is a non-nil 0-element slice,
-// so doExecute can avoid an allocation
-// when 0 captures are requested from a successful match.
-var empty = make([]int, 0)
+// doMatch reports whether either r, b or s match the regexp.
+func (re *Regexp) doMatch(r io.RuneReader, b []byte, s string) bool {
+ return re.doExecute(r, b, s, 0, 0, nil) != nil
+}
-// doExecute finds the leftmost match in the input and returns
-// the position of its subexpressions.
-func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int {
+// doExecute finds the leftmost match in the input, appends the position
+// of its subexpressions to dstCap and returns dstCap.
+//
+// nil is returned if no matches are found and non-nil if matches are found.
+func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int, dstCap []int) []int {
m := re.get()
var i input
var size int
@@ -457,12 +447,15 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
return nil
}
}
- if ncap == 0 {
- re.put(m)
- return empty // empty but not nil
+ dstCap = append(dstCap, m.matchcap...)
+ if dstCap == nil {
+ // Keep the promise of returning non-nil value on match.
+ dstCap = arrayNoInts[:0]
}
- cap := make([]int, len(m.matchcap))
- copy(cap, m.matchcap)
re.put(m)
- return cap
+ return dstCap
}
+
+// arrayNoInts is returned by doExecute match if nil dstCap is passed
+// to it with ncap=0.
+var arrayNoInts [0]int
diff --git a/libgo/go/regexp/exec_test.go b/libgo/go/regexp/exec_test.go
index 4872cb3def..766394de6e 100644
--- a/libgo/go/regexp/exec_test.go
+++ b/libgo/go/regexp/exec_test.go
@@ -8,6 +8,7 @@ import (
"bufio"
"compress/bzip2"
"fmt"
+ "internal/testenv"
"io"
"os"
"path/filepath"
@@ -22,7 +23,7 @@ import (
// considered during RE2's exhaustive tests, which run all possible
// regexps over a given set of atoms and operators, up to a given
// complexity, over all possible strings over a given alphabet,
-// up to a given size. Rather than try to link with RE2, we read a
+// up to a given size. Rather than try to link with RE2, we read a
// log file containing the test cases and the expected matches.
// The log file, re2-exhaustive.txt, is generated by running 'make log'
// in the open source RE2 distribution https://github.com/google/re2/.
@@ -41,21 +42,21 @@ import (
// -;0-3 0-1 1-2 2-3
//
// The stanza begins by defining a set of strings, quoted
-// using Go double-quote syntax, one per line. Then the
+// using Go double-quote syntax, one per line. Then the
// regexps section gives a sequence of regexps to run on
-// the strings. In the block that follows a regexp, each line
+// the strings. In the block that follows a regexp, each line
// gives the semicolon-separated match results of running
// the regexp on the corresponding string.
// Each match result is either a single -, meaning no match, or a
// space-separated sequence of pairs giving the match and
-// submatch indices. An unmatched subexpression formats
+// submatch indices. An unmatched subexpression formats
// its pair as a single - (not illustrated above). For now
// each regexp run produces two match results, one for a
// ``full match'' that restricts the regexp to matching the entire
// string or nothing, and one for a ``partial match'' that gives
// the leftmost first match found in the string.
//
-// Lines beginning with # are comments. Lines beginning with
+// Lines beginning with # are comments. Lines beginning with
// a capital letter are test names printed during RE2's test suite
// and are echoed into t but otherwise ignored.
//
@@ -155,9 +156,9 @@ func testRE2(t *testing.T, file string) {
if !isSingleBytes(text) && strings.Contains(re.String(), `\B`) {
// RE2's \B considers every byte position,
// so it sees 'not word boundary' in the
- // middle of UTF-8 sequences. This package
+ // middle of UTF-8 sequences. This package
// only considers the positions between runes,
- // so it disagrees. Skip those cases.
+ // so it disagrees. Skip those cases.
continue
}
res := strings.Split(line, ";")
@@ -409,7 +410,7 @@ Reading:
// h REG_MULTIREF multiple digit backref
// i REG_ICASE ignore case
// j REG_SPAN . matches \n
- // k REG_ESCAPE \ to ecape [...] delimiter
+ // k REG_ESCAPE \ to escape [...] delimiter
// l REG_LEFT implicit ^...
// m REG_MINIMAL minimal match
// n REG_NEWLINE explicit \n match
@@ -658,47 +659,47 @@ func makeText(n int) []byte {
return text
}
-func benchmark(b *testing.B, re string, n int) {
- r := MustCompile(re)
- t := makeText(n)
- b.ResetTimer()
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- if r.Match(t) {
- b.Fatal("match!")
+func BenchmarkMatch(b *testing.B) {
+ isRaceBuilder := strings.HasSuffix(testenv.Builder(), "-race")
+
+ for _, data := range benchData {
+ r := MustCompile(data.re)
+ for _, size := range benchSizes {
+ if isRaceBuilder && size.n > 1<<10 {
+ continue
+ }
+ t := makeText(size.n)
+ b.Run(data.name+"/"+size.name, func(b *testing.B) {
+ b.SetBytes(int64(size.n))
+ for i := 0; i < b.N; i++ {
+ if r.Match(t) {
+ b.Fatal("match!")
+ }
+ }
+ })
}
}
}
-const (
- easy0 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
- easy1 = "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"
- medium = "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
- hard = "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
- parens = "([ -~])*(A)(B)(C)(D)(E)(F)(G)(H)(I)(J)(K)(L)(M)" +
- "(N)(O)(P)(Q)(R)(S)(T)(U)(V)(W)(X)(Y)(Z)$"
-)
+var benchData = []struct{ name, re string }{
+ {"Easy0", "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+ {"Easy0i", "(?i)ABCDEFGHIJklmnopqrstuvwxyz$"},
+ {"Easy1", "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"},
+ {"Medium", "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+ {"Hard", "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+ {"Hard1", "ABCD|CDEF|EFGH|GHIJ|IJKL|KLMN|MNOP|OPQR|QRST|STUV|UVWX|WXYZ"},
+}
-func BenchmarkMatchEasy0_32(b *testing.B) { benchmark(b, easy0, 32<<0) }
-func BenchmarkMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) }
-func BenchmarkMatchEasy0_32K(b *testing.B) { benchmark(b, easy0, 32<<10) }
-func BenchmarkMatchEasy0_1M(b *testing.B) { benchmark(b, easy0, 1<<20) }
-func BenchmarkMatchEasy0_32M(b *testing.B) { benchmark(b, easy0, 32<<20) }
-func BenchmarkMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) }
-func BenchmarkMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) }
-func BenchmarkMatchEasy1_32K(b *testing.B) { benchmark(b, easy1, 32<<10) }
-func BenchmarkMatchEasy1_1M(b *testing.B) { benchmark(b, easy1, 1<<20) }
-func BenchmarkMatchEasy1_32M(b *testing.B) { benchmark(b, easy1, 32<<20) }
-func BenchmarkMatchMedium_32(b *testing.B) { benchmark(b, medium, 32<<0) }
-func BenchmarkMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) }
-func BenchmarkMatchMedium_32K(b *testing.B) { benchmark(b, medium, 32<<10) }
-func BenchmarkMatchMedium_1M(b *testing.B) { benchmark(b, medium, 1<<20) }
-func BenchmarkMatchMedium_32M(b *testing.B) { benchmark(b, medium, 32<<20) }
-func BenchmarkMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) }
-func BenchmarkMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) }
-func BenchmarkMatchHard_32K(b *testing.B) { benchmark(b, hard, 32<<10) }
-func BenchmarkMatchHard_1M(b *testing.B) { benchmark(b, hard, 1<<20) }
-func BenchmarkMatchHard_32M(b *testing.B) { benchmark(b, hard, 32<<20) }
+var benchSizes = []struct {
+ name string
+ n int
+}{
+ {"32", 32},
+ {"1K", 1 << 10},
+ {"32K", 32 << 10},
+ {"1M", 1 << 20},
+ {"32M", 32 << 20},
+}
func TestLongest(t *testing.T) {
re, err := Compile(`a(|b)`)
diff --git a/libgo/go/regexp/onepass.go b/libgo/go/regexp/onepass.go
index 2ce3902388..1b0564c3fd 100644
--- a/libgo/go/regexp/onepass.go
+++ b/libgo/go/regexp/onepass.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -33,7 +33,7 @@ type onePassInst struct {
}
// OnePassPrefix returns a literal string that all matches for the
-// regexp must start with. Complete is true if the prefix
+// regexp must start with. Complete is true if the prefix
// is the entire match. Pc is the index of the last rune instruction
// in the string. The OnePassPrefix skips over the mandatory
// EmptyBeginText
@@ -287,11 +287,6 @@ func (p runeSlice) Len() int { return len(p) }
func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-// Sort is a convenience method.
-func (p runeSlice) Sort() {
- sort.Sort(p)
-}
-
var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
var anyRune = []rune{0, unicode.MaxRune}
@@ -450,7 +445,7 @@ func makeOnePass(p *onePassProg) *onePassProg {
for !instQueue.empty() {
visitQueue.clear()
pc := instQueue.next()
- if !check(uint32(pc), m) {
+ if !check(pc, m) {
p = notOnePass
break
}
diff --git a/libgo/go/regexp/onepass_test.go b/libgo/go/regexp/onepass_test.go
index 8202ebefa5..f4e336c43b 100644
--- a/libgo/go/regexp/onepass_test.go
+++ b/libgo/go/regexp/onepass_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -133,8 +133,6 @@ func TestMergeRuneSet(t *testing.T) {
}
}
-const noStr = `!`
-
var onePass = &onePassProg{}
var onePassTests = []struct {
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
index d7d0edb993..01093d4bd0 100644
--- a/libgo/go/regexp/regexp.go
+++ b/libgo/go/regexp/regexp.go
@@ -22,14 +22,14 @@
// All characters are UTF-8-encoded code points.
//
// There are 16 methods of Regexp that match a regular expression and identify
-// the matched text. Their names are matched by this regular expression:
+// the matched text. Their names are matched by this regular expression:
//
// Find(All)?(String)?(Submatch)?(Index)?
//
// If 'All' is present, the routine matches successive non-overlapping
-// matches of the entire expression. Empty matches abutting a preceding
-// match are ignored. The return value is a slice containing the successive
-// return values of the corresponding non-'All' routine. These routines take
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
// an extra integer argument, n; if n >= 0, the function returns at most n
// matches/submatches.
//
@@ -45,9 +45,9 @@
//
// If 'Index' is present, matches and submatches are identified by byte index
// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
-// the nth submatch. The pair for n==0 identifies the match of the entire
-// expression. If 'Index' is not present, the match is identified by the
-// text of the match/submatch. If an index is negative, it means that
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
// subexpression did not match any string in the input.
//
// There is also a subset of the methods that can be applied to text read
@@ -55,7 +55,7 @@
//
// MatchReader, FindReaderIndex, FindReaderSubmatchIndex
//
-// This set may grow. Note that regular expression matches may need to
+// This set may grow. Note that regular expression matches may need to
// examine text beyond the text returned by a match, so the methods that
// match text from a RuneReader may read arbitrarily far into the input
// before returning.
@@ -75,12 +75,18 @@ import (
"unicode/utf8"
)
-var debug = false
-
// Regexp is the representation of a compiled regular expression.
// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
// read-only after Compile
+ regexpRO
+
+ // cache of machines for running regexp
+ mu sync.Mutex
+ machine []*machine
+}
+
+type regexpRO struct {
expr string // as passed to Compile
prog *syntax.Prog // compiled program
onepass *onePassProg // onepass program or nil
@@ -93,10 +99,6 @@ type Regexp struct {
numSubexp int
subexpNames []string
longest bool
-
- // cache of machines for running regexp
- mu sync.Mutex
- machine []*machine
}
// String returns the source text used to compile the regular expression.
@@ -109,10 +111,11 @@ func (re *Regexp) String() string {
// When using a Regexp in multiple goroutines, giving each goroutine
// its own copy helps to avoid lock contention.
func (re *Regexp) Copy() *Regexp {
- r := *re
- r.mu = sync.Mutex{}
- r.machine = nil
- return &r
+ // It is not safe to copy Regexp by value
+ // since it contains a sync.Mutex.
+ return &Regexp{
+ regexpRO: re.regexpRO,
+ }
}
// Compile parses a regular expression and returns, if successful,
@@ -174,13 +177,15 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
return nil, err
}
regexp := &Regexp{
- expr: expr,
- prog: prog,
- onepass: compileOnePass(prog),
- numSubexp: maxCap,
- subexpNames: capNames,
- cond: prog.StartCond(),
- longest: longest,
+ regexpRO: regexpRO{
+ expr: expr,
+ prog: prog,
+ onepass: compileOnePass(prog),
+ numSubexp: maxCap,
+ subexpNames: capNames,
+ cond: prog.StartCond(),
+ longest: longest,
+ },
}
if regexp.onepass == notOnePass {
regexp.prefix, regexp.prefixComplete = prog.Prefix()
@@ -258,10 +263,10 @@ func (re *Regexp) NumSubexp() int {
}
// SubexpNames returns the names of the parenthesized subexpressions
-// in this Regexp. The name for the first sub-expression is names[1],
+// in this Regexp. The name for the first sub-expression is names[1],
// so that if m is a match slice, the name for m[i] is SubexpNames()[i].
// Since the Regexp as a whole cannot be named, names[0] is always
-// the empty string. The slice should not be modified.
+// the empty string. The slice should not be modified.
func (re *Regexp) SubexpNames() []string {
return re.subexpNames
}
@@ -394,7 +399,7 @@ func (i *inputReader) context(pos int) syntax.EmptyOp {
}
// LiteralPrefix returns a literal string that must begin any match
-// of the regular expression re. It returns the boolean true if the
+// of the regular expression re. It returns the boolean true if the
// literal string comprises the entire regular expression.
func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
return re.prefix, re.prefixComplete
@@ -403,21 +408,21 @@ func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
// MatchReader reports whether the Regexp matches the text read by the
// RuneReader.
func (re *Regexp) MatchReader(r io.RuneReader) bool {
- return re.doExecute(r, nil, "", 0, 0) != nil
+ return re.doMatch(r, nil, "")
}
// MatchString reports whether the Regexp matches the string s.
func (re *Regexp) MatchString(s string) bool {
- return re.doExecute(nil, nil, s, 0, 0) != nil
+ return re.doMatch(nil, nil, s)
}
// Match reports whether the Regexp matches the byte slice b.
func (re *Regexp) Match(b []byte) bool {
- return re.doExecute(nil, b, "", 0, 0) != nil
+ return re.doMatch(nil, b, "")
}
// MatchReader checks whether a textual regular expression matches the text
-// read by the RuneReader. More complicated queries need to use Compile and
+// read by the RuneReader. More complicated queries need to use Compile and
// the full Regexp interface.
func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) {
re, err := Compile(pattern)
@@ -428,7 +433,7 @@ func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) {
}
// MatchString checks whether a textual regular expression
-// matches a string. More complicated queries need
+// matches a string. More complicated queries need
// to use Compile and the full Regexp interface.
func MatchString(pattern string, s string) (matched bool, err error) {
re, err := Compile(pattern)
@@ -439,7 +444,7 @@ func MatchString(pattern string, s string) (matched bool, err error) {
}
// Match checks whether a textual regular expression
-// matches a byte slice. More complicated queries need
+// matches a byte slice. More complicated queries need
// to use Compile and the full Regexp interface.
func Match(pattern string, b []byte) (matched bool, err error) {
re, err := Compile(pattern)
@@ -450,11 +455,11 @@ func Match(pattern string, b []byte) (matched bool, err error) {
}
// ReplaceAllString returns a copy of src, replacing matches of the Regexp
-// with the replacement string repl. Inside repl, $ signs are interpreted as
+// with the replacement string repl. Inside repl, $ signs are interpreted as
// in Expand, so for instance $1 represents the text of the first submatch.
func (re *Regexp) ReplaceAllString(src, repl string) string {
n := 2
- if strings.Index(repl, "$") >= 0 {
+ if strings.Contains(repl, "$") {
n = 2 * (re.numSubexp + 1)
}
b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte {
@@ -464,7 +469,7 @@ func (re *Regexp) ReplaceAllString(src, repl string) string {
}
// ReplaceAllLiteralString returns a copy of src, replacing matches of the Regexp
-// with the replacement string repl. The replacement repl is substituted directly,
+// with the replacement string repl. The replacement repl is substituted directly,
// without using Expand.
func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
return string(re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
@@ -474,7 +479,7 @@ func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
// ReplaceAllStringFunc returns a copy of src in which all matches of the
// Regexp have been replaced by the return value of function repl applied
-// to the matched substring. The replacement returned by repl is substituted
+// to the matched substring. The replacement returned by repl is substituted
// directly, without using Expand.
func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
b := re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
@@ -497,8 +502,9 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
nmatch = re.prog.NumCap
}
+ var dstCap [2]int
for searchPos <= endPos {
- a := re.doExecute(nil, bsrc, src, searchPos, nmatch)
+ a := re.doExecute(nil, bsrc, src, searchPos, nmatch, dstCap[:0])
if len(a) == 0 {
break // no more matches
}
@@ -530,7 +536,7 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
searchPos += width
} else if searchPos+1 > a[1] {
// This clause is only needed at the end of the input
- // string. In that case, DecodeRuneInString returns width=0.
+ // string. In that case, DecodeRuneInString returns width=0.
searchPos++
} else {
searchPos = a[1]
@@ -548,7 +554,7 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
}
// ReplaceAll returns a copy of src, replacing matches of the Regexp
-// with the replacement text repl. Inside repl, $ signs are interpreted as
+// with the replacement text repl. Inside repl, $ signs are interpreted as
// in Expand, so for instance $1 represents the text of the first submatch.
func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
n := 2
@@ -566,7 +572,7 @@ func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
}
// ReplaceAllLiteral returns a copy of src, replacing matches of the Regexp
-// with the replacement bytes repl. The replacement repl is substituted directly,
+// with the replacement bytes repl. The replacement repl is substituted directly,
// without using Expand.
func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
@@ -576,7 +582,7 @@ func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
// ReplaceAllFunc returns a copy of src in which all matches of the
// Regexp have been replaced by the return value of function repl applied
-// to the matched byte slice. The replacement returned by repl is substituted
+// to the matched byte slice. The replacement returned by repl is substituted
// directly, without using Expand.
func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
@@ -592,13 +598,24 @@ func special(b byte) bool {
// QuoteMeta returns a string that quotes all regular expression metacharacters
// inside the argument text; the returned string is a regular expression matching
-// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
func QuoteMeta(s string) string {
- b := make([]byte, 2*len(s))
-
// A byte loop is correct because all metacharacters are ASCII.
- j := 0
- for i := 0; i < len(s); i++ {
+ var i int
+ for i = 0; i < len(s); i++ {
+ if special(s[i]) {
+ break
+ }
+ }
+ // No meta characters found, so return original string.
+ if i >= len(s) {
+ return s
+ }
+
+ b := make([]byte, 2*len(s)-i)
+ copy(b, s[:i])
+ j := i
+ for ; i < len(s); i++ {
if special(s[i]) {
b[j] = '\\'
j++
@@ -606,7 +623,7 @@ func QuoteMeta(s string) string {
b[j] = s[i]
j++
}
- return string(b[0:j])
+ return string(b[:j])
}
// The number of capture values in the program may correspond
@@ -636,7 +653,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
}
for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
- matches := re.doExecute(nil, b, s, pos, re.prog.NumCap)
+ matches := re.doExecute(nil, b, s, pos, re.prog.NumCap, nil)
if len(matches) == 0 {
break
}
@@ -676,7 +693,8 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
// Find returns a slice holding the text of the leftmost match in b of the regular expression.
// A return value of nil indicates no match.
func (re *Regexp) Find(b []byte) []byte {
- a := re.doExecute(nil, b, "", 0, 2)
+ var dstCap [2]int
+ a := re.doExecute(nil, b, "", 0, 2, dstCap[:0])
if a == nil {
return nil
}
@@ -684,11 +702,11 @@ func (re *Regexp) Find(b []byte) []byte {
}
// FindIndex returns a two-element slice of integers defining the location of
-// the leftmost match in b of the regular expression. The match itself is at
+// the leftmost match in b of the regular expression. The match itself is at
// b[loc[0]:loc[1]].
// A return value of nil indicates no match.
func (re *Regexp) FindIndex(b []byte) (loc []int) {
- a := re.doExecute(nil, b, "", 0, 2)
+ a := re.doExecute(nil, b, "", 0, 2, nil)
if a == nil {
return nil
}
@@ -696,12 +714,13 @@ func (re *Regexp) FindIndex(b []byte) (loc []int) {
}
// FindString returns a string holding the text of the leftmost match in s of the regular
-// expression. If there is no match, the return value is an empty string,
+// expression. If there is no match, the return value is an empty string,
// but it will also be empty if the regular expression successfully matches
-// an empty string. Use FindStringIndex or FindStringSubmatch if it is
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
// necessary to distinguish these cases.
func (re *Regexp) FindString(s string) string {
- a := re.doExecute(nil, nil, s, 0, 2)
+ var dstCap [2]int
+ a := re.doExecute(nil, nil, s, 0, 2, dstCap[:0])
if a == nil {
return ""
}
@@ -709,11 +728,11 @@ func (re *Regexp) FindString(s string) string {
}
// FindStringIndex returns a two-element slice of integers defining the
-// location of the leftmost match in s of the regular expression. The match
+// location of the leftmost match in s of the regular expression. The match
// itself is at s[loc[0]:loc[1]].
// A return value of nil indicates no match.
func (re *Regexp) FindStringIndex(s string) (loc []int) {
- a := re.doExecute(nil, nil, s, 0, 2)
+ a := re.doExecute(nil, nil, s, 0, 2, nil)
if a == nil {
return nil
}
@@ -722,11 +741,11 @@ func (re *Regexp) FindStringIndex(s string) (loc []int) {
// FindReaderIndex returns a two-element slice of integers defining the
// location of the leftmost match of the regular expression in text read from
-// the RuneReader. The match text was found in the input stream at
+// the RuneReader. The match text was found in the input stream at
// byte offset loc[0] through loc[1]-1.
// A return value of nil indicates no match.
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
- a := re.doExecute(r, nil, "", 0, 2)
+ a := re.doExecute(r, nil, "", 0, 2, nil)
if a == nil {
return nil
}
@@ -739,7 +758,8 @@ func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
// comment.
// A return value of nil indicates no match.
func (re *Regexp) FindSubmatch(b []byte) [][]byte {
- a := re.doExecute(nil, b, "", 0, re.prog.NumCap)
+ var dstCap [4]int
+ a := re.doExecute(nil, b, "", 0, re.prog.NumCap, dstCap[:0])
if a == nil {
return nil
}
@@ -754,14 +774,14 @@ func (re *Regexp) FindSubmatch(b []byte) [][]byte {
// Expand appends template to dst and returns the result; during the
// append, Expand replaces variables in the template with corresponding
-// matches drawn from src. The match slice should have been returned by
+// matches drawn from src. The match slice should have been returned by
// FindSubmatchIndex.
//
// In the template, a variable is denoted by a substring of the form
// $name or ${name}, where name is a non-empty sequence of letters,
-// digits, and underscores. A purely numeric name like $1 refers to
+// digits, and underscores. A purely numeric name like $1 refers to
// the submatch with the corresponding index; other names refer to
-// capturing parentheses named with the (?P<name>...) syntax. A
+// capturing parentheses named with the (?P<name>...) syntax. A
// reference to an out of range or unmatched index or a name that is not
// present in the regular expression is replaced with an empty slice.
//
@@ -886,7 +906,7 @@ func extract(str string) (name string, num int, rest string, ok bool) {
// in the package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindSubmatchIndex(b []byte) []int {
- return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap))
+ return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap, nil))
}
// FindStringSubmatch returns a slice of strings holding the text of the
@@ -895,7 +915,8 @@ func (re *Regexp) FindSubmatchIndex(b []byte) []int {
// package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindStringSubmatch(s string) []string {
- a := re.doExecute(nil, nil, s, 0, re.prog.NumCap)
+ var dstCap [4]int
+ a := re.doExecute(nil, nil, s, 0, re.prog.NumCap, dstCap[:0])
if a == nil {
return nil
}
@@ -914,16 +935,16 @@ func (re *Regexp) FindStringSubmatch(s string) []string {
// 'Index' descriptions in the package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindStringSubmatchIndex(s string) []int {
- return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap))
+ return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap, nil))
}
// FindReaderSubmatchIndex returns a slice holding the index pairs
// identifying the leftmost match of the regular expression of text read by
// the RuneReader, and the matches, if any, of its subexpressions, as defined
-// by the 'Submatch' and 'Index' descriptions in the package comment. A
+// by the 'Submatch' and 'Index' descriptions in the package comment. A
// return value of nil indicates no match.
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
- return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap))
+ return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap, nil))
}
const startSize = 10 // The size at which to start a slice in the 'All' routines.
diff --git a/libgo/go/regexp/syntax/compile.go b/libgo/go/regexp/syntax/compile.go
index 95f6f15698..83e53ba6ca 100644
--- a/libgo/go/regexp/syntax/compile.go
+++ b/libgo/go/regexp/syntax/compile.go
@@ -8,11 +8,11 @@ import "unicode"
// A patchList is a list of instruction pointers that need to be filled in (patched).
// Because the pointers haven't been filled in yet, we can reuse their storage
-// to hold the list. It's kind of sleazy, but works well in practice.
+// to hold the list. It's kind of sleazy, but works well in practice.
// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
//
// These aren't really pointers: they're integers, so we can reinterpret them
-// this way without using package unsafe. A value l denotes
+// this way without using package unsafe. A value l denotes
// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
// l == 0 denotes the empty list, okay because we start every program
// with a fail instruction, so we'll never want to point at its output link.
diff --git a/libgo/go/regexp/syntax/doc.go b/libgo/go/regexp/syntax/doc.go
index e5e71f14f5..efc0b43571 100644
--- a/libgo/go/regexp/syntax/doc.go
+++ b/libgo/go/regexp/syntax/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -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
diff --git a/libgo/go/regexp/syntax/parse.go b/libgo/go/regexp/syntax/parse.go
index f38bbf66e3..7b8be55ddb 100644
--- a/libgo/go/regexp/syntax/parse.go
+++ b/libgo/go/regexp/syntax/parse.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -141,9 +141,9 @@ func (p *parser) push(re *Regexp) *Regexp {
}
// maybeConcat implements incremental concatenation
-// of literal runes into string nodes. The parser calls this
+// of literal runes into string nodes. The parser calls this
// before each push, so only the top fragment of the stack
-// might need processing. Since this is called before a push,
+// might need processing. Since this is called before a push,
// the topmost literal is no longer subject to operators like *
// (Otherwise ab* would turn into (ab)*.)
// If r >= 0 and there's a node left over, maybeConcat uses it
@@ -600,7 +600,7 @@ func (p *parser) leadingString(re *Regexp) ([]rune, Flags) {
}
// removeLeadingString removes the first n leading runes
-// from the beginning of re. It returns the replacement for re.
+// from the beginning of re. It returns the replacement for re.
func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp {
if re.Op == OpConcat && len(re.Sub) > 0 {
// Removing a leading string in a concatenation
@@ -957,11 +957,11 @@ func (p *parser) parsePerlFlags(s string) (rest string, err error) {
// Perl 5.10 gave in and implemented the Python version too,
// but they claim that the last two are the preferred forms.
// PCRE and languages based on it (specifically, PHP and Ruby)
- // support all three as well. EcmaScript 4 uses only the Python form.
+ // support all three as well. EcmaScript 4 uses only the Python form.
//
// In both the open source world (via Code Search) and the
// Google source tree, (?P<expr>name) is the dominant form,
- // so that's the one we implement. One is enough.
+ // so that's the one we implement. One is enough.
if len(t) > 4 && t[2] == 'P' && t[3] == '<' {
// Pull out name.
end := strings.IndexRune(t, '>')
@@ -989,7 +989,7 @@ func (p *parser) parsePerlFlags(s string) (rest string, err error) {
return t[end+1:], nil
}
- // Non-capturing group. Might also twiddle Perl flags.
+ // Non-capturing group. Might also twiddle Perl flags.
var c rune
t = t[2:] // skip (?
flags := p.flags
@@ -1257,7 +1257,7 @@ Switch:
if c < utf8.RuneSelf && !isalnum(c) {
// Escaped non-word characters are always themselves.
// PCRE is not quite so rigorous: it accepts things like
- // \q, but we don't. We once rejected \_, but too many
+ // \q, but we don't. We once rejected \_, but too many
// programs and people insist on using it, so allow \_.
return c, t, nil
}
@@ -1292,7 +1292,7 @@ Switch:
if c == '{' {
// Any number of digits in braces.
// Perl accepts any text at all; it ignores all text
- // after the first non-hex digit. We require only hex digits,
+ // after the first non-hex digit. We require only hex digits,
// and at least one.
nhex := 0
r = 0
@@ -1333,10 +1333,10 @@ Switch:
}
return x*16 + y, t, nil
- // C escapes. There is no case 'b', to avoid misparsing
+ // C escapes. There is no case 'b', to avoid misparsing
// the Perl word-boundary \b as the C backspace \b
- // when in POSIX mode. In Perl, /\b/ means word-boundary
- // but /[\b]/ means backspace. We don't support that.
+ // when in POSIX mode. In Perl, /\b/ means word-boundary
+ // but /[\b]/ means backspace. We don't support that.
// If you want a backspace, embed a literal backspace
// character or use \x08.
case 'a':
@@ -1377,7 +1377,7 @@ type charGroup struct {
}
// parsePerlClassEscape parses a leading Perl character class escape like \d
-// from the beginning of s. If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
// and returns the new slice r and the remainder of the string.
func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest string) {
if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
@@ -1391,7 +1391,7 @@ func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest stri
}
// parseNamedClass parses a leading POSIX named character class like [:alnum:]
-// from the beginning of s. If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
// and returns the new slice r and the remainder of the string.
func (p *parser) parseNamedClass(s string, r []rune) (out []rune, rest string, err error) {
if len(s) < 2 || s[0] != '[' || s[1] != ':' {
@@ -1454,7 +1454,7 @@ func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
}
// parseUnicodeClass parses a leading Unicode character class like \p{Han}
-// from the beginning of s. If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
// and returns the new slice r and the remainder of the string.
func (p *parser) parseUnicodeClass(s string, r []rune) (out []rune, rest string, err error) {
if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
@@ -1692,7 +1692,7 @@ const (
// minimum and maximum runes involved in folding.
// checked during test.
minFold = 0x0041
- maxFold = 0x118df
+ maxFold = 0x1e943
)
// appendFoldedRange returns the result of appending the range lo-hi
@@ -1718,7 +1718,7 @@ func appendFoldedRange(r []rune, lo, hi rune) []rune {
hi = maxFold
}
- // Brute force. Depend on appendRange to coalesce ranges on the fly.
+ // Brute force. Depend on appendRange to coalesce ranges on the fly.
for c := lo; c <= hi; c++ {
r = appendRange(r, c, c)
f := unicode.SimpleFold(c)
diff --git a/libgo/go/regexp/syntax/parse_test.go b/libgo/go/regexp/syntax/parse_test.go
index 5ca54bbe1e..dd6529f7c8 100644
--- a/libgo/go/regexp/syntax/parse_test.go
+++ b/libgo/go/regexp/syntax/parse_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go
index ae6db31a44..c32ae8d9fa 100644
--- a/libgo/go/regexp/syntax/prog.go
+++ b/libgo/go/regexp/syntax/prog.go
@@ -144,7 +144,7 @@ func (i *Inst) op() InstOp {
}
// Prefix returns a literal string that all matches for the
-// regexp must start with. Complete is true if the prefix
+// regexp must start with. Complete is true if the prefix
// is the entire match.
func (p *Prog) Prefix() (prefix string, complete bool) {
i, _ := p.skipNop(uint32(p.Start))
@@ -164,7 +164,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
}
// StartCond returns the leading empty-width conditions that must
-// be true in any match. It returns ^EmptyOp(0) if no matches are possible.
+// be true in any match. It returns ^EmptyOp(0) if no matches are possible.
func (p *Prog) StartCond() EmptyOp {
var flag EmptyOp
pc := uint32(p.Start)
diff --git a/libgo/go/regexp/syntax/regexp.go b/libgo/go/regexp/syntax/regexp.go
index 75822cf981..0fe9269f25 100644
--- a/libgo/go/regexp/syntax/regexp.go
+++ b/libgo/go/regexp/syntax/regexp.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -139,7 +139,7 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
if len(re.Rune) == 0 {
b.WriteString(`^\x00-\x{10FFFF}`)
} else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
- // Contains 0 and MaxRune. Probably a negated class.
+ // Contains 0 and MaxRune. Probably a negated class.
// Print the gaps.
b.WriteRune('^')
for i := 1; i < len(re.Rune)-1; i += 2 {
@@ -252,7 +252,7 @@ const meta = `\.+*?()|[]{}^$`
func escape(b *bytes.Buffer, r rune, force bool) {
if unicode.IsPrint(r) {
- if strings.IndexRune(meta, r) >= 0 || force {
+ if strings.ContainsRune(meta, r) || force {
b.WriteRune('\\')
}
b.WriteRune(r)
diff --git a/libgo/go/regexp/syntax/simplify.go b/libgo/go/regexp/syntax/simplify.go
index 72390417bb..e439325139 100644
--- a/libgo/go/regexp/syntax/simplify.go
+++ b/libgo/go/regexp/syntax/simplify.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -8,7 +8,7 @@ package syntax
// and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/.
// The resulting regexp will execute correctly but its string representation
// will not produce the same parse tree, because capturing parentheses
-// may have been duplicated or removed. For example, the simplified form
+// may have been duplicated or removed. For example, the simplified form
// for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1.
// The returned regexp may share structure with or be the original.
func (re *Regexp) Simplify() *Regexp {
@@ -117,13 +117,13 @@ func (re *Regexp) Simplify() *Regexp {
}
// simplify1 implements Simplify for the unary OpStar,
-// OpPlus, and OpQuest operators. It returns the simple regexp
+// OpPlus, and OpQuest operators. It returns the simple regexp
// equivalent to
//
// Regexp{Op: op, Flags: flags, Sub: {sub}}
//
// under the assumption that sub is already simple, and
-// without first allocating that structure. If the regexp
+// without first allocating that structure. If the regexp
// to be returned turns out to be equivalent to re, simplify1
// returns re instead.
//
diff --git a/libgo/go/regexp/syntax/simplify_test.go b/libgo/go/regexp/syntax/simplify_test.go
index 5d0f1dea5e..9877db3d0a 100644
--- a/libgo/go/regexp/syntax/simplify_test.go
+++ b/libgo/go/regexp/syntax/simplify_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -59,7 +59,7 @@ var simplifyTests = []struct {
{`a{0,1}`, `a?`},
// The next three are illegible because Simplify inserts (?:)
// parens instead of () parens to avoid creating extra
- // captured subexpressions. The comments show a version with fewer parens.
+ // captured subexpressions. The comments show a version with fewer parens.
{`(a){0,2}`, `(?:(a)(a)?)?`}, // (aa?)?
{`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // (a(a(aa?)?)?)?
{`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)?
@@ -117,7 +117,7 @@ var simplifyTests = []struct {
// Empty string as a regular expression.
// The empty string must be preserved inside parens in order
// to make submatches work right, so these tests are less
- // interesting than they might otherwise be. String inserts
+ // interesting than they might otherwise be. String inserts
// explicit (?:) in place of non-parenthesized empty strings,
// to make them easier to spot for other parsers.
{`(a|b|)`, `([a-b]|(?:))`},
diff --git a/libgo/go/runtime/alg.go b/libgo/go/runtime/alg.go
new file mode 100644
index 0000000000..4946269245
--- /dev/null
+++ b/libgo/go/runtime/alg.go
@@ -0,0 +1,390 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname memhash0 runtime.memhash0
+//go:linkname memhash8 runtime.memhash8
+//go:linkname memhash16 runtime.memhash16
+//go:linkname memhash32 runtime.memhash32
+//go:linkname memhash64 runtime.memhash64
+//go:linkname memhash128 runtime.memhash128
+//go:linkname strhash runtime.strhash
+//go:linkname f32hash runtime.f32hash
+//go:linkname f64hash runtime.f64hash
+//go:linkname c64hash runtime.c64hash
+//go:linkname c128hash runtime.c128hash
+//go:linkname interhash runtime.interhash
+//go:linkname nilinterhash runtime.nilinterhash
+//go:linkname memequal0 runtime.memequal0
+//go:linkname memequal8 runtime.memequal8
+//go:linkname memequal16 runtime.memequal16
+//go:linkname memequal32 runtime.memequal32
+//go:linkname memequal64 runtime.memequal64
+//go:linkname memequal128 runtime.memequal128
+//go:linkname strequal runtime.strequal
+//go:linkname f32equal runtime.f32equal
+//go:linkname f64equal runtime.f64equal
+//go:linkname c64equal runtime.c64equal
+//go:linkname c128equal runtime.c128equal
+//go:linkname interequal runtime.interequal
+//go:linkname nilinterequal runtime.nilinterequal
+//go:linkname efaceeq runtime.efaceeq
+//go:linkname ifaceeq runtime.ifaceeq
+//go:linkname ifacevaleq runtime.ifacevaleq
+//go:linkname ifaceefaceeq runtime.ifaceefaceeq
+//go:linkname efacevaleq runtime.efacevaleq
+//go:linkname eqstring runtime.eqstring
+//go:linkname cmpstring runtime.cmpstring
+//
+// Temporary to be called from C code.
+//go:linkname alginit runtime.alginit
+
+const (
+ c0 = uintptr((8-sys.PtrSize)/4*2860486313 + (sys.PtrSize-4)/4*33054211828000289)
+ c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503)
+)
+
+func memhash0(p unsafe.Pointer, h uintptr) uintptr {
+ return h
+}
+func memhash8(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, 1)
+}
+func memhash16(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, 2)
+}
+func memhash32(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, 4)
+}
+func memhash64(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, 8)
+}
+func memhash128(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, 16)
+}
+
+var useAeshash bool
+
+// in C code
+func aeshashbody(p unsafe.Pointer, h, s uintptr, sched []byte) uintptr
+
+func aeshash(p unsafe.Pointer, h, s uintptr) uintptr {
+ return aeshashbody(p, h, s, aeskeysched[:])
+}
+
+func aeshashstr(p unsafe.Pointer, h uintptr) uintptr {
+ ps := (*stringStruct)(p)
+ return aeshashbody(unsafe.Pointer(ps.str), h, uintptr(ps.len), aeskeysched[:])
+}
+
+func strhash(a unsafe.Pointer, h uintptr) uintptr {
+ x := (*stringStruct)(a)
+ return memhash(x.str, h, uintptr(x.len))
+}
+
+// NOTE: Because NaN != NaN, a map can contain any
+// number of (mostly useless) entries keyed with NaNs.
+// To avoid long hash chains, we assign a random number
+// as the hash value for a NaN.
+
+func f32hash(p unsafe.Pointer, h uintptr) uintptr {
+ f := *(*float32)(p)
+ switch {
+ case f == 0:
+ return c1 * (c0 ^ h) // +0, -0
+ case f != f:
+ return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
+ default:
+ return memhash(p, h, 4)
+ }
+}
+
+func f64hash(p unsafe.Pointer, h uintptr) uintptr {
+ f := *(*float64)(p)
+ switch {
+ case f == 0:
+ return c1 * (c0 ^ h) // +0, -0
+ case f != f:
+ return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
+ default:
+ return memhash(p, h, 8)
+ }
+}
+
+func c64hash(p unsafe.Pointer, h uintptr) uintptr {
+ x := (*[2]float32)(p)
+ return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
+}
+
+func c128hash(p unsafe.Pointer, h uintptr) uintptr {
+ x := (*[2]float64)(p)
+ return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
+}
+
+func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
+ a := (*iface)(p)
+ tab := a.tab
+ if tab == nil {
+ return h
+ }
+ t := *(**_type)(tab)
+ fn := t.hashfn
+ if fn == nil {
+ panic(errorString("hash of unhashable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return c1 * fn(unsafe.Pointer(&a.data), h^c0)
+ } else {
+ return c1 * fn(a.data, h^c0)
+ }
+}
+
+func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
+ a := (*eface)(p)
+ t := a._type
+ if t == nil {
+ return h
+ }
+ fn := t.hashfn
+ if fn == nil {
+ panic(errorString("hash of unhashable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return c1 * fn(unsafe.Pointer(&a.data), h^c0)
+ } else {
+ return c1 * fn(a.data, h^c0)
+ }
+}
+
+func memequal0(p, q unsafe.Pointer) bool {
+ return true
+}
+func memequal8(p, q unsafe.Pointer) bool {
+ return *(*int8)(p) == *(*int8)(q)
+}
+func memequal16(p, q unsafe.Pointer) bool {
+ return *(*int16)(p) == *(*int16)(q)
+}
+func memequal32(p, q unsafe.Pointer) bool {
+ return *(*int32)(p) == *(*int32)(q)
+}
+func memequal64(p, q unsafe.Pointer) bool {
+ return *(*int64)(p) == *(*int64)(q)
+}
+func memequal128(p, q unsafe.Pointer) bool {
+ return *(*[2]int64)(p) == *(*[2]int64)(q)
+}
+func f32equal(p, q unsafe.Pointer) bool {
+ return *(*float32)(p) == *(*float32)(q)
+}
+func f64equal(p, q unsafe.Pointer) bool {
+ return *(*float64)(p) == *(*float64)(q)
+}
+func c64equal(p, q unsafe.Pointer) bool {
+ return *(*complex64)(p) == *(*complex64)(q)
+}
+func c128equal(p, q unsafe.Pointer) bool {
+ return *(*complex128)(p) == *(*complex128)(q)
+}
+func strequal(p, q unsafe.Pointer) bool {
+ return *(*string)(p) == *(*string)(q)
+}
+func interequal(p, q unsafe.Pointer, size uintptr) bool {
+ return ifaceeq(*(*iface)(p), *(*iface)(q))
+}
+func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
+ return efaceeq(*(*eface)(p), *(*eface)(q))
+}
+func efaceeq(x, y eface) bool {
+ t := x._type
+ if !eqtype(t, y._type) {
+ return false
+ }
+ if t == nil {
+ return true
+ }
+ eq := t.equalfn
+ if eq == nil {
+ panic(errorString("comparing uncomparable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return x.data == y.data
+ }
+ return eq(x.data, y.data)
+}
+func ifaceeq(x, y iface) bool {
+ xtab := x.tab
+ if xtab == nil && y.tab == nil {
+ return true
+ }
+ if xtab == nil || y.tab == nil {
+ return false
+ }
+ t := *(**_type)(xtab)
+ if !eqtype(t, *(**_type)(y.tab)) {
+ return false
+ }
+ eq := t.equalfn
+ if eq == nil {
+ panic(errorString("comparing uncomparable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return x.data == y.data
+ }
+ return eq(x.data, y.data)
+}
+
+func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool {
+ if x.tab == nil {
+ return false
+ }
+ xt := *(**_type)(x.tab)
+ if !eqtype(xt, t) {
+ return false
+ }
+ eq := t.equalfn
+ if eq == nil {
+ panic(errorString("comparing uncomparable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return x.data == p
+ }
+ return eq(x.data, p)
+}
+
+func ifaceefaceeq(x iface, y eface) bool {
+ if x.tab == nil && y._type == nil {
+ return true
+ }
+ if x.tab == nil || y._type == nil {
+ return false
+ }
+ xt := *(**_type)(x.tab)
+ if !eqtype(xt, y._type) {
+ return false
+ }
+ eq := xt.equalfn
+ if eq == nil {
+ panic(errorString("comparing uncomparable type " + *xt.string))
+ }
+ if isDirectIface(xt) {
+ return x.data == y.data
+ }
+ return eq(x.data, y.data)
+}
+
+func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool {
+ if x._type == nil {
+ return false
+ }
+ if !eqtype(x._type, t) {
+ return false
+ }
+ eq := t.equalfn
+ if eq == nil {
+ panic(errorString("comparing uncomparable type " + *t.string))
+ }
+ if isDirectIface(t) {
+ return x.data == p
+ }
+ return eq(x.data, p)
+}
+
+func cmpstring(x, y string) int {
+ a := stringStructOf(&x)
+ b := stringStructOf(&y)
+ l := a.len
+ if l > b.len {
+ l = b.len
+ }
+ i := memcmp(unsafe.Pointer(a.str), unsafe.Pointer(b.str), uintptr(l))
+ if i != 0 {
+ return int(i)
+ }
+ if a.len < b.len {
+ return -1
+ } else if a.len > b.len {
+ return 1
+ }
+ return 0
+}
+
+// For the unsafe.Pointer type descriptor in libgo/runtime/go-unsafe-pointer.c.
+
+func pointerhash(p unsafe.Pointer, h uintptr) uintptr {
+ return memhash(p, h, unsafe.Sizeof(unsafe.Pointer))
+}
+
+func pointerequal(p, q unsafe.Pointer) bool {
+ return *(*unsafe.Pointer)(p) == *(*unsafe.Pointer)(q)
+}
+
+// Force the creation of function descriptors for equality and hash
+// functions. These will be referenced directly by the compiler.
+var _ = memhash
+var _ = memhash0
+var _ = memhash8
+var _ = memhash16
+var _ = memhash32
+var _ = memhash64
+var _ = memhash128
+var _ = strhash
+var _ = f32hash
+var _ = f64hash
+var _ = c64hash
+var _ = c128hash
+var _ = interhash
+var _ = nilinterhash
+var _ = memequal0
+var _ = memequal8
+var _ = memequal16
+var _ = memequal32
+var _ = memequal64
+var _ = memequal128
+var _ = f32equal
+var _ = f64equal
+var _ = c64equal
+var _ = c128equal
+var _ = strequal
+var _ = interequal
+var _ = nilinterequal
+var _ = pointerhash
+var _ = pointerequal
+
+const hashRandomBytes = sys.PtrSize / 4 * 64
+
+// used in asm_{386,amd64}.s to seed the hash function
+var aeskeysched [hashRandomBytes]byte
+
+// used in hash{32,64}.go to seed the hash function
+var hashkey [4]uintptr
+
+func alginit() {
+ // Install aes hash algorithm if we have the instructions we need
+ if (GOARCH == "386" || GOARCH == "amd64") &&
+ GOOS != "nacl" &&
+ support_aes &&
+ cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
+ cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
+ cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
+ useAeshash = true
+ // Initialize with random data so hash collisions will be hard to engineer.
+ getRandomData(aeskeysched[:])
+ return
+ }
+ getRandomData((*[len(hashkey) * sys.PtrSize]byte)(unsafe.Pointer(&hashkey))[:])
+ hashkey[0] |= 1 // make sure these numbers are odd
+ hashkey[1] |= 1
+ hashkey[2] |= 1
+ hashkey[3] |= 1
+}
diff --git a/libgo/go/runtime/append_test.go b/libgo/go/runtime/append_test.go
index a67dc9b494..6bd8f3bd95 100644
--- a/libgo/go/runtime/append_test.go
+++ b/libgo/go/runtime/append_test.go
@@ -3,10 +3,59 @@
// license that can be found in the LICENSE file.
package runtime_test
-import "testing"
+import (
+ "fmt"
+ "testing"
+)
const N = 20
+func BenchmarkMakeSlice(b *testing.B) {
+ var x []byte
+ for i := 0; i < b.N; i++ {
+ x = make([]byte, 32)
+ _ = x
+ }
+}
+
+func BenchmarkGrowSliceBytes(b *testing.B) {
+ b.StopTimer()
+ var x = make([]byte, 9)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ _ = append([]byte(nil), x...)
+ }
+}
+
+func BenchmarkGrowSliceInts(b *testing.B) {
+ b.StopTimer()
+ var x = make([]int, 9)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ _ = append([]int(nil), x...)
+ }
+}
+
+func BenchmarkGrowSlicePtr(b *testing.B) {
+ b.StopTimer()
+ var x = make([]*byte, 9)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ _ = append([]*byte(nil), x...)
+ }
+}
+
+type struct24 struct{ a, b, c int64 }
+
+func BenchmarkGrowSliceStruct24Bytes(b *testing.B) {
+ b.StopTimer()
+ var x = make([]struct24, 9)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ _ = append([]struct24(nil), x...)
+ }
+}
+
func BenchmarkAppend(b *testing.B) {
b.StopTimer()
x := make([]int, 0, N)
@@ -38,73 +87,51 @@ 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)
-}
+var (
+ blackhole []byte
+)
-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 BenchmarkAppendSliceLarge(b *testing.B) {
+ for _, length := range []int{1 << 10, 4 << 10, 16 << 10, 64 << 10, 256 << 10, 1024 << 10} {
+ y := make([]byte, length)
+ b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ blackhole = nil
+ blackhole = append(blackhole, y...)
+ }
+ })
}
}
-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 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 BenchmarkAppendSpecialCase(b *testing.B) {
@@ -149,42 +176,153 @@ 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)
+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 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)
- }
- 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
+ s2Ptr [][2]uintptr
+ s3Ptr [][3]uintptr
+ s4Ptr [][4]uintptr
+)
+
+// BenchmarkAppendInPlace tests the performance of append
+// when the result is being written back to the same slice.
+// In order for the in-place optimization to occur,
+// the slice must be referred to by address;
+// using a global is an easy way to trigger that.
+// We test the "grow" and "no grow" paths separately,
+// but not the "normal" (occasionally grow) path,
+// because it is a blend of the other two.
+// We use small numbers and small sizes in an attempt
+// to avoid benchmarking memory allocation and copying.
+// We use scalars instead of pointers in an attempt
+// to avoid benchmarking the write barriers.
+// We benchmark four common sizes (byte, pointer, string/interface, slice),
+// and one larger size.
+func BenchmarkAppendInPlace(b *testing.B) {
+ b.Run("NoGrow", func(b *testing.B) {
+ const C = 128
+
+ b.Run("Byte", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sByte = make([]byte, C)
+ for j := 0; j < C; j++ {
+ sByte = append(sByte, 0x77)
+ }
+ }
+ })
+
+ b.Run("1Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s1Ptr = make([]uintptr, C)
+ for j := 0; j < C; j++ {
+ s1Ptr = append(s1Ptr, 0x77)
+ }
+ }
+ })
+
+ b.Run("2Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s2Ptr = make([][2]uintptr, C)
+ for j := 0; j < C; j++ {
+ s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
+ }
+ }
+ })
+
+ b.Run("3Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s3Ptr = make([][3]uintptr, C)
+ for j := 0; j < C; j++ {
+ s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
+ }
+ }
+ })
+
+ b.Run("4Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s4Ptr = make([][4]uintptr, C)
+ for j := 0; j < C; j++ {
+ s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
+ }
+ }
+ })
+
+ })
+
+ b.Run("Grow", func(b *testing.B) {
+ const C = 5
+
+ b.Run("Byte", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sByte = make([]byte, 0)
+ for j := 0; j < C; j++ {
+ sByte = append(sByte, 0x77)
+ sByte = sByte[:cap(sByte)]
+ }
+ }
+ })
+
+ b.Run("1Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s1Ptr = make([]uintptr, 0)
+ for j := 0; j < C; j++ {
+ s1Ptr = append(s1Ptr, 0x77)
+ s1Ptr = s1Ptr[:cap(s1Ptr)]
+ }
+ }
+ })
+
+ b.Run("2Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s2Ptr = make([][2]uintptr, 0)
+ for j := 0; j < C; j++ {
+ s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
+ s2Ptr = s2Ptr[:cap(s2Ptr)]
+ }
+ }
+ })
+
+ b.Run("3Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s3Ptr = make([][3]uintptr, 0)
+ for j := 0; j < C; j++ {
+ s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
+ s3Ptr = s3Ptr[:cap(s3Ptr)]
+ }
+ }
+ })
+
+ b.Run("4Ptr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s4Ptr = make([][4]uintptr, 0)
+ for j := 0; j < C; j++ {
+ s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
+ s4Ptr = s4Ptr[:cap(s4Ptr)]
+ }
+ }
+ })
+
+ })
+}
diff --git a/libgo/go/runtime/callers_test.go b/libgo/go/runtime/callers_test.go
new file mode 100644
index 0000000000..ad83f9969c
--- /dev/null
+++ b/libgo/go/runtime/callers_test.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func f1(pan bool) []uintptr {
+ return f2(pan) // line 14
+}
+
+func f2(pan bool) []uintptr {
+ return f3(pan) // line 18
+}
+
+func f3(pan bool) []uintptr {
+ if pan {
+ panic("f3") // line 23
+ }
+ ret := make([]uintptr, 20)
+ return ret[:runtime.Callers(0, ret)] // line 26
+}
+
+func testCallers(t *testing.T, pcs []uintptr, pan bool) {
+ m := make(map[string]int, len(pcs))
+ frames := runtime.CallersFrames(pcs)
+ for {
+ frame, more := frames.Next()
+ if frame.Function != "" {
+ m[frame.Function] = frame.Line
+ }
+ if !more {
+ break
+ }
+ }
+
+ var seen []string
+ for k := range m {
+ seen = append(seen, k)
+ }
+ t.Logf("functions seen: %s", strings.Join(seen, " "))
+
+ var f3Line int
+ if pan {
+ f3Line = 23
+ } else {
+ f3Line = 26
+ }
+ want := []struct {
+ name string
+ line int
+ }{
+ {"f1", 14},
+ {"f2", 18},
+ {"f3", f3Line},
+ }
+ for _, w := range want {
+ if got := m["runtime_test."+w.name]; got != w.line {
+ t.Errorf("%s is line %d, want %d", w.name, got, w.line)
+ }
+ }
+}
+
+func TestCallers(t *testing.T) {
+ testCallers(t, f1(false), false)
+}
+
+func TestCallersPanic(t *testing.T) {
+ defer func() {
+ if r := recover(); r == nil {
+ t.Fatal("did not panic")
+ }
+ pcs := make([]uintptr, 20)
+ pcs = pcs[:runtime.Callers(0, pcs)]
+ testCallers(t, pcs, true)
+ }()
+ f1(true)
+}
diff --git a/libgo/go/runtime/cgo_gccgo.go b/libgo/go/runtime/cgo_gccgo.go
new file mode 100644
index 0000000000..a55fb436bc
--- /dev/null
+++ b/libgo/go/runtime/cgo_gccgo.go
@@ -0,0 +1,110 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ _ "unsafe"
+)
+
+// For historical reasons these functions are called as though they
+// were in the syscall package.
+//go:linkname Cgocall syscall.Cgocall
+//go:linkname CgocallDone syscall.CgocallDone
+//go:linkname CgocallBack syscall.CgocallBack
+//go:linkname CgocallBackDone syscall.CgocallBackDone
+
+// A routine that may be called by SWIG.
+//go:linkname _cgo_panic _cgo_panic
+
+// iscgo is set to true if the cgo tool sets the C variable runtime_iscgo
+// to true.
+var iscgo bool
+
+// cgoHasExtraM is set on startup when an extra M is created for cgo.
+// The extra M must be created before any C/C++ code calls cgocallback.
+var cgoHasExtraM bool
+
+// Cgocall prepares to call from code written in Go to code written in
+// C/C++. This takes the current goroutine out of the Go scheduler, as
+// though it were making a system call. Otherwise the program can
+// lookup if the C code blocks. The idea is to call this function,
+// then immediately call the C/C++ function. After the C/C++ function
+// returns, call cgocalldone. The usual Go code would look like
+// syscall.Cgocall()
+// defer syscall.Cgocalldone()
+// cfunction()
+func Cgocall() {
+ lockOSThread()
+ mp := getg().m
+ mp.ncgocall++
+ mp.ncgo++
+ entersyscall(0)
+}
+
+// CgocallDone prepares to return to Go code from C/C++ code.
+func CgocallDone() {
+ gp := getg()
+ if gp == nil {
+ throw("no g in CgocallDone")
+ }
+ gp.m.ncgo--
+
+ // If we are invoked because the C function called _cgo_panic,
+ // then _cgo_panic will already have exited syscall mode.
+ if gp.atomicstatus == _Gsyscall {
+ exitsyscall(0)
+ }
+
+ unlockOSThread()
+}
+
+// CgocallBack is used when calling from C/C++ code into Go code.
+// The usual approach is
+// syscall.CgocallBack()
+// defer syscall.CgocallBackDone()
+// gofunction()
+//go:nosplit
+func CgocallBack() {
+ if getg() == nil || getg().m == nil {
+ needm(0)
+ mp := getg().m
+ mp.dropextram = true
+ }
+
+ exitsyscall(0)
+
+ if getg().m.ncgo == 0 {
+ // The C call to Go came from a thread created by C.
+ // The C call to Go came from a thread not currently running
+ // any Go. In the case of -buildmode=c-archive or c-shared,
+ // this call may be coming in before package initialization
+ // is complete. Wait until it is.
+ <-main_init_done
+ }
+
+ mp := getg().m
+ if mp.needextram || atomic.Load(&extraMWaiters) > 0 {
+ mp.needextram = false
+ newextram()
+ }
+}
+
+// CgocallBackDone prepares to return to C/C++ code that has called
+// into Go code.
+func CgocallBackDone() {
+ entersyscall(0)
+ mp := getg().m
+ if mp.dropextram && mp.ncgo == 0 {
+ mp.dropextram = false
+ dropm()
+ }
+}
+
+// _cgo_panic may be called by SWIG code to panic.
+func _cgo_panic(p *byte) {
+ exitsyscall(0)
+ panic(gostringnocopy(p))
+}
diff --git a/libgo/go/runtime/cgo_mmap.go b/libgo/go/runtime/cgo_mmap.go
deleted file mode 100644
index c0396bdde5..0000000000
--- a/libgo/go/runtime/cgo_mmap.go
+++ /dev/null
@@ -1,41 +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.
-
-// Support for memory sanitizer. See runtime/cgo/mmap.go.
-
-// +build linux,amd64
-
-package runtime
-
-import "unsafe"
-
-// _cgo_mmap is filled in by runtime/cgo when it is linked into the
-// program, so it is only non-nil when using cgo.
-//go:linkname _cgo_mmap _cgo_mmap
-var _cgo_mmap unsafe.Pointer
-
-func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
- if _cgo_mmap != nil {
- // Make ret a uintptr so that writing to it in the
- // function literal does not trigger a write barrier.
- // A write barrier here could break because of the way
- // that mmap uses the same value both as a pointer and
- // an errno value.
- // TODO: Fix mmap to return two values.
- var ret uintptr
- systemstack(func() {
- ret = callCgoMmap(addr, n, prot, flags, fd, off)
- })
- return unsafe.Pointer(ret)
- }
- return sysMmap(addr, n, prot, flags, fd, off)
-}
-
-// sysMmap calls the mmap system call. It is implemented in assembly.
-func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
-
-// cgoMmap calls the mmap function in the runtime/cgo package on the
-// callCgoMmap calls the mmap function in the runtime/cgo package
-// using the GCC calling convention. It is implemented in assembly.
-func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr
diff --git a/libgo/go/runtime/cgo_ppc64x.go b/libgo/go/runtime/cgo_ppc64x.go
deleted file mode 100644
index 6a1b3bb417..0000000000
--- a/libgo/go/runtime/cgo_ppc64x.go
+++ /dev/null
@@ -1,12 +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 ppc64 ppc64le
-
-package runtime
-
-// crosscall_ppc64 calls into the runtime to set up the registers the
-// Go runtime expects and so the symbol it calls needs to be exported
-// for external linking to work.
-//go:cgo_export_static _cgo_reginit
diff --git a/libgo/go/runtime/cgocheck.go b/libgo/go/runtime/cgocheck.go
index aebce1506d..fec36462dd 100644
--- a/libgo/go/runtime/cgocheck.go
+++ b/libgo/go/runtime/cgocheck.go
@@ -1,7 +1,9 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 ignore
+
// Code to check that pointer writes follow the cgo rules.
// These functions are invoked via the write barrier when debug.cgocheck > 1.
@@ -89,18 +91,26 @@ func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
}
// cgoCheckTypedBlock checks the block of memory at src, for up to size bytes,
-// and throws if it finds a Go pointer. The type of the memory is typ,
+// and throws if it finds a Go pointer. The type of the memory is typ,
// and src is off bytes into that type.
//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
}
- // The type has a GC program. Try to find GC bits somewhere else.
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ // The type has a GC program. Try to find GC bits somewhere else.
+ for _, datap := range activeModules() {
if cgoInRange(src, datap.data, datap.edata) {
doff := uintptr(src) - datap.data
cgoCheckBits(add(src, -doff), datap.gcdatamask.bytedata, off+doff, size)
@@ -115,7 +125,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
aoff := uintptr(src) - mheap_.arena_start
idx := aoff >> _PageShift
- s := h_spans[idx]
+ s := mheap_.spans[idx]
if s.state == _MSpanStack {
// There are no heap bits for value stored on the stack.
// For a channel receive src might be on the stack of some
@@ -148,8 +158,8 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
}
// cgoCheckBits checks the block of memory at src, for up to size
-// bytes, and throws if it finds a Go pointer. The gcbits mark each
-// pointer value. The src pointer is off bytes into the gcbits.
+// bytes, and throws if it finds a Go pointer. The gcbits mark each
+// pointer value. The src pointer is off bytes into the gcbits.
//go:nosplit
//go:nowritebarrier
func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
@@ -184,15 +194,24 @@ 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.
+// GC bits. This is called on the system stack.
//go:nowritebarrier
//go:systemstack
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
diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go
new file mode 100644
index 0000000000..a9574dd8ac
--- /dev/null
+++ b/libgo/go/runtime/chan.go
@@ -0,0 +1,739 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// This file contains the implementation of Go channels.
+
+// Invariants:
+// At least one of c.sendq and c.recvq is empty,
+// except for the case of an unbuffered channel with a single goroutine
+// blocked on it for both sending and receiving using a select statement,
+// in which case the length of c.sendq and c.recvq is limited only by the
+// size of the select statement.
+//
+// For buffered channels, also:
+// c.qcount > 0 implies that c.recvq is empty.
+// c.qcount < c.dataqsiz implies that c.sendq is empty.
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname makechan runtime.makechan
+//go:linkname chansend1 runtime.chansend1
+//go:linkname chanrecv1 runtime.chanrecv1
+//go:linkname chanrecv2 runtime.chanrecv2
+//go:linkname closechan runtime.closechan
+
+const (
+ maxAlign = 8
+ hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1))
+ debugChan = false
+)
+
+type hchan struct {
+ qcount uint // total data in the queue
+ dataqsiz uint // size of the circular queue
+ buf unsafe.Pointer // points to an array of dataqsiz elements
+ elemsize uint16
+ closed uint32
+ elemtype *_type // element type
+ sendx uint // send index
+ recvx uint // receive index
+ recvq waitq // list of recv waiters
+ sendq waitq // list of send waiters
+
+ // lock protects all fields in hchan, as well as several
+ // fields in sudogs blocked on this channel.
+ //
+ // Do not change another G's status while holding this lock
+ // (in particular, do not ready a G), as this can deadlock
+ // with stack shrinking.
+ lock mutex
+}
+
+type waitq struct {
+ first *sudog
+ last *sudog
+}
+
+//go:linkname reflect_makechan reflect.makechan
+func reflect_makechan(t *chantype, size int64) *hchan {
+ return makechan(t, size)
+}
+
+func makechan(t *chantype, size int64) *hchan {
+ elem := t.elem
+
+ // compiler checks this but be safe.
+ if elem.size >= 1<<16 {
+ throw("makechan: invalid channel element type")
+ }
+ if hchanSize%maxAlign != 0 || elem.align > maxAlign {
+ throw("makechan: bad alignment")
+ }
+ if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) {
+ panic(plainError("makechan: size out of range"))
+ }
+
+ var c *hchan
+ if elem.kind&kindNoPointers != 0 || size == 0 {
+ // Allocate memory in one call.
+ // Hchan does not contain pointers interesting for GC in this case:
+ // buf points into the same allocation, elemtype is persistent.
+ // SudoG's are referenced from their owning thread so they can't be collected.
+ // TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
+ c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true))
+ if size > 0 && elem.size != 0 {
+ c.buf = add(unsafe.Pointer(c), hchanSize)
+ } else {
+ // race detector uses this location for synchronization
+ // Also prevents us from pointing beyond the allocation (see issue 9401).
+ c.buf = unsafe.Pointer(c)
+ }
+ } else {
+ c = new(hchan)
+ c.buf = newarray(elem, int(size))
+ }
+ c.elemsize = uint16(elem.size)
+ c.elemtype = elem
+ c.dataqsiz = uint(size)
+
+ if debugChan {
+ print("makechan: chan=", c, "; elemsize=", elem.size, "; dataqsiz=", size, "\n")
+ }
+ return c
+}
+
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+func chanbuf(c *hchan, i uint) unsafe.Pointer {
+ return add(c.buf, uintptr(i)*uintptr(c.elemsize))
+}
+
+// entry point for c <- x from compiled code
+//go:nosplit
+func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
+ chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t)))
+}
+
+/*
+ * generic single channel send/recv
+ * If block is not nil,
+ * then the protocol will not
+ * sleep but return if it could
+ * not complete.
+ *
+ * sleep can wake up with g.param == nil
+ * when a channel involved in the sleep has
+ * been closed. it is easiest to loop and re-run
+ * the operation; we'll see that it's now closed.
+ */
+func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
+ if raceenabled {
+ raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend))
+ }
+ if msanenabled {
+ msanread(ep, t.elem.size)
+ }
+
+ if c == nil {
+ if !block {
+ return false
+ }
+ gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
+ throw("unreachable")
+ }
+
+ if debugChan {
+ print("chansend: chan=", c, "\n")
+ }
+
+ if raceenabled {
+ racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
+ }
+
+ // Fast path: check for failed non-blocking operation without acquiring the lock.
+ //
+ // After observing that the channel is not closed, we observe that the channel is
+ // not ready for sending. Each of these observations is a single word-sized read
+ // (first c.closed and second c.recvq.first or c.qcount depending on kind of channel).
+ // Because a closed channel cannot transition from 'ready for sending' to
+ // 'not ready for sending', even if the channel is closed between the two observations,
+ // they imply a moment between the two when the channel was both not yet closed
+ // and not ready for sending. We behave as if we observed the channel at that moment,
+ // and report that the send cannot proceed.
+ //
+ // It is okay if the reads are reordered here: if we observe that the channel is not
+ // ready for sending and then observe that it is not closed, that implies that the
+ // channel wasn't closed during the first observation.
+ if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) ||
+ (c.dataqsiz > 0 && c.qcount == c.dataqsiz)) {
+ return false
+ }
+
+ var t0 int64
+ if blockprofilerate > 0 {
+ t0 = cputicks()
+ }
+
+ lock(&c.lock)
+
+ if c.closed != 0 {
+ unlock(&c.lock)
+ panic(plainError("send on closed channel"))
+ }
+
+ if sg := c.recvq.dequeue(); sg != nil {
+ // Found a waiting receiver. We pass the value we want to send
+ // directly to the receiver, bypassing the channel buffer (if any).
+ send(c, sg, ep, func() { unlock(&c.lock) })
+ return true
+ }
+
+ if c.qcount < c.dataqsiz {
+ // Space is available in the channel buffer. Enqueue the element to send.
+ qp := chanbuf(c, c.sendx)
+ if raceenabled {
+ raceacquire(qp)
+ racerelease(qp)
+ }
+ typedmemmove(c.elemtype, qp, ep)
+ c.sendx++
+ if c.sendx == c.dataqsiz {
+ c.sendx = 0
+ }
+ c.qcount++
+ unlock(&c.lock)
+ return true
+ }
+
+ if !block {
+ unlock(&c.lock)
+ return false
+ }
+
+ // Block on the channel. Some receiver will complete our operation for us.
+ gp := getg()
+ mysg := acquireSudog()
+ mysg.releasetime = 0
+ if t0 != 0 {
+ mysg.releasetime = -1
+ }
+ // No stack splits between assigning elem and enqueuing mysg
+ // on gp.waiting where copystack can find it.
+ mysg.elem = ep
+ mysg.waitlink = nil
+ mysg.g = gp
+ mysg.selectdone = nil
+ mysg.c = c
+ gp.waiting = mysg
+ gp.param = nil
+ c.sendq.enqueue(mysg)
+ goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
+
+ // someone woke us up.
+ if mysg != gp.waiting {
+ throw("G waiting list is corrupted")
+ }
+ gp.waiting = nil
+ if gp.param == nil {
+ if c.closed == 0 {
+ throw("chansend: spurious wakeup")
+ }
+ panic(plainError("send on closed channel"))
+ }
+ gp.param = nil
+ if mysg.releasetime > 0 {
+ blockevent(mysg.releasetime-t0, 2)
+ }
+ mysg.c = nil
+ releaseSudog(mysg)
+ return true
+}
+
+// send processes a send operation on an empty channel c.
+// The value ep sent by the sender is copied to the receiver sg.
+// The receiver is then woken up to go on its merry way.
+// Channel c must be empty and locked. send unlocks c with unlockf.
+// sg must already be dequeued from c.
+// ep must be non-nil and point to the heap or the caller's stack.
+func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
+ if raceenabled {
+ if c.dataqsiz == 0 {
+ racesync(c, sg)
+ } else {
+ // Pretend we go through the buffer, even though
+ // we copy directly. Note that we need to increment
+ // the head/tail locations only when raceenabled.
+ qp := chanbuf(c, c.recvx)
+ raceacquire(qp)
+ racerelease(qp)
+ raceacquireg(sg.g, qp)
+ racereleaseg(sg.g, qp)
+ c.recvx++
+ if c.recvx == c.dataqsiz {
+ c.recvx = 0
+ }
+ c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
+ }
+ }
+ if sg.elem != nil {
+ sendDirect(c.elemtype, sg, ep)
+ sg.elem = nil
+ }
+ gp := sg.g
+ unlockf()
+ gp.param = unsafe.Pointer(sg)
+ if sg.releasetime != 0 {
+ sg.releasetime = cputicks()
+ }
+ goready(gp, 4)
+}
+
+// Sends and receives on unbuffered or empty-buffered channels are the
+// only operations where one running goroutine writes to the stack of
+// another running goroutine. The GC assumes that stack writes only
+// happen when the goroutine is running and are only done by that
+// goroutine. Using a write barrier is sufficient to make up for
+// violating that assumption, but the write barrier has to work.
+// typedmemmove will call bulkBarrierPreWrite, but the target bytes
+// are not in the heap, so that will not help. We arrange to call
+// memmove and typeBitsBulkBarrier instead.
+
+func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
+ // src is on our stack, dst is a slot on another stack.
+
+ // Once we read sg.elem out of sg, it will no longer
+ // be updated if the destination's stack gets copied (shrunk).
+ // So make sure that no preemption points can happen between read & use.
+ dst := sg.elem
+ typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
+ memmove(dst, src, t.size)
+}
+
+func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {
+ // dst is on our stack or the heap, src is on another stack.
+ // The channel is locked, so src will not move during this
+ // operation.
+ src := sg.elem
+ typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
+ memmove(dst, src, t.size)
+}
+
+func closechan(c *hchan) {
+ if c == nil {
+ panic(plainError("close of nil channel"))
+ }
+
+ lock(&c.lock)
+ if c.closed != 0 {
+ unlock(&c.lock)
+ panic(plainError("close of closed channel"))
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&c))
+ racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan))
+ racerelease(unsafe.Pointer(c))
+ }
+
+ c.closed = 1
+
+ var glist *g
+
+ // release all readers
+ for {
+ sg := c.recvq.dequeue()
+ if sg == nil {
+ break
+ }
+ if sg.elem != nil {
+ typedmemclr(c.elemtype, sg.elem)
+ sg.elem = nil
+ }
+ if sg.releasetime != 0 {
+ sg.releasetime = cputicks()
+ }
+ gp := sg.g
+ gp.param = nil
+ if raceenabled {
+ raceacquireg(gp, unsafe.Pointer(c))
+ }
+ gp.schedlink.set(glist)
+ glist = gp
+ }
+
+ // release all writers (they will panic)
+ for {
+ sg := c.sendq.dequeue()
+ if sg == nil {
+ break
+ }
+ sg.elem = nil
+ if sg.releasetime != 0 {
+ sg.releasetime = cputicks()
+ }
+ gp := sg.g
+ gp.param = nil
+ if raceenabled {
+ raceacquireg(gp, unsafe.Pointer(c))
+ }
+ gp.schedlink.set(glist)
+ glist = gp
+ }
+ unlock(&c.lock)
+
+ // Ready all Gs now that we've dropped the channel lock.
+ for glist != nil {
+ gp := glist
+ glist = glist.schedlink.ptr()
+ gp.schedlink = 0
+ goready(gp, 3)
+ }
+}
+
+// entry points for <- c from compiled code
+//go:nosplit
+func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) {
+ chanrecv(t, c, elem, true)
+}
+
+//go:nosplit
+func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
+ _, received = chanrecv(t, c, elem, true)
+ return
+}
+
+// chanrecv receives on channel c and writes the received data to ep.
+// ep may be nil, in which case received data is ignored.
+// If block == false and no elements are available, returns (false, false).
+// Otherwise, if c is closed, zeros *ep and returns (true, false).
+// Otherwise, fills in *ep with an element and returns (true, true).
+// A non-nil ep must point to the heap or the caller's stack.
+func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
+ // raceenabled: don't need to check ep, as it is always on the stack
+ // or is new memory allocated by reflect.
+
+ if debugChan {
+ print("chanrecv: chan=", c, "\n")
+ }
+
+ if c == nil {
+ if !block {
+ return
+ }
+ gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
+ throw("unreachable")
+ }
+
+ // Fast path: check for failed non-blocking operation without acquiring the lock.
+ //
+ // After observing that the channel is not ready for receiving, we observe that the
+ // channel is not closed. Each of these observations is a single word-sized read
+ // (first c.sendq.first or c.qcount, and second c.closed).
+ // Because a channel cannot be reopened, the later observation of the channel
+ // being not closed implies that it was also not closed at the moment of the
+ // first observation. We behave as if we observed the channel at that moment
+ // and report that the receive cannot proceed.
+ //
+ // The order of operations is important here: reversing the operations can lead to
+ // incorrect behavior when racing with a close.
+ if !block && (c.dataqsiz == 0 && c.sendq.first == nil ||
+ c.dataqsiz > 0 && atomic.Loaduint(&c.qcount) == 0) &&
+ atomic.Load(&c.closed) == 0 {
+ return
+ }
+
+ var t0 int64
+ if blockprofilerate > 0 {
+ t0 = cputicks()
+ }
+
+ lock(&c.lock)
+
+ if c.closed != 0 && c.qcount == 0 {
+ if raceenabled {
+ raceacquire(unsafe.Pointer(c))
+ }
+ unlock(&c.lock)
+ if ep != nil {
+ typedmemclr(c.elemtype, ep)
+ }
+ return true, false
+ }
+
+ if sg := c.sendq.dequeue(); sg != nil {
+ // Found a waiting sender. If buffer is size 0, receive value
+ // directly from sender. Otherwise, receive from head of queue
+ // and add sender's value to the tail of the queue (both map to
+ // the same buffer slot because the queue is full).
+ recv(c, sg, ep, func() { unlock(&c.lock) })
+ return true, true
+ }
+
+ if c.qcount > 0 {
+ // Receive directly from queue
+ qp := chanbuf(c, c.recvx)
+ if raceenabled {
+ raceacquire(qp)
+ racerelease(qp)
+ }
+ if ep != nil {
+ typedmemmove(c.elemtype, ep, qp)
+ }
+ typedmemclr(c.elemtype, qp)
+ c.recvx++
+ if c.recvx == c.dataqsiz {
+ c.recvx = 0
+ }
+ c.qcount--
+ unlock(&c.lock)
+ return true, true
+ }
+
+ if !block {
+ unlock(&c.lock)
+ return false, false
+ }
+
+ // no sender available: block on this channel.
+ gp := getg()
+ mysg := acquireSudog()
+ mysg.releasetime = 0
+ if t0 != 0 {
+ mysg.releasetime = -1
+ }
+ // No stack splits between assigning elem and enqueuing mysg
+ // on gp.waiting where copystack can find it.
+ mysg.elem = ep
+ mysg.waitlink = nil
+ gp.waiting = mysg
+ mysg.g = gp
+ mysg.selectdone = nil
+ mysg.c = c
+ gp.param = nil
+ c.recvq.enqueue(mysg)
+ goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
+
+ // someone woke us up
+ if mysg != gp.waiting {
+ throw("G waiting list is corrupted")
+ }
+ gp.waiting = nil
+ if mysg.releasetime > 0 {
+ blockevent(mysg.releasetime-t0, 2)
+ }
+ closed := gp.param == nil
+ gp.param = nil
+ mysg.c = nil
+ releaseSudog(mysg)
+ return true, !closed
+}
+
+// recv processes a receive operation on a full channel c.
+// There are 2 parts:
+// 1) The value sent by the sender sg is put into the channel
+// and the sender is woken up to go on its merry way.
+// 2) The value received by the receiver (the current G) is
+// written to ep.
+// For synchronous channels, both values are the same.
+// For asynchronous channels, the receiver gets its data from
+// the channel buffer and the sender's data is put in the
+// channel buffer.
+// Channel c must be full and locked. recv unlocks c with unlockf.
+// sg must already be dequeued from c.
+// A non-nil ep must point to the heap or the caller's stack.
+func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
+ if c.dataqsiz == 0 {
+ if raceenabled {
+ racesync(c, sg)
+ }
+ if ep != nil {
+ // copy data from sender
+ recvDirect(c.elemtype, sg, ep)
+ }
+ } else {
+ // Queue is full. Take the item at the
+ // head of the queue. Make the sender enqueue
+ // its item at the tail of the queue. Since the
+ // queue is full, those are both the same slot.
+ qp := chanbuf(c, c.recvx)
+ if raceenabled {
+ raceacquire(qp)
+ racerelease(qp)
+ raceacquireg(sg.g, qp)
+ racereleaseg(sg.g, qp)
+ }
+ // copy data from queue to receiver
+ if ep != nil {
+ typedmemmove(c.elemtype, ep, qp)
+ }
+ // copy data from sender to queue
+ typedmemmove(c.elemtype, qp, sg.elem)
+ c.recvx++
+ if c.recvx == c.dataqsiz {
+ c.recvx = 0
+ }
+ c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
+ }
+ sg.elem = nil
+ gp := sg.g
+ unlockf()
+ gp.param = unsafe.Pointer(sg)
+ if sg.releasetime != 0 {
+ sg.releasetime = cputicks()
+ }
+ goready(gp, 4)
+}
+
+// compiler implements
+//
+// select {
+// case c <- v:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if selectnbsend(c, v) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
+ return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t)))
+}
+
+// compiler implements
+//
+// select {
+// case v = <-c:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if selectnbrecv(&v, c) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
+ selected, _ = chanrecv(t, c, elem, false)
+ return
+}
+
+// compiler implements
+//
+// select {
+// case v, ok = <-c:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if c != nil && selectnbrecv2(&v, &ok, c) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
+ // TODO(khr): just return 2 values from this function, now that it is in Go.
+ selected, *received = chanrecv(t, c, elem, false)
+ return
+}
+
+//go:linkname reflect_chansend reflect.chansend
+func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
+ return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
+}
+
+//go:linkname reflect_chanrecv reflect.chanrecv
+func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
+ return chanrecv(t, c, elem, !nb)
+}
+
+//go:linkname reflect_chanlen reflect.chanlen
+func reflect_chanlen(c *hchan) int {
+ if c == nil {
+ return 0
+ }
+ return int(c.qcount)
+}
+
+//go:linkname reflect_chancap reflect.chancap
+func reflect_chancap(c *hchan) int {
+ if c == nil {
+ return 0
+ }
+ return int(c.dataqsiz)
+}
+
+//go:linkname reflect_chanclose reflect.chanclose
+func reflect_chanclose(c *hchan) {
+ closechan(c)
+}
+
+func (q *waitq) enqueue(sgp *sudog) {
+ sgp.next = nil
+ x := q.last
+ if x == nil {
+ sgp.prev = nil
+ q.first = sgp
+ q.last = sgp
+ return
+ }
+ sgp.prev = x
+ x.next = sgp
+ q.last = sgp
+}
+
+func (q *waitq) dequeue() *sudog {
+ for {
+ sgp := q.first
+ if sgp == nil {
+ return nil
+ }
+ y := sgp.next
+ if y == nil {
+ q.first = nil
+ q.last = nil
+ } else {
+ y.prev = nil
+ q.first = y
+ sgp.next = nil // mark as removed (see dequeueSudog)
+ }
+
+ // if sgp participates in a select and is already signaled, ignore it
+ if sgp.selectdone != nil {
+ // claim the right to signal
+ if *sgp.selectdone != 0 || !atomic.Cas(sgp.selectdone, 0, 1) {
+ continue
+ }
+ }
+
+ return sgp
+ }
+}
+
+func racesync(c *hchan, sg *sudog) {
+ racerelease(chanbuf(c, 0))
+ raceacquireg(sg.g, chanbuf(c, 0))
+ racereleaseg(sg.g, chanbuf(c, 0))
+ raceacquire(chanbuf(c, 0))
+}
diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go
index 6553509457..b96af8af5d 100644
--- a/libgo/go/runtime/chan_test.go
+++ b/libgo/go/runtime/chan_test.go
@@ -215,11 +215,14 @@ func TestNonblockRecvRace(t *testing.T) {
select {
case <-c:
default:
- t.Fatal("chan is not ready")
+ t.Error("chan is not ready")
}
}()
close(c)
<-c
+ if t.Failed() {
+ return
+ }
}
}
@@ -316,14 +319,16 @@ func TestSelfSelect(t *testing.T) {
case c <- p:
case v := <-c:
if chanCap == 0 && v == p {
- t.Fatalf("self receive")
+ t.Errorf("self receive")
+ return
}
}
} else {
select {
case v := <-c:
if chanCap == 0 && v == p {
- t.Fatalf("self receive")
+ t.Errorf("self receive")
+ return
}
case c <- p:
}
@@ -578,7 +583,7 @@ func TestSelectDuplicateChannel(t *testing.T) {
}
e <- 9
}()
- time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
+ time.Sleep(time.Millisecond) // make sure goroutine A gets queued first on c
// goroutine B
go func() {
@@ -591,6 +596,84 @@ func TestSelectDuplicateChannel(t *testing.T) {
c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
}
+var selectSink interface{}
+
+func TestSelectStackAdjust(t *testing.T) {
+ // Test that channel receive slots that contain local stack
+ // pointers are adjusted correctly by stack shrinking.
+ c := make(chan *int)
+ d := make(chan *int)
+ ready1 := make(chan bool)
+ ready2 := make(chan bool)
+
+ f := func(ready chan bool, dup bool) {
+ // Temporarily grow the stack to 10K.
+ stackGrowthRecursive((10 << 10) / (128 * 8))
+
+ // We're ready to trigger GC and stack shrink.
+ ready <- true
+
+ val := 42
+ var cx *int
+ cx = &val
+
+ var c2 chan *int
+ var d2 chan *int
+ if dup {
+ c2 = c
+ d2 = d
+ }
+
+ // Receive from d. cx won't be affected.
+ select {
+ case cx = <-c:
+ case <-c2:
+ case <-d:
+ case <-d2:
+ }
+
+ // Check that pointer in cx was adjusted correctly.
+ if cx != &val {
+ t.Error("cx no longer points to val")
+ } else if val != 42 {
+ t.Error("val changed")
+ } else {
+ *cx = 43
+ if val != 43 {
+ t.Error("changing *cx failed to change val")
+ }
+ }
+ ready <- true
+ }
+
+ go f(ready1, false)
+ go f(ready2, true)
+
+ // Let the goroutines get into the select.
+ <-ready1
+ <-ready2
+ time.Sleep(10 * time.Millisecond)
+
+ // Force concurrent GC a few times.
+ var before, after runtime.MemStats
+ runtime.ReadMemStats(&before)
+ for i := 0; i < 100; i++ {
+ selectSink = new([1 << 20]byte)
+ runtime.ReadMemStats(&after)
+ if after.NumGC-before.NumGC >= 2 {
+ goto done
+ }
+ }
+ t.Fatal("failed to trigger concurrent GC")
+done:
+ selectSink = nil
+
+ // Wake selects.
+ close(d)
+ <-ready1
+ <-ready2
+}
+
func BenchmarkChanNonblocking(b *testing.B) {
myc := make(chan int)
b.RunParallel(func(pb *testing.PB) {
@@ -721,7 +804,7 @@ func BenchmarkChanContended(b *testing.B) {
})
}
-func BenchmarkChanSync(b *testing.B) {
+func benchmarkChanSync(b *testing.B, work int) {
const CallsPerSched = 1000
procs := 2
N := int32(b.N / CallsPerSched / procs * procs)
@@ -737,10 +820,14 @@ func BenchmarkChanSync(b *testing.B) {
for g := 0; g < CallsPerSched; g++ {
if i%2 == 0 {
<-myc
+ localWork(work)
myc <- 0
+ localWork(work)
} else {
myc <- 0
+ localWork(work)
<-myc
+ localWork(work)
}
}
}
@@ -752,6 +839,14 @@ func BenchmarkChanSync(b *testing.B) {
}
}
+func BenchmarkChanSync(b *testing.B) {
+ benchmarkChanSync(b, 0)
+}
+
+func BenchmarkChanSyncWork(b *testing.B) {
+ benchmarkChanSync(b, 1000)
+}
+
func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
const CallsPerSched = 1000
procs := runtime.GOMAXPROCS(-1)
@@ -925,3 +1020,18 @@ func BenchmarkChanPopular(b *testing.B) {
}
wg.Wait()
}
+
+var (
+ alwaysFalse = false
+ workSink = 0
+)
+
+func localWork(w int) {
+ foo := 0
+ for i := 0; i < w; i++ {
+ foo /= (foo + 1)
+ }
+ if alwaysFalse {
+ workSink += foo
+ }
+}
diff --git a/libgo/go/runtime/chanbarrier_test.go b/libgo/go/runtime/chanbarrier_test.go
index 770b850f87..b6029fb044 100644
--- a/libgo/go/runtime/chanbarrier_test.go
+++ b/libgo/go/runtime/chanbarrier_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/compiler.go b/libgo/go/runtime/compiler.go
index b04be6181a..02787ec558 100644
--- a/libgo/go/runtime/compiler.go
+++ b/libgo/go/runtime/compiler.go
@@ -1,11 +1,11 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
// Compiler is the name of the compiler toolchain that built the
-// running binary. Known toolchains are:
+// running binary. Known toolchains are:
//
// gc Also known as cmd/compile.
// gccgo The gccgo front end, part of the GCC compiler suite.
diff --git a/libgo/go/runtime/cpuprof.go b/libgo/go/runtime/cpuprof.go
new file mode 100644
index 0000000000..e1206f99f1
--- /dev/null
+++ b/libgo/go/runtime/cpuprof.go
@@ -0,0 +1,454 @@
+// 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.
+
+// CPU profiling.
+// Based on algorithms and data structures used in
+// https://github.com/google/pprof.
+//
+// The main difference between this code and the google-perftools
+// code is that this code is written to allow copying the profile data
+// to an arbitrary io.Writer, while the google-perftools code always
+// writes to an operating system file.
+//
+// The signal handler for the profiling clock tick adds a new stack trace
+// to a hash table tracking counts for recent traces. Most clock ticks
+// hit in the cache. In the event of a cache miss, an entry must be
+// evicted from the hash table, copied to a log that will eventually be
+// written as profile data. The google-perftools code flushed the
+// log itself during the signal handler. This code cannot do that, because
+// the io.Writer might block or need system calls or locks that are not
+// safe to use from within the signal handler. Instead, we split the log
+// into two halves and let the signal handler fill one half while a goroutine
+// is writing out the other half. When the signal handler fills its half, it
+// offers to swap with the goroutine. If the writer is not done with its half,
+// we lose the stack trace for this clock tick (and record that loss).
+// The goroutine interacts with the signal handler by calling getprofile() to
+// get the next log piece to write, implicitly handing back the last log
+// piece it obtained.
+//
+// The state of this dance between the signal handler and the goroutine
+// is encoded in the Profile.handoff field. If handoff == 0, then the goroutine
+// is not using either log half and is waiting (or will soon be waiting) for
+// a new piece by calling notesleep(&p.wait). If the signal handler
+// changes handoff from 0 to non-zero, it must call notewakeup(&p.wait)
+// to wake the goroutine. The value indicates the number of entries in the
+// log half being handed off. The goroutine leaves the non-zero value in
+// place until it has finished processing the log half and then flips the number
+// back to zero. Setting the high bit in handoff means that the profiling is over,
+// and the goroutine is now in charge of flushing the data left in the hash table
+// to the log and returning that data.
+//
+// The handoff field is manipulated using atomic operations.
+// For the most part, the manipulation of handoff is orderly: if handoff == 0
+// then the signal handler owns it and can change it to non-zero.
+// If handoff != 0 then the goroutine owns it and can change it to zero.
+// If that were the end of the story then we would not need to manipulate
+// handoff using atomic operations. The operations are needed, however,
+// in order to let the log closer set the high bit to indicate "EOF" safely
+// in the situation when normally the goroutine "owns" handoff.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+const (
+ numBuckets = 1 << 10
+ logSize = 1 << 17
+ assoc = 4
+ maxCPUProfStack = 64
+)
+
+type cpuprofEntry struct {
+ count uintptr
+ depth int
+ stack [maxCPUProfStack]uintptr
+}
+
+//go:notinheap
+type cpuProfile struct {
+ on bool // profiling is on
+ wait note // goroutine waits here
+ count uintptr // tick count
+ evicts uintptr // eviction count
+ lost uintptr // lost ticks that need to be logged
+
+ // Active recent stack traces.
+ hash [numBuckets]struct {
+ entry [assoc]cpuprofEntry
+ }
+
+ // Log of traces evicted from hash.
+ // Signal handler has filled log[toggle][:nlog].
+ // Goroutine is writing log[1-toggle][:handoff].
+ log [2][logSize / 2]uintptr
+ nlog int
+ toggle int32
+ handoff uint32
+
+ // Writer state.
+ // Writer maintains its own toggle to avoid races
+ // looking at signal handler's toggle.
+ wtoggle uint32
+ wholding bool // holding & need to release a log half
+ flushing bool // flushing hash table - profile is over
+ eodSent bool // special end-of-data record sent; => flushing
+}
+
+var (
+ cpuprofLock mutex
+ cpuprof *cpuProfile
+
+ eod = [3]uintptr{0, 1, 0}
+)
+
+func setcpuprofilerate(hz int32) {
+ systemstack(func() {
+ setcpuprofilerate_m(hz)
+ })
+}
+
+// lostProfileData is a no-op function used in profiles
+// to mark the number of profiling stack traces that were
+// discarded due to slow data writers.
+func lostProfileData() {}
+
+// SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
+// If hz <= 0, SetCPUProfileRate turns off profiling.
+// If the profiler is on, the rate cannot be changed without first turning it off.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.cpuprofile flag instead of calling
+// SetCPUProfileRate directly.
+func SetCPUProfileRate(hz int) {
+ // Clamp hz to something reasonable.
+ if hz < 0 {
+ hz = 0
+ }
+ if hz > 1000000 {
+ hz = 1000000
+ }
+
+ lock(&cpuprofLock)
+ if hz > 0 {
+ if cpuprof == nil {
+ cpuprof = (*cpuProfile)(sysAlloc(unsafe.Sizeof(cpuProfile{}), &memstats.other_sys))
+ if cpuprof == nil {
+ print("runtime: cpu profiling cannot allocate memory\n")
+ unlock(&cpuprofLock)
+ return
+ }
+ }
+ if cpuprof.on || cpuprof.handoff != 0 {
+ print("runtime: cannot set cpu profile rate until previous profile has finished.\n")
+ unlock(&cpuprofLock)
+ return
+ }
+
+ cpuprof.on = true
+ // pprof binary header format.
+ // https://github.com/gperftools/gperftools/blob/master/src/profiledata.cc#L119
+ p := &cpuprof.log[0]
+ p[0] = 0 // count for header
+ p[1] = 3 // depth for header
+ p[2] = 0 // version number
+ p[3] = uintptr(1e6 / hz) // period (microseconds)
+ p[4] = 0
+ cpuprof.nlog = 5
+ cpuprof.toggle = 0
+ cpuprof.wholding = false
+ cpuprof.wtoggle = 0
+ cpuprof.flushing = false
+ cpuprof.eodSent = false
+ noteclear(&cpuprof.wait)
+
+ setcpuprofilerate(int32(hz))
+ } else if cpuprof != nil && cpuprof.on {
+ setcpuprofilerate(0)
+ cpuprof.on = false
+
+ // Now add is not running anymore, and getprofile owns the entire log.
+ // Set the high bit in cpuprof.handoff to tell getprofile.
+ for {
+ n := cpuprof.handoff
+ if n&0x80000000 != 0 {
+ print("runtime: setcpuprofile(off) twice\n")
+ }
+ if atomic.Cas(&cpuprof.handoff, n, n|0x80000000) {
+ if n == 0 {
+ // we did the transition from 0 -> nonzero so we wake getprofile
+ notewakeup(&cpuprof.wait)
+ }
+ break
+ }
+ }
+ }
+ unlock(&cpuprofLock)
+}
+
+// add adds the stack trace to the profile.
+// It is called from signal handlers and other limited environments
+// and cannot allocate memory or acquire locks that might be
+// held at the time of the signal, nor can it use substantial amounts
+// of stack. It is allowed to call evict.
+//go:nowritebarrierrec
+func (p *cpuProfile) add(pc []uintptr) {
+ p.addWithFlushlog(pc, p.flushlog)
+}
+
+// addWithFlushlog implements add and addNonGo.
+// It is called from signal handlers and other limited environments
+// and cannot allocate memory or acquire locks that might be
+// held at the time of the signal, nor can it use substantial amounts
+// of stack. It may be called by a signal handler with no g or m.
+// It is allowed to call evict, passing the flushlog parameter.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) addWithFlushlog(pc []uintptr, flushlog func() bool) {
+ if len(pc) > maxCPUProfStack {
+ pc = pc[:maxCPUProfStack]
+ }
+
+ // Compute hash.
+ h := uintptr(0)
+ for _, x := range pc {
+ h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
+ h += x * 41
+ }
+ p.count++
+
+ // Add to entry count if already present in table.
+ b := &p.hash[h%numBuckets]
+Assoc:
+ for i := range b.entry {
+ e := &b.entry[i]
+ if e.depth != len(pc) {
+ continue
+ }
+ for j := range pc {
+ if e.stack[j] != pc[j] {
+ continue Assoc
+ }
+ }
+ e.count++
+ return
+ }
+
+ // Evict entry with smallest count.
+ var e *cpuprofEntry
+ for i := range b.entry {
+ if e == nil || b.entry[i].count < e.count {
+ e = &b.entry[i]
+ }
+ }
+ if e.count > 0 {
+ if !p.evict(e, flushlog) {
+ // Could not evict entry. Record lost stack.
+ p.lost++
+ return
+ }
+ p.evicts++
+ }
+
+ // Reuse the newly evicted entry.
+ e.depth = len(pc)
+ e.count = 1
+ copy(e.stack[:], pc)
+}
+
+// evict copies the given entry's data into the log, so that
+// the entry can be reused. evict is called from add, which
+// is called from the profiling signal handler, so it must not
+// allocate memory or block, and it may be called with no g or m.
+// It is safe to call flushlog. evict returns true if the entry was
+// copied to the log, false if there was no room available.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) evict(e *cpuprofEntry, flushlog func() bool) bool {
+ d := e.depth
+ nslot := d + 2
+ log := &p.log[p.toggle]
+ if p.nlog+nslot > len(log) {
+ if !flushlog() {
+ return false
+ }
+ log = &p.log[p.toggle]
+ }
+
+ q := p.nlog
+ log[q] = e.count
+ q++
+ log[q] = uintptr(d)
+ q++
+ copy(log[q:], e.stack[:d])
+ q += d
+ p.nlog = q
+ e.count = 0
+ return true
+}
+
+// flushlog tries to flush the current log and switch to the other one.
+// flushlog is called from evict, called from add, called from the signal handler,
+// so it cannot allocate memory or block. It can try to swap logs with
+// the writing goroutine, as explained in the comment at the top of this file.
+//go:nowritebarrierrec
+func (p *cpuProfile) flushlog() bool {
+ if !atomic.Cas(&p.handoff, 0, uint32(p.nlog)) {
+ return false
+ }
+ notewakeup(&p.wait)
+
+ p.toggle = 1 - p.toggle
+ log := &p.log[p.toggle]
+ q := 0
+ if p.lost > 0 {
+ lostPC := funcPC(lostProfileData)
+ log[0] = p.lost
+ log[1] = 1
+ log[2] = lostPC
+ q = 3
+ p.lost = 0
+ }
+ p.nlog = q
+ return true
+}
+
+// addNonGo is like add, but runs on a non-Go thread.
+// It can't do anything that might need a g or an m.
+// With this entry point, we don't try to flush the log when evicting an
+// old entry. Instead, we just drop the stack trace if we're out of space.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) addNonGo(pc []uintptr) {
+ p.addWithFlushlog(pc, func() bool { return false })
+}
+
+// getprofile blocks until the next block of profiling data is available
+// and returns it as a []byte. It is called from the writing goroutine.
+func (p *cpuProfile) getprofile() []byte {
+ if p == nil {
+ return nil
+ }
+
+ if p.wholding {
+ // Release previous log to signal handling side.
+ // Loop because we are racing against SetCPUProfileRate(0).
+ for {
+ n := p.handoff
+ if n == 0 {
+ print("runtime: phase error during cpu profile handoff\n")
+ return nil
+ }
+ if n&0x80000000 != 0 {
+ p.wtoggle = 1 - p.wtoggle
+ p.wholding = false
+ p.flushing = true
+ goto Flush
+ }
+ if atomic.Cas(&p.handoff, n, 0) {
+ break
+ }
+ }
+ p.wtoggle = 1 - p.wtoggle
+ p.wholding = false
+ }
+
+ if p.flushing {
+ goto Flush
+ }
+
+ if !p.on && p.handoff == 0 {
+ return nil
+ }
+
+ // Wait for new log.
+ notetsleepg(&p.wait, -1)
+ noteclear(&p.wait)
+
+ switch n := p.handoff; {
+ case n == 0:
+ print("runtime: phase error during cpu profile wait\n")
+ return nil
+ case n == 0x80000000:
+ p.flushing = true
+ goto Flush
+ default:
+ n &^= 0x80000000
+
+ // Return new log to caller.
+ p.wholding = true
+
+ return uintptrBytes(p.log[p.wtoggle][:n])
+ }
+
+ // In flush mode.
+ // Add is no longer being called. We own the log.
+ // Also, p.handoff is non-zero, so flushlog will return false.
+ // Evict the hash table into the log and return it.
+Flush:
+ for i := range p.hash {
+ b := &p.hash[i]
+ for j := range b.entry {
+ e := &b.entry[j]
+ if e.count > 0 && !p.evict(e, p.flushlog) {
+ // Filled the log. Stop the loop and return what we've got.
+ break Flush
+ }
+ }
+ }
+
+ // Return pending log data.
+ if p.nlog > 0 {
+ // Note that we're using toggle now, not wtoggle,
+ // because we're working on the log directly.
+ n := p.nlog
+ p.nlog = 0
+ return uintptrBytes(p.log[p.toggle][:n])
+ }
+
+ // Made it through the table without finding anything to log.
+ if !p.eodSent {
+ // We may not have space to append this to the partial log buf,
+ // so we always return a new slice for the end-of-data marker.
+ p.eodSent = true
+ return uintptrBytes(eod[:])
+ }
+
+ // Finally done. Clean up and return nil.
+ p.flushing = false
+ if !atomic.Cas(&p.handoff, p.handoff, 0) {
+ print("runtime: profile flush racing with something\n")
+ }
+ return nil
+}
+
+func uintptrBytes(p []uintptr) (ret []byte) {
+ pp := (*slice)(unsafe.Pointer(&p))
+ rp := (*slice)(unsafe.Pointer(&ret))
+
+ rp.array = pp.array
+ rp.len = pp.len * int(unsafe.Sizeof(p[0]))
+ rp.cap = rp.len
+
+ return
+}
+
+// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
+// blocking until data is available. If profiling is turned off and all the profile
+// data accumulated while it was on has been returned, CPUProfile returns nil.
+// The caller must save the returned data before calling CPUProfile again.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.cpuprofile flag instead of calling
+// CPUProfile directly.
+func CPUProfile() []byte {
+ return cpuprof.getprofile()
+}
+
+//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime_pprof.runtime_cyclesPerSecond
+func runtime_pprof_runtime_cyclesPerSecond() int64 {
+ return tickspersecond()
+}
diff --git a/libgo/go/runtime/cputicks.go b/libgo/go/runtime/cputicks.go
new file mode 100644
index 0000000000..ee15aca24e
--- /dev/null
+++ b/libgo/go/runtime/cputicks.go
@@ -0,0 +1,9 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// careful: cputicks is not guaranteed to be monotonic! In particular, we have
+// noticed drift between cpus on certain os/arch combinations. See issue 8976.
+func cputicks() int64
diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go
index d7b367f941..347b820eb5 100644
--- a/libgo/go/runtime/crash_cgo_test.go
+++ b/libgo/go/runtime/crash_cgo_test.go
@@ -7,17 +7,24 @@
package runtime_test
import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "os"
"os/exec"
"runtime"
"strings"
"testing"
+ "time"
)
func TestCgoCrashHandler(t *testing.T) {
+ t.Parallel()
testCrashHandler(t, true)
}
func TestCgoSignalDeadlock(t *testing.T) {
+ t.Parallel()
if testing.Short() && runtime.GOOS == "windows" {
t.Skip("Skipping in short mode") // takes up to 64 seconds
}
@@ -29,6 +36,7 @@ func TestCgoSignalDeadlock(t *testing.T) {
}
func TestCgoTraceback(t *testing.T) {
+ t.Parallel()
got := runTestProg(t, "testprogcgo", "CgoTraceback")
want := "OK\n"
if got != want {
@@ -37,7 +45,9 @@ func TestCgoTraceback(t *testing.T) {
}
func TestCgoCallbackGC(t *testing.T) {
- if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+ t.Parallel()
+ switch runtime.GOOS {
+ case "plan9", "windows":
t.Skipf("no pthreads on %s", runtime.GOOS)
}
if testing.Short() {
@@ -46,6 +56,8 @@ func TestCgoCallbackGC(t *testing.T) {
t.Skip("see golang.org/issue/11990")
case runtime.GOOS == "linux" && runtime.GOARCH == "arm":
t.Skip("too slow for arm builders")
+ case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le"):
+ t.Skip("too slow for mips64x builders")
}
}
got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
@@ -56,6 +68,7 @@ func TestCgoCallbackGC(t *testing.T) {
}
func TestCgoExternalThreadPanic(t *testing.T) {
+ t.Parallel()
if runtime.GOOS == "plan9" {
t.Skipf("no pthreads on %s", runtime.GOOS)
}
@@ -67,6 +80,7 @@ func TestCgoExternalThreadPanic(t *testing.T) {
}
func TestCgoExternalThreadSIGPROF(t *testing.T) {
+ t.Parallel()
// issue 9456.
switch runtime.GOOS {
case "plan9", "windows":
@@ -90,22 +104,42 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
// ppc64 (issue #8912)
t.Skipf("no external linking on ppc64")
}
- got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF")
- want := "OK\n"
- if got != want {
+
+ exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
+ if err != nil {
+ t.Fatalf("exit status: %v\n%s", err, got)
+ }
+
+ if want := "OK\n"; string(got) != want {
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
func TestCgoExternalThreadSignal(t *testing.T) {
+ t.Parallel()
// issue 10139
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("no pthreads on %s", runtime.GOOS)
}
- got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
- want := "OK\n"
- if got != want {
+
+ exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
+ if err != nil {
+ t.Fatalf("exit status: %v\n%s", err, got)
+ }
+
+ want := []byte("OK\n")
+ if !bytes.Equal(got, want) {
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
@@ -123,6 +157,7 @@ func TestCgoDLLImports(t *testing.T) {
}
func TestCgoExecSignalMask(t *testing.T) {
+ t.Parallel()
// Test issue 13164.
switch runtime.GOOS {
case "windows", "plan9":
@@ -136,6 +171,7 @@ func TestCgoExecSignalMask(t *testing.T) {
}
func TestEnsureDropM(t *testing.T) {
+ t.Parallel()
// Test for issue 13881.
switch runtime.GOOS {
case "windows", "plan9":
@@ -147,3 +183,205 @@ func TestEnsureDropM(t *testing.T) {
t.Errorf("expected %q, got %v", want, got)
}
}
+
+// Test for issue 14387.
+// Test that the program that doesn't need any cgo pointer checking
+// takes about the same amount of time with it as without it.
+func TestCgoCheckBytes(t *testing.T) {
+ t.Parallel()
+ // Make sure we don't count the build time as part of the run time.
+ testenv.MustHaveGoBuild(t)
+ exe, err := buildTestProg(t, "testprogcgo")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Try it 10 times to avoid flakiness.
+ const tries = 10
+ var tot1, tot2 time.Duration
+ for i := 0; i < tries; i++ {
+ cmd := testEnv(exec.Command(exe, "CgoCheckBytes"))
+ cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
+
+ start := time.Now()
+ cmd.Run()
+ d1 := time.Since(start)
+
+ cmd = testEnv(exec.Command(exe, "CgoCheckBytes"))
+ cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
+
+ start = time.Now()
+ cmd.Run()
+ d2 := time.Since(start)
+
+ if d1*20 > d2 {
+ // The slow version (d2) was less than 20 times
+ // slower than the fast version (d1), so OK.
+ return
+ }
+
+ tot1 += d1
+ tot2 += d2
+ }
+
+ t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
+}
+
+func TestCgoPanicDeadlock(t *testing.T) {
+ t.Parallel()
+ // test issue 14432
+ got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
+ want := "panic: cgo error\n\n"
+ if !strings.HasPrefix(got, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, got)
+ }
+}
+
+func TestCgoCCodeSIGPROF(t *testing.T) {
+ t.Parallel()
+ got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
+ want := "OK\n"
+ if got != want {
+ t.Errorf("expected %q got %v", want, got)
+ }
+}
+
+func TestCgoCrashTraceback(t *testing.T) {
+ t.Parallel()
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+ got := runTestProg(t, "testprogcgo", "CrashTraceback")
+ for i := 1; i <= 3; i++ {
+ if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
+ t.Errorf("missing cgo symbolizer:%d", i)
+ }
+ }
+}
+
+func TestCgoTracebackContext(t *testing.T) {
+ t.Parallel()
+ got := runTestProg(t, "testprogcgo", "TracebackContext")
+ want := "OK\n"
+ if got != want {
+ t.Errorf("expected %q got %v", want, got)
+ }
+}
+
+func testCgoPprof(t *testing.T, buildArg, runArg string) {
+ t.Parallel()
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+ testenv.MustHaveGoRun(t)
+
+ exe, err := buildTestProg(t, "testprogcgo", buildArg)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ fn := strings.TrimSpace(string(got))
+ defer os.Remove(fn)
+
+ cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1", exe, fn))
+
+ found := false
+ for i, e := range cmd.Env {
+ if strings.HasPrefix(e, "PPROF_TMPDIR=") {
+ cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
+ found = true
+ break
+ }
+ }
+ if !found {
+ cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
+ }
+
+ top, err := cmd.CombinedOutput()
+ t.Logf("%s", top)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Contains(top, []byte("cpuHog")) {
+ t.Error("missing cpuHog in pprof output")
+ }
+}
+
+func TestCgoPprof(t *testing.T) {
+ testCgoPprof(t, "", "CgoPprof")
+}
+
+func TestCgoPprofPIE(t *testing.T) {
+ testCgoPprof(t, "-ldflags=-extldflags=-pie", "CgoPprof")
+}
+
+func TestCgoPprofThread(t *testing.T) {
+ testCgoPprof(t, "", "CgoPprofThread")
+}
+
+func TestCgoPprofThreadNoTraceback(t *testing.T) {
+ testCgoPprof(t, "", "CgoPprofThreadNoTraceback")
+}
+
+func TestRaceProf(t *testing.T) {
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ testenv.MustHaveGoRun(t)
+
+ // This test requires building various packages with -race, so
+ // it's somewhat slow.
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+
+ exe, err := buildTestProg(t, "testprogcgo", "-race")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "OK\n"
+ if string(got) != want {
+ t.Errorf("expected %q got %s", want, got)
+ }
+}
+
+func TestRaceSignal(t *testing.T) {
+ t.Parallel()
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ testenv.MustHaveGoRun(t)
+
+ // This test requires building various packages with -race, so
+ // it's somewhat slow.
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+
+ exe, err := buildTestProg(t, "testprogcgo", "-race")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
+ if err != nil {
+ t.Logf("%s\n", got)
+ t.Fatal(err)
+ }
+ want := "OK\n"
+ if string(got) != want {
+ t.Errorf("expected %q got %s", want, got)
+ }
+}
diff --git a/libgo/go/runtime/crash_nonunix_test.go b/libgo/go/runtime/crash_nonunix_test.go
new file mode 100644
index 0000000000..2ce995c069
--- /dev/null
+++ b/libgo/go/runtime/crash_nonunix_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows plan9 nacl
+
+package runtime_test
+
+import "os"
+
+// sigquit is the signal to send to kill a hanging testdata program.
+// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill.
+var sigquit = os.Kill
diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go
index 5f0e77b0dc..9ec0ae468b 100644
--- a/libgo/go/runtime/crash_test.go
+++ b/libgo/go/runtime/crash_test.go
@@ -5,6 +5,8 @@
package runtime_test
import (
+ "bytes"
+ "flag"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -13,9 +15,11 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"sync"
"testing"
+ "time"
)
var toRemove []string
@@ -65,11 +69,48 @@ func runTestProg(t *testing.T, binary, name string) string {
if err != nil {
t.Fatal(err)
}
- got, _ := testEnv(exec.Command(exe, name)).CombinedOutput()
- return string(got)
+
+ cmd := testEnv(exec.Command(exe, name))
+ var b bytes.Buffer
+ cmd.Stdout = &b
+ cmd.Stderr = &b
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("starting %s %s: %v", binary, name, err)
+ }
+
+ // If the process doesn't complete within 1 minute,
+ // assume it is hanging and kill it to get a stack trace.
+ p := cmd.Process
+ done := make(chan bool)
+ go func() {
+ scale := 1
+ // This GOARCH/GOOS test is copied from cmd/dist/test.go.
+ // TODO(iant): Have cmd/dist update the environment variable.
+ if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
+ scale = 2
+ }
+ if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
+ if sc, err := strconv.Atoi(s); err == nil {
+ scale = sc
+ }
+ }
+
+ select {
+ case <-done:
+ case <-time.After(time.Duration(scale) * time.Minute):
+ p.Signal(sigquit)
+ }
+ }()
+
+ if err := cmd.Wait(); err != nil {
+ t.Logf("%s %s exit status: %v", binary, name, err)
+ }
+ close(done)
+
+ return b.String()
}
-func buildTestProg(t *testing.T, binary string) (string, error) {
+func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) {
checkStaleRuntime(t)
testprog.Lock()
@@ -86,23 +127,26 @@ func buildTestProg(t *testing.T, binary string) (string, error) {
if testprog.target == nil {
testprog.target = make(map[string]buildexe)
}
- target, ok := testprog.target[binary]
+ name := binary
+ if len(flags) > 0 {
+ name += "_" + strings.Join(flags, "_")
+ }
+ target, ok := testprog.target[name]
if ok {
return target.exe, target.err
}
- exe := filepath.Join(testprog.dir, binary+".exe")
- cmd := exec.Command("go", "build", "-o", exe)
+ exe := filepath.Join(testprog.dir, name+".exe")
+ cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...)
cmd.Dir = "testdata/" + binary
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
- exe = ""
- target.err = fmt.Errorf("building %s: %v\n%s", binary, err, out)
- testprog.target[binary] = target
+ target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
+ testprog.target[name] = target
return "", target.err
}
target.exe = exe
- testprog.target[binary] = target
+ testprog.target[name] = target
return exe, nil
}
@@ -114,7 +158,7 @@ var (
func checkStaleRuntime(t *testing.T) {
staleRuntimeOnce.Do(func() {
// 'go run' uses the installed copy of runtime.a, which may be out of date.
- out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
+ out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
if err != nil {
staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
return
@@ -273,6 +317,52 @@ func TestGoexitInPanic(t *testing.T) {
}
}
+// Issue 14965: Runtime panics should be of type runtime.Error
+func TestRuntimePanicWithRuntimeError(t *testing.T) {
+ testCases := [...]func(){
+ 0: func() {
+ var m map[uint64]bool
+ m[1234] = true
+ },
+ 1: func() {
+ ch := make(chan struct{})
+ close(ch)
+ close(ch)
+ },
+ 2: func() {
+ var ch = make(chan struct{})
+ close(ch)
+ ch <- struct{}{}
+ },
+ 3: func() {
+ var s = make([]int, 2)
+ _ = s[2]
+ },
+ 4: func() {
+ n := -1
+ _ = make(chan bool, n)
+ },
+ 5: func() {
+ close((chan bool)(nil))
+ },
+ }
+
+ for i, fn := range testCases {
+ got := panicValue(fn)
+ if _, ok := got.(runtime.Error); !ok {
+ t.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i, got, got)
+ }
+ }
+}
+
+func panicValue(fn func()) (recovered interface{}) {
+ defer func() {
+ recovered = recover()
+ }()
+ fn()
+ return
+}
+
func TestPanicAfterGoexit(t *testing.T) {
// an uncaught panic should still work after goexit
output := runTestProg(t, "testprog", "PanicAfterGoexit")
@@ -294,9 +384,9 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
// 1. defer a function that recovers
// 2. defer a function that panics
// 3. call goexit
- // Goexit should run the #2 defer. Its panic
+ // Goexit should run the #2 defer. Its panic
// should be caught by the #1 defer, and execution
- // should resume in the caller. Like the Goexit
+ // should resume in the caller. Like the Goexit
// never happened!
defer func() {
r := recover()
@@ -311,6 +401,7 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
}
func TestNetpollDeadlock(t *testing.T) {
+ t.Parallel()
output := runTestProg(t, "testprognet", "NetpollDeadlock")
want := "done\n"
if !strings.HasSuffix(output, want) {
@@ -319,6 +410,7 @@ func TestNetpollDeadlock(t *testing.T) {
}
func TestPanicTraceback(t *testing.T) {
+ t.Parallel()
output := runTestProg(t, "testprog", "PanicTraceback")
want := "panic: hello"
if !strings.HasPrefix(output, want) {
@@ -326,7 +418,7 @@ func TestPanicTraceback(t *testing.T) {
}
// Check functions in the traceback.
- fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
+ fns := []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
for _, fn := range fns {
re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
idx := re.FindStringIndex(output)
@@ -336,3 +428,102 @@ func TestPanicTraceback(t *testing.T) {
output = output[idx[1]:]
}
}
+
+func testPanicDeadlock(t *testing.T, name string, want string) {
+ // test issue 14432
+ output := runTestProg(t, "testprog", name)
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+func TestPanicDeadlockGosched(t *testing.T) {
+ testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
+}
+
+func TestPanicDeadlockSyscall(t *testing.T) {
+ testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
+}
+
+func TestPanicLoop(t *testing.T) {
+ output := runTestProg(t, "testprog", "PanicLoop")
+ if want := "panic while printing panic value"; !strings.Contains(output, want) {
+ t.Errorf("output does not contain %q:\n%s", want, output)
+ }
+}
+
+func TestMemPprof(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+
+ exe, err := buildTestProg(t, "testprog")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "MemProf")).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ fn := strings.TrimSpace(string(got))
+ defer os.Remove(fn)
+
+ cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top", exe, fn))
+
+ found := false
+ for i, e := range cmd.Env {
+ if strings.HasPrefix(e, "PPROF_TMPDIR=") {
+ cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
+ found = true
+ break
+ }
+ }
+ if !found {
+ cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
+ }
+
+ top, err := cmd.CombinedOutput()
+ t.Logf("%s", top)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Contains(top, []byte("MemProf")) {
+ t.Error("missing MemProf in pprof output")
+ }
+}
+
+var concurrentMapTest = flag.Bool("run_concurrent_map_tests", false, "also run flaky concurrent map tests")
+
+func TestConcurrentMapWrites(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapWrites")
+ want := "fatal error: concurrent map writes"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+func TestConcurrentMapReadWrite(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapReadWrite")
+ want := "fatal error: concurrent map read and map write"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+func TestConcurrentMapIterateWrite(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapIterateWrite")
+ want := "fatal error: concurrent map iteration and map write"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
diff --git a/libgo/go/runtime/crash_unix_test.go b/libgo/go/runtime/crash_unix_test.go
index 771b303f6e..182c84b639 100644
--- a/libgo/go/runtime/crash_unix_test.go
+++ b/libgo/go/runtime/crash_unix_test.go
@@ -9,6 +9,7 @@ package runtime_test
import (
"bytes"
"internal/testenv"
+ "io"
"io/ioutil"
"os"
"os/exec"
@@ -19,6 +20,10 @@ import (
"testing"
)
+// sigquit is the signal to send to kill a hanging testdata program.
+// Send SIGQUIT to get a stack trace.
+var sigquit = syscall.SIGQUIT
+
func TestCrashDumpsAllThreads(t *testing.T) {
switch runtime.GOOS {
case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
@@ -33,6 +38,8 @@ func TestCrashDumpsAllThreads(t *testing.T) {
checkStaleRuntime(t)
+ t.Parallel()
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
@@ -43,7 +50,7 @@ func TestCrashDumpsAllThreads(t *testing.T) {
t.Fatalf("failed to create Go file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
@@ -147,12 +154,80 @@ func loop(i int, c chan bool) {
}
`
+func TestPanicSystemstack(t *testing.T) {
+ // Test that GOTRACEBACK=crash prints both the system and user
+ // stack of other threads.
+
+ // The GOTRACEBACK=crash handler takes 0.1 seconds even if
+ // it's not writing a core file and potentially much longer if
+ // it is. Skip in short mode.
+ if testing.Short() {
+ t.Skip("Skipping in short mode (GOTRACEBACK=crash is slow)")
+ }
+
+ t.Parallel()
+ cmd := exec.Command(os.Args[0], "testPanicSystemstackInternal")
+ cmd = testEnv(cmd)
+ cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ t.Fatal("creating pipe: ", err)
+ }
+ cmd.Stderr = pw
+ if err := cmd.Start(); err != nil {
+ t.Fatal("starting command: ", err)
+ }
+ defer cmd.Process.Wait()
+ defer cmd.Process.Kill()
+ if err := pw.Close(); err != nil {
+ t.Log("closing write pipe: ", err)
+ }
+ defer pr.Close()
+
+ // Wait for "x\nx\n" to indicate readiness.
+ buf := make([]byte, 4)
+ _, err = io.ReadFull(pr, buf)
+ if err != nil || string(buf) != "x\nx\n" {
+ t.Fatal("subprocess failed; output:\n", string(buf))
+ }
+
+ // Send SIGQUIT.
+ if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
+ t.Fatal("signaling subprocess: ", err)
+ }
+
+ // Get traceback.
+ tb, err := ioutil.ReadAll(pr)
+ if err != nil {
+ t.Fatal("reading traceback from pipe: ", err)
+ }
+
+ // Traceback should have two testPanicSystemstackInternal's
+ // and two blockOnSystemStackInternal's.
+ if bytes.Count(tb, []byte("testPanicSystemstackInternal")) != 2 {
+ t.Fatal("traceback missing user stack:\n", string(tb))
+ } else if bytes.Count(tb, []byte("blockOnSystemStackInternal")) != 2 {
+ t.Fatal("traceback missing system stack:\n", string(tb))
+ }
+}
+
+func init() {
+ if len(os.Args) >= 2 && os.Args[1] == "testPanicSystemstackInternal" {
+ // Get two threads running on the system stack with
+ // something recognizable in the stack trace.
+ runtime.GOMAXPROCS(2)
+ go testPanicSystemstackInternal()
+ testPanicSystemstackInternal()
+ }
+}
+
+func testPanicSystemstackInternal() {
+ runtime.BlockOnSystemStack()
+ os.Exit(1) // Should be unreachable.
+}
+
func TestSignalExitStatus(t *testing.T) {
testenv.MustHaveGoBuild(t)
- switch runtime.GOOS {
- case "netbsd", "solaris":
- t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS)
- }
exe, err := buildTestProg(t, "testprog")
if err != nil {
t.Fatal(err)
diff --git a/libgo/go/runtime/debug.go b/libgo/go/runtime/debug.go
index 0c915a2a76..a8827f20b2 100644
--- a/libgo/go/runtime/debug.go
+++ b/libgo/go/runtime/debug.go
@@ -4,24 +4,35 @@
package runtime
-// Breakpoint executes a breakpoint trap.
-func Breakpoint()
-
-// LockOSThread wires the calling goroutine to its current operating system thread.
-// Until the calling goroutine exits or calls UnlockOSThread, it will always
-// execute in that thread, and no other goroutine can.
-func LockOSThread()
-
-// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
-// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
-func UnlockOSThread()
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
// GOMAXPROCS sets the maximum number of CPUs that can be executing
-// simultaneously and returns the previous setting. If n < 1, it does not
+// simultaneously and returns the previous setting. If n < 1, it does not
// change the current setting.
// The number of logical CPUs on the local machine can be queried with NumCPU.
// This call will go away when the scheduler improves.
-func GOMAXPROCS(n int) int
+func GOMAXPROCS(n int) int {
+ if n > _MaxGomaxprocs {
+ n = _MaxGomaxprocs
+ }
+ lock(&sched.lock)
+ ret := int(gomaxprocs)
+ unlock(&sched.lock)
+ if n <= 0 || n == ret {
+ return ret
+ }
+
+ stopTheWorld("GOMAXPROCS")
+
+ // newprocs will be processed by startTheWorld
+ newprocs = int32(n)
+
+ startTheWorld()
+ return ret
+}
// NumCPU returns the number of logical CPUs usable by the current process.
//
@@ -31,150 +42,19 @@ func GOMAXPROCS(n int) int
func NumCPU() int
// NumCgoCall returns the number of cgo calls made by the current process.
-func NumCgoCall() int64
-
-// NumGoroutine returns the number of goroutines that currently exist.
-func NumGoroutine() int
-
-// MemProfileRate controls the fraction of memory allocations
-// that are recorded and reported in the memory profile.
-// The profiler aims to sample an average of
-// one allocation per MemProfileRate bytes allocated.
-//
-// To include every allocated block in the profile, set MemProfileRate to 1.
-// To turn off profiling entirely, set MemProfileRate to 0.
-//
-// The tools that process the memory profiles assume that the
-// profile rate is constant across the lifetime of the program
-// and equal to the current value. Programs that change the
-// memory profiling rate should do so just once, as early as
-// possible in the execution of the program (for example,
-// at the beginning of main).
-var MemProfileRate int = 512 * 1024
-
-// A MemProfileRecord describes the live objects allocated
-// by a particular call sequence (stack trace).
-type MemProfileRecord struct {
- AllocBytes, FreeBytes int64 // number of bytes allocated, freed
- AllocObjects, FreeObjects int64 // number of objects allocated, freed
- Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
-}
-
-// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
-func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
-
-// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
-func (r *MemProfileRecord) InUseObjects() int64 {
- return r.AllocObjects - r.FreeObjects
-}
-
-// Stack returns the stack trace associated with the record,
-// a prefix of r.Stack0.
-func (r *MemProfileRecord) Stack() []uintptr {
- for i, v := range r.Stack0 {
- if v == 0 {
- return r.Stack0[0:i]
- }
+func NumCgoCall() int64 {
+ var n int64
+ for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+ n += int64(mp.ncgocall)
}
- return r.Stack0[0:]
+ return n
}
-// MemProfile returns n, the number of records in the current memory profile.
-// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
-// If len(p) < n, MemProfile does not change p and returns n, false.
-//
-// If inuseZero is true, the profile includes allocation records
-// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
-// These are sites where memory was allocated, but it has all
-// been released back to the runtime.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.memprofile flag instead
-// of calling MemProfile directly.
-func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
-
-// A StackRecord describes a single execution stack.
-type StackRecord struct {
- Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
-}
-
-// Stack returns the stack trace associated with the record,
-// a prefix of r.Stack0.
-func (r *StackRecord) Stack() []uintptr {
- for i, v := range r.Stack0 {
- if v == 0 {
- return r.Stack0[0:i]
- }
- }
- return r.Stack0[0:]
-}
-
-// ThreadCreateProfile returns n, the number of records in the thread creation profile.
-// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
-// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package instead
-// of calling ThreadCreateProfile directly.
-func ThreadCreateProfile(p []StackRecord) (n int, ok bool)
-
-// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
-// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
-// If len(p) < n, GoroutineProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package instead
-// of calling GoroutineProfile directly.
-func GoroutineProfile(p []StackRecord) (n int, ok bool)
-
-// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
-// blocking until data is available. If profiling is turned off and all the profile
-// data accumulated while it was on has been returned, CPUProfile returns nil.
-// The caller must save the returned data before calling CPUProfile again.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.cpuprofile flag instead of calling
-// CPUProfile directly.
-func CPUProfile() []byte
-
-// SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
-// If hz <= 0, SetCPUProfileRate turns off profiling.
-// If the profiler is on, the rate cannot be changed without first turning it off.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.cpuprofile flag instead of calling
-// SetCPUProfileRate directly.
-func SetCPUProfileRate(hz int)
-
-// SetBlockProfileRate controls the fraction of goroutine blocking events
-// that are reported in the blocking profile. The profiler aims to sample
-// an average of one blocking event per rate nanoseconds spent blocked.
-//
-// To include every blocking event in the profile, pass rate = 1.
-// To turn off profiling entirely, pass rate <= 0.
-func SetBlockProfileRate(rate int)
-
-// BlockProfileRecord describes blocking events originated
-// at a particular call sequence (stack trace).
-type BlockProfileRecord struct {
- Count int64
- Cycles int64
- StackRecord
+// NumGoroutine returns the number of goroutines that currently exist.
+func NumGoroutine() int {
+ return int(gcount())
}
-// BlockProfile returns n, the number of records in the current blocking profile.
-// If len(p) >= n, BlockProfile copies the profile into p and returns n, true.
-// If len(p) < n, BlockProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.blockprofile flag instead
-// of calling BlockProfile directly.
-func BlockProfile(p []BlockProfileRecord) (n int, ok bool)
-
-// Stack formats a stack trace of the calling goroutine into buf
-// and returns the number of bytes written to buf.
-// If all is true, Stack formats stack traces of all other goroutines
-// into buf after the trace for the current goroutine.
-func Stack(buf []byte, all bool) int
-
// Get field tracking information. Only fields with a tag go:"track"
// are tracked. This function will add every such field that is
// referenced to the map. The keys in the map will be
diff --git a/libgo/go/runtime/debug/garbage.go b/libgo/go/runtime/debug/garbage.go
index 0f8a44c4c6..c82c024235 100644
--- a/libgo/go/runtime/debug/garbage.go
+++ b/libgo/go/runtime/debug/garbage.go
@@ -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.
@@ -16,17 +16,10 @@ type GCStats struct {
NumGC int64 // number of garbage collections
PauseTotal time.Duration // total pause for all collections
Pause []time.Duration // pause history, most recent first
+ PauseEnd []time.Time // pause end times history, most recent first
PauseQuantiles []time.Duration
}
-// Implemented in package runtime.
-func readGCStats(*[]time.Duration)
-func enableGC(bool) bool
-func setGCPercent(int) int
-func freeOSMemory()
-func setMaxStack(int) int
-func setMaxThreads(int) int
-
// ReadGCStats reads statistics about garbage collection into stats.
// The number of entries in the pause history is system-dependent;
// stats.Pause slice will be reused if large enough, reallocated otherwise.
@@ -38,25 +31,36 @@ func setMaxThreads(int) int
func ReadGCStats(stats *GCStats) {
// Create a buffer with space for at least two copies of the
// pause history tracked by the runtime. One will be returned
- // to the caller and the other will be used as a temporary buffer
- // for computing quantiles.
+ // to the caller and the other will be used as transfer buffer
+ // for end times history and as a temporary buffer for
+ // computing quantiles.
const maxPause = len(((*runtime.MemStats)(nil)).PauseNs)
- if cap(stats.Pause) < 2*maxPause {
- stats.Pause = make([]time.Duration, 2*maxPause)
+ if cap(stats.Pause) < 2*maxPause+3 {
+ stats.Pause = make([]time.Duration, 2*maxPause+3)
}
- // readGCStats fills in the pause history (up to maxPause entries)
- // and then three more: Unix ns time of last GC, number of GC,
- // and total pause time in nanoseconds. Here we depend on the
- // fact that time.Duration's native unit is nanoseconds, so the
- // pauses and the total pause time do not need any conversion.
+ // readGCStats fills in the pause and end times histories (up to
+ // maxPause entries) and then three more: Unix ns time of last GC,
+ // number of GC, and total pause time in nanoseconds. Here we
+ // depend on the fact that time.Duration's native unit is
+ // nanoseconds, so the pauses and the total pause time do not need
+ // any conversion.
readGCStats(&stats.Pause)
n := len(stats.Pause) - 3
stats.LastGC = time.Unix(0, int64(stats.Pause[n]))
stats.NumGC = int64(stats.Pause[n+1])
stats.PauseTotal = stats.Pause[n+2]
+ n /= 2 // buffer holds pauses and end times
stats.Pause = stats.Pause[:n]
+ if cap(stats.PauseEnd) < maxPause {
+ stats.PauseEnd = make([]time.Time, 0, maxPause)
+ }
+ stats.PauseEnd = stats.PauseEnd[:0]
+ for _, ns := range stats.Pause[n : n+n] {
+ stats.PauseEnd = append(stats.PauseEnd, time.Unix(0, int64(ns)))
+ }
+
if len(stats.PauseQuantiles) > 0 {
if n == 0 {
for i := range stats.PauseQuantiles {
@@ -67,7 +71,7 @@ func ReadGCStats(stats *GCStats) {
// See the allocation at the top of the function.
sorted := stats.Pause[n : n+n]
copy(sorted, stats.Pause)
- sort.Sort(byDuration(sorted))
+ sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] })
nq := len(stats.PauseQuantiles) - 1
for i := 0; i < nq; i++ {
stats.PauseQuantiles[i] = sorted[len(sorted)*i/nq]
@@ -77,12 +81,6 @@ func ReadGCStats(stats *GCStats) {
}
}
-type byDuration []time.Duration
-
-func (x byDuration) Len() int { return len(x) }
-func (x byDuration) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
-
// SetGCPercent sets the garbage collection target percentage:
// a collection is triggered when the ratio of freshly allocated data
// to live data remaining after the previous collection reaches this percentage.
@@ -91,9 +89,9 @@ func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
// at startup, or 100 if the variable is not set.
// A negative percentage disables garbage collection.
func SetGCPercent(percent int) int {
- old := setGCPercent(percent)
+ old := setGCPercent(int32(percent))
runtime.GC()
- return old
+ return int(old)
}
// FreeOSMemory forces a garbage collection followed by an
@@ -145,11 +143,19 @@ func SetMaxThreads(threads int) int {
// that the runtime trigger only a panic, not a crash.
// SetPanicOnFault applies only to the current goroutine.
// It returns the previous setting.
-func SetPanicOnFault(enabled bool) bool
+func SetPanicOnFault(enabled bool) bool {
+ return setPanicOnFault(enabled)
+}
// WriteHeapDump writes a description of the heap and the objects in
// it to the given file descriptor.
-// The heap dump format is defined at https://golang.org/s/go13heapdump.
+//
+// WriteHeapDump suspends the execution of all goroutines until the heap
+// dump is completely written. Thus, the file descriptor must not be
+// connected to a pipe or socket whose other end is in the same Go
+// process; instead, use a temporary file or network socket.
+//
+// The heap dump format is defined at https://golang.org/s/go15heapdump.
func WriteHeapDump(fd uintptr)
// SetTraceback sets the amount of detail printed by the runtime in
diff --git a/libgo/go/runtime/debug/garbage_test.go b/libgo/go/runtime/debug/garbage_test.go
index 21bf6eb558..04e954b1b1 100644
--- a/libgo/go/runtime/debug/garbage_test.go
+++ b/libgo/go/runtime/debug/garbage_test.go
@@ -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.
@@ -71,15 +71,24 @@ func TestReadGCStats(t *testing.T) {
t.Errorf("stats.PauseQuantiles[%d]=%d > stats.PauseQuantiles[%d]=%d", i, q[i], i+1, q[i+1])
}
}
+
+ // compare memory stats with gc stats:
+ if len(stats.PauseEnd) != n {
+ t.Fatalf("len(stats.PauseEnd) = %d, want %d", len(stats.PauseEnd), n)
+ }
+ off := (int(mstats.NumGC) + len(mstats.PauseEnd) - 1) % len(mstats.PauseEnd)
+ for i := 0; i < n; i++ {
+ dt := stats.PauseEnd[i]
+ if dt.UnixNano() != int64(mstats.PauseEnd[off]) {
+ t.Errorf("stats.PauseEnd[%d] = %d, want %d", i, dt.UnixNano(), mstats.PauseEnd[off])
+ }
+ off = (off + len(mstats.PauseEnd) - 1) % len(mstats.PauseEnd)
+ }
}
var big = make([]byte, 1<<20)
func TestFreeOSMemory(t *testing.T) {
- if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" ||
- runtime.GOOS == "nacl" {
- t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
- }
var ms1, ms2 runtime.MemStats
if big == nil {
@@ -105,3 +114,16 @@ func TestSetGCPercent(t *testing.T) {
t.Errorf("SetGCPercent(123); SetGCPercent(x) = %d, want 123", new)
}
}
+
+func TestSetMaxThreadsOvf(t *testing.T) {
+ // Verify that a big threads count will not overflow the int32
+ // maxmcount variable, causing a panic (see Issue 16076).
+ //
+ // This can only happen when ints are 64 bits, since on platforms
+ // with 32 bit ints SetMaxThreads (which takes an int parameter)
+ // cannot be given anything that will overflow an int32.
+ //
+ // Call SetMaxThreads with 1<<31, but only on 64 bit systems.
+ nt := SetMaxThreads(1 << (30 + ^uint(0)>>63))
+ SetMaxThreads(nt) // restore previous value
+}
diff --git a/libgo/go/runtime/debug/heapdump_test.go b/libgo/go/runtime/debug/heapdump_test.go
index 5761c015b8..7d5b950895 100644
--- a/libgo/go/runtime/debug/heapdump_test.go
+++ b/libgo/go/runtime/debug/heapdump_test.go
@@ -38,7 +38,7 @@ type Obj struct {
}
func objfin(x *Obj) {
- println("finalized", x)
+ //println("finalized", x)
}
func TestWriteHeapDumpFinalizers(t *testing.T) {
diff --git a/libgo/go/runtime/debug/stack_test.go b/libgo/go/runtime/debug/stack_test.go
index 0f769ee6ca..67931d17f6 100644
--- a/libgo/go/runtime/debug/stack_test.go
+++ b/libgo/go/runtime/debug/stack_test.go
@@ -50,14 +50,16 @@ func TestStack(t *testing.T) {
check(t, lines[n], line)
n++
}
- frame("stack_test.go", "\tmethod.N15_runtime_debug.T: return Stack()")
- frame("stack_test.go", "\tmethod.N15_runtime_debug.T: return t.ptrmethod()")
- frame("stack_test.go", "\tTestStack: b := T(0).method()")
- frame("testing/testing.go", "")
+ n++
+ frame("stack.go", "runtime_debug.Stack")
+ frame("stack_test.go", "ptrmethod")
+ frame("stack_test.go", "method")
+ frame("stack_test.go", "runtime_debug_test.TestStack")
+ frame("testing.go", "")
}
func check(t *testing.T, line, has string) {
- if strings.Index(line, has) < 0 {
+ if !strings.Contains(line, has) {
t.Errorf("expected %q in %q", has, line)
}
}
diff --git a/libgo/go/runtime/debug/stubs.go b/libgo/go/runtime/debug/stubs.go
new file mode 100644
index 0000000000..2cba136044
--- /dev/null
+++ b/libgo/go/runtime/debug/stubs.go
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package debug
+
+import (
+ "time"
+)
+
+// Implemented in package runtime.
+func readGCStats(*[]time.Duration)
+func freeOSMemory()
+func setMaxStack(int) int
+func setGCPercent(int32) int32
+func setPanicOnFault(bool) bool
+func setMaxThreads(int) int
diff --git a/libgo/go/runtime/defs_linux_mips64x.go b/libgo/go/runtime/defs_linux_mips64x.go
deleted file mode 100644
index bb3cd9801e..0000000000
--- a/libgo/go/runtime/defs_linux_mips64x.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// +build mips64 mips64le
-// +build linux
-
-package runtime
-
-const (
- _EINTR = 0x4
- _EAGAIN = 0xb
- _ENOMEM = 0xc
-
- _PROT_NONE = 0x0
- _PROT_READ = 0x1
- _PROT_WRITE = 0x2
- _PROT_EXEC = 0x4
-
- _MAP_ANON = 0x800
- _MAP_PRIVATE = 0x2
- _MAP_FIXED = 0x10
-
- _MADV_DONTNEED = 0x4
- _MADV_HUGEPAGE = 0xe
- _MADV_NOHUGEPAGE = 0xf
-
- _SA_RESTART = 0x10000000
- _SA_ONSTACK = 0x8000000
- _SA_SIGINFO = 0x8
-
- _SIGHUP = 0x1
- _SIGINT = 0x2
- _SIGQUIT = 0x3
- _SIGILL = 0x4
- _SIGTRAP = 0x5
- _SIGABRT = 0x6
- _SIGEMT = 0x7
- _SIGFPE = 0x8
- _SIGKILL = 0x9
- _SIGBUS = 0xa
- _SIGSEGV = 0xb
- _SIGSYS = 0xc
- _SIGPIPE = 0xd
- _SIGALRM = 0xe
- _SIGUSR1 = 0x10
- _SIGUSR2 = 0x11
- _SIGCHLD = 0x12
- _SIGPWR = 0x13
- _SIGWINCH = 0x14
- _SIGURG = 0x15
- _SIGIO = 0x16
- _SIGSTOP = 0x17
- _SIGTSTP = 0x18
- _SIGCONT = 0x19
- _SIGTTIN = 0x1a
- _SIGTTOU = 0x1b
- _SIGVTALRM = 0x1c
- _SIGPROF = 0x1d
- _SIGXCPU = 0x1e
- _SIGXFSZ = 0x1f
-
- _FPE_INTDIV = 0x1
- _FPE_INTOVF = 0x2
- _FPE_FLTDIV = 0x3
- _FPE_FLTOVF = 0x4
- _FPE_FLTUND = 0x5
- _FPE_FLTRES = 0x6
- _FPE_FLTINV = 0x7
- _FPE_FLTSUB = 0x8
-
- _BUS_ADRALN = 0x1
- _BUS_ADRERR = 0x2
- _BUS_OBJERR = 0x3
-
- _SEGV_MAPERR = 0x1
- _SEGV_ACCERR = 0x2
-
- _ITIMER_REAL = 0x0
- _ITIMER_VIRTUAL = 0x1
- _ITIMER_PROF = 0x2
-
- _EPOLLIN = 0x1
- _EPOLLOUT = 0x4
- _EPOLLERR = 0x8
- _EPOLLHUP = 0x10
- _EPOLLRDHUP = 0x2000
- _EPOLLET = 0x80000000
- _EPOLL_CLOEXEC = 0x80000
- _EPOLL_CTL_ADD = 0x1
- _EPOLL_CTL_DEL = 0x2
- _EPOLL_CTL_MOD = 0x3
-)
-
-//struct Sigset {
-// uint64 sig[1];
-//};
-//typedef uint64 Sigset;
-
-type timespec struct {
- tv_sec int64
- tv_nsec int64
-}
-
-func (ts *timespec) set_sec(x int64) {
- ts.tv_sec = x
-}
-
-func (ts *timespec) set_nsec(x int32) {
- ts.tv_nsec = int64(x)
-}
-
-type timeval struct {
- tv_sec int64
- tv_usec int64
-}
-
-func (tv *timeval) set_usec(x int32) {
- tv.tv_usec = int64(x)
-}
-
-type sigactiont struct {
- sa_flags uint32
- sa_handler uintptr
- sa_mask [2]uint64
- // linux header does not have sa_restorer field,
- // but it is used in setsig(). it is no harm to put it here
- sa_restorer uintptr
-}
-
-type siginfo struct {
- si_signo int32
- si_code int32
- si_errno int32
- __pad0 [1]int32
- // below here is a union; si_addr is the only field we use
- si_addr uint64
-}
-
-type itimerval struct {
- it_interval timeval
- it_value timeval
-}
-
-type epollevent struct {
- events uint32
- pad_cgo_0 [4]byte
- data [8]byte // unaligned uintptr
-}
-
-const (
- _O_RDONLY = 0x0
- _O_CLOEXEC = 0x80000
- _SA_RESTORER = 0
-)
-
-type sigaltstackt struct {
- ss_sp *byte
- ss_size uintptr
- ss_flags int32
-}
-
-type sigcontext struct {
- sc_regs [32]uint64
- sc_fpregs [32]uint64
- sc_mdhi uint64
- sc_hi1 uint64
- sc_hi2 uint64
- sc_hi3 uint64
- sc_mdlo uint64
- sc_lo1 uint64
- sc_lo2 uint64
- sc_lo3 uint64
- sc_pc uint64
- sc_fpc_csr uint32
- sc_used_math uint32
- sc_dsp uint32
- sc_reserved uint32
-}
-
-type ucontext struct {
- uc_flags uint64
- uc_link *ucontext
- uc_stack sigaltstackt
- uc_mcontext sigcontext
- uc_sigmask uint64
-}
diff --git a/libgo/go/runtime/env_posix.go b/libgo/go/runtime/env_posix.go
new file mode 100644
index 0000000000..e076edb85d
--- /dev/null
+++ b/libgo/go/runtime/env_posix.go
@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package runtime
+
+func gogetenv(key string) string {
+ env := environ()
+ if env == nil {
+ throw("getenv before env init")
+ }
+ for _, s := range environ() {
+ if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
+ return s[len(key)+1:]
+ }
+ }
+ return ""
+}
diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go
index c4621b6f85..9cf2230ab3 100644
--- a/libgo/go/runtime/error.go
+++ b/libgo/go/runtime/error.go
@@ -4,6 +4,8 @@
package runtime
+import "unsafe"
+
// The Error interface identifies a run time error.
type Error interface {
error
@@ -101,21 +103,14 @@ func (e errorString) Error() string {
return "runtime error: " + string(e)
}
-// For calling from C.
-func NewErrorString(s string, ret *interface{}) {
- *ret = errorString(s)
-}
-
// An errorCString represents a runtime error described by a single C string.
// Not "type errorCString uintptr" because of http://golang.org/issue/7084.
type errorCString struct{ cstr uintptr }
func (e errorCString) RuntimeError() {}
-func cstringToGo(uintptr) string
-
func (e errorCString) Error() string {
- return "runtime error: " + cstringToGo(e.cstr)
+ return "runtime error: " + gostringnocopy((*byte)(unsafe.Pointer(e.cstr)))
}
// For calling from C.
@@ -123,17 +118,31 @@ func NewErrorCString(s uintptr, ret *interface{}) {
*ret = errorCString{s}
}
+// plainError represents a runtime error described a string without
+// the prefix "runtime error: " after invoking errorString.Error().
+// See Issue #14965.
+type plainError string
+
+func (e plainError) RuntimeError() {}
+
+func (e plainError) Error() string {
+ return string(e)
+}
+
type stringer interface {
String() string
}
-func typestring(interface{}) string
+func typestring(x interface{}) string {
+ e := efaceOf(&x)
+ return *e._type.string
+}
// For calling from C.
// Prints an argument passed to panic.
// There's room for arbitrary complexity here, but we keep it
// simple and handle just a few important cases: int, string, and Stringer.
-func Printany(i interface{}) {
+func printany(i interface{}) {
switch v := i.(type) {
case nil:
print("nil")
@@ -152,5 +161,5 @@ func Printany(i interface{}) {
// called from generated code
func panicwrap(pkg, typ, meth string) {
- panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+ panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
}
diff --git a/libgo/go/runtime/export_arm_test.go b/libgo/go/runtime/export_arm_test.go
index 446d26465c..b8a89fc0d2 100644
--- a/libgo/go/runtime/export_arm_test.go
+++ b/libgo/go/runtime/export_arm_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/export_linux_test.go b/libgo/go/runtime/export_linux_test.go
index 4e76600e20..183a6eeee2 100644
--- a/libgo/go/runtime/export_linux_test.go
+++ b/libgo/go/runtime/export_linux_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/export_mmap_test.go b/libgo/go/runtime/export_mmap_test.go
index 07b0a56e09..6e05bb9fbb 100644
--- a/libgo/go/runtime/export_mmap_test.go
+++ b/libgo/go/runtime/export_mmap_test.go
@@ -1,15 +1,20 @@
-// Copyright 2016 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.
-// +build ignore
-
// Export guts for testing.
package runtime
var Mmap = mmap
+var Munmap = munmap
+var Errno = errno
const ENOMEM = _ENOMEM
const MAP_ANON = _MAP_ANON
const MAP_PRIVATE = _MAP_PRIVATE
+const MAP_FIXED = _MAP_FIXED
+
+func GetPhysPageSize() uintptr {
+ return physPageSize
+}
diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go
index fd328a1d36..cc4b188b60 100644
--- a/libgo/go/runtime/export_test.go
+++ b/libgo/go/runtime/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -7,6 +7,8 @@
package runtime
import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
"unsafe"
)
@@ -21,66 +23,130 @@ import (
//var F64toint = f64toint
//var Sqrt = sqrt
-func entersyscall(int32)
-func exitsyscall(int32)
-func golockedOSThread() bool
-
var Entersyscall = entersyscall
var Exitsyscall = exitsyscall
-var LockedOSThread = golockedOSThread
+var LockedOSThread = lockedOSThread
// var Xadduintptr = xadduintptr
// var FuncPC = funcPC
+var Atoi = atoi
+var Atoi32 = atoi32
+
type LFNode struct {
Next uint64
Pushcnt uintptr
}
-func lfstackpush_go(head *uint64, node *LFNode)
-func lfstackpop_go(head *uint64) *LFNode
-
-var LFStackPush = lfstackpush_go
-var LFStackPop = lfstackpop_go
-
-type ParFor struct {
- body func(*ParFor, uint32)
- done uint32
- Nthr uint32
- thrseq uint32
- Cnt uint32
- wait bool
+func LFStackPush(head *uint64, node *LFNode) {
+ lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
}
-func newParFor(nthrmax uint32) *ParFor
-func parForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32))
-func parForDo(desc *ParFor)
-func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr)
-
-var NewParFor = newParFor
-var ParForSetup = parForSetup
-var ParForDo = parForDo
-
-func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
- begin, end := parForIters(desc, uintptr(tid))
- return uint32(begin), uint32(end)
+func LFStackPop(head *uint64) *LFNode {
+ return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
}
func GCMask(x interface{}) (ret []byte) {
return nil
}
-//func testSchedLocalQueue()
-//func testSchedLocalQueueSteal()
-//
-//func RunSchedLocalQueueTest() {
-// testSchedLocalQueue()
-//}
-//
-//func RunSchedLocalQueueStealTest() {
-// testSchedLocalQueueSteal()
-//}
+func RunSchedLocalQueueTest() {
+ _p_ := new(p)
+ gs := make([]g, len(_p_.runq))
+ for i := 0; i < len(_p_.runq); i++ {
+ if g, _ := runqget(_p_); g != nil {
+ throw("runq is not empty initially")
+ }
+ for j := 0; j < i; j++ {
+ runqput(_p_, &gs[i], false)
+ }
+ for j := 0; j < i; j++ {
+ if g, _ := runqget(_p_); g != &gs[i] {
+ print("bad element at iter ", i, "/", j, "\n")
+ throw("bad element")
+ }
+ }
+ if g, _ := runqget(_p_); g != nil {
+ throw("runq is not empty afterwards")
+ }
+ }
+}
+
+func RunSchedLocalQueueStealTest() {
+ p1 := new(p)
+ p2 := new(p)
+ gs := make([]g, len(p1.runq))
+ for i := 0; i < len(p1.runq); i++ {
+ for j := 0; j < i; j++ {
+ gs[j].sig = 0
+ runqput(p1, &gs[j], false)
+ }
+ gp := runqsteal(p2, p1, true)
+ s := 0
+ if gp != nil {
+ s++
+ gp.sig++
+ }
+ for {
+ gp, _ = runqget(p2)
+ if gp == nil {
+ break
+ }
+ s++
+ gp.sig++
+ }
+ for {
+ gp, _ = runqget(p1)
+ if gp == nil {
+ break
+ }
+ gp.sig++
+ }
+ for j := 0; j < i; j++ {
+ if gs[j].sig != 1 {
+ print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
+ throw("bad element")
+ }
+ }
+ if s != i/2 && s != i/2+1 {
+ print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
+ throw("bad steal")
+ }
+ }
+}
+
+func RunSchedLocalQueueEmptyTest(iters int) {
+ // Test that runq is not spuriously reported as empty.
+ // Runq emptiness affects scheduling decisions and spurious emptiness
+ // can lead to underutilization (both runnable Gs and idle Ps coexist
+ // for arbitrary long time).
+ done := make(chan bool, 1)
+ p := new(p)
+ gs := make([]g, 2)
+ ready := new(uint32)
+ for i := 0; i < iters; i++ {
+ *ready = 0
+ next0 := (i & 1) == 0
+ next1 := (i & 2) == 0
+ runqput(p, &gs[0], next0)
+ go func() {
+ for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
+ }
+ if runqempty(p) {
+ println("next:", next0, next1)
+ throw("queue is empty")
+ }
+ done <- true
+ }()
+ for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
+ }
+ runqput(p, &gs[1], next1)
+ runqget(p)
+ <-done
+ runqget(p)
+ }
+}
//var StringHash = stringHash
//var BytesHash = bytesHash
@@ -88,9 +154,13 @@ func GCMask(x interface{}) (ret []byte) {
//var Int64Hash = int64Hash
//var EfaceHash = efaceHash
//var IfaceHash = ifaceHash
-//var MemclrBytes = memclrBytes
-// var HashLoad = &hashLoad
+func MemclrBytes(b []byte) {
+ s := (*slice)(unsafe.Pointer(&b))
+ memclrNoHeapPointers(s.array, uintptr(s.len))
+}
+
+var HashLoad = &hashLoad
// entry point for testing
//func GostringW(w []uint16) (s string) {
@@ -98,44 +168,15 @@ func GCMask(x interface{}) (ret []byte) {
// return
//}
-//var Gostringnocopy = gostringnocopy
-//var Maxstring = &maxstring
+type Uintreg sys.Uintreg
-//type Uintreg uintreg
+var Open = open
+var Close = closefd
+var Read = read
+var Write = write
-//extern __go_open
-func open(path *byte, mode int32, perm int32) int32
-
-func Open(path *byte, mode int32, perm int32) int32 {
- return open(path, mode, perm)
-}
-
-//extern close
-func close(int32) int32
-
-func Close(fd int32) int32 {
- return close(fd)
-}
-
-//extern read
-func read(fd int32, buf unsafe.Pointer, size int32) int32
-
-func Read(fd int32, buf unsafe.Pointer, size int32) int32 {
- return read(fd, buf, size)
-}
-
-//extern write
-func write(fd int32, buf unsafe.Pointer, size int32) int32
-
-func Write(fd uintptr, buf unsafe.Pointer, size int32) int32 {
- return write(int32(fd), buf, size)
-}
-
-func envs() []string
-func setenvs([]string)
-
-var Envs = envs
-var SetEnvs = setenvs
+func Envs() []string { return envs }
+func SetEnvs(e []string) { envs = e }
//var BigEndian = sys.BigEndian
@@ -171,13 +212,47 @@ func BenchSetType(n int, x interface{}) {
const PtrSize = sys.PtrSize
-var TestingAssertE2I2GC = &testingAssertE2I2GC
-var TestingAssertE2T2GC = &testingAssertE2T2GC
-
var ForceGCPeriod = &forcegcperiod
*/
// SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
// the "environment" traceback level, so later calls to
// debug.SetTraceback (e.g., from testing timeouts) can't lower it.
-func SetTracebackEnv(level string)
+func SetTracebackEnv(level string) {
+ setTraceback(level)
+ traceback_env = traceback_cache
+}
+
+/*
+var ReadUnaligned32 = readUnaligned32
+var ReadUnaligned64 = readUnaligned64
+
+func CountPagesInUse() (pagesInUse, counted uintptr) {
+ stopTheWorld("CountPagesInUse")
+
+ pagesInUse = uintptr(mheap_.pagesInUse)
+
+ for _, s := range mheap_.allspans {
+ if s.state == mSpanInUse {
+ counted += s.npages
+ }
+ }
+
+ startTheWorld()
+
+ return
+}
+*/
+
+// BlockOnSystemStack switches to the system stack, prints "x\n" to
+// stderr, and blocks in a stack containing
+// "runtime.blockOnSystemStackInternal".
+func BlockOnSystemStack() {
+ systemstack(blockOnSystemStackInternal)
+}
+
+func blockOnSystemStackInternal() {
+ print("x\n")
+ lock(&deadlock)
+ lock(&deadlock)
+}
diff --git a/libgo/go/runtime/export_windows_test.go b/libgo/go/runtime/export_windows_test.go
index 7b269ecccb..536b398fd7 100644
--- a/libgo/go/runtime/export_windows_test.go
+++ b/libgo/go/runtime/export_windows_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,7 +8,11 @@ package runtime
import "unsafe"
-var TestingWER = &testingWER
+var (
+ TestingWER = &testingWER
+ OsYield = osyield
+ TimeBeginPeriodRetValue = &timeBeginPeriodRetValue
+)
func NumberOfProcessors() int32 {
var info systeminfo
diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go
index eca54a7514..5aa76ac8e2 100644
--- a/libgo/go/runtime/extern.go
+++ b/libgo/go/runtime/extern.go
@@ -57,6 +57,11 @@ It is a comma-separated list of name=val pairs setting these named variables:
gcstackbarrierall: setting gcstackbarrierall=1 installs stack barriers
in every stack frame, rather than in exponentially-spaced frames.
+ gcrescanstacks: setting gcrescanstacks=1 enables stack
+ re-scanning during the STW mark termination phase. This is
+ helpful for debugging if objects are being prematurely
+ garbage collected.
+
gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
also disables concurrent sweeping after the garbage collection finishes.
@@ -82,6 +87,21 @@ It is a comma-separated list of name=val pairs setting these named variables:
If the line ends with "(forced)", this GC was forced by a
runtime.GC() call and all phases are STW.
+ Setting gctrace to any value > 0 also causes the garbage collector
+ to emit a summary when memory is released back to the system.
+ This process of returning memory to the system is called scavenging.
+ The format of this summary is subject to change.
+ Currently it is:
+ scvg#: # MB released printed only if non-zero
+ scvg#: inuse: # idle: # sys: # released: # consumed: # (MB)
+ where the fields are as follows:
+ scvg# the scavenge cycle number, incremented at each scavenge
+ inuse: # MB used or partially used spans
+ idle: # MB spans pending scavenging
+ sys: # MB mapped from the system
+ released: # MB released to the system
+ consumed: # MB allocated from the system
+
memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
When set to 0 memory profiling is disabled. Refer to the description of
MemProfileRate for the default value.
@@ -142,79 +162,41 @@ of the run-time system.
*/
package runtime
+import "runtime/internal/sys"
+
// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()
-// Goexit terminates the goroutine that calls it. No other goroutine is affected.
-// Goexit runs all deferred calls before terminating the goroutine.
-//
-// Calling Goexit from the main goroutine terminates that goroutine
-// without func main returning. Since func main has not returned,
-// the program continues execution of other goroutines.
-// If all other goroutines exit, the program crashes.
-func Goexit()
-
// Caller reports file and line number information about function invocations on
-// the calling goroutine's stack. The argument skip is the number of stack frames
+// the calling goroutine's stack. The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller. (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call. The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
-// Callers fills the slice pc with the program counters of function invocations
-// on the calling goroutine's stack. The argument skip is the number of stack frames
+// Callers fills the slice pc with the return program counters of function invocations
+// on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int
-type Func struct {
- opaque struct{} // unexported field to disallow conversions
-}
-
-// FuncForPC returns a *Func describing the function that contains the
-// given program counter address, or else nil.
-func FuncForPC(pc uintptr) *Func
-
-// Name returns the name of the function.
-func (f *Func) Name() string {
- return funcname_go(f)
-}
-
-// Entry returns the entry address of the function.
-func (f *Func) Entry() uintptr {
- return funcentry_go(f)
-}
-
-// FileLine returns the file name and line number of the
-// source code corresponding to the program counter pc.
-// The result will not be accurate if pc is not a program
-// counter within f.
-func (f *Func) FileLine(pc uintptr) (file string, line int) {
- return funcline_go(f, pc)
-}
-
-// implemented in symtab.c
-func funcline_go(*Func, uintptr) (string, int)
-func funcname_go(*Func) string
-func funcentry_go(*Func) uintptr
-
-// SetFinalizer sets the finalizer associated with x to f.
-// When the garbage collector finds an unreachable block
+// SetFinalizer sets the finalizer associated with obj to the provided
+// finalizer function. When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
-// f(x) in a separate goroutine. This makes x reachable again, but
-// now without an associated finalizer. Assuming that SetFinalizer
+// finalizer(obj) in a separate goroutine. This makes obj reachable again,
+// but now without an associated finalizer. Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
-// that x is unreachable, it will free x.
+// that obj is unreachable, it will free obj.
//
-// SetFinalizer(x, nil) clears any finalizer associated with x.
+// SetFinalizer(obj, nil) clears any finalizer associated with obj.
//
-// The argument x must be a pointer to an object allocated by
+// The argument obj must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
-// The argument f must be a function that takes a single argument
-// to which x's type can be assigned, and can have arbitrary ignored return
+// The argument finalizer must be a function that takes a single argument
+// to which obj's type can be assigned, and can have arbitrary ignored return
// values. If either of these is not true, SetFinalizer aborts the
// program.
//
@@ -226,8 +208,8 @@ func funcentry_go(*Func) uintptr
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
-// The finalizer for x is scheduled to run at some arbitrary time after
-// x becomes unreachable.
+// The finalizer for obj is scheduled to run at some arbitrary time after
+// obj becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
@@ -237,41 +219,82 @@ func funcentry_go(*Func) uintptr
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
-// It is not guaranteed that a finalizer will run if the size of *x is
+// It is not guaranteed that a finalizer will run if the size of *obj is
// zero bytes.
//
+// It is not guaranteed that a finalizer will run for objects allocated
+// 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.
-func SetFinalizer(x, f interface{})
+func SetFinalizer(obj interface{}, finalizer interface{})
-func getgoroot() string
+// 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{})
// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
- s := getgoroot()
+ s := gogetenv("GOROOT")
if s != "" {
return s
}
- return defaultGoroot
+ return sys.DefaultGoroot
}
// Version returns the Go tree's version string.
// It is either the commit hash and date at the time of the build or,
// when possible, a release tag like "go1.3".
func Version() string {
- return theVersion
+ return sys.TheVersion
}
// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
-const GOOS string = theGoos
+const GOOS string = sys.GOOS
// GOARCH is the running program's architecture target:
-// 386, amd64, arm, arm64, ppc64, ppc64le.
-const GOARCH string = theGoarch
+// 386, amd64, arm, or s390x.
+const GOARCH string = sys.GOARCH
// GCCGOTOOLDIR is the Tool Dir for the gccgo build
-const GCCGOTOOLDIR string = theGccgoToolDir
+const GCCGOTOOLDIR string = sys.GccgoToolDir
diff --git a/libgo/go/runtime/fastlog2.go b/libgo/go/runtime/fastlog2.go
index b22e8259ad..6fbe572f4a 100644
--- a/libgo/go/runtime/fastlog2.go
+++ b/libgo/go/runtime/fastlog2.go
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
package runtime
import "unsafe"
// fastlog2 implements a fast approximation to the base 2 log of a
// float64. This is used to compute a geometric distribution for heap
-// sampling, without introducing dependences into package math. This
+// sampling, without introducing dependencies into package math. This
// uses a very rough approximation using the float64 exponent and the
// first 25 bits of the mantissa. The top 5 bits of the mantissa are
// used to load limits from a table of constants and the rest are used
@@ -29,5 +31,5 @@ func fastlog2(x float64) float64 {
}
// float64bits returns the IEEE 754 binary representation of f.
-// Taken from math.Float64bits to avoid dependences into package math.
+// Taken from math.Float64bits to avoid dependencies into package math.
func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
diff --git a/libgo/go/runtime/fastlog2_test.go b/libgo/go/runtime/fastlog2_test.go
index 8f92dc6694..6e9fcd4d45 100644
--- a/libgo/go/runtime/fastlog2_test.go
+++ b/libgo/go/runtime/fastlog2_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/fastlog2table.go b/libgo/go/runtime/fastlog2table.go
index c36d5835f6..47ae5e81fb 100644
--- a/libgo/go/runtime/fastlog2table.go
+++ b/libgo/go/runtime/fastlog2table.go
@@ -2,6 +2,8 @@
// Run go generate from src/runtime to update.
// See mkfastlog2table.go for comments.
+// +build ignore
+
package runtime
const fastlogNumBits = 5
diff --git a/libgo/go/runtime/ffi.go b/libgo/go/runtime/ffi.go
new file mode 100644
index 0000000000..164e1770ea
--- /dev/null
+++ b/libgo/go/runtime/ffi.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Only build this file if libffi is supported.
+
+// +build libffi
+
+package runtime
+
+import "unsafe"
+
+// This file contains the code that converts a Go type to an FFI type.
+// This has to be written in Go because it allocates memory in the Go heap.
+
+// C functions to return pointers to libffi variables.
+
+func ffi_type_pointer() *__ffi_type
+func ffi_type_sint8() *__ffi_type
+func ffi_type_sint16() *__ffi_type
+func ffi_type_sint32() *__ffi_type
+func ffi_type_sint64() *__ffi_type
+func ffi_type_uint8() *__ffi_type
+func ffi_type_uint16() *__ffi_type
+func ffi_type_uint32() *__ffi_type
+func ffi_type_uint64() *__ffi_type
+func ffi_type_float() *__ffi_type
+func ffi_type_double() *__ffi_type
+func ffi_supports_complex() bool
+func ffi_type_complex_float() *__ffi_type
+func ffi_type_complex_double() *__ffi_type
+func ffi_type_void() *__ffi_type
+
+// C functions defined in libffi.
+
+//extern ffi_prep_cif
+func ffi_prep_cif(*_ffi_cif, _ffi_abi, uint32, *__ffi_type, **__ffi_type) _ffi_status
+
+// ffiFuncToCIF is called from C code.
+//go:linkname ffiFuncToCIF runtime.ffiFuncToCIF
+
+// ffiFuncToCIF builds an _ffi_cif struct for function described by ft.
+func ffiFuncToCIF(ft *functype, isInterface bool, isMethod bool, cif *_ffi_cif) {
+ nparams := len(ft.in)
+ nargs := nparams
+ if isInterface {
+ nargs++
+ }
+ args := make([]*__ffi_type, nargs)
+ i := 0
+ off := 0
+ if isInterface {
+ args[0] = ffi_type_pointer()
+ off = 1
+ } else if isMethod {
+ args[0] = ffi_type_pointer()
+ i = 1
+ }
+ for ; i < nparams; i++ {
+ args[i+off] = typeToFFI(ft.in[i])
+ }
+
+ rettype := funcReturnFFI(ft)
+
+ var pargs **__ffi_type
+ if len(args) > 0 {
+ pargs = &args[0]
+ }
+ status := ffi_prep_cif(cif, _FFI_DEFAULT_ABI, uint32(nargs), rettype, pargs)
+ if status != _FFI_OK {
+ throw("ffi_prep_cif failed")
+ }
+}
+
+// funcReturnFFI returns the FFI definition of the return type of ft.
+func funcReturnFFI(ft *functype) *__ffi_type {
+ c := len(ft.out)
+ if c == 0 {
+ return ffi_type_void()
+ }
+
+ // Compile a function that returns a zero-sized value as
+ // though it returns void. This works around a problem in
+ // libffi: it can't represent a zero-sized value.
+ var size uintptr
+ for _, v := range ft.out {
+ size += v.size
+ }
+ if size == 0 {
+ return ffi_type_void()
+ }
+
+ if c == 1 {
+ return typeToFFI(ft.out[0])
+ }
+
+ elements := make([]*__ffi_type, c+1)
+ for i, v := range ft.out {
+ elements[i] = typeToFFI(v)
+ }
+ elements[c] = nil
+
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// typeToFFI returns the __ffi_type for a Go type.
+func typeToFFI(typ *_type) *__ffi_type {
+ switch typ.kind & kindMask {
+ case kindBool:
+ switch unsafe.Sizeof(false) {
+ case 1:
+ return ffi_type_uint8()
+ case 4:
+ return ffi_type_uint32()
+ default:
+ throw("bad bool size")
+ return nil
+ }
+ case kindInt:
+ return intToFFI()
+ case kindInt8:
+ return ffi_type_sint8()
+ case kindInt16:
+ return ffi_type_sint16()
+ case kindInt32:
+ return ffi_type_sint32()
+ case kindInt64:
+ return ffi_type_sint64()
+ case kindUint:
+ switch unsafe.Sizeof(uint(0)) {
+ case 4:
+ return ffi_type_uint32()
+ case 8:
+ return ffi_type_uint64()
+ default:
+ throw("bad uint size")
+ return nil
+ }
+ case kindUint8:
+ return ffi_type_uint8()
+ case kindUint16:
+ return ffi_type_uint16()
+ case kindUint32:
+ return ffi_type_uint32()
+ case kindUint64:
+ return ffi_type_uint64()
+ case kindUintptr:
+ switch unsafe.Sizeof(uintptr(0)) {
+ case 4:
+ return ffi_type_uint32()
+ case 8:
+ return ffi_type_uint64()
+ default:
+ throw("bad uinptr size")
+ return nil
+ }
+ case kindFloat32:
+ return ffi_type_float()
+ case kindFloat64:
+ return ffi_type_double()
+ case kindComplex64:
+ if ffi_supports_complex() {
+ return ffi_type_complex_float()
+ } else {
+ return complexToFFI(ffi_type_float())
+ }
+ case kindComplex128:
+ if ffi_supports_complex() {
+ return ffi_type_complex_double()
+ } else {
+ return complexToFFI(ffi_type_double())
+ }
+ case kindArray:
+ return arrayToFFI((*arraytype)(unsafe.Pointer(typ)))
+ case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer:
+ // These types are always simple pointers, and for FFI
+ // purposes nothing else matters.
+ return ffi_type_pointer()
+ case kindInterface:
+ return interfaceToFFI()
+ case kindSlice:
+ return sliceToFFI((*slicetype)(unsafe.Pointer(typ)))
+ case kindString:
+ return stringToFFI()
+ case kindStruct:
+ return structToFFI((*structtype)(unsafe.Pointer(typ)))
+ default:
+ throw("unknown type kind")
+ return nil
+ }
+}
+
+// interfaceToFFI returns an ffi_type for a Go interface type.
+// This is used for both empty and non-empty interface types.
+func interfaceToFFI() *__ffi_type {
+ elements := make([]*__ffi_type, 3)
+ elements[0] = ffi_type_pointer()
+ elements[1] = elements[0]
+ elements[2] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// stringToFFI returns an ffi_type for a Go string type.
+func stringToFFI() *__ffi_type {
+ elements := make([]*__ffi_type, 3)
+ elements[0] = ffi_type_pointer()
+ elements[1] = intToFFI()
+ elements[2] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// structToFFI returns an ffi_type for a Go struct type.
+func structToFFI(typ *structtype) *__ffi_type {
+ c := len(typ.fields)
+ if c == 0 {
+ return emptyStructToFFI()
+ }
+
+ fields := make([]*__ffi_type, c+1)
+ for i, v := range typ.fields {
+ fields[i] = typeToFFI(v.typ)
+ }
+ fields[c] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &fields[0],
+ }
+}
+
+// sliceToFFI returns an ffi_type for a Go slice type.
+func sliceToFFI(typ *slicetype) *__ffi_type {
+ elements := make([]*__ffi_type, 4)
+ elements[0] = ffi_type_pointer()
+ elements[1] = intToFFI()
+ elements[2] = elements[1]
+ elements[3] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// complexToFFI returns an ffi_type for a Go complex type.
+// This is only used if libffi does not support complex types internally
+// for this target.
+func complexToFFI(ffiFloatType *__ffi_type) *__ffi_type {
+ elements := make([]*__ffi_type, 3)
+ elements[0] = ffiFloatType
+ elements[1] = ffiFloatType
+ elements[2] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// arrayToFFI returns an ffi_type for a Go array type.
+func arrayToFFI(typ *arraytype) *__ffi_type {
+ if typ.len == 0 {
+ return emptyStructToFFI()
+ }
+ elements := make([]*__ffi_type, typ.len+1)
+ et := typeToFFI(typ.elem)
+ for i := uintptr(0); i < typ.len; i++ {
+ elements[i] = et
+ }
+ elements[typ.len] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+// intToFFI returns an ffi_type for the Go int type.
+func intToFFI() *__ffi_type {
+ switch unsafe.Sizeof(0) {
+ case 4:
+ return ffi_type_sint32()
+ case 8:
+ return ffi_type_sint64()
+ default:
+ throw("bad int size")
+ return nil
+ }
+}
+
+// emptyStructToFFI returns an ffi_type for an empty struct.
+// The libffi library won't accept a struct with no fields.
+func emptyStructToFFI() *__ffi_type {
+ elements := make([]*__ffi_type, 2)
+ elements[0] = ffi_type_void()
+ elements[1] = nil
+ return &__ffi_type{
+ _type: _FFI_TYPE_STRUCT,
+ elements: &elements[0],
+ }
+}
+
+//go:linkname makeCIF reflect.makeCIF
+
+// makeCIF is used by the reflect package to allocate a CIF.
+func makeCIF(ft *functype) *_ffi_cif {
+ cif := new(_ffi_cif)
+ ffiFuncToCIF(ft, false, false, cif)
+ return cif
+}
diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go
index 71d46561e0..2a6acf0836 100644
--- a/libgo/go/runtime/gc_test.go
+++ b/libgo/go/runtime/gc_test.go
@@ -400,39 +400,6 @@ func TestPrintGC(t *testing.T) {
close(done)
}
-/*
-
-// The implicit y, ok := x.(error) for the case error
-// in testTypeSwitch used to not initialize the result y
-// before passing &y to assertE2I2GC.
-// Catch this by making assertE2I2 call runtime.GC,
-// which will force a stack scan and failure if there are
-// bad pointers, and then fill the stack with bad pointers
-// and run the type switch.
-func TestAssertE2I2Liveness(t *testing.T) {
- // Note that this flag is defined in export_test.go
- // and is not available to ordinary imports of runtime.
- *runtime.TestingAssertE2I2GC = true
- defer func() {
- *runtime.TestingAssertE2I2GC = false
- }()
-
- poisonStack()
- testTypeSwitch(io.EOF)
- poisonStack()
- testAssert(io.EOF)
- poisonStack()
- testAssertVar(io.EOF)
-}
-
-func poisonStack() uintptr {
- var x [1000]uintptr
- for i := range x {
- x[i] = 0xff
- }
- return x[123]
-}
-
func testTypeSwitch(x interface{}) error {
switch y := x.(type) {
case nil:
@@ -458,16 +425,6 @@ func testAssertVar(x interface{}) error {
return nil
}
-func TestAssertE2T2Liveness(t *testing.T) {
- *runtime.TestingAssertE2T2GC = true
- defer func() {
- *runtime.TestingAssertE2T2GC = false
- }()
-
- poisonStack()
- testIfaceEqual(io.EOF)
-}
-
var a bool
//go:noinline
@@ -477,4 +434,23 @@ func testIfaceEqual(x interface{}) {
}
}
+/*
+
+func TestPageAccounting(t *testing.T) {
+ // Grow the heap in small increments. This used to drop the
+ // pages-in-use count below zero because of a rounding
+ // mismatch (golang.org/issue/15022).
+ const blockSize = 64 << 10
+ blocks := make([]*[blockSize]byte, (64<<20)/blockSize)
+ for i := range blocks {
+ blocks[i] = new([blockSize]byte)
+ }
+
+ // Check that the running page count matches reality.
+ pagesInUse, counted := runtime.CountPagesInUse()
+ if pagesInUse != counted {
+ t.Fatalf("mheap_.pagesInUse is %d, but direct count is %d", pagesInUse, counted)
+ }
+}
+
*/
diff --git a/libgo/go/runtime/gcinfo_test.go b/libgo/go/runtime/gcinfo_test.go
index d3262a656c..4ac67dc4be 100644
--- a/libgo/go/runtime/gcinfo_test.go
+++ b/libgo/go/runtime/gcinfo_test.go
@@ -45,14 +45,14 @@ func TestGCInfo(t *testing.T) {
func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
mask := runtime.GCMask(p)
- if bytes.Compare(mask, mask0) != 0 {
+ if !bytes.Equal(mask, mask0) {
t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
return
}
}
func padDead(mask []byte) []byte {
- // Because the dead bit isn't encoded until the third word,
+ // Because the dead bit isn't encoded in the second word,
// and because on 32-bit systems a one-word allocation
// uses a two-word block, the pointer info for a one-word
// object needs to be expanded to include an extra scalar
@@ -67,6 +67,9 @@ func trimDead(mask []byte) []byte {
for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
mask = mask[:len(mask)-1]
}
+ if len(mask) == 2 && mask[0] == typeScalar && mask[1] == typeScalar {
+ mask = mask[:0]
+ }
return mask
}
@@ -122,7 +125,7 @@ type BigStruct struct {
func infoBigStruct() []byte {
switch runtime.GOARCH {
- case "386", "arm":
+ case "386", "arm", "mips", "mipsle":
return []byte{
typePointer, // q *int
typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
@@ -130,7 +133,7 @@ func infoBigStruct() []byte {
typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
typePointer, typeScalar, // i string
}
- case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le":
+ case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le", "s390x":
return []byte{
typePointer, // q *int
typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
diff --git a/libgo/go/runtime/hash32.go b/libgo/go/runtime/hash32.go
new file mode 100644
index 0000000000..cfb3a58c7c
--- /dev/null
+++ b/libgo/go/runtime/hash32.go
@@ -0,0 +1,94 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Hashing algorithm inspired by
+// xxhash: https://code.google.com/p/xxhash/
+// cityhash: https://code.google.com/p/cityhash/
+
+// +build 386 arm armbe m68k mipso32 mipsn32 mips mipsle ppc s390 sparc
+
+package runtime
+
+import "unsafe"
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname memhash runtime.memhash
+
+const (
+ // Constants for multiplication: four random odd 32-bit numbers.
+ m1 = 3168982561
+ m2 = 3339683297
+ m3 = 832293441
+ m4 = 2336365089
+)
+
+func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
+ if GOARCH == "386" && GOOS != "nacl" && useAeshash {
+ return aeshash(p, seed, s)
+ }
+ h := uint32(seed + s*hashkey[0])
+tail:
+ switch {
+ case s == 0:
+ case s < 4:
+ h ^= uint32(*(*byte)(p))
+ h ^= uint32(*(*byte)(add(p, s>>1))) << 8
+ h ^= uint32(*(*byte)(add(p, s-1))) << 16
+ h = rotl_15(h*m1) * m2
+ case s == 4:
+ h ^= readUnaligned32(p)
+ h = rotl_15(h*m1) * m2
+ case s <= 8:
+ h ^= readUnaligned32(p)
+ h = rotl_15(h*m1) * m2
+ h ^= readUnaligned32(add(p, s-4))
+ h = rotl_15(h*m1) * m2
+ case s <= 16:
+ h ^= readUnaligned32(p)
+ h = rotl_15(h*m1) * m2
+ h ^= readUnaligned32(add(p, 4))
+ h = rotl_15(h*m1) * m2
+ h ^= readUnaligned32(add(p, s-8))
+ h = rotl_15(h*m1) * m2
+ h ^= readUnaligned32(add(p, s-4))
+ h = rotl_15(h*m1) * m2
+ default:
+ v1 := h
+ v2 := uint32(seed * hashkey[1])
+ v3 := uint32(seed * hashkey[2])
+ v4 := uint32(seed * hashkey[3])
+ for s >= 16 {
+ v1 ^= readUnaligned32(p)
+ v1 = rotl_15(v1*m1) * m2
+ p = add(p, 4)
+ v2 ^= readUnaligned32(p)
+ v2 = rotl_15(v2*m2) * m3
+ p = add(p, 4)
+ v3 ^= readUnaligned32(p)
+ v3 = rotl_15(v3*m3) * m4
+ p = add(p, 4)
+ v4 ^= readUnaligned32(p)
+ v4 = rotl_15(v4*m4) * m1
+ p = add(p, 4)
+ s -= 16
+ }
+ h = v1 ^ v2 ^ v3 ^ v4
+ goto tail
+ }
+ h ^= h >> 17
+ h *= m3
+ h ^= h >> 13
+ h *= m4
+ h ^= h >> 16
+ return uintptr(h)
+}
+
+// Note: in order to get the compiler to issue rotl instructions, we
+// need to constant fold the shift amount by hand.
+// TODO: convince the compiler to issue rotl instructions after inlining.
+func rotl_15(x uint32) uint32 {
+ return (x << 15) | (x >> (32 - 15))
+}
diff --git a/libgo/go/runtime/hash64.go b/libgo/go/runtime/hash64.go
new file mode 100644
index 0000000000..551d5b5f8d
--- /dev/null
+++ b/libgo/go/runtime/hash64.go
@@ -0,0 +1,94 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Hashing algorithm inspired by
+// xxhash: https://code.google.com/p/xxhash/
+// cityhash: https://code.google.com/p/cityhash/
+
+// +build amd64 amd64p32 arm64 mips64 mips64le ppc64 ppc64le s390x alpha arm64be ia64 mipso64 mipsn64 mips64p32 mips64p32le sparc64
+
+package runtime
+
+import "unsafe"
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname memhash runtime.memhash
+
+const (
+ // Constants for multiplication: four random odd 64-bit numbers.
+ m1 = 16877499708836156737
+ m2 = 2820277070424839065
+ m3 = 9497967016996688599
+ m4 = 15839092249703872147
+)
+
+func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
+ if GOARCH == "amd64" && GOOS != "nacl" && useAeshash {
+ return aeshash(p, seed, s)
+ }
+ h := uint64(seed + s*hashkey[0])
+tail:
+ switch {
+ case s == 0:
+ case s < 4:
+ h ^= uint64(*(*byte)(p))
+ h ^= uint64(*(*byte)(add(p, s>>1))) << 8
+ h ^= uint64(*(*byte)(add(p, s-1))) << 16
+ h = rotl_31(h*m1) * m2
+ case s <= 8:
+ h ^= uint64(readUnaligned32(p))
+ h ^= uint64(readUnaligned32(add(p, s-4))) << 32
+ h = rotl_31(h*m1) * m2
+ case s <= 16:
+ h ^= readUnaligned64(p)
+ h = rotl_31(h*m1) * m2
+ h ^= readUnaligned64(add(p, s-8))
+ h = rotl_31(h*m1) * m2
+ case s <= 32:
+ h ^= readUnaligned64(p)
+ h = rotl_31(h*m1) * m2
+ h ^= readUnaligned64(add(p, 8))
+ h = rotl_31(h*m1) * m2
+ h ^= readUnaligned64(add(p, s-16))
+ h = rotl_31(h*m1) * m2
+ h ^= readUnaligned64(add(p, s-8))
+ h = rotl_31(h*m1) * m2
+ default:
+ v1 := h
+ v2 := uint64(seed * hashkey[1])
+ v3 := uint64(seed * hashkey[2])
+ v4 := uint64(seed * hashkey[3])
+ for s >= 32 {
+ v1 ^= readUnaligned64(p)
+ v1 = rotl_31(v1*m1) * m2
+ p = add(p, 8)
+ v2 ^= readUnaligned64(p)
+ v2 = rotl_31(v2*m2) * m3
+ p = add(p, 8)
+ v3 ^= readUnaligned64(p)
+ v3 = rotl_31(v3*m3) * m4
+ p = add(p, 8)
+ v4 ^= readUnaligned64(p)
+ v4 = rotl_31(v4*m4) * m1
+ p = add(p, 8)
+ s -= 32
+ }
+ h = v1 ^ v2 ^ v3 ^ v4
+ goto tail
+ }
+
+ h ^= h >> 29
+ h *= m3
+ h ^= h >> 32
+ return uintptr(h)
+}
+
+// Note: in order to get the compiler to issue rotl instructions, we
+// need to constant fold the shift amount by hand.
+// TODO: convince the compiler to issue rotl instructions after inlining.
+func rotl_31(x uint64) uint64 {
+ return (x << 31) | (x >> (64 - 31))
+}
diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go
new file mode 100644
index 0000000000..5b191d4575
--- /dev/null
+++ b/libgo/go/runtime/hashmap.go
@@ -0,0 +1,1202 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// This file contains the implementation of Go's map type.
+//
+// A map is just a hash table. The data is arranged
+// into an array of buckets. Each bucket contains up to
+// 8 key/value pairs. The low-order bits of the hash are
+// used to select a bucket. Each bucket contains a few
+// high-order bits of each hash to distinguish the entries
+// within a single bucket.
+//
+// If more than 8 keys hash to a bucket, we chain on
+// extra buckets.
+//
+// When the hashtable grows, we allocate a new array
+// of buckets twice as big. Buckets are incrementally
+// copied from the old bucket array to the new bucket array.
+//
+// Map iterators walk through the array of buckets and
+// return the keys in walk order (bucket #, then overflow
+// chain order, then bucket index). To maintain iteration
+// semantics, we never move keys within their bucket (if
+// we did, keys might be returned 0 or 2 times). When
+// growing the table, iterators remain iterating through the
+// old table and must check the new table if the bucket
+// they are iterating through has been moved ("evacuated")
+// to the new table.
+
+// Picking loadFactor: too large and we have lots of overflow
+// buckets, too small and we waste a lot of space. I wrote
+// a simple program to check some stats for different loads:
+// (64-bit, 8 byte keys and values)
+// loadFactor %overflow bytes/entry hitprobe missprobe
+// 4.00 2.13 20.77 3.00 4.00
+// 4.50 4.05 17.30 3.25 4.50
+// 5.00 6.85 14.77 3.50 5.00
+// 5.50 10.55 12.94 3.75 5.50
+// 6.00 15.27 11.67 4.00 6.00
+// 6.50 20.90 10.79 4.25 6.50
+// 7.00 27.14 10.15 4.50 7.00
+// 7.50 34.03 9.73 4.75 7.50
+// 8.00 41.10 9.40 5.00 8.00
+//
+// %overflow = percentage of buckets which have an overflow bucket
+// bytes/entry = overhead bytes used per key/value pair
+// hitprobe = # of entries to check when looking up a present key
+// missprobe = # of entries to check when looking up an absent key
+//
+// Keep in mind this data is for maximally loaded tables, i.e. just
+// before the table grows. Typical tables will be somewhat less loaded.
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname makemap runtime.makemap
+//go:linkname mapaccess1 runtime.mapaccess1
+//go:linkname mapaccess2 runtime.mapaccess2
+//go:linkname mapaccess1_fat runtime.mapaccess1_fat
+//go:linkname mapaccess2_fat runtime.mapaccess2_fat
+//go:linkname mapassign runtime.mapassign
+//go:linkname mapdelete runtime.mapdelete
+//go:linkname mapiterinit runtime.mapiterinit
+//go:linkname mapiternext runtime.mapiternext
+
+const (
+ // Maximum number of key/value pairs a bucket can hold.
+ bucketCntBits = 3
+ bucketCnt = 1 << bucketCntBits
+
+ // Maximum average load of a bucket that triggers growth.
+ loadFactor = 6.5
+
+ // Maximum key or value size to keep inline (instead of mallocing per element).
+ // Must fit in a uint8.
+ // Fast versions cannot handle big values - the cutoff size for
+ // fast versions in ../../cmd/internal/gc/walk.go must be at most this value.
+ maxKeySize = 128
+ maxValueSize = 128
+
+ // data offset should be the size of the bmap struct, but needs to be
+ // aligned correctly. For amd64p32 this means 64-bit alignment
+ // even though pointers are 32 bit.
+ dataOffset = unsafe.Offsetof(struct {
+ b bmap
+ v int64
+ }{}.v)
+
+ // Possible tophash values. We reserve a few possibilities for special marks.
+ // Each bucket (including its overflow buckets, if any) will have either all or none of its
+ // entries in the evacuated* states (except during the evacuate() method, which only happens
+ // during map writes and thus no one else can observe the map during that time).
+ empty = 0 // cell is empty
+ evacuatedEmpty = 1 // cell is empty, bucket is evacuated.
+ evacuatedX = 2 // key/value is valid. Entry has been evacuated to first half of larger table.
+ evacuatedY = 3 // same as above, but evacuated to second half of larger table.
+ minTopHash = 4 // minimum tophash for a normal filled cell.
+
+ // flags
+ iterator = 1 // there may be an iterator using buckets
+ oldIterator = 2 // there may be an iterator using oldbuckets
+ hashWriting = 4 // a goroutine is writing to the map
+ sameSizeGrow = 8 // the current map growth is to a new map of the same size
+
+ // sentinel bucket ID for iterator checks
+ noCheck = 1<<(8*sys.PtrSize) - 1
+)
+
+// A header for a Go map.
+type hmap struct {
+ // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
+ // ../reflect/type.go. Don't change this structure without also changing that code!
+ count int // # live cells == size of map. Must be first (used by len() builtin)
+ flags uint8
+ B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
+ noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
+ hash0 uint32 // hash seed
+
+ buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
+ oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
+ nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
+
+ // If both key and value do not contain pointers and are inline, then we mark bucket
+ // type as containing no pointers. This avoids scanning such maps.
+ // However, bmap.overflow is a pointer. In order to keep overflow buckets
+ // alive, we store pointers to all overflow buckets in hmap.overflow.
+ // Overflow is used only if key and value do not contain pointers.
+ // overflow[0] contains overflow buckets for hmap.buckets.
+ // overflow[1] contains overflow buckets for hmap.oldbuckets.
+ // The first indirection allows us to reduce static size of hmap.
+ // The second indirection allows to store a pointer to the slice in hiter.
+ overflow *[2]*[]*bmap
+}
+
+// A bucket for a Go map.
+type bmap struct {
+ // tophash generally contains the top byte of the hash value
+ // for each key in this bucket. If tophash[0] < minTopHash,
+ // tophash[0] is a bucket evacuation state instead.
+ tophash [bucketCnt]uint8
+ // Followed by bucketCnt keys and then bucketCnt values.
+ // NOTE: packing all the keys together and then all the values together makes the
+ // code a bit more complicated than alternating key/value/key/value/... but it allows
+ // us to eliminate padding which would be needed for, e.g., map[int64]int8.
+ // Followed by an overflow pointer.
+}
+
+// A hash iteration structure.
+// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
+// the layout of this structure.
+type hiter struct {
+ key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go).
+ value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
+ t *maptype
+ h *hmap
+ buckets unsafe.Pointer // bucket ptr at hash_iter initialization time
+ bptr *bmap // current bucket
+ overflow [2]*[]*bmap // keeps overflow buckets alive
+ startBucket uintptr // bucket iteration started at
+ offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
+ wrapped bool // already wrapped around from end of bucket array to beginning
+ B uint8
+ i uint8
+ bucket uintptr
+ checkBucket uintptr
+}
+
+func evacuated(b *bmap) bool {
+ h := b.tophash[0]
+ return h > empty && h < minTopHash
+}
+
+func (b *bmap) overflow(t *maptype) *bmap {
+ return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize))
+}
+
+// incrnoverflow increments h.noverflow.
+// noverflow counts the number of overflow buckets.
+// This is used to trigger same-size map growth.
+// See also tooManyOverflowBuckets.
+// To keep hmap small, noverflow is a uint16.
+// When there are few buckets, noverflow is an exact count.
+// When there are many buckets, noverflow is an approximate count.
+func (h *hmap) incrnoverflow() {
+ // We trigger same-size map growth if there are
+ // as many overflow buckets as buckets.
+ // We need to be able to count to 1<<h.B.
+ if h.B < 16 {
+ h.noverflow++
+ return
+ }
+ // Increment with probability 1/(1<<(h.B-15)).
+ // When we reach 1<<15 - 1, we will have approximately
+ // as many overflow buckets as buckets.
+ mask := uint32(1)<<(h.B-15) - 1
+ // Example: if h.B == 18, then mask == 7,
+ // and fastrand & 7 == 0 with probability 1/8.
+ if fastrand()&mask == 0 {
+ h.noverflow++
+ }
+}
+
+func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
+ h.incrnoverflow()
+ if t.bucket.kind&kindNoPointers != 0 {
+ h.createOverflow()
+ *h.overflow[0] = append(*h.overflow[0], ovf)
+ }
+ *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf
+}
+
+func (h *hmap) createOverflow() {
+ if h.overflow == nil {
+ h.overflow = new([2]*[]*bmap)
+ }
+ if h.overflow[0] == nil {
+ h.overflow[0] = new([]*bmap)
+ }
+}
+
+// makemap implements a Go map creation make(map[k]v, hint)
+// If the compiler has determined that the map or the first bucket
+// can be created on the stack, h and/or bucket may be non-nil.
+// If h != nil, the map can be created directly in h.
+// If bucket != nil, bucket can be used as the first bucket.
+func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
+ if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != t.hmap.size {
+ println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
+ throw("bad hmap size")
+ }
+
+ if hint < 0 || int64(int32(hint)) != hint {
+ panic(plainError("makemap: size out of range"))
+ // TODO: make hint an int, then none of this nonsense
+ }
+
+ if !ismapkey(t.key) {
+ throw("runtime.makemap: unsupported map key type")
+ }
+
+ // check compiler's and reflect's math
+ if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(sys.PtrSize)) ||
+ t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) {
+ throw("key size wrong")
+ }
+ if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(sys.PtrSize)) ||
+ t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) {
+ throw("value size wrong")
+ }
+
+ // invariants we depend on. We should probably check these at compile time
+ // somewhere, but for now we'll do it here.
+ if t.key.align > bucketCnt {
+ throw("key align too big")
+ }
+ if t.elem.align > bucketCnt {
+ throw("value align too big")
+ }
+ if t.key.size%uintptr(t.key.align) != 0 {
+ throw("key size not a multiple of key align")
+ }
+ if t.elem.size%uintptr(t.elem.align) != 0 {
+ throw("value size not a multiple of value align")
+ }
+ if bucketCnt < 8 {
+ throw("bucketsize too small for proper alignment")
+ }
+ if dataOffset%uintptr(t.key.align) != 0 {
+ throw("need padding in bucket (key)")
+ }
+ if dataOffset%uintptr(t.elem.align) != 0 {
+ throw("need padding in bucket (value)")
+ }
+
+ // find size parameter which will hold the requested # of elements
+ B := uint8(0)
+ for ; overLoadFactor(hint, B); B++ {
+ }
+
+ // allocate initial hash table
+ // if B == 0, the buckets field is allocated lazily later (in mapassign)
+ // If hint is large zeroing this memory could take a while.
+ buckets := bucket
+ if B != 0 {
+ buckets = newarray(t.bucket, 1<<B)
+ }
+
+ // initialize Hmap
+ if h == nil {
+ h = (*hmap)(newobject(t.hmap))
+ }
+ h.count = 0
+ h.B = B
+ h.flags = 0
+ h.hash0 = fastrand()
+ h.buckets = buckets
+ h.oldbuckets = nil
+ h.nevacuate = 0
+ h.noverflow = 0
+
+ return h
+}
+
+// mapaccess1 returns a pointer to h[key]. Never returns nil, instead
+// it will return a reference to the zero object for the value type if
+// the key is not in the map.
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
+func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ pc := funcPC(mapaccess1)
+ racereadpc(unsafe.Pointer(h), callerpc, pc)
+ raceReadObjectPC(t.key, key, callerpc, pc)
+ }
+ if msanenabled && h != nil {
+ msanread(key, t.key.size)
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ hash := hashfn(key, uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ if b.tophash[i] != top {
+ continue
+ }
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey {
+ k = *((*unsafe.Pointer)(k))
+ }
+ if equalfn(key, k) {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue {
+ v = *((*unsafe.Pointer)(v))
+ }
+ return v
+ }
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ }
+}
+
+func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ pc := funcPC(mapaccess2)
+ racereadpc(unsafe.Pointer(h), callerpc, pc)
+ raceReadObjectPC(t.key, key, callerpc, pc)
+ }
+ if msanenabled && h != nil {
+ msanread(key, t.key.size)
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ hash := hashfn(key, uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ if b.tophash[i] != top {
+ continue
+ }
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey {
+ k = *((*unsafe.Pointer)(k))
+ }
+ if equalfn(key, k) {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue {
+ v = *((*unsafe.Pointer)(v))
+ }
+ return v, true
+ }
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ }
+}
+
+// returns both key and value. Used by map iterator
+func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) {
+ if h == nil || h.count == 0 {
+ return nil, nil
+ }
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ hash := hashfn(key, uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ if b.tophash[i] != top {
+ continue
+ }
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey {
+ k = *((*unsafe.Pointer)(k))
+ }
+ if equalfn(key, k) {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue {
+ v = *((*unsafe.Pointer)(v))
+ }
+ return k, v
+ }
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return nil, nil
+ }
+ }
+}
+
+func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer {
+ v := mapaccess1(t, h, key)
+ if v == unsafe.Pointer(&zeroVal[0]) {
+ return zero
+ }
+ return v
+}
+
+func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) {
+ v := mapaccess1(t, h, key)
+ if v == unsafe.Pointer(&zeroVal[0]) {
+ return zero, false
+ }
+ return v, true
+}
+
+// Like mapaccess, but allocates a slot for the key if it is not present in the map.
+func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
+ if h == nil {
+ panic(plainError("assignment to entry in nil map"))
+ }
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ pc := funcPC(mapassign)
+ racewritepc(unsafe.Pointer(h), callerpc, pc)
+ raceReadObjectPC(t.key, key, callerpc, pc)
+ }
+ if msanenabled {
+ msanread(key, t.key.size)
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map writes")
+ }
+ h.flags |= hashWriting
+
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ hash := hashfn(key, uintptr(h.hash0))
+
+ if h.buckets == nil {
+ h.buckets = newarray(t.bucket, 1)
+ }
+
+again:
+ bucket := hash & (uintptr(1)<<h.B - 1)
+ if h.growing() {
+ growWork(t, h, bucket)
+ }
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+
+ var inserti *uint8
+ var insertk unsafe.Pointer
+ var val unsafe.Pointer
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ if b.tophash[i] != top {
+ if b.tophash[i] == empty && inserti == nil {
+ inserti = &b.tophash[i]
+ insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ }
+ continue
+ }
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey {
+ k = *((*unsafe.Pointer)(k))
+ }
+ if !equalfn(key, k) {
+ continue
+ }
+ // already have a mapping for key. Update it.
+ if t.needkeyupdate {
+ typedmemmove(t.key, k, key)
+ }
+ val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ goto done
+ }
+ ovf := b.overflow(t)
+ if ovf == nil {
+ break
+ }
+ b = ovf
+ }
+
+ // Did not find mapping for key. Allocate new cell & add entry.
+
+ // If we hit the max load factor or we have too many overflow buckets,
+ // and we're not already in the middle of growing, start growing.
+ if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
+ hashGrow(t, h)
+ goto again // Growing the table invalidates everything, so try again
+ }
+
+ if inserti == nil {
+ // all current buckets are full, allocate a new one.
+ newb := (*bmap)(newobject(t.bucket))
+ h.setoverflow(t, b, newb)
+ inserti = &newb.tophash[0]
+ insertk = add(unsafe.Pointer(newb), dataOffset)
+ val = add(insertk, bucketCnt*uintptr(t.keysize))
+ }
+
+ // store new key/value at insert position
+ if t.indirectkey {
+ kmem := newobject(t.key)
+ *(*unsafe.Pointer)(insertk) = kmem
+ insertk = kmem
+ }
+ if t.indirectvalue {
+ vmem := newobject(t.elem)
+ *(*unsafe.Pointer)(val) = vmem
+ }
+ typedmemmove(t.key, insertk, key)
+ *inserti = top
+ h.count++
+
+done:
+ if h.flags&hashWriting == 0 {
+ throw("concurrent map writes")
+ }
+ h.flags &^= hashWriting
+ if t.indirectvalue {
+ val = *((*unsafe.Pointer)(val))
+ }
+ return val
+}
+
+func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ pc := funcPC(mapdelete)
+ racewritepc(unsafe.Pointer(h), callerpc, pc)
+ raceReadObjectPC(t.key, key, callerpc, pc)
+ }
+ if msanenabled && h != nil {
+ msanread(key, t.key.size)
+ }
+ if h == nil || h.count == 0 {
+ return
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map writes")
+ }
+ h.flags |= hashWriting
+
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ hash := hashfn(key, uintptr(h.hash0))
+ bucket := hash & (uintptr(1)<<h.B - 1)
+ if h.growing() {
+ growWork(t, h, bucket)
+ }
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ if b.tophash[i] != top {
+ continue
+ }
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ k2 := k
+ if t.indirectkey {
+ k2 = *((*unsafe.Pointer)(k2))
+ }
+ if !equalfn(key, k2) {
+ continue
+ }
+ if t.indirectkey {
+ *(*unsafe.Pointer)(k) = nil
+ } else {
+ typedmemclr(t.key, k)
+ }
+ v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
+ if t.indirectvalue {
+ *(*unsafe.Pointer)(v) = nil
+ } else {
+ typedmemclr(t.elem, v)
+ }
+ b.tophash[i] = empty
+ h.count--
+ goto done
+ }
+ b = b.overflow(t)
+ if b == nil {
+ goto done
+ }
+ }
+
+done:
+ if h.flags&hashWriting == 0 {
+ throw("concurrent map writes")
+ }
+ h.flags &^= hashWriting
+}
+
+func mapiterinit(t *maptype, h *hmap, it *hiter) {
+ // Clear pointer fields so garbage collector does not complain.
+ it.key = nil
+ it.value = nil
+ it.t = nil
+ it.h = nil
+ it.buckets = nil
+ it.bptr = nil
+ it.overflow[0] = nil
+ it.overflow[1] = nil
+
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit))
+ }
+
+ if h == nil || h.count == 0 {
+ it.key = nil
+ it.value = nil
+ return
+ }
+
+ if unsafe.Sizeof(hiter{})/sys.PtrSize != 12 {
+ throw("hash_iter size incorrect") // see ../../cmd/internal/gc/reflect.go
+ }
+ it.t = t
+ it.h = h
+
+ // grab snapshot of bucket state
+ it.B = h.B
+ it.buckets = h.buckets
+ if t.bucket.kind&kindNoPointers != 0 {
+ // Allocate the current slice and remember pointers to both current and old.
+ // This preserves all relevant overflow buckets alive even if
+ // the table grows and/or overflow buckets are added to the table
+ // while we are iterating.
+ h.createOverflow()
+ it.overflow = *h.overflow
+ }
+
+ // decide where to start
+ r := uintptr(fastrand())
+ if h.B > 31-bucketCntBits {
+ r += uintptr(fastrand()) << 31
+ }
+ it.startBucket = r & (uintptr(1)<<h.B - 1)
+ it.offset = uint8(r >> h.B & (bucketCnt - 1))
+
+ // iterator state
+ it.bucket = it.startBucket
+ it.wrapped = false
+ it.bptr = nil
+
+ // Remember we have an iterator.
+ // Can run concurrently with another hash_iter_init().
+ if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator {
+ atomic.Or8(&h.flags, iterator|oldIterator)
+ }
+
+ mapiternext(it)
+}
+
+func mapiternext(it *hiter) {
+ h := it.h
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer( /* &it */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext))
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map iteration and map write")
+ }
+ t := it.t
+ bucket := it.bucket
+ b := it.bptr
+ i := it.i
+ checkBucket := it.checkBucket
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+
+next:
+ if b == nil {
+ if bucket == it.startBucket && it.wrapped {
+ // end of iteration
+ it.key = nil
+ it.value = nil
+ return
+ }
+ if h.growing() && it.B == h.B {
+ // Iterator was started in the middle of a grow, and the grow isn't done yet.
+ // If the bucket we're looking at hasn't been filled in yet (i.e. the old
+ // bucket hasn't been evacuated) then we need to iterate through the old
+ // bucket and only return the ones that will be migrated to this bucket.
+ oldbucket := bucket & it.h.oldbucketmask()
+ b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
+ if !evacuated(b) {
+ checkBucket = bucket
+ } else {
+ b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
+ checkBucket = noCheck
+ }
+ } else {
+ b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
+ checkBucket = noCheck
+ }
+ bucket++
+ if bucket == uintptr(1)<<it.B {
+ bucket = 0
+ it.wrapped = true
+ }
+ i = 0
+ }
+ for ; i < bucketCnt; i++ {
+ offi := (i + it.offset) & (bucketCnt - 1)
+ k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.keysize))
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+uintptr(offi)*uintptr(t.valuesize))
+ if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
+ if checkBucket != noCheck && !h.sameSizeGrow() {
+ // Special case: iterator was started during a grow to a larger size
+ // and the grow is not done yet. We're working on a bucket whose
+ // oldbucket has not been evacuated yet. Or at least, it wasn't
+ // evacuated when we started the bucket. So we're iterating
+ // through the oldbucket, skipping any keys that will go
+ // to the other new bucket (each oldbucket expands to two
+ // buckets during a grow).
+ k2 := k
+ if t.indirectkey {
+ k2 = *((*unsafe.Pointer)(k2))
+ }
+ if t.reflexivekey || equalfn(k2, k2) {
+ // If the item in the oldbucket is not destined for
+ // the current new bucket in the iteration, skip it.
+ hash := hashfn(k2, uintptr(h.hash0))
+ if hash&(uintptr(1)<<it.B-1) != checkBucket {
+ continue
+ }
+ } else {
+ // Hash isn't repeatable if k != k (NaNs). We need a
+ // repeatable and randomish choice of which direction
+ // to send NaNs during evacuation. We'll use the low
+ // bit of tophash to decide which way NaNs go.
+ // NOTE: this case is why we need two evacuate tophash
+ // values, evacuatedX and evacuatedY, that differ in
+ // their low bit.
+ if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) {
+ continue
+ }
+ }
+ }
+ if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY {
+ // this is the golden data, we can return it.
+ if t.indirectkey {
+ k = *((*unsafe.Pointer)(k))
+ }
+ it.key = k
+ if t.indirectvalue {
+ v = *((*unsafe.Pointer)(v))
+ }
+ it.value = v
+ } else {
+ // The hash table has grown since the iterator was started.
+ // The golden data for this key is now somewhere else.
+ k2 := k
+ if t.indirectkey {
+ k2 = *((*unsafe.Pointer)(k2))
+ }
+ if t.reflexivekey || equalfn(k2, k2) {
+ // Check the current hash table for the data.
+ // This code handles the case where the key
+ // has been deleted, updated, or deleted and reinserted.
+ // NOTE: we need to regrab the key as it has potentially been
+ // updated to an equal() but not identical key (e.g. +0.0 vs -0.0).
+ rk, rv := mapaccessK(t, h, k2)
+ if rk == nil {
+ continue // key has been deleted
+ }
+ it.key = rk
+ it.value = rv
+ } else {
+ // if key!=key then the entry can't be deleted or
+ // updated, so we can just return it. That's lucky for
+ // us because when key!=key we can't look it up
+ // successfully in the current table.
+ it.key = k2
+ if t.indirectvalue {
+ v = *((*unsafe.Pointer)(v))
+ }
+ it.value = v
+ }
+ }
+ it.bucket = bucket
+ if it.bptr != b { // avoid unnecessary write barrier; see issue 14921
+ it.bptr = b
+ }
+ it.i = i + 1
+ it.checkBucket = checkBucket
+ return
+ }
+ }
+ b = b.overflow(t)
+ i = 0
+ goto next
+}
+
+func hashGrow(t *maptype, h *hmap) {
+ // If we've hit the load factor, get bigger.
+ // Otherwise, there are too many overflow buckets,
+ // so keep the same number of buckets and "grow" laterally.
+ bigger := uint8(1)
+ if !overLoadFactor(int64(h.count), h.B) {
+ bigger = 0
+ h.flags |= sameSizeGrow
+ }
+ oldbuckets := h.buckets
+ newbuckets := newarray(t.bucket, 1<<(h.B+bigger))
+ flags := h.flags &^ (iterator | oldIterator)
+ if h.flags&iterator != 0 {
+ flags |= oldIterator
+ }
+ // commit the grow (atomic wrt gc)
+ h.B += bigger
+ h.flags = flags
+ h.oldbuckets = oldbuckets
+ h.buckets = newbuckets
+ h.nevacuate = 0
+ h.noverflow = 0
+
+ if h.overflow != nil {
+ // Promote current overflow buckets to the old generation.
+ if h.overflow[1] != nil {
+ throw("overflow is not nil")
+ }
+ h.overflow[1] = h.overflow[0]
+ h.overflow[0] = nil
+ }
+
+ // the actual copying of the hash table data is done incrementally
+ // by growWork() and evacuate().
+}
+
+// overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor.
+func overLoadFactor(count int64, B uint8) bool {
+ // TODO: rewrite to use integer math and comparison?
+ return count >= bucketCnt && float32(count) >= loadFactor*float32((uintptr(1)<<B))
+}
+
+// tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<<B buckets.
+// Note that most of these overflow buckets must be in sparse use;
+// if use was dense, then we'd have already triggered regular map growth.
+func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
+ // If the threshold is too low, we do extraneous work.
+ // If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory.
+ // "too many" means (approximately) as many overflow buckets as regular buckets.
+ // See incrnoverflow for more details.
+ if B < 16 {
+ return noverflow >= uint16(1)<<B
+ }
+ return noverflow >= 1<<15
+}
+
+// growing reports whether h is growing. The growth may be to the same size or bigger.
+func (h *hmap) growing() bool {
+ return h.oldbuckets != nil
+}
+
+// sameSizeGrow reports whether the current growth is to a map of the same size.
+func (h *hmap) sameSizeGrow() bool {
+ return h.flags&sameSizeGrow != 0
+}
+
+// noldbuckets calculates the number of buckets prior to the current map growth.
+func (h *hmap) noldbuckets() uintptr {
+ oldB := h.B
+ if !h.sameSizeGrow() {
+ oldB--
+ }
+ return uintptr(1) << oldB
+}
+
+// oldbucketmask provides a mask that can be applied to calculate n % noldbuckets().
+func (h *hmap) oldbucketmask() uintptr {
+ return h.noldbuckets() - 1
+}
+
+func growWork(t *maptype, h *hmap, bucket uintptr) {
+ // make sure we evacuate the oldbucket corresponding
+ // to the bucket we're about to use
+ evacuate(t, h, bucket&h.oldbucketmask())
+
+ // evacuate one more oldbucket to make progress on growing
+ if h.growing() {
+ evacuate(t, h, h.nevacuate)
+ }
+}
+
+func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
+ b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
+ newbit := h.noldbuckets()
+ hashfn := t.key.hashfn
+ equalfn := t.key.equalfn
+ if !evacuated(b) {
+ // TODO: reuse overflow buckets instead of using new ones, if there
+ // is no iterator using the old buckets. (If !oldIterator.)
+
+ var (
+ x, y *bmap // current low/high buckets in new map
+ xi, yi int // key/val indices into x and y
+ xk, yk unsafe.Pointer // pointers to current x and y key storage
+ xv, yv unsafe.Pointer // pointers to current x and y value storage
+ )
+ x = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
+ xi = 0
+ xk = add(unsafe.Pointer(x), dataOffset)
+ xv = add(xk, bucketCnt*uintptr(t.keysize))
+ if !h.sameSizeGrow() {
+ // Only calculate y pointers if we're growing bigger.
+ // Otherwise GC can see bad pointers.
+ y = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
+ yi = 0
+ yk = add(unsafe.Pointer(y), dataOffset)
+ yv = add(yk, bucketCnt*uintptr(t.keysize))
+ }
+ for ; b != nil; b = b.overflow(t) {
+ k := add(unsafe.Pointer(b), dataOffset)
+ v := add(k, bucketCnt*uintptr(t.keysize))
+ for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) {
+ top := b.tophash[i]
+ if top == empty {
+ b.tophash[i] = evacuatedEmpty
+ continue
+ }
+ if top < minTopHash {
+ throw("bad map state")
+ }
+ k2 := k
+ if t.indirectkey {
+ k2 = *((*unsafe.Pointer)(k2))
+ }
+ useX := true
+ if !h.sameSizeGrow() {
+ // Compute hash to make our evacuation decision (whether we need
+ // to send this key/value to bucket x or bucket y).
+ hash := hashfn(k2, uintptr(h.hash0))
+ if h.flags&iterator != 0 {
+ if !t.reflexivekey && !equalfn(k2, k2) {
+ // If key != key (NaNs), then the hash could be (and probably
+ // will be) entirely different from the old hash. Moreover,
+ // it isn't reproducible. Reproducibility is required in the
+ // presence of iterators, as our evacuation decision must
+ // match whatever decision the iterator made.
+ // Fortunately, we have the freedom to send these keys either
+ // way. Also, tophash is meaningless for these kinds of keys.
+ // We let the low bit of tophash drive the evacuation decision.
+ // We recompute a new random tophash for the next level so
+ // these keys will get evenly distributed across all buckets
+ // after multiple grows.
+ if top&1 != 0 {
+ hash |= newbit
+ } else {
+ hash &^= newbit
+ }
+ top = uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ }
+ }
+ useX = hash&newbit == 0
+ }
+ if useX {
+ b.tophash[i] = evacuatedX
+ if xi == bucketCnt {
+ newx := (*bmap)(newobject(t.bucket))
+ h.setoverflow(t, x, newx)
+ x = newx
+ xi = 0
+ xk = add(unsafe.Pointer(x), dataOffset)
+ xv = add(xk, bucketCnt*uintptr(t.keysize))
+ }
+ x.tophash[xi] = top
+ if t.indirectkey {
+ *(*unsafe.Pointer)(xk) = k2 // copy pointer
+ } else {
+ typedmemmove(t.key, xk, k) // copy value
+ }
+ if t.indirectvalue {
+ *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
+ } else {
+ typedmemmove(t.elem, xv, v)
+ }
+ xi++
+ xk = add(xk, uintptr(t.keysize))
+ xv = add(xv, uintptr(t.valuesize))
+ } else {
+ b.tophash[i] = evacuatedY
+ if yi == bucketCnt {
+ newy := (*bmap)(newobject(t.bucket))
+ h.setoverflow(t, y, newy)
+ y = newy
+ yi = 0
+ yk = add(unsafe.Pointer(y), dataOffset)
+ yv = add(yk, bucketCnt*uintptr(t.keysize))
+ }
+ y.tophash[yi] = top
+ if t.indirectkey {
+ *(*unsafe.Pointer)(yk) = k2
+ } else {
+ typedmemmove(t.key, yk, k)
+ }
+ if t.indirectvalue {
+ *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
+ } else {
+ typedmemmove(t.elem, yv, v)
+ }
+ yi++
+ yk = add(yk, uintptr(t.keysize))
+ yv = add(yv, uintptr(t.valuesize))
+ }
+ }
+ }
+ // Unlink the overflow buckets & clear key/value to help GC.
+ if h.flags&oldIterator == 0 {
+ b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
+ // Preserve b.tophash because the evacuation
+ // state is maintained there.
+ if t.bucket.kind&kindNoPointers == 0 {
+ memclrHasPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
+ } else {
+ memclrNoHeapPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
+ }
+ }
+ }
+
+ // Advance evacuation mark
+ if oldbucket == h.nevacuate {
+ h.nevacuate = oldbucket + 1
+ if oldbucket+1 == newbit { // newbit == # of oldbuckets
+ // Growing is all done. Free old main bucket array.
+ h.oldbuckets = nil
+ // Can discard old overflow buckets as well.
+ // If they are still referenced by an iterator,
+ // then the iterator holds a pointers to the slice.
+ if h.overflow != nil {
+ h.overflow[1] = nil
+ }
+ h.flags &^= sameSizeGrow
+ }
+ }
+}
+
+func ismapkey(t *_type) bool {
+ return t.hashfn != nil
+}
+
+// Reflect stubs. Called from ../reflect/asm_*.s
+
+//go:linkname reflect_makemap reflect.makemap
+func reflect_makemap(t *maptype) *hmap {
+ return makemap(t, 0, nil, nil)
+}
+
+//go:linkname reflect_mapaccess reflect.mapaccess
+func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
+ val, ok := mapaccess2(t, h, key)
+ if !ok {
+ // reflect wants nil for a missing element
+ val = nil
+ }
+ return val
+}
+
+//go:linkname reflect_mapassign reflect.mapassign
+func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
+ p := mapassign(t, h, key)
+ typedmemmove(t.elem, p, val)
+}
+
+//go:linkname reflect_mapdelete reflect.mapdelete
+func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
+ mapdelete(t, h, key)
+}
+
+//go:linkname reflect_mapiterinit reflect.mapiterinit
+func reflect_mapiterinit(t *maptype, h *hmap) *hiter {
+ it := new(hiter)
+ mapiterinit(t, h, it)
+ return it
+}
+
+//go:linkname reflect_mapiternext reflect.mapiternext
+func reflect_mapiternext(it *hiter) {
+ mapiternext(it)
+}
+
+//go:linkname reflect_mapiterkey reflect.mapiterkey
+func reflect_mapiterkey(it *hiter) unsafe.Pointer {
+ return it.key
+}
+
+//go:linkname reflect_maplen reflect.maplen
+func reflect_maplen(h *hmap) int {
+ if h == nil {
+ return 0
+ }
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer( /* &h */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen))
+ }
+ return h.count
+}
+
+//go:linkname reflect_ismapkey reflect.ismapkey
+func reflect_ismapkey(t *_type) bool {
+ return ismapkey(t)
+}
+
+const maxZero = 1024 // must match value in ../cmd/compile/internal/gc/walk.go
+var zeroVal [maxZero]byte
diff --git a/libgo/go/runtime/hashmap_fast.go b/libgo/go/runtime/hashmap_fast.go
new file mode 100644
index 0000000000..853da70e96
--- /dev/null
+++ b/libgo/go/runtime/hashmap_fast.go
@@ -0,0 +1,422 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ var b *bmap
+ if h.B == 0 {
+ // One-bucket table. No need to hash.
+ b = (*bmap)(h.buckets)
+ } else {
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4)))
+ if k != key {
+ continue
+ }
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ }
+}
+
+func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ var b *bmap
+ if h.B == 0 {
+ // One-bucket table. No need to hash.
+ b = (*bmap)(h.buckets)
+ } else {
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4)))
+ if k != key {
+ continue
+ }
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ }
+}
+
+func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ var b *bmap
+ if h.B == 0 {
+ // One-bucket table. No need to hash.
+ b = (*bmap)(h.buckets)
+ } else {
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8)))
+ if k != key {
+ continue
+ }
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ }
+}
+
+func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ var b *bmap
+ if h.B == 0 {
+ // One-bucket table. No need to hash.
+ b = (*bmap)(h.buckets)
+ } else {
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8)))
+ if k != key {
+ continue
+ }
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ }
+}
+
+func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ key := stringStructOf(&ky)
+ if h.B == 0 {
+ // One-bucket table.
+ b := (*bmap)(h.buckets)
+ if key.len < 32 {
+ // short key, doing lots of comparisons is ok
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
+ }
+ }
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ // long key, try not to do more comparisons than necessary
+ keymaybe := uintptr(bucketCnt)
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
+ }
+ // check first 4 bytes
+ // TODO: on amd64/386 at least, make this compile to one 4-byte comparison instead of
+ // four 1-byte comparisons.
+ if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
+ continue
+ }
+ // check last 4 bytes
+ if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) {
+ continue
+ }
+ if keymaybe != bucketCnt {
+ // Two keys are potential matches. Use hash to distinguish them.
+ goto dohash
+ }
+ keymaybe = i
+ }
+ if keymaybe != bucketCnt {
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
+ if memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize))
+ }
+ }
+ return unsafe.Pointer(&zeroVal[0])
+ }
+dohash:
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x != top {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
+ }
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0])
+ }
+ }
+}
+
+func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil))
+ racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr))
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map read and map write")
+ }
+ key := stringStructOf(&ky)
+ if h.B == 0 {
+ // One-bucket table.
+ b := (*bmap)(h.buckets)
+ if key.len < 32 {
+ // short key, doing lots of comparisons is ok
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
+ }
+ }
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ // long key, try not to do more comparisons than necessary
+ keymaybe := uintptr(bucketCnt)
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
+ }
+ // check first 4 bytes
+ if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
+ continue
+ }
+ // check last 4 bytes
+ if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) {
+ continue
+ }
+ if keymaybe != bucketCnt {
+ // Two keys are potential matches. Use hash to distinguish them.
+ goto dohash
+ }
+ keymaybe = i
+ }
+ if keymaybe != bucketCnt {
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
+ if memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true
+ }
+ }
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+dohash:
+ hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
+ if !evacuated(oldb) {
+ b = oldb
+ }
+ }
+ top := uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
+ for {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x != top {
+ continue
+ }
+ k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+ if k.len != key.len {
+ continue
+ }
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
+ }
+ }
+ b = b.overflow(t)
+ if b == nil {
+ return unsafe.Pointer(&zeroVal[0]), false
+ }
+ }
+}
diff --git a/libgo/go/runtime/iface.go b/libgo/go/runtime/iface.go
new file mode 100644
index 0000000000..62d47ce68a
--- /dev/null
+++ b/libgo/go/runtime/iface.go
@@ -0,0 +1,334 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname requireitab runtime.requireitab
+//go:linkname assertitab runtime.assertitab
+//go:linkname assertI2T runtime.assertI2T
+//go:linkname ifacetypeeq runtime.ifacetypeeq
+//go:linkname efacetype runtime.efacetype
+//go:linkname ifacetype runtime.ifacetype
+//go:linkname ifaceE2E2 runtime.ifaceE2E2
+//go:linkname ifaceI2E2 runtime.ifaceI2E2
+//go:linkname ifaceE2I2 runtime.ifaceE2I2
+//go:linkname ifaceI2I2 runtime.ifaceI2I2
+//go:linkname ifaceE2T2P runtime.ifaceE2T2P
+//go:linkname ifaceI2T2P runtime.ifaceI2T2P
+//go:linkname ifaceE2T2 runtime.ifaceE2T2
+//go:linkname ifaceI2T2 runtime.ifaceI2T2
+//go:linkname ifaceT2Ip runtime.ifaceT2Ip
+// Temporary for C code to call:
+//go:linkname getitab runtime.getitab
+
+// The gccgo itab structure is different than the gc one.
+//
+// Both gccgo and gc represent empty interfaces the same way:
+// a two field struct, where the first field points to a type descriptor
+// (a *_type) and the second field is the data pointer.
+//
+// Non-empty interfaces are also two-field structs, and the second
+// field is the data pointer. However, for gccgo, the first field, the
+// itab field, is different. The itab field points to the interface
+// method table, which is the implemention of a specific interface
+// type for a specific dynamic non-interface type. An interface
+// method table is a list of pointer values. The first pointer is the
+// type descriptor (a *_type) for the dynamic type. The subsequent
+// pointers are pointers to function code, which implement the methods
+// required by the interface. The pointers are sorted by name.
+//
+// The method pointers in the itab are C function pointers, not Go
+// function pointers; they may be called directly, and they have no
+// closures. The receiver is always passed as a pointer, and it is
+// always the same pointer stored in the interface value. A value
+// method starts by copying the receiver value out of the pointer into
+// a local variable.
+//
+// A method call on an interface value is by definition calling a
+// method at a known index m in the list of methods. Given a non-empty
+// interface value i, the call i.m(args) looks like
+// i.itab[m+1](i.iface, args)
+
+// Both an empty interface and a non-empty interface have a data
+// pointer field. The meaning of this field is determined by the
+// kindDirectIface bit in the `kind` field of the type descriptor of
+// the value stored in the interface. If kindDirectIface is set, then
+// the data pointer field in the interface value is exactly the value
+// stored in the interface. Otherwise, the data pointer field is a
+// pointer to memory that holds the value. It follows from this that
+// kindDirectIface can only be set for a type whose representation is
+// simply a pointer. In the current gccgo implementation, this is set
+// only for pointer types (including unsafe.Pointer). In the future it
+// could also be set for other types: channels, maps, functions,
+// single-field structs and single-element arrays whose single field
+// is simply a pointer.
+
+// For a nil interface value both fields in the interface struct are nil.
+
+// Return the interface method table for a value of type rhs converted
+// to an interface of type lhs.
+func getitab(lhs, rhs *_type, canfail bool) unsafe.Pointer {
+ if rhs == nil {
+ return nil
+ }
+
+ if lhs.kind&kindMask != kindInterface {
+ throw("getitab called for non-interface type")
+ }
+
+ lhsi := (*interfacetype)(unsafe.Pointer(lhs))
+
+ if len(lhsi.methods) == 0 {
+ throw("getitab called for empty interface type")
+ }
+
+ if rhs.uncommontype == nil || len(rhs.methods) == 0 {
+ if canfail {
+ return nil
+ }
+ panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsi.methods[0].name})
+ }
+
+ methods := make([]unsafe.Pointer, len(lhsi.methods)+1)
+ methods[0] = unsafe.Pointer(rhs)
+
+ ri := 0
+ for li := range lhsi.methods {
+ lhsMethod := &lhsi.methods[li]
+ var rhsMethod *method
+
+ for {
+ if ri >= len(rhs.methods) {
+ if canfail {
+ return nil
+ }
+ panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name})
+ }
+
+ rhsMethod = &rhs.methods[ri]
+ if (lhsMethod.name == rhsMethod.name || *lhsMethod.name == *rhsMethod.name) &&
+ (lhsMethod.pkgPath == rhsMethod.pkgPath || *lhsMethod.pkgPath == *rhsMethod.pkgPath) {
+ break
+ }
+
+ ri++
+ }
+
+ if !eqtype(lhsMethod.typ, rhsMethod.mtyp) {
+ if canfail {
+ return nil
+ }
+ panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name})
+ }
+
+ methods[li+1] = unsafe.Pointer(rhsMethod.tfn)
+ ri++
+ }
+
+ return unsafe.Pointer(&methods[0])
+}
+
+// Return the interface method table for a value of type rhs converted
+// to an interface of type lhs. Panics if the conversion is impossible.
+func requireitab(lhs, rhs *_type) unsafe.Pointer {
+ return getitab(lhs, rhs, false)
+}
+
+// Return the interface method table for a value of type rhs converted
+// to an interface of type lhs. Panics if the conversion is
+// impossible or if the rhs type is nil.
+func assertitab(lhs, rhs *_type) unsafe.Pointer {
+ if rhs == nil {
+ panic(&TypeAssertionError{"", "", *lhs.string, ""})
+ }
+
+ if lhs.kind&kindMask != kindInterface {
+ throw("assertitab called for non-interface type")
+ }
+
+ lhsi := (*interfacetype)(unsafe.Pointer(lhs))
+
+ if len(lhsi.methods) == 0 {
+ return unsafe.Pointer(rhs)
+ }
+
+ return getitab(lhs, rhs, false)
+}
+
+// Check whether an interface type may be converted to a non-interface
+// type, panicing if not.
+func assertI2T(lhs, rhs, inter *_type) {
+ if rhs == nil {
+ panic(&TypeAssertionError{"", "", *lhs.string, ""})
+ }
+ if !eqtype(lhs, rhs) {
+ panic(&TypeAssertionError{*inter.string, *rhs.string, *lhs.string, ""})
+ }
+}
+
+// Compare two type descriptors for equality.
+func ifacetypeeq(a, b *_type) bool {
+ return eqtype(a, b)
+}
+
+// Return the type descriptor of an empty interface.
+// FIXME: This should be inlined by the compiler.
+func efacetype(e eface) *_type {
+ return e._type
+}
+
+// Return the type descriptor of a non-empty interface.
+// FIXME: This should be inlined by the compiler.
+func ifacetype(i iface) *_type {
+ if i.tab == nil {
+ return nil
+ }
+ return *(**_type)(i.tab)
+}
+
+// Convert an empty interface to an empty interface, for a comma-ok
+// type assertion.
+func ifaceE2E2(e eface) (eface, bool) {
+ return e, e._type != nil
+}
+
+// Convert a non-empty interface to an empty interface, for a comma-ok
+// type assertion.
+func ifaceI2E2(i iface) (eface, bool) {
+ if i.tab == nil {
+ return eface{nil, nil}, false
+ } else {
+ return eface{*(**_type)(i.tab), i.data}, true
+ }
+}
+
+// Convert an empty interface to a non-empty interface, for a comma-ok
+// type assertion.
+func ifaceE2I2(inter *_type, e eface) (iface, bool) {
+ if e._type == nil {
+ return iface{nil, nil}, false
+ } else {
+ itab := getitab(inter, e._type, true)
+ if itab == nil {
+ return iface{nil, nil}, false
+ } else {
+ return iface{itab, e.data}, true
+ }
+ }
+}
+
+// Convert a non-empty interface to a non-empty interface, for a
+// comma-ok type assertion.
+func ifaceI2I2(inter *_type, i iface) (iface, bool) {
+ if i.tab == nil {
+ return iface{nil, nil}, false
+ } else {
+ itab := getitab(inter, *(**_type)(i.tab), true)
+ if itab == nil {
+ return iface{nil, nil}, false
+ } else {
+ return iface{itab, i.data}, true
+ }
+ }
+}
+
+// Convert an empty interface to a pointer non-interface type.
+func ifaceE2T2P(t *_type, e eface) (unsafe.Pointer, bool) {
+ if !eqtype(t, e._type) {
+ return nil, false
+ } else {
+ return e.data, true
+ }
+}
+
+// Convert a non-empty interface to a pointer non-interface type.
+func ifaceI2T2P(t *_type, i iface) (unsafe.Pointer, bool) {
+ if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
+ return nil, false
+ } else {
+ return i.data, true
+ }
+}
+
+// Convert an empty interface to a non-pointer non-interface type.
+func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool {
+ if !eqtype(t, e._type) {
+ typedmemclr(t, ret)
+ return false
+ } else {
+ typedmemmove(t, ret, e.data)
+ return true
+ }
+}
+
+// Convert a non-empty interface to a non-pointer non-interface type.
+func ifaceI2T2(t *_type, i iface, ret unsafe.Pointer) bool {
+ if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
+ typedmemclr(t, ret)
+ return false
+ } else {
+ typedmemmove(t, ret, i.data)
+ return true
+ }
+}
+
+// Return whether we can convert a type to an interface type.
+func ifaceT2Ip(to, from *_type) bool {
+ if from == nil {
+ return false
+ }
+
+ if to.kind&kindMask != kindInterface {
+ throw("ifaceT2Ip called with non-interface type")
+ }
+ toi := (*interfacetype)(unsafe.Pointer(to))
+
+ if from.uncommontype == nil || len(from.methods) == 0 {
+ return len(toi.methods) == 0
+ }
+
+ ri := 0
+ for li := range toi.methods {
+ toMethod := &toi.methods[li]
+ var fromMethod *method
+ for {
+ if ri >= len(from.methods) {
+ return false
+ }
+
+ fromMethod = &from.methods[ri]
+ if (toMethod.name == fromMethod.name || *toMethod.name == *fromMethod.name) &&
+ (toMethod.pkgPath == fromMethod.pkgPath || *toMethod.pkgPath == *fromMethod.pkgPath) {
+ break
+ }
+
+ ri++
+ }
+
+ if !eqtype(fromMethod.mtyp, toMethod.typ) {
+ return false
+ }
+
+ ri++
+ }
+
+ return true
+}
+
+//go:linkname reflect_ifaceE2I reflect.ifaceE2I
+func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
+ t := e._type
+ if t == nil {
+ panic(TypeAssertionError{"", "", *inter.typ.string, ""})
+ }
+ dst.tab = requireitab((*_type)(unsafe.Pointer(inter)), t)
+ dst.data = e.data
+}
diff --git a/libgo/go/runtime/internal/atomic/atomic.c b/libgo/go/runtime/internal/atomic/atomic.c
new file mode 100644
index 0000000000..b584656f81
--- /dev/null
+++ b/libgo/go/runtime/internal/atomic/atomic.c
@@ -0,0 +1,251 @@
+// 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 <stdint.h>
+
+#include "runtime.h"
+
+uint32_t Load (uint32_t *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load")
+ __attribute__ ((no_split_stack));
+
+uint32_t
+Load (uint32_t *ptr)
+{
+ return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+void *Loadp (void *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadp")
+ __attribute__ ((no_split_stack));
+
+void *
+Loadp (void *ptr)
+{
+ return __atomic_load_n ((void **) ptr, __ATOMIC_ACQUIRE);
+}
+
+uint64_t Load64 (uint64_t *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load64")
+ __attribute__ ((no_split_stack));
+
+uint64_t
+Load64 (uint64_t *ptr)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uintptr_t Loaduintptr (uintptr_t *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduintptr")
+ __attribute__ ((no_split_stack));
+
+uintptr_t
+Loaduintptr (uintptr_t *ptr)
+{
+ return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uintgo Loaduint (uintgo *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduint")
+ __attribute__ ((no_split_stack));
+
+uintgo
+Loaduint (uintgo *ptr)
+{
+ return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+int64_t Loadint64 (int64_t *ptr)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadint64")
+ __attribute__ ((no_split_stack));
+
+int64_t
+Loadint64 (int64_t *ptr)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uint32_t Xadd (uint32_t *ptr, int32_t delta)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd")
+ __attribute__ ((no_split_stack));
+
+uint32_t
+Xadd (uint32_t *ptr, int32_t delta)
+{
+ return __atomic_add_fetch (ptr, (uint32_t) delta, __ATOMIC_SEQ_CST);
+}
+
+uint64_t Xadd64 (uint64_t *ptr, int64_t delta)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd64")
+ __attribute__ ((no_split_stack));
+
+uint64_t
+Xadd64 (uint64_t *ptr, int64_t delta)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_add_fetch (ptr, (uint64_t) delta, __ATOMIC_SEQ_CST);
+}
+
+uintptr_t Xadduintptr (uintptr_t *ptr, uintptr_t delta)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadduintptr")
+ __attribute__ ((no_split_stack));
+
+uintptr_t
+Xadduintptr (uintptr_t *ptr, uintptr_t delta)
+{
+ return __atomic_add_fetch (ptr, delta, __ATOMIC_SEQ_CST);
+}
+
+int64_t Xaddint64 (int64_t *ptr, int64_t delta)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xaddint64")
+ __attribute__ ((no_split_stack));
+
+int64_t
+Xaddint64 (int64_t *ptr, int64_t delta)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_add_fetch (ptr, delta, __ATOMIC_SEQ_CST);
+}
+
+uint32_t Xchg (uint32_t *ptr, uint32_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg")
+ __attribute__ ((no_split_stack));
+
+uint32_t
+Xchg (uint32_t *ptr, uint32_t new)
+{
+ return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+uint64_t Xchg64 (uint64_t *ptr, uint64_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg64")
+ __attribute__ ((no_split_stack));
+
+uint64_t
+Xchg64 (uint64_t *ptr, uint64_t new)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+uintptr_t Xchguintptr (uintptr_t *ptr, uintptr_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchguintptr")
+ __attribute__ ((no_split_stack));
+
+uintptr_t
+Xchguintptr (uintptr_t *ptr, uintptr_t new)
+{
+ return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+void And8 (uint8_t *ptr, uint8_t val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.And8")
+ __attribute__ ((no_split_stack));
+
+void
+And8 (uint8_t *ptr, uint8_t val)
+{
+ __atomic_and_fetch (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Or8 (uint8_t *ptr, uint8_t val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Or8")
+ __attribute__ ((no_split_stack));
+
+void
+Or8 (uint8_t *ptr, uint8_t val)
+{
+ __atomic_or_fetch (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+_Bool Cas (uint32_t *ptr, uint32_t old, uint32_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas")
+ __attribute__ ((no_split_stack));
+
+_Bool
+Cas (uint32_t *ptr, uint32_t old, uint32_t new)
+{
+ return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Cas64 (uint64_t *ptr, uint64_t old, uint64_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas64")
+ __attribute__ ((no_split_stack));
+
+_Bool
+Cas64 (uint64_t *ptr, uint64_t old, uint64_t new)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Casp1 (void **ptr, void *old, void *new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casp1")
+ __attribute__ ((no_split_stack));
+
+_Bool
+Casp1 (void **ptr, void *old, void *new)
+{
+ return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Casuintptr (uintptr_t *ptr, uintptr_t old, uintptr_t new)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casuintptr")
+ __attribute__ ((no_split_stack));
+
+_Bool
+Casuintptr (uintptr_t *ptr, uintptr_t old, uintptr_t new)
+{
+ return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void Store (uint32_t *ptr, uint32_t val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store")
+ __attribute__ ((no_split_stack));
+
+void
+Store (uint32_t *ptr, uint32_t val)
+{
+ __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Store64 (uint64_t *ptr, uint64_t val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store64")
+ __attribute__ ((no_split_stack));
+
+void
+Store64 (uint64_t *ptr, uint64_t val)
+{
+ if (((uintptr_t) ptr & 7) != 0)
+ ptr = NULL;
+ __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Storeuintptr (uintptr_t *ptr, uintptr_t val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Storeuintptr")
+ __attribute__ ((no_split_stack));
+
+void
+Storeuintptr (uintptr_t *ptr, uintptr_t val)
+{
+ __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void StorepNoWB (void *ptr, void *val)
+ __asm__ (GOSYM_PREFIX "runtime_internal_atomic.StorepNoWB")
+ __attribute__ ((no_split_stack));
+
+void
+StorepNoWB (void *ptr, void *val)
+{
+ __atomic_store_n ((void**) ptr, val, __ATOMIC_SEQ_CST);
+}
diff --git a/libgo/go/runtime/internal/atomic/atomic_test.go b/libgo/go/runtime/internal/atomic/atomic_test.go
new file mode 100644
index 0000000000..879a82f9c8
--- /dev/null
+++ b/libgo/go/runtime/internal/atomic/atomic_test.go
@@ -0,0 +1,105 @@
+// 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 atomic_test
+
+import (
+ "runtime"
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "testing"
+ "unsafe"
+)
+
+func runParallel(N, iter int, f func()) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(int(N)))
+ done := make(chan bool)
+ for i := 0; i < N; i++ {
+ go func() {
+ for j := 0; j < iter; j++ {
+ f()
+ }
+ done <- true
+ }()
+ }
+ for i := 0; i < N; i++ {
+ <-done
+ }
+}
+
+func TestXadduintptr(t *testing.T) {
+ const N = 20
+ const iter = 100000
+ inc := uintptr(100)
+ total := uintptr(0)
+ runParallel(N, iter, func() {
+ atomic.Xadduintptr(&total, inc)
+ })
+ if want := uintptr(N * iter * inc); want != total {
+ t.Fatalf("xadduintpr error, want %d, got %d", want, total)
+ }
+ total = 0
+ runParallel(N, iter, func() {
+ atomic.Xadduintptr(&total, inc)
+ atomic.Xadduintptr(&total, uintptr(-int64(inc)))
+ })
+ if total != 0 {
+ t.Fatalf("xadduintpr total error, want %d, got %d", 0, total)
+ }
+}
+
+// Tests that xadduintptr correctly updates 64-bit values. The place where
+// we actually do so is mstats.go, functions mSysStat{Inc,Dec}.
+func TestXadduintptrOnUint64(t *testing.T) {
+ if sys.BigEndian != 0 {
+ // On big endian architectures, we never use xadduintptr to update
+ // 64-bit values and hence we skip the test. (Note that functions
+ // mSysStat{Inc,Dec} in mstats.go have explicit checks for
+ // big-endianness.)
+ t.Skip("skip xadduintptr on big endian architecture")
+ }
+ const inc = 100
+ val := uint64(0)
+ atomic.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc)
+ if inc != val {
+ t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val)
+ }
+}
+
+func shouldPanic(t *testing.T, name string, f func()) {
+ defer func() {
+ if recover() == nil {
+ t.Errorf("%s did not panic", name)
+ }
+ }()
+ f()
+}
+
+// Variant of sync/atomic's TestUnaligned64:
+func TestUnaligned64(t *testing.T) {
+ // Unaligned 64-bit atomics on 32-bit systems are
+ // a continual source of pain. Test that on 32-bit systems they crash
+ // instead of failing silently.
+
+ switch runtime.GOARCH {
+ default:
+ if unsafe.Sizeof(int(0)) != 4 {
+ t.Skip("test only runs on 32-bit systems")
+ }
+ case "amd64p32":
+ // amd64p32 can handle unaligned atomics.
+ t.Skipf("test not needed on %v", runtime.GOARCH)
+ }
+
+ x := make([]uint32, 4)
+ up64 := (*uint64)(unsafe.Pointer(&x[1])) // misaligned
+ p64 := (*int64)(unsafe.Pointer(&x[1])) // misaligned
+
+ shouldPanic(t, "Load64", func() { atomic.Load64(up64) })
+ shouldPanic(t, "Loadint64", func() { atomic.Loadint64(p64) })
+ shouldPanic(t, "Store64", func() { atomic.Store64(up64, 0) })
+ shouldPanic(t, "Xadd64", func() { atomic.Xadd64(up64, 1) })
+ shouldPanic(t, "Xchg64", func() { atomic.Xchg64(up64, 1) })
+ shouldPanic(t, "Cas64", func() { atomic.Cas64(up64, 1, 2) })
+}
diff --git a/libgo/go/runtime/internal/atomic/bench_test.go b/libgo/go/runtime/internal/atomic/bench_test.go
new file mode 100644
index 0000000000..47010e32d5
--- /dev/null
+++ b/libgo/go/runtime/internal/atomic/bench_test.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic_test
+
+import (
+ "runtime/internal/atomic"
+ "testing"
+)
+
+var sink interface{}
+
+func BenchmarkAtomicLoad64(b *testing.B) {
+ var x uint64
+ sink = &x
+ for i := 0; i < b.N; i++ {
+ _ = atomic.Load64(&x)
+ }
+}
+
+func BenchmarkAtomicStore64(b *testing.B) {
+ var x uint64
+ sink = &x
+ for i := 0; i < b.N; i++ {
+ atomic.Store64(&x, 0)
+ }
+}
diff --git a/libgo/go/runtime/internal/atomic/gccgo.go b/libgo/go/runtime/internal/atomic/gccgo.go
new file mode 100644
index 0000000000..696736465f
--- /dev/null
+++ b/libgo/go/runtime/internal/atomic/gccgo.go
@@ -0,0 +1,59 @@
+// 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 atomic
+
+// Stubs for atomic functions that in gccgo are implemented in C.
+
+import "unsafe"
+
+//go:noescape
+func Load(ptr *uint32) uint32
+
+//go:noescape
+func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func Load64(ptr *uint64) uint64
+
+//go:noescape
+func Xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func Xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
+func Xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func Xchg64(ptr *uint64, new uint64) uint64
+
+//go:noescape
+func Xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func And8(ptr *uint8, val uint8)
+
+//go:noescape
+func Or8(ptr *uint8, val uint8)
+
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
+//go:noescape
+func Cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func Store(ptr *uint32, val uint32)
+
+//go:noescape
+func Store64(ptr *uint64, val uint64)
+
+// StorepNoWB performs *ptr = val atomically and without a write
+// barrier.
+//
+// NO go:noescape annotation; see atomic_pointer.go.
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/libgo/go/runtime/internal/atomic/stubs.go b/libgo/go/runtime/internal/atomic/stubs.go
new file mode 100644
index 0000000000..497b98046d
--- /dev/null
+++ b/libgo/go/runtime/internal/atomic/stubs.go
@@ -0,0 +1,33 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic
+
+import "unsafe"
+
+//go:noescape
+func Cas(ptr *uint32, old, new uint32) bool
+
+// NO go:noescape annotation; see atomic_pointer.go.
+func Casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+
+//go:noescape
+func Casuintptr(ptr *uintptr, old, new uintptr) bool
+
+//go:noescape
+func Storeuintptr(ptr *uintptr, new uintptr)
+
+//go:noescape
+func Loaduintptr(ptr *uintptr) uintptr
+
+//go:noescape
+func Loaduint(ptr *uint) uint
+
+// TODO(matloob): Should these functions have the go:noescape annotation?
+
+//go:noescape
+func Loadint64(ptr *int64) int64
+
+//go:noescape
+func Xaddint64(ptr *int64, delta int64) int64
diff --git a/libgo/go/runtime/internal/sys/intrinsics.go b/libgo/go/runtime/internal/sys/intrinsics.go
new file mode 100644
index 0000000000..43acf34b80
--- /dev/null
+++ b/libgo/go/runtime/internal/sys/intrinsics.go
@@ -0,0 +1,55 @@
+// 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 sys
+
+//extern __builtin_ctz
+func builtinCtz32(uint32) int32
+
+//extern __builtin_ctzll
+func builtinCtz64(uint64) int32
+
+//go:nosplit
+
+// Ctz64 counts trailing (low-order) zeroes,
+// and if all are zero, then 64.
+func Ctz64(x uint64) uint64 {
+ if x == 0 {
+ return 64
+ }
+ return uint64(builtinCtz64(x))
+}
+
+//go:nosplit
+
+// Ctz32 counts trailing (low-order) zeroes,
+// and if all are zero, then 32.
+func Ctz32(x uint32) uint32 {
+ if x == 0 {
+ return 32
+ }
+ return uint32(builtinCtz32(x))
+}
+
+//extern __builtin_bswap64
+func bswap64(uint64) uint64
+
+//go:nosplit
+
+// Bswap64 returns its input with byte order reversed
+// 0x0102030405060708 -> 0x0807060504030201
+func Bswap64(x uint64) uint64 {
+ return bswap64(x)
+}
+
+//extern __builtin_bswap32
+func bswap32(uint32) uint32
+
+//go:nosplit
+
+// Bswap32 returns its input with byte order reversed
+// 0x01020304 -> 0x04030201
+func Bswap32(x uint32) uint32 {
+ return bswap32(x)
+}
diff --git a/libgo/go/runtime/internal/sys/intrinsics_test.go b/libgo/go/runtime/internal/sys/intrinsics_test.go
new file mode 100644
index 0000000000..1f2c8daa96
--- /dev/null
+++ b/libgo/go/runtime/internal/sys/intrinsics_test.go
@@ -0,0 +1,38 @@
+package sys_test
+
+import (
+ "runtime/internal/sys"
+ "testing"
+)
+
+func TestCtz64(t *testing.T) {
+ for i := uint(0); i <= 64; i++ {
+ x := uint64(5) << i
+ if got := sys.Ctz64(x); got != uint64(i) {
+ t.Errorf("Ctz64(%d)=%d, want %d", x, got, i)
+ }
+ }
+}
+func TestCtz32(t *testing.T) {
+ for i := uint(0); i <= 32; i++ {
+ x := uint32(5) << i
+ if got := sys.Ctz32(x); got != uint32(i) {
+ t.Errorf("Ctz32(%d)=%d, want %d", x, got, i)
+ }
+ }
+}
+
+func TestBswap64(t *testing.T) {
+ x := uint64(0x1122334455667788)
+ y := sys.Bswap64(x)
+ if y != 0x8877665544332211 {
+ t.Errorf("Bswap(%x)=%x, want 0x8877665544332211", x, y)
+ }
+}
+func TestBswap32(t *testing.T) {
+ x := uint32(0x11223344)
+ y := sys.Bswap32(x)
+ if y != 0x44332211 {
+ t.Errorf("Bswap(%x)=%x, want 0x44332211", x, y)
+ }
+}
diff --git a/libgo/go/runtime/internal/sys/stubs.go b/libgo/go/runtime/internal/sys/stubs.go
new file mode 100644
index 0000000000..0a94502f32
--- /dev/null
+++ b/libgo/go/runtime/internal/sys/stubs.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+// Declarations for runtime services implemented in C or assembly.
+
+const PtrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
+const RegSize = 4 << (^Uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const
+const SpAlign = 1*(1-GoarchArm64) + 16*GoarchArm64 // SP alignment: 1 normally, 16 for ARM64
diff --git a/libgo/go/runtime/internal/sys/sys.go b/libgo/go/runtime/internal/sys/sys.go
new file mode 100644
index 0000000000..586a763717
--- /dev/null
+++ b/libgo/go/runtime/internal/sys/sys.go
@@ -0,0 +1,15 @@
+// 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 sys contains system- and configuration- and architecture-specific
+// constants used by the runtime.
+package sys
+
+// The next line makes 'go generate' write the zgen_*.go files with
+// per-OS and per-arch information, including constants
+// named goos_$GOOS and goarch_$GOARCH for every
+// known GOOS and GOARCH. The constant is 1 on the
+// current system, 0 otherwise; multiplying by them is
+// useful for defining GOOS- or GOARCH-specific constants.
+//go:generate go run gengoos.go
diff --git a/libgo/go/runtime/lfstack.go b/libgo/go/runtime/lfstack.go
new file mode 100644
index 0000000000..2f2958c886
--- /dev/null
+++ b/libgo/go/runtime/lfstack.go
@@ -0,0 +1,50 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lock-free stack.
+// Initialize head to 0, compare with 0 to test for emptiness.
+// The stack does not keep pointers to nodes,
+// so they can be garbage collected if there are no other pointers to nodes.
+// The following code runs only in non-preemptible contexts.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// Temporary for C code to call:
+//go:linkname lfstackpush runtime.lfstackpush
+//go:linkname lfstackpop runtime.lfstackpop
+
+func lfstackpush(head *uint64, node *lfnode) {
+ node.pushcnt++
+ new := lfstackPack(node, node.pushcnt)
+ if node1 := lfstackUnpack(new); node1 != node {
+ print("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n")
+ throw("lfstackpush")
+ }
+ for {
+ old := atomic.Load64(head)
+ node.next = old
+ if atomic.Cas64(head, old, new) {
+ break
+ }
+ }
+}
+
+func lfstackpop(head *uint64) unsafe.Pointer {
+ for {
+ old := atomic.Load64(head)
+ if old == 0 {
+ return nil
+ }
+ node := lfstackUnpack(old)
+ next := atomic.Load64(&node.next)
+ if atomic.Cas64(head, old, next) {
+ return unsafe.Pointer(node)
+ }
+ }
+}
diff --git a/libgo/go/runtime/lfstack_32bit.go b/libgo/go/runtime/lfstack_32bit.go
new file mode 100644
index 0000000000..bc53b13c41
--- /dev/null
+++ b/libgo/go/runtime/lfstack_32bit.go
@@ -0,0 +1,19 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le mipso32 mipsn32 ppc s390 sparc
+
+package runtime
+
+import "unsafe"
+
+// On 32-bit systems, the stored uint64 has a 32-bit pointer and 32-bit count.
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+ return uint64(uintptr(unsafe.Pointer(node)))<<32 | uint64(cnt)
+}
+
+func lfstackUnpack(val uint64) *lfnode {
+ return (*lfnode)(unsafe.Pointer(uintptr(val >> 32)))
+}
diff --git a/libgo/go/runtime/lfstack_64bit.go b/libgo/go/runtime/lfstack_64bit.go
new file mode 100644
index 0000000000..213efb1070
--- /dev/null
+++ b/libgo/go/runtime/lfstack_64bit.go
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64 arm64 mips64 mips64le ppc64 ppc64le s390x arm64be alpha mipsn64 sparc64
+
+package runtime
+
+import "unsafe"
+
+const (
+ // addrBits is the number of bits needed to represent a virtual address.
+ //
+ // In Linux the user address space for each architecture is limited as
+ // follows (taken from the processor.h file for the architecture):
+ //
+ // Architecture Name Maximum Value (exclusive)
+ // ---------------------------------------------------------------------
+ // arm64 TASK_SIZE_64 Depends on configuration.
+ // ppc64{,le} TASK_SIZE_USER64 0x400000000000UL (46 bit addresses)
+ // mips64{,le} TASK_SIZE64 0x010000000000UL (40 bit addresses)
+ // s390x TASK_SIZE 0x020000000000UL (41 bit addresses)
+ //
+ // These values may increase over time.
+ //
+ // On AMD64, virtual addresses are 48-bit numbers sign extended to 64.
+ // We shift the address left 16 to eliminate the sign extended part and make
+ // room in the bottom for the count.
+ addrBits = 48
+
+ // In addition to the 16 bits taken from the top, we can take 3 from the
+ // bottom, because node must be pointer-aligned, giving a total of 19 bits
+ // of count.
+ cntBits = 64 - addrBits + 3
+)
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+ return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
+}
+
+func lfstackUnpack(val uint64) *lfnode {
+ if GOARCH == "amd64" || GOOS == "solaris" {
+ // amd64 or Solaris systems can place the stack above the VA hole, so we need to sign extend
+ // val before unpacking.
+ return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3)))
+ }
+ return (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+}
diff --git a/libgo/go/runtime/lfstack_linux_mips64x.go b/libgo/go/runtime/lfstack_linux_mips64x.go
deleted file mode 100644
index 49b65585f4..0000000000
--- a/libgo/go/runtime/lfstack_linux_mips64x.go
+++ /dev/null
@@ -1,32 +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 mips64 mips64le
-// +build linux
-
-package runtime
-
-import "unsafe"
-
-// On mips64, Linux limits the user address space to 40 bits (see
-// TASK_SIZE64 in the Linux kernel). This has grown over time,
-// so here we allow 48 bit addresses.
-//
-// In addition to the 16 bits taken from the top, we can take 3 from the
-// bottom, because node must be pointer-aligned, giving a total of 19 bits
-// of count.
-const (
- addrBits = 48
- cntBits = 64 - addrBits + 3
-)
-
-func lfstackPack(node *lfnode, cnt uintptr) uint64 {
- return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
-}
-
-func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
- node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
- cnt = uintptr(val & (1<<cntBits - 1))
- return
-}
diff --git a/libgo/go/runtime/lock_futex.go b/libgo/go/runtime/lock_futex.go
new file mode 100644
index 0000000000..4d914b25fa
--- /dev/null
+++ b/libgo/go/runtime/lock_futex.go
@@ -0,0 +1,224 @@
+// 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.
+
+// +build dragonfly freebsd linux
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname lock runtime.lock
+//go:linkname unlock runtime.unlock
+//go:linkname noteclear runtime.noteclear
+//go:linkname notewakeup runtime.notewakeup
+//go:linkname notesleep runtime.notesleep
+//go:linkname notetsleep runtime.notetsleep
+//go:linkname notetsleepg runtime.notetsleepg
+
+// This implementation depends on OS-specific implementations of
+//
+// futexsleep(addr *uint32, val uint32, ns int64)
+// Atomically,
+// if *addr == val { sleep }
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//
+// futexwakeup(addr *uint32, cnt uint32)
+// If any procs are sleeping on addr, wake up at most cnt.
+
+const (
+ mutex_unlocked = 0
+ mutex_locked = 1
+ mutex_sleeping = 2
+
+ active_spin = 4
+ active_spin_cnt = 30
+ passive_spin = 1
+)
+
+// Possible lock states are mutex_unlocked, mutex_locked and mutex_sleeping.
+// mutex_sleeping means that there is presumably at least one sleeping thread.
+// Note that there can be spinning threads during all states - they do not
+// affect mutex's state.
+
+// We use the uintptr mutex.key and note.key as a uint32.
+func key32(p *uintptr) *uint32 {
+ return (*uint32)(unsafe.Pointer(p))
+}
+
+func lock(l *mutex) {
+ gp := getg()
+
+ if gp.m.locks < 0 {
+ throw("runtime·lock: lock count")
+ }
+ gp.m.locks++
+
+ // Speculative grab for lock.
+ v := atomic.Xchg(key32(&l.key), mutex_locked)
+ if v == mutex_unlocked {
+ return
+ }
+
+ // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
+ // depending on whether there is a thread sleeping
+ // on this mutex. If we ever change l->key from
+ // MUTEX_SLEEPING to some other value, we must be
+ // careful to change it back to MUTEX_SLEEPING before
+ // returning, to ensure that the sleeping thread gets
+ // its wakeup call.
+ wait := v
+
+ // On uniprocessors, no point spinning.
+ // On multiprocessors, spin for ACTIVE_SPIN attempts.
+ spin := 0
+ if ncpu > 1 {
+ spin = active_spin
+ }
+ for {
+ // Try for lock, spinning.
+ for i := 0; i < spin; i++ {
+ for l.key == mutex_unlocked {
+ if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
+ return
+ }
+ }
+ procyield(active_spin_cnt)
+ }
+
+ // Try for lock, rescheduling.
+ for i := 0; i < passive_spin; i++ {
+ for l.key == mutex_unlocked {
+ if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
+ return
+ }
+ }
+ osyield()
+ }
+
+ // Sleep.
+ v = atomic.Xchg(key32(&l.key), mutex_sleeping)
+ if v == mutex_unlocked {
+ return
+ }
+ wait = mutex_sleeping
+ futexsleep(key32(&l.key), mutex_sleeping, -1)
+ }
+}
+
+func unlock(l *mutex) {
+ v := atomic.Xchg(key32(&l.key), mutex_unlocked)
+ if v == mutex_unlocked {
+ throw("unlock of unlocked lock")
+ }
+ if v == mutex_sleeping {
+ futexwakeup(key32(&l.key), 1)
+ }
+
+ gp := getg()
+ gp.m.locks--
+ if gp.m.locks < 0 {
+ throw("runtime·unlock: lock count")
+ }
+ // if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
+ // gp.stackguard0 = stackPreempt
+ // }
+}
+
+// One-time notifications.
+func noteclear(n *note) {
+ n.key = 0
+}
+
+func notewakeup(n *note) {
+ old := atomic.Xchg(key32(&n.key), 1)
+ if old != 0 {
+ print("notewakeup - double wakeup (", old, ")\n")
+ throw("notewakeup - double wakeup")
+ }
+ futexwakeup(key32(&n.key), 1)
+}
+
+func notesleep(n *note) {
+ gp := getg()
+ if gp != gp.m.g0 {
+ throw("notesleep not on g0")
+ }
+ for atomic.Load(key32(&n.key)) == 0 {
+ gp.m.blocked = true
+ futexsleep(key32(&n.key), 0, -1)
+ gp.m.blocked = false
+ }
+}
+
+// May run with m.p==nil if called from notetsleep, so write barriers
+// are not allowed.
+//
+//go:nosplit
+//go:nowritebarrier
+func notetsleep_internal(n *note, ns int64) bool {
+ gp := getg()
+
+ if ns < 0 {
+ for atomic.Load(key32(&n.key)) == 0 {
+ gp.m.blocked = true
+ futexsleep(key32(&n.key), 0, -1)
+ gp.m.blocked = false
+ }
+ return true
+ }
+
+ if atomic.Load(key32(&n.key)) != 0 {
+ return true
+ }
+
+ deadline := nanotime() + ns
+ for {
+ gp.m.blocked = true
+ futexsleep(key32(&n.key), 0, ns)
+ gp.m.blocked = false
+ if atomic.Load(key32(&n.key)) != 0 {
+ break
+ }
+ now := nanotime()
+ if now >= deadline {
+ break
+ }
+ ns = deadline - now
+ }
+ return atomic.Load(key32(&n.key)) != 0
+}
+
+func notetsleep(n *note, ns int64) bool {
+ // Currently OK to sleep in non-g0 for gccgo. It happens in
+ // stoptheworld because our version of systemstack does not
+ // change to g0.
+ // gp := getg()
+ // if gp != gp.m.g0 && gp.m.preemptoff != "" {
+ // throw("notetsleep not on g0")
+ // }
+
+ return notetsleep_internal(n, ns)
+}
+
+// same as runtime·notetsleep, but called on user g (not g0)
+// calls only nosplit functions between entersyscallblock/exitsyscall
+func notetsleepg(n *note, ns int64) bool {
+ gp := getg()
+ if gp == gp.m.g0 {
+ throw("notetsleepg on g0")
+ }
+
+ entersyscallblock(0)
+ ok := notetsleep_internal(n, ns)
+ exitsyscall(0)
+ return ok
+}
diff --git a/libgo/go/runtime/lock_sema.go b/libgo/go/runtime/lock_sema.go
new file mode 100644
index 0000000000..5c70a747da
--- /dev/null
+++ b/libgo/go/runtime/lock_sema.go
@@ -0,0 +1,278 @@
+// 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.
+
+// +build darwin nacl netbsd openbsd plan9 solaris windows
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname lock runtime.lock
+//go:linkname unlock runtime.unlock
+//go:linkname noteclear runtime.noteclear
+//go:linkname notewakeup runtime.notewakeup
+//go:linkname notesleep runtime.notesleep
+//go:linkname notetsleep runtime.notetsleep
+//go:linkname notetsleepg runtime.notetsleepg
+
+// This implementation depends on OS-specific implementations of
+//
+// func semacreate(mp *m)
+// Create a semaphore for mp, if it does not already have one.
+//
+// func semasleep(ns int64) int32
+// If ns < 0, acquire m's semaphore and return 0.
+// If ns >= 0, try to acquire m's semaphore for at most ns nanoseconds.
+// Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
+//
+// func semawakeup(mp *m)
+// Wake up mp, which is or will soon be sleeping on its semaphore.
+//
+const (
+ mutex_locked uintptr = 1
+
+ active_spin = 4
+ active_spin_cnt = 30
+ passive_spin = 1
+)
+
+func lock(l *mutex) {
+ gp := getg()
+ if gp.m.locks < 0 {
+ throw("runtime·lock: lock count")
+ }
+ gp.m.locks++
+
+ // Speculative grab for lock.
+ if atomic.Casuintptr(&l.key, 0, mutex_locked) {
+ return
+ }
+ semacreate(gp.m)
+
+ // On uniprocessor's, no point spinning.
+ // On multiprocessors, spin for ACTIVE_SPIN attempts.
+ spin := 0
+ if ncpu > 1 {
+ spin = active_spin
+ }
+Loop:
+ for i := 0; ; i++ {
+ v := atomic.Loaduintptr(&l.key)
+ if v&mutex_locked == 0 {
+ // Unlocked. Try to lock.
+ if atomic.Casuintptr(&l.key, v, v|mutex_locked) {
+ return
+ }
+ i = 0
+ }
+ if i < spin {
+ procyield(active_spin_cnt)
+ } else if i < spin+passive_spin {
+ osyield()
+ } else {
+ // Someone else has it.
+ // l->waitm points to a linked list of M's waiting
+ // for this lock, chained through m->nextwaitm.
+ // Queue this M.
+ for {
+ gp.m.nextwaitm = v &^ mutex_locked
+ if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|mutex_locked) {
+ break
+ }
+ v = atomic.Loaduintptr(&l.key)
+ if v&mutex_locked == 0 {
+ continue Loop
+ }
+ }
+ if v&mutex_locked != 0 {
+ // Queued. Wait.
+ semasleep(-1)
+ i = 0
+ }
+ }
+ }
+}
+
+//go:nowritebarrier
+// We might not be holding a p in this code.
+func unlock(l *mutex) {
+ gp := getg()
+ var mp *m
+ for {
+ v := atomic.Loaduintptr(&l.key)
+ if v == mutex_locked {
+ if atomic.Casuintptr(&l.key, mutex_locked, 0) {
+ break
+ }
+ } else {
+ // Other M's are waiting for the lock.
+ // Dequeue an M.
+ mp = (*m)(unsafe.Pointer(v &^ mutex_locked))
+ if atomic.Casuintptr(&l.key, v, mp.nextwaitm) {
+ // Dequeued an M. Wake it.
+ semawakeup(mp)
+ break
+ }
+ }
+ }
+ gp.m.locks--
+ if gp.m.locks < 0 {
+ throw("runtime·unlock: lock count")
+ }
+ // if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
+ // gp.stackguard0 = stackPreempt
+ // }
+}
+
+// One-time notifications.
+func noteclear(n *note) {
+ n.key = 0
+}
+
+func notewakeup(n *note) {
+ var v uintptr
+ for {
+ v = atomic.Loaduintptr(&n.key)
+ if atomic.Casuintptr(&n.key, v, mutex_locked) {
+ break
+ }
+ }
+
+ // Successfully set waitm to locked.
+ // What was it before?
+ switch {
+ case v == 0:
+ // Nothing was waiting. Done.
+ case v == mutex_locked:
+ // Two notewakeups! Not allowed.
+ throw("notewakeup - double wakeup")
+ default:
+ // Must be the waiting m. Wake it up.
+ semawakeup((*m)(unsafe.Pointer(v)))
+ }
+}
+
+func notesleep(n *note) {
+ gp := getg()
+ if gp != gp.m.g0 {
+ throw("notesleep not on g0")
+ }
+ semacreate(gp.m)
+ if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
+ // Must be locked (got wakeup).
+ if n.key != mutex_locked {
+ throw("notesleep - waitm out of sync")
+ }
+ return
+ }
+ // Queued. Sleep.
+ gp.m.blocked = true
+ semasleep(-1)
+ gp.m.blocked = false
+}
+
+//go:nosplit
+func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
+ // gp and deadline are logically local variables, but they are written
+ // as parameters so that the stack space they require is charged
+ // to the caller.
+ // This reduces the nosplit footprint of notetsleep_internal.
+ gp = getg()
+
+ // Register for wakeup on n->waitm.
+ if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
+ // Must be locked (got wakeup).
+ if n.key != mutex_locked {
+ throw("notetsleep - waitm out of sync")
+ }
+ return true
+ }
+ if ns < 0 {
+ // Queued. Sleep.
+ gp.m.blocked = true
+ semasleep(-1)
+ gp.m.blocked = false
+ return true
+ }
+
+ deadline = nanotime() + ns
+ for {
+ // Registered. Sleep.
+ gp.m.blocked = true
+ if semasleep(ns) >= 0 {
+ gp.m.blocked = false
+ // Acquired semaphore, semawakeup unregistered us.
+ // Done.
+ return true
+ }
+ gp.m.blocked = false
+ // Interrupted or timed out. Still registered. Semaphore not acquired.
+ ns = deadline - nanotime()
+ if ns <= 0 {
+ break
+ }
+ // Deadline hasn't arrived. Keep sleeping.
+ }
+
+ // Deadline arrived. Still registered. Semaphore not acquired.
+ // Want to give up and return, but have to unregister first,
+ // so that any notewakeup racing with the return does not
+ // try to grant us the semaphore when we don't expect it.
+ for {
+ v := atomic.Loaduintptr(&n.key)
+ switch v {
+ case uintptr(unsafe.Pointer(gp.m)):
+ // No wakeup yet; unregister if possible.
+ if atomic.Casuintptr(&n.key, v, 0) {
+ return false
+ }
+ case mutex_locked:
+ // Wakeup happened so semaphore is available.
+ // Grab it to avoid getting out of sync.
+ gp.m.blocked = true
+ if semasleep(-1) < 0 {
+ throw("runtime: unable to acquire - semaphore out of sync")
+ }
+ gp.m.blocked = false
+ return true
+ default:
+ throw("runtime: unexpected waitm - semaphore out of sync")
+ }
+ }
+}
+
+func notetsleep(n *note, ns int64) bool {
+ gp := getg()
+
+ // Currently OK to sleep in non-g0 for gccgo. It happens in
+ // stoptheworld because our version of systemstack does not
+ // change to g0.
+ // if gp != gp.m.g0 && gp.m.preemptoff != "" {
+ // throw("notetsleep not on g0")
+ // }
+
+ semacreate(gp.m)
+ return notetsleep_internal(n, ns, nil, 0)
+}
+
+// same as runtime·notetsleep, but called on user g (not g0)
+// calls only nosplit functions between entersyscallblock/exitsyscall
+func notetsleepg(n *note, ns int64) bool {
+ gp := getg()
+ if gp == gp.m.g0 {
+ throw("notetsleepg on g0")
+ }
+ semacreate(gp.m)
+ entersyscallblock(0)
+ ok := notetsleep_internal(n, ns, nil, 0)
+ exitsyscall(0)
+ return ok
+}
diff --git a/libgo/go/runtime/malloc_test.go b/libgo/go/runtime/malloc_test.go
index 4f9262760e..bc5530c2f2 100644
--- a/libgo/go/runtime/malloc_test.go
+++ b/libgo/go/runtime/malloc_test.go
@@ -14,6 +14,10 @@ import (
func TestMemStats(t *testing.T) {
t.Skip("skipping test with gccgo")
+
+ // Make sure there's at least one forced GC.
+ GC()
+
// Test that MemStats has sane values.
st := new(MemStats)
ReadMemStats(st)
@@ -25,7 +29,7 @@ func TestMemStats(t *testing.T) {
st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 ||
st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 ||
st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 ||
- st.NextGC == 0 {
+ st.NextGC == 0 || st.NumForcedGC == 0 {
t.Fatalf("Zero value: %+v", *st)
}
@@ -34,7 +38,7 @@ func TestMemStats(t *testing.T) {
st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
- st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 {
+ st.NextGC > 1e10 || st.NumGC > 1e9 || st.NumForcedGC > 1e9 || st.PauseTotalNs > 1e11 {
t.Fatalf("Insanely high value (overflow?): %+v", *st)
}
if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+
@@ -72,6 +76,10 @@ func TestMemStats(t *testing.T) {
t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
}
}
+
+ if st.NumForcedGC > st.NumGC {
+ t.Fatalf("NumForcedGC(%d) > NumGC(%d)", st.NumForcedGC, st.NumGC)
+ }
}
func TestStringConcatenationAllocs(t *testing.T) {
diff --git a/libgo/go/runtime/map_test.go b/libgo/go/runtime/map_test.go
index ed0347a453..9b5b051250 100644
--- a/libgo/go/runtime/map_test.go
+++ b/libgo/go/runtime/map_test.go
@@ -30,13 +30,11 @@ func TestNegativeZero(t *testing.T) {
t.Error("length wrong")
}
- /* gccgo fails this test; this is not required by the spec.
for k := range m {
if math.Copysign(1.0, k) > 0 {
t.Error("wrong sign")
}
}
- */
m = make(map[float64]bool, 0)
m[math.Copysign(0.0, -1.0)] = true
@@ -46,13 +44,11 @@ func TestNegativeZero(t *testing.T) {
t.Error("length wrong")
}
- /* gccgo fails this test; this is not required by the spec.
for k := range m {
if math.Copysign(1.0, k) < 0 {
t.Error("wrong sign")
}
}
- */
}
// nan is a good test because nan != nan, and nan has
@@ -93,7 +89,6 @@ func TestAlias(t *testing.T) {
}
func TestGrowWithNaN(t *testing.T) {
- t.Skip("fails with gccgo")
m := make(map[float64]int, 4)
nan := math.NaN()
m[nan] = 1
@@ -115,7 +110,6 @@ func TestGrowWithNaN(t *testing.T) {
s |= v
}
}
- t.Log("cnt:", cnt, "s:", s)
if cnt != 3 {
t.Error("NaN keys lost during grow")
}
@@ -130,7 +124,6 @@ type FloatInt struct {
}
func TestGrowWithNegativeZero(t *testing.T) {
- t.Skip("fails with gccgo")
negzero := math.Copysign(0.0, -1.0)
m := make(map[FloatInt]int, 4)
m[FloatInt{0.0, 0}] = 1
@@ -242,6 +235,7 @@ func TestIterGrowWithGC(t *testing.T) {
}
func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
+ t.Parallel()
if runtime.GOMAXPROCS(-1) == 1 {
if runtime.GOARCH == "s390" {
// Test uses too much address space on 31-bit S390.
@@ -329,6 +323,22 @@ func TestBigItems(t *testing.T) {
}
}
+func TestMapHugeZero(t *testing.T) {
+ type T [4000]byte
+ m := map[int]T{}
+ x := m[0]
+ if x != (T{}) {
+ t.Errorf("map value not zero")
+ }
+ y, ok := m[0]
+ if ok {
+ t.Errorf("map value should be missing")
+ }
+ if y != (T{}) {
+ t.Errorf("map value not zero")
+ }
+}
+
type empty struct {
}
@@ -391,7 +401,7 @@ func TestMapNanGrowIterator(t *testing.T) {
nan := math.NaN()
const nBuckets = 16
// To fill nBuckets buckets takes LOAD * nBuckets keys.
- nKeys := int(nBuckets * /* *runtime.HashLoad */ 6.5)
+ nKeys := int(nBuckets * *runtime.HashLoad)
// Get map to full point with nan keys.
for i := 0; i < nKeys; i++ {
@@ -423,10 +433,6 @@ func TestMapNanGrowIterator(t *testing.T) {
}
func TestMapIterOrder(t *testing.T) {
- if runtime.Compiler == "gccgo" {
- t.Skip("skipping for gccgo")
- }
-
for _, n := range [...]int{3, 7, 9, 15} {
for i := 0; i < 1000; i++ {
// Make m be {0: true, 1: true, ..., n-1: true}.
@@ -462,9 +468,6 @@ func TestMapIterOrder(t *testing.T) {
func TestMapSparseIterOrder(t *testing.T) {
// Run several rounds to increase the probability
// of failure. One is not enough.
- if runtime.Compiler == "gccgo" {
- t.Skip("skipping for gccgo")
- }
NextRound:
for round := 0; round < 10; round++ {
m := make(map[int]bool)
@@ -498,9 +501,6 @@ NextRound:
}
func TestMapStringBytesLookup(t *testing.T) {
- if runtime.Compiler == "gccgo" {
- t.Skip("skipping for gccgo")
- }
// Use large string keys to avoid small-allocation coalescing,
// which can cause AllocsPerRun to report lower counts than it should.
m := map[string]int{
@@ -516,6 +516,8 @@ func TestMapStringBytesLookup(t *testing.T) {
t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
}
+ t.Skip("does not work on gccgo without better escape analysis")
+
var x int
n := testing.AllocsPerRun(100, func() {
x += m[string(buf)]
diff --git a/libgo/go/runtime/mcache.go b/libgo/go/runtime/mcache.go
new file mode 100644
index 0000000000..b65dd37421
--- /dev/null
+++ b/libgo/go/runtime/mcache.go
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// This is a temporary mcache.go for gccgo.
+// At some point it will be replaced by the one in the gc runtime package.
+
+import "unsafe"
+
+type mcachelist struct {
+ list *mlink
+ nlist uint32
+}
+
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
+//
+// mcaches are allocated from non-GC'd memory, so any heap pointers
+// must be specially handled.
+//
+//go:notinheap
+type mcache struct {
+ // The following members are accessed on every malloc,
+ // so they are grouped here for better caching.
+ next_sample int32 // trigger heap sample after allocating this many bytes
+ local_cachealloc uintptr // bytes allocated (or freed) from cache since last lock of heap
+
+ // Allocator cache for tiny objects w/o pointers.
+ // See "Tiny allocator" comment in malloc.go.
+
+ // tiny points to the beginning of the current tiny block, or
+ // nil if there is no current tiny block.
+ //
+ // tiny is a heap pointer. Since mcache is in non-GC'd memory,
+ // we handle it by clearing it in releaseAll during mark
+ // termination.
+ tiny unsafe.Pointer
+ tinysize uintptr
+
+ // The rest is not accessed on every malloc.
+ alloc [_NumSizeClasses]*mspan // spans to allocate from
+ free [_NumSizeClasses]mcachelist // lists of explicitly freed objects
+
+ // Local allocator stats, flushed during GC.
+ local_nlookup uintptr // number of pointer lookups
+ local_largefree uintptr // bytes freed for large objects (>maxsmallsize)
+ local_nlargefree uintptr // number of frees for large objects (>maxsmallsize)
+ local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize)
+}
+
+type mtypes struct {
+ compression byte
+ data uintptr
+}
+
+type special struct {
+ next *special
+ offset uint16
+ kind byte
+}
+
+type mspan struct {
+ next *mspan // next span in list, or nil if none
+ prev *mspan // previous span's next field, or list head's first field if none
+ start uintptr
+ npages uintptr // number of pages in span
+ freelist *mlink
+
+ // sweep generation:
+ // if sweepgen == h->sweepgen - 2, the span needs sweeping
+ // if sweepgen == h->sweepgen - 1, the span is currently being swept
+ // if sweepgen == h->sweepgen, the span is swept and ready to use
+ // h->sweepgen is incremented by 2 after every GC
+
+ sweepgen uint32
+ ref uint16
+ sizeclass uint8 // size class
+ incache bool // being used by an mcache
+ state uint8 // mspaninuse etc
+ needzero uint8 // needs to be zeroed before allocation
+ elemsize uintptr // computed from sizeclass or from npages
+ unusedsince int64 // first time spotted by gc in mspanfree state
+ npreleased uintptr // number of pages released to the os
+ limit uintptr // end of data in span
+ types mtypes
+ speciallock mutex // guards specials list
+ specials *special // linked list of special records sorted by offset.
+ freebuf *mlink
+}
+
+type mlink struct {
+ next *mlink
+}
diff --git a/libgo/go/runtime/mem.go b/libgo/go/runtime/mem.go
deleted file mode 100644
index b41d741b93..0000000000
--- a/libgo/go/runtime/mem.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import "unsafe"
-
-// Note: the MemStats struct should be kept in sync with
-// struct MStats in malloc.h
-
-// A MemStats records statistics about the memory allocator.
-type MemStats struct {
- // General statistics.
- Alloc uint64 // bytes allocated and still in use
- TotalAlloc uint64 // bytes allocated (even if freed)
- Sys uint64 // bytes obtained from system (sum of XxxSys below)
- Lookups uint64 // number of pointer lookups
- Mallocs uint64 // number of mallocs
- Frees uint64 // number of frees
-
- // Main allocation heap statistics.
- HeapAlloc uint64 // bytes allocated and still in use
- HeapSys uint64 // bytes obtained from system
- HeapIdle uint64 // bytes in idle spans
- HeapInuse uint64 // bytes in non-idle span
- HeapReleased uint64 // bytes released to the OS
- HeapObjects uint64 // total number of allocated objects
-
- // Low-level fixed-size structure allocator statistics.
- // Inuse is bytes used now.
- // Sys is bytes obtained from system.
- StackInuse uint64 // bootstrap stacks
- StackSys uint64
- MSpanInuse uint64 // mspan structures
- MSpanSys uint64
- MCacheInuse uint64 // mcache structures
- MCacheSys uint64
- BuckHashSys uint64 // profiling bucket hash table
- GCSys uint64 // GC metadata
- OtherSys uint64 // other system allocations
-
- // Garbage collector statistics.
- NextGC uint64 // next run in HeapAlloc time (bytes)
- LastGC uint64 // last run in absolute time (ns)
- PauseTotalNs uint64
- PauseNs [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
- PauseEnd [256]uint64 // circular buffer of recent GC pause end times
- NumGC uint32
- GCCPUFraction float64 // fraction of CPU time used by GC
- EnableGC bool
- DebugGC bool
-
- // Per-size allocation statistics.
- // 61 is NumSizeClasses in the C code.
- BySize [61]struct {
- Size uint32
- Mallocs uint64
- Frees uint64
- }
-}
-
-var Sizeof_C_MStats uintptr // filled in by malloc.goc
-
-func init() {
- var memStats MemStats
- if Sizeof_C_MStats != unsafe.Sizeof(memStats) {
- println(Sizeof_C_MStats, unsafe.Sizeof(memStats))
- panic("MStats vs MemStatsType size mismatch")
- }
-}
-
-// ReadMemStats populates m with memory allocator statistics.
-func ReadMemStats(m *MemStats)
-
-// GC runs a garbage collection.
-func GC()
diff --git a/libgo/go/runtime/mksizeclasses.go b/libgo/go/runtime/mksizeclasses.go
new file mode 100644
index 0000000000..0f897ba8e6
--- /dev/null
+++ b/libgo/go/runtime/mksizeclasses.go
@@ -0,0 +1,325 @@
+// 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
+
+// Generate tables for small malloc size classes.
+//
+// See malloc.go for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+// Generate msize.go
+
+var stdout = flag.Bool("stdout", false, "write to stdout instead of sizeclasses.go")
+
+func main() {
+ flag.Parse()
+
+ var b bytes.Buffer
+ fmt.Fprintln(&b, "// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT")
+ fmt.Fprintln(&b, "//go:generate go run mksizeclasses.go")
+ fmt.Fprintln(&b)
+ fmt.Fprintln(&b, "package runtime")
+ classes := makeClasses()
+
+ printComment(&b, classes)
+
+ printClasses(&b, classes)
+
+ out, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if *stdout {
+ _, err = os.Stdout.Write(out)
+ } else {
+ err = ioutil.WriteFile("sizeclasses.go", out, 0666)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+const (
+ // Constants that we use and will transfer to the runtime.
+ maxSmallSize = 32 << 10
+ smallSizeDiv = 8
+ smallSizeMax = 1024
+ largeSizeDiv = 128
+ pageShift = 13
+
+ // Derived constants.
+ pageSize = 1 << pageShift
+)
+
+type class struct {
+ size int // max size
+ npages int // number of pages
+
+ mul int
+ shift uint
+ shift2 uint
+ mask int
+}
+
+func powerOfTwo(x int) bool {
+ return x != 0 && x&(x-1) == 0
+}
+
+func makeClasses() []class {
+ var classes []class
+
+ classes = append(classes, class{}) // class #0 is a dummy entry
+
+ align := 8
+ for size := align; size <= maxSmallSize; size += align {
+ if powerOfTwo(size) { // bump alignment once in a while
+ if size >= 2048 {
+ align = 256
+ } else if size >= 128 {
+ align = size / 8
+ } else if size >= 16 {
+ align = 16 // required for x86 SSE instructions, if we want to use them
+ }
+ }
+ if !powerOfTwo(align) {
+ panic("incorrect alignment")
+ }
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize := pageSize
+ for allocsize%size > allocsize/8 {
+ allocsize += pageSize
+ }
+ npages := allocsize / pageSize
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if len(classes) > 1 && npages == classes[len(classes)-1].npages && allocsize/size == allocsize/classes[len(classes)-1].size {
+ classes[len(classes)-1].size = size
+ continue
+ }
+ classes = append(classes, class{size: size, npages: npages})
+ }
+
+ // Increase object sizes if we can fit the same number of larger objects
+ // into the same number of pages. For example, we choose size 8448 above
+ // with 6 objects in 7 pages. But we can well use object size 9472,
+ // which is also 6 objects in 7 pages but +1024 bytes (+12.12%).
+ // We need to preserve at least largeSizeDiv alignment otherwise
+ // sizeToClass won't work.
+ for i := range classes {
+ if i == 0 {
+ continue
+ }
+ c := &classes[i]
+ psize := c.npages * pageSize
+ new_size := (psize / (psize / c.size)) &^ (largeSizeDiv - 1)
+ if new_size > c.size {
+ c.size = new_size
+ }
+ }
+
+ if len(classes) != 67 {
+ panic("number of size classes has changed")
+ }
+
+ for i := range classes {
+ computeDivMagic(&classes[i])
+ }
+
+ return classes
+}
+
+// computeDivMagic computes some magic constants to implement
+// the division required to compute object number from span offset.
+// n / c.size is implemented as n >> c.shift * c.mul >> c.shift2
+// for all 0 <= n < c.npages * pageSize
+func computeDivMagic(c *class) {
+ // divisor
+ d := c.size
+ if d == 0 {
+ return
+ }
+
+ // maximum input value for which the formula needs to work.
+ max := c.npages*pageSize - 1
+
+ if powerOfTwo(d) {
+ // If the size is a power of two, heapBitsForObject can divide even faster by masking.
+ // Compute this mask.
+ if max >= 1<<16 {
+ panic("max too big for power of two size")
+ }
+ c.mask = 1<<16 - d
+ }
+
+ // Compute pre-shift by factoring power of 2 out of d.
+ for d%2 == 0 {
+ c.shift++
+ d >>= 1
+ max >>= 1
+ }
+
+ // Find the smallest k that works.
+ // A small k allows us to fit the math required into 32 bits
+ // so we can use 32-bit multiplies and shifts on 32-bit platforms.
+nextk:
+ for k := uint(0); ; k++ {
+ mul := (int(1)<<k + d - 1) / d // ⌈2^k / d⌉
+
+ // Test to see if mul works.
+ for n := 0; n <= max; n++ {
+ if n*mul>>k != n/d {
+ continue nextk
+ }
+ }
+ if mul >= 1<<16 {
+ panic("mul too big")
+ }
+ if uint64(mul)*uint64(max) >= 1<<32 {
+ panic("mul*max too big")
+ }
+ c.mul = mul
+ c.shift2 = k
+ break
+ }
+
+ // double-check.
+ for n := 0; n <= max; n++ {
+ if n*c.mul>>c.shift2 != n/d {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad multiply magic")
+ }
+ // Also check the exact computations that will be done by the runtime,
+ // for both 32 and 64 bit operations.
+ if uint32(n)*uint32(c.mul)>>uint8(c.shift2) != uint32(n/d) {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad 32-bit multiply magic")
+ }
+ if uint64(n)*uint64(c.mul)>>uint8(c.shift2) != uint64(n/d) {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad 64-bit multiply magic")
+ }
+ }
+}
+
+func printComment(w io.Writer, classes []class) {
+ fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-11s\n", "class", "bytes/obj", "bytes/span", "objects", "waste bytes")
+ for i, c := range classes {
+ if i == 0 {
+ continue
+ }
+ spanSize := c.npages * pageSize
+ objects := spanSize / c.size
+ waste := spanSize - c.size*(spanSize/c.size)
+ fmt.Fprintf(w, "// %5d %9d %10d %7d %11d\n", i, c.size, spanSize, objects, waste)
+ }
+ fmt.Fprintf(w, "\n")
+}
+
+func printClasses(w io.Writer, classes []class) {
+ fmt.Fprintln(w, "const (")
+ fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize)
+ fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv)
+ fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax)
+ fmt.Fprintf(w, "largeSizeDiv = %d\n", largeSizeDiv)
+ fmt.Fprintf(w, "_NumSizeClasses = %d\n", len(classes))
+ fmt.Fprintf(w, "_PageShift = %d\n", pageShift)
+ fmt.Fprintln(w, ")")
+
+ fmt.Fprint(w, "var class_to_size = [_NumSizeClasses]uint16 {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "%d,", c.size)
+ }
+ fmt.Fprintln(w, "}")
+
+ fmt.Fprint(w, "var class_to_allocnpages = [_NumSizeClasses]uint8 {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "%d,", c.npages)
+ }
+ fmt.Fprintln(w, "}")
+
+ fmt.Fprintln(w, "type divMagic struct {")
+ fmt.Fprintln(w, " shift uint8")
+ fmt.Fprintln(w, " shift2 uint8")
+ fmt.Fprintln(w, " mul uint16")
+ fmt.Fprintln(w, " baseMask uint16")
+ fmt.Fprintln(w, "}")
+ fmt.Fprint(w, "var class_to_divmagic = [_NumSizeClasses]divMagic {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "{%d,%d,%d,%d},", c.shift, c.shift2, c.mul, c.mask)
+ }
+ fmt.Fprintln(w, "}")
+
+ // map from size to size class, for small sizes.
+ sc := make([]int, smallSizeMax/smallSizeDiv+1)
+ for i := range sc {
+ size := i * smallSizeDiv
+ for j, c := range classes {
+ if c.size >= size {
+ sc[i] = j
+ break
+ }
+ }
+ }
+ fmt.Fprint(w, "var size_to_class8 = [smallSizeMax/smallSizeDiv+1]uint8 {")
+ for _, v := range sc {
+ fmt.Fprintf(w, "%d,", v)
+ }
+ fmt.Fprintln(w, "}")
+
+ // map from size to size class, for large sizes.
+ sc = make([]int, (maxSmallSize-smallSizeMax)/largeSizeDiv+1)
+ for i := range sc {
+ size := smallSizeMax + i*largeSizeDiv
+ for j, c := range classes {
+ if c.size >= size {
+ sc[i] = j
+ break
+ }
+ }
+ }
+ fmt.Fprint(w, "var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv+1]uint8 {")
+ for _, v := range sc {
+ fmt.Fprintf(w, "%d,", v)
+ }
+ fmt.Fprintln(w, "}")
+}
diff --git a/libgo/go/runtime/mmap.go b/libgo/go/runtime/mmap.go
deleted file mode 100644
index a0768428b4..0000000000
--- a/libgo/go/runtime/mmap.go
+++ /dev/null
@@ -1,16 +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 !plan9
-// +build !solaris
-// +build !windows
-// +build !nacl
-// +build !linux !amd64
-
-package runtime
-
-import "unsafe"
-
-// mmap calls the mmap system call. It is implemented in assembly.
-func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
diff --git a/libgo/go/runtime/mprof.go b/libgo/go/runtime/mprof.go
new file mode 100644
index 0000000000..1bfdc39b62
--- /dev/null
+++ b/libgo/go/runtime/mprof.go
@@ -0,0 +1,775 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc profiling.
+// Patterned after tcmalloc's algorithms; shorter code.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// Export temporarily for gccgo's C code to call:
+//go:linkname mProf_Malloc runtime.mProf_Malloc
+//go:linkname mProf_Free runtime.mProf_Free
+//go:linkname mProf_GC runtime.mProf_GC
+//go:linkname tracealloc runtime.tracealloc
+//go:linkname tracefree runtime.tracefree
+//go:linkname tracegc runtime.tracegc
+//go:linkname iterate_memprof runtime.iterate_memprof
+
+// NOTE(rsc): Everything here could use cas if contention became an issue.
+var proflock mutex
+
+// All memory allocations are local and do not escape outside of the profiler.
+// The profiler is forbidden from referring to garbage-collected memory.
+
+const (
+ // profile types
+ memProfile bucketType = 1 + iota
+ blockProfile
+ mutexProfile
+
+ // size of bucket hash table
+ buckHashSize = 179999
+
+ // max depth of stack to record in bucket
+ maxStack = 32
+)
+
+type bucketType int
+
+// A bucket holds per-call-stack profiling information.
+// The representation is a bit sleazy, inherited from C.
+// This struct defines the bucket header. It is followed in
+// memory by the stack words and then the actual record
+// data, either a memRecord or a blockRecord.
+//
+// Per-call-stack profiling information.
+// Lookup by hashing call stack into a linked-list hash table.
+//
+// No heap pointers.
+//
+//go:notinheap
+type bucket struct {
+ next *bucket
+ allnext *bucket
+ typ bucketType // memBucket or blockBucket (includes mutexProfile)
+ hash uintptr
+ size uintptr
+ nstk uintptr
+}
+
+// A memRecord is the bucket data for a bucket of type memProfile,
+// part of the memory profile.
+type memRecord struct {
+ // The following complex 3-stage scheme of stats accumulation
+ // is required to obtain a consistent picture of mallocs and frees
+ // for some point in time.
+ // The problem is that mallocs come in real time, while frees
+ // come only after a GC during concurrent sweeping. So if we would
+ // naively count them, we would get a skew toward mallocs.
+ //
+ // Mallocs are accounted in recent stats.
+ // Explicit frees are accounted in recent stats.
+ // GC frees are accounted in prev stats.
+ // After GC prev stats are added to final stats and
+ // recent stats are moved into prev stats.
+ allocs uintptr
+ frees uintptr
+ alloc_bytes uintptr
+ free_bytes uintptr
+
+ // changes between next-to-last GC and last GC
+ prev_allocs uintptr
+ prev_frees uintptr
+ prev_alloc_bytes uintptr
+ prev_free_bytes uintptr
+
+ // changes since last GC
+ recent_allocs uintptr
+ recent_frees uintptr
+ recent_alloc_bytes uintptr
+ recent_free_bytes uintptr
+}
+
+// A blockRecord is the bucket data for a bucket of type blockProfile,
+// which is used in blocking and mutex profiles.
+type blockRecord struct {
+ count int64
+ cycles int64
+}
+
+var (
+ mbuckets *bucket // memory profile buckets
+ bbuckets *bucket // blocking profile buckets
+ xbuckets *bucket // mutex profile buckets
+ buckhash *[179999]*bucket
+ bucketmem uintptr
+)
+
+// newBucket allocates a bucket with the given type and number of stack entries.
+func newBucket(typ bucketType, nstk int) *bucket {
+ size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(location{})
+ switch typ {
+ default:
+ throw("invalid profile bucket type")
+ case memProfile:
+ size += unsafe.Sizeof(memRecord{})
+ case blockProfile, mutexProfile:
+ size += unsafe.Sizeof(blockRecord{})
+ }
+
+ b := (*bucket)(persistentalloc(size, 0, &memstats.buckhash_sys))
+ bucketmem += size
+ b.typ = typ
+ b.nstk = uintptr(nstk)
+ return b
+}
+
+// stk returns the slice in b holding the stack.
+func (b *bucket) stk() []location {
+ stk := (*[maxStack]location)(add(unsafe.Pointer(b), unsafe.Sizeof(*b)))
+ return stk[:b.nstk:b.nstk]
+}
+
+// mp returns the memRecord associated with the memProfile bucket b.
+func (b *bucket) mp() *memRecord {
+ if b.typ != memProfile {
+ throw("bad use of bucket.mp")
+ }
+ data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(location{}))
+ return (*memRecord)(data)
+}
+
+// bp returns the blockRecord associated with the blockProfile bucket b.
+func (b *bucket) bp() *blockRecord {
+ if b.typ != blockProfile && b.typ != mutexProfile {
+ throw("bad use of bucket.bp")
+ }
+ data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(location{}))
+ return (*blockRecord)(data)
+}
+
+// Return the bucket for stk[0:nstk], allocating new bucket if needed.
+func stkbucket(typ bucketType, size uintptr, stk []location, alloc bool) *bucket {
+ if buckhash == nil {
+ buckhash = (*[buckHashSize]*bucket)(sysAlloc(unsafe.Sizeof(*buckhash), &memstats.buckhash_sys))
+ if buckhash == nil {
+ throw("runtime: cannot allocate memory")
+ }
+ }
+
+ // Hash stack.
+ var h uintptr
+ for _, loc := range stk {
+ h += loc.pc
+ h += h << 10
+ h ^= h >> 6
+ }
+ // hash in size
+ h += size
+ h += h << 10
+ h ^= h >> 6
+ // finalize
+ h += h << 3
+ h ^= h >> 11
+
+ i := int(h % buckHashSize)
+ for b := buckhash[i]; b != nil; b = b.next {
+ if b.typ == typ && b.hash == h && b.size == size && eqslice(b.stk(), stk) {
+ return b
+ }
+ }
+
+ if !alloc {
+ return nil
+ }
+
+ // Create new bucket.
+ b := newBucket(typ, len(stk))
+ copy(b.stk(), stk)
+ b.hash = h
+ b.size = size
+ b.next = buckhash[i]
+ buckhash[i] = b
+ if typ == memProfile {
+ b.allnext = mbuckets
+ mbuckets = b
+ } else if typ == mutexProfile {
+ b.allnext = xbuckets
+ xbuckets = b
+ } else {
+ b.allnext = bbuckets
+ bbuckets = b
+ }
+ return b
+}
+
+func eqslice(x, y []location) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, xi := range x {
+ if xi != y[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func mprof_GC() {
+ for b := mbuckets; b != nil; b = b.allnext {
+ mp := b.mp()
+ mp.allocs += mp.prev_allocs
+ mp.frees += mp.prev_frees
+ mp.alloc_bytes += mp.prev_alloc_bytes
+ mp.free_bytes += mp.prev_free_bytes
+
+ mp.prev_allocs = mp.recent_allocs
+ mp.prev_frees = mp.recent_frees
+ mp.prev_alloc_bytes = mp.recent_alloc_bytes
+ mp.prev_free_bytes = mp.recent_free_bytes
+
+ mp.recent_allocs = 0
+ mp.recent_frees = 0
+ mp.recent_alloc_bytes = 0
+ mp.recent_free_bytes = 0
+ }
+}
+
+// Record that a gc just happened: all the 'recent' statistics are now real.
+func mProf_GC() {
+ lock(&proflock)
+ mprof_GC()
+ unlock(&proflock)
+}
+
+// Called by malloc to record a profiled block.
+func mProf_Malloc(p unsafe.Pointer, size uintptr) {
+ var stk [maxStack]location
+ nstk := callers(4, stk[:])
+ lock(&proflock)
+ b := stkbucket(memProfile, size, stk[:nstk], true)
+ mp := b.mp()
+ mp.recent_allocs++
+ mp.recent_alloc_bytes += size
+ unlock(&proflock)
+
+ // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
+ // This reduces potential contention and chances of deadlocks.
+ // Since the object must be alive during call to mProf_Malloc,
+ // it's fine to do this non-atomically.
+ systemstack(func() {
+ setprofilebucket(p, b)
+ })
+}
+
+// Called when freeing a profiled block.
+func mProf_Free(b *bucket, size uintptr) {
+ lock(&proflock)
+ mp := b.mp()
+ mp.prev_frees++
+ mp.prev_free_bytes += size
+ unlock(&proflock)
+}
+
+var blockprofilerate uint64 // in CPU ticks
+
+// SetBlockProfileRate controls the fraction of goroutine blocking events
+// that are reported in the blocking profile. The profiler aims to sample
+// an average of one blocking event per rate nanoseconds spent blocked.
+//
+// To include every blocking event in the profile, pass rate = 1.
+// To turn off profiling entirely, pass rate <= 0.
+func SetBlockProfileRate(rate int) {
+ var r int64
+ if rate <= 0 {
+ r = 0 // disable profiling
+ } else if rate == 1 {
+ r = 1 // profile everything
+ } else {
+ // convert ns to cycles, use float64 to prevent overflow during multiplication
+ r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000))
+ if r == 0 {
+ r = 1
+ }
+ }
+
+ atomic.Store64(&blockprofilerate, uint64(r))
+}
+
+func blockevent(cycles int64, skip int) {
+ if cycles <= 0 {
+ cycles = 1
+ }
+ if blocksampled(cycles) {
+ saveblockevent(cycles, skip+1, blockProfile, &blockprofilerate)
+ }
+}
+
+func blocksampled(cycles int64) bool {
+ rate := int64(atomic.Load64(&blockprofilerate))
+ if rate <= 0 || (rate > cycles && int64(fastrand())%rate > cycles) {
+ return false
+ }
+ return true
+}
+
+func saveblockevent(cycles int64, skip int, which bucketType, ratep *uint64) {
+ gp := getg()
+ var nstk int
+ var stk [maxStack]location
+ if gp.m.curg == nil || gp.m.curg == gp {
+ nstk = callers(skip, stk[:])
+ } else {
+ // FIXME: This should get a traceback of gp.m.curg.
+ // nstk = gcallers(gp.m.curg, skip, stk[:])
+ nstk = callers(skip, stk[:])
+ }
+ lock(&proflock)
+ b := stkbucket(which, 0, stk[:nstk], true)
+ b.bp().count++
+ b.bp().cycles += cycles
+ unlock(&proflock)
+}
+
+var mutexprofilerate uint64 // fraction sampled
+
+// SetMutexProfileFraction controls the fraction of mutex contention events
+// that are reported in the mutex profile. On average 1/rate events are
+// reported. The previous rate is returned.
+//
+// To turn off profiling entirely, pass rate 0.
+// To just read the current rate, pass rate -1.
+// (For n>1 the details of sampling may change.)
+func SetMutexProfileFraction(rate int) int {
+ if rate < 0 {
+ return int(mutexprofilerate)
+ }
+ old := mutexprofilerate
+ atomic.Store64(&mutexprofilerate, uint64(rate))
+ return int(old)
+}
+
+//go:linkname mutexevent sync.event
+func mutexevent(cycles int64, skip int) {
+ if cycles < 0 {
+ cycles = 0
+ }
+ rate := int64(atomic.Load64(&mutexprofilerate))
+ // TODO(pjw): measure impact of always calling fastrand vs using something
+ // like malloc.go:nextSample()
+ if rate > 0 && int64(fastrand())%rate == 0 {
+ saveblockevent(cycles, skip+1, mutexProfile, &mutexprofilerate)
+ }
+}
+
+// Go interface to profile data.
+
+// A StackRecord describes a single execution stack.
+type StackRecord struct {
+ Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *StackRecord) Stack() []uintptr {
+ for i, v := range r.Stack0 {
+ if v == 0 {
+ return r.Stack0[0:i]
+ }
+ }
+ return r.Stack0[0:]
+}
+
+// MemProfileRate controls the fraction of memory allocations
+// that are recorded and reported in the memory profile.
+// The profiler aims to sample an average of
+// one allocation per MemProfileRate bytes allocated.
+//
+// To include every allocated block in the profile, set MemProfileRate to 1.
+// To turn off profiling entirely, set MemProfileRate to 0.
+//
+// The tools that process the memory profiles assume that the
+// profile rate is constant across the lifetime of the program
+// and equal to the current value. Programs that change the
+// memory profiling rate should do so just once, as early as
+// possible in the execution of the program (for example,
+// at the beginning of main).
+var MemProfileRate int = 512 * 1024
+
+// A MemProfileRecord describes the live objects allocated
+// by a particular call sequence (stack trace).
+type MemProfileRecord struct {
+ AllocBytes, FreeBytes int64 // number of bytes allocated, freed
+ AllocObjects, FreeObjects int64 // number of objects allocated, freed
+ Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
+func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
+
+// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
+func (r *MemProfileRecord) InUseObjects() int64 {
+ return r.AllocObjects - r.FreeObjects
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *MemProfileRecord) Stack() []uintptr {
+ for i, v := range r.Stack0 {
+ if v == 0 {
+ return r.Stack0[0:i]
+ }
+ }
+ return r.Stack0[0:]
+}
+
+// MemProfile returns a profile of memory allocated and freed per allocation
+// site.
+//
+// MemProfile returns n, the number of records in the current memory profile.
+// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
+// If len(p) < n, MemProfile does not change p and returns n, false.
+//
+// If inuseZero is true, the profile includes allocation records
+// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
+// These are sites where memory was allocated, but it has all
+// been released back to the runtime.
+//
+// The returned profile may be up to two garbage collection cycles old.
+// This is to avoid skewing the profile toward allocations; because
+// allocations happen in real time but frees are delayed until the garbage
+// collector performs sweeping, the profile only accounts for allocations
+// that have had a chance to be freed by the garbage collector.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.memprofile flag instead
+// of calling MemProfile directly.
+func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
+ lock(&proflock)
+ clear := true
+ for b := mbuckets; b != nil; b = b.allnext {
+ mp := b.mp()
+ if inuseZero || mp.alloc_bytes != mp.free_bytes {
+ n++
+ }
+ if mp.allocs != 0 || mp.frees != 0 {
+ clear = false
+ }
+ }
+ if clear {
+ // Absolutely no data, suggesting that a garbage collection
+ // has not yet happened. In order to allow profiling when
+ // garbage collection is disabled from the beginning of execution,
+ // accumulate stats as if a GC just happened, and recount buckets.
+ mprof_GC()
+ mprof_GC()
+ n = 0
+ for b := mbuckets; b != nil; b = b.allnext {
+ mp := b.mp()
+ if inuseZero || mp.alloc_bytes != mp.free_bytes {
+ n++
+ }
+ }
+ }
+ if n <= len(p) {
+ ok = true
+ idx := 0
+ for b := mbuckets; b != nil; b = b.allnext {
+ mp := b.mp()
+ if inuseZero || mp.alloc_bytes != mp.free_bytes {
+ record(&p[idx], b)
+ idx++
+ }
+ }
+ }
+ unlock(&proflock)
+ return
+}
+
+// Write b's data to r.
+func record(r *MemProfileRecord, b *bucket) {
+ mp := b.mp()
+ r.AllocBytes = int64(mp.alloc_bytes)
+ r.FreeBytes = int64(mp.free_bytes)
+ r.AllocObjects = int64(mp.allocs)
+ r.FreeObjects = int64(mp.frees)
+ for i, loc := range b.stk() {
+ if i >= len(r.Stack0) {
+ break
+ }
+ r.Stack0[i] = loc.pc
+ }
+ for i := int(b.nstk); i < len(r.Stack0); i++ {
+ r.Stack0[i] = 0
+ }
+}
+
+func iterate_memprof(fn func(*bucket, uintptr, *location, uintptr, uintptr, uintptr)) {
+ lock(&proflock)
+ for b := mbuckets; b != nil; b = b.allnext {
+ mp := b.mp()
+ fn(b, b.nstk, &b.stk()[0], b.size, mp.allocs, mp.frees)
+ }
+ unlock(&proflock)
+}
+
+// BlockProfileRecord describes blocking events originated
+// at a particular call sequence (stack trace).
+type BlockProfileRecord struct {
+ Count int64
+ Cycles int64
+ StackRecord
+}
+
+// BlockProfile returns n, the number of records in the current blocking profile.
+// If len(p) >= n, BlockProfile copies the profile into p and returns n, true.
+// If len(p) < n, BlockProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.blockprofile flag instead
+// of calling BlockProfile directly.
+func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
+ lock(&proflock)
+ for b := bbuckets; b != nil; b = b.allnext {
+ n++
+ }
+ if n <= len(p) {
+ ok = true
+ for b := bbuckets; b != nil; b = b.allnext {
+ bp := b.bp()
+ r := &p[0]
+ r.Count = bp.count
+ r.Cycles = bp.cycles
+ i := 0
+ var loc location
+ for i, loc = range b.stk() {
+ if i >= len(r.Stack0) {
+ break
+ }
+ r.Stack0[i] = loc.pc
+ }
+ for ; i < len(r.Stack0); i++ {
+ r.Stack0[i] = 0
+ }
+ p = p[1:]
+ }
+ }
+ unlock(&proflock)
+ return
+}
+
+// MutexProfile returns n, the number of records in the current mutex profile.
+// If len(p) >= n, MutexProfile copies the profile into p and returns n, true.
+// Otherwise, MutexProfile does not change p, and returns n, false.
+//
+// Most clients should use the runtime/pprof package
+// instead of calling MutexProfile directly.
+func MutexProfile(p []BlockProfileRecord) (n int, ok bool) {
+ lock(&proflock)
+ for b := xbuckets; b != nil; b = b.allnext {
+ n++
+ }
+ if n <= len(p) {
+ ok = true
+ for b := xbuckets; b != nil; b = b.allnext {
+ bp := b.bp()
+ r := &p[0]
+ r.Count = int64(bp.count)
+ r.Cycles = bp.cycles
+ i := 0
+ var loc location
+ for i, loc = range b.stk() {
+ if i >= len(r.Stack0) {
+ break
+ }
+ r.Stack0[i] = loc.pc
+ }
+ for ; i < len(r.Stack0); i++ {
+ r.Stack0[i] = 0
+ }
+ p = p[1:]
+ }
+ }
+ unlock(&proflock)
+ return
+}
+
+// ThreadCreateProfile returns n, the number of records in the thread creation profile.
+// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
+// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling ThreadCreateProfile directly.
+func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
+ first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
+ for mp := first; mp != nil; mp = mp.alllink {
+ n++
+ }
+ if n <= len(p) {
+ ok = true
+ i := 0
+ for mp := first; mp != nil; mp = mp.alllink {
+ for j := range mp.createstack {
+ p[i].Stack0[j] = mp.createstack[j].pc
+ }
+ i++
+ }
+ }
+ return
+}
+
+// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
+// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
+// If len(p) < n, GoroutineProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling GoroutineProfile directly.
+func GoroutineProfile(p []StackRecord) (n int, ok bool) {
+ gp := getg()
+
+ isOK := func(gp1 *g) bool {
+ // Checking isSystemGoroutine here makes GoroutineProfile
+ // consistent with both NumGoroutine and Stack.
+ return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1)
+ }
+
+ stopTheWorld("profile")
+
+ n = 1
+ for _, gp1 := range allgs {
+ if isOK(gp1) {
+ n++
+ }
+ }
+
+ if n <= len(p) {
+ ok = true
+ r := p
+
+ // Save current goroutine.
+ saveg(gp, &r[0])
+ r = r[1:]
+
+ // Save other goroutines.
+ for _, gp1 := range allgs {
+ if isOK(gp1) {
+ if len(r) == 0 {
+ // Should be impossible, but better to return a
+ // truncated profile than to crash the entire process.
+ break
+ }
+ saveg(gp1, &r[0])
+ r = r[1:]
+ }
+ }
+ }
+
+ startTheWorld()
+
+ return n, ok
+}
+
+func saveg(gp *g, r *StackRecord) {
+ if gp == getg() {
+ var locbuf [32]location
+ n := callers(1, locbuf[:])
+ for i := 0; i < n; i++ {
+ r.Stack0[i] = locbuf[i].pc
+ }
+ if n < len(r.Stack0) {
+ r.Stack0[n] = 0
+ }
+ } else {
+ // FIXME: Not implemented.
+ r.Stack0[0] = 0
+ }
+}
+
+// Stack formats a stack trace of the calling goroutine into buf
+// and returns the number of bytes written to buf.
+// If all is true, Stack formats stack traces of all other goroutines
+// into buf after the trace for the current goroutine.
+func Stack(buf []byte, all bool) int {
+ if all {
+ stopTheWorld("stack trace")
+ }
+
+ n := 0
+ if len(buf) > 0 {
+ gp := getg()
+ // Force traceback=1 to override GOTRACEBACK setting,
+ // so that Stack's results are consistent.
+ // GOTRACEBACK is only about crash dumps.
+ gp.m.traceback = 1
+ gp.writebuf = buf[0:0:len(buf)]
+ goroutineheader(gp)
+ traceback(1)
+ if all {
+ tracebackothers(gp)
+ }
+ gp.m.traceback = 0
+ n = len(gp.writebuf)
+ gp.writebuf = nil
+ }
+
+ if all {
+ startTheWorld()
+ }
+ return n
+}
+
+// Tracing of alloc/free/gc.
+
+var tracelock mutex
+
+func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
+ lock(&tracelock)
+ gp := getg()
+ gp.m.traceback = 2
+ if typ == nil {
+ print("tracealloc(", p, ", ", hex(size), ")\n")
+ } else {
+ print("tracealloc(", p, ", ", hex(size), ", ", *typ.string, ")\n")
+ }
+ if gp.m.curg == nil || gp == gp.m.curg {
+ goroutineheader(gp)
+ traceback(1)
+ } else {
+ goroutineheader(gp.m.curg)
+ // FIXME: Can't do traceback of other g.
+ }
+ print("\n")
+ gp.m.traceback = 0
+ unlock(&tracelock)
+}
+
+func tracefree(p unsafe.Pointer, size uintptr) {
+ lock(&tracelock)
+ gp := getg()
+ gp.m.traceback = 2
+ print("tracefree(", p, ", ", hex(size), ")\n")
+ goroutineheader(gp)
+ traceback(1)
+ print("\n")
+ gp.m.traceback = 0
+ unlock(&tracelock)
+}
+
+func tracegc() {
+ lock(&tracelock)
+ gp := getg()
+ gp.m.traceback = 2
+ print("tracegc()\n")
+ // running on m->g0 stack; show all non-g0 goroutines
+ tracebackothers(gp)
+ print("end tracegc\n")
+ print("\n")
+ gp.m.traceback = 0
+ unlock(&tracelock)
+}
diff --git a/libgo/go/runtime/msan.go b/libgo/go/runtime/msan.go
deleted file mode 100644
index 4dbdf05b21..0000000000
--- a/libgo/go/runtime/msan.go
+++ /dev/null
@@ -1,55 +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 msan
-
-package runtime
-
-import (
- "unsafe"
-)
-
-// Public memory sanitizer API.
-
-func MSanRead(addr unsafe.Pointer, len int) {
- msanread(addr, uintptr(len))
-}
-
-func MSanWrite(addr unsafe.Pointer, len int) {
- msanwrite(addr, uintptr(len))
-}
-
-// Private interface for the runtime.
-const msanenabled = true
-
-// If we are running on the system stack, the C program may have
-// marked part of that stack as uninitialized. We don't instrument
-// the runtime, but operations like a slice copy can call msanread
-// anyhow for values on the stack. Just ignore msanread when running
-// on the system stack. The other msan functions are fine.
-func msanread(addr unsafe.Pointer, sz uintptr) {
- g := getg()
- if g == g.m.g0 || g == g.m.gsignal {
- return
- }
- domsanread(addr, sz)
-}
-
-//go:noescape
-func domsanread(addr unsafe.Pointer, sz uintptr)
-
-//go:noescape
-func msanwrite(addr unsafe.Pointer, sz uintptr)
-
-//go:noescape
-func msanmalloc(addr unsafe.Pointer, sz uintptr)
-
-//go:noescape
-func msanfree(addr unsafe.Pointer, sz uintptr)
-
-// These are called from msan_amd64.s
-//go:cgo_import_static __msan_read_go
-//go:cgo_import_static __msan_write_go
-//go:cgo_import_static __msan_malloc_go
-//go:cgo_import_static __msan_free_go
diff --git a/libgo/go/runtime/msan0.go b/libgo/go/runtime/msan0.go
index e206720697..117c5e5789 100644
--- a/libgo/go/runtime/msan0.go
+++ b/libgo/go/runtime/msan0.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/mstats.go b/libgo/go/runtime/mstats.go
new file mode 100644
index 0000000000..178c32c032
--- /dev/null
+++ b/libgo/go/runtime/mstats.go
@@ -0,0 +1,693 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Memory statistics
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// Statistics.
+// If you edit this structure, also edit type MemStats below.
+// Their layouts must match exactly.
+//
+// For detailed descriptions see the documentation for MemStats.
+// Fields that differ from MemStats are further documented here.
+//
+// Many of these fields are updated on the fly, while others are only
+// updated when updatememstats is called.
+type mstats struct {
+ // General statistics.
+ alloc uint64 // bytes allocated and not yet freed
+ total_alloc uint64 // bytes allocated (even if freed)
+ sys uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+ nlookup uint64 // number of pointer lookups
+ nmalloc uint64 // number of mallocs
+ nfree uint64 // number of frees
+
+ // Statistics about malloc heap.
+ // Protected by mheap.lock
+ //
+ // In mstats, heap_sys and heap_inuse includes stack memory,
+ // while in MemStats stack memory is separated out from the
+ // heap stats.
+ heap_alloc uint64 // bytes allocated and not yet freed (same as alloc above)
+ heap_sys uint64 // virtual address space obtained from system
+ heap_idle uint64 // bytes in idle spans
+ heap_inuse uint64 // bytes in non-idle spans
+ heap_released uint64 // bytes released to the os
+ heap_objects uint64 // total number of allocated objects
+
+ // TODO(austin): heap_released is both useless and inaccurate
+ // in its current form. It's useless because, from the user's
+ // and OS's perspectives, there's no difference between a page
+ // that has not yet been faulted in and a page that has been
+ // released back to the OS. We could fix this by considering
+ // newly mapped spans to be "released". It's inaccurate
+ // because when we split a large span for allocation, we
+ // "unrelease" all pages in the large span and not just the
+ // ones we split off for use. This is trickier to fix because
+ // we currently don't know which pages of a span we've
+ // released. We could fix it by separating "free" and
+ // "released" spans, but then we have to allocate from runs of
+ // free and released spans.
+
+ // Statistics about allocation of low-level fixed-size structures.
+ // Protected by FixAlloc locks.
+ stacks_inuse uint64 // this number is included in heap_inuse above; differs from MemStats.StackInuse
+ stacks_sys uint64 // only counts newosproc0 stack in mstats; differs from MemStats.StackSys
+ mspan_inuse uint64 // mspan structures
+ mspan_sys uint64
+ mcache_inuse uint64 // mcache structures
+ mcache_sys uint64
+ buckhash_sys uint64 // profiling bucket hash table
+ gc_sys uint64
+ other_sys uint64
+
+ // Statistics about garbage collector.
+ // Protected by mheap or stopping the world during GC.
+ next_gc uint64 // goal heap_live for when next GC ends; ^0 if disabled
+ last_gc uint64 // last gc (in absolute time)
+ pause_total_ns uint64
+ pause_ns [256]uint64 // circular buffer of recent gc pause lengths
+ pause_end [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
+ numgc uint32
+ numforcedgc uint32 // number of user-forced GCs
+ gc_cpu_fraction float64 // fraction of CPU time used by GC
+ enablegc bool
+ debuggc bool
+
+ // Statistics about allocation size classes.
+
+ by_size [_NumSizeClasses]struct {
+ size uint32
+ nmalloc uint64
+ nfree uint64
+ }
+
+ // Statistics below here are not exported to MemStats directly.
+
+ tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+
+ // gc_trigger is the heap size that triggers marking.
+ //
+ // When heap_live ≥ gc_trigger, the mark phase will start.
+ // This is also the heap size by which proportional sweeping
+ // must be complete.
+ gc_trigger uint64
+
+ // heap_live is the number of bytes considered live by the GC.
+ // That is: retained by the most recent GC plus allocated
+ // since then. heap_live <= heap_alloc, since heap_alloc
+ // includes unmarked objects that have not yet been swept (and
+ // hence goes up as we allocate and down as we sweep) while
+ // heap_live excludes these objects (and hence only goes up
+ // between GCs).
+ //
+ // This is updated atomically without locking. To reduce
+ // contention, this is updated only when obtaining a span from
+ // an mcentral and at this point it counts all of the
+ // unallocated slots in that span (which will be allocated
+ // before that mcache obtains another span from that
+ // mcentral). Hence, it slightly overestimates the "true" live
+ // heap size. It's better to overestimate than to
+ // underestimate because 1) this triggers the GC earlier than
+ // necessary rather than potentially too late and 2) this
+ // leads to a conservative GC rate rather than a GC rate that
+ // is potentially too low.
+ //
+ // Whenever this is updated, call traceHeapAlloc() and
+ // gcController.revise().
+ heap_live uint64
+
+ // heap_scan is the number of bytes of "scannable" heap. This
+ // is the live heap (as counted by heap_live), but omitting
+ // no-scan objects and no-scan tails of objects.
+ //
+ // Whenever this is updated, call gcController.revise().
+ heap_scan uint64
+
+ // heap_marked is the number of bytes marked by the previous
+ // GC. After mark termination, heap_live == heap_marked, but
+ // unlike heap_live, heap_marked does not change until the
+ // next mark termination.
+ heap_marked uint64
+}
+
+var memstats mstats
+
+// A MemStats records statistics about the memory allocator.
+type MemStats struct {
+ // General statistics.
+
+ // Alloc is bytes of allocated heap objects.
+ //
+ // This is the same as HeapAlloc (see below).
+ Alloc uint64
+
+ // TotalAlloc is cumulative bytes allocated for heap objects.
+ //
+ // TotalAlloc increases as heap objects are allocated, but
+ // unlike Alloc and HeapAlloc, it does not decrease when
+ // objects are freed.
+ TotalAlloc uint64
+
+ // Sys is the total bytes of memory obtained from the OS.
+ //
+ // Sys is the sum of the XSys fields below. Sys measures the
+ // virtual address space reserved by the Go runtime for the
+ // heap, stacks, and other internal data structures. It's
+ // likely that not all of the virtual address space is backed
+ // by physical memory at any given moment, though in general
+ // it all was at some point.
+ Sys uint64
+
+ // Lookups is the number of pointer lookups performed by the
+ // runtime.
+ //
+ // This is primarily useful for debugging runtime internals.
+ Lookups uint64
+
+ // Mallocs is the cumulative count of heap objects allocated.
+ // The number of live objects is Mallocs - Frees.
+ Mallocs uint64
+
+ // Frees is the cumulative count of heap objects freed.
+ Frees uint64
+
+ // Heap memory statistics.
+ //
+ // Interpreting the heap statistics requires some knowledge of
+ // how Go organizes memory. Go divides the virtual address
+ // space of the heap into "spans", which are contiguous
+ // regions of memory 8K or larger. A span may be in one of
+ // three states:
+ //
+ // An "idle" span contains no objects or other data. The
+ // physical memory backing an idle span can be released back
+ // to the OS (but the virtual address space never is), or it
+ // can be converted into an "in use" or "stack" span.
+ //
+ // An "in use" span contains at least one heap object and may
+ // have free space available to allocate more heap objects.
+ //
+ // A "stack" span is used for goroutine stacks. Stack spans
+ // are not considered part of the heap. A span can change
+ // between heap and stack memory; it is never used for both
+ // simultaneously.
+
+ // HeapAlloc is bytes of allocated heap objects.
+ //
+ // "Allocated" heap objects include all reachable objects, as
+ // well as unreachable objects that the garbage collector has
+ // not yet freed. Specifically, HeapAlloc increases as heap
+ // objects are allocated and decreases as the heap is swept
+ // and unreachable objects are freed. Sweeping occurs
+ // incrementally between GC cycles, so these two processes
+ // occur simultaneously, and as a result HeapAlloc tends to
+ // change smoothly (in contrast with the sawtooth that is
+ // typical of stop-the-world garbage collectors).
+ HeapAlloc uint64
+
+ // HeapSys is bytes of heap memory obtained from the OS.
+ //
+ // HeapSys measures the amount of virtual address space
+ // reserved for the heap. This includes virtual address space
+ // that has been reserved but not yet used, which consumes no
+ // physical memory, but tends to be small, as well as virtual
+ // address space for which the physical memory has been
+ // returned to the OS after it became unused (see HeapReleased
+ // for a measure of the latter).
+ //
+ // HeapSys estimates the largest size the heap has had.
+ HeapSys uint64
+
+ // HeapIdle is bytes in idle (unused) spans.
+ //
+ // Idle spans have no objects in them. These spans could be
+ // (and may already have been) returned to the OS, or they can
+ // be reused for heap allocations, or they can be reused as
+ // stack memory.
+ //
+ // HeapIdle minus HeapReleased estimates the amount of memory
+ // that could be returned to the OS, but is being retained by
+ // the runtime so it can grow the heap without requesting more
+ // memory from the OS. If this difference is significantly
+ // larger than the heap size, it indicates there was a recent
+ // transient spike in live heap size.
+ HeapIdle uint64
+
+ // HeapInuse is bytes in in-use spans.
+ //
+ // In-use spans have at least one object in them. These spans
+ // can only be used for other objects of roughly the same
+ // size.
+ //
+ // HeapInuse minus HeapAlloc esimates the amount of memory
+ // that has been dedicated to particular size classes, but is
+ // not currently being used. This is an upper bound on
+ // fragmentation, but in general this memory can be reused
+ // efficiently.
+ HeapInuse uint64
+
+ // HeapReleased is bytes of physical memory returned to the OS.
+ //
+ // This counts heap memory from idle spans that was returned
+ // to the OS and has not yet been reacquired for the heap.
+ HeapReleased uint64
+
+ // HeapObjects is the number of allocated heap objects.
+ //
+ // Like HeapAlloc, this increases as objects are allocated and
+ // decreases as the heap is swept and unreachable objects are
+ // freed.
+ HeapObjects uint64
+
+ // Stack memory statistics.
+ //
+ // Stacks are not considered part of the heap, but the runtime
+ // can reuse a span of heap memory for stack memory, and
+ // vice-versa.
+
+ // StackInuse is bytes in stack spans.
+ //
+ // In-use stack spans have at least one stack in them. These
+ // spans can only be used for other stacks of the same size.
+ //
+ // There is no StackIdle because unused stack spans are
+ // returned to the heap (and hence counted toward HeapIdle).
+ StackInuse uint64
+
+ // StackSys is bytes of stack memory obtained from the OS.
+ //
+ // StackSys is StackInuse, plus any memory obtained directly
+ // from the OS for OS thread stacks (which should be minimal).
+ StackSys uint64
+
+ // Off-heap memory statistics.
+ //
+ // The following statistics measure runtime-internal
+ // structures that are not allocated from heap memory (usually
+ // because they are part of implementing the heap). Unlike
+ // heap or stack memory, any memory allocated to these
+ // structures is dedicated to these structures.
+ //
+ // These are primarily useful for debugging runtime memory
+ // overheads.
+
+ // MSpanInuse is bytes of allocated mspan structures.
+ MSpanInuse uint64
+
+ // MSpanSys is bytes of memory obtained from the OS for mspan
+ // structures.
+ MSpanSys uint64
+
+ // MCacheInuse is bytes of allocated mcache structures.
+ MCacheInuse uint64
+
+ // MCacheSys is bytes of memory obtained from the OS for
+ // mcache structures.
+ MCacheSys uint64
+
+ // BuckHashSys is bytes of memory in profiling bucket hash tables.
+ BuckHashSys uint64
+
+ // GCSys is bytes of memory in garbage collection metadata.
+ GCSys uint64
+
+ // OtherSys is bytes of memory in miscellaneous off-heap
+ // runtime allocations.
+ OtherSys uint64
+
+ // Garbage collector statistics.
+
+ // NextGC is the target heap size of the next GC cycle.
+ //
+ // The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
+ // At the end of each GC cycle, the target for the next cycle
+ // is computed based on the amount of reachable data and the
+ // value of GOGC.
+ NextGC uint64
+
+ // LastGC is the time the last garbage collection finished, as
+ // nanoseconds since 1970 (the UNIX epoch).
+ LastGC uint64
+
+ // PauseTotalNs is the cumulative nanoseconds in GC
+ // stop-the-world pauses since the program started.
+ //
+ // During a stop-the-world pause, all goroutines are paused
+ // and only the garbage collector can run.
+ PauseTotalNs uint64
+
+ // PauseNs is a circular buffer of recent GC stop-the-world
+ // pause times in nanoseconds.
+ //
+ // The most recent pause is at PauseNs[(NumGC+255)%256]. In
+ // general, PauseNs[N%256] records the time paused in the most
+ // recent N%256th GC cycle. There may be multiple pauses per
+ // GC cycle; this is the sum of all pauses during a cycle.
+ PauseNs [256]uint64
+
+ // PauseEnd is a circular buffer of recent GC pause end times,
+ // as nanoseconds since 1970 (the UNIX epoch).
+ //
+ // This buffer is filled the same way as PauseNs. There may be
+ // multiple pauses per GC cycle; this records the end of the
+ // last pause in a cycle.
+ PauseEnd [256]uint64
+
+ // NumGC is the number of completed GC cycles.
+ NumGC uint32
+
+ // NumForcedGC is the number of GC cycles that were forced by
+ // the application calling the GC function.
+ NumForcedGC uint32
+
+ // GCCPUFraction is the fraction of this program's available
+ // CPU time used by the GC since the program started.
+ //
+ // GCCPUFraction is expressed as a number between 0 and 1,
+ // where 0 means GC has consumed none of this program's CPU. A
+ // program's available CPU time is defined as the integral of
+ // GOMAXPROCS since the program started. That is, if
+ // GOMAXPROCS is 2 and a program has been running for 10
+ // seconds, its "available CPU" is 20 seconds. GCCPUFraction
+ // does not include CPU time used for write barrier activity.
+ //
+ // This is the same as the fraction of CPU reported by
+ // GODEBUG=gctrace=1.
+ GCCPUFraction float64
+
+ // EnableGC indicates that GC is enabled. It is always true,
+ // even if GOGC=off.
+ EnableGC bool
+
+ // DebugGC is currently unused.
+ DebugGC bool
+
+ // BySize reports per-size class allocation statistics.
+ //
+ // BySize[N] gives statistics for allocations of size S where
+ // BySize[N-1].Size < S ≤ BySize[N].Size.
+ //
+ // This does not report allocations larger than BySize[60].Size.
+ BySize [61]struct {
+ // Size is the maximum byte size of an object in this
+ // size class.
+ Size uint32
+
+ // Mallocs is the cumulative count of heap objects
+ // allocated in this size class. The cumulative bytes
+ // of allocation is Size*Mallocs. The number of live
+ // objects in this size class is Mallocs - Frees.
+ Mallocs uint64
+
+ // Frees is the cumulative count of heap objects freed
+ // in this size class.
+ Frees uint64
+ }
+}
+
+// Size of the trailing by_size array differs between mstats and MemStats,
+// and all data after by_size is local to runtime, not exported.
+// NumSizeClasses was changed, but we cannot change MemStats because of backward compatibility.
+// sizeof_C_MStats is the size of the prefix of mstats that
+// corresponds to MemStats. It should match Sizeof(MemStats{}).
+var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
+
+func init() {
+ var memStats MemStats
+ if sizeof_C_MStats != unsafe.Sizeof(memStats) {
+ println(sizeof_C_MStats, unsafe.Sizeof(memStats))
+ throw("MStats vs MemStatsType size mismatch")
+ }
+
+ if unsafe.Offsetof(memstats.heap_live)%8 != 0 {
+ println(unsafe.Offsetof(memstats.heap_live))
+ throw("memstats.heap_live not aligned to 8 bytes")
+ }
+}
+
+// ReadMemStats populates m with memory allocator statistics.
+//
+// The returned memory allocator statistics are up to date as of the
+// call to ReadMemStats. This is in contrast with a heap profile,
+// which is a snapshot as of the most recently completed garbage
+// collection cycle.
+func ReadMemStats(m *MemStats) {
+ stopTheWorld("read mem stats")
+
+ systemstack(func() {
+ readmemstats_m(m)
+ })
+
+ startTheWorld()
+}
+
+func readmemstats_m(stats *MemStats) {
+ updatememstats(nil)
+
+ // The size of the trailing by_size array differs between
+ // mstats and MemStats. NumSizeClasses was changed, but we
+ // cannot change MemStats because of backward compatibility.
+ memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
+
+ // Stack numbers are part of the heap numbers, separate those out for user consumption
+ stats.StackSys += stats.StackInuse
+ stats.HeapInuse -= stats.StackInuse
+ stats.HeapSys -= stats.StackInuse
+}
+
+// For gccgo this is in runtime/mgc0.c.
+func updatememstats(stats *gcstats)
+
+/*
+For gccgo these are still in runtime/mgc0.c.
+
+//go:linkname readGCStats runtime/debug.readGCStats
+func readGCStats(pauses *[]uint64) {
+ systemstack(func() {
+ readGCStats_m(pauses)
+ })
+}
+
+func readGCStats_m(pauses *[]uint64) {
+ p := *pauses
+ // Calling code in runtime/debug should make the slice large enough.
+ if cap(p) < len(memstats.pause_ns)+3 {
+ throw("short slice passed to readGCStats")
+ }
+
+ // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
+ lock(&mheap_.lock)
+
+ n := memstats.numgc
+ if n > uint32(len(memstats.pause_ns)) {
+ n = uint32(len(memstats.pause_ns))
+ }
+
+ // The pause buffer is circular. The most recent pause is at
+ // pause_ns[(numgc-1)%len(pause_ns)], and then backward
+ // from there to go back farther in time. We deliver the times
+ // most recent first (in p[0]).
+ p = p[:cap(p)]
+ for i := uint32(0); i < n; i++ {
+ j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns))
+ p[i] = memstats.pause_ns[j]
+ p[n+i] = memstats.pause_end[j]
+ }
+
+ p[n+n] = memstats.last_gc
+ p[n+n+1] = uint64(memstats.numgc)
+ p[n+n+2] = memstats.pause_total_ns
+ unlock(&mheap_.lock)
+ *pauses = p[:n+n+3]
+}
+
+//go:nowritebarrier
+func updatememstats(stats *gcstats) {
+ if stats != nil {
+ *stats = gcstats{}
+ }
+ for mp := allm; mp != nil; mp = mp.alllink {
+ if stats != nil {
+ src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats))
+ dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats))
+ for i, v := range src {
+ dst[i] += v
+ }
+ mp.gcstats = gcstats{}
+ }
+ }
+
+ memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse)
+ memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse)
+ memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys +
+ memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys
+
+ // Calculate memory allocator stats.
+ // During program execution we only count number of frees and amount of freed memory.
+ // Current number of alive object in the heap and amount of alive heap memory
+ // are calculated by scanning all spans.
+ // Total number of mallocs is calculated as number of frees plus number of alive objects.
+ // Similarly, total amount of allocated memory is calculated as amount of freed memory
+ // plus amount of alive heap memory.
+ memstats.alloc = 0
+ memstats.total_alloc = 0
+ memstats.nmalloc = 0
+ memstats.nfree = 0
+ for i := 0; i < len(memstats.by_size); i++ {
+ memstats.by_size[i].nmalloc = 0
+ memstats.by_size[i].nfree = 0
+ }
+
+ // Flush MCache's to MCentral.
+ systemstack(flushallmcaches)
+
+ // Aggregate local stats.
+ cachestats()
+
+ // Scan all spans and count number of alive objects.
+ lock(&mheap_.lock)
+ for _, s := range mheap_.allspans {
+ if s.state != mSpanInUse {
+ continue
+ }
+ if s.sizeclass == 0 {
+ memstats.nmalloc++
+ memstats.alloc += uint64(s.elemsize)
+ } else {
+ memstats.nmalloc += uint64(s.allocCount)
+ memstats.by_size[s.sizeclass].nmalloc += uint64(s.allocCount)
+ memstats.alloc += uint64(s.allocCount) * uint64(s.elemsize)
+ }
+ }
+ unlock(&mheap_.lock)
+
+ // Aggregate by size class.
+ smallfree := uint64(0)
+ memstats.nfree = mheap_.nlargefree
+ for i := 0; i < len(memstats.by_size); i++ {
+ memstats.nfree += mheap_.nsmallfree[i]
+ memstats.by_size[i].nfree = mheap_.nsmallfree[i]
+ memstats.by_size[i].nmalloc += mheap_.nsmallfree[i]
+ smallfree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
+ }
+ memstats.nfree += memstats.tinyallocs
+ memstats.nmalloc += memstats.nfree
+
+ // Calculate derived stats.
+ memstats.total_alloc = memstats.alloc + mheap_.largefree + smallfree
+ memstats.heap_alloc = memstats.alloc
+ memstats.heap_objects = memstats.nmalloc - memstats.nfree
+}
+
+//go:nowritebarrier
+func cachestats() {
+ for i := 0; ; i++ {
+ p := allp[i]
+ if p == nil {
+ break
+ }
+ c := p.mcache
+ if c == nil {
+ continue
+ }
+ purgecachedstats(c)
+ }
+}
+
+// flushmcache flushes the mcache of allp[i].
+//
+// The world must be stopped.
+//
+//go:nowritebarrier
+func flushmcache(i int) {
+ p := allp[i]
+ if p == nil {
+ return
+ }
+ c := p.mcache
+ if c == nil {
+ return
+ }
+ c.releaseAll()
+ stackcache_clear(c)
+}
+
+// flushallmcaches flushes the mcaches of all Ps.
+//
+// The world must be stopped.
+//
+//go:nowritebarrier
+func flushallmcaches() {
+ for i := 0; i < int(gomaxprocs); i++ {
+ flushmcache(i)
+ }
+}
+
+//go:nosplit
+func purgecachedstats(c *mcache) {
+ // Protected by either heap or GC lock.
+ h := &mheap_
+ memstats.heap_scan += uint64(c.local_scan)
+ c.local_scan = 0
+ memstats.tinyallocs += uint64(c.local_tinyallocs)
+ c.local_tinyallocs = 0
+ memstats.nlookup += uint64(c.local_nlookup)
+ c.local_nlookup = 0
+ h.largefree += uint64(c.local_largefree)
+ c.local_largefree = 0
+ h.nlargefree += uint64(c.local_nlargefree)
+ c.local_nlargefree = 0
+ for i := 0; i < len(c.local_nsmallfree); i++ {
+ h.nsmallfree[i] += uint64(c.local_nsmallfree[i])
+ c.local_nsmallfree[i] = 0
+ }
+}
+
+*/
+
+// Atomically increases a given *system* memory stat. We are counting on this
+// stat never overflowing a uintptr, so this function must only be used for
+// system memory stats.
+//
+// The current implementation for little endian architectures is based on
+// xadduintptr(), which is less than ideal: xadd64() should really be used.
+// Using xadduintptr() is a stop-gap solution until arm supports xadd64() that
+// doesn't use locks. (Locks are a problem as they require a valid G, which
+// restricts their useability.)
+//
+// A side-effect of using xadduintptr() is that we need to check for
+// overflow errors.
+//go:nosplit
+func mSysStatInc(sysStat *uint64, n uintptr) {
+ if sys.BigEndian != 0 {
+ atomic.Xadd64(sysStat, int64(n))
+ return
+ }
+ if val := atomic.Xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), n); val < n {
+ print("runtime: stat overflow: val ", val, ", n ", n, "\n")
+ exit(2)
+ }
+}
+
+// Atomically decreases a given *system* memory stat. Same comments as
+// mSysStatInc apply.
+//go:nosplit
+func mSysStatDec(sysStat *uint64, n uintptr) {
+ if sys.BigEndian != 0 {
+ atomic.Xadd64(sysStat, -int64(n))
+ return
+ }
+ if val := atomic.Xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), uintptr(-int64(n))); val+n < n {
+ print("runtime: stat underflow: val ", val, ", n ", n, "\n")
+ exit(2)
+ }
+}
diff --git a/libgo/go/runtime/mstkbar.go b/libgo/go/runtime/mstkbar.go
index 016625ae92..616c220132 100644
--- a/libgo/go/runtime/mstkbar.go
+++ b/libgo/go/runtime/mstkbar.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
// Garbage collector: stack barriers
//
// Stack barriers enable the garbage collector to determine how much
@@ -148,6 +150,10 @@ var firstStackBarrierOffset = 1024
// gcMaxStackBarriers returns the maximum number of stack barriers
// that can be installed in a stack of stackSize bytes.
func gcMaxStackBarriers(stackSize int) (n int) {
+ if debug.gcstackbarrieroff > 0 {
+ return 0
+ }
+
if firstStackBarrierOffset == 0 {
// Special debugging case for inserting stack barriers
// at every frame. Steal half of the stack for the
@@ -214,14 +220,15 @@ func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
}
// gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
+//
+// gp's stack barriers must be locked.
+//
//go:nowritebarrier
func gcRemoveStackBarriers(gp *g) {
if debugStackBarrier && gp.stkbarPos != 0 {
print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
}
- gcLockStackBarriers(gp)
-
// Remove stack barriers that we didn't hit.
for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
gcRemoveStackBarrier(gp, stkbar)
@@ -231,8 +238,6 @@ func gcRemoveStackBarriers(gp *g) {
// adjust them.
gp.stkbarPos = 0
gp.stkbar = gp.stkbar[:0]
-
- gcUnlockStackBarriers(gp)
}
// gcRemoveStackBarrier removes a single stack barrier. It is the
@@ -258,6 +263,31 @@ func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
*lrPtr = sys.Uintreg(stkbar.savedLRVal)
}
+// gcTryRemoveAllStackBarriers tries to remove stack barriers from all
+// Gs in gps. It is best-effort and efficient. If it can't remove
+// barriers from a G immediately, it will simply skip it.
+func gcTryRemoveAllStackBarriers(gps []*g) {
+ for _, gp := range gps {
+ retry:
+ for {
+ switch s := readgstatus(gp); s {
+ default:
+ break retry
+
+ case _Grunnable, _Gsyscall, _Gwaiting:
+ if !castogscanstatus(gp, s, s|_Gscan) {
+ continue
+ }
+ gcLockStackBarriers(gp)
+ gcRemoveStackBarriers(gp)
+ gcUnlockStackBarriers(gp)
+ restartg(gp)
+ break retry
+ }
+ }
+ }
+}
+
// gcPrintStkbars prints the stack barriers of gp for debugging. It
// places a "@@@" marker at gp.stkbarPos. If marker >= 0, it will also
// place a "==>" marker before the marker'th entry.
diff --git a/libgo/go/runtime/net_plan9.go b/libgo/go/runtime/net_plan9.go
new file mode 100644
index 0000000000..10fd089aea
--- /dev/null
+++ b/libgo/go/runtime/net_plan9.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ _ "unsafe"
+)
+
+//go:linkname runtime_ignoreHangup net.runtime_ignoreHangup
+func runtime_ignoreHangup() {
+ getg().m.ignoreHangup = true
+}
+
+//go:linkname runtime_unignoreHangup net.runtime_unignoreHangup
+func runtime_unignoreHangup(sig string) {
+ getg().m.ignoreHangup = false
+}
+
+func ignoredNote(note *byte) bool {
+ if note == nil {
+ return false
+ }
+ if gostringnocopy(note) != "hangup" {
+ return false
+ }
+ return getg().m.ignoreHangup
+}
diff --git a/libgo/go/runtime/netpoll.go b/libgo/go/runtime/netpoll.go
new file mode 100644
index 0000000000..876eaeac79
--- /dev/null
+++ b/libgo/go/runtime/netpoll.go
@@ -0,0 +1,456 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// Export temporarily for gccgo's C code to call:
+//go:linkname netpoll runtime.netpoll
+
+// Integrated network poller (platform-independent part).
+// A particular implementation (epoll/kqueue) must define the following functions:
+// func netpollinit() // to initialize the poller
+// func netpollopen(fd uintptr, pd *pollDesc) int32 // to arm edge-triggered notifications
+// and associate fd with pd.
+// An implementation must call the following function to denote that the pd is ready.
+// func netpollready(gpp **g, pd *pollDesc, mode int32)
+
+// pollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
+// goroutines respectively. The semaphore can be in the following states:
+// pdReady - io readiness notification is pending;
+// a goroutine consumes the notification by changing the state to nil.
+// pdWait - a goroutine prepares to park on the semaphore, but not yet parked;
+// the goroutine commits to park by changing the state to G pointer,
+// or, alternatively, concurrent io notification changes the state to READY,
+// or, alternatively, concurrent timeout/close changes the state to nil.
+// G pointer - the goroutine is blocked on the semaphore;
+// io notification or timeout/close changes the state to READY or nil respectively
+// and unparks the goroutine.
+// nil - nothing of the above.
+const (
+ pdReady uintptr = 1
+ pdWait uintptr = 2
+)
+
+const pollBlockSize = 4 * 1024
+
+// Network poller descriptor.
+//
+// No heap pointers.
+//
+//go:notinheap
+type pollDesc struct {
+ link *pollDesc // in pollcache, protected by pollcache.lock
+
+ // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
+ // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
+ // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification)
+ // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
+ // in a lock-free way by all operations.
+ // NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
+ // that will blow up when GC starts moving objects.
+ lock mutex // protects the following fields
+ fd uintptr
+ closing bool
+ seq uintptr // protects from stale timers and ready notifications
+ rg uintptr // pdReady, pdWait, G waiting for read or nil
+ rt timer // read deadline timer (set if rt.f != nil)
+ rd int64 // read deadline
+ wg uintptr // pdReady, pdWait, G waiting for write or nil
+ wt timer // write deadline timer
+ wd int64 // write deadline
+ user uint32 // user settable cookie
+}
+
+type pollCache struct {
+ lock mutex
+ first *pollDesc
+ // PollDesc objects must be type-stable,
+ // because we can get ready notification from epoll/kqueue
+ // after the descriptor is closed/reused.
+ // Stale notifications are detected using seq variable,
+ // seq is incremented when deadlines are changed or descriptor is reused.
+}
+
+var (
+ netpollInited uint32
+ pollcache pollCache
+)
+
+//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
+func net_runtime_pollServerInit() {
+ netpollinit()
+ atomic.Store(&netpollInited, 1)
+}
+
+func netpollinited() bool {
+ return atomic.Load(&netpollInited) != 0
+}
+
+//go:linkname net_runtime_pollOpen net.runtime_pollOpen
+func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
+ pd := pollcache.alloc()
+ lock(&pd.lock)
+ if pd.wg != 0 && pd.wg != pdReady {
+ throw("netpollOpen: blocked write on free descriptor")
+ }
+ if pd.rg != 0 && pd.rg != pdReady {
+ throw("netpollOpen: blocked read on free descriptor")
+ }
+ pd.fd = fd
+ pd.closing = false
+ pd.seq++
+ pd.rg = 0
+ pd.rd = 0
+ pd.wg = 0
+ pd.wd = 0
+ unlock(&pd.lock)
+
+ var errno int32
+ errno = netpollopen(fd, pd)
+ return pd, int(errno)
+}
+
+//go:linkname net_runtime_pollClose net.runtime_pollClose
+func net_runtime_pollClose(pd *pollDesc) {
+ if !pd.closing {
+ throw("netpollClose: close w/o unblock")
+ }
+ if pd.wg != 0 && pd.wg != pdReady {
+ throw("netpollClose: blocked write on closing descriptor")
+ }
+ if pd.rg != 0 && pd.rg != pdReady {
+ throw("netpollClose: blocked read on closing descriptor")
+ }
+ netpollclose(pd.fd)
+ pollcache.free(pd)
+}
+
+func (c *pollCache) free(pd *pollDesc) {
+ lock(&c.lock)
+ pd.link = c.first
+ c.first = pd
+ unlock(&c.lock)
+}
+
+//go:linkname net_runtime_pollReset net.runtime_pollReset
+func net_runtime_pollReset(pd *pollDesc, mode int) int {
+ err := netpollcheckerr(pd, int32(mode))
+ if err != 0 {
+ return err
+ }
+ if mode == 'r' {
+ pd.rg = 0
+ } else if mode == 'w' {
+ pd.wg = 0
+ }
+ return 0
+}
+
+//go:linkname net_runtime_pollWait net.runtime_pollWait
+func net_runtime_pollWait(pd *pollDesc, mode int) int {
+ err := netpollcheckerr(pd, int32(mode))
+ if err != 0 {
+ return err
+ }
+ // As for now only Solaris uses level-triggered IO.
+ if GOOS == "solaris" {
+ netpollarm(pd, mode)
+ }
+ for !netpollblock(pd, int32(mode), false) {
+ err = netpollcheckerr(pd, int32(mode))
+ if err != 0 {
+ return err
+ }
+ // Can happen if timeout has fired and unblocked us,
+ // but before we had a chance to run, timeout has been reset.
+ // Pretend it has not happened and retry.
+ }
+ return 0
+}
+
+//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled
+func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
+ // This function is used only on windows after a failed attempt to cancel
+ // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
+ for !netpollblock(pd, int32(mode), true) {
+ }
+}
+
+//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline
+func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+ lock(&pd.lock)
+ if pd.closing {
+ unlock(&pd.lock)
+ return
+ }
+ pd.seq++ // invalidate current timers
+ // Reset current timers.
+ if pd.rt.f != nil {
+ deltimer(&pd.rt)
+ pd.rt.f = nil
+ }
+ if pd.wt.f != nil {
+ deltimer(&pd.wt)
+ pd.wt.f = nil
+ }
+ // Setup new timers.
+ if d != 0 && d <= nanotime() {
+ d = -1
+ }
+ if mode == 'r' || mode == 'r'+'w' {
+ pd.rd = d
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ pd.wd = d
+ }
+ if pd.rd > 0 && pd.rd == pd.wd {
+ pd.rt.f = netpollDeadline
+ pd.rt.when = pd.rd
+ // Copy current seq into the timer arg.
+ // Timer func will check the seq against current descriptor seq,
+ // if they differ the descriptor was reused or timers were reset.
+ pd.rt.arg = pd
+ pd.rt.seq = pd.seq
+ addtimer(&pd.rt)
+ } else {
+ if pd.rd > 0 {
+ pd.rt.f = netpollReadDeadline
+ pd.rt.when = pd.rd
+ pd.rt.arg = pd
+ pd.rt.seq = pd.seq
+ addtimer(&pd.rt)
+ }
+ if pd.wd > 0 {
+ pd.wt.f = netpollWriteDeadline
+ pd.wt.when = pd.wd
+ pd.wt.arg = pd
+ pd.wt.seq = pd.seq
+ addtimer(&pd.wt)
+ }
+ }
+ // If we set the new deadline in the past, unblock currently pending IO if any.
+ var rg, wg *g
+ atomicstorep(unsafe.Pointer(&wg), nil) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
+ if pd.rd < 0 {
+ rg = netpollunblock(pd, 'r', false)
+ }
+ if pd.wd < 0 {
+ wg = netpollunblock(pd, 'w', false)
+ }
+ unlock(&pd.lock)
+ if rg != nil {
+ goready(rg, 3)
+ }
+ if wg != nil {
+ goready(wg, 3)
+ }
+}
+
+//go:linkname net_runtime_pollUnblock net.runtime_pollUnblock
+func net_runtime_pollUnblock(pd *pollDesc) {
+ lock(&pd.lock)
+ if pd.closing {
+ throw("netpollUnblock: already closing")
+ }
+ pd.closing = true
+ pd.seq++
+ var rg, wg *g
+ atomicstorep(unsafe.Pointer(&rg), nil) // full memory barrier between store to closing and read of rg/wg in netpollunblock
+ rg = netpollunblock(pd, 'r', false)
+ wg = netpollunblock(pd, 'w', false)
+ if pd.rt.f != nil {
+ deltimer(&pd.rt)
+ pd.rt.f = nil
+ }
+ if pd.wt.f != nil {
+ deltimer(&pd.wt)
+ pd.wt.f = nil
+ }
+ unlock(&pd.lock)
+ if rg != nil {
+ goready(rg, 3)
+ }
+ if wg != nil {
+ goready(wg, 3)
+ }
+}
+
+// make pd ready, newly runnable goroutines (if any) are returned in rg/wg
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func netpollready(gpp *guintptr, pd *pollDesc, mode int32) {
+ var rg, wg guintptr
+ if mode == 'r' || mode == 'r'+'w' {
+ rg.set(netpollunblock(pd, 'r', true))
+ }
+ if mode == 'w' || mode == 'r'+'w' {
+ wg.set(netpollunblock(pd, 'w', true))
+ }
+ if rg != 0 {
+ rg.ptr().schedlink = *gpp
+ *gpp = rg
+ }
+ if wg != 0 {
+ wg.ptr().schedlink = *gpp
+ *gpp = wg
+ }
+}
+
+func netpollcheckerr(pd *pollDesc, mode int32) int {
+ if pd.closing {
+ return 1 // errClosing
+ }
+ if (mode == 'r' && pd.rd < 0) || (mode == 'w' && pd.wd < 0) {
+ return 2 // errTimeout
+ }
+ return 0
+}
+
+func netpollblockcommit(gp *g, gpp unsafe.Pointer) bool {
+ return atomic.Casuintptr((*uintptr)(gpp), pdWait, uintptr(unsafe.Pointer(gp)))
+}
+
+// returns true if IO is ready, or false if timedout or closed
+// waitio - wait only for completed IO, ignore errors
+func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
+ gpp := &pd.rg
+ if mode == 'w' {
+ gpp = &pd.wg
+ }
+
+ // set the gpp semaphore to WAIT
+ for {
+ old := *gpp
+ if old == pdReady {
+ *gpp = 0
+ return true
+ }
+ if old != 0 {
+ throw("netpollblock: double wait")
+ }
+ if atomic.Casuintptr(gpp, 0, pdWait) {
+ break
+ }
+ }
+
+ // need to recheck error states after setting gpp to WAIT
+ // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
+ // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
+ if waitio || netpollcheckerr(pd, mode) == 0 {
+ gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet, 5)
+ }
+ // be careful to not lose concurrent READY notification
+ old := atomic.Xchguintptr(gpp, 0)
+ if old > pdWait {
+ throw("netpollblock: corrupted state")
+ }
+ return old == pdReady
+}
+
+func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
+ gpp := &pd.rg
+ if mode == 'w' {
+ gpp = &pd.wg
+ }
+
+ for {
+ old := *gpp
+ if old == pdReady {
+ return nil
+ }
+ if old == 0 && !ioready {
+ // Only set READY for ioready. runtime_pollWait
+ // will check for timeout/cancel before waiting.
+ return nil
+ }
+ var new uintptr
+ if ioready {
+ new = pdReady
+ }
+ if atomic.Casuintptr(gpp, old, new) {
+ if old == pdReady || old == pdWait {
+ old = 0
+ }
+ return (*g)(unsafe.Pointer(old))
+ }
+ }
+}
+
+func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
+ lock(&pd.lock)
+ // Seq arg is seq when the timer was set.
+ // If it's stale, ignore the timer event.
+ if seq != pd.seq {
+ // The descriptor was reused or timers were reset.
+ unlock(&pd.lock)
+ return
+ }
+ var rg *g
+ if read {
+ if pd.rd <= 0 || pd.rt.f == nil {
+ throw("netpolldeadlineimpl: inconsistent read deadline")
+ }
+ pd.rd = -1
+ atomicstorep(unsafe.Pointer(&pd.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock
+ rg = netpollunblock(pd, 'r', false)
+ }
+ var wg *g
+ if write {
+ if pd.wd <= 0 || pd.wt.f == nil && !read {
+ throw("netpolldeadlineimpl: inconsistent write deadline")
+ }
+ pd.wd = -1
+ atomicstorep(unsafe.Pointer(&pd.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock
+ wg = netpollunblock(pd, 'w', false)
+ }
+ unlock(&pd.lock)
+ if rg != nil {
+ goready(rg, 0)
+ }
+ if wg != nil {
+ goready(wg, 0)
+ }
+}
+
+func netpollDeadline(arg interface{}, seq uintptr) {
+ netpolldeadlineimpl(arg.(*pollDesc), seq, true, true)
+}
+
+func netpollReadDeadline(arg interface{}, seq uintptr) {
+ netpolldeadlineimpl(arg.(*pollDesc), seq, true, false)
+}
+
+func netpollWriteDeadline(arg interface{}, seq uintptr) {
+ netpolldeadlineimpl(arg.(*pollDesc), seq, false, true)
+}
+
+func (c *pollCache) alloc() *pollDesc {
+ lock(&c.lock)
+ if c.first == nil {
+ const pdSize = unsafe.Sizeof(pollDesc{})
+ n := pollBlockSize / pdSize
+ if n == 0 {
+ n = 1
+ }
+ // Must be in non-GC memory because can be referenced
+ // only from epoll/kqueue internals.
+ mem := persistentalloc(n*pdSize, 0, &memstats.other_sys)
+ for i := uintptr(0); i < n; i++ {
+ pd := (*pollDesc)(add(mem, i*pdSize))
+ pd.link = c.first
+ c.first = pd
+ }
+ }
+ pd := c.first
+ c.first = pd.link
+ unlock(&c.lock)
+ return pd
+}
diff --git a/libgo/go/runtime/netpoll_epoll.go b/libgo/go/runtime/netpoll_epoll.go
new file mode 100644
index 0000000000..247692ef04
--- /dev/null
+++ b/libgo/go/runtime/netpoll_epoll.go
@@ -0,0 +1,116 @@
+// 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.
+
+// +build linux
+
+package runtime
+
+import "unsafe"
+
+//extern epoll_create
+func epollcreate(size int32) int32
+
+//extern epoll_create1
+func epollcreate1(flags int32) int32
+
+//go:noescape
+//extern epoll_ctl
+func epollctl(epfd, op, fd int32, ev *epollevent) int32
+
+//go:noescape
+//extern epoll_wait
+func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32
+
+//extern __go_fcntl_uintptr
+func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
+
+func closeonexec(fd int32) {
+ fcntlUintptr(uintptr(fd), _F_SETFD, _FD_CLOEXEC)
+}
+
+var (
+ epfd int32 = -1 // epoll descriptor
+)
+
+func netpollinit() {
+ epfd = epollcreate1(_EPOLL_CLOEXEC)
+ if epfd >= 0 {
+ return
+ }
+ epfd = epollcreate(1024)
+ if epfd >= 0 {
+ closeonexec(epfd)
+ return
+ }
+ println("netpollinit: failed to create epoll descriptor", errno())
+ throw("netpollinit: failed to create descriptor")
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ var ev epollevent
+ ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLETpos
+ *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd
+ if epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev) < 0 {
+ return int32(errno())
+ }
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ var ev epollevent
+ if epollctl(epfd, _EPOLL_CTL_DEL, int32(fd), &ev) < 0 {
+ return int32(errno())
+ }
+ return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+ throw("unused")
+}
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+func netpoll(block bool) *g {
+ if epfd == -1 {
+ return nil
+ }
+ waitms := int32(-1)
+ if !block {
+ waitms = 0
+ }
+ var events [128]epollevent
+retry:
+ n := epollwait(epfd, &events[0], int32(len(events)), waitms)
+ if n < 0 {
+ e := errno()
+ if e != _EINTR {
+ println("runtime: epollwait on fd", epfd, "failed with", e)
+ throw("epollwait failed")
+ }
+ goto retry
+ }
+ var gp guintptr
+ for i := int32(0); i < n; i++ {
+ ev := &events[i]
+ if ev.events == 0 {
+ continue
+ }
+ var mode int32
+ if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 {
+ mode += 'r'
+ }
+ if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 {
+ mode += 'w'
+ }
+ if mode != 0 {
+ pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
+
+ netpollready(&gp, pd, mode)
+ }
+ }
+ if block && gp == 0 {
+ goto retry
+ }
+ return gp.ptr()
+}
diff --git a/libgo/go/runtime/netpoll_kqueue.go b/libgo/go/runtime/netpoll_kqueue.go
new file mode 100644
index 0000000000..eae4f21d1d
--- /dev/null
+++ b/libgo/go/runtime/netpoll_kqueue.go
@@ -0,0 +1,110 @@
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package runtime
+
+// Integrated network poller (kqueue-based implementation).
+
+import "unsafe"
+
+//extern kqueue
+func kqueue() int32
+
+//go:noescape
+//extern kevent
+func kevent(kq int32, ch *keventt, nch uintptr, ev *keventt, nev uintptr, ts *timespec) int32
+
+//extern __go_fcntl_uintptr
+func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
+
+func closeonexec(fd int32) {
+ fcntlUintptr(uintptr(fd), _F_SETFD, _FD_CLOEXEC)
+}
+
+var (
+ kq int32 = -1
+)
+
+func netpollinit() {
+ kq = kqueue()
+ if kq < 0 {
+ println("netpollinit: kqueue failed with", errno())
+ throw("netpollinit: kqueue failed")
+ }
+ closeonexec(kq)
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR)
+ // for the whole fd lifetime. The notifications are automatically unregistered
+ // when fd is closed.
+ var ev [2]keventt
+ *(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd
+ ev[0].filter = _EVFILT_READ
+ ev[0].flags = _EV_ADD | _EV_CLEAR
+ ev[0].fflags = 0
+ ev[0].data = 0
+ ev[0].udata = (*byte)(unsafe.Pointer(pd))
+ ev[1] = ev[0]
+ ev[1].filter = _EVFILT_WRITE
+ n := kevent(kq, &ev[0], 2, nil, 0, nil)
+ if n < 0 {
+ return int32(errno())
+ }
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ // Don't need to unregister because calling close()
+ // on fd will remove any kevents that reference the descriptor.
+ return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+ throw("unused")
+}
+
+// Polls for ready network connections.
+// Returns list of goroutines that become runnable.
+func netpoll(block bool) *g {
+ if kq == -1 {
+ return nil
+ }
+ var tp *timespec
+ var ts timespec
+ if !block {
+ tp = &ts
+ }
+ var events [64]keventt
+retry:
+ n := kevent(kq, nil, 0, &events[0], uintptr(len(events)), tp)
+ if n < 0 {
+ e := errno()
+ if e != _EINTR {
+ println("runtime: kevent on fd", kq, "failed with", e)
+ throw("kevent failed")
+ }
+ goto retry
+ }
+ var gp guintptr
+ for i := 0; i < int(n); i++ {
+ ev := &events[i]
+ var mode int32
+ if ev.filter == _EVFILT_READ {
+ mode += 'r'
+ }
+ if ev.filter == _EVFILT_WRITE {
+ mode += 'w'
+ }
+ if mode != 0 {
+ netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
+ }
+ }
+ if block && gp == 0 {
+ goto retry
+ }
+ return gp.ptr()
+}
diff --git a/libgo/go/runtime/netpoll_nacl.go b/libgo/go/runtime/netpoll_nacl.go
new file mode 100644
index 0000000000..5cbc300321
--- /dev/null
+++ b/libgo/go/runtime/netpoll_nacl.go
@@ -0,0 +1,26 @@
+// 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.
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+package runtime
+
+func netpollinit() {
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+}
+
+func netpoll(block bool) *g {
+ return nil
+}
diff --git a/libgo/go/runtime/netpoll_solaris.go b/libgo/go/runtime/netpoll_solaris.go
new file mode 100644
index 0000000000..cc6754cd2e
--- /dev/null
+++ b/libgo/go/runtime/netpoll_solaris.go
@@ -0,0 +1,225 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+// Solaris runtime-integrated network poller.
+//
+// Solaris uses event ports for scalable network I/O. Event
+// ports are level-triggered, unlike epoll and kqueue which
+// can be configured in both level-triggered and edge-triggered
+// mode. Level triggering means we have to keep track of a few things
+// ourselves. After we receive an event for a file descriptor,
+// it's our responsibility to ask again to be notified for future
+// events for that descriptor. When doing this we must keep track of
+// what kind of events the goroutines are currently interested in,
+// for example a fd may be open both for reading and writing.
+//
+// A description of the high level operation of this code
+// follows. Networking code will get a file descriptor by some means
+// and will register it with the netpolling mechanism by a code path
+// that eventually calls runtime·netpollopen. runtime·netpollopen
+// calls port_associate with an empty event set. That means that we
+// will not receive any events at this point. The association needs
+// to be done at this early point because we need to process the I/O
+// readiness notification at some point in the future. If I/O becomes
+// ready when nobody is listening, when we finally care about it,
+// nobody will tell us anymore.
+//
+// Beside calling runtime·netpollopen, the networking code paths
+// will call runtime·netpollarm each time goroutines are interested
+// in doing network I/O. Because now we know what kind of I/O we
+// are interested in (reading/writing), we can call port_associate
+// passing the correct type of event set (POLLIN/POLLOUT). As we made
+// sure to have already associated the file descriptor with the port,
+// when we now call port_associate, we will unblock the main poller
+// loop (in runtime·netpoll) right away if the socket is actually
+// ready for I/O.
+//
+// The main poller loop runs in its own thread waiting for events
+// using port_getn. When an event happens, it will tell the scheduler
+// about it using runtime·netpollready. Besides doing this, it must
+// also re-associate the events that were not part of this current
+// notification with the file descriptor. Failing to do this would
+// mean each notification will prevent concurrent code using the
+// same file descriptor in parallel.
+//
+// The logic dealing with re-associations is encapsulated in
+// runtime·netpollupdate. This function takes care to associate the
+// descriptor only with the subset of events that were previously
+// part of the association, except the one that just happened. We
+// can't re-associate with that right away, because event ports
+// are level triggered so it would cause a busy loop. Instead, that
+// association is effected only by the runtime·netpollarm code path,
+// when Go code actually asks for I/O.
+//
+// The open and arming mechanisms are serialized using the lock
+// inside PollDesc. This is required because the netpoll loop runs
+// asynchronously in respect to other Go code and by the time we get
+// to call port_associate to update the association in the loop, the
+// file descriptor might have been closed and reopened already. The
+// lock allows runtime·netpollupdate to be called synchronously from
+// the loop thread while preventing other threads operating to the
+// same PollDesc, so once we unblock in the main loop, until we loop
+// again we know for sure we are always talking about the same file
+// descriptor and can safely access the data we want (the event set).
+
+//extern __go_fcntl_uintptr
+func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
+
+func fcntl(fd, cmd int32, arg uintptr) int32 {
+ r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
+ return int32(r)
+}
+
+//extern port_create
+func port_create() int32
+
+//extern port_associate
+func port_associate(port, source int32, object uintptr, events uint32, user uintptr) int32
+
+//extern port_dissociate
+func port_dissociate(port, source int32, object uintptr) int32
+
+//extern port_getn
+func port_getn(port int32, evs *portevent, max uint32, nget *uint32, timeout *timespec) int32
+
+var portfd int32 = -1
+
+func netpollinit() {
+ portfd = port_create()
+ if portfd >= 0 {
+ fcntl(portfd, _F_SETFD, _FD_CLOEXEC)
+ return
+ }
+
+ print("netpollinit: failed to create port (", errno(), ")\n")
+ throw("netpollinit: failed to create port")
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ lock(&pd.lock)
+ // We don't register for any specific type of events yet, that's
+ // netpollarm's job. We merely ensure we call port_associate before
+ // asynchronous connect/accept completes, so when we actually want
+ // to do any I/O, the call to port_associate (from netpollarm,
+ // with the interested event set) will unblock port_getn right away
+ // because of the I/O readiness notification.
+ pd.user = 0
+ r := port_associate(portfd, _PORT_SOURCE_FD, fd, 0, uintptr(unsafe.Pointer(pd)))
+ unlock(&pd.lock)
+ if r < 0 {
+ return int32(errno())
+ }
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ if port_dissociate(portfd, _PORT_SOURCE_FD, fd) < 0 {
+ return int32(errno())
+ }
+ return 0
+}
+
+// Updates the association with a new set of interested events. After
+// this call, port_getn will return one and only one event for that
+// particular descriptor, so this function needs to be called again.
+func netpollupdate(pd *pollDesc, set, clear uint32) {
+ if pd.closing {
+ return
+ }
+
+ old := pd.user
+ events := (old & ^clear) | set
+ if old == events {
+ return
+ }
+
+ if events != 0 && port_associate(portfd, _PORT_SOURCE_FD, pd.fd, events, uintptr(unsafe.Pointer(pd))) != 0 {
+ print("netpollupdate: failed to associate (", errno(), ")\n")
+ throw("netpollupdate: failed to associate")
+ }
+ pd.user = events
+}
+
+// subscribe the fd to the port such that port_getn will return one event.
+func netpollarm(pd *pollDesc, mode int) {
+ lock(&pd.lock)
+ switch mode {
+ case 'r':
+ netpollupdate(pd, _POLLIN, 0)
+ case 'w':
+ netpollupdate(pd, _POLLOUT, 0)
+ default:
+ throw("netpollarm: bad mode")
+ }
+ unlock(&pd.lock)
+}
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+func netpoll(block bool) *g {
+ if portfd == -1 {
+ return nil
+ }
+
+ var wait *timespec
+ var zero timespec
+ if !block {
+ wait = &zero
+ }
+
+ var events [128]portevent
+retry:
+ var n uint32 = 1
+ if port_getn(portfd, &events[0], uint32(len(events)), &n, wait) < 0 {
+ if e := errno(); e != _EINTR {
+ print("runtime: port_getn on fd ", portfd, " failed with ", e, "\n")
+ throw("port_getn failed")
+ }
+ goto retry
+ }
+
+ var gp guintptr
+ for i := 0; i < int(n); i++ {
+ ev := &events[i]
+
+ if ev.portev_events == 0 {
+ continue
+ }
+ pd := (*pollDesc)(unsafe.Pointer(ev.portev_user))
+
+ var mode, clear int32
+ if (ev.portev_events & (_POLLIN | _POLLHUP | _POLLERR)) != 0 {
+ mode += 'r'
+ clear |= _POLLIN
+ }
+ if (ev.portev_events & (_POLLOUT | _POLLHUP | _POLLERR)) != 0 {
+ mode += 'w'
+ clear |= _POLLOUT
+ }
+ // To effect edge-triggered events, we need to be sure to
+ // update our association with whatever events were not
+ // set with the event. For example if we are registered
+ // for POLLIN|POLLOUT, and we get POLLIN, besides waking
+ // the goroutine interested in POLLIN we have to not forget
+ // about the one interested in POLLOUT.
+ if clear != 0 {
+ lock(&pd.lock)
+ netpollupdate(pd, 0, uint32(clear))
+ unlock(&pd.lock)
+ }
+
+ if mode != 0 {
+ netpollready(&gp, pd, mode)
+ }
+ }
+
+ if block && gp == 0 {
+ goto retry
+ }
+ return gp.ptr()
+}
diff --git a/libgo/runtime/netpoll_stub.c b/libgo/go/runtime/netpoll_stub.go
index 468a610f6f..09f64ad9b5 100644
--- a/libgo/runtime/netpoll_stub.c
+++ b/libgo/go/runtime/netpoll_stub.go
@@ -4,23 +4,16 @@
// +build plan9
-#include "runtime.h"
-#include "malloc.h"
+package runtime
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
-G*
-runtime_netpoll(bool block)
-{
+func netpoll(block bool) (gp *g) {
// Implementation for platforms that do not support
// integrated network poller.
- USED(block);
- return nil;
+ return
}
-void
-runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- USED(wbufp);
- USED(addroot);
+func netpollinited() bool {
+ return false
}
diff --git a/libgo/go/runtime/netpoll_windows.go b/libgo/go/runtime/netpoll_windows.go
new file mode 100644
index 0000000000..7ad115850d
--- /dev/null
+++ b/libgo/go/runtime/netpoll_windows.go
@@ -0,0 +1,145 @@
+// 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.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+const _DWORD_MAX = 0xffffffff
+
+const _INVALID_HANDLE_VALUE = ^uintptr(0)
+
+// net_op must be the same as beginning of net.operation. Keep these in sync.
+type net_op struct {
+ // used by windows
+ o overlapped
+ // used by netpoll
+ pd *pollDesc
+ mode int32
+ errno int32
+ qty uint32
+}
+
+type overlappedEntry struct {
+ key uintptr
+ op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
+ internal uintptr
+ qty uint32
+}
+
+var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
+
+func netpollinit() {
+ iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX)
+ if iocphandle == 0 {
+ println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
+ throw("netpoll: failed to create iocp handle")
+ }
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+ if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
+ return -int32(getlasterror())
+ }
+ return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+ // nothing to do
+ return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+ throw("unused")
+}
+
+// Polls for completed network IO.
+// Returns list of goroutines that become runnable.
+func netpoll(block bool) *g {
+ var entries [64]overlappedEntry
+ var wait, qty, key, flags, n, i uint32
+ var errno int32
+ var op *net_op
+ var gp guintptr
+
+ mp := getg().m
+
+ if iocphandle == _INVALID_HANDLE_VALUE {
+ return nil
+ }
+ wait = 0
+ if block {
+ wait = _INFINITE
+ }
+retry:
+ if _GetQueuedCompletionStatusEx != nil {
+ n = uint32(len(entries) / int(gomaxprocs))
+ if n < 8 {
+ n = 8
+ }
+ if block {
+ mp.blocked = true
+ }
+ if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
+ mp.blocked = false
+ errno = int32(getlasterror())
+ if !block && errno == _WAIT_TIMEOUT {
+ return nil
+ }
+ println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
+ throw("netpoll: GetQueuedCompletionStatusEx failed")
+ }
+ mp.blocked = false
+ for i = 0; i < n; i++ {
+ op = entries[i].op
+ errno = 0
+ qty = 0
+ if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
+ errno = int32(getlasterror())
+ }
+ handlecompletion(&gp, op, errno, qty)
+ }
+ } else {
+ op = nil
+ errno = 0
+ qty = 0
+ if block {
+ mp.blocked = true
+ }
+ if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
+ mp.blocked = false
+ errno = int32(getlasterror())
+ if !block && errno == _WAIT_TIMEOUT {
+ return nil
+ }
+ if op == nil {
+ println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
+ throw("netpoll: GetQueuedCompletionStatus failed")
+ }
+ // dequeued failed IO packet, so report that
+ }
+ mp.blocked = false
+ handlecompletion(&gp, op, errno, qty)
+ }
+ if block && gp == 0 {
+ goto retry
+ }
+ return gp.ptr()
+}
+
+func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
+ if op == nil {
+ throw("netpoll: GetQueuedCompletionStatus returned op == nil")
+ }
+ mode := op.mode
+ if mode != 'r' && mode != 'w' {
+ println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
+ throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
+ }
+ op.errno = errno
+ op.qty = qty
+ netpollready(gpp, op.pd, mode)
+}
diff --git a/libgo/go/runtime/norace_test.go b/libgo/go/runtime/norace_test.go
index 3681bf190d..e9b39b2f45 100644
--- a/libgo/go/runtime/norace_test.go
+++ b/libgo/go/runtime/norace_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The file contains tests that can not run under race detector for some reason.
+// The file contains tests that cannot run under race detector for some reason.
// +build !race
package runtime_test
diff --git a/libgo/go/runtime/os1_linux_generic.go b/libgo/go/runtime/os1_linux_generic.go
deleted file mode 100644
index 2c8b743aeb..0000000000
--- a/libgo/go/runtime/os1_linux_generic.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !mips64
-// +build !mips64le
-// +build linux
-
-package runtime
-
-var sigset_all = sigset{^uint32(0), ^uint32(0)}
-
-func sigaddset(mask *sigset, i int) {
- (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
-}
-
-func sigdelset(mask *sigset, i int) {
- (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
-}
-
-func sigfillset(mask *uint64) {
- *mask = ^uint64(0)
-}
-
-func sigcopyset(mask *sigset, m sigmask) {
- copy((*mask)[:], m[:])
-}
diff --git a/libgo/go/runtime/os1_linux_mips64x.go b/libgo/go/runtime/os1_linux_mips64x.go
deleted file mode 100644
index 701e979102..0000000000
--- a/libgo/go/runtime/os1_linux_mips64x.go
+++ /dev/null
@@ -1,26 +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 mips64 mips64le
-// +build linux
-
-package runtime
-
-var sigset_all = sigset{^uint64(0), ^uint64(0)}
-
-func sigaddset(mask *sigset, i int) {
- (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
-}
-
-func sigdelset(mask *sigset, i int) {
- (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
-}
-
-func sigfillset(mask *[2]uint64) {
- (*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0)
-}
-
-func sigcopyset(mask *sigset, m sigmask) {
- (*mask)[0] = uint64(m[0]) | uint64(m[1])<<32
-}
diff --git a/libgo/go/runtime/os2_linux_generic.go b/libgo/go/runtime/os2_linux_generic.go
deleted file mode 100644
index 01e6c8a5ec..0000000000
--- a/libgo/go/runtime/os2_linux_generic.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !mips64
-// +build !mips64le
-// +build linux
-
-package runtime
-
-const (
- _SS_DISABLE = 2
- _NSIG = 65
- _SI_USER = 0
- _SIG_BLOCK = 0
- _SIG_UNBLOCK = 1
- _SIG_SETMASK = 2
- _RLIMIT_AS = 9
-)
-
-// It's hard to tease out exactly how big a Sigset is, but
-// rt_sigprocmask crashes if we get it wrong, so if binaries
-// are running, this is right.
-type sigset [2]uint32
-
-type rlimit struct {
- rlim_cur uintptr
- rlim_max uintptr
-}
diff --git a/libgo/go/runtime/os2_linux_mips64x.go b/libgo/go/runtime/os2_linux_mips64x.go
deleted file mode 100644
index 9a6a92a87d..0000000000
--- a/libgo/go/runtime/os2_linux_mips64x.go
+++ /dev/null
@@ -1,25 +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 linux
-// +build mips64 mips64le
-
-package runtime
-
-const (
- _SS_DISABLE = 2
- _NSIG = 65
- _SI_USER = 0
- _SIG_BLOCK = 1
- _SIG_UNBLOCK = 2
- _SIG_SETMASK = 3
- _RLIMIT_AS = 6
-)
-
-type sigset [2]uint64
-
-type rlimit struct {
- rlim_cur uintptr
- rlim_max uintptr
-}
diff --git a/libgo/go/runtime/os_android.go b/libgo/go/runtime/os_android.go
deleted file mode 100644
index 52c8c86ee8..0000000000
--- a/libgo/go/runtime/os_android.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import _ "unsafe" // for go:cgo_export_static and go:cgo_export_dynamic
-
-// Export the main function.
-//
-// Used by the app package to start all-Go Android apps that are
-// loaded via JNI. See golang.org/x/mobile/app.
-
-//go:cgo_export_static main.main
-//go:cgo_export_dynamic main.main
diff --git a/libgo/go/runtime/os_darwin.go b/libgo/go/runtime/os_darwin.go
new file mode 100644
index 0000000000..ec92370ad7
--- /dev/null
+++ b/libgo/go/runtime/os_darwin.go
@@ -0,0 +1,329 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+ machport uint32 // return address for mach ipc
+ waitsema uint32 // semaphore for parking on locks
+}
+
+//go:noescape
+//extern mach_msg_trap
+func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
+
+//extern mach_reply_port
+func mach_reply_port() uint32
+
+//extern mach_task_self
+func mach_task_self() uint32
+
+func unimplemented(name string) {
+ println(name, "not implemented")
+ *(*int)(unsafe.Pointer(uintptr(1231))) = 1231
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ mach_semrelease(mp.mos.waitsema)
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+ if mp.mos.waitsema != 0 {
+ return
+ }
+ systemstack(func() {
+ mp.mos.waitsema = mach_semcreate()
+ })
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+func macherror(r int32, fn string) {
+ print("mach error ", fn, ": ", r, "\n")
+ throw("mach error")
+}
+
+const _DebugMach = false
+
+var zerondr machndr
+
+func mach_msgh_bits(a, b uint32) uint32 {
+ return a | b<<8
+}
+
+func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
+ // TODO: Loop on interrupt.
+ return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
+}
+
+// Mach RPC (MIG)
+const (
+ _MinMachMsg = 48
+ _MachReply = 100
+)
+
+type codemsg struct {
+ h machheader
+ ndr machndr
+ code int32
+}
+
+func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
+ _g_ := getg()
+ port := _g_.m.mos.machport
+ if port == 0 {
+ port = mach_reply_port()
+ _g_.m.mos.machport = port
+ }
+
+ h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
+ h.msgh_local_port = port
+ h.msgh_reserved = 0
+ id := h.msgh_id
+
+ if _DebugMach {
+ p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+ print("send:\t")
+ var i uint32
+ for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+ print(" ", p[i])
+ if i%8 == 7 {
+ print("\n\t")
+ }
+ }
+ if i%8 != 0 {
+ print("\n")
+ }
+ }
+ ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
+ if ret != 0 {
+ if _DebugMach {
+ print("mach_msg error ", ret, "\n")
+ }
+ return ret
+ }
+ if _DebugMach {
+ p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+ var i uint32
+ for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+ print(" ", p[i])
+ if i%8 == 7 {
+ print("\n\t")
+ }
+ }
+ if i%8 != 0 {
+ print("\n")
+ }
+ }
+ if h.msgh_id != id+_MachReply {
+ if _DebugMach {
+ print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
+ }
+ return -303 // MIG_REPLY_MISMATCH
+ }
+ // Look for a response giving the return value.
+ // Any call can send this back with an error,
+ // and some calls only have return values so they
+ // send it back on success too. I don't quite see how
+ // you know it's one of these and not the full response
+ // format, so just look if the message is right.
+ c := (*codemsg)(unsafe.Pointer(h))
+ if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
+ if _DebugMach {
+ print("mig result ", c.code, "\n")
+ }
+ return c.code
+ }
+ if h.msgh_size != uint32(rxsize) {
+ if _DebugMach {
+ print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
+ }
+ return -307 // MIG_ARRAY_TOO_LARGE
+ }
+ return 0
+}
+
+// Semaphores!
+
+const (
+ tmach_semcreate = 3418
+ rmach_semcreate = tmach_semcreate + _MachReply
+
+ tmach_semdestroy = 3419
+ rmach_semdestroy = tmach_semdestroy + _MachReply
+
+ _KERN_ABORTED = 14
+ _KERN_OPERATION_TIMED_OUT = 49
+)
+
+type tmach_semcreatemsg struct {
+ h machheader
+ ndr machndr
+ policy int32
+ value int32
+}
+
+type rmach_semcreatemsg struct {
+ h machheader
+ body machbody
+ semaphore machport
+}
+
+type tmach_semdestroymsg struct {
+ h machheader
+ body machbody
+ semaphore machport
+}
+
+func mach_semcreate() uint32 {
+ var m [256]uint8
+ tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
+ rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
+
+ tx.h.msgh_bits = 0
+ tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+ tx.h.msgh_remote_port = mach_task_self()
+ tx.h.msgh_id = tmach_semcreate
+ tx.ndr = zerondr
+
+ tx.policy = 0 // 0 = SYNC_POLICY_FIFO
+ tx.value = 0
+
+ for {
+ r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_create")
+ }
+ if rx.body.msgh_descriptor_count != 1 {
+ unimplemented("mach_semcreate desc count")
+ }
+ return rx.semaphore.name
+}
+
+func mach_semdestroy(sem uint32) {
+ var m [256]uint8
+ tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
+
+ tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
+ tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+ tx.h.msgh_remote_port = mach_task_self()
+ tx.h.msgh_id = tmach_semdestroy
+ tx.body.msgh_descriptor_count = 1
+ tx.semaphore.name = sem
+ tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
+ tx.semaphore._type = 0
+
+ for {
+ r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_destroy")
+ }
+}
+
+//extern semaphore_wait
+func mach_semaphore_wait(sema uint32) int32
+
+//extern semaphore_timedwait
+func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+
+//extern semaphore_signal
+func mach_semaphore_signal(sema uint32) int32
+
+//extern semaphore_signal_all
+func mach_semaphore_signal_all(sema uint32) int32
+
+func semasleep1(ns int64) int32 {
+ _g_ := getg()
+
+ if ns >= 0 {
+ var nsecs int32
+ secs := timediv(ns, 1000000000, &nsecs)
+ r := mach_semaphore_timedwait(_g_.m.mos.waitsema, uint32(secs), uint32(nsecs))
+ if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
+ return -1
+ }
+ if r != 0 {
+ macherror(r, "semaphore_wait")
+ }
+ return 0
+ }
+
+ for {
+ r := mach_semaphore_wait(_g_.m.mos.waitsema)
+ if r == 0 {
+ break
+ }
+ // Note: We don't know how this call (with no timeout) can get _KERN_OPERATION_TIMED_OUT,
+ // but it does reliably, though at a very low rate, on OS X 10.8, 10.9, 10.10, and 10.11.
+ // See golang.org/issue/17161.
+ if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT { // interrupted
+ continue
+ }
+ macherror(r, "semaphore_wait")
+ }
+ return 0
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ var r int32
+ systemstack(func() {
+ r = semasleep1(ns)
+ })
+ return r
+}
+
+//go:nosplit
+func mach_semrelease(sem uint32) {
+ for {
+ r := mach_semaphore_signal(sem)
+ if r == 0 {
+ break
+ }
+ if r == _KERN_ABORTED { // interrupted
+ continue
+ }
+
+ // mach_semrelease must be completely nosplit,
+ // because it is called from Go code.
+ // If we're going to die, start that process on the system stack
+ // to avoid a Go stack split.
+ systemstack(func() { macherror(r, "semaphore_signal") })
+ }
+}
+
+type machheader struct {
+ msgh_bits uint32
+ msgh_size uint32
+ msgh_remote_port uint32
+ msgh_local_port uint32
+ msgh_reserved uint32
+ msgh_id int32
+}
+
+type machndr struct {
+ mig_vers uint8
+ if_vers uint8
+ reserved1 uint8
+ mig_encoding uint8
+ int_rep uint8
+ char_rep uint8
+ float_rep uint8
+ reserved2 uint8
+}
diff --git a/libgo/go/runtime/os_dragonfly.go b/libgo/go/runtime/os_dragonfly.go
new file mode 100644
index 0000000000..645298436b
--- /dev/null
+++ b/libgo/go/runtime/os_dragonfly.go
@@ -0,0 +1,62 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+ unused byte
+}
+
+//go:noescape
+//extern umtx_sleep
+func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
+
+//go:noescape
+//extern umtx_wakeup
+func sys_umtx_wakeup(addr *uint32, val int32) int32
+
+//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 timeout int32
+ if ns >= 0 {
+ // The timeout is specified in microseconds - ensure that we
+ // do not end up dividing to zero, which would put us to sleep
+ // indefinitely...
+ timeout = timediv(ns, 1000, nil)
+ if timeout == 0 {
+ timeout = 1
+ }
+ }
+
+ // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
+ // expires or EBUSY if the mutex value does not match.
+ ret := sys_umtx_sleep(addr, int32(val), timeout)
+ if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
+ return
+ }
+
+ print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := sys_umtx_wakeup(addr, int32(cnt))
+ if ret >= 0 {
+ return
+ }
+
+ systemstack(func() {
+ print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+ })
+}
diff --git a/libgo/go/runtime/os_freebsd.go b/libgo/go/runtime/os_freebsd.go
new file mode 100644
index 0000000000..a4d2886d6a
--- /dev/null
+++ b/libgo/go/runtime/os_freebsd.go
@@ -0,0 +1,56 @@
+// 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"
+)
+
+type mOS struct {
+ unused byte
+}
+
+//go:noescape
+//extern _umtx_op
+func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uinptr, ts *umtx_time) int32
+
+// 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 utp *umtx_time
+ if ns >= 0 {
+ var ut umtx_time
+ ut._clockid = _CLOCK_MONOTONIC
+ ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec)))))
+ utp = &ut
+ }
+ ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
+ 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, 0, nil)
+ if ret >= 0 {
+ return
+ }
+
+ systemstack(func() {
+ print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+ })
+}
diff --git a/libgo/go/runtime/os_gccgo.go b/libgo/go/runtime/os_gccgo.go
new file mode 100644
index 0000000000..a8f05a4b3d
--- /dev/null
+++ b/libgo/go/runtime/os_gccgo.go
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// Temporary for C code to call:
+//go:linkname minit runtime.minit
+
+// 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(true, true, &mp.gsignalstack, &mp.gsignalstacksize)
+ mp.gsignal.m = mp
+}
+
+// minit is called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+ minitSignals()
+
+ // FIXME: We should set _g_.m.procid here.
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+ unminitSignals()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+func getRandomData(r []byte) {
+ if startupRandomData != nil {
+ n := copy(r, startupRandomData)
+ extendRandom(r, n)
+ return
+ }
+ 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))
+}
diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go
new file mode 100644
index 0000000000..ad334869ed
--- /dev/null
+++ b/libgo/go/runtime/os_linux.go
@@ -0,0 +1,171 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+type mOS struct {
+ unused byte
+}
+
+func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 {
+ return int32(syscall(_SYS_futex, uintptr(addr), uintptr(op), uintptr(val), uintptr(ts), uintptr(addr2), uintptr(val3)))
+}
+
+// Linux futex.
+//
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+const (
+ _FUTEX_WAIT = 0
+ _FUTEX_WAKE = 1
+)
+
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ var ts timespec
+
+ // Some Linux kernels have a bug where futex of
+ // FUTEX_WAIT returns an internal error code
+ // as an errno. Libpthread ignores the return value
+ // here, and so can we: as it says a few lines up,
+ // spurious wakeups are allowed.
+ if ns < 0 {
+ futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
+ return
+ }
+
+ // It's difficult to live within the no-split stack limits here.
+ // On ARM and 386, a 64-bit divide invokes a general software routine
+ // that needs more stack than we can afford. So we use timediv instead.
+ // But on real 64-bit systems, where words are larger but the stack limit
+ // is not, even timediv is too heavy, and we really need to use just an
+ // ordinary machine instruction.
+ if sys.PtrSize == 8 {
+ ts.set_sec(ns / 1000000000)
+ ts.set_nsec(int32(ns % 1000000000))
+ } else {
+ ts.tv_nsec = 0
+ ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+ }
+ futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
+}
+
+// If any procs are sleeping on addr, wake up at most cnt.
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
+ if ret >= 0 {
+ return
+ }
+
+ // I don't know that futex wakeup can return
+ // EAGAIN or EINTR, but if it does, it would be
+ // safe to loop and call futex again.
+ systemstack(func() {
+ print("futexwakeup addr=", addr, " returned ", ret, "\n")
+ })
+
+ *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+}
+
+const (
+ _AT_NULL = 0 // End of vector
+ _AT_PAGESZ = 6 // System physical page size
+ _AT_HWCAP = 16 // hardware capability bit vector
+ _AT_RANDOM = 25 // introduced in 2.6.29
+ _AT_HWCAP2 = 26 // hardware capability bit vector 2
+)
+
+var procAuxv = []byte("/proc/self/auxv\x00")
+
+func sysargs(argc int32, argv **byte) {
+ n := argc + 1
+
+ // skip over argv, envp to get to auxv
+ for argv_index(argv, n) != nil {
+ n++
+ }
+
+ // skip NULL separator
+ n++
+
+ // now argv+n is auxv
+ auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
+ if sysauxv(auxv[:]) == 0 {
+ // In some situations we don't get a loader-provided
+ // auxv, such as when loaded as a library on Android.
+ // Fall back to /proc/self/auxv.
+ fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0)
+ if fd < 0 {
+ // On Android, /proc/self/auxv might be unreadable (issue 9229), so we fallback to
+ // try using mincore to detect the physical page size.
+ // mincore should return EINVAL when address is not a multiple of system page size.
+ const size = 256 << 10 // size of memory region to allocate
+ p := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+ if uintptr(p) < 4096 {
+ return
+ }
+ var n uintptr
+ for n = 4 << 10; n < size; n <<= 1 {
+ err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0])
+ if err == 0 {
+ physPageSize = n
+ break
+ }
+ }
+ if physPageSize == 0 {
+ physPageSize = size
+ }
+ munmap(p, size)
+ return
+ }
+ var buf [128]uintptr
+ n := read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf)))
+ closefd(fd)
+ if n < 0 {
+ return
+ }
+ // Make sure buf is terminated, even if we didn't read
+ // the whole file.
+ buf[len(buf)-2] = _AT_NULL
+ sysauxv(buf[:])
+ }
+}
+
+func sysauxv(auxv []uintptr) int {
+ var i int
+ for ; auxv[i] != _AT_NULL; i += 2 {
+ tag, val := auxv[i], auxv[i+1]
+ switch tag {
+ case _AT_RANDOM:
+ // The kernel provides a pointer to 16-bytes
+ // worth of random data.
+ startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:]
+
+ case _AT_PAGESZ:
+ physPageSize = val
+ }
+
+ // Commented out for gccgo for now.
+ // archauxv(tag, val)
+ }
+ return i / 2
+}
+
+// Temporary for gccgo until we port mem_GOOS.go.
+var addrspace_vec [1]byte
diff --git a/libgo/go/runtime/os_linux_mips64x.go b/libgo/go/runtime/os_linux_mips64x.go
deleted file mode 100644
index 4d2e9e8a20..0000000000
--- a/libgo/go/runtime/os_linux_mips64x.go
+++ /dev/null
@@ -1,18 +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 mips64 mips64le
-// +build linux
-
-package runtime
-
-var randomNumber uint32
-
-//go:nosplit
-func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed fastrand1().
- // nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // randomNumber provides better seeding of fastrand1.
- return nanotime() + int64(randomNumber)
-}
diff --git a/libgo/go/runtime/os_linux_ppc64x.go b/libgo/go/runtime/os_linux_ppc64x.go
new file mode 100644
index 0000000000..b324344493
--- /dev/null
+++ b/libgo/go/runtime/os_linux_ppc64x.go
@@ -0,0 +1,61 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore_for_gccgo
+// +build ppc64 ppc64le
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+)
+
+const (
+ // ISA level
+ // Go currently requires POWER5 as a minimum for ppc64, so we need
+ // to check for ISA 2.03 and beyond.
+ _PPC_FEATURE_POWER5_PLUS = 0x00020000 // ISA 2.03 (POWER5+)
+ _PPC_FEATURE_ARCH_2_05 = 0x00001000 // ISA 2.05 (POWER6)
+ _PPC_FEATURE_POWER6_EXT = 0x00000200 // mffgpr/mftgpr extension (POWER6x)
+ _PPC_FEATURE_ARCH_2_06 = 0x00000100 // ISA 2.06 (POWER7)
+ _PPC_FEATURE2_ARCH_2_07 = 0x80000000 // ISA 2.07 (POWER8)
+
+ // Standalone capabilities
+ _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 // SIMD/Vector unit
+ _PPC_FEATURE_HAS_VSX = 0x00000080 // Vector scalar unit
+)
+
+type facilities struct {
+ _ [sys.CacheLineSize]byte
+ isPOWER5x bool // ISA 2.03
+ isPOWER6 bool // ISA 2.05
+ isPOWER6x bool // ISA 2.05 + mffgpr/mftgpr extension
+ isPOWER7 bool // ISA 2.06
+ isPOWER8 bool // ISA 2.07
+ hasVMX bool // Vector unit
+ hasVSX bool // Vector scalar unit
+ _ [sys.CacheLineSize]byte
+}
+
+// cpu can be tested at runtime in go assembler code to check for
+// a certain ISA level or hardware capability, for example:
+// ·cpu+facilities_hasVSX(SB) for checking the availability of VSX
+// or
+// ·cpu+facilities_isPOWER7(SB) for checking if the processor implements
+// ISA 2.06 instructions.
+var cpu facilities
+
+func archauxv(tag, val uintptr) {
+ switch tag {
+ case _AT_HWCAP:
+ cpu.isPOWER5x = val&_PPC_FEATURE_POWER5_PLUS != 0
+ cpu.isPOWER6 = val&_PPC_FEATURE_ARCH_2_05 != 0
+ cpu.isPOWER6x = val&_PPC_FEATURE_POWER6_EXT != 0
+ cpu.isPOWER7 = val&_PPC_FEATURE_ARCH_2_06 != 0
+ cpu.hasVMX = val&_PPC_FEATURE_HAS_ALTIVEC != 0
+ cpu.hasVSX = val&_PPC_FEATURE_HAS_VSX != 0
+ case _AT_HWCAP2:
+ cpu.isPOWER8 = val&_PPC_FEATURE2_ARCH_2_07 != 0
+ }
+}
diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go
new file mode 100644
index 0000000000..464ce88d9c
--- /dev/null
+++ b/libgo/go/runtime/os_netbsd.go
@@ -0,0 +1,73 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+type mOS struct {
+ waitsemacount uint32
+}
+
+//go:noescape
+//extern lwp_park
+func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
+//extern lwp_unpark
+func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
+
+//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.mos.waitsemacount)
+ if v > 0 {
+ if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) {
+ return 0 // semaphore acquired
+ }
+ continue
+ }
+
+ // Sleep until unparked by semawakeup or timeout.
+ ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.mos.waitsemacount), nil)
+ if ret == _ETIMEDOUT {
+ return -1
+ }
+ }
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ atomic.Xadd(&mp.mos.waitsemacount, 1)
+ // From NetBSD's _lwp_unpark(2) manual:
+ // "If the target LWP is not currently waiting, it will return
+ // immediately upon the next call to _lwp_park()."
+ ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.mos.waitsemacount))
+ if ret != 0 && ret != _ESRCH {
+ // semawakeup can be called on signal stack.
+ systemstack(func() {
+ print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n")
+ })
+ }
+}
diff --git a/libgo/go/runtime/os_openbsd.go b/libgo/go/runtime/os_openbsd.go
new file mode 100644
index 0000000000..b64d3af385
--- /dev/null
+++ b/libgo/go/runtime/os_openbsd.go
@@ -0,0 +1,76 @@
+// 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
+}
+
+//go:noescape
+//extern thrsleep
+func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
+
+//go:noescape
+//extern thrwakeup
+func thrwakeup(ident uintptr, n int32) int32
+
+//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.mos.waitsemacount)
+ if v > 0 {
+ if atomic.Cas(&_g_.m.mos.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.mos.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.mos.waitsemacount)
+ if ret == _EWOULDBLOCK {
+ return -1
+ }
+ }
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ atomic.Xadd(&mp.mos.waitsemacount, 1)
+ ret := thrwakeup(uintptr(unsafe.Pointer(&mp.mos.waitsemacount)), 1)
+ if ret != 0 && ret != _ESRCH {
+ // semawakeup can be called on signal stack.
+ systemstack(func() {
+ print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n")
+ })
+ }
+}
diff --git a/libgo/go/runtime/os_solaris.go b/libgo/go/runtime/os_solaris.go
new file mode 100644
index 0000000000..cf457680f7
--- /dev/null
+++ b/libgo/go/runtime/os_solaris.go
@@ -0,0 +1,85 @@
+// 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"
+
+type mOS struct {
+ waitsema uintptr // semaphore for parking on locks
+}
+
+//extern malloc
+func libc_malloc(uintptr) unsafe.Pointer
+
+//go:noescape
+//extern sem_init
+func sem_init(sem *semt, pshared int32, value uint32) int32
+
+//go:noescape
+//extern sem_wait
+func sem_wait(sem *semt) int32
+
+//go:noescape
+//extern sem_post
+func sem_post(sem *semt) int32
+
+//go:noescape
+//extern sem_reltimedwait_np
+func sem_reltimedwait_np(sem *semt, timeout *timespec) int32
+
+//go:nosplit
+func semacreate(mp *m) {
+ if mp.mos.waitsema != 0 {
+ return
+ }
+
+ var sem *semt
+
+ // Call libc's malloc rather than malloc. This will
+ // allocate space on the C heap. We can't call malloc
+ // here because it could cause a deadlock.
+ sem = (*semt)(libc_malloc(unsafe.Sizeof(*sem)))
+ if sem_init(sem, 0, 0) != 0 {
+ throw("sem_init")
+ }
+ mp.mos.waitsema = uintptr(unsafe.Pointer(sem))
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ _m_ := getg().m
+ if ns >= 0 {
+ var ts timespec
+ ts.set_sec(ns / 1000000000)
+ ts.set_nsec(int32(ns % 1000000000))
+
+ if sem_reltimedwait_np((*semt)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 {
+ err := errno()
+ if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
+ return -1
+ }
+ throw("sem_reltimedwait_np")
+ }
+ return 0
+ }
+ for {
+ r1 := sem_wait((*semt)(unsafe.Pointer(_m_.mos.waitsema)))
+ if r1 == 0 {
+ break
+ }
+ if errno() == _EINTR {
+ continue
+ }
+ throw("sem_wait")
+ }
+ return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ if sem_post((*semt)(unsafe.Pointer(mp.mos.waitsema))) != 0 {
+ throw("sem_post")
+ }
+}
diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go
new file mode 100644
index 0000000000..b76bb21191
--- /dev/null
+++ b/libgo/go/runtime/panic.go
@@ -0,0 +1,882 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname deferproc runtime.deferproc
+//go:linkname deferreturn runtime.deferreturn
+//go:linkname setdeferretaddr runtime.setdeferretaddr
+//go:linkname checkdefer runtime.checkdefer
+//go:linkname gopanic runtime.gopanic
+//go:linkname canrecover runtime.canrecover
+//go:linkname makefuncfficanrecover runtime.makefuncfficanrecover
+//go:linkname makefuncreturning runtime.makefuncreturning
+//go:linkname gorecover runtime.gorecover
+//go:linkname deferredrecover runtime.deferredrecover
+// Temporary for C code to call:
+//go:linkname throw runtime.throw
+
+// Calling panic with one of the errors below will call errorString.Error
+// which will call mallocgc to concatenate strings. That will fail if
+// malloc is locked, causing a confusing error message. Throw a better
+// error message instead.
+func panicCheckMalloc(err error) {
+ gp := getg()
+ if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
+ throw(string(err.(errorString)))
+ }
+}
+
+var indexError = error(errorString("index out of range"))
+
+func panicindex() {
+ panicCheckMalloc(indexError)
+ panic(indexError)
+}
+
+var sliceError = error(errorString("slice bounds out of range"))
+
+func panicslice() {
+ panicCheckMalloc(sliceError)
+ panic(sliceError)
+}
+
+var divideError = error(errorString("integer divide by zero"))
+
+func panicdivide() {
+ panicCheckMalloc(divideError)
+ panic(divideError)
+}
+
+var overflowError = error(errorString("integer overflow"))
+
+func panicoverflow() {
+ panicCheckMalloc(overflowError)
+ panic(overflowError)
+}
+
+var floatError = error(errorString("floating point error"))
+
+func panicfloat() {
+ panicCheckMalloc(floatError)
+ panic(floatError)
+}
+
+var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
+
+func panicmem() {
+ panicCheckMalloc(memoryError)
+ panic(memoryError)
+}
+
+func throwinit() {
+ throw("recursive call during initialization - linker skew")
+}
+
+// deferproc creates a new deferred function.
+// The compiler turns a defer statement into a call to this.
+// frame points into the stack frame; it is used to determine which
+// deferred functions are for the current stack frame, and whether we
+// have already deferred functions for this frame.
+// pfn is a C function pointer.
+// arg is a value to pass to pfn.
+func deferproc(frame *bool, pfn uintptr, arg unsafe.Pointer) {
+ n := newdefer()
+ n.frame = frame
+ n._panic = getg()._panic
+ n.pfn = pfn
+ n.arg = arg
+ n.retaddr = 0
+ n.makefunccanrecover = false
+ n.special = false
+}
+
+// Allocate a Defer, usually using per-P pool.
+// Each defer must be released with freedefer.
+func newdefer() *_defer {
+ var d *_defer
+ gp := getg()
+ pp := gp.m.p.ptr()
+ if len(pp.deferpool) == 0 && sched.deferpool != nil {
+ systemstack(func() {
+ lock(&sched.deferlock)
+ for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil {
+ d := sched.deferpool
+ sched.deferpool = d.link
+ d.link = nil
+ pp.deferpool = append(pp.deferpool, d)
+ }
+ unlock(&sched.deferlock)
+ })
+ }
+ if n := len(pp.deferpool); n > 0 {
+ d = pp.deferpool[n-1]
+ pp.deferpool[n-1] = nil
+ pp.deferpool = pp.deferpool[:n-1]
+ }
+ if d == nil {
+ systemstack(func() {
+ d = new(_defer)
+ })
+ }
+ d.link = gp._defer
+ gp._defer = d
+ return d
+}
+
+// Free the given defer.
+// The defer cannot be used after this call.
+//
+// This must not grow the stack because there may be a frame without a
+// stack map when this is called.
+//
+//go:nosplit
+func freedefer(d *_defer) {
+ if d.special {
+ return
+ }
+
+ // When C code calls a Go function on a non-Go thread, the
+ // deferred call to cgocallBackDone will set g to nil.
+ // Don't crash trying to put d on the free list; just let it
+ // be garbage collected.
+ if getg() == nil {
+ return
+ }
+
+ pp := getg().m.p.ptr()
+ if len(pp.deferpool) == cap(pp.deferpool) {
+ // Transfer half of local cache to the central cache.
+ //
+ // Take this slow path on the system stack so
+ // we don't grow freedefer's stack.
+ systemstack(func() {
+ var first, last *_defer
+ for len(pp.deferpool) > cap(pp.deferpool)/2 {
+ n := len(pp.deferpool)
+ d := pp.deferpool[n-1]
+ pp.deferpool[n-1] = nil
+ pp.deferpool = pp.deferpool[:n-1]
+ if first == nil {
+ first = d
+ } else {
+ last.link = d
+ }
+ last = d
+ }
+ lock(&sched.deferlock)
+ last.link = sched.deferpool
+ sched.deferpool = first
+ unlock(&sched.deferlock)
+ })
+ }
+ *d = _defer{}
+ pp.deferpool = append(pp.deferpool, d)
+}
+
+// deferreturn is called to undefer the stack.
+// The compiler inserts a call to this function as a finally clause
+// wrapped around the body of any function that calls defer.
+// The frame argument points to the stack frame of the function.
+func deferreturn(frame *bool) {
+ gp := getg()
+ for gp._defer != nil && gp._defer.frame == frame {
+ d := gp._defer
+ pfn := d.pfn
+ d.pfn = 0
+
+ if pfn != 0 {
+ // This is rather awkward.
+ // The gc compiler does this using assembler
+ // code in jmpdefer.
+ var fn func(unsafe.Pointer)
+ *(**uintptr)(unsafe.Pointer(&fn)) = &pfn
+ fn(d.arg)
+ }
+
+ gp._defer = d.link
+
+ freedefer(d)
+
+ // Since we are executing a defer function now, we
+ // know that we are returning from the calling
+ // function. If the calling function, or one of its
+ // callees, panicked, then the defer functions would
+ // be executed by panic.
+ *frame = true
+ }
+}
+
+// __builtin_extract_return_addr is a GCC intrinsic that converts an
+// address returned by __builtin_return_address(0) to a real address.
+// On most architectures this is a nop.
+//extern __builtin_extract_return_addr
+func __builtin_extract_return_addr(uintptr) uintptr
+
+// setdeferretaddr records the address to which the deferred function
+// returns. This is check by canrecover. The frontend relies on this
+// function returning false.
+func setdeferretaddr(retaddr uintptr) bool {
+ gp := getg()
+ if gp._defer != nil {
+ gp._defer.retaddr = __builtin_extract_return_addr(retaddr)
+ }
+ return false
+}
+
+// checkdefer is called by exception handlers used when unwinding the
+// stack after a recovered panic. The exception handler is simply
+// checkdefer(frame)
+// return;
+// If we have not yet reached the frame we are looking for, we
+// continue unwinding.
+func checkdefer(frame *bool) {
+ gp := getg()
+ if gp == nil {
+ // We should never wind up here. Even if some other
+ // language throws an exception, the cgo code
+ // should ensure that g is set.
+ throw("no g in checkdefer")
+ } else if gp.isforeign {
+ // Some other language has thrown an exception.
+ // We need to run the local defer handlers.
+ // If they call recover, we stop unwinding here.
+ var p _panic
+ p.isforeign = true
+ p.link = gp._panic
+ gp._panic = &p
+ for {
+ d := gp._defer
+ if d == nil || d.frame != frame || d.pfn == 0 {
+ break
+ }
+
+ pfn := d.pfn
+ gp._defer = d.link
+
+ var fn func(unsafe.Pointer)
+ *(**uintptr)(unsafe.Pointer(&fn)) = &pfn
+ fn(d.arg)
+
+ freedefer(d)
+
+ if p.recovered {
+ // The recover function caught the panic
+ // thrown by some other language.
+ break
+ }
+ }
+
+ recovered := p.recovered
+ gp._panic = p.link
+
+ if recovered {
+ // Just return and continue executing Go code.
+ *frame = true
+ return
+ }
+
+ // We are panicking through this function.
+ *frame = false
+ } else if gp._defer != nil && gp._defer.pfn == 0 && gp._defer.frame == frame {
+ // This is the defer function that called recover.
+ // Simply return to stop the stack unwind, and let the
+ // Go code continue to execute.
+ d := gp._defer
+ gp._defer = d.link
+ freedefer(d)
+
+ // We are returning from this function.
+ *frame = true
+
+ return
+ }
+
+ // This is some other defer function. It was already run by
+ // the call to panic, or just above. Rethrow the exception.
+ rethrowException()
+ throw("rethrowException returned")
+}
+
+// unwindStack starts unwinding the stack for a panic. We unwind
+// function calls until we reach the one which used a defer function
+// which called recover. Each function which uses a defer statement
+// will have an exception handler, as shown above for checkdefer.
+func unwindStack() {
+ // Allocate the exception type used by the unwind ABI.
+ // It would be nice to define it in runtime_sysinfo.go,
+ // but current definitions don't work because the required
+ // alignment is larger than can be represented in Go.
+ // The type never contains any Go pointers.
+ size := unwindExceptionSize()
+ usize := uintptr(unsafe.Sizeof(uintptr(0)))
+ c := (size + usize - 1) / usize
+ s := make([]uintptr, c)
+ getg().exception = unsafe.Pointer(&s[0])
+ throwException()
+}
+
+// Goexit terminates the goroutine that calls it. No other goroutine is affected.
+// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
+// is not panic, however, any recover calls in those deferred functions will return nil.
+//
+// Calling Goexit from the main goroutine terminates that goroutine
+// without func main returning. Since func main has not returned,
+// the program continues execution of other goroutines.
+// If all other goroutines exit, the program crashes.
+func Goexit() {
+ // Run all deferred functions for the current goroutine.
+ // This code is similar to gopanic, see that implementation
+ // for detailed comments.
+ gp := getg()
+ for {
+ d := gp._defer
+ if d == nil {
+ break
+ }
+ gp._defer = d.link
+
+ pfn := d.pfn
+ d.pfn = 0
+
+ if pfn != 0 {
+ var fn func(unsafe.Pointer)
+ *(**uintptr)(unsafe.Pointer(&fn)) = &pfn
+ fn(d.arg)
+ }
+
+ freedefer(d)
+ // Note: we ignore recovers here because Goexit isn't a panic
+ }
+ goexit1()
+}
+
+// Call all Error and String methods before freezing the world.
+// Used when crashing with panicking.
+// This must match types handled by printany.
+func preprintpanics(p *_panic) {
+ defer func() {
+ if recover() != nil {
+ throw("panic while printing panic value")
+ }
+ }()
+ for p != nil {
+ switch v := p.arg.(type) {
+ case error:
+ p.arg = v.Error()
+ case stringer:
+ p.arg = v.String()
+ }
+ p = p.link
+ }
+}
+
+// Print all currently active panics. Used when crashing.
+func printpanics(p *_panic) {
+ if p.link != nil {
+ printpanics(p.link)
+ print("\t")
+ }
+ print("panic: ")
+ printany(p.arg)
+ if p.recovered {
+ print(" [recovered]")
+ }
+ print("\n")
+}
+
+// The implementation of the predeclared function panic.
+func gopanic(e interface{}) {
+ gp := getg()
+ if gp.m.curg != gp {
+ print("panic: ")
+ printany(e)
+ print("\n")
+ throw("panic on system stack")
+ }
+
+ if gp.m.mallocing != 0 {
+ print("panic: ")
+ printany(e)
+ print("\n")
+ throw("panic during malloc")
+ }
+ if gp.m.preemptoff != "" {
+ print("panic: ")
+ printany(e)
+ print("\n")
+ print("preempt off reason: ")
+ print(gp.m.preemptoff)
+ print("\n")
+ throw("panic during preemptoff")
+ }
+ if gp.m.locks != 0 {
+ print("panic: ")
+ printany(e)
+ print("\n")
+ throw("panic holding locks")
+ }
+
+ // The gc compiler allocates this new _panic struct on the
+ // stack. We can't do that, because when a deferred function
+ // recovers the panic we unwind the stack. We unlink this
+ // entry before unwinding the stack, but that doesn't help in
+ // the case where we panic, a deferred function recovers and
+ // then panics itself, that panic is in turn recovered, and
+ // unwinds the stack past this stack frame.
+
+ p := &_panic{
+ arg: e,
+ link: gp._panic,
+ }
+ gp._panic = p
+
+ for {
+ d := gp._defer
+ if d == nil {
+ break
+ }
+
+ pfn := d.pfn
+ d.pfn = 0
+
+ if pfn != 0 {
+ var fn func(unsafe.Pointer)
+ *(**uintptr)(unsafe.Pointer(&fn)) = &pfn
+ fn(d.arg)
+
+ if p.recovered {
+ // Some deferred function called recover.
+ // Stop running this panic.
+ gp._panic = p.link
+
+ // Unwind the stack by throwing an exception.
+ // The compiler has arranged to create
+ // exception handlers in each function
+ // that uses a defer statement. These
+ // exception handlers will check whether
+ // the entry on the top of the defer stack
+ // is from the current function. If it is,
+ // we have unwound the stack far enough.
+ unwindStack()
+
+ throw("unwindStack returned")
+ }
+
+ // Because we executed that defer function by a panic,
+ // and it did not call recover, we know that we are
+ // not returning from the calling function--we are
+ // panicking through it.
+ *d.frame = false
+ }
+
+ gp._defer = d.link
+ freedefer(d)
+ }
+
+ // ran out of deferred calls - old-school panic now
+ // Because it is unsafe to call arbitrary user code after freezing
+ // the world, we call preprintpanics to invoke all necessary Error
+ // and String methods to prepare the panic strings before startpanic.
+ preprintpanics(gp._panic)
+ startpanic()
+ printpanics(gp._panic)
+ dopanic(0) // should not return
+ *(*int)(nil) = 0 // not reached
+}
+
+// currentDefer returns the top of the defer stack if it can be recovered.
+// Otherwise it returns nil.
+func currentDefer() *_defer {
+ gp := getg()
+ d := gp._defer
+ if d == nil {
+ return nil
+ }
+
+ // The panic that would be recovered is the one on the top of
+ // the panic stack. We do not want to recover it if that panic
+ // was on the top of the panic stack when this function was
+ // deferred.
+ if d._panic == gp._panic {
+ return nil
+ }
+
+ // The deferred thunk will call setdeferretaddr. If this has
+ // not happened, then we have not been called via defer, and
+ // we can not recover.
+ if d.retaddr == 0 {
+ return nil
+ }
+
+ return d
+}
+
+// canrecover is called by a thunk to see if the real function would
+// be permitted to recover a panic value. Recovering a value is
+// permitted if the thunk was called directly by defer. retaddr is the
+// return address of the function that is calling canrecover--that is,
+// the thunk.
+func canrecover(retaddr uintptr) bool {
+ d := currentDefer()
+ if d == nil {
+ return false
+ }
+
+ ret := __builtin_extract_return_addr(retaddr)
+ dret := d.retaddr
+ if ret <= dret && ret+16 >= dret {
+ return true
+ }
+
+ // On some systems, in some cases, the return address does not
+ // work reliably. See http://gcc.gnu.org/PR60406. If we are
+ // permitted to call recover, the call stack will look like this:
+ // runtime.gopanic, runtime.deferreturn, etc.
+ // thunk to call deferred function (calls __go_set_defer_retaddr)
+ // function that calls __go_can_recover (passing return address)
+ // runtime.canrecover
+ // Calling callers will skip the thunks. So if our caller's
+ // caller starts with "runtime.", then we are permitted to
+ // call recover.
+ var locs [16]location
+ if callers(2, locs[:2]) < 2 {
+ return false
+ }
+
+ name := locs[1].function
+ if hasprefix(name, "runtime.") {
+ return true
+ }
+
+ // If the function calling recover was created by reflect.MakeFunc,
+ // then makefuncfficanrecover will have set makefunccanrecover.
+ if !d.makefunccanrecover {
+ return false
+ }
+
+ // We look up the stack, ignoring libffi functions and
+ // functions in the reflect package, until we find
+ // reflect.makeFuncStub or reflect.ffi_callback called by FFI
+ // functions. Then we check the caller of that function.
+
+ n := callers(3, locs[:])
+ foundFFICallback := false
+ i := 0
+ for ; i < n; i++ {
+ name = locs[i].function
+ if name == "" {
+ // No function name means this caller isn't Go code.
+ // Assume that this is libffi.
+ continue
+ }
+
+ // Ignore function in libffi.
+ if hasprefix(name, "ffi_") {
+ continue
+ }
+
+ if foundFFICallback {
+ break
+ }
+
+ if name == "reflect.ffi_callback" {
+ foundFFICallback = true
+ continue
+ }
+
+ // Ignore other functions in the reflect package.
+ if hasprefix(name, "reflect.") {
+ continue
+ }
+
+ // We should now be looking at the real caller.
+ break
+ }
+
+ if i < n {
+ name = locs[i].function
+ if hasprefix(name, "runtime.") {
+ return true
+ }
+ }
+
+ return false
+}
+
+// This function is called when code is about to enter a function
+// created by the libffi version of reflect.MakeFunc. This function is
+// passed the names of the callers of the libffi code that called the
+// stub. It uses them to decide whether it is permitted to call
+// recover, and sets d.makefunccanrecover so that gorecover can make
+// the same decision.
+func makefuncfficanrecover(loc []location) {
+ d := currentDefer()
+ if d == nil {
+ return
+ }
+
+ // If we are already in a call stack of MakeFunc functions,
+ // there is nothing we can usefully check here.
+ if d.makefunccanrecover {
+ return
+ }
+
+ // loc starts with the caller of our caller. That will be a thunk.
+ // If its caller was a function function, then it was called
+ // directly by defer.
+ if len(loc) < 2 {
+ return
+ }
+
+ name := loc[1].function
+ if hasprefix(name, "runtime.") {
+ d.makefunccanrecover = true
+ }
+}
+
+// makefuncreturning is called when code is about to exit a function
+// created by reflect.MakeFunc. It is called by the function stub used
+// by reflect.MakeFunc. It clears the makefunccanrecover field. It's
+// OK to always clear this field, because canrecover will only be
+// called by a stub created for a function that calls recover. That
+// stub will not call a function created by reflect.MakeFunc, so by
+// the time we get here any caller higher up on the call stack no
+// longer needs the information.
+func makefuncreturning() {
+ d := getg()._defer
+ if d != nil {
+ d.makefunccanrecover = false
+ }
+}
+
+// The implementation of the predeclared function recover.
+func gorecover() interface{} {
+ gp := getg()
+ p := gp._panic
+ if p != nil && !p.recovered {
+ p.recovered = true
+ return p.arg
+ }
+ return nil
+}
+
+// deferredrecover is called when a call to recover is deferred. That
+// is, something like
+// defer recover()
+//
+// We need to handle this specially. In gc, the recover function
+// looks up the stack frame. In particular, that means that a deferred
+// recover will not recover a panic thrown in the same function that
+// defers the recover. It will only recover a panic thrown in a
+// function that defers the deferred call to recover.
+//
+// In other words:
+//
+// func f1() {
+// defer recover() // does not stop panic
+// panic(0)
+// }
+//
+// func f2() {
+// defer func() {
+// defer recover() // stops panic(0)
+// }()
+// panic(0)
+// }
+//
+// func f3() {
+// defer func() {
+// defer recover() // does not stop panic
+// panic(0)
+// }()
+// panic(1)
+// }
+//
+// func f4() {
+// defer func() {
+// defer func() {
+// defer recover() // stops panic(0)
+// }()
+// panic(0)
+// }()
+// panic(1)
+// }
+//
+// The interesting case here is f3. As can be seen from f2, the
+// deferred recover could pick up panic(1). However, this does not
+// happen because it is blocked by the panic(0).
+//
+// When a function calls recover, then when we invoke it we pass a
+// hidden parameter indicating whether it should recover something.
+// This parameter is set based on whether the function is being
+// invoked directly from defer. The parameter winds up determining
+// whether __go_recover or __go_deferred_recover is called at all.
+//
+// In the case of a deferred recover, the hidden parameter that
+// controls the call is actually the one set up for the function that
+// runs the defer recover() statement. That is the right thing in all
+// the cases above except for f3. In f3 the function is permitted to
+// call recover, but the deferred recover call is not. We address that
+// here by checking for that specific case before calling recover. If
+// this function was deferred when there is already a panic on the
+// panic stack, then we can only recover that panic, not any other.
+
+// Note that we can get away with using a special function here
+// because you are not permitted to take the address of a predeclared
+// function like recover.
+func deferredrecover() interface{} {
+ gp := getg()
+ if gp._defer == nil || gp._defer._panic != gp._panic {
+ return nil
+ }
+ return gorecover()
+}
+
+//go:linkname sync_throw sync.throw
+func sync_throw(s string) {
+ throw(s)
+}
+
+//go:nosplit
+func throw(s string) {
+ print("fatal error: ", s, "\n")
+ gp := getg()
+ if gp.m.throwing == 0 {
+ gp.m.throwing = 1
+ }
+ startpanic()
+ dopanic(0)
+ *(*int)(nil) = 0 // not reached
+}
+
+//uint32 runtime·panicking;
+var paniclk mutex
+
+func startpanic() {
+ _g_ := getg()
+ // Uncomment when mheap_ is in Go.
+ // if mheap_.cachealloc.size == 0 { // very early
+ // print("runtime: panic before malloc heap initialized\n")
+ // _g_.m.mallocing = 1 // tell rest of panic not to try to malloc
+ // } else
+ if _g_.m.mcache == nil { // can happen if called from signal handler or throw
+ _g_.m.mcache = allocmcache()
+ }
+
+ switch _g_.m.dying {
+ case 0:
+ _g_.m.dying = 1
+ _g_.writebuf = nil
+ atomic.Xadd(&panicking, 1)
+ lock(&paniclk)
+ if debug.schedtrace > 0 || debug.scheddetail > 0 {
+ schedtrace(true)
+ }
+ freezetheworld()
+ return
+ case 1:
+ // Something failed while panicking, probably the print of the
+ // argument to panic(). Just print a stack trace and exit.
+ _g_.m.dying = 2
+ print("panic during panic\n")
+ dopanic(0)
+ exit(3)
+ fallthrough
+ case 2:
+ // This is a genuine bug in the runtime, we couldn't even
+ // print the stack trace successfully.
+ _g_.m.dying = 3
+ print("stack trace unavailable\n")
+ exit(4)
+ fallthrough
+ default:
+ // Can't even print! Just exit.
+ exit(5)
+ }
+}
+
+var didothers bool
+var deadlock mutex
+
+func dopanic(unused int) {
+ gp := getg()
+ if gp.sig != 0 {
+ signame := signame(gp.sig)
+ if signame != "" {
+ print("[signal ", signame)
+ } else {
+ print("[signal ", hex(gp.sig))
+ }
+ print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
+ }
+
+ level, all, docrash := gotraceback()
+ _g_ := getg()
+ if level > 0 {
+ if gp != gp.m.curg {
+ all = true
+ }
+ if gp != gp.m.g0 {
+ print("\n")
+ goroutineheader(gp)
+ traceback(0)
+ } else if level >= 2 || _g_.m.throwing > 0 {
+ print("\nruntime stack:\n")
+ traceback(0)
+ }
+ if !didothers && all {
+ didothers = true
+ tracebackothers(gp)
+ }
+ }
+ unlock(&paniclk)
+
+ if atomic.Xadd(&panicking, -1) != 0 {
+ // Some other m is panicking too.
+ // Let it print what it needs to print.
+ // Wait forever without chewing up cpu.
+ // It will exit when it's done.
+ lock(&deadlock)
+ lock(&deadlock)
+ }
+
+ if docrash {
+ crash()
+ }
+
+ exit(2)
+}
+
+//go:nosplit
+func canpanic(gp *g) bool {
+ // Note that g is m->gsignal, different from gp.
+ // Note also that g->m can change at preemption, so m can go stale
+ // if this function ever makes a function call.
+ _g_ := getg()
+ _m_ := _g_.m
+
+ // Is it okay for gp to panic instead of crashing the program?
+ // Yes, as long as it is running Go code, not runtime code,
+ // and not stuck in a system call.
+ if gp == nil || gp != _m_.curg {
+ return false
+ }
+ if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
+ return false
+ }
+ status := readgstatus(gp)
+ if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
+ return false
+ }
+ return true
+}
diff --git a/libgo/go/runtime/parfor_test.go b/libgo/go/runtime/parfor_test.go
deleted file mode 100644
index 5d22aecc9b..0000000000
--- a/libgo/go/runtime/parfor_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// The race detector does not understand ParFor synchronization.
-// +build !race
-
-package runtime_test
-
-import (
- . "runtime"
- "testing"
-)
-
-// Simple serial sanity test for parallelfor.
-func TestParFor(t *testing.T) {
- const P = 1
- const N = 20
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- desc := NewParFor(P)
- ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- ParForDo(desc)
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-}
-
-// Test that nonblocking parallelfor does not block.
-func TestParFor2(t *testing.T) {
- const P = 7
- const N = 1003
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- desc := NewParFor(P)
- ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- for p := 0; p < P; p++ {
- ParForDo(desc)
- }
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-}
-
-// Test that iterations are properly distributed.
-func TestParForSetup(t *testing.T) {
- const P = 11
- const N = 101
- desc := NewParFor(P)
- for n := uint32(0); n < N; n++ {
- for p := uint32(1); p <= P; p++ {
- ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
- sum := uint32(0)
- size0 := uint32(0)
- end0 := uint32(0)
- for i := uint32(0); i < p; i++ {
- begin, end := ParForIters(desc, i)
- size := end - begin
- sum += size
- if i == 0 {
- size0 = size
- if begin != 0 {
- t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
- }
- } else {
- if size != size0 && size != size0+1 {
- t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
- }
- if begin != end0 {
- t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
- }
- }
- end0 = end
- }
- if sum != n {
- t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
- }
- }
- }
-}
-
-// Test parallel parallelfor.
-func TestParForParallel(t *testing.T) {
- N := uint64(1e7)
- if testing.Short() {
- N /= 10
- }
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- P := GOMAXPROCS(-1)
- c := make(chan bool, P)
- desc := NewParFor(uint32(P))
- ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- for p := 1; p < P; p++ {
- go func() {
- ParForDo(desc)
- c <- true
- }()
- }
- ParForDo(desc)
- for p := 1; p < P; p++ {
- <-c
- }
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-
- data, desc = nil, nil
- GC()
-}
diff --git a/libgo/go/runtime/pprof/internal/protopprof/protomemprofile.go b/libgo/go/runtime/pprof/internal/protopprof/protomemprofile.go
new file mode 100644
index 0000000000..c2ab5b5702
--- /dev/null
+++ b/libgo/go/runtime/pprof/internal/protopprof/protomemprofile.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package protopprof
+
+import (
+ "internal/pprof/profile"
+ "math"
+ "runtime"
+ "time"
+)
+
+// EncodeMemProfile converts MemProfileRecords to a Profile.
+func EncodeMemProfile(mr []runtime.MemProfileRecord, rate int64, t time.Time) *profile.Profile {
+ p := &profile.Profile{
+ Period: rate,
+ PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"},
+ SampleType: []*profile.ValueType{
+ {Type: "alloc_objects", Unit: "count"},
+ {Type: "alloc_space", Unit: "bytes"},
+ {Type: "inuse_objects", Unit: "count"},
+ {Type: "inuse_space", Unit: "bytes"},
+ },
+ TimeNanos: int64(t.UnixNano()),
+ }
+
+ locs := make(map[uintptr]*profile.Location)
+ for _, r := range mr {
+ stack := r.Stack()
+ sloc := make([]*profile.Location, len(stack))
+ for i, addr := range stack {
+ loc := locs[addr]
+ if loc == nil {
+ loc = &profile.Location{
+ ID: uint64(len(p.Location) + 1),
+ Address: uint64(addr),
+ }
+ locs[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ sloc[i] = loc
+ }
+
+ ao, ab := scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
+ uo, ub := scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
+
+ p.Sample = append(p.Sample, &profile.Sample{
+ Value: []int64{ao, ab, uo, ub},
+ Location: sloc,
+ })
+ }
+ if runtime.GOOS == "linux" {
+ addMappings(p)
+ }
+ return p
+}
+
+// scaleHeapSample adjusts the data from a heap Sample to
+// account for its probability of appearing in the collected
+// data. heap profiles are a sampling of the memory allocations
+// requests in a program. We estimate the unsampled value by dividing
+// each collected sample by its probability of appearing in the
+// profile. heap profiles rely on a poisson process to determine
+// which samples to collect, based on the desired average collection
+// rate R. The probability of a sample of size S to appear in that
+// profile is 1-exp(-S/R).
+func scaleHeapSample(count, size, rate int64) (int64, int64) {
+ if count == 0 || size == 0 {
+ return 0, 0
+ }
+
+ if rate <= 1 {
+ // if rate==1 all samples were collected so no adjustment is needed.
+ // if rate<1 treat as unknown and skip scaling.
+ return count, size
+ }
+
+ avgSize := float64(size) / float64(count)
+ scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
+
+ return int64(float64(count) * scale), int64(float64(size) * scale)
+}
diff --git a/libgo/go/runtime/pprof/internal/protopprof/protomemprofile_test.go b/libgo/go/runtime/pprof/internal/protopprof/protomemprofile_test.go
new file mode 100644
index 0000000000..a10fe772cc
--- /dev/null
+++ b/libgo/go/runtime/pprof/internal/protopprof/protomemprofile_test.go
@@ -0,0 +1,104 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package protopprof
+
+import (
+ "bytes"
+ "internal/pprof/profile"
+ "io/ioutil"
+ "reflect"
+ "runtime"
+ "testing"
+ "time"
+)
+
+// TestSampledHeapAllocProfile tests encoding of a memory profile from
+// runtime.MemProfileRecord data.
+func TestSampledHeapAllocProfile(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("Test requires a system with /proc/self/maps")
+ }
+
+ // Figure out two addresses from /proc/self/maps.
+ mmap, err := ioutil.ReadFile("/proc/self/maps")
+ if err != nil {
+ t.Fatal("Cannot read /proc/self/maps")
+ }
+ rd := bytes.NewReader(mmap)
+ mprof := &profile.Profile{}
+ if err = mprof.ParseMemoryMap(rd); err != nil {
+ t.Fatalf("Cannot parse /proc/self/maps")
+ }
+ if len(mprof.Mapping) < 2 {
+ // It is possible for a binary to only have 1 executable
+ // region of memory.
+ t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping))
+ }
+ address1 := mprof.Mapping[0].Start
+ address2 := mprof.Mapping[1].Start
+
+ var buf bytes.Buffer
+
+ rec, rate := testMemRecords(address1, address2)
+ p := EncodeMemProfile(rec, rate, time.Now())
+ if err := p.Write(&buf); err != nil {
+ t.Fatalf("Failed to write profile: %v", err)
+ }
+
+ p, err = profile.Parse(&buf)
+ if err != nil {
+ t.Fatalf("Could not parse Profile profile: %v", err)
+ }
+
+ // Expected PeriodType, SampleType and Sample.
+ expectedPeriodType := &profile.ValueType{Type: "space", Unit: "bytes"}
+ expectedSampleType := []*profile.ValueType{
+ {Type: "alloc_objects", Unit: "count"},
+ {Type: "alloc_space", Unit: "bytes"},
+ {Type: "inuse_objects", Unit: "count"},
+ {Type: "inuse_space", Unit: "bytes"},
+ }
+ // Expected samples, with values unsampled according to the profiling rate.
+ expectedSample := []*profile.Sample{
+ {Value: []int64{2050, 2099200, 1537, 1574400}, Location: []*profile.Location{
+ {ID: 1, Mapping: mprof.Mapping[0], Address: address1},
+ {ID: 2, Mapping: mprof.Mapping[1], Address: address2},
+ }},
+ {Value: []int64{1, 829411, 1, 829411}, Location: []*profile.Location{
+ {ID: 3, Mapping: mprof.Mapping[1], Address: address2 + 1},
+ {ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 2},
+ }},
+ {Value: []int64{1, 829411, 0, 0}, Location: []*profile.Location{
+ {ID: 5, Mapping: mprof.Mapping[0], Address: address1 + 1},
+ {ID: 6, Mapping: mprof.Mapping[0], Address: address1 + 2},
+ {ID: 7, Mapping: mprof.Mapping[1], Address: address2 + 3},
+ }},
+ }
+
+ if p.Period != 512*1024 {
+ t.Fatalf("Sampling periods do not match")
+ }
+ if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) {
+ t.Fatalf("Period types do not match")
+ }
+ if !reflect.DeepEqual(p.SampleType, expectedSampleType) {
+ t.Fatalf("Sample types do not match")
+ }
+ if !reflect.DeepEqual(p.Sample, expectedSample) {
+ t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample),
+ getSampleAsString(p.Sample))
+ }
+}
+
+func testMemRecords(a1, a2 uint64) ([]runtime.MemProfileRecord, int64) {
+ addr1, addr2 := uintptr(a1), uintptr(a2)
+ rate := int64(512 * 1024)
+ rec := []runtime.MemProfileRecord{
+ {4096, 1024, 4, 1, [32]uintptr{addr1, addr2}},
+ {512 * 1024, 0, 1, 0, [32]uintptr{addr2 + 1, addr2 + 2}},
+ {512 * 1024, 512 * 1024, 1, 1, [32]uintptr{addr1 + 1, addr1 + 2, addr2 + 3}},
+ }
+ return rec, rate
+}
diff --git a/libgo/go/runtime/pprof/internal/protopprof/protopprof.go b/libgo/go/runtime/pprof/internal/protopprof/protopprof.go
new file mode 100644
index 0000000000..5d269c4f65
--- /dev/null
+++ b/libgo/go/runtime/pprof/internal/protopprof/protopprof.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package protopprof converts the runtime's raw profile logs
+// to Profile structs containing a representation of the pprof
+// protocol buffer profile format.
+package protopprof
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "time"
+ "unsafe"
+
+ "internal/pprof/profile"
+)
+
+// TranslateCPUProfile parses binary CPU profiling stack trace data
+// generated by runtime.CPUProfile() into a profile struct.
+func TranslateCPUProfile(b []byte, startTime time.Time) (*profile.Profile, error) {
+ const wordSize = unsafe.Sizeof(uintptr(0))
+ const minRawProfile = 5 * wordSize // Need a minimum of 5 words.
+ if uintptr(len(b)) < minRawProfile {
+ return nil, fmt.Errorf("truncated profile")
+ }
+ n := int(uintptr(len(b)) / wordSize)
+ data := ((*[1 << 28]uintptr)(unsafe.Pointer(&b[0])))[:n:n]
+ period := data[3]
+ data = data[5:] // skip header
+
+ // profile initialization taken from pprof tool
+ p := &profile.Profile{
+ Period: int64(period) * 1000,
+ PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"},
+ SampleType: []*profile.ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "nanoseconds"},
+ },
+ TimeNanos: int64(startTime.UnixNano()),
+ DurationNanos: time.Since(startTime).Nanoseconds(),
+ }
+ // Parse CPU samples from the profile.
+ locs := make(map[uint64]*profile.Location)
+ for len(b) > 0 {
+ if len(data) < 2 || uintptr(len(data)) < 2+data[1] {
+ return nil, fmt.Errorf("truncated profile")
+ }
+ count := data[0]
+ nstk := data[1]
+ if uintptr(len(data)) < 2+nstk {
+ return nil, fmt.Errorf("truncated profile")
+ }
+ stk := data[2 : 2+nstk]
+ data = data[2+nstk:]
+
+ if count == 0 && nstk == 1 && stk[0] == 0 {
+ // end of data marker
+ break
+ }
+
+ sloc := make([]*profile.Location, len(stk))
+ for i, addr := range stk {
+ addr := uint64(addr)
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call
+ // (except for the leaf, which is not a call).
+ if i > 0 {
+ addr--
+ }
+ loc := locs[addr]
+ if loc == nil {
+ loc = &profile.Location{
+ ID: uint64(len(p.Location) + 1),
+ Address: addr,
+ }
+ locs[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ sloc[i] = loc
+ }
+ p.Sample = append(p.Sample, &profile.Sample{
+ Value: []int64{int64(count), int64(count) * int64(p.Period)},
+ Location: sloc,
+ })
+ }
+
+ if runtime.GOOS == "linux" {
+ if err := addMappings(p); err != nil {
+ return nil, err
+ }
+ }
+ return p, nil
+}
+
+func addMappings(p *profile.Profile) error {
+ // Parse memory map from /proc/self/maps
+ f, err := os.Open("/proc/self/maps")
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ return p.ParseMemoryMap(f)
+}
diff --git a/libgo/go/runtime/pprof/internal/protopprof/protopprof_test.go b/libgo/go/runtime/pprof/internal/protopprof/protopprof_test.go
new file mode 100644
index 0000000000..f1937b5bd0
--- /dev/null
+++ b/libgo/go/runtime/pprof/internal/protopprof/protopprof_test.go
@@ -0,0 +1,171 @@
+// 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 protopprof
+
+import (
+ "bytes"
+ "fmt"
+ "internal/pprof/profile"
+ "io/ioutil"
+ "reflect"
+ "runtime"
+ "testing"
+ "time"
+ "unsafe"
+)
+
+// Helper function to initialize empty cpu profile with sampling period provided.
+func createEmptyProfileWithPeriod(t *testing.T, periodMs uint64) bytes.Buffer {
+ // Mock the sample header produced by cpu profiler. Write a sample
+ // period of 2000 microseconds, followed by no samples.
+ buf := new(bytes.Buffer)
+ // Profile header is as follows:
+ // The first, third and fifth words are 0. The second word is 3.
+ // The fourth word is the period.
+ // EOD marker:
+ // The sixth word -- count is initialized to 0 above.
+ // The code below sets the seventh word -- nstk to 1
+ // The eighth word -- addr is initialized to 0 above.
+ words := []int{0, 3, 0, int(periodMs), 0, 0, 1, 0}
+ n := int(unsafe.Sizeof(0)) * len(words)
+ data := ((*[1 << 29]byte)(unsafe.Pointer(&words[0])))[:n:n]
+ if _, err := buf.Write(data); err != nil {
+ t.Fatalf("createEmptyProfileWithPeriod failed: %v", err)
+ }
+ return *buf
+}
+
+// Helper function to initialize cpu profile with two sample values.
+func createProfileWithTwoSamples(t *testing.T, periodMs uintptr, count1 uintptr, count2 uintptr,
+ address1 uintptr, address2 uintptr) bytes.Buffer {
+ // Mock the sample header produced by cpu profiler. Write a sample
+ // period of 2000 microseconds, followed by no samples.
+ buf := new(bytes.Buffer)
+ words := []uintptr{0, 3, 0, uintptr(periodMs), 0, uintptr(count1), 2,
+ uintptr(address1), uintptr(address1 + 2),
+ uintptr(count2), 2, uintptr(address2), uintptr(address2 + 2),
+ 0, 1, 0}
+ for _, n := range words {
+ var err error
+ switch unsafe.Sizeof(int(0)) {
+ case 8:
+ _, err = buf.Write((*[8]byte)(unsafe.Pointer(&n))[:8:8])
+ case 4:
+ _, err = buf.Write((*[4]byte)(unsafe.Pointer(&n))[:4:4])
+ }
+ if err != nil {
+ t.Fatalf("createProfileWithTwoSamples failed: %v", err)
+ }
+ }
+ return *buf
+}
+
+// Tests TranslateCPUProfile parses correct sampling period in an otherwise empty cpu profile.
+func TestTranlateCPUProfileSamplingPeriod(t *testing.T) {
+ // A test server with mock cpu profile data.
+ var buf bytes.Buffer
+
+ startTime := time.Now()
+ b := createEmptyProfileWithPeriod(t, 2000)
+ p, err := TranslateCPUProfile(b.Bytes(), startTime)
+ if err != nil {
+ t.Fatalf("translate failed: %v", err)
+ }
+ if err := p.Write(&buf); err != nil {
+ t.Fatalf("write failed: %v", err)
+ }
+
+ p, err = profile.Parse(&buf)
+ if err != nil {
+ t.Fatalf("Could not parse Profile profile: %v", err)
+ }
+
+ // Expected PeriodType and SampleType.
+ expectedPeriodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
+ expectedSampleType := []*profile.ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "nanoseconds"},
+ }
+ if p.Period != 2000*1000 || !reflect.DeepEqual(p.PeriodType, expectedPeriodType) ||
+ !reflect.DeepEqual(p.SampleType, expectedSampleType) || p.Sample != nil {
+ t.Fatalf("Unexpected Profile fields")
+ }
+}
+
+func getSampleAsString(sample []*profile.Sample) string {
+ var str string
+ for _, x := range sample {
+ for _, y := range x.Location {
+ if y.Mapping != nil {
+ str += fmt.Sprintf("Mapping:%v\n", *y.Mapping)
+ }
+ str += fmt.Sprintf("Location:%v\n", y)
+ }
+ str += fmt.Sprintf("Sample:%v\n", *x)
+ }
+ return str
+}
+
+// Tests TranslateCPUProfile parses a cpu profile with sample values present.
+func TestTranslateCPUProfileWithSamples(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("test requires a system with /proc/self/maps")
+ }
+ // Figure out two addresses from /proc/self/maps.
+ mmap, err := ioutil.ReadFile("/proc/self/maps")
+ if err != nil {
+ t.Fatal("Cannot read /proc/self/maps")
+ }
+ rd := bytes.NewReader(mmap)
+ mprof := &profile.Profile{}
+ if err = mprof.ParseMemoryMap(rd); err != nil {
+ t.Fatalf("Cannot parse /proc/self/maps")
+ }
+ if len(mprof.Mapping) < 2 {
+ // It is possible for a binary to only have 1 executable
+ // region of memory.
+ t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping))
+ }
+ address1 := mprof.Mapping[0].Start
+ address2 := mprof.Mapping[1].Start
+ // A test server with mock cpu profile data.
+
+ startTime := time.Now()
+ b := createProfileWithTwoSamples(t, 2000, 20, 40, uintptr(address1), uintptr(address2))
+ p, err := TranslateCPUProfile(b.Bytes(), startTime)
+
+ if err != nil {
+ t.Fatalf("Could not parse Profile profile: %v", err)
+ }
+ // Expected PeriodType, SampleType and Sample.
+ expectedPeriodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
+ expectedSampleType := []*profile.ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "nanoseconds"},
+ }
+ expectedSample := []*profile.Sample{
+ {Value: []int64{20, 20 * 2000 * 1000}, Location: []*profile.Location{
+ {ID: 1, Mapping: mprof.Mapping[0], Address: address1},
+ {ID: 2, Mapping: mprof.Mapping[0], Address: address1 + 1},
+ }},
+ {Value: []int64{40, 40 * 2000 * 1000}, Location: []*profile.Location{
+ {ID: 3, Mapping: mprof.Mapping[1], Address: address2},
+ {ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 1},
+ }},
+ }
+ if p.Period != 2000*1000 {
+ t.Fatalf("Sampling periods do not match")
+ }
+ if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) {
+ t.Fatalf("Period types do not match")
+ }
+ if !reflect.DeepEqual(p.SampleType, expectedSampleType) {
+ t.Fatalf("Sample types do not match")
+ }
+ if !reflect.DeepEqual(p.Sample, expectedSample) {
+ t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample),
+ getSampleAsString(p.Sample))
+ }
+}
diff --git a/libgo/go/runtime/pprof/mprof_test.go b/libgo/go/runtime/pprof/mprof_test.go
index bfa7b3b474..079af15588 100644
--- a/libgo/go/runtime/pprof/mprof_test.go
+++ b/libgo/go/runtime/pprof/mprof_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,6 +7,7 @@ package pprof_test
import (
"bytes"
"fmt"
+ "reflect"
"regexp"
"runtime"
. "runtime/pprof"
@@ -42,6 +43,17 @@ func allocatePersistent1K() {
}
}
+// Allocate transient memory using reflect.Call.
+
+func allocateReflectTransient() {
+ memSink = make([]byte, 2<<20)
+}
+
+func allocateReflect() {
+ rv := reflect.ValueOf(allocateReflectTransient)
+ rv.Call(nil)
+}
+
var memoryProfilerRun = 0
func TestMemoryProfiler(t *testing.T) {
@@ -61,6 +73,7 @@ func TestMemoryProfiler(t *testing.T) {
allocateTransient1M()
allocateTransient2M()
allocatePersistent1K()
+ allocateReflect()
memSink = nil
runtime.GC() // materialize stats
@@ -74,21 +87,25 @@ func TestMemoryProfiler(t *testing.T) {
tests := []string{
fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f x]+
-# 0x[0-9,a-f]+ pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+ .*/mprof_test\.go:40
-# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test\.go:63
+# 0x[0-9,a-f]+ pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+ .*/mprof_test\.go:41
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test\.go:75
`, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f x]+
-# 0x[0-9,a-f]+ pprof_test\.allocateTransient1M\+0x[0-9,a-f]+ .*/mprof_test.go:21
-# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:61
+# 0x[0-9,a-f]+ pprof_test\.allocateTransient1M\+0x[0-9,a-f]+ .*/mprof_test.go:22
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:73
`, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
// This should start with "0: 0" but gccgo's imprecise
// GC means that sometimes the value is not collected.
fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @ 0x[0-9,a-f x]+
-# 0x[0-9,a-f]+ pprof_test\.allocateTransient2M\+0x[0-9,a-f]+ .*/mprof_test.go:27
-# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:62
+# 0x[0-9,a-f]+ pprof_test\.allocateTransient2M\+0x[0-9,a-f]+ .*/mprof_test.go:28
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:74
`, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun),
+
+ fmt.Sprintf(`0: 0 \[%v: %v\] @( 0x[0-9,a-f]+)+
+# 0x[0-9,a-f]+ pprof_test\.allocateReflectTransient\+0x[0-9,a-f]+ .*/mprof_test.go:49
+`, memoryProfilerRun, (2<<20)*memoryProfilerRun),
}
for _, test := range tests {
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 18e99366fb..0db1dedd7a 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -1,23 +1,87 @@
-// Copyright 2010 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 pprof writes runtime profiling data in the format expected
// by the pprof visualization tool.
+//
+// Profiling a Go program
+//
+// The first step to profiling a Go program is to enable profiling.
+// Support for profiling benchmarks built with the standard testing
+// package is built into go test. For example, the following command
+// runs benchmarks in the current directory and writes the CPU and
+// memory profiles to cpu.prof and mem.prof:
+//
+// go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
+//
+// To add equivalent profiling support to a standalone program, add
+// code like the following to your main function:
+//
+// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
+// var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
+//
+// func main() {
+// flag.Parse()
+// if *cpuprofile != "" {
+// f, err := os.Create(*cpuprofile)
+// if err != nil {
+// log.Fatal("could not create CPU profile: ", err)
+// }
+// if err := pprof.StartCPUProfile(f); err != nil {
+// log.Fatal("could not start CPU profile: ", err)
+// }
+// defer pprof.StopCPUProfile()
+// }
+// ...
+// if *memprofile != "" {
+// f, err := os.Create(*memprofile)
+// if err != nil {
+// log.Fatal("could not create memory profile: ", err)
+// }
+// runtime.GC() // get up-to-date statistics
+// if err := pprof.WriteHeapProfile(f); err != nil {
+// log.Fatal("could not write memory profile: ", err)
+// }
+// f.Close()
+// }
+// }
+//
+// There is also a standard HTTP interface to profiling data. Adding
+// the following line will install handlers under the /debug/pprof/
+// URL to download live profiles:
+//
+// import _ "net/http/pprof"
+//
+// See the net/http/pprof package for more details.
+//
+// Profiles can then be visualized with the pprof tool:
+//
+// go tool pprof cpu.prof
+//
+// There are many commands available from the pprof command line.
+// Commonly used commands include "top", which prints a summary of the
+// top program hot-spots, and "web", which opens an interactive graph
+// of hot-spots and their call graphs. Use "help" for information on
+// all pprof commands.
+//
// For more information about pprof, see
-// http://code.google.com/p/google-perftools/.
+// https://github.com/google/pprof/blob/master/doc/pprof.md.
package pprof
import (
"bufio"
"bytes"
"fmt"
+ "internal/pprof/profile"
"io"
"runtime"
+ "runtime/pprof/internal/protopprof"
"sort"
"strings"
"sync"
"text/tabwriter"
+ "time"
)
// BUG(rsc): Profiles are only as good as the kernel support used to generate them.
@@ -31,12 +95,13 @@ import (
//
// A Profile's methods can be called from multiple goroutines simultaneously.
//
-// Each Profile has a unique name. A few profiles are predefined:
+// Each Profile has a unique name. A few profiles are predefined:
//
// goroutine - stack traces of all current goroutines
// heap - a sampling of all heap allocations
// threadcreate - stack traces that led to the creation of new OS threads
// block - stack traces that led to blocking on synchronization primitives
+// mutex - stack traces of holders of contended mutexes
//
// These predefined profiles maintain themselves and panic on an explicit
// Add or Remove method call.
@@ -48,7 +113,7 @@ import (
// all known allocations. This exception helps mainly in programs running
// without garbage collection enabled, usually for debugging purposes.
//
-// The CPU profile is not available as a Profile. It has a special API,
+// The CPU profile is not available as a Profile. It has a special API,
// the StartCPUProfile and StopCPUProfile functions, because it streams
// output to a writer during profiling.
//
@@ -90,6 +155,12 @@ var blockProfile = &Profile{
write: writeBlock,
}
+var mutexProfile = &Profile{
+ name: "mutex",
+ count: countMutex,
+ write: writeMutex,
+}
+
func lockProfiles() {
profiles.mu.Lock()
if profiles.m == nil {
@@ -99,6 +170,7 @@ func lockProfiles() {
"threadcreate": threadcreateProfile,
"heap": heapProfile,
"block": blockProfile,
+ "mutex": mutexProfile,
}
}
}
@@ -140,21 +212,15 @@ func Profiles() []*Profile {
lockProfiles()
defer unlockProfiles()
- var all []*Profile
+ all := make([]*Profile, 0, len(profiles.m))
for _, p := range profiles.m {
all = append(all, p)
}
- sort.Sort(byName(all))
+ sort.Slice(all, func(i, j int) bool { return all[i].name < all[j].name })
return all
}
-type byName []*Profile
-
-func (x byName) Len() int { return len(x) }
-func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byName) Less(i, j int) bool { return x[i].name < x[j].name }
-
// Name returns this profile's name, which can be passed to Lookup to reobtain the profile.
func (p *Profile) Name() string {
return p.name
@@ -173,11 +239,11 @@ func (p *Profile) Count() int {
// Add adds the current execution stack to the profile, associated with value.
// Add stores value in an internal map, so value must be suitable for use as
// a map key and will not be garbage collected until the corresponding
-// call to Remove. Add panics if the profile already contains a stack for value.
+// call to Remove. Add panics if the profile already contains a stack for value.
//
// The skip parameter has the same meaning as runtime.Caller's skip
-// and controls where the stack trace begins. Passing skip=0 begins the
-// trace in the function calling Add. For example, given this
+// and controls where the stack trace begins. Passing skip=0 begins the
+// trace in the function calling Add. For example, given this
// execution stack:
//
// Add
@@ -237,7 +303,7 @@ func (p *Profile) WriteTo(w io.Writer, debug int) error {
}
// Obtain consistent snapshot under lock; then process without lock.
- var all [][]uintptr
+ all := make([][]uintptr, 0, len(p.m))
p.mu.Lock()
for _, stk := range p.m {
all = append(all, stk)
@@ -266,7 +332,7 @@ func (x stackProfile) Less(i, j int) bool {
}
// A countProfile is a set of stack traces to be printed as counts
-// grouped by stack trace. There are multiple implementations:
+// grouped by stack trace. There are multiple implementations:
// all that matters is that we can find out how many traces there are
// and obtain each trace in turn.
type countProfile interface {
@@ -275,17 +341,8 @@ type countProfile interface {
}
// printCountProfile prints a countProfile at the specified debug level.
+// The profile will be in compressed proto format unless debug is nonzero.
func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
- b := bufio.NewWriter(w)
- var tw *tabwriter.Writer
- w = b
- if debug > 0 {
- tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
- w = tw
- }
-
- fmt.Fprintf(w, "%s profile: total %d\n", name, p.Len())
-
// Build count of each stack.
var buf bytes.Buffer
key := func(stk []uintptr) string {
@@ -296,74 +353,114 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
}
return buf.String()
}
- m := map[string]int{}
+ count := map[string]int{}
+ index := map[string]int{}
+ var keys []string
n := p.Len()
for i := 0; i < n; i++ {
- m[key(p.Stack(i))]++
+ k := key(p.Stack(i))
+ if count[k] == 0 {
+ index[k] = i
+ keys = append(keys, k)
+ }
+ count[k]++
}
- // Print stacks, listing count on first occurrence of a unique stack.
- for i := 0; i < n; i++ {
- stk := p.Stack(i)
- s := key(stk)
- if count := m[s]; count != 0 {
- fmt.Fprintf(w, "%d %s\n", count, s)
- if debug > 0 {
- printStackRecord(w, stk, false)
+ sort.Sort(&keysByCount{keys, count})
+
+ if debug > 0 {
+ // Print debug profile in legacy format
+ tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len())
+ for _, k := range keys {
+ fmt.Fprintf(tw, "%d %s\n", count[k], k)
+ printStackRecord(tw, p.Stack(index[k]), false)
+ }
+ return tw.Flush()
+ }
+
+ // Output profile in protobuf form.
+ prof := &profile.Profile{
+ PeriodType: &profile.ValueType{Type: name, Unit: "count"},
+ Period: 1,
+ Sample: make([]*profile.Sample, 0, len(keys)),
+ SampleType: []*profile.ValueType{{Type: name, Unit: "count"}},
+ }
+ locMap := make(map[uintptr]*profile.Location)
+ for _, k := range keys {
+ stk := p.Stack(index[k])
+ c := count[k]
+ locs := make([]*profile.Location, len(stk))
+ for i, addr := range stk {
+ loc := locMap[addr]
+ if loc == nil {
+ loc = &profile.Location{
+ ID: uint64(len(locMap) + 1),
+ Address: uint64(addr - 1),
+ }
+ prof.Location = append(prof.Location, loc)
+ locMap[addr] = loc
}
- delete(m, s)
+ locs[i] = loc
}
+ prof.Sample = append(prof.Sample, &profile.Sample{
+ Location: locs,
+ Value: []int64{int64(c)},
+ })
}
+ return prof.Write(w)
+}
- if tw != nil {
- tw.Flush()
+// keysByCount sorts keys with higher counts first, breaking ties by key string order.
+type keysByCount struct {
+ keys []string
+ count map[string]int
+}
+
+func (x *keysByCount) Len() int { return len(x.keys) }
+func (x *keysByCount) Swap(i, j int) { x.keys[i], x.keys[j] = x.keys[j], x.keys[i] }
+func (x *keysByCount) Less(i, j int) bool {
+ ki, kj := x.keys[i], x.keys[j]
+ ci, cj := x.count[ki], x.count[kj]
+ if ci != cj {
+ return ci > cj
}
- return b.Flush()
+ return ki < kj
}
// printStackRecord prints the function + source line information
// for a single stack trace.
func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
show := allFrames
- wasPanic := false
- for i, pc := range stk {
- f := runtime.FuncForPC(pc)
- if f == nil {
- show = true
- fmt.Fprintf(w, "#\t%#x\n", pc)
- wasPanic = false
- } else {
- tracepc := pc
- // Back up to call instruction.
- if i > 0 && pc > f.Entry() && !wasPanic {
- if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
- tracepc--
- } else if runtime.GOARCH == "s390" || runtime.GOARCH == "s390x" {
- // only works if function was called
- // with the brasl instruction (or a
- // different 6-byte instruction).
- tracepc -= 6
- } else {
- tracepc -= 4 // arm, etc
- }
- }
- file, line := f.FileLine(tracepc)
- name := f.Name()
- // Hide runtime.goexit and any runtime functions at the beginning.
- // This is useful mainly for allocation traces.
- wasPanic = name == "runtime.gopanic"
- if name == "runtime.goexit" || !show && (strings.HasPrefix(name, "runtime.") || strings.HasPrefix(name, "runtime_")) {
- continue
- }
- if !show && !strings.Contains(name, ".") && strings.HasPrefix(name, "__go_") {
- continue
- }
- if !show && name == "" {
- // This can happen due to http://gcc.gnu.org/PR65797.
- continue
+ frames := runtime.CallersFrames(stk)
+ for {
+ frame, more := frames.Next()
+ name := frame.Function
+
+ // Hide runtime.goexit and any runtime functions at the beginning.
+ // This is useful mainly for allocation traces.
+ skip := name == "runtime.goexit"
+ if !show {
+ switch {
+ case strings.HasPrefix(name, "runtime."):
+ skip = true
+ case strings.HasPrefix(name, "runtime_"):
+ skip = true
+ case !strings.Contains(name, ".") && strings.HasPrefix(name, "__go_"):
+ skip = true
}
+ }
+
+ if !show && name == "" {
+ // This can happen due to http://gcc.gnu.org/PR65797.
+ } else if name == "" {
+ fmt.Fprintf(w, "#\t%#x\n", frame.PC)
+ } else if !skip {
show = true
- fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, name, pc-f.Entry(), file, line)
+ fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line)
+ }
+ if !more {
+ break
}
}
if !show {
@@ -377,12 +474,6 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
// Interface to system profiles.
-type byInUseBytes []runtime.MemProfileRecord
-
-func (x byInUseBytes) Len() int { return len(x) }
-func (x byInUseBytes) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byInUseBytes) Less(i, j int) bool { return x[i].InUseBytes() > x[j].InUseBytes() }
-
// WriteHeapProfile is shorthand for Lookup("heap").WriteTo(w, 0).
// It is preserved for backwards compatibility.
func WriteHeapProfile(w io.Writer) error {
@@ -418,15 +509,16 @@ func writeHeap(w io.Writer, debug int) error {
// Profile grew; try again.
}
- sort.Sort(byInUseBytes(p))
+ if debug == 0 {
+ pp := protopprof.EncodeMemProfile(p, int64(runtime.MemProfileRate), time.Now())
+ return pp.Write(w)
+ }
+
+ sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() })
b := bufio.NewWriter(w)
- var tw *tabwriter.Writer
- w = b
- if debug > 0 {
- tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
- w = tw
- }
+ tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0)
+ w = tw
var total runtime.MemProfileRecord
for i := range p {
@@ -454,9 +546,7 @@ func writeHeap(w io.Writer, debug int) error {
fmt.Fprintf(w, " %#x", pc)
}
fmt.Fprintf(w, "\n")
- if debug > 0 {
- printStackRecord(w, r.Stack(), false)
- }
+ printStackRecord(w, r.Stack(), false)
}
// Print memstats information too.
@@ -482,16 +572,15 @@ func writeHeap(w io.Writer, debug int) error {
fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+ fmt.Fprintf(w, "# GCSys = %d\n", s.GCSys)
+ fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys)
fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
- fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
- if tw != nil {
- tw.Flush()
- }
+ tw.Flush()
return b.Flush()
}
@@ -521,7 +610,7 @@ func writeGoroutine(w io.Writer, debug int) error {
func writeGoroutineStacks(w io.Writer) error {
// We don't know how big the buffer needs to be to collect
- // all the goroutines. Start with 1 MB and try a few times, doubling each time.
+ // all the goroutines. Start with 1 MB and try a few times, doubling each time.
// Give up and use a truncated trace if 64 MB is not enough.
buf := make([]byte, 1<<20)
for i := 0; ; i++ {
@@ -584,7 +673,7 @@ var cpu struct {
// Go code built with -buildmode=c-archive or -buildmode=c-shared.
// StartCPUProfile relies on the SIGPROF signal, but that signal will
// be delivered to the main program's SIGPROF signal handler (if any)
-// not to the one used by Go. To make it work, call os/signal.Notify
+// not to the one used by Go. To make it work, call os/signal.Notify
// for syscall.SIGPROF, but note that doing so may break any profiling
// being done by the main program.
func StartCPUProfile(w io.Writer) error {
@@ -595,7 +684,7 @@ func StartCPUProfile(w io.Writer) error {
// 100 Hz is a reasonable choice: it is frequent enough to
// produce useful data, rare enough not to bog down the
// system, and a nice round number to make it easy to
- // convert sample counts to seconds. Instead of requiring
+ // convert sample counts to seconds. Instead of requiring
// each client to specify the frequency, we hard code it.
const hz = 100
@@ -615,13 +704,29 @@ func StartCPUProfile(w io.Writer) error {
}
func profileWriter(w io.Writer) {
+ startTime := time.Now()
+ // This will buffer the entire profile into buf and then
+ // translate it into a profile.Profile structure. This will
+ // create two copies of all the data in the profile in memory.
+ // TODO(matloob): Convert each chunk of the proto output and
+ // stream it out instead of converting the entire profile.
+ var buf bytes.Buffer
for {
data := runtime.CPUProfile()
if data == nil {
break
}
- w.Write(data)
+ buf.Write(data)
+ }
+
+ profile, err := protopprof.TranslateCPUProfile(buf.Bytes(), startTime)
+ if err != nil {
+ // The runtime should never produce an invalid or truncated profile.
+ // It drops records that can't fit into its log buffers.
+ panic(fmt.Errorf("could not translate binary profile to proto format: %v", err))
}
+
+ profile.Write(w)
cpu.done <- true
}
@@ -640,18 +745,18 @@ func StopCPUProfile() {
<-cpu.done
}
-type byCycles []runtime.BlockProfileRecord
-
-func (x byCycles) Len() int { return len(x) }
-func (x byCycles) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byCycles) Less(i, j int) bool { return x[i].Cycles > x[j].Cycles }
-
// countBlock returns the number of records in the blocking profile.
func countBlock() int {
n, _ := runtime.BlockProfile(nil)
return n
}
+// countMutex returns the number of records in the mutex profile.
+func countMutex() int {
+ n, _ := runtime.MutexProfile(nil)
+ return n
+}
+
// writeBlock writes the current blocking profile to w.
func writeBlock(w io.Writer, debug int) error {
var p []runtime.BlockProfileRecord
@@ -665,7 +770,7 @@ func writeBlock(w io.Writer, debug int) error {
}
}
- sort.Sort(byCycles(p))
+ sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
b := bufio.NewWriter(w)
var tw *tabwriter.Writer
@@ -695,4 +800,49 @@ func writeBlock(w io.Writer, debug int) error {
return b.Flush()
}
+// writeMutex writes the current mutex profile to w.
+func writeMutex(w io.Writer, debug int) error {
+ // TODO(pjw): too much common code with writeBlock. FIX!
+ var p []runtime.BlockProfileRecord
+ n, ok := runtime.MutexProfile(nil)
+ for {
+ p = make([]runtime.BlockProfileRecord, n+50)
+ n, ok = runtime.MutexProfile(p)
+ if ok {
+ p = p[:n]
+ break
+ }
+ }
+
+ sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
+
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
+ fmt.Fprintf(w, "--- mutex:\n")
+ fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond())
+ fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1))
+ for i := range p {
+ r := &p[i]
+ fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count)
+ for _, pc := range r.Stack() {
+ fmt.Fprintf(w, " %#x", pc)
+ }
+ fmt.Fprint(w, "\n")
+ if debug > 0 {
+ printStackRecord(w, r.Stack(), true)
+ }
+ }
+
+ if tw != nil {
+ tw.Flush()
+ }
+ return b.Flush()
+}
+
func runtime_cyclesPerSecond() int64
diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go
index e384e11eda..60340582d5 100644
--- a/libgo/go/runtime/pprof/pprof_test.go
+++ b/libgo/go/runtime/pprof/pprof_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -8,8 +8,12 @@ package pprof_test
import (
"bytes"
+ "compress/gzip"
"fmt"
+ "internal/pprof/profile"
"internal/testenv"
+ "io"
+ "io/ioutil"
"math/big"
"os"
"os/exec"
@@ -20,7 +24,6 @@ import (
"sync"
"testing"
"time"
- "unsafe"
)
func cpuHogger(f func(), dur time.Duration) {
@@ -86,37 +89,18 @@ func TestCPUProfileMultithreaded(t *testing.T) {
})
}
-func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
- // Convert []byte to []uintptr.
- l := len(bytes) / int(unsafe.Sizeof(uintptr(0)))
- val := *(*[]uintptr)(unsafe.Pointer(&bytes))
- val = val[:l]
-
- // 5 for the header, 3 for the trailer.
- if l < 5+3 {
- t.Logf("profile too short: %#x", val)
- if badOS[runtime.GOOS] {
- t.Skipf("ignoring failure on %s; see golang.org/issue/13841", runtime.GOOS)
- return
- }
- t.FailNow()
- }
-
- hd, val, tl := val[:5], val[5:l-3], val[l-3:]
- if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
- t.Fatalf("unexpected header %#x", hd)
- }
-
- if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
- t.Fatalf("malformed end-of-data marker %#x", tl)
+func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) {
+ p, err := profile.Parse(bytes.NewReader(valBytes))
+ if err != nil {
+ t.Fatal(err)
}
-
- for len(val) > 0 {
- if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
- t.Fatalf("malformed profile. leftover: %#x", val)
+ for _, sample := range p.Sample {
+ count := uintptr(sample.Value[0])
+ stk := make([]uintptr, len(sample.Location))
+ for i := range sample.Location {
+ stk[i] = uintptr(sample.Location[i].Address)
}
- f(val[0], val[2:2+val[1]])
- val = val[2+val[1]:]
+ f(count, stk)
}
}
@@ -221,7 +205,11 @@ func profileOk(t *testing.T, need []string, prof bytes.Buffer, duration time.Dur
}
// Check that we got a reasonable number of samples.
- if ideal := uintptr(duration * 100 / time.Second); samples == 0 || samples < ideal/4 {
+ // We used to always require at least ideal/4 samples,
+ // but that is too hard to guarantee on a loaded system.
+ // Now we accept 10 or more samples, which we take to be
+ // enough to show that at least some profiling is occurring.
+ if ideal := uintptr(duration * 100 / time.Second); samples == 0 || (samples < ideal/4 && samples < 10) {
t.Logf("too few samples; got %d, want at least %d, ideally %d", samples, ideal/4, ideal)
ok = false
}
@@ -363,8 +351,49 @@ func TestMathBigDivide(t *testing.T) {
})
}
+func slurpString(r io.Reader) string {
+ slurp, _ := ioutil.ReadAll(r)
+ return string(slurp)
+}
+
+func getLinuxKernelConfig() string {
+ if f, err := os.Open("/proc/config"); err == nil {
+ defer f.Close()
+ return slurpString(f)
+ }
+ if f, err := os.Open("/proc/config.gz"); err == nil {
+ defer f.Close()
+ r, err := gzip.NewReader(f)
+ if err != nil {
+ return ""
+ }
+ return slurpString(r)
+ }
+ if f, err := os.Open("/boot/config"); err == nil {
+ defer f.Close()
+ return slurpString(f)
+ }
+ uname, _ := exec.Command("uname", "-r").Output()
+ if len(uname) > 0 {
+ if f, err := os.Open("/boot/config-" + strings.TrimSpace(string(uname))); err == nil {
+ defer f.Close()
+ return slurpString(f)
+ }
+ }
+ return ""
+}
+
+func haveLinuxHiresTimers() bool {
+ config := getLinuxKernelConfig()
+ return strings.Contains(config, "CONFIG_HIGH_RES_TIMERS=y")
+}
+
func TestStackBarrierProfiling(t *testing.T) {
- if (runtime.GOOS == "linux" && runtime.GOARCH == "arm") || runtime.GOOS == "openbsd" || runtime.GOOS == "solaris" || runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
+ if (runtime.GOOS == "linux" && runtime.GOARCH == "arm") ||
+ runtime.GOOS == "openbsd" ||
+ runtime.GOOS == "solaris" ||
+ runtime.GOOS == "dragonfly" ||
+ runtime.GOOS == "freebsd" {
// This test currently triggers a large number of
// usleep(100)s. These kernels/arches have poor
// resolution timers, so this gives up a whole
@@ -377,6 +406,12 @@ func TestStackBarrierProfiling(t *testing.T) {
return
}
+ if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "mips") {
+ if !haveLinuxHiresTimers() {
+ t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405, golang.org/issue/17936)")
+ }
+ }
+
if !strings.Contains(os.Getenv("GODEBUG"), "gcstackbarrierall=1") {
// Re-execute this test with constant GC and stack
// barriers at every frame.
@@ -389,7 +424,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)
}
@@ -495,6 +530,10 @@ func TestBlockProfile(t *testing.T) {
t.Fatalf("Bad profile header:\n%v", prof)
}
+ if strings.HasSuffix(prof, "#\t0x0\n\n") {
+ t.Errorf("Useless 0 suffix:\n%v", prof)
+ }
+
for _, test := range tests {
if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) {
t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof)
@@ -532,15 +571,20 @@ func blockChanClose() {
}
func blockSelectRecvAsync() {
+ const numTries = 3
c := make(chan bool, 1)
c2 := make(chan bool, 1)
go func() {
- time.Sleep(blockDelay)
- c <- true
+ for i := 0; i < numTries; i++ {
+ time.Sleep(blockDelay)
+ c <- true
+ }
}()
- select {
- case <-c:
- case <-c2:
+ for i := 0; i < numTries; i++ {
+ select {
+ case <-c:
+ case <-c2:
+ }
}
}
@@ -580,3 +624,135 @@ func blockCond() {
c.Wait()
mu.Unlock()
}
+
+func TestMutexProfile(t *testing.T) {
+ old := runtime.SetMutexProfileFraction(1)
+ defer runtime.SetMutexProfileFraction(old)
+ if old != 0 {
+ t.Fatalf("need MutexProfileRate 0, got %d", old)
+ }
+
+ blockMutex()
+
+ var w bytes.Buffer
+ Lookup("mutex").WriteTo(&w, 1)
+ prof := w.String()
+
+ if !strings.HasPrefix(prof, "--- mutex:\ncycles/second=") {
+ t.Errorf("Bad profile header:\n%v", prof)
+ }
+ prof = strings.Trim(prof, "\n")
+ lines := strings.Split(prof, "\n")
+ // gccgo adds an extra line in the stack trace, not sure why.
+ if len(lines) < 6 {
+ t.Errorf("expected 6 lines, got %d %q\n%s", len(lines), prof, prof)
+ }
+ if len(lines) < 6 {
+ return
+ }
+ // checking that the line is like "35258904 1 @ 0x48288d 0x47cd28 0x458931"
+ r2 := `^\d+ 1 @(?: 0x[[:xdigit:]]+)+`
+ //r2 := "^[0-9]+ 1 @ 0x[0-9a-f x]+$"
+ if ok, err := regexp.MatchString(r2, lines[3]); err != nil || !ok {
+ t.Errorf("%q didn't match %q", lines[3], r2)
+ }
+ r3 := "^#.*pprof_test.\\$nested.*$"
+ match := false
+ for _, i := range []int{5, 6} {
+ if ok, _ := regexp.MatchString(r3, lines[i]); ok {
+ match = true
+ break
+ }
+ }
+ if !match {
+ t.Errorf("neither %q nor %q matched %q", lines[5], lines[6], r3)
+ }
+}
+
+func func1(c chan int) { <-c }
+func func2(c chan int) { <-c }
+func func3(c chan int) { <-c }
+func func4(c chan int) { <-c }
+
+func TestGoroutineCounts(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("goroutine stacks not supported on gccgo")
+ }
+ if runtime.GOOS == "openbsd" {
+ testenv.SkipFlaky(t, 15156)
+ }
+ c := make(chan int)
+ for i := 0; i < 100; i++ {
+ if i%10 == 0 {
+ go func1(c)
+ continue
+ }
+ if i%2 == 0 {
+ go func2(c)
+ continue
+ }
+ go func3(c)
+ }
+ time.Sleep(10 * time.Millisecond) // let goroutines block on channel
+
+ var w bytes.Buffer
+ goroutineProf := Lookup("goroutine")
+
+ // Check debug profile
+ goroutineProf.WriteTo(&w, 1)
+ prof := w.String()
+
+ if !containsInOrder(prof, "\n50 @ ", "\n40 @", "\n10 @", "\n1 @") {
+ t.Errorf("expected sorted goroutine counts:\n%s", prof)
+ }
+
+ // Check proto profile
+ w.Reset()
+ goroutineProf.WriteTo(&w, 0)
+ p, err := profile.Parse(&w)
+ if err != nil {
+ t.Errorf("error parsing protobuf profile: %v", err)
+ }
+ if err := p.CheckValid(); err != nil {
+ t.Errorf("protobuf profile is invalid: %v", err)
+ }
+ if !containsCounts(p, []int64{50, 40, 10, 1}) {
+ t.Errorf("expected count profile to contain goroutines with counts %v, got %v",
+ []int64{50, 40, 10, 1}, p)
+ }
+
+ close(c)
+
+ time.Sleep(10 * time.Millisecond) // let goroutines exit
+}
+
+func containsInOrder(s string, all ...string) bool {
+ for _, t := range all {
+ i := strings.Index(s, t)
+ if i < 0 {
+ return false
+ }
+ s = s[i+len(t):]
+ }
+ return true
+}
+
+func containsCounts(prof *profile.Profile, counts []int64) bool {
+ m := make(map[int64]int)
+ for _, c := range counts {
+ m[c]++
+ }
+ for _, s := range prof.Sample {
+ // The count is the single value in the sample
+ if len(s.Value) != 1 {
+ return false
+ }
+ m[s.Value[0]]--
+ }
+ for _, n := range m {
+ if n > 0 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/runtime/print.go b/libgo/go/runtime/print.go
index f789f89083..4db726a755 100644
--- a/libgo/go/runtime/print.go
+++ b/libgo/go/runtime/print.go
@@ -4,7 +4,32 @@
package runtime
-import "unsafe"
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname printbool runtime.printbool
+//go:linkname printfloat runtime.printfloat
+//go:linkname printint runtime.printint
+//go:linkname printhex runtime.printhex
+//go:linkname printuint runtime.printuint
+//go:linkname printcomplex runtime.printcomplex
+//go:linkname printstring runtime.printstring
+//go:linkname printpointer runtime.printpointer
+//go:linkname printiface runtime.printiface
+//go:linkname printeface runtime.printeface
+//go:linkname printslice runtime.printslice
+//go:linkname printnl runtime.printnl
+//go:linkname printsp runtime.printsp
+//go:linkname printlock runtime.printlock
+//go:linkname printunlock runtime.printunlock
+// Temporary for C code to call:
+//go:linkname gwrite runtime.gwrite
+//go:linkname printhex runtime.printhex
// The compiler knows that a print of a value of this type
// should use printhex instead of printuint (decimal).
@@ -19,6 +44,36 @@ func bytes(s string) (ret []byte) {
return
}
+var (
+ // printBacklog is a circular buffer of messages written with the builtin
+ // print* functions, for use in postmortem analysis of core dumps.
+ printBacklog [512]byte
+ printBacklogIndex int
+)
+
+// recordForPanic maintains a circular buffer of messages written by the
+// runtime leading up to a process crash, allowing the messages to be
+// extracted from a core dump.
+//
+// The text written during a process crash (following "panic" or "fatal
+// error") is not saved, since the goroutine stacks will generally be readable
+// from the runtime datastructures in the core file.
+func recordForPanic(b []byte) {
+ printlock()
+
+ if atomic.Load(&panicking) == 0 {
+ // Not actively crashing: maintain circular buffer of print output.
+ for i := 0; i < len(b); {
+ n := copy(printBacklog[printBacklogIndex:], b[i:])
+ i += n
+ printBacklogIndex += n
+ printBacklogIndex %= len(printBacklog)
+ }
+ }
+
+ printunlock()
+}
+
var debuglock mutex
// The compiler emits calls to printlock and printunlock around
@@ -53,6 +108,7 @@ func gwrite(b []byte) {
if len(b) == 0 {
return
}
+ recordForPanic(b)
gp := getg()
if gp == nil || gp.writebuf == nil {
writeErr(b)
@@ -199,17 +255,13 @@ func printpointer(p unsafe.Pointer) {
}
func printstring(s string) {
- if uintptr(len(s)) > maxstring {
- gwrite(bytes("[string too long]"))
- return
- }
gwrite(bytes(s))
}
func printslice(s []byte) {
sp := (*slice)(unsafe.Pointer(&s))
print("[", len(s), "/", cap(s), "]")
- printpointer(unsafe.Pointer(sp.array))
+ printpointer(sp.array)
}
func printeface(e eface) {
diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go
new file mode 100644
index 0000000000..ea7f84e9b7
--- /dev/null
+++ b/libgo/go/runtime/proc.go
@@ -0,0 +1,2890 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
+// Functions temporarily called by C code.
+//go:linkname newextram runtime.newextram
+//go:linkname acquirep runtime.acquirep
+//go:linkname releasep runtime.releasep
+//go:linkname incidlelocked runtime.incidlelocked
+//go:linkname checkdead runtime.checkdead
+//go:linkname sysmon runtime.sysmon
+//go:linkname schedtrace runtime.schedtrace
+//go:linkname allgadd runtime.allgadd
+//go:linkname mcommoninit runtime.mcommoninit
+//go:linkname ready runtime.ready
+//go:linkname gcprocs runtime.gcprocs
+//go:linkname needaddgcproc runtime.needaddgcproc
+//go:linkname stopm runtime.stopm
+//go:linkname handoffp runtime.handoffp
+//go:linkname wakep runtime.wakep
+//go:linkname stoplockedm runtime.stoplockedm
+//go:linkname schedule runtime.schedule
+//go:linkname execute runtime.execute
+//go:linkname gfput runtime.gfput
+//go:linkname gfget runtime.gfget
+//go:linkname lockOSThread runtime.lockOSThread
+//go:linkname unlockOSThread runtime.unlockOSThread
+//go:linkname procresize runtime.procresize
+//go:linkname helpgc runtime.helpgc
+//go:linkname stopTheWorldWithSema runtime.stopTheWorldWithSema
+//go:linkname startTheWorldWithSema runtime.startTheWorldWithSema
+//go:linkname mput runtime.mput
+//go:linkname mget runtime.mget
+//go:linkname globrunqput runtime.globrunqput
+//go:linkname pidleget runtime.pidleget
+//go:linkname runqempty runtime.runqempty
+//go:linkname runqput runtime.runqput
+
+// Function called by misc/cgo/test.
+//go:linkname lockedOSThread runtime.lockedOSThread
+
+// Functions temporarily in C that have not yet been ported.
+func allocm(*p, bool, *unsafe.Pointer, *uintptr) *m
+func malg(bool, bool, *unsafe.Pointer, *uintptr) *g
+func startm(*p, bool)
+func newm(unsafe.Pointer, *p)
+func gchelper()
+func getfingwait() bool
+func getfingwake() bool
+func wakefing() *g
+
+// C functions for ucontext management.
+func gogo(*g)
+func setGContext()
+func makeGContext(*g, unsafe.Pointer, uintptr)
+func getTraceback(me, gp *g)
+
+// main_init_done is a signal used by cgocallbackg that initialization
+// has been completed. It is made before _cgo_notify_runtime_init_done,
+// so all cgo calls can rely on it existing. When main_init is complete,
+// it is closed, meaning cgocallbackg can reliably receive from it.
+var main_init_done chan bool
+
+func goready(gp *g, traceskip int) {
+ systemstack(func() {
+ ready(gp, traceskip, true)
+ })
+}
+
+//go:nosplit
+func acquireSudog() *sudog {
+ // Delicate dance: the semaphore implementation calls
+ // acquireSudog, acquireSudog calls new(sudog),
+ // new calls malloc, malloc can call the garbage collector,
+ // and the garbage collector calls the semaphore implementation
+ // in stopTheWorld.
+ // Break the cycle by doing acquirem/releasem around new(sudog).
+ // The acquirem/releasem increments m.locks during new(sudog),
+ // which keeps the garbage collector from being invoked.
+ mp := acquirem()
+ pp := mp.p.ptr()
+ if len(pp.sudogcache) == 0 {
+ lock(&sched.sudoglock)
+ // First, try to grab a batch from central cache.
+ for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
+ s := sched.sudogcache
+ sched.sudogcache = s.next
+ s.next = nil
+ pp.sudogcache = append(pp.sudogcache, s)
+ }
+ unlock(&sched.sudoglock)
+ // If the central cache is empty, allocate a new one.
+ if len(pp.sudogcache) == 0 {
+ pp.sudogcache = append(pp.sudogcache, new(sudog))
+ }
+ }
+ n := len(pp.sudogcache)
+ s := pp.sudogcache[n-1]
+ pp.sudogcache[n-1] = nil
+ pp.sudogcache = pp.sudogcache[:n-1]
+ if s.elem != nil {
+ throw("acquireSudog: found s.elem != nil in cache")
+ }
+ releasem(mp)
+ return s
+}
+
+//go:nosplit
+func releaseSudog(s *sudog) {
+ if s.elem != nil {
+ throw("runtime: sudog with non-nil elem")
+ }
+ if s.selectdone != nil {
+ throw("runtime: sudog with non-nil selectdone")
+ }
+ if s.next != nil {
+ throw("runtime: sudog with non-nil next")
+ }
+ if s.prev != nil {
+ throw("runtime: sudog with non-nil prev")
+ }
+ if s.waitlink != nil {
+ throw("runtime: sudog with non-nil waitlink")
+ }
+ if s.c != nil {
+ throw("runtime: sudog with non-nil c")
+ }
+ gp := getg()
+ if gp.param != nil {
+ throw("runtime: releaseSudog with non-nil gp.param")
+ }
+ mp := acquirem() // avoid rescheduling to another P
+ pp := mp.p.ptr()
+ if len(pp.sudogcache) == cap(pp.sudogcache) {
+ // Transfer half of local cache to the central cache.
+ var first, last *sudog
+ for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
+ n := len(pp.sudogcache)
+ p := pp.sudogcache[n-1]
+ pp.sudogcache[n-1] = nil
+ pp.sudogcache = pp.sudogcache[:n-1]
+ if first == nil {
+ first = p
+ } else {
+ last.next = p
+ }
+ last = p
+ }
+ lock(&sched.sudoglock)
+ last.next = sched.sudogcache
+ sched.sudogcache = first
+ unlock(&sched.sudoglock)
+ }
+ pp.sudogcache = append(pp.sudogcache, s)
+ releasem(mp)
+}
+
+// funcPC returns the entry PC of the function f.
+// It assumes that f is a func value. Otherwise the behavior is undefined.
+// For gccgo here unless and until we port proc.go.
+// Note that this differs from the gc implementation; the gc implementation
+// adds sys.PtrSize to the address of the interface value, but GCC's
+// alias analysis decides that that can not be a reference to the second
+// field of the interface, and in some cases it drops the initialization
+// of the second field as a dead store.
+//go:nosplit
+func funcPC(f interface{}) uintptr {
+ i := (*iface)(unsafe.Pointer(&f))
+ return **(**uintptr)(i.data)
+}
+
+func lockedOSThread() bool {
+ gp := getg()
+ return gp.lockedm != nil && gp.m.lockedg != nil
+}
+
+var (
+ allgs []*g
+ allglock mutex
+)
+
+func allgadd(gp *g) {
+ if readgstatus(gp) == _Gidle {
+ throw("allgadd: bad status Gidle")
+ }
+
+ lock(&allglock)
+ allgs = append(allgs, gp)
+ allglen = uintptr(len(allgs))
+
+ // Grow GC rescan list if necessary.
+ if len(allgs) > cap(work.rescan.list) {
+ lock(&work.rescan.lock)
+ l := work.rescan.list
+ // Let append do the heavy lifting, but keep the
+ // length the same.
+ work.rescan.list = append(l[:cap(l)], 0)[:len(l)]
+ unlock(&work.rescan.lock)
+ }
+ unlock(&allglock)
+}
+
+func dumpgstatus(gp *g) {
+ _g_ := getg()
+ print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+ print("runtime: g: g=", _g_, ", goid=", _g_.goid, ", g->atomicstatus=", readgstatus(_g_), "\n")
+}
+
+func checkmcount() {
+ // sched lock is held
+ if sched.mcount > sched.maxmcount {
+ print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n")
+ throw("thread exhaustion")
+ }
+}
+
+func mcommoninit(mp *m) {
+ _g_ := getg()
+
+ // g0 stack won't make sense for user (and is not necessary unwindable).
+ if _g_ != _g_.m.g0 {
+ callers(1, mp.createstack[:])
+ }
+
+ mp.fastrand = 0x49f6428a + uint32(mp.id) + uint32(cputicks())
+ if mp.fastrand == 0 {
+ mp.fastrand = 0x49f6428a
+ }
+
+ lock(&sched.lock)
+ mp.id = sched.mcount
+ sched.mcount++
+ checkmcount()
+ mpreinit(mp)
+
+ // Add to allm so garbage collector doesn't free g->m
+ // when it is just in a register or thread-local storage.
+ mp.alllink = allm
+
+ // NumCgoCall() iterates over allm w/o schedlock,
+ // so we need to publish it safely.
+ atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))
+ unlock(&sched.lock)
+}
+
+// Mark gp ready to run.
+func ready(gp *g, traceskip int, next bool) {
+ if trace.enabled {
+ traceGoUnpark(gp, traceskip)
+ }
+
+ status := readgstatus(gp)
+
+ // Mark runnable.
+ _g_ := getg()
+ _g_.m.locks++ // disable preemption because it can be holding p in a local var
+ if status&^_Gscan != _Gwaiting {
+ dumpgstatus(gp)
+ throw("bad g->status in ready")
+ }
+
+ // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ runqput(_g_.m.p.ptr(), gp, next)
+ if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
+ wakep()
+ }
+ _g_.m.locks--
+}
+
+func gcprocs() int32 {
+ // Figure out how many CPUs to use during GC.
+ // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+ lock(&sched.lock)
+ n := gomaxprocs
+ if n > ncpu {
+ n = ncpu
+ }
+ if n > _MaxGcproc {
+ n = _MaxGcproc
+ }
+ if n > sched.nmidle+1 { // one M is currently running
+ n = sched.nmidle + 1
+ }
+ unlock(&sched.lock)
+ return n
+}
+
+func needaddgcproc() bool {
+ lock(&sched.lock)
+ n := gomaxprocs
+ if n > ncpu {
+ n = ncpu
+ }
+ if n > _MaxGcproc {
+ n = _MaxGcproc
+ }
+ n -= sched.nmidle + 1 // one M is currently running
+ unlock(&sched.lock)
+ return n > 0
+}
+
+func helpgc(nproc int32) {
+ _g_ := getg()
+ lock(&sched.lock)
+ pos := 0
+ for n := int32(1); n < nproc; n++ { // one M is currently running
+ if allp[pos].mcache == _g_.m.mcache {
+ pos++
+ }
+ mp := mget()
+ if mp == nil {
+ throw("gcprocs inconsistency")
+ }
+ mp.helpgc = n
+ mp.p.set(allp[pos])
+ mp.mcache = allp[pos].mcache
+ pos++
+ notewakeup(&mp.park)
+ }
+ unlock(&sched.lock)
+}
+
+// freezeStopWait is a large value that freezetheworld sets
+// sched.stopwait to in order to request that all Gs permanently stop.
+const freezeStopWait = 0x7fffffff
+
+// freezing is set to non-zero if the runtime is trying to freeze the
+// world.
+var freezing uint32
+
+// Similar to stopTheWorld but best-effort and can be called several times.
+// There is no reverse operation, used during crashing.
+// This function must not lock any mutexes.
+func freezetheworld() {
+ atomic.Store(&freezing, 1)
+ // stopwait and preemption requests can be lost
+ // due to races with concurrently executing threads,
+ // so try several times
+ for i := 0; i < 5; i++ {
+ // this should tell the scheduler to not start any new goroutines
+ sched.stopwait = freezeStopWait
+ atomic.Store(&sched.gcwaiting, 1)
+ // this should stop running goroutines
+ if !preemptall() {
+ break // no running goroutines
+ }
+ usleep(1000)
+ }
+ // to be sure
+ usleep(1000)
+ preemptall()
+ usleep(1000)
+}
+
+func isscanstatus(status uint32) bool {
+ if status == _Gscan {
+ throw("isscanstatus: Bad status Gscan")
+ }
+ return status&_Gscan == _Gscan
+}
+
+// All reads and writes of g's status go through readgstatus, casgstatus
+// castogscanstatus, casfrom_Gscanstatus.
+//go:nosplit
+func readgstatus(gp *g) uint32 {
+ return atomic.Load(&gp.atomicstatus)
+}
+
+// Ownership of gcscanvalid:
+//
+// If gp is running (meaning status == _Grunning or _Grunning|_Gscan),
+// then gp owns gp.gcscanvalid, and other goroutines must not modify it.
+//
+// Otherwise, a second goroutine can lock the scan state by setting _Gscan
+// in the status bit and then modify gcscanvalid, and then unlock the scan state.
+//
+// Note that the first condition implies an exception to the second:
+// if a second goroutine changes gp's status to _Grunning|_Gscan,
+// that second goroutine still does not have the right to modify gcscanvalid.
+
+// The Gscanstatuses are acting like locks and this releases them.
+// If it proves to be a performance hit we should be able to make these
+// simple atomic stores but for now we are going to throw if
+// we see an inconsistent state.
+func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
+ success := false
+
+ // Check that transition is valid.
+ switch oldval {
+ default:
+ print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+ dumpgstatus(gp)
+ throw("casfrom_Gscanstatus:top gp->status is not in scan state")
+ case _Gscanrunnable,
+ _Gscanwaiting,
+ _Gscanrunning,
+ _Gscansyscall:
+ if newval == oldval&^_Gscan {
+ success = atomic.Cas(&gp.atomicstatus, oldval, newval)
+ }
+ }
+ if !success {
+ print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+ dumpgstatus(gp)
+ throw("casfrom_Gscanstatus: gp->status is not in scan state")
+ }
+}
+
+// This will return false if the gp is not in the expected status and the cas fails.
+// This acts like a lock acquire while the casfromgstatus acts like a lock release.
+func castogscanstatus(gp *g, oldval, newval uint32) bool {
+ switch oldval {
+ case _Grunnable,
+ _Grunning,
+ _Gwaiting,
+ _Gsyscall:
+ if newval == oldval|_Gscan {
+ return atomic.Cas(&gp.atomicstatus, oldval, newval)
+ }
+ }
+ print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
+ throw("castogscanstatus")
+ panic("not reached")
+}
+
+// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
+// and casfrom_Gscanstatus instead.
+// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that
+// put it in the Gscan state is finished.
+//go:nosplit
+func casgstatus(gp *g, oldval, newval uint32) {
+ if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval {
+ systemstack(func() {
+ print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")
+ throw("casgstatus: bad incoming values")
+ })
+ }
+
+ if oldval == _Grunning && gp.gcscanvalid {
+ // If oldvall == _Grunning, then the actual status must be
+ // _Grunning or _Grunning|_Gscan; either way,
+ // we own gp.gcscanvalid, so it's safe to read.
+ // gp.gcscanvalid must not be true when we are running.
+ print("runtime: casgstatus ", hex(oldval), "->", hex(newval), " gp.status=", hex(gp.atomicstatus), " gp.gcscanvalid=true\n")
+ throw("casgstatus")
+ }
+
+ // See http://golang.org/cl/21503 for justification of the yield delay.
+ const yieldDelay = 5 * 1000
+ var nextYield int64
+
+ // loop if gp->atomicstatus is in a scan state giving
+ // GC time to finish and change the state to oldval.
+ for i := 0; !atomic.Cas(&gp.atomicstatus, oldval, newval); i++ {
+ if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
+ systemstack(func() {
+ throw("casgstatus: waiting for Gwaiting but is Grunnable")
+ })
+ }
+ // Help GC if needed.
+ // if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
+ // gp.preemptscan = false
+ // systemstack(func() {
+ // gcphasework(gp)
+ // })
+ // }
+ // But meanwhile just yield.
+ if i == 0 {
+ nextYield = nanotime() + yieldDelay
+ }
+ if nanotime() < nextYield {
+ for x := 0; x < 10 && gp.atomicstatus != oldval; x++ {
+ procyield(1)
+ }
+ } else {
+ osyield()
+ nextYield = nanotime() + yieldDelay/2
+ }
+ }
+ if newval == _Grunning && gp.gcscanvalid {
+ // Run queueRescan on the system stack so it has more space.
+ systemstack(func() { queueRescan(gp) })
+ }
+}
+
+// stopTheWorld stops all P's from executing goroutines, interrupting
+// all goroutines at GC safe points and records reason as the reason
+// for the stop. On return, only the current goroutine's P is running.
+// stopTheWorld must not be called from a system stack and the caller
+// must not hold worldsema. The caller must call startTheWorld when
+// other P's should resume execution.
+//
+// stopTheWorld is safe for multiple goroutines to call at the
+// same time. Each will execute its own stop, and the stops will
+// be serialized.
+//
+// This is also used by routines that do stack dumps. If the system is
+// in panic or being exited, this may not reliably stop all
+// goroutines.
+func stopTheWorld(reason string) {
+ semacquire(&worldsema, 0)
+ getg().m.preemptoff = reason
+ systemstack(stopTheWorldWithSema)
+}
+
+// startTheWorld undoes the effects of stopTheWorld.
+func startTheWorld() {
+ systemstack(startTheWorldWithSema)
+ // worldsema must be held over startTheWorldWithSema to ensure
+ // gomaxprocs cannot change while worldsema is held.
+ semrelease(&worldsema)
+ getg().m.preemptoff = ""
+}
+
+// Holding worldsema grants an M the right to try to stop the world
+// and prevents gomaxprocs from changing concurrently.
+var worldsema uint32 = 1
+
+// stopTheWorldWithSema is the core implementation of stopTheWorld.
+// The caller is responsible for acquiring worldsema and disabling
+// preemption first and then should stopTheWorldWithSema on the system
+// stack:
+//
+// semacquire(&worldsema, 0)
+// m.preemptoff = "reason"
+// systemstack(stopTheWorldWithSema)
+//
+// When finished, the caller must either call startTheWorld or undo
+// these three operations separately:
+//
+// m.preemptoff = ""
+// systemstack(startTheWorldWithSema)
+// semrelease(&worldsema)
+//
+// It is allowed to acquire worldsema once and then execute multiple
+// startTheWorldWithSema/stopTheWorldWithSema pairs.
+// Other P's are able to execute between successive calls to
+// startTheWorldWithSema and stopTheWorldWithSema.
+// Holding worldsema causes any other goroutines invoking
+// stopTheWorld to block.
+func stopTheWorldWithSema() {
+ _g_ := getg()
+
+ // If we hold a lock, then we won't be able to stop another M
+ // that is blocked trying to acquire the lock.
+ if _g_.m.locks > 0 {
+ throw("stopTheWorld: holding locks")
+ }
+
+ lock(&sched.lock)
+ sched.stopwait = gomaxprocs
+ atomic.Store(&sched.gcwaiting, 1)
+ preemptall()
+ // stop current P
+ _g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic.
+ sched.stopwait--
+ // try to retake all P's in Psyscall status
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ s := p.status
+ if s == _Psyscall && atomic.Cas(&p.status, s, _Pgcstop) {
+ if trace.enabled {
+ traceGoSysBlock(p)
+ traceProcStop(p)
+ }
+ p.syscalltick++
+ sched.stopwait--
+ }
+ }
+ // stop idle P's
+ for {
+ p := pidleget()
+ if p == nil {
+ break
+ }
+ p.status = _Pgcstop
+ sched.stopwait--
+ }
+ wait := sched.stopwait > 0
+ unlock(&sched.lock)
+
+ // wait for remaining P's to stop voluntarily
+ if wait {
+ for {
+ // wait for 100us, then try to re-preempt in case of any races
+ if notetsleep(&sched.stopnote, 100*1000) {
+ noteclear(&sched.stopnote)
+ break
+ }
+ preemptall()
+ }
+ }
+
+ // sanity checks
+ bad := ""
+ if sched.stopwait != 0 {
+ bad = "stopTheWorld: not stopped (stopwait != 0)"
+ } else {
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ if p.status != _Pgcstop {
+ bad = "stopTheWorld: not stopped (status != _Pgcstop)"
+ }
+ }
+ }
+ if atomic.Load(&freezing) != 0 {
+ // Some other thread is panicking. This can cause the
+ // sanity checks above to fail if the panic happens in
+ // the signal handler on a stopped thread. Either way,
+ // we should halt this thread.
+ lock(&deadlock)
+ lock(&deadlock)
+ }
+ if bad != "" {
+ throw(bad)
+ }
+}
+
+func mhelpgc() {
+ _g_ := getg()
+ _g_.m.helpgc = -1
+}
+
+func startTheWorldWithSema() {
+ _g_ := getg()
+
+ _g_.m.locks++ // disable preemption because it can be holding p in a local var
+ gp := netpoll(false) // non-blocking
+ injectglist(gp)
+ add := needaddgcproc()
+ lock(&sched.lock)
+
+ procs := gomaxprocs
+ if newprocs != 0 {
+ procs = newprocs
+ newprocs = 0
+ }
+ p1 := procresize(procs)
+ sched.gcwaiting = 0
+ if sched.sysmonwait != 0 {
+ sched.sysmonwait = 0
+ notewakeup(&sched.sysmonnote)
+ }
+ unlock(&sched.lock)
+
+ for p1 != nil {
+ p := p1
+ p1 = p1.link.ptr()
+ if p.m != 0 {
+ mp := p.m.ptr()
+ p.m = 0
+ if mp.nextp != 0 {
+ throw("startTheWorld: inconsistent mp->nextp")
+ }
+ mp.nextp.set(p)
+ notewakeup(&mp.park)
+ } else {
+ // Start M to run P. Do not start another M below.
+ newm(nil, p)
+ add = false
+ }
+ }
+
+ // Wakeup an additional proc in case we have excessive runnable goroutines
+ // in local queues or in the global queue. If we don't, the proc will park itself.
+ // If we have lots of excessive work, resetspinning will unpark additional procs as necessary.
+ if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
+ wakep()
+ }
+
+ if add {
+ // If GC could have used another helper proc, start one now,
+ // in the hope that it will be available next time.
+ // It would have been even better to start it before the collection,
+ // but doing so requires allocating memory, so it's tricky to
+ // coordinate. This lazy approach works out in practice:
+ // we don't mind if the first couple gc rounds don't have quite
+ // the maximum number of procs.
+ newm(unsafe.Pointer(funcPC(mhelpgc)), nil)
+ }
+ _g_.m.locks--
+}
+
+// forEachP calls fn(p) for every P p when p reaches a GC safe point.
+// If a P is currently executing code, this will bring the P to a GC
+// safe point and execute fn on that P. If the P is not executing code
+// (it is idle or in a syscall), this will call fn(p) directly while
+// preventing the P from exiting its state. This does not ensure that
+// fn will run on every CPU executing Go code, but it acts as a global
+// memory barrier. GC uses this as a "ragged barrier."
+//
+// The caller must hold worldsema.
+//
+//go:systemstack
+func forEachP(fn func(*p)) {
+ mp := acquirem()
+ _p_ := getg().m.p.ptr()
+
+ lock(&sched.lock)
+ if sched.safePointWait != 0 {
+ throw("forEachP: sched.safePointWait != 0")
+ }
+ sched.safePointWait = gomaxprocs - 1
+ sched.safePointFn = fn
+
+ // Ask all Ps to run the safe point function.
+ for _, p := range allp[:gomaxprocs] {
+ if p != _p_ {
+ atomic.Store(&p.runSafePointFn, 1)
+ }
+ }
+ preemptall()
+
+ // Any P entering _Pidle or _Psyscall from now on will observe
+ // p.runSafePointFn == 1 and will call runSafePointFn when
+ // changing its status to _Pidle/_Psyscall.
+
+ // Run safe point function for all idle Ps. sched.pidle will
+ // not change because we hold sched.lock.
+ for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
+ if atomic.Cas(&p.runSafePointFn, 1, 0) {
+ fn(p)
+ sched.safePointWait--
+ }
+ }
+
+ wait := sched.safePointWait > 0
+ unlock(&sched.lock)
+
+ // Run fn for the current P.
+ fn(_p_)
+
+ // Force Ps currently in _Psyscall into _Pidle and hand them
+ // off to induce safe point function execution.
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ s := p.status
+ if s == _Psyscall && p.runSafePointFn == 1 && atomic.Cas(&p.status, s, _Pidle) {
+ if trace.enabled {
+ traceGoSysBlock(p)
+ traceProcStop(p)
+ }
+ p.syscalltick++
+ handoffp(p)
+ }
+ }
+
+ // Wait for remaining Ps to run fn.
+ if wait {
+ for {
+ // Wait for 100us, then try to re-preempt in
+ // case of any races.
+ //
+ // Requires system stack.
+ if notetsleep(&sched.safePointNote, 100*1000) {
+ noteclear(&sched.safePointNote)
+ break
+ }
+ preemptall()
+ }
+ }
+ if sched.safePointWait != 0 {
+ throw("forEachP: not done")
+ }
+ for i := 0; i < int(gomaxprocs); i++ {
+ p := allp[i]
+ if p.runSafePointFn != 0 {
+ throw("forEachP: P did not run fn")
+ }
+ }
+
+ lock(&sched.lock)
+ sched.safePointFn = nil
+ unlock(&sched.lock)
+ releasem(mp)
+}
+
+// runSafePointFn runs the safe point function, if any, for this P.
+// This should be called like
+//
+// if getg().m.p.runSafePointFn != 0 {
+// runSafePointFn()
+// }
+//
+// runSafePointFn must be checked on any transition in to _Pidle or
+// _Psyscall to avoid a race where forEachP sees that the P is running
+// just before the P goes into _Pidle/_Psyscall and neither forEachP
+// nor the P run the safe-point function.
+func runSafePointFn() {
+ p := getg().m.p.ptr()
+ // Resolve the race between forEachP running the safe-point
+ // function on this P's behalf and this P running the
+ // safe-point function directly.
+ if !atomic.Cas(&p.runSafePointFn, 1, 0) {
+ return
+ }
+ sched.safePointFn(p)
+ lock(&sched.lock)
+ sched.safePointWait--
+ if sched.safePointWait == 0 {
+ notewakeup(&sched.safePointNote)
+ }
+ unlock(&sched.lock)
+}
+
+// needm is called when a cgo callback happens on a
+// thread without an m (a thread not created by Go).
+// In this case, needm is expected to find an m to use
+// and return with m, g initialized correctly.
+// Since m and g are not set now (likely nil, but see below)
+// needm is limited in what routines it can call. In particular
+// it can only call nosplit functions (textflag 7) and cannot
+// do any scheduling that requires an m.
+//
+// In order to avoid needing heavy lifting here, we adopt
+// the following strategy: there is a stack of available m's
+// that can be stolen. Using compare-and-swap
+// to pop from the stack has ABA races, so we simulate
+// a lock by doing an exchange (via casp) to steal the stack
+// head and replace the top pointer with MLOCKED (1).
+// This serves as a simple spin lock that we can use even
+// without an m. The thread that locks the stack in this way
+// unlocks the stack by storing a valid stack head pointer.
+//
+// In order to make sure that there is always an m structure
+// available to be stolen, we maintain the invariant that there
+// is always one more than needed. At the beginning of the
+// program (if cgo is in use) the list is seeded with a single m.
+// If needm finds that it has taken the last m off the list, its job
+// is - once it has installed its own m so that it can do things like
+// allocate memory - to create a spare m and put it on the list.
+//
+// Each of these extra m's also has a g0 and a curg that are
+// pressed into service as the scheduling stack and current
+// goroutine for the duration of the cgo callback.
+//
+// When the callback is done with the m, it calls dropm to
+// put the m back on the list.
+//go:nosplit
+func needm(x byte) {
+ if iscgo && !cgoHasExtraM {
+ // Can happen if C/C++ code calls Go from a global ctor.
+ // Can not throw, because scheduler is not initialized yet.
+ write(2, unsafe.Pointer(&earlycgocallback[0]), int32(len(earlycgocallback)))
+ exit(1)
+ }
+
+ // Lock extra list, take head, unlock popped list.
+ // nilokay=false is safe here because of the invariant above,
+ // that the extra list always contains or will soon contain
+ // at least one m.
+ mp := lockextra(false)
+
+ // Set needextram when we've just emptied the list,
+ // so that the eventual call into cgocallbackg will
+ // allocate a new m for the extra list. We delay the
+ // allocation until then so that it can be done
+ // after exitsyscall makes sure it is okay to be
+ // running at all (that is, there's no garbage collection
+ // running right now).
+ mp.needextram = mp.schedlink == 0
+ unlockextra(mp.schedlink.ptr())
+
+ // Save and block signals before installing g.
+ // Once g is installed, any incoming signals will try to execute,
+ // but we won't have the sigaltstack settings and other data
+ // set up appropriately until the end of minit, which will
+ // unblock the signals. This is the same dance as when
+ // starting a new m to run Go code via newosproc.
+ msigsave(mp)
+ sigblock()
+
+ // Install g (= m->curg).
+ setg(mp.curg)
+ atomic.Store(&mp.curg.atomicstatus, _Gsyscall)
+ setGContext()
+
+ // Initialize this thread to use the m.
+ minit()
+}
+
+var earlycgocallback = []byte("fatal error: cgo callback before cgo call\n")
+
+// newextram allocates m's and puts them on the extra list.
+// It is called with a working local m, so that it can do things
+// like call schedlock and allocate.
+func newextram() {
+ c := atomic.Xchg(&extraMWaiters, 0)
+ if c > 0 {
+ for i := uint32(0); i < c; i++ {
+ oneNewExtraM()
+ }
+ } else {
+ // Make sure there is at least one extra M.
+ mp := lockextra(true)
+ unlockextra(mp)
+ if mp == nil {
+ oneNewExtraM()
+ }
+ }
+}
+
+// oneNewExtraM allocates an m and puts it on the extra list.
+func oneNewExtraM() {
+ // Create extra goroutine locked to extra m.
+ // The goroutine is the context in which the cgo callback will run.
+ // The sched.pc will never be returned to, but setting it to
+ // goexit makes clear to the traceback routines where
+ // the goroutine stack ends.
+ var g0SP unsafe.Pointer
+ var g0SPSize uintptr
+ mp := allocm(nil, true, &g0SP, &g0SPSize)
+ gp := malg(true, false, nil, nil)
+ gp.gcscanvalid = true // fresh G, so no dequeueRescan necessary
+ gp.gcscandone = true
+ gp.gcRescan = -1
+
+ // malg returns status as Gidle, change to Gdead before adding to allg
+ // where GC will see it.
+ // gccgo uses Gdead here, not Gsyscall, because the split
+ // stack context is not initialized.
+ casgstatus(gp, _Gidle, _Gdead)
+ gp.m = mp
+ mp.curg = gp
+ mp.locked = _LockInternal
+ mp.lockedg = gp
+ gp.lockedm = mp
+ gp.goid = int64(atomic.Xadd64(&sched.goidgen, 1))
+ // put on allg for garbage collector
+ allgadd(gp)
+
+ // The context for gp will be set up in needm.
+ // Here we need to set the context for g0.
+ makeGContext(mp.g0, g0SP, g0SPSize)
+
+ // Add m to the extra list.
+ mnext := lockextra(true)
+ mp.schedlink.set(mnext)
+ unlockextra(mp)
+}
+
+// dropm is called when a cgo callback has called needm but is now
+// done with the callback and returning back into the non-Go thread.
+// It puts the current m back onto the extra list.
+//
+// The main expense here is the call to signalstack to release the
+// m's signal stack, and then the call to needm on the next callback
+// from this thread. It is tempting to try to save the m for next time,
+// which would eliminate both these costs, but there might not be
+// a next time: the current thread (which Go does not control) might exit.
+// If we saved the m for that thread, there would be an m leak each time
+// such a thread exited. Instead, we acquire and release an m on each
+// call. These should typically not be scheduling operations, just a few
+// atomics, so the cost should be small.
+//
+// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
+// variable using pthread_key_create. Unlike the pthread keys we already use
+// on OS X, this dummy key would never be read by Go code. It would exist
+// only so that we could register at thread-exit-time destructor.
+// That destructor would put the m back onto the extra list.
+// This is purely a performance optimization. The current version,
+// in which dropm happens on each cgo call, is still correct too.
+// We may have to keep the current version on systems with cgo
+// but without pthreads, like Windows.
+func dropm() {
+ // Clear m and g, and return m to the extra list.
+ // After the call to setg we can only call nosplit functions
+ // with no pointer manipulation.
+ mp := getg().m
+
+ // Block signals before unminit.
+ // Unminit unregisters the signal handling stack (but needs g on some systems).
+ // Setg(nil) clears g, which is the signal handler's cue not to run Go handlers.
+ // It's important not to try to handle a signal between those two steps.
+ sigmask := mp.sigmask
+ sigblock()
+ unminit()
+
+ // gccgo sets the stack to Gdead here, because the splitstack
+ // context is not initialized.
+ mp.curg.atomicstatus = _Gdead
+ mp.curg.gcstack = nil
+ mp.curg.gcnextsp = nil
+
+ mnext := lockextra(true)
+ mp.schedlink.set(mnext)
+
+ setg(nil)
+
+ // Commit the release of mp.
+ unlockextra(mp)
+
+ msigrestore(sigmask)
+}
+
+// A helper function for EnsureDropM.
+func getm() uintptr {
+ return uintptr(unsafe.Pointer(getg().m))
+}
+
+var extram uintptr
+var extraMWaiters uint32
+
+// lockextra locks the extra list and returns the list head.
+// The caller must unlock the list by storing a new list head
+// to extram. If nilokay is true, then lockextra will
+// return a nil list head if that's what it finds. If nilokay is false,
+// lockextra will keep waiting until the list head is no longer nil.
+//go:nosplit
+func lockextra(nilokay bool) *m {
+ const locked = 1
+
+ incr := false
+ for {
+ old := atomic.Loaduintptr(&extram)
+ if old == locked {
+ yield := osyield
+ yield()
+ continue
+ }
+ if old == 0 && !nilokay {
+ if !incr {
+ // Add 1 to the number of threads
+ // waiting for an M.
+ // This is cleared by newextram.
+ atomic.Xadd(&extraMWaiters, 1)
+ incr = true
+ }
+ usleep(1)
+ continue
+ }
+ if atomic.Casuintptr(&extram, old, locked) {
+ return (*m)(unsafe.Pointer(old))
+ }
+ yield := osyield
+ yield()
+ continue
+ }
+}
+
+//go:nosplit
+func unlockextra(mp *m) {
+ atomic.Storeuintptr(&extram, uintptr(unsafe.Pointer(mp)))
+}
+
+// Stops execution of the current m until new work is available.
+// Returns with acquired P.
+func stopm() {
+ _g_ := getg()
+
+ if _g_.m.locks != 0 {
+ throw("stopm holding locks")
+ }
+ if _g_.m.p != 0 {
+ throw("stopm holding p")
+ }
+ if _g_.m.spinning {
+ throw("stopm spinning")
+ }
+
+retry:
+ lock(&sched.lock)
+ mput(_g_.m)
+ unlock(&sched.lock)
+ notesleep(&_g_.m.park)
+ noteclear(&_g_.m.park)
+ if _g_.m.helpgc != 0 {
+ gchelper()
+ _g_.m.helpgc = 0
+ _g_.m.mcache = nil
+ _g_.m.p = 0
+ goto retry
+ }
+ acquirep(_g_.m.nextp.ptr())
+ _g_.m.nextp = 0
+}
+
+// Hands off P from syscall or locked M.
+// Always runs without a P, so write barriers are not allowed.
+//go:nowritebarrierrec
+func handoffp(_p_ *p) {
+ // handoffp must start an M in any situation where
+ // findrunnable would return a G to run on _p_.
+
+ // if it has local work, start it straight away
+ if !runqempty(_p_) || sched.runqsize != 0 {
+ startm(_p_, false)
+ return
+ }
+ // if it has GC work, start it straight away
+ if gcBlackenEnabled != 0 && gcMarkWorkAvailable(_p_) {
+ startm(_p_, false)
+ return
+ }
+ // no local work, check that there are no spinning/idle M's,
+ // otherwise our help is not required
+ if atomic.Load(&sched.nmspinning)+atomic.Load(&sched.npidle) == 0 && atomic.Cas(&sched.nmspinning, 0, 1) { // TODO: fast atomic
+ startm(_p_, true)
+ return
+ }
+ lock(&sched.lock)
+ if sched.gcwaiting != 0 {
+ _p_.status = _Pgcstop
+ sched.stopwait--
+ if sched.stopwait == 0 {
+ notewakeup(&sched.stopnote)
+ }
+ unlock(&sched.lock)
+ return
+ }
+ if _p_.runSafePointFn != 0 && atomic.Cas(&_p_.runSafePointFn, 1, 0) {
+ sched.safePointFn(_p_)
+ sched.safePointWait--
+ if sched.safePointWait == 0 {
+ notewakeup(&sched.safePointNote)
+ }
+ }
+ if sched.runqsize != 0 {
+ unlock(&sched.lock)
+ startm(_p_, false)
+ return
+ }
+ // If this is the last running P and nobody is polling network,
+ // need to wakeup another M to poll network.
+ if sched.npidle == uint32(gomaxprocs-1) && atomic.Load64(&sched.lastpoll) != 0 {
+ unlock(&sched.lock)
+ startm(_p_, false)
+ return
+ }
+ pidleput(_p_)
+ unlock(&sched.lock)
+}
+
+// Tries to add one more P to execute G's.
+// Called when a G is made runnable (newproc, ready).
+func wakep() {
+ // be conservative about spinning threads
+ if !atomic.Cas(&sched.nmspinning, 0, 1) {
+ return
+ }
+ startm(nil, true)
+}
+
+// Stops execution of the current m that is locked to a g until the g is runnable again.
+// Returns with acquired P.
+func stoplockedm() {
+ _g_ := getg()
+
+ if _g_.m.lockedg == nil || _g_.m.lockedg.lockedm != _g_.m {
+ throw("stoplockedm: inconsistent locking")
+ }
+ if _g_.m.p != 0 {
+ // Schedule another M to run this p.
+ _p_ := releasep()
+ handoffp(_p_)
+ }
+ incidlelocked(1)
+ // Wait until another thread schedules lockedg again.
+ notesleep(&_g_.m.park)
+ noteclear(&_g_.m.park)
+ status := readgstatus(_g_.m.lockedg)
+ if status&^_Gscan != _Grunnable {
+ print("runtime:stoplockedm: g is not Grunnable or Gscanrunnable\n")
+ dumpgstatus(_g_)
+ throw("stoplockedm: not runnable")
+ }
+ acquirep(_g_.m.nextp.ptr())
+ _g_.m.nextp = 0
+}
+
+// Schedules the locked m to run the locked gp.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func startlockedm(gp *g) {
+ _g_ := getg()
+
+ mp := gp.lockedm
+ if mp == _g_.m {
+ throw("startlockedm: locked to me")
+ }
+ if mp.nextp != 0 {
+ throw("startlockedm: m has p")
+ }
+ // directly handoff current P to the locked m
+ incidlelocked(-1)
+ _p_ := releasep()
+ mp.nextp.set(_p_)
+ notewakeup(&mp.park)
+ stopm()
+}
+
+// Stops the current m for stopTheWorld.
+// Returns when the world is restarted.
+func gcstopm() {
+ _g_ := getg()
+
+ if sched.gcwaiting == 0 {
+ throw("gcstopm: not waiting for gc")
+ }
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ // OK to just drop nmspinning here,
+ // startTheWorld will unpark threads as necessary.
+ if int32(atomic.Xadd(&sched.nmspinning, -1)) < 0 {
+ throw("gcstopm: negative nmspinning")
+ }
+ }
+ _p_ := releasep()
+ lock(&sched.lock)
+ _p_.status = _Pgcstop
+ sched.stopwait--
+ if sched.stopwait == 0 {
+ notewakeup(&sched.stopnote)
+ }
+ unlock(&sched.lock)
+ stopm()
+}
+
+// Schedules gp to run on the current M.
+// If inheritTime is true, gp inherits the remaining time in the
+// current time slice. Otherwise, it starts a new time slice.
+// Never returns.
+//
+// Write barriers are allowed because this is called immediately after
+// acquiring a P in several places.
+//
+//go:yeswritebarrierrec
+func execute(gp *g, inheritTime bool) {
+ _g_ := getg()
+
+ casgstatus(gp, _Grunnable, _Grunning)
+ gp.waitsince = 0
+ gp.preempt = false
+ if !inheritTime {
+ _g_.m.p.ptr().schedtick++
+ }
+ _g_.m.curg = gp
+ gp.m = _g_.m
+
+ // Check whether the profiler needs to be turned on or off.
+ hz := sched.profilehz
+ if _g_.m.profilehz != hz {
+ resetcpuprofiler(hz)
+ }
+
+ if trace.enabled {
+ // GoSysExit has to happen when we have a P, but before GoStart.
+ // So we emit it here.
+ if gp.syscallsp != 0 && gp.sysblocktraced {
+ traceGoSysExit(gp.sysexitticks)
+ }
+ traceGoStart()
+ }
+
+ gogo(gp)
+}
+
+// Finds a runnable goroutine to execute.
+// Tries to steal from other P's, get g from global queue, poll network.
+func findrunnable() (gp *g, inheritTime bool) {
+ _g_ := getg()
+
+ // The conditions here and in handoffp must agree: if
+ // findrunnable would return a G to run, handoffp must start
+ // an M.
+
+top:
+ _p_ := _g_.m.p.ptr()
+ if sched.gcwaiting != 0 {
+ gcstopm()
+ goto top
+ }
+ if _p_.runSafePointFn != 0 {
+ runSafePointFn()
+ }
+ if getfingwait() && getfingwake() {
+ if gp := wakefing(); gp != nil {
+ ready(gp, 0, true)
+ }
+ }
+
+ // local runq
+ if gp, inheritTime := runqget(_p_); gp != nil {
+ return gp, inheritTime
+ }
+
+ // global runq
+ if sched.runqsize != 0 {
+ lock(&sched.lock)
+ gp := globrunqget(_p_, 0)
+ unlock(&sched.lock)
+ if gp != nil {
+ return gp, false
+ }
+ }
+
+ // Poll network.
+ // This netpoll is only an optimization before we resort to stealing.
+ // We can safely skip it if there a thread blocked in netpoll already.
+ // If there is any kind of logical race with that blocked thread
+ // (e.g. it has already returned from netpoll, but does not set lastpoll yet),
+ // this thread will do blocking netpoll below anyway.
+ if netpollinited() && sched.lastpoll != 0 {
+ if gp := netpoll(false); gp != nil { // non-blocking
+ // netpoll returns list of goroutines linked by schedlink.
+ injectglist(gp.schedlink.ptr())
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ return gp, false
+ }
+ }
+
+ // Steal work from other P's.
+ procs := uint32(gomaxprocs)
+ if atomic.Load(&sched.npidle) == procs-1 {
+ // Either GOMAXPROCS=1 or everybody, except for us, is idle already.
+ // New work can appear from returning syscall/cgocall, network or timers.
+ // Neither of that submits to local run queues, so no point in stealing.
+ goto stop
+ }
+ // If number of spinning M's >= number of busy P's, block.
+ // This is necessary to prevent excessive CPU consumption
+ // when GOMAXPROCS>>1 but the program parallelism is low.
+ if !_g_.m.spinning && 2*atomic.Load(&sched.nmspinning) >= procs-atomic.Load(&sched.npidle) {
+ goto stop
+ }
+ if !_g_.m.spinning {
+ _g_.m.spinning = true
+ atomic.Xadd(&sched.nmspinning, 1)
+ }
+ for i := 0; i < 4; i++ {
+ for enum := stealOrder.start(fastrand()); !enum.done(); enum.next() {
+ if sched.gcwaiting != 0 {
+ goto top
+ }
+ stealRunNextG := i > 2 // first look for ready queues with more than 1 g
+ if gp := runqsteal(_p_, allp[enum.position()], stealRunNextG); gp != nil {
+ return gp, false
+ }
+ }
+ }
+
+stop:
+
+ // We have nothing to do. If we're in the GC mark phase, can
+ // safely scan and blacken objects, and have work to do, run
+ // idle-time marking rather than give up the P.
+ if gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != 0 && gcMarkWorkAvailable(_p_) {
+ _p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
+ gp := _p_.gcBgMarkWorker.ptr()
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ return gp, false
+ }
+
+ // return P and block
+ lock(&sched.lock)
+ if sched.gcwaiting != 0 || _p_.runSafePointFn != 0 {
+ unlock(&sched.lock)
+ goto top
+ }
+ if sched.runqsize != 0 {
+ gp := globrunqget(_p_, 0)
+ unlock(&sched.lock)
+ return gp, false
+ }
+ if releasep() != _p_ {
+ throw("findrunnable: wrong p")
+ }
+ pidleput(_p_)
+ unlock(&sched.lock)
+
+ // Delicate dance: thread transitions from spinning to non-spinning state,
+ // potentially concurrently with submission of new goroutines. We must
+ // drop nmspinning first and then check all per-P queues again (with
+ // #StoreLoad memory barrier in between). If we do it the other way around,
+ // another thread can submit a goroutine after we've checked all run queues
+ // but before we drop nmspinning; as the result nobody will unpark a thread
+ // to run the goroutine.
+ // If we discover new work below, we need to restore m.spinning as a signal
+ // for resetspinning to unpark a new worker thread (because there can be more
+ // than one starving goroutine). However, if after discovering new work
+ // we also observe no idle Ps, it is OK to just park the current thread:
+ // the system is fully loaded so no spinning threads are required.
+ // Also see "Worker thread parking/unparking" comment at the top of the file.
+ wasSpinning := _g_.m.spinning
+ if _g_.m.spinning {
+ _g_.m.spinning = false
+ if int32(atomic.Xadd(&sched.nmspinning, -1)) < 0 {
+ throw("findrunnable: negative nmspinning")
+ }
+ }
+
+ // check all runqueues once again
+ for i := 0; i < int(gomaxprocs); i++ {
+ _p_ := allp[i]
+ if _p_ != nil && !runqempty(_p_) {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ if wasSpinning {
+ _g_.m.spinning = true
+ atomic.Xadd(&sched.nmspinning, 1)
+ }
+ goto top
+ }
+ break
+ }
+ }
+
+ // Check for idle-priority GC work again.
+ if gcBlackenEnabled != 0 && gcMarkWorkAvailable(nil) {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ if _p_ != nil && _p_.gcBgMarkWorker == 0 {
+ pidleput(_p_)
+ _p_ = nil
+ }
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ if wasSpinning {
+ _g_.m.spinning = true
+ atomic.Xadd(&sched.nmspinning, 1)
+ }
+ // Go back to idle GC check.
+ goto stop
+ }
+ }
+
+ // poll network
+ if netpollinited() && atomic.Xchg64(&sched.lastpoll, 0) != 0 {
+ if _g_.m.p != 0 {
+ throw("findrunnable: netpoll with p")
+ }
+ if _g_.m.spinning {
+ throw("findrunnable: netpoll with spinning")
+ }
+ gp := netpoll(true) // block until new work is available
+ atomic.Store64(&sched.lastpoll, uint64(nanotime()))
+ if gp != nil {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ injectglist(gp.schedlink.ptr())
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ return gp, false
+ }
+ injectglist(gp)
+ }
+ }
+ stopm()
+ goto top
+}
+
+// pollWork returns true if there is non-background work this P could
+// be doing. This is a fairly lightweight check to be used for
+// background work loops, like idle GC. It checks a subset of the
+// conditions checked by the actual scheduler.
+func pollWork() bool {
+ if sched.runqsize != 0 {
+ return true
+ }
+ p := getg().m.p.ptr()
+ if !runqempty(p) {
+ return true
+ }
+ if netpollinited() && sched.lastpoll != 0 {
+ if gp := netpoll(false); gp != nil {
+ injectglist(gp)
+ return true
+ }
+ }
+ return false
+}
+
+func resetspinning() {
+ _g_ := getg()
+ if !_g_.m.spinning {
+ throw("resetspinning: not a spinning m")
+ }
+ _g_.m.spinning = false
+ nmspinning := atomic.Xadd(&sched.nmspinning, -1)
+ if int32(nmspinning) < 0 {
+ throw("findrunnable: negative nmspinning")
+ }
+ // M wakeup policy is deliberately somewhat conservative, so check if we
+ // need to wakeup another P here. See "Worker thread parking/unparking"
+ // comment at the top of the file for details.
+ if nmspinning == 0 && atomic.Load(&sched.npidle) > 0 {
+ wakep()
+ }
+}
+
+// Injects the list of runnable G's into the scheduler.
+// Can run concurrently with GC.
+func injectglist(glist *g) {
+ if glist == nil {
+ return
+ }
+ if trace.enabled {
+ for gp := glist; gp != nil; gp = gp.schedlink.ptr() {
+ traceGoUnpark(gp, 0)
+ }
+ }
+ lock(&sched.lock)
+ var n int
+ for n = 0; glist != nil; n++ {
+ gp := glist
+ glist = gp.schedlink.ptr()
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ globrunqput(gp)
+ }
+ unlock(&sched.lock)
+ for ; n != 0 && sched.npidle != 0; n-- {
+ startm(nil, false)
+ }
+}
+
+// One round of scheduler: find a runnable goroutine and execute it.
+// Never returns.
+func schedule() {
+ _g_ := getg()
+
+ if _g_.m.locks != 0 {
+ throw("schedule: holding locks")
+ }
+
+ if _g_.m.lockedg != nil {
+ stoplockedm()
+ execute(_g_.m.lockedg, false) // Never returns.
+ }
+
+top:
+ if sched.gcwaiting != 0 {
+ gcstopm()
+ goto top
+ }
+ if _g_.m.p.ptr().runSafePointFn != 0 {
+ runSafePointFn()
+ }
+
+ var gp *g
+ var inheritTime bool
+ if trace.enabled || trace.shutdown {
+ gp = traceReader()
+ if gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ traceGoUnpark(gp, 0)
+ }
+ }
+ if gp == nil && gcBlackenEnabled != 0 {
+ gp = gcController.findRunnableGCWorker(_g_.m.p.ptr())
+ }
+ if gp == nil {
+ // Check the global runnable queue once in a while to ensure fairness.
+ // Otherwise two goroutines can completely occupy the local runqueue
+ // by constantly respawning each other.
+ if _g_.m.p.ptr().schedtick%61 == 0 && sched.runqsize > 0 {
+ lock(&sched.lock)
+ gp = globrunqget(_g_.m.p.ptr(), 1)
+ unlock(&sched.lock)
+ }
+ }
+ if gp == nil {
+ gp, inheritTime = runqget(_g_.m.p.ptr())
+ if gp != nil && _g_.m.spinning {
+ throw("schedule: spinning with local work")
+ }
+
+ // Because gccgo does not implement preemption as a stack check,
+ // we need to check for preemption here for fairness.
+ // Otherwise goroutines on the local queue may starve
+ // goroutines on the global queue.
+ // Since we preempt by storing the goroutine on the global
+ // queue, this is the only place we need to check preempt.
+ if gp != nil && gp.preempt {
+ gp.preempt = false
+ lock(&sched.lock)
+ globrunqput(gp)
+ unlock(&sched.lock)
+ goto top
+ }
+ }
+ if gp == nil {
+ gp, inheritTime = findrunnable() // blocks until work is available
+ }
+
+ // This thread is going to run a goroutine and is not spinning anymore,
+ // so if it was marked as spinning we need to reset it now and potentially
+ // start a new spinning M.
+ if _g_.m.spinning {
+ resetspinning()
+ }
+
+ if gp.lockedm != nil {
+ // Hands off own p to the locked m,
+ // then blocks waiting for a new p.
+ startlockedm(gp)
+ goto top
+ }
+
+ execute(gp, inheritTime)
+}
+
+// dropg removes the association between m and the current goroutine m->curg (gp for short).
+// Typically a caller sets gp's status away from Grunning and then
+// immediately calls dropg to finish the job. The caller is also responsible
+// for arranging that gp will be restarted using ready at an
+// appropriate time. After calling dropg and arranging for gp to be
+// readied later, the caller can do other work but eventually should
+// call schedule to restart the scheduling of goroutines on this m.
+func dropg() {
+ _g_ := getg()
+
+ setMNoWB(&_g_.m.curg.m, nil)
+ setGNoWB(&_g_.m.curg, nil)
+}
+
+func beforefork() {
+ gp := getg().m.curg
+
+ // Fork can hang if preempted with signals frequently enough (see issue 5517).
+ // Ensure that we stay on the same M where we disable profiling.
+ gp.m.locks++
+ if gp.m.profilehz != 0 {
+ resetcpuprofiler(0)
+ }
+}
+
+// Called from syscall package before fork.
+//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork
+//go:nosplit
+func syscall_runtime_BeforeFork() {
+ systemstack(beforefork)
+}
+
+func afterfork() {
+ gp := getg().m.curg
+
+ hz := sched.profilehz
+ if hz != 0 {
+ resetcpuprofiler(hz)
+ }
+ gp.m.locks--
+}
+
+// Called from syscall package after fork in parent.
+//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork
+//go:nosplit
+func syscall_runtime_AfterFork() {
+ systemstack(afterfork)
+}
+
+// Put on gfree list.
+// If local list is too long, transfer a batch to the global list.
+func gfput(_p_ *p, gp *g) {
+ if readgstatus(gp) != _Gdead {
+ throw("gfput: bad status (not Gdead)")
+ }
+
+ gp.schedlink.set(_p_.gfree)
+ _p_.gfree = gp
+ _p_.gfreecnt++
+ if _p_.gfreecnt >= 64 {
+ lock(&sched.gflock)
+ for _p_.gfreecnt >= 32 {
+ _p_.gfreecnt--
+ gp = _p_.gfree
+ _p_.gfree = gp.schedlink.ptr()
+ gp.schedlink.set(sched.gfree)
+ sched.gfree = gp
+ sched.ngfree++
+ }
+ unlock(&sched.gflock)
+ }
+}
+
+// Get from gfree list.
+// If local list is empty, grab a batch from global list.
+func gfget(_p_ *p) *g {
+retry:
+ gp := _p_.gfree
+ if gp == nil && sched.gfree != nil {
+ lock(&sched.gflock)
+ for _p_.gfreecnt < 32 {
+ if sched.gfree != nil {
+ gp = sched.gfree
+ sched.gfree = gp.schedlink.ptr()
+ } else {
+ break
+ }
+ _p_.gfreecnt++
+ sched.ngfree--
+ gp.schedlink.set(_p_.gfree)
+ _p_.gfree = gp
+ }
+ unlock(&sched.gflock)
+ goto retry
+ }
+ if gp != nil {
+ _p_.gfree = gp.schedlink.ptr()
+ _p_.gfreecnt--
+ }
+ return gp
+}
+
+// Purge all cached G's from gfree list to the global list.
+func gfpurge(_p_ *p) {
+ lock(&sched.gflock)
+ for _p_.gfreecnt != 0 {
+ _p_.gfreecnt--
+ gp := _p_.gfree
+ _p_.gfree = gp.schedlink.ptr()
+ gp.schedlink.set(sched.gfree)
+ sched.gfree = gp
+ sched.ngfree++
+ }
+ unlock(&sched.gflock)
+}
+
+// dolockOSThread is called by LockOSThread and lockOSThread below
+// after they modify m.locked. Do not allow preemption during this call,
+// or else the m might be different in this function than in the caller.
+//go:nosplit
+func dolockOSThread() {
+ _g_ := getg()
+ _g_.m.lockedg = _g_
+ _g_.lockedm = _g_.m
+}
+
+//go:nosplit
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+func LockOSThread() {
+ getg().m.locked |= _LockExternal
+ dolockOSThread()
+}
+
+//go:nosplit
+func lockOSThread() {
+ getg().m.locked += _LockInternal
+ dolockOSThread()
+}
+
+// dounlockOSThread is called by UnlockOSThread and unlockOSThread below
+// after they update m->locked. Do not allow preemption during this call,
+// or else the m might be in different in this function than in the caller.
+//go:nosplit
+func dounlockOSThread() {
+ _g_ := getg()
+ if _g_.m.locked != 0 {
+ return
+ }
+ _g_.m.lockedg = nil
+ _g_.lockedm = nil
+}
+
+//go:nosplit
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread() {
+ getg().m.locked &^= _LockExternal
+ dounlockOSThread()
+}
+
+//go:nosplit
+func unlockOSThread() {
+ _g_ := getg()
+ if _g_.m.locked < _LockInternal {
+ systemstack(badunlockosthread)
+ }
+ _g_.m.locked -= _LockInternal
+ dounlockOSThread()
+}
+
+func badunlockosthread() {
+ throw("runtime: internal error: misuse of lockOSThread/unlockOSThread")
+}
+
+func gcount() int32 {
+ n := int32(allglen) - sched.ngfree - int32(atomic.Load(&sched.ngsys))
+ for i := 0; ; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ break
+ }
+ n -= _p_.gfreecnt
+ }
+
+ // All these variables can be changed concurrently, so the result can be inconsistent.
+ // But at least the current goroutine is running.
+ if n < 1 {
+ n = 1
+ }
+ return n
+}
+
+func mcount() int32 {
+ return sched.mcount
+}
+
+// Change number of processors. The world is stopped, sched is locked.
+// gcworkbufs are not being modified by either the GC or
+// the write barrier code.
+// Returns list of Ps with local work, they need to be scheduled by the caller.
+func procresize(nprocs int32) *p {
+ old := gomaxprocs
+ if old < 0 || old > _MaxGomaxprocs || nprocs <= 0 || nprocs > _MaxGomaxprocs {
+ throw("procresize: invalid arg")
+ }
+ if trace.enabled {
+ traceGomaxprocs(nprocs)
+ }
+
+ // update statistics
+ now := nanotime()
+ if sched.procresizetime != 0 {
+ sched.totaltime += int64(old) * (now - sched.procresizetime)
+ }
+ sched.procresizetime = now
+
+ // initialize new P's
+ for i := int32(0); i < nprocs; i++ {
+ pp := allp[i]
+ if pp == nil {
+ pp = new(p)
+ pp.id = i
+ pp.status = _Pgcstop
+ pp.sudogcache = pp.sudogbuf[:0]
+ pp.deferpool = pp.deferpoolbuf[:0]
+ atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
+ }
+ if pp.mcache == nil {
+ if old == 0 && i == 0 {
+ if getg().m.mcache == nil {
+ throw("missing mcache?")
+ }
+ pp.mcache = getg().m.mcache // bootstrap
+ } else {
+ pp.mcache = allocmcache()
+ }
+ }
+ }
+
+ // free unused P's
+ for i := nprocs; i < old; i++ {
+ p := allp[i]
+ if trace.enabled {
+ if p == getg().m.p.ptr() {
+ // moving to p[0], pretend that we were descheduled
+ // and then scheduled again to keep the trace sane.
+ traceGoSched()
+ traceProcStop(p)
+ }
+ }
+ // move all runnable goroutines to the global queue
+ for p.runqhead != p.runqtail {
+ // pop from tail of local queue
+ p.runqtail--
+ gp := p.runq[p.runqtail%uint32(len(p.runq))].ptr()
+ // push onto head of global queue
+ globrunqputhead(gp)
+ }
+ if p.runnext != 0 {
+ globrunqputhead(p.runnext.ptr())
+ p.runnext = 0
+ }
+ // if there's a background worker, make it runnable and put
+ // it on the global queue so it can clean itself up
+ if gp := p.gcBgMarkWorker.ptr(); gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ globrunqput(gp)
+ // This assignment doesn't race because the
+ // world is stopped.
+ p.gcBgMarkWorker.set(nil)
+ }
+ for i := range p.sudogbuf {
+ p.sudogbuf[i] = nil
+ }
+ p.sudogcache = p.sudogbuf[:0]
+ for i := range p.deferpoolbuf {
+ p.deferpoolbuf[i] = nil
+ }
+ p.deferpool = p.deferpoolbuf[:0]
+ freemcache(p.mcache)
+ p.mcache = nil
+ gfpurge(p)
+ traceProcFree(p)
+ p.status = _Pdead
+ // can't free P itself because it can be referenced by an M in syscall
+ }
+
+ _g_ := getg()
+ if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs {
+ // continue to use the current P
+ _g_.m.p.ptr().status = _Prunning
+ } else {
+ // release the current P and acquire allp[0]
+ if _g_.m.p != 0 {
+ _g_.m.p.ptr().m = 0
+ }
+ _g_.m.p = 0
+ _g_.m.mcache = nil
+ p := allp[0]
+ p.m = 0
+ p.status = _Pidle
+ acquirep(p)
+ if trace.enabled {
+ traceGoStart()
+ }
+ }
+ var runnablePs *p
+ for i := nprocs - 1; i >= 0; i-- {
+ p := allp[i]
+ if _g_.m.p.ptr() == p {
+ continue
+ }
+ p.status = _Pidle
+ if runqempty(p) {
+ pidleput(p)
+ } else {
+ p.m.set(mget())
+ p.link.set(runnablePs)
+ runnablePs = p
+ }
+ }
+ stealOrder.reset(uint32(nprocs))
+ var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32
+ atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
+ return runnablePs
+}
+
+// Associate p and the current m.
+//
+// This function is allowed to have write barriers even if the caller
+// isn't because it immediately acquires _p_.
+//
+//go:yeswritebarrierrec
+func acquirep(_p_ *p) {
+ // Do the part that isn't allowed to have write barriers.
+ acquirep1(_p_)
+
+ // have p; write barriers now allowed
+ _g_ := getg()
+ _g_.m.mcache = _p_.mcache
+
+ if trace.enabled {
+ traceProcStart()
+ }
+}
+
+// acquirep1 is the first step of acquirep, which actually acquires
+// _p_. This is broken out so we can disallow write barriers for this
+// part, since we don't yet have a P.
+//
+//go:nowritebarrierrec
+func acquirep1(_p_ *p) {
+ _g_ := getg()
+
+ if _g_.m.p != 0 || _g_.m.mcache != nil {
+ throw("acquirep: already in go")
+ }
+ if _p_.m != 0 || _p_.status != _Pidle {
+ id := int32(0)
+ if _p_.m != 0 {
+ id = _p_.m.ptr().id
+ }
+ print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
+ throw("acquirep: invalid p state")
+ }
+ _g_.m.p.set(_p_)
+ _p_.m.set(_g_.m)
+ _p_.status = _Prunning
+}
+
+// Disassociate p and the current m.
+func releasep() *p {
+ _g_ := getg()
+
+ if _g_.m.p == 0 || _g_.m.mcache == nil {
+ throw("releasep: invalid arg")
+ }
+ _p_ := _g_.m.p.ptr()
+ if _p_.m.ptr() != _g_.m || _p_.mcache != _g_.m.mcache || _p_.status != _Prunning {
+ print("releasep: m=", _g_.m, " m->p=", _g_.m.p.ptr(), " p->m=", _p_.m, " m->mcache=", _g_.m.mcache, " p->mcache=", _p_.mcache, " p->status=", _p_.status, "\n")
+ throw("releasep: invalid p state")
+ }
+ if trace.enabled {
+ traceProcStop(_g_.m.p.ptr())
+ }
+ _g_.m.p = 0
+ _g_.m.mcache = nil
+ _p_.m = 0
+ _p_.status = _Pidle
+ return _p_
+}
+
+func incidlelocked(v int32) {
+ lock(&sched.lock)
+ sched.nmidlelocked += v
+ if v > 0 {
+ checkdead()
+ }
+ unlock(&sched.lock)
+}
+
+// Check for deadlock situation.
+// The check is based on number of running M's, if 0 -> deadlock.
+func checkdead() {
+ // For -buildmode=c-shared or -buildmode=c-archive it's OK if
+ // there are no running goroutines. The calling program is
+ // assumed to be running.
+ if islibrary || isarchive {
+ return
+ }
+
+ // If we are dying because of a signal caught on an already idle thread,
+ // freezetheworld will cause all running threads to block.
+ // And runtime will essentially enter into deadlock state,
+ // except that there is a thread that will call exit soon.
+ if panicking > 0 {
+ return
+ }
+
+ // -1 for sysmon
+ run := sched.mcount - sched.nmidle - sched.nmidlelocked - 1
+ if run > 0 {
+ return
+ }
+ if run < 0 {
+ print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", sched.mcount, "\n")
+ throw("checkdead: inconsistent counts")
+ }
+
+ grunning := 0
+ lock(&allglock)
+ for i := 0; i < len(allgs); i++ {
+ gp := allgs[i]
+ if isSystemGoroutine(gp) {
+ continue
+ }
+ s := readgstatus(gp)
+ switch s &^ _Gscan {
+ case _Gwaiting:
+ grunning++
+ case _Grunnable,
+ _Grunning,
+ _Gsyscall:
+ unlock(&allglock)
+ print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n")
+ throw("checkdead: runnable g")
+ }
+ }
+ unlock(&allglock)
+ if grunning == 0 { // possible if main goroutine calls runtime·Goexit()
+ throw("no goroutines (main called runtime.Goexit) - deadlock!")
+ }
+
+ // Maybe jump time forward for playground.
+ gp := timejump()
+ if gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ globrunqput(gp)
+ _p_ := pidleget()
+ if _p_ == nil {
+ throw("checkdead: no p for timer")
+ }
+ mp := mget()
+ if mp == nil {
+ // There should always be a free M since
+ // nothing is running.
+ throw("checkdead: no m for timer")
+ }
+ mp.nextp.set(_p_)
+ notewakeup(&mp.park)
+ return
+ }
+
+ getg().m.throwing = -1 // do not dump full stacks
+ throw("all goroutines are asleep - deadlock!")
+}
+
+// forcegcperiod is the maximum time in nanoseconds between garbage
+// collections. If we go this long without a garbage collection, one
+// is forced to run.
+//
+// This is a variable for testing purposes. It normally doesn't change.
+var forcegcperiod int64 = 2 * 60 * 1e9
+
+// Always runs without a P, so write barriers are not allowed.
+//
+//go:nowritebarrierrec
+func sysmon() {
+ // If a heap span goes unused for 5 minutes after a garbage collection,
+ // we hand it back to the operating system.
+ scavengelimit := int64(5 * 60 * 1e9)
+
+ if debug.scavenge > 0 {
+ // Scavenge-a-lot for testing.
+ forcegcperiod = 10 * 1e6
+ scavengelimit = 20 * 1e6
+ }
+
+ lastscavenge := nanotime()
+ nscavenge := 0
+
+ lasttrace := int64(0)
+ idle := 0 // how many cycles in succession we had not wokeup somebody
+ delay := uint32(0)
+ for {
+ if idle == 0 { // start with 20us sleep...
+ delay = 20
+ } else if idle > 50 { // start doubling the sleep after 1ms...
+ delay *= 2
+ }
+ if delay > 10*1000 { // up to 10ms
+ delay = 10 * 1000
+ }
+ usleep(delay)
+ if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)) {
+ lock(&sched.lock)
+ if atomic.Load(&sched.gcwaiting) != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs) {
+ atomic.Store(&sched.sysmonwait, 1)
+ unlock(&sched.lock)
+ // Make wake-up period small enough
+ // for the sampling to be correct.
+ maxsleep := forcegcperiod / 2
+ if scavengelimit < forcegcperiod {
+ maxsleep = scavengelimit / 2
+ }
+ notetsleep(&sched.sysmonnote, maxsleep)
+ lock(&sched.lock)
+ atomic.Store(&sched.sysmonwait, 0)
+ noteclear(&sched.sysmonnote)
+ idle = 0
+ delay = 20
+ }
+ unlock(&sched.lock)
+ }
+ // poll network if not polled for more than 10ms
+ lastpoll := int64(atomic.Load64(&sched.lastpoll))
+ now := nanotime()
+ unixnow := unixnanotime()
+ if lastpoll != 0 && lastpoll+10*1000*1000 < now {
+ atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
+ gp := netpoll(false) // non-blocking - returns list of goroutines
+ if gp != nil {
+ // Need to decrement number of idle locked M's
+ // (pretending that one more is running) before injectglist.
+ // Otherwise it can lead to the following situation:
+ // injectglist grabs all P's but before it starts M's to run the P's,
+ // another M returns from syscall, finishes running its G,
+ // observes that there is no work to do and no other running M's
+ // and reports deadlock.
+ incidlelocked(-1)
+ injectglist(gp)
+ incidlelocked(1)
+ }
+ }
+ // retake P's blocked in syscalls
+ // and preempt long running G's
+ if retake(now) != 0 {
+ idle = 0
+ } else {
+ idle++
+ }
+ // check if we need to force a GC
+ lastgc := int64(atomic.Load64(&memstats.last_gc))
+ if gcphase == _GCoff && lastgc != 0 && unixnow-lastgc > forcegcperiod && atomic.Load(&forcegc.idle) != 0 {
+ lock(&forcegc.lock)
+ forcegc.idle = 0
+ forcegc.g.schedlink = 0
+ injectglist(forcegc.g)
+ unlock(&forcegc.lock)
+ }
+ // scavenge heap once in a while
+ if lastscavenge+scavengelimit/2 < now {
+ mheap_.scavenge(int32(nscavenge), uint64(now), uint64(scavengelimit))
+ lastscavenge = now
+ nscavenge++
+ }
+ if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now {
+ lasttrace = now
+ schedtrace(debug.scheddetail > 0)
+ }
+ }
+}
+
+var pdesc [_MaxGomaxprocs]struct {
+ schedtick uint32
+ schedwhen int64
+ syscalltick uint32
+ syscallwhen int64
+}
+
+// forcePreemptNS is the time slice given to a G before it is
+// preempted.
+const forcePreemptNS = 10 * 1000 * 1000 // 10ms
+
+func retake(now int64) uint32 {
+ n := 0
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ continue
+ }
+ pd := &pdesc[i]
+ s := _p_.status
+ if s == _Psyscall {
+ // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
+ t := int64(_p_.syscalltick)
+ if int64(pd.syscalltick) != t {
+ pd.syscalltick = uint32(t)
+ pd.syscallwhen = now
+ continue
+ }
+ // On the one hand we don't want to retake Ps if there is no other work to do,
+ // but on the other hand we want to retake them eventually
+ // because they can prevent the sysmon thread from deep sleep.
+ if runqempty(_p_) && atomic.Load(&sched.nmspinning)+atomic.Load(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
+ continue
+ }
+ // Need to decrement number of idle locked M's
+ // (pretending that one more is running) before the CAS.
+ // Otherwise the M from which we retake can exit the syscall,
+ // increment nmidle and report deadlock.
+ incidlelocked(-1)
+ if atomic.Cas(&_p_.status, s, _Pidle) {
+ if trace.enabled {
+ traceGoSysBlock(_p_)
+ traceProcStop(_p_)
+ }
+ n++
+ _p_.syscalltick++
+ handoffp(_p_)
+ }
+ incidlelocked(1)
+ } else if s == _Prunning {
+ // Preempt G if it's running for too long.
+ t := int64(_p_.schedtick)
+ if int64(pd.schedtick) != t {
+ pd.schedtick = uint32(t)
+ pd.schedwhen = now
+ continue
+ }
+ if pd.schedwhen+forcePreemptNS > now {
+ continue
+ }
+ preemptone(_p_)
+ }
+ }
+ return uint32(n)
+}
+
+// Tell all goroutines that they have been preempted and they should stop.
+// This function is purely best-effort. It can fail to inform a goroutine if a
+// processor just started running it.
+// No locks need to be held.
+// Returns true if preemption request was issued to at least one goroutine.
+func preemptall() bool {
+ res := false
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil || _p_.status != _Prunning {
+ continue
+ }
+ if preemptone(_p_) {
+ res = true
+ }
+ }
+ return res
+}
+
+// Tell the goroutine running on processor P to stop.
+// This function is purely best-effort. It can incorrectly fail to inform the
+// goroutine. It can send inform the wrong goroutine. Even if it informs the
+// correct goroutine, that goroutine might ignore the request if it is
+// simultaneously executing newstack.
+// No lock needs to be held.
+// Returns true if preemption request was issued.
+// The actual preemption will happen at some point in the future
+// and will be indicated by the gp->status no longer being
+// Grunning
+func preemptone(_p_ *p) bool {
+ mp := _p_.m.ptr()
+ if mp == nil || mp == getg().m {
+ return false
+ }
+ gp := mp.curg
+ if gp == nil || gp == mp.g0 {
+ return false
+ }
+
+ gp.preempt = true
+
+ // At this point the gc implementation sets gp.stackguard0 to
+ // a value that causes the goroutine to suspend itself.
+ // gccgo has no support for this, and it's hard to support.
+ // The split stack code reads a value from its TCB.
+ // We have no way to set a value in the TCB of a different thread.
+ // And, of course, not all systems support split stack anyhow.
+ // Checking the field in the g is expensive, since it requires
+ // loading the g from TLS. The best mechanism is likely to be
+ // setting a global variable and figuring out a way to efficiently
+ // check that global variable.
+ //
+ // For now we check gp.preempt in schedule and mallocgc,
+ // which is at least better than doing nothing at all.
+
+ return true
+}
+
+var starttime int64
+
+func schedtrace(detailed bool) {
+ now := nanotime()
+ if starttime == 0 {
+ starttime = now
+ }
+
+ lock(&sched.lock)
+ print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle, " threads=", sched.mcount, " spinningthreads=", sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize)
+ if detailed {
+ print(" gcwaiting=", sched.gcwaiting, " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait, "\n")
+ }
+ // We must be careful while reading data from P's, M's and G's.
+ // Even if we hold schedlock, most data can be changed concurrently.
+ // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
+ for i := int32(0); i < gomaxprocs; i++ {
+ _p_ := allp[i]
+ if _p_ == nil {
+ continue
+ }
+ mp := _p_.m.ptr()
+ h := atomic.Load(&_p_.runqhead)
+ t := atomic.Load(&_p_.runqtail)
+ if detailed {
+ id := int32(-1)
+ if mp != nil {
+ id = mp.id
+ }
+ print(" P", i, ": status=", _p_.status, " schedtick=", _p_.schedtick, " syscalltick=", _p_.syscalltick, " m=", id, " runqsize=", t-h, " gfreecnt=", _p_.gfreecnt, "\n")
+ } else {
+ // In non-detailed mode format lengths of per-P run queues as:
+ // [len1 len2 len3 len4]
+ print(" ")
+ if i == 0 {
+ print("[")
+ }
+ print(t - h)
+ if i == gomaxprocs-1 {
+ print("]\n")
+ }
+ }
+ }
+
+ if !detailed {
+ unlock(&sched.lock)
+ return
+ }
+
+ for mp := allm; mp != nil; mp = mp.alllink {
+ _p_ := mp.p.ptr()
+ gp := mp.curg
+ lockedg := mp.lockedg
+ id1 := int32(-1)
+ if _p_ != nil {
+ id1 = _p_.id
+ }
+ id2 := int64(-1)
+ if gp != nil {
+ id2 = gp.goid
+ }
+ id3 := int64(-1)
+ if lockedg != nil {
+ id3 = lockedg.goid
+ }
+ print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=", id3, "\n")
+ }
+
+ lock(&allglock)
+ for gi := 0; gi < len(allgs); gi++ {
+ gp := allgs[gi]
+ mp := gp.m
+ lockedm := gp.lockedm
+ id1 := int32(-1)
+ if mp != nil {
+ id1 = mp.id
+ }
+ id2 := int32(-1)
+ if lockedm != nil {
+ id2 = lockedm.id
+ }
+ print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason, ") m=", id1, " lockedm=", id2, "\n")
+ }
+ unlock(&allglock)
+ unlock(&sched.lock)
+}
+
+// Put mp on midle list.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func mput(mp *m) {
+ mp.schedlink = sched.midle
+ sched.midle.set(mp)
+ sched.nmidle++
+ checkdead()
+}
+
+// Try to get an m from midle list.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func mget() *m {
+ mp := sched.midle.ptr()
+ if mp != nil {
+ sched.midle = mp.schedlink
+ sched.nmidle--
+ }
+ return mp
+}
+
+// Put gp on the global runnable queue.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func globrunqput(gp *g) {
+ gp.schedlink = 0
+ if sched.runqtail != 0 {
+ sched.runqtail.ptr().schedlink.set(gp)
+ } else {
+ sched.runqhead.set(gp)
+ }
+ sched.runqtail.set(gp)
+ sched.runqsize++
+}
+
+// Put gp at the head of the global runnable queue.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func globrunqputhead(gp *g) {
+ gp.schedlink = sched.runqhead
+ sched.runqhead.set(gp)
+ if sched.runqtail == 0 {
+ sched.runqtail.set(gp)
+ }
+ sched.runqsize++
+}
+
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+func globrunqputbatch(ghead *g, gtail *g, n int32) {
+ gtail.schedlink = 0
+ if sched.runqtail != 0 {
+ sched.runqtail.ptr().schedlink.set(ghead)
+ } else {
+ sched.runqhead.set(ghead)
+ }
+ sched.runqtail.set(gtail)
+ sched.runqsize += n
+}
+
+// Try get a batch of G's from the global runnable queue.
+// Sched must be locked.
+func globrunqget(_p_ *p, max int32) *g {
+ if sched.runqsize == 0 {
+ return nil
+ }
+
+ n := sched.runqsize/gomaxprocs + 1
+ if n > sched.runqsize {
+ n = sched.runqsize
+ }
+ if max > 0 && n > max {
+ n = max
+ }
+ if n > int32(len(_p_.runq))/2 {
+ n = int32(len(_p_.runq)) / 2
+ }
+
+ sched.runqsize -= n
+ if sched.runqsize == 0 {
+ sched.runqtail = 0
+ }
+
+ gp := sched.runqhead.ptr()
+ sched.runqhead = gp.schedlink
+ n--
+ for ; n > 0; n-- {
+ gp1 := sched.runqhead.ptr()
+ sched.runqhead = gp1.schedlink
+ runqput(_p_, gp1, false)
+ }
+ return gp
+}
+
+// Put p to on _Pidle list.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func pidleput(_p_ *p) {
+ if !runqempty(_p_) {
+ throw("pidleput: P has non-empty run queue")
+ }
+ _p_.link = sched.pidle
+ sched.pidle.set(_p_)
+ atomic.Xadd(&sched.npidle, 1) // TODO: fast atomic
+}
+
+// Try get a p from _Pidle list.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrierrec
+func pidleget() *p {
+ _p_ := sched.pidle.ptr()
+ if _p_ != nil {
+ sched.pidle = _p_.link
+ atomic.Xadd(&sched.npidle, -1) // TODO: fast atomic
+ }
+ return _p_
+}
+
+// runqempty returns true if _p_ has no Gs on its local run queue.
+// It never returns true spuriously.
+func runqempty(_p_ *p) bool {
+ // Defend against a race where 1) _p_ has G1 in runqnext but runqhead == runqtail,
+ // 2) runqput on _p_ kicks G1 to the runq, 3) runqget on _p_ empties runqnext.
+ // Simply observing that runqhead == runqtail and then observing that runqnext == nil
+ // does not mean the queue is empty.
+ for {
+ head := atomic.Load(&_p_.runqhead)
+ tail := atomic.Load(&_p_.runqtail)
+ runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&_p_.runnext)))
+ if tail == atomic.Load(&_p_.runqtail) {
+ return head == tail && runnext == 0
+ }
+ }
+}
+
+// To shake out latent assumptions about scheduling order,
+// we introduce some randomness into scheduling decisions
+// when running with the race detector.
+// The need for this was made obvious by changing the
+// (deterministic) scheduling order in Go 1.5 and breaking
+// many poorly-written tests.
+// With the randomness here, as long as the tests pass
+// consistently with -race, they shouldn't have latent scheduling
+// assumptions.
+const randomizeScheduler = raceenabled
+
+// runqput tries to put g on the local runnable queue.
+// If next if false, runqput adds g to the tail of the runnable queue.
+// If next is true, runqput puts g in the _p_.runnext slot.
+// If the run queue is full, runnext puts g on the global queue.
+// Executed only by the owner P.
+func runqput(_p_ *p, gp *g, next bool) {
+ if randomizeScheduler && next && fastrand()%2 == 0 {
+ next = false
+ }
+
+ if next {
+ retryNext:
+ oldnext := _p_.runnext
+ if !_p_.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
+ goto retryNext
+ }
+ if oldnext == 0 {
+ return
+ }
+ // Kick the old runnext out to the regular run queue.
+ gp = oldnext.ptr()
+ }
+
+retry:
+ h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with consumers
+ t := _p_.runqtail
+ if t-h < uint32(len(_p_.runq)) {
+ _p_.runq[t%uint32(len(_p_.runq))].set(gp)
+ atomic.Store(&_p_.runqtail, t+1) // store-release, makes the item available for consumption
+ return
+ }
+ if runqputslow(_p_, gp, h, t) {
+ return
+ }
+ // the queue is not full, now the put above must succeed
+ goto retry
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+func runqputslow(_p_ *p, gp *g, h, t uint32) bool {
+ var batch [len(_p_.runq)/2 + 1]*g
+
+ // First, grab a batch from local queue.
+ n := t - h
+ n = n / 2
+ if n != uint32(len(_p_.runq)/2) {
+ throw("runqputslow: queue is not full")
+ }
+ for i := uint32(0); i < n; i++ {
+ batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))].ptr()
+ }
+ if !atomic.Cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ return false
+ }
+ batch[n] = gp
+
+ if randomizeScheduler {
+ for i := uint32(1); i <= n; i++ {
+ j := fastrand() % (i + 1)
+ batch[i], batch[j] = batch[j], batch[i]
+ }
+ }
+
+ // Link the goroutines.
+ for i := uint32(0); i < n; i++ {
+ batch[i].schedlink.set(batch[i+1])
+ }
+
+ // Now put the batch on global queue.
+ lock(&sched.lock)
+ globrunqputbatch(batch[0], batch[n], int32(n+1))
+ unlock(&sched.lock)
+ return true
+}
+
+// Get g from local runnable queue.
+// If inheritTime is true, gp should inherit the remaining time in the
+// current time slice. Otherwise, it should start a new time slice.
+// Executed only by the owner P.
+func runqget(_p_ *p) (gp *g, inheritTime bool) {
+ // If there's a runnext, it's the next G to run.
+ for {
+ next := _p_.runnext
+ if next == 0 {
+ break
+ }
+ if _p_.runnext.cas(next, 0) {
+ return next.ptr(), true
+ }
+ }
+
+ for {
+ h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ t := _p_.runqtail
+ if t == h {
+ return nil, false
+ }
+ gp := _p_.runq[h%uint32(len(_p_.runq))].ptr()
+ if atomic.Cas(&_p_.runqhead, h, h+1) { // cas-release, commits consume
+ return gp, false
+ }
+ }
+}
+
+// Grabs a batch of goroutines from _p_'s runnable queue into batch.
+// Batch is a ring buffer starting at batchHead.
+// Returns number of grabbed goroutines.
+// Can be executed by any P.
+func runqgrab(_p_ *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 {
+ for {
+ h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ t := atomic.Load(&_p_.runqtail) // load-acquire, synchronize with the producer
+ n := t - h
+ n = n - n/2
+ if n == 0 {
+ if stealRunNextG {
+ // Try to steal from _p_.runnext.
+ if next := _p_.runnext; next != 0 {
+ // Sleep to ensure that _p_ isn't about to run the g we
+ // are about to steal.
+ // The important use case here is when the g running on _p_
+ // ready()s another g and then almost immediately blocks.
+ // Instead of stealing runnext in this window, back off
+ // to give _p_ a chance to schedule runnext. This will avoid
+ // thrashing gs between different Ps.
+ // A sync chan send/recv takes ~50ns as of time of writing,
+ // so 3us gives ~50x overshoot.
+ if GOOS != "windows" {
+ usleep(3)
+ } else {
+ // On windows system timer granularity is 1-15ms,
+ // which is way too much for this optimization.
+ // So just yield.
+ osyield()
+ }
+ if !_p_.runnext.cas(next, 0) {
+ continue
+ }
+ batch[batchHead%uint32(len(batch))] = next
+ return 1
+ }
+ }
+ return 0
+ }
+ if n > uint32(len(_p_.runq)/2) { // read inconsistent h and t
+ continue
+ }
+ for i := uint32(0); i < n; i++ {
+ g := _p_.runq[(h+i)%uint32(len(_p_.runq))]
+ batch[(batchHead+i)%uint32(len(batch))] = g
+ }
+ if atomic.Cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ return n
+ }
+ }
+}
+
+// Steal half of elements from local runnable queue of p2
+// and put onto local runnable queue of p.
+// Returns one of the stolen elements (or nil if failed).
+func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
+ t := _p_.runqtail
+ n := runqgrab(p2, &_p_.runq, t, stealRunNextG)
+ if n == 0 {
+ return nil
+ }
+ n--
+ gp := _p_.runq[(t+n)%uint32(len(_p_.runq))].ptr()
+ if n == 0 {
+ return gp
+ }
+ h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with consumers
+ if t-h+n >= uint32(len(_p_.runq)) {
+ throw("runqsteal: runq overflow")
+ }
+ atomic.Store(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
+ return gp
+}
+
+//go:linkname setMaxThreads runtime_debug.setMaxThreads
+func setMaxThreads(in int) (out int) {
+ lock(&sched.lock)
+ out = int(sched.maxmcount)
+ if in > 0x7fffffff { // MaxInt32
+ sched.maxmcount = 0x7fffffff
+ } else {
+ sched.maxmcount = int32(in)
+ }
+ checkmcount()
+ unlock(&sched.lock)
+ return
+}
+
+//go:nosplit
+func procPin() int {
+ _g_ := getg()
+ mp := _g_.m
+
+ mp.locks++
+ return int(mp.p.ptr().id)
+}
+
+//go:nosplit
+func procUnpin() {
+ _g_ := getg()
+ _g_.m.locks--
+}
+
+//go:linkname sync_runtime_procPin sync.runtime_procPin
+//go:nosplit
+func sync_runtime_procPin() int {
+ return procPin()
+}
+
+//go:linkname sync_runtime_procUnpin sync.runtime_procUnpin
+//go:nosplit
+func sync_runtime_procUnpin() {
+ procUnpin()
+}
+
+//go:linkname sync_atomic_runtime_procPin sync_atomic.runtime_procPin
+//go:nosplit
+func sync_atomic_runtime_procPin() int {
+ return procPin()
+}
+
+//go:linkname sync_atomic_runtime_procUnpin sync_atomic.runtime_procUnpin
+//go:nosplit
+func sync_atomic_runtime_procUnpin() {
+ procUnpin()
+}
+
+// Active spinning for sync.Mutex.
+//go:linkname sync_runtime_canSpin sync.runtime_canSpin
+//go:nosplit
+func sync_runtime_canSpin(i int) bool {
+ // sync.Mutex is cooperative, so we are conservative with spinning.
+ // Spin only few times and only if running on a multicore machine and
+ // GOMAXPROCS>1 and there is at least one other running P and local runq is empty.
+ // As opposed to runtime mutex we don't do passive spinning here,
+ // because there can be work on global runq on on other Ps.
+ if i >= active_spin || ncpu <= 1 || gomaxprocs <= int32(sched.npidle+sched.nmspinning)+1 {
+ return false
+ }
+ if p := getg().m.p.ptr(); !runqempty(p) {
+ return false
+ }
+ return true
+}
+
+//go:linkname sync_runtime_doSpin sync.runtime_doSpin
+//go:nosplit
+func sync_runtime_doSpin() {
+ procyield(active_spin_cnt)
+}
+
+var stealOrder randomOrder
+
+// randomOrder/randomEnum are helper types for randomized work stealing.
+// They allow to enumerate all Ps in different pseudo-random orders without repetitions.
+// The algorithm is based on the fact that if we have X such that X and GOMAXPROCS
+// are coprime, then a sequences of (i + X) % GOMAXPROCS gives the required enumeration.
+type randomOrder struct {
+ count uint32
+ coprimes []uint32
+}
+
+type randomEnum struct {
+ i uint32
+ count uint32
+ pos uint32
+ inc uint32
+}
+
+func (ord *randomOrder) reset(count uint32) {
+ ord.count = count
+ ord.coprimes = ord.coprimes[:0]
+ for i := uint32(1); i <= count; i++ {
+ if gcd(i, count) == 1 {
+ ord.coprimes = append(ord.coprimes, i)
+ }
+ }
+}
+
+func (ord *randomOrder) start(i uint32) randomEnum {
+ return randomEnum{
+ count: ord.count,
+ pos: i % ord.count,
+ inc: ord.coprimes[i%uint32(len(ord.coprimes))],
+ }
+}
+
+func (enum *randomEnum) done() bool {
+ return enum.i == enum.count
+}
+
+func (enum *randomEnum) next() {
+ enum.i++
+ enum.pos = (enum.pos + enum.inc) % enum.count
+}
+
+func (enum *randomEnum) position() uint32 {
+ return enum.pos
+}
+
+func gcd(a, b uint32) uint32 {
+ for b != 0 {
+ a, b = b, a%b
+ }
+ return a
+}
diff --git a/libgo/go/runtime/proc_runtime_test.go b/libgo/go/runtime/proc_runtime_test.go
new file mode 100644
index 0000000000..d56f9b1463
--- /dev/null
+++ b/libgo/go/runtime/proc_runtime_test.go
@@ -0,0 +1,35 @@
+// 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
+
+// Proc unit tests. In runtime package so can use runtime guts.
+
+package runtime
+
+func RunStealOrderTest() {
+ var ord randomOrder
+ for procs := 1; procs <= 64; procs++ {
+ ord.reset(uint32(procs))
+ if procs >= 3 && len(ord.coprimes) < 2 {
+ panic("too few coprimes")
+ }
+ for co := 0; co < len(ord.coprimes); co++ {
+ enum := ord.start(uint32(co))
+ checked := make([]bool, procs)
+ for p := 0; p < procs; p++ {
+ x := enum.position()
+ if checked[x] {
+ println("procs:", procs, "inc:", enum.inc)
+ panic("duplicate during enumeration")
+ }
+ checked[x] = true
+ enum.next()
+ }
+ if !enum.done() {
+ panic("not done")
+ }
+ }
+ }
+}
diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go
index 37adad570b..813c92912b 100644
--- a/libgo/go/runtime/proc_test.go
+++ b/libgo/go/runtime/proc_test.go
@@ -178,7 +178,14 @@ func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
}
if netpoll {
// Enable netpoller, affects schedler behavior.
- ln, err := net.Listen("tcp", "localhost:0")
+ laddr := "localhost:0"
+ if runtime.GOOS == "android" {
+ // On some Android devices, there are no records for localhost,
+ // see https://golang.org/issues/14486.
+ // Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
+ laddr = "127.0.0.1:0"
+ }
+ ln, err := net.Listen("tcp", laddr)
if err != nil {
defer ln.Close() // yup, defer in a loop
}
@@ -339,6 +346,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"
@@ -423,6 +438,9 @@ func TestPingPongHog(t *testing.T) {
}
func BenchmarkPingPongHog(b *testing.B) {
+ if b.N == 0 {
+ return
+ }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
// Create a CPU hog
@@ -538,17 +556,31 @@ func nonleaf(stop chan int) bool {
}
}
-/*
func TestSchedLocalQueue(t *testing.T) {
- runtime.TestSchedLocalQueue1()
+ runtime.RunSchedLocalQueueTest()
}
-*/
-/*
func TestSchedLocalQueueSteal(t *testing.T) {
- runtime.TestSchedLocalQueueSteal1()
+ runtime.RunSchedLocalQueueStealTest()
+}
+
+func TestSchedLocalQueueEmpty(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ // Takes too long and does not trigger the race.
+ t.Skip("skipping on uniprocessor")
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+
+ // If runtime triggers a forced GC during this test then it will deadlock,
+ // since the goroutines can't be stopped/preempted during spin wait.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+
+ iters := int(1e5)
+ if testing.Short() {
+ iters = 1e2
+ }
+ runtime.RunSchedLocalQueueEmptyTest(iters)
}
-*/
func benchmarkStackGrowth(b *testing.B, rec int) {
b.RunParallel(func(pb *testing.PB) {
@@ -686,3 +718,9 @@ func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, thres
done <- struct{}{}
}
}
+
+/*
+func TestStealOrder(t *testing.T) {
+ runtime.RunStealOrderTest()
+}
+*/
diff --git a/libgo/go/runtime/race/testdata/issue12225_test.go b/libgo/go/runtime/race/testdata/issue12225_test.go
deleted file mode 100644
index 0494493b2e..0000000000
--- a/libgo/go/runtime/race/testdata/issue12225_test.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package race_test
-
-import "unsafe"
-
-// golang.org/issue/12225
-// The test is that this compiles at all.
-
-//go:noinline
-func convert(s string) []byte {
- return []byte(s)
-}
-
-func issue12225() {
- println(*(*int)(unsafe.Pointer(&convert("")[0])))
- println(*(*int)(unsafe.Pointer(&[]byte("")[0])))
-}
diff --git a/libgo/go/runtime/race/testdata/issue12664_test.go b/libgo/go/runtime/race/testdata/issue12664_test.go
deleted file mode 100644
index c9f790edc8..0000000000
--- a/libgo/go/runtime/race/testdata/issue12664_test.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package race_test
-
-import (
- "fmt"
- "testing"
-)
-
-var issue12664 = "hi"
-
-func TestRaceIssue12664(t *testing.T) {
- c := make(chan struct{})
- go func() {
- issue12664 = "bye"
- close(c)
- }()
- fmt.Println(issue12664)
- <-c
-}
-
-type MyI interface {
- foo()
-}
-
-type MyT int
-
-func (MyT) foo() {
-}
-
-var issue12664_2 MyT = 0
-
-func TestRaceIssue12664_2(t *testing.T) {
- c := make(chan struct{})
- go func() {
- issue12664_2 = 1
- close(c)
- }()
- func(x MyI) {
- // Never true, but prevents inlining.
- if x.(MyT) == -1 {
- close(c)
- }
- }(issue12664_2)
- <-c
-}
-
-var issue12664_3 MyT = 0
-
-func TestRaceIssue12664_3(t *testing.T) {
- c := make(chan struct{})
- go func() {
- issue12664_3 = 1
- close(c)
- }()
- var r MyT
- var i interface{} = r
- issue12664_3 = i.(MyT)
- <-c
-}
-
-var issue12664_4 MyT = 0
-
-func TestRaceIssue12664_4(t *testing.T) {
- c := make(chan struct{})
- go func() {
- issue12664_4 = 1
- close(c)
- }()
- var r MyT
- var i MyI = r
- issue12664_4 = i.(MyT)
- <-c
-}
diff --git a/libgo/go/runtime/race/testdata/issue13264_test.go b/libgo/go/runtime/race/testdata/issue13264_test.go
deleted file mode 100644
index d42290de50..0000000000
--- a/libgo/go/runtime/race/testdata/issue13264_test.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package race_test
-
-// golang.org/issue/13264
-// The test is that this compiles at all.
-
-func issue13264() {
- for ; ; []map[int]int{}[0][0] = 0 {
- }
-}
diff --git a/libgo/go/runtime/race0.go b/libgo/go/runtime/race0.go
new file mode 100644
index 0000000000..f1d3706231
--- /dev/null
+++ b/libgo/go/runtime/race0.go
@@ -0,0 +1,40 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !race
+
+// Dummy race detection API, used when not built with -race.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+const raceenabled = false
+
+// Because raceenabled is false, none of these functions should be called.
+
+func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
+func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
+func raceinit() (uintptr, uintptr) { throw("race"); return 0, 0 }
+func racefini() { throw("race") }
+func raceproccreate() uintptr { throw("race"); return 0 }
+func raceprocdestroy(ctx uintptr) { throw("race") }
+func racemapshadow(addr unsafe.Pointer, size uintptr) { throw("race") }
+func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
+func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
+func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr) { throw("race") }
+func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr) { throw("race") }
+func raceacquire(addr unsafe.Pointer) { throw("race") }
+func raceacquireg(gp *g, addr unsafe.Pointer) { throw("race") }
+func racerelease(addr unsafe.Pointer) { throw("race") }
+func racereleaseg(gp *g, addr unsafe.Pointer) { throw("race") }
+func racereleasemerge(addr unsafe.Pointer) { throw("race") }
+func racereleasemergeg(gp *g, addr unsafe.Pointer) { throw("race") }
+func racefingo() { throw("race") }
+func racemalloc(p unsafe.Pointer, sz uintptr) { throw("race") }
+func racefree(p unsafe.Pointer, sz uintptr) { throw("race") }
+func racegostart(pc uintptr) uintptr { throw("race"); return 0 }
+func racegoend() { throw("race") }
diff --git a/libgo/go/runtime/rdebug.go b/libgo/go/runtime/rdebug.go
new file mode 100644
index 0000000000..76535a905a
--- /dev/null
+++ b/libgo/go/runtime/rdebug.go
@@ -0,0 +1,27 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+// Define maxstacksize here for gccgo. For gc it is defined in
+// stack.go, but gccgo doesn't use that file. Or, for that matter,
+// maxstacksize.
+var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real
+
+//go:linkname setMaxStack runtime_debug.setMaxStack
+func setMaxStack(in int) (out int) {
+ out = int(maxstacksize)
+ maxstacksize = uintptr(in)
+ return out
+}
+
+//go:linkname setPanicOnFault runtime_debug.setPanicOnFault
+func setPanicOnFault(new bool) (old bool) {
+ _g_ := getg()
+ old = _g_.paniconfault
+ _g_.paniconfault = new
+ return old
+}
diff --git a/libgo/go/runtime/runtime-lldb_test.go b/libgo/go/runtime/runtime-lldb_test.go
index 2bd91c1ec0..98bc906666 100644
--- a/libgo/go/runtime/runtime-lldb_test.go
+++ b/libgo/go/runtime/runtime-lldb_test.go
@@ -158,7 +158,7 @@ func TestLldbPython(t *testing.T) {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags", "-N -l", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
@@ -198,7 +198,7 @@ func TestDwarfAranges(t *testing.T) {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
@@ -232,7 +232,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker)
SegmentSize uint8
}
for {
- offset, err := data.Seek(0, 1)
+ offset, err := data.Seek(0, io.SeekCurrent)
if err != nil {
t.Fatalf("Seek error: %v", err)
}
@@ -246,7 +246,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker)
if lastTupleOffset%tupleSize != 0 {
t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
}
- if _, err = data.Seek(lastTupleOffset, 0); err != nil {
+ if _, err = data.Seek(lastTupleOffset, io.SeekStart); err != nil {
t.Fatalf("Seek error: %v", err)
}
buf := make([]byte, tupleSize)
diff --git a/libgo/go/runtime/runtime.go b/libgo/go/runtime/runtime.go
new file mode 100644
index 0000000000..e63130b149
--- /dev/null
+++ b/libgo/go/runtime/runtime.go
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ _ "unsafe" // for go:linkname
+)
+
+//go:generate go run wincallback.go
+//go:generate go run mkduff.go
+//go:generate go run mkfastlog2table.go
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname tickspersecond runtime.tickspersecond
+
+var ticks struct {
+ lock mutex
+ pad uint32 // ensure 8-byte alignment of val on 386
+ val uint64
+}
+
+// Note: Called by runtime/pprof in addition to runtime code.
+func tickspersecond() int64 {
+ r := int64(atomic.Load64(&ticks.val))
+ if r != 0 {
+ return r
+ }
+ lock(&ticks.lock)
+ r = int64(ticks.val)
+ if r == 0 {
+ t0 := nanotime()
+ c0 := cputicks()
+ usleep(100 * 1000)
+ t1 := nanotime()
+ c1 := cputicks()
+ if t1 == t0 {
+ t1++
+ }
+ r = (c1 - c0) * 1000 * 1000 * 1000 / (t1 - t0)
+ if r == 0 {
+ r++
+ }
+ atomic.Store64(&ticks.val, uint64(r))
+ }
+ unlock(&ticks.lock)
+ return r
+}
+
+var envs []string
+var argslice []string
+
+//go:linkname syscall_runtime_envs syscall.runtime_envs
+func syscall_runtime_envs() []string { return append([]string{}, envs...) }
+
+//go:linkname syscall_Getpagesize syscall.Getpagesize
+func syscall_Getpagesize() int { return int(physPageSize) }
+
+//go:linkname os_runtime_args os.runtime_args
+func os_runtime_args() []string { return append([]string{}, argslice...) }
+
+// Temporary, for the gccgo runtime code written in C.
+//go:linkname get_envs runtime_get_envs
+func get_envs() []string { return envs }
+
+//go:linkname get_args runtime_get_args
+func get_args() []string { return argslice }
diff --git a/libgo/go/runtime/runtime1.go b/libgo/go/runtime/runtime1.go
new file mode 100644
index 0000000000..99c0f11930
--- /dev/null
+++ b/libgo/go/runtime/runtime1.go
@@ -0,0 +1,530 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname gotraceback runtime.gotraceback
+//go:linkname args runtime.args
+//go:linkname goargs runtime.goargs
+//go:linkname check runtime.check
+//go:linkname goenvs_unix runtime.goenvs_unix
+//go:linkname parsedebugvars runtime.parsedebugvars
+//go:linkname timediv runtime.timediv
+
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bits
+// are the "crash" and "all" settings and the remaining
+// bits are the traceback value (0 off, 1 on, 2 include system).
+const (
+ tracebackCrash = 1 << iota
+ tracebackAll
+ tracebackShift = iota
+)
+
+var traceback_cache uint32 = 2 << tracebackShift
+var traceback_env uint32
+
+// gotraceback returns the current traceback settings.
+//
+// If level is 0, suppress all tracebacks.
+// If level is 1, show tracebacks, but exclude runtime frames.
+// If level is 2, show tracebacks including runtime frames.
+// If all is set, print all goroutine stacks. Otherwise, print just the current goroutine.
+// If crash is set, crash (core dump, etc) after tracebacking.
+//
+//go:nosplit
+func gotraceback() (level int32, all, crash bool) {
+ _g_ := getg()
+ all = _g_.m.throwing > 0
+ if _g_.m.traceback != 0 {
+ level = int32(_g_.m.traceback)
+ return
+ }
+ t := atomic.Load(&traceback_cache)
+ crash = t&tracebackCrash != 0
+ all = all || t&tracebackAll != 0
+ level = int32(t >> tracebackShift)
+ return
+}
+
+var (
+ argc int32
+ argv **byte
+)
+
+// nosplit for use in linux startup sysargs
+//go:nosplit
+func argv_index(argv **byte, i int32) *byte {
+ return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*sys.PtrSize))
+}
+
+func args(c int32, v **byte) {
+ argc = c
+ argv = v
+ sysargs(c, v)
+}
+
+func goargs() {
+ if GOOS == "windows" {
+ return
+ }
+ argslice = make([]string, argc)
+ for i := int32(0); i < argc; i++ {
+ argslice[i] = gostringnocopy(argv_index(argv, i))
+ }
+}
+
+func goenvs_unix() {
+ // TODO(austin): ppc64 in dynamic linking mode doesn't
+ // guarantee env[] will immediately follow argv. Might cause
+ // problems.
+ n := int32(0)
+ for argv_index(argv, argc+1+n) != nil {
+ n++
+ }
+
+ envs = make([]string, n)
+ for i := int32(0); i < n; i++ {
+ envs[i] = gostring(argv_index(argv, argc+1+i))
+ }
+}
+
+func environ() []string {
+ return envs
+}
+
+// TODO: These should be locals in testAtomic64, but we don't 8-byte
+// align stack variables on 386.
+var test_z64, test_x64 uint64
+
+func testAtomic64() {
+ test_z64 = 42
+ test_x64 = 0
+ // prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
+ // prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
+ // prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
+ // prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
+ if atomic.Cas64(&test_z64, test_x64, 1) {
+ throw("cas64 failed")
+ }
+ if test_x64 != 0 {
+ throw("cas64 failed")
+ }
+ test_x64 = 42
+ if !atomic.Cas64(&test_z64, test_x64, 1) {
+ throw("cas64 failed")
+ }
+ if test_x64 != 42 || test_z64 != 1 {
+ throw("cas64 failed")
+ }
+ if atomic.Load64(&test_z64) != 1 {
+ throw("load64 failed")
+ }
+ atomic.Store64(&test_z64, (1<<40)+1)
+ if atomic.Load64(&test_z64) != (1<<40)+1 {
+ throw("store64 failed")
+ }
+ if atomic.Xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
+ throw("xadd64 failed")
+ }
+ if atomic.Load64(&test_z64) != (2<<40)+2 {
+ throw("xadd64 failed")
+ }
+ if atomic.Xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
+ throw("xchg64 failed")
+ }
+ if atomic.Load64(&test_z64) != (3<<40)+3 {
+ throw("xchg64 failed")
+ }
+}
+
+func check() {
+
+ // This doesn't currently work for gccgo. Because escape
+ // analysis is not turned on by default, the code below that
+ // takes the address of local variables causes memory
+ // allocation, but this function is called before the memory
+ // allocator has been initialized.
+ return
+
+ var (
+ a int8
+ b uint8
+ c int16
+ d uint16
+ e int32
+ f uint32
+ g int64
+ h uint64
+ i, i1 float32
+ j, j1 float64
+ k, k1 unsafe.Pointer
+ l *uint16
+ m [4]byte
+ )
+ type x1t struct {
+ x uint8
+ }
+ type y1t struct {
+ x1 x1t
+ y uint8
+ }
+ var x1 x1t
+ var y1 y1t
+
+ if unsafe.Sizeof(a) != 1 {
+ throw("bad a")
+ }
+ if unsafe.Sizeof(b) != 1 {
+ throw("bad b")
+ }
+ if unsafe.Sizeof(c) != 2 {
+ throw("bad c")
+ }
+ if unsafe.Sizeof(d) != 2 {
+ throw("bad d")
+ }
+ if unsafe.Sizeof(e) != 4 {
+ throw("bad e")
+ }
+ if unsafe.Sizeof(f) != 4 {
+ throw("bad f")
+ }
+ if unsafe.Sizeof(g) != 8 {
+ throw("bad g")
+ }
+ if unsafe.Sizeof(h) != 8 {
+ throw("bad h")
+ }
+ if unsafe.Sizeof(i) != 4 {
+ throw("bad i")
+ }
+ if unsafe.Sizeof(j) != 8 {
+ throw("bad j")
+ }
+ if unsafe.Sizeof(k) != sys.PtrSize {
+ throw("bad k")
+ }
+ if unsafe.Sizeof(l) != sys.PtrSize {
+ throw("bad l")
+ }
+ if unsafe.Sizeof(x1) != 1 {
+ throw("bad unsafe.Sizeof x1")
+ }
+ if unsafe.Offsetof(y1.y) != 1 {
+ throw("bad offsetof y1.y")
+ }
+ if unsafe.Sizeof(y1) != 2 {
+ throw("bad unsafe.Sizeof y1")
+ }
+
+ if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
+ throw("bad timediv")
+ }
+
+ var z uint32
+ z = 1
+ if !atomic.Cas(&z, 1, 2) {
+ throw("cas1")
+ }
+ if z != 2 {
+ throw("cas2")
+ }
+
+ z = 4
+ if atomic.Cas(&z, 5, 6) {
+ throw("cas3")
+ }
+ if z != 4 {
+ throw("cas4")
+ }
+
+ z = 0xffffffff
+ if !atomic.Cas(&z, 0xffffffff, 0xfffffffe) {
+ throw("cas5")
+ }
+ if z != 0xfffffffe {
+ throw("cas6")
+ }
+
+ k = unsafe.Pointer(uintptr(0xfedcb123))
+ if sys.PtrSize == 8 {
+ k = unsafe.Pointer(uintptr(k) << 10)
+ }
+ if casp(&k, nil, nil) {
+ throw("casp1")
+ }
+ k1 = add(k, 1)
+ if !casp(&k, k, k1) {
+ throw("casp2")
+ }
+ if k != k1 {
+ throw("casp3")
+ }
+
+ m = [4]byte{1, 1, 1, 1}
+ atomic.Or8(&m[1], 0xf0)
+ if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
+ throw("atomicor8")
+ }
+
+ m = [4]byte{0xff, 0xff, 0xff, 0xff}
+ atomic.And8(&m[1], 0x1)
+ if m[0] != 0xff || m[1] != 0x1 || m[2] != 0xff || m[3] != 0xff {
+ throw("atomicand8")
+ }
+
+ *(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
+ if j == j {
+ throw("float64nan")
+ }
+ if !(j != j) {
+ throw("float64nan1")
+ }
+
+ *(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
+ if j == j1 {
+ throw("float64nan2")
+ }
+ if !(j != j1) {
+ throw("float64nan3")
+ }
+
+ *(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
+ if i == i {
+ throw("float32nan")
+ }
+ if i == i {
+ throw("float32nan1")
+ }
+
+ *(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
+ if i == i1 {
+ throw("float32nan2")
+ }
+ if i == i1 {
+ throw("float32nan3")
+ }
+
+ testAtomic64()
+
+ // if _FixedStack != round2(_FixedStack) {
+ // throw("FixedStack is not power-of-2")
+ // }
+
+ if !checkASM() {
+ throw("assembly checks failed")
+ }
+}
+
+type dbgVar struct {
+ name string
+ value *int32
+}
+
+// Holds variables parsed from GODEBUG env var,
+// except for "memprofilerate" since there is an
+// existing int var for that value, which may
+// already have an initial value.
+
+// For gccgo we use a named type so that the C code can see the
+// definition.
+type debugVars struct {
+ allocfreetrace int32
+ cgocheck int32
+ efence int32
+ gccheckmark int32
+ gcpacertrace int32
+ gcshrinkstackoff int32
+ gcstackbarrieroff int32
+ gcstackbarrierall int32
+ gcrescanstacks int32
+ gcstoptheworld int32
+ gctrace int32
+ invalidptr int32
+ sbrk int32
+ scavenge int32
+ scheddetail int32
+ schedtrace int32
+ wbshadow int32
+}
+
+var debug debugVars
+
+// For gccgo's C code.
+//extern runtime_setdebug
+func runtime_setdebug(*debugVars)
+
+var dbgvars = []dbgVar{
+ {"allocfreetrace", &debug.allocfreetrace},
+ {"cgocheck", &debug.cgocheck},
+ {"efence", &debug.efence},
+ {"gccheckmark", &debug.gccheckmark},
+ {"gcpacertrace", &debug.gcpacertrace},
+ {"gcshrinkstackoff", &debug.gcshrinkstackoff},
+ {"gcstackbarrieroff", &debug.gcstackbarrieroff},
+ {"gcstackbarrierall", &debug.gcstackbarrierall},
+ {"gcrescanstacks", &debug.gcrescanstacks},
+ {"gcstoptheworld", &debug.gcstoptheworld},
+ {"gctrace", &debug.gctrace},
+ {"invalidptr", &debug.invalidptr},
+ {"sbrk", &debug.sbrk},
+ {"scavenge", &debug.scavenge},
+ {"scheddetail", &debug.scheddetail},
+ {"schedtrace", &debug.schedtrace},
+ {"wbshadow", &debug.wbshadow},
+}
+
+func parsedebugvars() {
+ // defaults
+ debug.cgocheck = 1
+ debug.invalidptr = 1
+
+ for p := gogetenv("GODEBUG"); p != ""; {
+ field := ""
+ i := index(p, ",")
+ if i < 0 {
+ field, p = p, ""
+ } else {
+ field, p = p[:i], p[i+1:]
+ }
+ i = index(field, "=")
+ if i < 0 {
+ continue
+ }
+ key, value := field[:i], field[i+1:]
+
+ // Update MemProfileRate directly here since it
+ // is int, not int32, and should only be updated
+ // if specified in GODEBUG.
+ if key == "memprofilerate" {
+ if n, ok := atoi(value); ok {
+ MemProfileRate = n
+ }
+ } else {
+ for _, v := range dbgvars {
+ if v.name == key {
+ if n, ok := atoi32(value); ok {
+ *v.value = n
+ }
+ }
+ }
+ }
+ }
+
+ setTraceback(gogetenv("GOTRACEBACK"))
+ traceback_env = traceback_cache
+
+ if debug.gcrescanstacks == 0 {
+ // Without rescanning, there's no need for stack
+ // barriers.
+ debug.gcstackbarrieroff = 1
+ debug.gcstackbarrierall = 0
+ }
+
+ // if debug.gcstackbarrierall > 0 {
+ // firstStackBarrierOffset = 0
+ // }
+
+ // For cgocheck > 1, we turn on the write barrier at all times
+ // and check all pointer writes.
+ if debug.cgocheck > 1 {
+ writeBarrier.cgo = true
+ writeBarrier.enabled = true
+ }
+
+ // Tell the C code what the value is.
+ runtime_setdebug(&debug)
+}
+
+//go:linkname setTraceback runtime_debug.SetTraceback
+func setTraceback(level string) {
+ var t uint32
+ switch level {
+ case "none":
+ t = 0
+ case "single", "":
+ t = 1 << tracebackShift
+ case "all":
+ t = 1<<tracebackShift | tracebackAll
+ case "system":
+ t = 2<<tracebackShift | tracebackAll
+ case "crash":
+ t = 2<<tracebackShift | tracebackAll | tracebackCrash
+ default:
+ t = tracebackAll
+ if n, ok := atoi(level); ok && n == int(uint32(n)) {
+ t |= uint32(n) << tracebackShift
+ }
+ }
+ // when C owns the process, simply exit'ing the process on fatal errors
+ // and panics is surprising. Be louder and abort instead.
+ if islibrary || isarchive {
+ t |= tracebackCrash
+ }
+
+ t |= traceback_env
+
+ atomic.Store(&traceback_cache, t)
+}
+
+// Poor mans 64-bit division.
+// This is a very special function, do not use it if you are not sure what you are doing.
+// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
+// Handles overflow in a time-specific manner.
+//go:nosplit
+func timediv(v int64, div int32, rem *int32) int32 {
+ res := int32(0)
+ for bit := 30; bit >= 0; bit-- {
+ if v >= int64(div)<<uint(bit) {
+ v = v - (int64(div) << uint(bit))
+ res += 1 << uint(bit)
+ }
+ }
+ if v >= int64(div) {
+ if rem != nil {
+ *rem = 0
+ }
+ return 0x7fffffff
+ }
+ if rem != nil {
+ *rem = int32(v)
+ }
+ return res
+}
+
+// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
+
+//go:nosplit
+func acquirem() *m {
+ _g_ := getg()
+ _g_.m.locks++
+ return _g_.m
+}
+
+//go:nosplit
+func releasem(mp *m) {
+ // _g_ := getg()
+ mp.locks--
+ // if mp.locks == 0 && _g_.preempt {
+ // // restore the preemption request in case we've cleared it in newstack
+ // _g_.stackguard0 = stackPreempt
+ // }
+}
+
+//go:nosplit
+func gomcache() *mcache {
+ return getg().m.mcache
+}
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
new file mode 100644
index 0000000000..195d65bbd7
--- /dev/null
+++ b/libgo/go/runtime/runtime2.go
@@ -0,0 +1,797 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// defined constants
+const (
+ // G status
+ //
+ // Beyond indicating the general state of a G, the G status
+ // acts like a lock on the goroutine's stack (and hence its
+ // ability to execute user code).
+ //
+ // If you add to this list, add to the list
+ // of "okay during garbage collection" status
+ // in mgcmark.go too.
+
+ // _Gidle means this goroutine was just allocated and has not
+ // yet been initialized.
+ _Gidle = iota // 0
+
+ // _Grunnable means this goroutine is on a run queue. It is
+ // not currently executing user code. The stack is not owned.
+ _Grunnable // 1
+
+ // _Grunning means this goroutine may execute user code. The
+ // stack is owned by this goroutine. It is not on a run queue.
+ // It is assigned an M and a P.
+ _Grunning // 2
+
+ // _Gsyscall means this goroutine is executing a system call.
+ // It is not executing user code. The stack is owned by this
+ // goroutine. It is not on a run queue. It is assigned an M.
+ _Gsyscall // 3
+
+ // _Gwaiting means this goroutine is blocked in the runtime.
+ // It is not executing user code. It is not on a run queue,
+ // but should be recorded somewhere (e.g., a channel wait
+ // queue) so it can be ready()d when necessary. The stack is
+ // not owned *except* that a channel operation may read or
+ // write parts of the stack under the appropriate channel
+ // lock. Otherwise, it is not safe to access the stack after a
+ // goroutine enters _Gwaiting (e.g., it may get moved).
+ _Gwaiting // 4
+
+ // _Gmoribund_unused is currently unused, but hardcoded in gdb
+ // scripts.
+ _Gmoribund_unused // 5
+
+ // _Gdead means this goroutine is currently unused. It may be
+ // just exited, on a free list, or just being initialized. It
+ // is not executing user code. It may or may not have a stack
+ // allocated. The G and its stack (if any) are owned by the M
+ // that is exiting the G or that obtained the G from the free
+ // list.
+ _Gdead // 6
+
+ // _Genqueue_unused is currently unused.
+ _Genqueue_unused // 7
+
+ // _Gcopystack means this goroutine's stack is being moved. It
+ // is not executing user code and is not on a run queue. The
+ // stack is owned by the goroutine that put it in _Gcopystack.
+ _Gcopystack // 8
+
+ // _Gscan combined with one of the above states other than
+ // _Grunning indicates that GC is scanning the stack. The
+ // goroutine is not executing user code and the stack is owned
+ // by the goroutine that set the _Gscan bit.
+ //
+ // _Gscanrunning is different: it is used to briefly block
+ // state transitions while GC signals the G to scan its own
+ // stack. This is otherwise like _Grunning.
+ //
+ // atomicstatus&~Gscan gives the state the goroutine will
+ // return to when the scan completes.
+ _Gscan = 0x1000
+ _Gscanrunnable = _Gscan + _Grunnable // 0x1001
+ _Gscanrunning = _Gscan + _Grunning // 0x1002
+ _Gscansyscall = _Gscan + _Gsyscall // 0x1003
+ _Gscanwaiting = _Gscan + _Gwaiting // 0x1004
+)
+
+const (
+ // P status
+ _Pidle = iota
+ _Prunning // Only this P is allowed to change from _Prunning.
+ _Psyscall
+ _Pgcstop
+ _Pdead
+)
+
+// Mutual exclusion locks. In the uncontended case,
+// as fast as spin locks (just a few user-level instructions),
+// but on the contention path they sleep in the kernel.
+// A zeroed Mutex is unlocked (no need to initialize each lock).
+type mutex struct {
+ // Futex-based impl treats it as uint32 key,
+ // while sema-based impl as M* waitm.
+ // Used to be a union, but unions break precise GC.
+ key uintptr
+}
+
+// sleep and wakeup on one-time events.
+// before any calls to notesleep or notewakeup,
+// must call noteclear to initialize the Note.
+// then, exactly one thread can call notesleep
+// and exactly one thread can call notewakeup (once).
+// once notewakeup has been called, the notesleep
+// will return. future notesleep will return immediately.
+// subsequent noteclear must be called only after
+// previous notesleep has returned, e.g. it's disallowed
+// to call noteclear straight after notewakeup.
+//
+// notetsleep is like notesleep but wakes up after
+// a given number of nanoseconds even if the event
+// has not yet happened. if a goroutine uses notetsleep to
+// wake up early, it must wait to call noteclear until it
+// can be sure that no other goroutine is calling
+// notewakeup.
+//
+// notesleep/notetsleep are generally called on g0,
+// notetsleepg is similar to notetsleep but is called on user g.
+type note struct {
+ // Futex-based impl treats it as uint32 key,
+ // while sema-based impl as M* waitm.
+ // Used to be a union, but unions break precise GC.
+ key uintptr
+}
+
+type funcval struct {
+ fn uintptr
+ // variable-size, fn-specific data here
+}
+
+// The representation of a non-empty interface.
+// See comment in iface.go for more details on this struct.
+type iface struct {
+ tab unsafe.Pointer
+ data unsafe.Pointer
+}
+
+// The representation of an empty interface.
+// See comment in iface.go for more details on this struct.
+type eface struct {
+ _type *_type
+ data unsafe.Pointer
+}
+
+func efaceOf(ep *interface{}) *eface {
+ return (*eface)(unsafe.Pointer(ep))
+}
+
+// The guintptr, muintptr, and puintptr are all used to bypass write barriers.
+// It is particularly important to avoid write barriers when the current P has
+// been released, because the GC thinks the world is stopped, and an
+// unexpected write barrier would not be synchronized with the GC,
+// which can lead to a half-executed write barrier that has marked the object
+// but not queued it. If the GC skips the object and completes before the
+// queuing can occur, it will incorrectly free the object.
+//
+// We tried using special assignment functions invoked only when not
+// holding a running P, but then some updates to a particular memory
+// word went through write barriers and some did not. This breaks the
+// write barrier shadow checking mode, and it is also scary: better to have
+// a word that is completely ignored by the GC than to have one for which
+// only a few updates are ignored.
+//
+// Gs, Ms, and Ps are always reachable via true pointers in the
+// allgs, allm, and allp lists or (during allocation before they reach those lists)
+// from stack variables.
+
+// A guintptr holds a goroutine pointer, but typed as a uintptr
+// to bypass write barriers. It is used in the Gobuf goroutine state
+// and in scheduling lists that are manipulated without a P.
+//
+// The Gobuf.g goroutine pointer is almost always updated by assembly code.
+// In one of the few places it is updated by Go code - func save - it must be
+// treated as a uintptr to avoid a write barrier being emitted at a bad time.
+// Instead of figuring out how to emit the write barriers missing in the
+// assembly manipulation, we change the type of the field to uintptr,
+// so that it does not require write barriers at all.
+//
+// Goroutine structs are published in the allg list and never freed.
+// That will keep the goroutine structs from being collected.
+// There is never a time that Gobuf.g's contain the only references
+// to a goroutine: the publishing of the goroutine in allg comes first.
+// Goroutine pointers are also kept in non-GC-visible places like TLS,
+// so I can't see them ever moving. If we did want to start moving data
+// in the GC, we'd need to allocate the goroutine structs from an
+// alternate arena. Using guintptr doesn't make that problem any worse.
+type guintptr uintptr
+
+//go:nosplit
+func (gp guintptr) ptr() *g { return (*g)(unsafe.Pointer(gp)) }
+
+//go:nosplit
+func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) }
+
+//go:nosplit
+func (gp *guintptr) cas(old, new guintptr) bool {
+ return atomic.Casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
+}
+
+// setGNoWB performs *gp = new without a write barrier.
+// For times when it's impractical to use a guintptr.
+//go:nosplit
+//go:nowritebarrier
+func setGNoWB(gp **g, new *g) {
+ (*guintptr)(unsafe.Pointer(gp)).set(new)
+}
+
+type puintptr uintptr
+
+//go:nosplit
+func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) }
+
+//go:nosplit
+func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }
+
+type muintptr uintptr
+
+//go:nosplit
+func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) }
+
+//go:nosplit
+func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }
+
+// setMNoWB performs *mp = new without a write barrier.
+// For times when it's impractical to use an muintptr.
+//go:nosplit
+//go:nowritebarrier
+func setMNoWB(mp **m, new *m) {
+ (*muintptr)(unsafe.Pointer(mp)).set(new)
+}
+
+// sudog represents a g in a wait list, such as for sending/receiving
+// on a channel.
+//
+// sudog is necessary because the g ↔ synchronization object relation
+// is many-to-many. A g can be on many wait lists, so there may be
+// many sudogs for one g; and many gs may be waiting on the same
+// synchronization object, so there may be many sudogs for one object.
+//
+// sudogs are allocated from a special pool. Use acquireSudog and
+// releaseSudog to allocate and free them.
+type sudog struct {
+ // The following fields are protected by the hchan.lock of the
+ // channel this sudog is blocking on. shrinkstack depends on
+ // this.
+
+ g *g
+ selectdone *uint32 // CAS to 1 to win select race (may point to stack)
+ next *sudog
+ prev *sudog
+ elem unsafe.Pointer // data element (may point to stack)
+
+ // The following fields are never accessed concurrently.
+ // waitlink is only accessed by g.
+
+ acquiretime int64
+ releasetime int64
+ ticket uint32
+ waitlink *sudog // g.waiting list
+ c *hchan // channel
+}
+
+type gcstats struct {
+ // the struct must consist of only uint64's,
+ // because it is casted to uint64[].
+ nhandoff uint64
+ nhandoffcnt uint64
+ nprocyield uint64
+ nosyield uint64
+ nsleep uint64
+}
+
+/*
+Not used by gccgo.
+
+type libcall struct {
+ fn uintptr
+ n uintptr // number of parameters
+ args uintptr // parameters
+ r1 uintptr // return values
+ r2 uintptr
+ err uintptr // error number
+}
+
+*/
+
+/*
+Not used by gccgo.
+
+// describes how to handle callback
+type wincallbackcontext struct {
+ gobody unsafe.Pointer // go function to call
+ argsize uintptr // callback arguments size (in bytes)
+ restorestack uintptr // adjust stack on return by (in bytes) (386 only)
+ cleanstack bool
+}
+*/
+
+/*
+Not used by gccgo.
+
+// Stack describes a Go execution stack.
+// The bounds of the stack are exactly [lo, hi),
+// with no implicit data structures on either side.
+type stack struct {
+ lo uintptr
+ hi uintptr
+}
+
+// stkbar records the state of a G's stack barrier.
+type stkbar struct {
+ savedLRPtr uintptr // location overwritten by stack barrier PC
+ savedLRVal uintptr // value overwritten at savedLRPtr
+}
+*/
+
+type g struct {
+ // Stack parameters.
+ // stack describes the actual stack memory: [stack.lo, stack.hi).
+ // stackguard0 is the stack pointer compared in the Go stack growth prologue.
+ // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
+ // stackguard1 is the stack pointer compared in the C stack growth prologue.
+ // It is stack.lo+StackGuard on g0 and gsignal stacks.
+ // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
+ // Not for gccgo: stack stack // offset known to runtime/cgo
+ // Not for gccgo: stackguard0 uintptr // offset known to liblink
+ // Not for gccgo: stackguard1 uintptr // offset known to liblink
+
+ _panic *_panic // innermost panic - offset known to liblink
+ _defer *_defer // innermost defer
+ m *m // current m; offset known to arm liblink
+ // Not for gccgo: stackAlloc uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc)
+ // Not for gccgo: sched gobuf
+ syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
+ syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
+ // Not for gccgo: stkbar []stkbar // stack barriers, from low to high (see top of mstkbar.go)
+ // Not for gccgo: stkbarPos uintptr // index of lowest stack barrier not hit
+ // Not for gccgo: stktopsp uintptr // expected sp at top of stack, to check in traceback
+ param unsafe.Pointer // passed parameter on wakeup
+ atomicstatus uint32
+ // Not for gccgo: stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
+ goid int64
+ waitsince int64 // approx time when the g become blocked
+ waitreason string // if status==Gwaiting
+ schedlink guintptr
+ preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
+ paniconfault bool // panic (instead of crash) on unexpected fault address
+ preemptscan bool // preempted g does scan for gc
+ gcscandone bool // g has scanned stack; protected by _Gscan bit in status
+ gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; transition from true to false by calling queueRescan and false to true by calling dequeueRescan
+ throwsplit bool // must not split stack
+ raceignore int8 // ignore race detection events
+ sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
+ sysexitticks int64 // cputicks when syscall has returned (for tracing)
+ traceseq uint64 // trace event sequencer
+ tracelastp puintptr // last P emitted an event for this goroutine
+ lockedm *m
+ sig uint32
+ writebuf []byte
+ sigcode0 uintptr
+ sigcode1 uintptr
+ sigpc uintptr
+ gopc uintptr // pc of go statement that created this goroutine
+ startpc uintptr // pc of goroutine function
+ // Not for gccgo: racectx uintptr
+ waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
+ // Not for gccgo: cgoCtxt []uintptr // cgo traceback context
+
+ // Per-G GC state
+
+ // gcRescan is this G's index in work.rescan.list. If this is
+ // -1, this G is not on the rescan list.
+ //
+ // If gcphase != _GCoff and this G is visible to the garbage
+ // collector, writes to this are protected by work.rescan.lock.
+ gcRescan int32
+
+ // gcAssistBytes is this G's GC assist credit in terms of
+ // bytes allocated. If this is positive, then the G has credit
+ // to allocate gcAssistBytes bytes without assisting. If this
+ // is negative, then the G must correct this by performing
+ // scan work. We track this in bytes to make it fast to update
+ // and check for debt in the malloc hot path. The assist ratio
+ // determines how this corresponds to scan work debt.
+ gcAssistBytes int64
+
+ // Remaining fields are specific to gccgo.
+
+ exception unsafe.Pointer // current exception being thrown
+ isforeign bool // whether current exception is not from Go
+
+ // Fields that hold stack and context information if status is Gsyscall
+ gcstack unsafe.Pointer
+ gcstacksize uintptr
+ gcnextsegment unsafe.Pointer
+ gcnextsp unsafe.Pointer
+ gcinitialsp unsafe.Pointer
+ gcregs g_ucontext_t
+
+ entry unsafe.Pointer // goroutine entry point
+ fromgogo bool // whether entered from gogo function
+
+ issystem bool // do not output in stack dump
+ isbackground bool // ignore in deadlock detector
+
+ traceback *tracebackg // stack traceback buffer
+
+ context g_ucontext_t // saved context for setcontext
+ stackcontext [10]unsafe.Pointer // split-stack context
+}
+
+type m struct {
+ g0 *g // goroutine with scheduling stack
+ // Not for gccgo: morebuf gobuf // gobuf arg to morestack
+ // Not for gccgo: divmod uint32 // div/mod denominator for arm - known to liblink
+
+ // Fields not known to debuggers.
+ procid uint64 // for debuggers, but offset not hard-coded
+ gsignal *g // signal-handling g
+ sigmask sigset // storage for saved signal mask
+ // Not for gccgo: tls [6]uintptr // thread-local storage (for x86 extern register)
+ mstartfn uintptr
+ curg *g // current running goroutine
+ caughtsig guintptr // goroutine running during fatal signal
+ p puintptr // attached p for executing go code (nil if not executing go code)
+ nextp puintptr
+ id int32
+ mallocing int32
+ throwing int32
+ preemptoff string // if != "", keep curg running on this m
+ locks int32
+ softfloat int32
+ dying int32
+ profilehz int32
+ helpgc int32
+ spinning bool // m is out of work and is actively looking for work
+ blocked bool // m is blocked on a note
+ inwb bool // m is executing a write barrier
+ newSigstack bool // minit on C thread called sigaltstack
+ printlock int8
+ fastrand uint32
+ ncgocall uint64 // number of cgo calls in total
+ ncgo int32 // number of cgo calls currently in progress
+ // Not for gccgo: cgoCallersUse uint32 // if non-zero, cgoCallers in use temporarily
+ // Not for gccgo: cgoCallers *cgoCallers // cgo traceback if crashing in cgo call
+ park note
+ alllink *m // on allm
+ schedlink muintptr
+ mcache *mcache
+ lockedg *g
+ createstack [32]location // stack that created this thread.
+ // Not for gccgo: freglo [16]uint32 // d[i] lsb and f[i]
+ // Not for gccgo: freghi [16]uint32 // d[i] msb and f[i+16]
+ // Not for gccgo: fflag uint32 // floating point compare flags
+ locked uint32 // tracking for lockosthread
+ nextwaitm uintptr // next m waiting for lock
+ gcstats gcstats
+ needextram bool
+ traceback uint8
+ waitunlockf unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
+ waitlock unsafe.Pointer
+ waittraceev byte
+ waittraceskip int
+ startingtrace bool
+ syscalltick uint32
+ // Not for gccgo: thread uintptr // thread handle
+
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ // Not for gccgo: libcall libcall
+ // Not for gccgo: libcallpc uintptr // for cpu profiler
+ // Not for gccgo: libcallsp uintptr
+ // Not for gccgo: libcallg guintptr
+ // Not for gccgo: syscall libcall // stores syscall parameters on windows
+
+ mos mOS
+
+ // Remaining fields are specific to gccgo.
+
+ gsignalstack unsafe.Pointer // stack for gsignal
+ gsignalstacksize uintptr
+
+ dropextram bool // drop after call is done
+
+ gcing int32
+}
+
+type p struct {
+ lock mutex
+
+ id int32
+ status uint32 // one of pidle/prunning/...
+ link puintptr
+ schedtick uint32 // incremented on every scheduler call
+ syscalltick uint32 // incremented on every system call
+ m muintptr // back-link to associated m (nil if idle)
+ mcache *mcache
+ // Not for gccgo: racectx uintptr
+
+ // gccgo has only one size of defer.
+ deferpool []*_defer
+ deferpoolbuf [32]*_defer
+
+ // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
+ goidcache uint64
+ goidcacheend uint64
+
+ // Queue of runnable goroutines. Accessed without lock.
+ runqhead uint32
+ runqtail uint32
+ runq [256]guintptr
+ // runnext, if non-nil, is a runnable G that was ready'd by
+ // the current G and should be run next instead of what's in
+ // runq if there's time remaining in the running G's time
+ // slice. It will inherit the time left in the current time
+ // slice. If a set of goroutines is locked in a
+ // communicate-and-wait pattern, this schedules that set as a
+ // unit and eliminates the (potentially large) scheduling
+ // latency that otherwise arises from adding the ready'd
+ // goroutines to the end of the run queue.
+ runnext guintptr
+
+ // Available G's (status == Gdead)
+ gfree *g
+ gfreecnt int32
+
+ sudogcache []*sudog
+ sudogbuf [128]*sudog
+
+ tracebuf traceBufPtr
+
+ // Not for gccgo for now: palloc persistentAlloc // per-P to avoid mutex
+
+ // Per-P GC state
+ gcAssistTime int64 // Nanoseconds in assistAlloc
+ gcBgMarkWorker guintptr
+ gcMarkWorkerMode gcMarkWorkerMode
+
+ // gcw is this P's GC work buffer cache. The work buffer is
+ // filled by write barriers, drained by mutator assists, and
+ // disposed on certain GC state transitions.
+ // Not for gccgo for now: gcw gcWork
+
+ runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point
+
+ pad [sys.CacheLineSize]byte
+}
+
+const (
+ // The max value of GOMAXPROCS.
+ // There are no fundamental restrictions on the value.
+ _MaxGomaxprocs = 1 << 8
+)
+
+type schedt struct {
+ // accessed atomically. keep at top to ensure alignment on 32-bit systems.
+ goidgen uint64
+ lastpoll uint64
+
+ lock mutex
+
+ midle muintptr // idle m's waiting for work
+ nmidle int32 // number of idle m's waiting for work
+ nmidlelocked int32 // number of locked m's waiting for work
+ mcount int32 // number of m's that have been created
+ maxmcount int32 // maximum number of m's allowed (or die)
+
+ ngsys uint32 // number of system goroutines; updated atomically
+
+ pidle puintptr // idle p's
+ npidle uint32
+ nmspinning uint32 // See "Worker thread parking/unparking" comment in proc.go.
+
+ // Global runnable queue.
+ runqhead guintptr
+ runqtail guintptr
+ runqsize int32
+
+ // Global cache of dead G's.
+ gflock mutex
+ gfree *g
+ ngfree int32
+
+ // Central cache of sudog structs.
+ sudoglock mutex
+ sudogcache *sudog
+
+ // Central pool of available defer structs.
+ deferlock mutex
+ deferpool *_defer
+
+ gcwaiting uint32 // gc is waiting to run
+ stopwait int32
+ stopnote note
+ sysmonwait uint32
+ sysmonnote note
+
+ // safepointFn should be called on each P at the next GC
+ // safepoint if p.runSafePointFn is set.
+ safePointFn func(*p)
+ safePointWait int32
+ safePointNote note
+
+ profilehz int32 // cpu profiling rate
+
+ procresizetime int64 // nanotime() of last change to gomaxprocs
+ totaltime int64 // ∫gomaxprocs dt up to procresizetime
+}
+
+// The m.locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
+// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
+// External locks are not recursive; a second lock is silently ignored.
+// The upper bits of m.locked record the nesting depth of calls to lockOSThread
+// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
+// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
+// goroutine is holding the lock during the initialization phase.
+const (
+ _LockExternal = 1
+ _LockInternal = 2
+)
+
+const (
+ _SigNotify = 1 << iota // let signal.Notify have signal, even if from kernel
+ _SigKill // if signal.Notify doesn't take it, exit quietly
+ _SigThrow // if signal.Notify doesn't take it, exit loudly
+ _SigPanic // if the signal is from the kernel, panic
+ _SigDefault // if the signal isn't explicitly requested, don't monitor it
+ _SigHandling // our signal handler is registered
+ _SigGoExit // cause all runtime procs to exit (only used on Plan 9).
+ _SigSetStack // add SA_ONSTACK to libc handler
+ _SigUnblock // unblocked in minit
+)
+
+// Lock-free stack node.
+// // Also known to export_test.go.
+type lfnode struct {
+ next uint64
+ pushcnt uintptr
+}
+
+type forcegcstate struct {
+ lock mutex
+ g *g
+ idle uint32
+}
+
+// startup_random_data holds random bytes initialized at startup. These come from
+// the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.go or os_linux_386.go).
+var startupRandomData []byte
+
+// extendRandom extends the random numbers in r[:n] to the whole slice r.
+// Treats n<0 as n==0.
+func extendRandom(r []byte, n int) {
+ if n < 0 {
+ n = 0
+ }
+ for n < len(r) {
+ // Extend random bits using hash function & time seed
+ w := n
+ if w > 16 {
+ w = 16
+ }
+ h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w))
+ for i := 0; i < sys.PtrSize && n < len(r); i++ {
+ r[n] = byte(h)
+ n++
+ h >>= 8
+ }
+ }
+}
+
+// deferred subroutine calls
+// This is the gccgo version.
+type _defer struct {
+ // The next entry in the stack.
+ link *_defer
+
+ // The stack variable for the function which called this defer
+ // statement. This is set to true if we are returning from
+ // that function, false if we are panicing through it.
+ frame *bool
+
+ // The value of the panic stack when this function is
+ // deferred. This function can not recover this value from
+ // the panic stack. This can happen if a deferred function
+ // has a defer statement itself.
+ _panic *_panic
+
+ // The function to call.
+ pfn uintptr
+
+ // The argument to pass to the function.
+ arg unsafe.Pointer
+
+ // The return address that a recover thunk matches against.
+ // This is set by __go_set_defer_retaddr which is called by
+ // the thunks created by defer statements.
+ retaddr uintptr
+
+ // Set to true if a function created by reflect.MakeFunc is
+ // permitted to recover. The return address of such a
+ // function function will be somewhere in libffi, so __retaddr
+ // is not useful.
+ makefunccanrecover bool
+
+ // Set to true if this defer stack entry is not part of the
+ // defer pool.
+ special bool
+}
+
+// panics
+// This is the gccgo version.
+type _panic struct {
+ // The next entry in the stack.
+ link *_panic
+
+ // The value associated with this panic.
+ arg interface{}
+
+ // Whether this panic has been recovered.
+ recovered bool
+
+ // Whether this panic was pushed on the stack because of an
+ // exception thrown in some other language.
+ isforeign bool
+}
+
+const (
+ _TraceRuntimeFrames = 1 << iota // include frames for internal runtime functions.
+ _TraceTrap // the initial PC, SP are from a trap, not a return PC from a call
+ _TraceJumpStack // if traceback is on a systemstack, resume trace at g that called into it
+)
+
+// The maximum number of frames we print for a traceback
+const _TracebackMaxFrames = 100
+
+var (
+ // emptystring string
+
+ allglen uintptr
+ allm *m
+ allp [_MaxGomaxprocs + 1]*p
+ gomaxprocs int32
+ panicking uint32
+ ncpu int32
+ forcegc forcegcstate
+ sched schedt
+ newprocs int32
+
+ // Information about what cpu features are available.
+ // Set on startup in asm_{x86,amd64}.s.
+ cpuid_ecx uint32
+ support_aes bool
+
+ // cpuid_edx uint32
+ // cpuid_ebx7 uint32
+ // lfenceBeforeRdtsc bool
+ // support_avx bool
+ // support_avx2 bool
+ // support_bmi1 bool
+ // support_bmi2 bool
+
+// 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.
+var (
+ islibrary bool // -buildmode=c-shared
+ isarchive bool // -buildmode=c-archive
+)
+
+// Types that are only used by gccgo.
+
+// g_ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
+// _sizeof_ucontext_t is defined by mkrsysinfo.sh from <ucontext.h>.
+// On some systems getcontext and friends require a value that is
+// aligned to a 16-byte boundary. We implement this by increasing the
+// required size and picking an appropriate offset when we use the
+// array.
+type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
+
+// sigset is the Go version of the C type sigset_t.
+// _sigset_t is defined by the Makefile from <signal.h>.
+type sigset _sigset_t
diff --git a/libgo/go/runtime/runtime_mmap_test.go b/libgo/go/runtime/runtime_mmap_test.go
index 3995305052..0141e81d4a 100644
--- a/libgo/go/runtime/runtime_mmap_test.go
+++ b/libgo/go/runtime/runtime_mmap_test.go
@@ -1,22 +1,20 @@
-// Copyright 2016 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.
-// +build ignore
-
package runtime_test
import (
"runtime"
- "runtime/internal/sys"
"testing"
+ "unsafe"
)
// Test that the error value returned by mmap is positive, as that is
// what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects.
// See the uses of ENOMEM in sysMap in those files.
func TestMmapErrorSign(t *testing.T) {
- p := runtime.Mmap(nil, ^uintptr(0)&^(sys.PhysPageSize-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
+ p := runtime.Mmap(nil, ^uintptr(0)&^(runtime.GetPhysPageSize()-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
// The runtime.mmap function is nosplit, but t.Errorf is not.
// Reset the pointer so that we don't get an "invalid stack
@@ -24,7 +22,32 @@ func TestMmapErrorSign(t *testing.T) {
v := uintptr(p)
p = nil
- if v != runtime.ENOMEM {
- t.Errorf("mmap = %v, want %v", v, runtime.ENOMEM)
+ err := runtime.Errno()
+ if v != ^uintptr(0) || err != runtime.ENOMEM {
+ t.Errorf("mmap = %v, %v, want %v", v, err, runtime.ENOMEM)
+ }
+}
+
+func TestPhysPageSize(t *testing.T) {
+ // Mmap fails if the address is not page aligned, so we can
+ // use this to test if the page size is the true page size.
+ ps := runtime.GetPhysPageSize()
+
+ // Get a region of memory to play with. This should be page-aligned.
+ b := uintptr(runtime.Mmap(nil, 2*ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0))
+ if b == ^uintptr(0) {
+ t.Fatalf("Mmap: %v %v", b, runtime.Errno())
+ }
+
+ // Mmap should fail at a half page into the buffer.
+ err := uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps/2), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0))
+ if err != ^uintptr(0) {
+ t.Errorf("Mmap should have failed with half-page alignment %d, but succeeded: %v", ps/2, err)
+ }
+
+ // Mmap should succeed at a full page into the buffer.
+ err = uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0))
+ if err == ^uintptr(0) {
+ t.Errorf("Mmap at full-page alignment %d failed: %v %v", ps, err, runtime.Errno())
}
}
diff --git a/libgo/go/runtime/runtime_test.go b/libgo/go/runtime/runtime_test.go
index a520f56347..1f403a1705 100644
--- a/libgo/go/runtime/runtime_test.go
+++ b/libgo/go/runtime/runtime_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -8,6 +8,7 @@ import (
"io"
. "runtime"
"runtime/debug"
+ "strings"
"testing"
"unsafe"
)
@@ -104,7 +105,7 @@ func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
// of the larger addresses must themselves be invalid addresses.
// We might get unlucky and the OS might have mapped one of these
// addresses, but probably not: they're all in the first page, very high
-// adderesses that normally an OS would reserve for itself, or malformed
+// addresses that normally an OS would reserve for itself, or malformed
// addresses. Even so, we might have to remove one or two on different
// systems. We will see.
@@ -249,8 +250,8 @@ func TestBadOpen(t *testing.T) {
if GOOS == "windows" || GOOS == "nacl" {
t.Skip("skipping OS that doesn't have open/read/write/close")
}
- // make sure we get the correct error code if open fails. Same for
- // read/write/close on the resulting -1 fd. See issue 10052.
+ // make sure we get the correct error code if open fails. Same for
+ // read/write/close on the resulting -1 fd. See issue 10052.
nonfile := []byte("/notreallyafile")
fd := Open(&nonfile[0], 0, 0)
if fd != -1 {
@@ -331,3 +332,11 @@ func TestGoroutineProfileTrivial(t *testing.T) {
}
}
}
+
+func TestVersion(t *testing.T) {
+ // Test that version does not contain \r or \n.
+ vers := Version()
+ if strings.Contains(vers, "\r") || strings.Contains(vers, "\n") {
+ t.Fatalf("cr/nl in version: %q", vers)
+ }
+}
diff --git a/libgo/go/runtime/runtime_unix_test.go b/libgo/go/runtime/runtime_unix_test.go
index cfec3326bd..e91216365e 100644
--- a/libgo/go/runtime/runtime_unix_test.go
+++ b/libgo/go/runtime/runtime_unix_test.go
@@ -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.
diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go
new file mode 100644
index 0000000000..62c404949f
--- /dev/null
+++ b/libgo/go/runtime/select.go
@@ -0,0 +1,758 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// This file contains the implementation of Go select statements.
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname newselect runtime.newselect
+//go:linkname selectdefault runtime.selectdefault
+//go:linkname selectsend runtime.selectsend
+//go:linkname selectrecv runtime.selectrecv
+//go:linkname selectrecv2 runtime.selectrecv2
+//go:linkname selectgo runtime.selectgo
+
+const (
+ debugSelect = false
+
+ // scase.kind
+ caseRecv = iota
+ caseSend
+ caseDefault
+)
+
+// Select statement header.
+// Known to compiler.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+type hselect struct {
+ tcase uint16 // total count of scase[]
+ ncase uint16 // currently filled scase[]
+ pollorder *uint16 // case poll order
+ lockorder *uint16 // channel lock order
+ scase [1]scase // one per case (in order of appearance)
+}
+
+// Select case descriptor.
+// Known to compiler.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+type scase struct {
+ elem unsafe.Pointer // data element
+ c *hchan // chan
+ pc uintptr // return pc
+ kind uint16
+ index uint16 // case index
+ receivedp *bool // pointer to received bool (recv2)
+ releasetime int64
+}
+
+var (
+ chansendpc = funcPC(chansend)
+ chanrecvpc = funcPC(chanrecv)
+)
+
+func selectsize(size uintptr) uintptr {
+ selsize := unsafe.Sizeof(hselect{}) +
+ (size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
+ size*unsafe.Sizeof(*hselect{}.lockorder) +
+ size*unsafe.Sizeof(*hselect{}.pollorder)
+ return round(selsize, sys.Int64Align)
+}
+
+func newselect(sel *hselect, selsize int64, size int32) {
+ if selsize != int64(selectsize(uintptr(size))) {
+ print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
+ throw("bad select size")
+ }
+ if size != int32(uint16(size)) {
+ throw("select size too large")
+ }
+ sel.tcase = uint16(size)
+ sel.ncase = 0
+ sel.lockorder = (*uint16)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
+ sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)))
+
+ // For gccgo the temporary variable will not have been zeroed.
+ memclrNoHeapPointers(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])+uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)+uintptr(size)*unsafe.Sizeof(*hselect{}.pollorder))
+
+ if debugSelect {
+ print("newselect s=", sel, " size=", size, "\n")
+ }
+}
+
+func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
+ // nil cases do not compete
+ if c != nil {
+ selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, index)
+ }
+ return
+}
+
+// cut in half to give stack a chance to split
+func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, index int32) {
+ i := sel.ncase
+ if i >= sel.tcase {
+ throw("selectsend: too many cases")
+ }
+ sel.ncase = i + 1
+ cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
+
+ cas.pc = pc
+ cas.c = c
+ cas.index = uint16(index)
+ cas.kind = caseSend
+ cas.elem = elem
+
+ if debugSelect {
+ print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
+ }
+}
+
+func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
+ // nil cases do not compete
+ if c != nil {
+ selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, index)
+ }
+ return
+}
+
+func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool, index int32) {
+ // nil cases do not compete
+ if c != nil {
+ selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, index)
+ }
+ return
+}
+
+func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, index int32) {
+ i := sel.ncase
+ if i >= sel.tcase {
+ throw("selectrecv: too many cases")
+ }
+ sel.ncase = i + 1
+ cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
+ cas.pc = pc
+ cas.c = c
+ cas.index = uint16(index)
+ cas.kind = caseRecv
+ cas.elem = elem
+ cas.receivedp = received
+
+ if debugSelect {
+ print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
+ }
+}
+
+func selectdefault(sel *hselect, index int32) {
+ selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), index)
+ return
+}
+
+func selectdefaultImpl(sel *hselect, callerpc uintptr, index int32) {
+ i := sel.ncase
+ if i >= sel.tcase {
+ throw("selectdefault: too many cases")
+ }
+ sel.ncase = i + 1
+ cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
+ cas.pc = callerpc
+ cas.c = nil
+ cas.index = uint16(index)
+ cas.kind = caseDefault
+
+ if debugSelect {
+ print("selectdefault s=", sel, " pc=", hex(cas.pc), " index=", cas.index, "\n")
+ }
+}
+
+func sellock(scases []scase, lockorder []uint16) {
+ var c *hchan
+ for _, o := range lockorder {
+ c0 := scases[o].c
+ if c0 != nil && c0 != c {
+ c = c0
+ lock(&c.lock)
+ }
+ }
+}
+
+func selunlock(scases []scase, lockorder []uint16) {
+ // We must be very careful here to not touch sel after we have unlocked
+ // the last lock, because sel can be freed right after the last unlock.
+ // Consider the following situation.
+ // First M calls runtime·park() in runtime·selectgo() passing the sel.
+ // Once runtime·park() has unlocked the last lock, another M makes
+ // the G that calls select runnable again and schedules it for execution.
+ // When the G runs on another M, it locks all the locks and frees sel.
+ // Now if the first M touches sel, it will access freed memory.
+ n := len(scases)
+ r := 0
+ // skip the default case
+ if n > 0 && scases[lockorder[0]].c == nil {
+ r = 1
+ }
+ for i := n - 1; i >= r; i-- {
+ c := scases[lockorder[i]].c
+ if i > 0 && c == scases[lockorder[i-1]].c {
+ continue // will unlock it on the next iteration
+ }
+ unlock(&c.lock)
+ }
+}
+
+func selparkcommit(gp *g, _ unsafe.Pointer) bool {
+ // This must not access gp's stack (see gopark). In
+ // particular, it must not access the *hselect. That's okay,
+ // because by the time this is called, gp.waiting has all
+ // channels in lock order.
+ var lastc *hchan
+ for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+ if sg.c != lastc && lastc != nil {
+ // As soon as we unlock the channel, fields in
+ // any sudog with that channel may change,
+ // including c and waitlink. Since multiple
+ // sudogs may have the same channel, we unlock
+ // only after we've passed the last instance
+ // of a channel.
+ unlock(&lastc.lock)
+ }
+ lastc = sg.c
+ }
+ if lastc != nil {
+ unlock(&lastc.lock)
+ }
+ return true
+}
+
+func block() {
+ gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever
+}
+
+// selectgo implements the select statement.
+//
+// *sel is on the current goroutine's stack (regardless of any
+// escaping in selectgo).
+//
+// selectgo does not return. Instead, it overwrites its return PC and
+// returns directly to the triggered select case. Because of this, it
+// cannot appear at the top of a split stack.
+func selectgo(sel *hselect) int32 {
+ _, index := selectgoImpl(sel)
+ return int32(index)
+}
+
+// selectgoImpl returns scase.pc and scase.so for the select
+// case which fired.
+func selectgoImpl(sel *hselect) (uintptr, uint16) {
+ if debugSelect {
+ print("select: sel=", sel, "\n")
+ }
+
+ scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
+ scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
+
+ var t0 int64
+ if blockprofilerate > 0 {
+ t0 = cputicks()
+ for i := 0; i < int(sel.ncase); i++ {
+ scases[i].releasetime = -1
+ }
+ }
+
+ // The compiler rewrites selects that statically have
+ // only 0 or 1 cases plus default into simpler constructs.
+ // The only way we can end up with such small sel.ncase
+ // values here is for a larger select in which most channels
+ // have been nilled out. The general code handles those
+ // cases correctly, and they are rare enough not to bother
+ // optimizing (and needing to test).
+
+ // generate permuted order
+ pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
+ pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
+ for i := 1; i < int(sel.ncase); i++ {
+ j := int(fastrand()) % (i + 1)
+ pollorder[i] = pollorder[j]
+ pollorder[j] = uint16(i)
+ }
+
+ // sort the cases by Hchan address to get the locking order.
+ // simple heap sort, to guarantee n log n time and constant stack footprint.
+ lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+ lockorder := *(*[]uint16)(unsafe.Pointer(&lockslice))
+ for i := 0; i < int(sel.ncase); i++ {
+ j := i
+ // Start with the pollorder to permute cases on the same channel.
+ c := scases[pollorder[i]].c
+ for j > 0 && scases[lockorder[(j-1)/2]].c.sortkey() < c.sortkey() {
+ k := (j - 1) / 2
+ lockorder[j] = lockorder[k]
+ j = k
+ }
+ lockorder[j] = pollorder[i]
+ }
+ for i := int(sel.ncase) - 1; i >= 0; i-- {
+ o := lockorder[i]
+ c := scases[o].c
+ lockorder[i] = lockorder[0]
+ j := 0
+ for {
+ k := j*2 + 1
+ if k >= i {
+ break
+ }
+ if k+1 < i && scases[lockorder[k]].c.sortkey() < scases[lockorder[k+1]].c.sortkey() {
+ k++
+ }
+ if c.sortkey() < scases[lockorder[k]].c.sortkey() {
+ lockorder[j] = lockorder[k]
+ j = k
+ continue
+ }
+ break
+ }
+ lockorder[j] = o
+ }
+ /*
+ for i := 0; i+1 < int(sel.ncase); i++ {
+ if scases[lockorder[i]].c.sortkey() > scases[lockorder[i+1]].c.sortkey() {
+ print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n")
+ throw("select: broken sort")
+ }
+ }
+ */
+
+ // lock all the channels involved in the select
+ sellock(scases, lockorder)
+
+ var (
+ gp *g
+ done uint32
+ sg *sudog
+ c *hchan
+ k *scase
+ sglist *sudog
+ sgnext *sudog
+ qp unsafe.Pointer
+ nextp **sudog
+ )
+
+loop:
+ // pass 1 - look for something already waiting
+ var dfl *scase
+ var cas *scase
+ for i := 0; i < int(sel.ncase); i++ {
+ cas = &scases[pollorder[i]]
+ c = cas.c
+
+ switch cas.kind {
+ case caseRecv:
+ sg = c.sendq.dequeue()
+ if sg != nil {
+ goto recv
+ }
+ if c.qcount > 0 {
+ goto bufrecv
+ }
+ if c.closed != 0 {
+ goto rclose
+ }
+
+ case caseSend:
+ if raceenabled {
+ racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
+ }
+ if c.closed != 0 {
+ goto sclose
+ }
+ sg = c.recvq.dequeue()
+ if sg != nil {
+ goto send
+ }
+ if c.qcount < c.dataqsiz {
+ goto bufsend
+ }
+
+ case caseDefault:
+ dfl = cas
+ }
+ }
+
+ if dfl != nil {
+ selunlock(scases, lockorder)
+ cas = dfl
+ goto retc
+ }
+
+ // pass 2 - enqueue on all chans
+ gp = getg()
+ done = 0
+ if gp.waiting != nil {
+ throw("gp.waiting != nil")
+ }
+ nextp = &gp.waiting
+ for _, casei := range lockorder {
+ cas = &scases[casei]
+ c = cas.c
+ sg := acquireSudog()
+ sg.g = gp
+ // Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
+ sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
+ // No stack splits between assigning elem and enqueuing
+ // sg on gp.waiting where copystack can find it.
+ sg.elem = cas.elem
+ sg.releasetime = 0
+ if t0 != 0 {
+ sg.releasetime = -1
+ }
+ sg.c = c
+ // Construct waiting list in lock order.
+ *nextp = sg
+ nextp = &sg.waitlink
+
+ switch cas.kind {
+ case caseRecv:
+ c.recvq.enqueue(sg)
+
+ case caseSend:
+ c.sendq.enqueue(sg)
+ }
+ }
+
+ // wait for someone to wake us up
+ gp.param = nil
+ gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 2)
+
+ // While we were asleep, some goroutine came along and completed
+ // one of the cases in the select and woke us up (called ready).
+ // As part of that process, the goroutine did a cas on done above
+ // (aka *sg.selectdone for all queued sg) to win the right to
+ // complete the select. Now done = 1.
+ //
+ // If we copy (grow) our own stack, we will update the
+ // selectdone pointers inside the gp.waiting sudog list to point
+ // at the new stack. Another goroutine attempting to
+ // complete one of our (still linked in) select cases might
+ // see the new selectdone pointer (pointing at the new stack)
+ // before the new stack has real data; if the new stack has done = 0
+ // (before the old values are copied over), the goroutine might
+ // do a cas via sg.selectdone and incorrectly believe that it has
+ // won the right to complete the select, executing a second
+ // communication and attempting to wake us (call ready) again.
+ //
+ // Then things break.
+ //
+ // The best break is that the goroutine doing ready sees the
+ // _Gcopystack status and throws, as in #17007.
+ // A worse break would be for us to continue on, start running real code,
+ // block in a semaphore acquisition (sema.go), and have the other
+ // goroutine wake us up without having really acquired the semaphore.
+ // That would result in the goroutine spuriously running and then
+ // queue up another spurious wakeup when the semaphore really is ready.
+ // In general the situation can cascade until something notices the
+ // problem and causes a crash.
+ //
+ // A stack shrink does not have this problem, because it locks
+ // all the channels that are involved first, blocking out the
+ // possibility of a cas on selectdone.
+ //
+ // A stack growth before gopark above does not have this
+ // problem, because we hold those channel locks (released by
+ // selparkcommit).
+ //
+ // A stack growth after sellock below does not have this
+ // problem, because again we hold those channel locks.
+ //
+ // The only problem is a stack growth during sellock.
+ // To keep that from happening, run sellock on the system stack.
+ //
+ // It might be that we could avoid this if copystack copied the
+ // stack before calling adjustsudogs. In that case,
+ // syncadjustsudogs would need to recopy the tiny part that
+ // it copies today, resulting in a little bit of extra copying.
+ //
+ // An even better fix, not for the week before a release candidate,
+ // would be to put space in every sudog and make selectdone
+ // point at (say) the space in the first sudog.
+
+ systemstack(func() {
+ sellock(scases, lockorder)
+ })
+
+ sg = (*sudog)(gp.param)
+ gp.param = nil
+
+ // pass 3 - dequeue from unsuccessful chans
+ // otherwise they stack up on quiet channels
+ // record the successful case, if any.
+ // We singly-linked up the SudoGs in lock order.
+ cas = nil
+ sglist = gp.waiting
+ // Clear all elem before unlinking from gp.waiting.
+ for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
+ sg1.selectdone = nil
+ sg1.elem = nil
+ sg1.c = nil
+ }
+ gp.waiting = nil
+
+ for _, casei := range lockorder {
+ k = &scases[casei]
+ if sglist.releasetime > 0 {
+ k.releasetime = sglist.releasetime
+ }
+ if sg == sglist {
+ // sg has already been dequeued by the G that woke us up.
+ cas = k
+ } else {
+ c = k.c
+ if k.kind == caseSend {
+ c.sendq.dequeueSudoG(sglist)
+ } else {
+ c.recvq.dequeueSudoG(sglist)
+ }
+ }
+ sgnext = sglist.waitlink
+ sglist.waitlink = nil
+ releaseSudog(sglist)
+ sglist = sgnext
+ }
+
+ if cas == nil {
+ // We can wake up with gp.param == nil (so cas == nil)
+ // when a channel involved in the select has been closed.
+ // It is easiest to loop and re-run the operation;
+ // we'll see that it's now closed.
+ // Maybe some day we can signal the close explicitly,
+ // but we'd have to distinguish close-on-reader from close-on-writer.
+ // It's easiest not to duplicate the code and just recheck above.
+ // We know that something closed, and things never un-close,
+ // so we won't block again.
+ goto loop
+ }
+
+ c = cas.c
+
+ if debugSelect {
+ print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
+ }
+
+ if cas.kind == caseRecv {
+ if cas.receivedp != nil {
+ *cas.receivedp = true
+ }
+ }
+
+ if raceenabled {
+ if cas.kind == caseRecv && cas.elem != nil {
+ raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
+ } else if cas.kind == caseSend {
+ raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
+ }
+ }
+ if msanenabled {
+ if cas.kind == caseRecv && cas.elem != nil {
+ msanwrite(cas.elem, c.elemtype.size)
+ } else if cas.kind == caseSend {
+ msanread(cas.elem, c.elemtype.size)
+ }
+ }
+
+ selunlock(scases, lockorder)
+ goto retc
+
+bufrecv:
+ // can receive from buffer
+ if raceenabled {
+ if cas.elem != nil {
+ raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
+ }
+ raceacquire(chanbuf(c, c.recvx))
+ racerelease(chanbuf(c, c.recvx))
+ }
+ if msanenabled && cas.elem != nil {
+ msanwrite(cas.elem, c.elemtype.size)
+ }
+ if cas.receivedp != nil {
+ *cas.receivedp = true
+ }
+ qp = chanbuf(c, c.recvx)
+ if cas.elem != nil {
+ typedmemmove(c.elemtype, cas.elem, qp)
+ }
+ typedmemclr(c.elemtype, qp)
+ c.recvx++
+ if c.recvx == c.dataqsiz {
+ c.recvx = 0
+ }
+ c.qcount--
+ selunlock(scases, lockorder)
+ goto retc
+
+bufsend:
+ // can send to buffer
+ if raceenabled {
+ raceacquire(chanbuf(c, c.sendx))
+ racerelease(chanbuf(c, c.sendx))
+ raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
+ }
+ if msanenabled {
+ msanread(cas.elem, c.elemtype.size)
+ }
+ typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
+ c.sendx++
+ if c.sendx == c.dataqsiz {
+ c.sendx = 0
+ }
+ c.qcount++
+ selunlock(scases, lockorder)
+ goto retc
+
+recv:
+ // can receive from sleeping sender (sg)
+ recv(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
+ if debugSelect {
+ print("syncrecv: sel=", sel, " c=", c, "\n")
+ }
+ if cas.receivedp != nil {
+ *cas.receivedp = true
+ }
+ goto retc
+
+rclose:
+ // read at end of closed channel
+ selunlock(scases, lockorder)
+ if cas.receivedp != nil {
+ *cas.receivedp = false
+ }
+ if cas.elem != nil {
+ typedmemclr(c.elemtype, cas.elem)
+ }
+ if raceenabled {
+ raceacquire(unsafe.Pointer(c))
+ }
+ goto retc
+
+send:
+ // can send to a sleeping receiver (sg)
+ if raceenabled {
+ raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
+ }
+ if msanenabled {
+ msanread(cas.elem, c.elemtype.size)
+ }
+ send(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
+ if debugSelect {
+ print("syncsend: sel=", sel, " c=", c, "\n")
+ }
+ goto retc
+
+retc:
+ if cas.releasetime > 0 {
+ blockevent(cas.releasetime-t0, 2)
+ }
+ return cas.pc, cas.index
+
+sclose:
+ // send on closed channel
+ selunlock(scases, lockorder)
+ panic(plainError("send on closed channel"))
+}
+
+func (c *hchan) sortkey() uintptr {
+ // TODO(khr): if we have a moving garbage collector, we'll need to
+ // change this function.
+ return uintptr(unsafe.Pointer(c))
+}
+
+// A runtimeSelect is a single case passed to rselect.
+// This must match ../reflect/value.go:/runtimeSelect
+type runtimeSelect struct {
+ dir selectDir
+ typ unsafe.Pointer // channel type (not used here)
+ ch *hchan // channel
+ val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
+}
+
+// These values must match ../reflect/value.go:/SelectDir.
+type selectDir int
+
+const (
+ _ selectDir = iota
+ selectSend // case Chan <- Send
+ selectRecv // case <-Chan:
+ selectDefault // default
+)
+
+//go:linkname reflect_rselect reflect.rselect
+func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
+ // flagNoScan is safe here, because all objects are also referenced from cases.
+ size := selectsize(uintptr(len(cases)))
+ sel := (*hselect)(mallocgc(size, nil, true))
+ newselect(sel, int64(size), int32(len(cases)))
+ r := new(bool)
+ for i := range cases {
+ rc := &cases[i]
+ switch rc.dir {
+ case selectDefault:
+ selectdefaultImpl(sel, uintptr(i), 0)
+ case selectSend:
+ if rc.ch == nil {
+ break
+ }
+ selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
+ case selectRecv:
+ if rc.ch == nil {
+ break
+ }
+ selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
+ }
+ }
+
+ pc, _ := selectgoImpl(sel)
+ chosen = int(pc)
+ recvOK = *r
+ return
+}
+
+func (q *waitq) dequeueSudoG(sgp *sudog) {
+ x := sgp.prev
+ y := sgp.next
+ if x != nil {
+ if y != nil {
+ // middle of queue
+ x.next = y
+ y.prev = x
+ sgp.next = nil
+ sgp.prev = nil
+ return
+ }
+ // end of queue
+ x.next = nil
+ q.last = x
+ sgp.prev = nil
+ return
+ }
+ if y != nil {
+ // start of queue
+ y.prev = nil
+ q.first = y
+ sgp.next = nil
+ return
+ }
+
+ // x==y==nil. Either sgp is the only element in the queue,
+ // or it has already been removed. Use q.first to disambiguate.
+ if q.first == sgp {
+ q.first = nil
+ q.last = nil
+ }
+}
diff --git a/libgo/go/runtime/sema.go b/libgo/go/runtime/sema.go
new file mode 100644
index 0000000000..37318ff9d5
--- /dev/null
+++ b/libgo/go/runtime/sema.go
@@ -0,0 +1,385 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Semaphore implementation exposed to Go.
+// Intended use is provide a sleep and wakeup
+// primitive that can be used in the contended case
+// of other synchronization primitives.
+// Thus it targets the same goal as Linux's futex,
+// but it has much simpler semantics.
+//
+// That is, don't think of these as semaphores.
+// Think of them as a way to implement sleep and wakeup
+// such that every sleep is paired with a single wakeup,
+// even if, due to races, the wakeup happens before the sleep.
+//
+// See Mullender and Cox, ``Semaphores in Plan 9,''
+// http://swtch.com/semaphore.pdf
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// Asynchronous semaphore for sync.Mutex.
+
+type semaRoot struct {
+ lock mutex
+ head *sudog
+ tail *sudog
+ nwait uint32 // Number of waiters. Read w/o the lock.
+}
+
+// Prime to not correlate with any user patterns.
+const semTabSize = 251
+
+var semtable [semTabSize]struct {
+ root semaRoot
+ pad [sys.CacheLineSize - unsafe.Sizeof(semaRoot{})]byte
+}
+
+//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
+func sync_runtime_Semacquire(addr *uint32) {
+ semacquire(addr, semaBlockProfile)
+}
+
+//go:linkname net_runtime_Semacquire net.runtime_Semacquire
+func net_runtime_Semacquire(addr *uint32) {
+ semacquire(addr, semaBlockProfile)
+}
+
+//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
+func sync_runtime_Semrelease(addr *uint32) {
+ semrelease(addr)
+}
+
+//go:linkname sync_runtime_SemacquireMutex sync.runtime_SemacquireMutex
+func sync_runtime_SemacquireMutex(addr *uint32) {
+ semacquire(addr, semaBlockProfile|semaMutexProfile)
+}
+
+//go:linkname net_runtime_Semrelease net.runtime_Semrelease
+func net_runtime_Semrelease(addr *uint32) {
+ semrelease(addr)
+}
+
+func readyWithTime(s *sudog, traceskip int) {
+ if s.releasetime != 0 {
+ s.releasetime = cputicks()
+ }
+ goready(s.g, traceskip)
+}
+
+type semaProfileFlags int
+
+const (
+ semaBlockProfile semaProfileFlags = 1 << iota
+ semaMutexProfile
+)
+
+// Called from runtime.
+func semacquire(addr *uint32, profile semaProfileFlags) {
+ gp := getg()
+ if gp != gp.m.curg {
+ throw("semacquire not on the G stack")
+ }
+
+ // Easy case.
+ if cansemacquire(addr) {
+ return
+ }
+
+ // Harder case:
+ // increment waiter count
+ // try cansemacquire one more time, return if succeeded
+ // enqueue itself as a waiter
+ // sleep
+ // (waiter descriptor is dequeued by signaler)
+ s := acquireSudog()
+ root := semroot(addr)
+ t0 := int64(0)
+ s.releasetime = 0
+ s.acquiretime = 0
+ if profile&semaBlockProfile != 0 && blockprofilerate > 0 {
+ t0 = cputicks()
+ s.releasetime = -1
+ }
+ if profile&semaMutexProfile != 0 && mutexprofilerate > 0 {
+ if t0 == 0 {
+ t0 = cputicks()
+ }
+ s.acquiretime = t0
+ }
+ for {
+ lock(&root.lock)
+ // Add ourselves to nwait to disable "easy case" in semrelease.
+ atomic.Xadd(&root.nwait, 1)
+ // Check cansemacquire to avoid missed wakeup.
+ if cansemacquire(addr) {
+ atomic.Xadd(&root.nwait, -1)
+ unlock(&root.lock)
+ break
+ }
+ // Any semrelease after the cansemacquire knows we're waiting
+ // (we set nwait above), so go to sleep.
+ root.queue(addr, s)
+ goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
+ if cansemacquire(addr) {
+ break
+ }
+ }
+ if s.releasetime > 0 {
+ blockevent(s.releasetime-t0, 3)
+ }
+ releaseSudog(s)
+}
+
+func semrelease(addr *uint32) {
+ root := semroot(addr)
+ atomic.Xadd(addr, 1)
+
+ // Easy case: no waiters?
+ // This check must happen after the xadd, to avoid a missed wakeup
+ // (see loop in semacquire).
+ if atomic.Load(&root.nwait) == 0 {
+ return
+ }
+
+ // Harder case: search for a waiter and wake it.
+ lock(&root.lock)
+ if atomic.Load(&root.nwait) == 0 {
+ // The count is already consumed by another goroutine,
+ // so no need to wake up another goroutine.
+ unlock(&root.lock)
+ return
+ }
+ s := root.head
+ for ; s != nil; s = s.next {
+ if s.elem == unsafe.Pointer(addr) {
+ atomic.Xadd(&root.nwait, -1)
+ root.dequeue(s)
+ break
+ }
+ }
+ if s != nil {
+ if s.acquiretime != 0 {
+ t0 := cputicks()
+ for x := root.head; x != nil; x = x.next {
+ if x.elem == unsafe.Pointer(addr) {
+ x.acquiretime = t0
+ break
+ }
+ }
+ mutexevent(t0-s.acquiretime, 3)
+ }
+ }
+ unlock(&root.lock)
+ if s != nil { // May be slow, so unlock first
+ readyWithTime(s, 5)
+ }
+}
+
+func semroot(addr *uint32) *semaRoot {
+ return &semtable[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
+}
+
+func cansemacquire(addr *uint32) bool {
+ for {
+ v := atomic.Load(addr)
+ if v == 0 {
+ return false
+ }
+ if atomic.Cas(addr, v, v-1) {
+ return true
+ }
+ }
+}
+
+func (root *semaRoot) queue(addr *uint32, s *sudog) {
+ s.g = getg()
+ s.elem = unsafe.Pointer(addr)
+ s.next = nil
+ s.prev = root.tail
+ if root.tail != nil {
+ root.tail.next = s
+ } else {
+ root.head = s
+ }
+ root.tail = s
+}
+
+func (root *semaRoot) dequeue(s *sudog) {
+ if s.next != nil {
+ s.next.prev = s.prev
+ } else {
+ root.tail = s.prev
+ }
+ if s.prev != nil {
+ s.prev.next = s.next
+ } else {
+ root.head = s.next
+ }
+ s.elem = nil
+ s.next = nil
+ s.prev = nil
+}
+
+// notifyList is a ticket-based notification list used to implement sync.Cond.
+//
+// It must be kept in sync with the sync package.
+type notifyList struct {
+ // wait is the ticket number of the next waiter. It is atomically
+ // incremented outside the lock.
+ wait uint32
+
+ // notify is the ticket number of the next waiter to be notified. It can
+ // be read outside the lock, but is only written to with lock held.
+ //
+ // Both wait & notify can wrap around, and such cases will be correctly
+ // handled as long as their "unwrapped" difference is bounded by 2^31.
+ // For this not to be the case, we'd need to have 2^31+ goroutines
+ // blocked on the same condvar, which is currently not possible.
+ notify uint32
+
+ // List of parked waiters.
+ lock mutex
+ head *sudog
+ tail *sudog
+}
+
+// less checks if a < b, considering a & b running counts that may overflow the
+// 32-bit range, and that their "unwrapped" difference is always less than 2^31.
+func less(a, b uint32) bool {
+ return int32(a-b) < 0
+}
+
+// notifyListAdd adds the caller to a notify list such that it can receive
+// notifications. The caller must eventually call notifyListWait to wait for
+// such a notification, passing the returned ticket number.
+//go:linkname notifyListAdd sync.runtime_notifyListAdd
+func notifyListAdd(l *notifyList) uint32 {
+ // This may be called concurrently, for example, when called from
+ // sync.Cond.Wait while holding a RWMutex in read mode.
+ return atomic.Xadd(&l.wait, 1) - 1
+}
+
+// notifyListWait waits for a notification. If one has been sent since
+// notifyListAdd was called, it returns immediately. Otherwise, it blocks.
+//go:linkname notifyListWait sync.runtime_notifyListWait
+func notifyListWait(l *notifyList, t uint32) {
+ lock(&l.lock)
+
+ // Return right away if this ticket has already been notified.
+ if less(t, l.notify) {
+ unlock(&l.lock)
+ return
+ }
+
+ // Enqueue itself.
+ s := acquireSudog()
+ s.g = getg()
+ s.ticket = t
+ s.releasetime = 0
+ t0 := int64(0)
+ if blockprofilerate > 0 {
+ t0 = cputicks()
+ s.releasetime = -1
+ }
+ if l.tail == nil {
+ l.head = s
+ } else {
+ l.tail.next = s
+ }
+ l.tail = s
+ goparkunlock(&l.lock, "semacquire", traceEvGoBlockCond, 3)
+ if t0 != 0 {
+ blockevent(s.releasetime-t0, 2)
+ }
+ releaseSudog(s)
+}
+
+// notifyListNotifyAll notifies all entries in the list.
+//go:linkname notifyListNotifyAll sync.runtime_notifyListNotifyAll
+func notifyListNotifyAll(l *notifyList) {
+ // Fast-path: if there are no new waiters since the last notification
+ // we don't need to acquire the lock.
+ if atomic.Load(&l.wait) == atomic.Load(&l.notify) {
+ return
+ }
+
+ // Pull the list out into a local variable, waiters will be readied
+ // outside the lock.
+ lock(&l.lock)
+ s := l.head
+ l.head = nil
+ l.tail = nil
+
+ // Update the next ticket to be notified. We can set it to the current
+ // value of wait because any previous waiters are already in the list
+ // or will notice that they have already been notified when trying to
+ // add themselves to the list.
+ atomic.Store(&l.notify, atomic.Load(&l.wait))
+ unlock(&l.lock)
+
+ // Go through the local list and ready all waiters.
+ for s != nil {
+ next := s.next
+ s.next = nil
+ readyWithTime(s, 4)
+ s = next
+ }
+}
+
+// notifyListNotifyOne notifies one entry in the list.
+//go:linkname notifyListNotifyOne sync.runtime_notifyListNotifyOne
+func notifyListNotifyOne(l *notifyList) {
+ // Fast-path: if there are no new waiters since the last notification
+ // we don't need to acquire the lock at all.
+ if atomic.Load(&l.wait) == atomic.Load(&l.notify) {
+ return
+ }
+
+ lock(&l.lock)
+
+ // Re-check under the lock if we need to do anything.
+ t := l.notify
+ if t == atomic.Load(&l.wait) {
+ unlock(&l.lock)
+ return
+ }
+
+ // Update the next notify ticket number, and try to find the G that
+ // needs to be notified. If it hasn't made it to the list yet we won't
+ // find it, but it won't park itself once it sees the new notify number.
+ atomic.Store(&l.notify, t+1)
+ for p, s := (*sudog)(nil), l.head; s != nil; p, s = s, s.next {
+ if s.ticket == t {
+ n := s.next
+ if p != nil {
+ p.next = n
+ } else {
+ l.head = n
+ }
+ if n == nil {
+ l.tail = p
+ }
+ unlock(&l.lock)
+ s.next = nil
+ readyWithTime(s, 4)
+ return
+ }
+ }
+ unlock(&l.lock)
+}
+
+//go:linkname notifyListCheck sync.runtime_notifyListCheck
+func notifyListCheck(sz uintptr) {
+ if sz != unsafe.Sizeof(notifyList{}) {
+ print("runtime: bad notifyList size - sync=", sz, " runtime=", unsafe.Sizeof(notifyList{}), "\n")
+ throw("bad notifyList size")
+ }
+}
diff --git a/libgo/go/runtime/signal2_unix.go b/libgo/go/runtime/signal2_unix.go
deleted file mode 100644
index 3fe625f83c..0000000000
--- a/libgo/go/runtime/signal2_unix.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-package runtime
-
-import "unsafe"
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-// Determines if the signal should be handled by Go and if not, forwards the
-// signal to the handler that was installed before Go's. Returns whether the
-// signal was forwarded.
-// This is called by the signal handler, and the world may be stopped.
-//go:nosplit
-//go:nowritebarrierrec
-func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
- if sig >= uint32(len(sigtable)) {
- return false
- }
- fwdFn := fwdSig[sig]
-
- if !signalsOK {
- // The only way we can get here is if we are in a
- // library or archive, we installed a signal handler
- // at program startup, but the Go runtime has not yet
- // been initialized.
- if fwdFn == _SIG_DFL {
- dieFromSignal(int32(sig))
- } else {
- sigfwd(fwdFn, sig, info, ctx)
- }
- return true
- }
-
- flags := sigtable[sig].flags
-
- // If there is no handler to forward to, no need to forward.
- if fwdFn == _SIG_DFL {
- return false
- }
-
- // If we aren't handling the signal, forward it.
- if flags&_SigHandling == 0 {
- sigfwd(fwdFn, sig, info, ctx)
- return true
- }
-
- // Only forward synchronous signals.
- c := &sigctxt{info, ctx}
- if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
- return false
- }
- // Determine if the signal occurred inside Go code. We test that:
- // (1) we were in a goroutine (i.e., m.curg != nil), and
- // (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
- g := getg()
- if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
- return false
- }
- // Signal not handled by Go, forward it.
- if fwdFn != _SIG_IGN {
- sigfwd(fwdFn, sig, info, ctx)
- }
- return true
-}
diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go
new file mode 100644
index 0000000000..b4257c9f97
--- /dev/null
+++ b/libgo/go/runtime/signal_gccgo.go
@@ -0,0 +1,144 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// Functions for gccgo to support signal handling. In the gc runtime
+// these are written in OS-specific files and in assembler.
+
+//extern sigaction
+func sigaction(signum uint32, act *_sigaction, oact *_sigaction) int32
+
+//extern sigprocmask
+func sigprocmask(how int32, set *sigset, oldset *sigset) int32
+
+//extern sigfillset
+func sigfillset(set *sigset) int32
+
+//extern sigemptyset
+func sigemptyset(set *sigset) int32
+
+//extern sigaddset
+func c_sigaddset(set *sigset, signum uint32) int32
+
+//extern sigdelset
+func c_sigdelset(set *sigset, signum uint32) int32
+
+//extern sigaltstack
+func sigaltstack(ss *_stack_t, oss *_stack_t) int32
+
+//extern raise
+func raise(sig uint32) int32
+
+//extern getpid
+func getpid() _pid_t
+
+//extern kill
+func kill(pid _pid_t, sig uint32) int32
+
+//extern setitimer
+func setitimer(which int32, new *_itimerval, old *_itimerval) int32
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+type sigctxt struct {
+ info *_siginfo_t
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) sigcode() uint64 {
+ if c.info == nil {
+ // This can happen on Solaris 10. We don't know the
+ // code, just avoid a misleading value.
+ return _SI_USER + 1
+ }
+ return uint64(c.info.si_code)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i uint32, fn uintptr) {
+ var sa _sigaction
+ sa.sa_flags = _SA_SIGINFO | _SA_RESTART
+
+ // For gccgo we do not set SA_ONSTACK for a signal that can
+ // cause a panic. Instead, we trust that the split stack has
+ // enough room to start the signal handler. This is because
+ // otherwise we have no good way to switch back to the
+ // original stack before panicing.
+ if sigtable[i].flags&_SigPanic == 0 {
+ sa.sa_flags |= _SA_ONSTACK
+ }
+
+ sigfillset((*sigset)(unsafe.Pointer(&sa.sa_mask)))
+ setSigactionHandler(&sa, fn)
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i uint32) {
+ var sa _sigaction
+ sigaction(i, nil, &sa)
+ handler := getSigactionHandler(&sa)
+ if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
+ return
+ }
+ if sigtable[i].flags&_SigPanic != 0 {
+ return
+ }
+ sa.sa_flags |= _SA_ONSTACK
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i uint32) uintptr {
+ var sa _sigaction
+ if sigaction(i, nil, &sa) < 0 {
+ // On GNU/Linux glibc rejects attempts to call
+ // sigaction with signal 32 (SIGCANCEL) or 33 (SIGSETXID).
+ if GOOS == "linux" && (i == 32 || i == 33) {
+ return _SIG_DFL
+ }
+ throw("sigaction read failure")
+ }
+ return getSigactionHandler(&sa)
+}
+
+func signalstack(p unsafe.Pointer, n uintptr)
+
+//go:nosplit
+//go:nowritebarrierrec
+func raiseproc(sig uint32) {
+ kill(getpid(), sig)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigfwd(fn uintptr, sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
+ f1 := [1]uintptr{fn}
+ f2 := &f1
+ f3 := *(*func(uint32, *_siginfo_t, unsafe.Pointer))(unsafe.Pointer(&f2))
+ f3(sig, info, ctx)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigaddset(mask *sigset, i int) {
+ c_sigaddset(mask, uint32(i))
+}
+
+func sigdelset(mask *sigset, i int) {
+ c_sigdelset(mask, uint32(i))
+}
diff --git a/libgo/go/runtime/signal_linux_mips64x.go b/libgo/go/runtime/signal_linux_mips64x.go
deleted file mode 100644
index 671b9167b8..0000000000
--- a/libgo/go/runtime/signal_linux_mips64x.go
+++ /dev/null
@@ -1,70 +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 linux
-// +build mips64 mips64le
-
-package runtime
-
-import (
- "runtime/internal/sys"
- "unsafe"
-)
-
-type sigctxt struct {
- info *siginfo
- ctxt unsafe.Pointer
-}
-
-func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint64 { return c.regs().sc_regs[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().sc_regs[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().sc_regs[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().sc_regs[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().sc_regs[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().sc_regs[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().sc_regs[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().sc_regs[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().sc_regs[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().sc_regs[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().sc_regs[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().sc_regs[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().sc_regs[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().sc_regs[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().sc_regs[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().sc_regs[15] }
-func (c *sigctxt) r16() uint64 { return c.regs().sc_regs[16] }
-func (c *sigctxt) r17() uint64 { return c.regs().sc_regs[17] }
-func (c *sigctxt) r18() uint64 { return c.regs().sc_regs[18] }
-func (c *sigctxt) r19() uint64 { return c.regs().sc_regs[19] }
-func (c *sigctxt) r20() uint64 { return c.regs().sc_regs[20] }
-func (c *sigctxt) r21() uint64 { return c.regs().sc_regs[21] }
-func (c *sigctxt) r22() uint64 { return c.regs().sc_regs[22] }
-func (c *sigctxt) r23() uint64 { return c.regs().sc_regs[23] }
-func (c *sigctxt) r24() uint64 { return c.regs().sc_regs[24] }
-func (c *sigctxt) r25() uint64 { return c.regs().sc_regs[25] }
-func (c *sigctxt) r26() uint64 { return c.regs().sc_regs[26] }
-func (c *sigctxt) r27() uint64 { return c.regs().sc_regs[27] }
-func (c *sigctxt) r28() uint64 { return c.regs().sc_regs[28] }
-func (c *sigctxt) r29() uint64 { return c.regs().sc_regs[29] }
-func (c *sigctxt) r30() uint64 { return c.regs().sc_regs[30] }
-func (c *sigctxt) r31() uint64 { return c.regs().sc_regs[31] }
-func (c *sigctxt) sp() uint64 { return c.regs().sc_regs[29] }
-func (c *sigctxt) pc() uint64 { return c.regs().sc_pc }
-func (c *sigctxt) link() uint64 { return c.regs().sc_regs[31] }
-func (c *sigctxt) lo() uint64 { return c.regs().sc_mdlo }
-func (c *sigctxt) hi() uint64 { return c.regs().sc_mdhi }
-
-func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
-func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
-
-func (c *sigctxt) set_r30(x uint64) { c.regs().sc_regs[30] = x }
-func (c *sigctxt) set_pc(x uint64) { c.regs().sc_pc = x }
-func (c *sigctxt) set_sp(x uint64) { c.regs().sc_regs[29] = x }
-func (c *sigctxt) set_link(x uint64) { c.regs().sc_regs[31] = x }
-
-func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
-func (c *sigctxt) set_sigaddr(x uint64) {
- *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x)
-}
diff --git a/libgo/go/runtime/signal_mips64x.go b/libgo/go/runtime/signal_mips64x.go
deleted file mode 100644
index 77c27148e8..0000000000
--- a/libgo/go/runtime/signal_mips64x.go
+++ /dev/null
@@ -1,188 +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 linux
-// +build mips64 mips64le
-
-package runtime
-
-import (
- "runtime/internal/sys"
- "unsafe"
-)
-
-func dumpregs(c *sigctxt) {
- print("r0 ", hex(c.r0()), "\t")
- print("r1 ", hex(c.r1()), "\n")
- print("r2 ", hex(c.r2()), "\t")
- print("r3 ", hex(c.r3()), "\n")
- print("r4 ", hex(c.r4()), "\t")
- print("r5 ", hex(c.r5()), "\n")
- print("r6 ", hex(c.r6()), "\t")
- print("r7 ", hex(c.r7()), "\n")
- print("r8 ", hex(c.r8()), "\t")
- print("r9 ", hex(c.r9()), "\n")
- print("r10 ", hex(c.r10()), "\t")
- print("r11 ", hex(c.r11()), "\n")
- print("r12 ", hex(c.r12()), "\t")
- print("r13 ", hex(c.r13()), "\n")
- print("r14 ", hex(c.r14()), "\t")
- print("r15 ", hex(c.r15()), "\n")
- print("r16 ", hex(c.r16()), "\t")
- print("r17 ", hex(c.r17()), "\n")
- print("r18 ", hex(c.r18()), "\t")
- print("r19 ", hex(c.r19()), "\n")
- print("r20 ", hex(c.r20()), "\t")
- print("r21 ", hex(c.r21()), "\n")
- print("r22 ", hex(c.r22()), "\t")
- print("r23 ", hex(c.r23()), "\n")
- print("r24 ", hex(c.r24()), "\t")
- print("r25 ", hex(c.r25()), "\n")
- print("r26 ", hex(c.r26()), "\t")
- print("r27 ", hex(c.r27()), "\n")
- print("r28 ", hex(c.r28()), "\t")
- print("r29 ", hex(c.r29()), "\n")
- print("r30 ", hex(c.r30()), "\t")
- print("r31 ", hex(c.r31()), "\n")
- print("pc ", hex(c.pc()), "\t")
- print("link ", hex(c.link()), "\n")
- print("lo ", hex(c.lo()), "\t")
- print("hi ", hex(c.hi()), "\n")
-}
-
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
-//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
- return
- }
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.sigaddr())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange link, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LINK to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - sys.PtrSize
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
-
- pc := uintptr(gp.sigpc)
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_link(uint64(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
- c.set_pc(uint64(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
- }
-
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
- }
-
- exit(2)
-}
diff --git a/libgo/go/runtime/signal_sighandler.go b/libgo/go/runtime/signal_sighandler.go
new file mode 100644
index 0000000000..279001b154
--- /dev/null
+++ b/libgo/go/runtime/signal_sighandler.go
@@ -0,0 +1,133 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// crashing is the number of m's we have waited for when implementing
+// GOTRACEBACK=crash when a signal is received.
+var crashing int32
+
+// sighandler is invoked when a signal occurs. The global g will be
+// set to a gsignal goroutine and we will be running on the alternate
+// signal stack. The parameter g will be the value of the global g
+// when the signal occurred. The sig, info, and ctxt parameters are
+// from the system signal handler: they are the parameters passed when
+// the SA is passed to the sigaction system call.
+//
+// The garbage collector may have stopped the world, so write barriers
+// are not allowed.
+//
+//go:nowritebarrierrec
+func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof()
+ return
+ }
+
+ sigfault, sigpc := getSiginfo(info, ctxt)
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Emulate gc by passing arguments out of band,
+ // although we don't really have to.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = sigfault
+ gp.sigpc = sigpc
+
+ setg(gp)
+
+ // All signals were blocked due to the sigaction mask;
+ // unblock them.
+ var set sigset
+ sigfillset(&set)
+ sigprocmask(_SIG_UNBLOCK, &set, nil)
+
+ sigpanic()
+ throw("sigpanic returned")
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if c.sigcode() == _SI_USER && signal_ignored(sig) {
+ return
+ }
+
+ if flags&_SigKill != 0 {
+ dieFromSignal(sig)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig.set(gp)
+
+ if crashing == 0 {
+ startpanic()
+ }
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(sigpc), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ level, _, docrash := gotraceback()
+ if level > 0 {
+ goroutineheader(gp)
+ traceback(0)
+ if crashing == 0 {
+ tracebackothers(gp)
+ print("\n")
+ }
+ dumpregs(info, ctxt)
+ }
+
+ if docrash {
+ crashing++
+ if crashing < sched.mcount {
+ // There are other m's that need to dump their stacks.
+ // Relay SIGQUIT to the next m by sending it to the current process.
+ // All m's that have already received SIGQUIT have signal masks blocking
+ // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+ // When the last m receives the SIGQUIT, it will fall through to the call to
+ // crash below. Just in case the relaying gets botched, each m involved in
+ // the relay sleeps for 5 seconds and then does the crash/exit itself.
+ // In expected operation, the last m has received the SIGQUIT and run
+ // crash/exit and the process is gone, all long before any of the
+ // 5-second sleeps have finished.
+ print("\n-----\n\n")
+ raiseproc(_SIGQUIT)
+ usleep(5 * 1000 * 1000)
+ }
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/libgo/go/runtime/signal_sigtramp.go b/libgo/go/runtime/signal_sigtramp.go
deleted file mode 100644
index 00ab03846e..0000000000
--- a/libgo/go/runtime/signal_sigtramp.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build dragonfly linux netbsd
-
-package runtime
-
-import "unsafe"
-
-// Continuation of the (assembly) sigtramp() logic.
-// This may be called with the world stopped.
-//go:nosplit
-//go:nowritebarrierrec
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- return
- }
- g := getg()
- if g == nil {
- badsignal(uintptr(sig))
- return
- }
-
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st sigaltstackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
- }
- 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.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
- setg(g.m.gsignal)
- sighandler(sig, info, ctx, g)
- setg(g)
-}
diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go
new file mode 100644
index 0000000000..13b79305fd
--- /dev/null
+++ b/libgo/go/runtime/signal_unix.go
@@ -0,0 +1,606 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// For gccgo's C code to call:
+//go:linkname initsig runtime.initsig
+//go:linkname crash runtime.crash
+//go:linkname resetcpuprofiler runtime.resetcpuprofiler
+//go:linkname sigtrampgo runtime.sigtrampgo
+
+//go:linkname os_sigpipe os.sigpipe
+func os_sigpipe() {
+ systemstack(sigpipe)
+}
+
+func signame(sig uint32) string {
+ if sig >= uint32(len(sigtable)) {
+ return ""
+ }
+ return sigtable[sig].name
+}
+
+const (
+ _SIG_DFL uintptr = 0
+ _SIG_IGN uintptr = 1
+)
+
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Darwin and Linux.
+var fwdSig [_NSIG]uintptr
+
+// channels for synchronizing signal mask updates with the signal mask
+// thread
+var (
+ disableSigChan chan uint32
+ enableSigChan chan uint32
+ maskUpdatedChan chan struct{}
+)
+
+func init() {
+ // _NSIG is the number of signals on this operating system.
+ // sigtable should describe what to do for all the possible signals.
+ if len(sigtable) != _NSIG {
+ print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
+ throw("bad sigtable len")
+ }
+}
+
+var signalsOK bool
+
+// Initialize signals.
+// Called by libpreinit so runtime may not be initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func initsig(preinit bool) {
+ if preinit {
+ // preinit is only passed as true if isarchive should be true.
+ isarchive = true
+ }
+
+ if !preinit {
+ // It's now OK for signal handlers to run.
+ signalsOK = true
+ }
+
+ // For c-archive/c-shared this is called by libpreinit with
+ // preinit == true.
+ if (isarchive || islibrary) && !preinit {
+ return
+ }
+
+ for i := uint32(0); i < _NSIG; i++ {
+ t := &sigtable[i]
+ if t.flags == 0 || t.flags&_SigDefault != 0 {
+ continue
+ }
+ fwdSig[i] = getsig(i)
+
+ if !sigInstallGoHandler(i) {
+ // Even if we are not installing a signal handler,
+ // set SA_ONSTACK if necessary.
+ if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
+ setsigstack(i)
+ }
+ continue
+ }
+
+ t.flags |= _SigHandling
+ setsig(i, getSigtramp())
+ }
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigInstallGoHandler(sig uint32) bool {
+ // For some signals, we respect an inherited SIG_IGN handler
+ // rather than insist on installing our own default handler.
+ // Even these signals can be fetched using the os/signal package.
+ switch sig {
+ case _SIGHUP, _SIGINT:
+ if fwdSig[sig] == _SIG_IGN {
+ return false
+ }
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigSetStack != 0 {
+ return false
+ }
+
+ // When built using c-archive or c-shared, only install signal
+ // handlers for synchronous signals.
+ if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
+ return false
+ }
+
+ return true
+}
+
+func sigenable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ enableSigChan <- sig
+ <-maskUpdatedChan
+ if t.flags&_SigHandling == 0 {
+ t.flags |= _SigHandling
+ fwdSig[sig] = getsig(sig)
+ setsig(sig, getSigtramp())
+ }
+ }
+}
+
+func sigdisable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ disableSigChan <- sig
+ <-maskUpdatedChan
+
+ // If initsig does not install a signal handler for a
+ // signal, then to go back to the state before Notify
+ // we should remove the one we installed.
+ if !sigInstallGoHandler(sig) {
+ t.flags &^= _SigHandling
+ setsig(sig, fwdSig[sig])
+ }
+ }
+}
+
+func sigignore(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ t.flags &^= _SigHandling
+ setsig(sig, _SIG_IGN)
+ }
+}
+
+func resetcpuprofiler(hz int32) {
+ var it _itimerval
+ if hz == 0 {
+ setitimer(_ITIMER_PROF, &it, nil)
+ } else {
+ it.it_interval.tv_sec = 0
+ it.it_interval.set_usec(1000000 / hz)
+ it.it_value = it.it_interval
+ setitimer(_ITIMER_PROF, &it, nil)
+ }
+ _g_ := getg()
+ _g_.m.profilehz = hz
+}
+
+func sigpipe() {
+ if sigsend(_SIGPIPE) {
+ return
+ }
+ dieFromSignal(_SIGPIPE)
+}
+
+// sigtrampgo is called from the signal handler function, sigtramp,
+// written in assembly code.
+// This is called by the signal handler, and the world may be stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ c := sigctxt{info, ctx}
+ if sig == _SIGPROF {
+ _, pc := getSiginfo(info, ctx)
+ sigprofNonGoPC(pc)
+ return
+ }
+ badsignal(uintptr(sig), &c)
+ return
+ }
+
+ setg(g.m.gsignal)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
+
+// sigpanic turns a synchronous signal into a run-time panic.
+// If the signal handler sees a synchronous panic, it arranges the
+// stack to look like the function where the signal occurred called
+// sigpanic, sets the signal's PC value to sigpanic, and returns from
+// the signal handler. The effect is that the program will act as
+// though the function that got the signal simply called sigpanic
+// instead.
+func sigpanic() {
+ g := getg()
+ if !canpanic(g) {
+ throw("unexpected signal during runtime execution")
+ }
+
+ switch g.sig {
+ case _SIGBUS:
+ if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 {
+ panicmem()
+ }
+ // Support runtime/debug.SetPanicOnFault.
+ if g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGSEGV:
+ if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 {
+ panicmem()
+ }
+ // Support runtime/debug.SetPanicOnFault.
+ if g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGFPE:
+ switch g.sigcode0 {
+ case _FPE_INTDIV:
+ panicdivide()
+ case _FPE_INTOVF:
+ panicoverflow()
+ }
+ panicfloat()
+ }
+
+ if g.sig >= uint32(len(sigtable)) {
+ // can't happen: we looked up g.sig in sigtable to decide to call sigpanic
+ throw("unexpected signal value")
+ }
+ panic(errorString(sigtable[g.sig].name))
+}
+
+// dieFromSignal kills the program with a signal.
+// This provides the expected exit status for the shell.
+// This is only called with fatal signals expected to kill the process.
+//go:nosplit
+//go:nowritebarrierrec
+func dieFromSignal(sig uint32) {
+ setsig(sig, _SIG_DFL)
+ unblocksig(sig)
+ raise(sig)
+
+ // 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)
+}
+
+// raisebadsignal is called when a signal is received on a non-Go
+// thread, and the Go program does not want to handle it (that is, the
+// program has not called os/signal.Notify for the signal).
+func raisebadsignal(sig uint32, c *sigctxt) {
+ if sig == _SIGPROF {
+ // Ignore profiling signals that arrive on non-Go threads.
+ return
+ }
+
+ var handler uintptr
+ if sig >= _NSIG {
+ handler = _SIG_DFL
+ } else {
+ handler = fwdSig[sig]
+ }
+
+ // Reset the signal handler and raise the signal.
+ // We are currently running inside a signal handler, so the
+ // signal is blocked. We need to unblock it before raising the
+ // signal, or the signal we raise will be ignored until we return
+ // from the signal handler. We know that the signal was unblocked
+ // before entering the handler, or else we would not have received
+ // it. That means that we don't have to worry about blocking it
+ // again.
+ unblocksig(sig)
+ setsig(sig, handler)
+
+ // If we're linked into a non-Go program we want to try to
+ // avoid modifying the original context in which the signal
+ // was raised. If the handler is the default, we know it
+ // is non-recoverable, so we don't have to worry about
+ // re-installing sighandler. At this point we can just
+ // return and the signal will be re-raised and caught by
+ // the default handler with the correct context.
+ if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+ return
+ }
+
+ raise(sig)
+
+ // Give the signal a chance to be delivered.
+ // In almost all real cases the program is about to crash,
+ // so sleeping here is not a waste of time.
+ usleep(1000)
+
+ // If the signal didn't cause the program to exit, restore the
+ // Go signal handler and carry on.
+ //
+ // We may receive another instance of the signal before we
+ // restore the Go handler, but that is not so bad: we know
+ // that the Go program has been ignoring the signal.
+ setsig(sig, getSigtramp())
+}
+
+func crash() {
+ if GOOS == "darwin" {
+ // OS X core dumps are linear dumps of the mapped memory,
+ // from the first virtual byte to the last, with zeros in the gaps.
+ // Because of the way we arrange the address space on 64-bit systems,
+ // this means the OS X core file will be >128 GB and even on a zippy
+ // workstation can take OS X well over an hour to write (uninterruptible).
+ // Save users from making that mistake.
+ if sys.PtrSize == 8 {
+ return
+ }
+ }
+
+ dieFromSignal(_SIGABRT)
+}
+
+// ensureSigM starts one global, sleeping thread to make sure at least one thread
+// is available to catch signals enabled for os/signal.
+func ensureSigM() {
+ if maskUpdatedChan != nil {
+ return
+ }
+ maskUpdatedChan = make(chan struct{})
+ disableSigChan = make(chan uint32)
+ enableSigChan = make(chan uint32)
+ go func() {
+ // Signal masks are per-thread, so make sure this goroutine stays on one
+ // thread.
+ LockOSThread()
+ defer UnlockOSThread()
+ // The sigBlocked mask contains the signals not active for os/signal,
+ // initially all signals except the essential. When signal.Notify()/Stop is called,
+ // sigenable/sigdisable in turn notify this thread to update its signal
+ // mask accordingly.
+ var sigBlocked sigset
+ sigfillset(&sigBlocked)
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ sigdelset(&sigBlocked, i)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &sigBlocked, nil)
+ for {
+ select {
+ case sig := <-enableSigChan:
+ if sig > 0 {
+ sigdelset(&sigBlocked, int(sig))
+ }
+ case sig := <-disableSigChan:
+ if sig > 0 {
+ sigaddset(&sigBlocked, int(sig))
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &sigBlocked, nil)
+ maskUpdatedChan <- struct{}{}
+ }
+ }()
+}
+
+// This is called when we receive a signal when there is no signal stack.
+// This can only happen if non-Go code calls sigaltstack to disable the
+// signal stack.
+func noSignalStack(sig uint32) {
+ println("signal", sig, "received on thread with no signal stack")
+ throw("non-Go code disabled sigaltstack")
+}
+
+// This is called if we receive a signal when there is a signal stack
+// but we are not on it. This can only happen if non-Go code called
+// sigaction without setting the SS_ONSTACK flag.
+func sigNotOnStack(sig uint32) {
+ println("signal", sig, "received but handler not on signal stack")
+ throw("non-Go code set up signal handler without SA_ONSTACK flag")
+}
+
+// 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, c *sigctxt) {
+ needm(0)
+ if !sigsend(uint32(sig)) {
+ // A foreign thread received the signal sig, and the
+ // Go code does not want to handle it.
+ raisebadsignal(uint32(sig), c)
+ }
+ dropm()
+}
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's. Returns whether the
+// signal was forwarded.
+// This is called by the signal handler, and the world may be stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigfwdgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) bool {
+ if sig >= uint32(len(sigtable)) {
+ return false
+ }
+ fwdFn := fwdSig[sig]
+
+ if !signalsOK {
+ // The only way we can get here is if we are in a
+ // library or archive, we installed a signal handler
+ // at program startup, but the Go runtime has not yet
+ // been initialized.
+ if fwdFn == _SIG_DFL {
+ dieFromSignal(sig)
+ } else {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ return true
+ }
+
+ flags := sigtable[sig].flags
+
+ // If there is no handler to forward to, no need to forward.
+ if fwdFn == _SIG_DFL {
+ return false
+ }
+
+ // If we aren't handling the signal, forward it.
+ if flags&_SigHandling == 0 {
+ sigfwd(fwdFn, sig, info, ctx)
+ return true
+ }
+
+ // Only forward synchronous signals.
+ c := sigctxt{info, ctx}
+ if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+ return false
+ }
+ // Determine if the signal occurred inside Go code. We test that:
+ // (1) we were in a goroutine (i.e., m.curg != nil), and
+ // (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+ g := getg()
+ if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+ return false
+ }
+ // Signal not handled by Go, forward it.
+ if fwdFn != _SIG_IGN {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ return true
+}
+
+// msigsave saves the current thread's signal mask into mp.sigmask.
+// This is used to preserve the non-Go signal mask when a non-Go
+// thread calls a Go function.
+// This is nosplit and nowritebarrierrec because it is called by needm
+// which may be called on a non-Go thread with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func msigsave(mp *m) {
+ sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+// msigrestore sets the current thread's signal mask to sigmask.
+// This is used to restore the non-Go signal mask when a non-Go thread
+// calls a Go function.
+// This is nosplit and nowritebarrierrec because it is called by dropm
+// after g has been cleared.
+//go:nosplit
+//go:nowritebarrierrec
+func msigrestore(sigmask sigset) {
+ sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+// sigblock blocks all signals in the current thread's signal mask.
+// This is used to block signals while setting up and tearing down g
+// when a non-Go thread calls a Go function.
+// The OS-specific code is expected to define sigset_all.
+// This is nosplit and nowritebarrierrec because it is called by needm
+// which may be called on a non-Go thread with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func sigblock() {
+ var set sigset
+ sigfillset(&set)
+ sigprocmask(_SIG_SETMASK, &set, nil)
+}
+
+// unblocksig removes sig from the current thread's signal mask.
+// This is nosplit and nowritebarrierrec because it is called from
+// dieFromSignal, which can be called by sigfwdgo while running in the
+// signal handler, on the signal stack, with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func unblocksig(sig uint32) {
+ var set sigset
+ sigemptyset(&set)
+ sigaddset(&set, int(sig))
+ sigprocmask(_SIG_UNBLOCK, &set, nil)
+}
+
+// minitSignals is called when initializing a new m to set the
+// thread's alternate signal stack and signal mask.
+func minitSignals() {
+ minitSignalStack()
+ minitSignalMask()
+}
+
+// minitSignalStack is called when initializing a new m to set the
+// alternate signal stack. If the alternate signal stack is not set
+// for the thread (the normal case) then set the alternate signal
+// stack to the gsignal stack. If the alternate signal stack is set
+// for the thread (the case when a non-Go thread sets the alternate
+// signal stack and then calls a Go function) then set the gsignal
+// stack to the alternate signal stack. Record which choice was made
+// in newSigstack, so that it can be undone in unminit.
+func minitSignalStack() {
+ _g_ := getg()
+ var st _stack_t
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ signalstack(_g_.m.gsignalstack, _g_.m.gsignalstacksize)
+ _g_.m.newSigstack = true
+ } else {
+ _g_.m.newSigstack = false
+ }
+}
+
+// minitSignalMask is called when initializing a new m to set the
+// thread's signal mask. When this is called all signals have been
+// blocked for the thread. This starts with m.sigmask, which was set
+// either from initSigmask for a newly created thread or by calling
+// msigsave if this is a non-Go thread calling a Go function. It
+// removes all essential signals from the mask, thus causing those
+// signals to not be blocked. Then it sets the thread's signal mask.
+// After this is called the thread can receive signals.
+func minitSignalMask() {
+ nmask := getg().m.sigmask
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ sigdelset(&nmask, i)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// unminitSignals is called from dropm, via unminit, to undo the
+// effect of calling minit on a non-Go thread.
+//go:nosplit
+func unminitSignals() {
+ if getg().m.newSigstack {
+ signalstack(nil, 0)
+ }
+}
diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go
new file mode 100644
index 0000000000..a6d498f9b0
--- /dev/null
+++ b/libgo/go/runtime/sigqueue.go
@@ -0,0 +1,178 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block, allocate memory, or use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// sigsend is called by the signal handler to queue a new signal.
+// signal_recv is called by the Go program to receive a newly queued signal.
+// Synchronization between sigsend and signal_recv is based on the sig.state
+// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
+// sigReceiving means that signal_recv is blocked on sig.Note and there are no
+// new pending signals.
+// sigSending means that sig.mask *may* contain new pending signals,
+// signal_recv can't be blocked in this state.
+// sigIdle means that there are no new pending signals and signal_recv is not blocked.
+// Transitions between states are done atomically with CAS.
+// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
+// If several sigsends and signal_recv execute concurrently, it can lead to
+// unnecessary rechecks of sig.mask, but it cannot lead to missed signals
+// nor deadlocks.
+
+// +build !plan9
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ _ "unsafe" // for go:linkname
+)
+
+var sig struct {
+ note note
+ mask [(_NSIG + 31) / 32]uint32
+ wanted [(_NSIG + 31) / 32]uint32
+ ignored [(_NSIG + 31) / 32]uint32
+ recv [(_NSIG + 31) / 32]uint32
+ state uint32
+ inuse bool
+}
+
+const (
+ sigIdle = iota
+ sigReceiving
+ sigSending
+)
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+// Reports whether the signal was sent. If not, the caller typically crashes the program.
+func sigsend(s uint32) bool {
+ bit := uint32(1) << uint(s&31)
+ if !sig.inuse || s >= uint32(32*len(sig.wanted)) || sig.wanted[s/32]&bit == 0 {
+ return false
+ }
+
+ // Add signal to outgoing queue.
+ for {
+ mask := sig.mask[s/32]
+ if mask&bit != 0 {
+ return true // signal already in queue
+ }
+ if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
+ break
+ }
+ }
+
+ // Notify receiver that queue has new bit.
+Send:
+ for {
+ switch atomic.Load(&sig.state) {
+ default:
+ throw("sigsend: inconsistent state")
+ case sigIdle:
+ if atomic.Cas(&sig.state, sigIdle, sigSending) {
+ break Send
+ }
+ case sigSending:
+ // notification already pending
+ break Send
+ case sigReceiving:
+ if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
+ notewakeup(&sig.note)
+ break Send
+ }
+ }
+ }
+
+ return true
+}
+
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_recv os_signal.signal_recv
+func signal_recv() uint32 {
+ for {
+ // Serve any signals from local copy.
+ for i := uint32(0); i < _NSIG; i++ {
+ if sig.recv[i/32]&(1<<(i&31)) != 0 {
+ sig.recv[i/32] &^= 1 << (i & 31)
+ return i
+ }
+ }
+
+ // Wait for updates to be available from signal sender.
+ Receive:
+ for {
+ switch atomic.Load(&sig.state) {
+ default:
+ throw("signal_recv: inconsistent state")
+ case sigIdle:
+ if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
+ notetsleepg(&sig.note, -1)
+ noteclear(&sig.note)
+ break Receive
+ }
+ case sigSending:
+ if atomic.Cas(&sig.state, sigSending, sigIdle) {
+ break Receive
+ }
+ }
+ }
+
+ // Incorporate updates from sender into local copy.
+ for i := range sig.mask {
+ sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
+ }
+ }
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_enable os_signal.signal_enable
+func signal_enable(s uint32) {
+ if !sig.inuse {
+ // The first call to signal_enable is for us
+ // to use for initialization. It does not pass
+ // signal information in m.
+ sig.inuse = true // enable reception of signals; cannot disable
+ noteclear(&sig.note)
+ return
+ }
+
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] |= 1 << (s & 31)
+ sig.ignored[s/32] &^= 1 << (s & 31)
+ sigenable(s)
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_disable os_signal.signal_disable
+func signal_disable(s uint32) {
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] &^= 1 << (s & 31)
+ sigdisable(s)
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_ignore os_signal.signal_ignore
+func signal_ignore(s uint32) {
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] &^= 1 << (s & 31)
+ sig.ignored[s/32] |= 1 << (s & 31)
+ sigignore(s)
+}
+
+// Checked by signal handlers.
+func signal_ignored(s uint32) bool {
+ return sig.ignored[s/32]&(1<<(s&31)) != 0
+}
diff --git a/libgo/go/runtime/sigtab_linux_generic.go b/libgo/go/runtime/sigtab_linux_generic.go
deleted file mode 100644
index 32c40c4768..0000000000
--- a/libgo/go/runtime/sigtab_linux_generic.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !mips64
-// +build !mips64le
-// +build linux
-
-package runtime
-
-type sigTabT struct {
- flags int32
- name string
-}
-
-var sigtable = [...]sigTabT{
- /* 0 */ {0, "SIGNONE: no trap"},
- /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
- /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
- /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
- /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
- /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
- /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
- /* 7 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
- /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
- /* 9 */ {0, "SIGKILL: kill"},
- /* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
- /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
- /* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
- /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
- /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
- /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
- /* 16 */ {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"},
- /* 17 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
- /* 18 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
- /* 19 */ {0, "SIGSTOP: stop, unblockable"},
- /* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
- /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
- /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
- /* 23 */ {_SigNotify, "SIGURG: urgent condition on socket"},
- /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
- /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
- /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
- /* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
- /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
- /* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
- /* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
- /* 31 */ {_SigNotify, "SIGSYS: bad system call"},
- /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
- /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
- /* 34 */ {_SigNotify, "signal 34"},
- /* 35 */ {_SigNotify, "signal 35"},
- /* 36 */ {_SigNotify, "signal 36"},
- /* 37 */ {_SigNotify, "signal 37"},
- /* 38 */ {_SigNotify, "signal 38"},
- /* 39 */ {_SigNotify, "signal 39"},
- /* 40 */ {_SigNotify, "signal 40"},
- /* 41 */ {_SigNotify, "signal 41"},
- /* 42 */ {_SigNotify, "signal 42"},
- /* 43 */ {_SigNotify, "signal 43"},
- /* 44 */ {_SigNotify, "signal 44"},
- /* 45 */ {_SigNotify, "signal 45"},
- /* 46 */ {_SigNotify, "signal 46"},
- /* 47 */ {_SigNotify, "signal 47"},
- /* 48 */ {_SigNotify, "signal 48"},
- /* 49 */ {_SigNotify, "signal 49"},
- /* 50 */ {_SigNotify, "signal 50"},
- /* 51 */ {_SigNotify, "signal 51"},
- /* 52 */ {_SigNotify, "signal 52"},
- /* 53 */ {_SigNotify, "signal 53"},
- /* 54 */ {_SigNotify, "signal 54"},
- /* 55 */ {_SigNotify, "signal 55"},
- /* 56 */ {_SigNotify, "signal 56"},
- /* 57 */ {_SigNotify, "signal 57"},
- /* 58 */ {_SigNotify, "signal 58"},
- /* 59 */ {_SigNotify, "signal 59"},
- /* 60 */ {_SigNotify, "signal 60"},
- /* 61 */ {_SigNotify, "signal 61"},
- /* 62 */ {_SigNotify, "signal 62"},
- /* 63 */ {_SigNotify, "signal 63"},
- /* 64 */ {_SigNotify, "signal 64"},
-}
diff --git a/libgo/go/runtime/sigtab_linux_mips64x.go b/libgo/go/runtime/sigtab_linux_mips64x.go
deleted file mode 100644
index dbd50f7b1f..0000000000
--- a/libgo/go/runtime/sigtab_linux_mips64x.go
+++ /dev/null
@@ -1,81 +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 mips64 mips64le
-// +build linux
-
-package runtime
-
-type sigTabT struct {
- flags int32
- name string
-}
-
-var sigtable = [...]sigTabT{
- /* 0 */ {0, "SIGNONE: no trap"},
- /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
- /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
- /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
- /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
- /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
- /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
- /* 7 */ {_SigThrow, "SIGEMT"},
- /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
- /* 9 */ {0, "SIGKILL: kill"},
- /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
- /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
- /* 12 */ {_SigNotify, "SIGSYS: bad system call"},
- /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
- /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
- /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
- /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
- /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
- /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
- /* 19 */ {_SigNotify, "SIGPWR: power failure restart"},
- /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
- /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"},
- /* 22 */ {_SigNotify, "SIGIO: i/o now possible"},
- /* 23 */ {0, "SIGSTOP: stop, unblockable"},
- /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
- /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
- /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
- /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
- /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
- /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
- /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
- /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
- /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
- /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
- /* 34 */ {_SigNotify, "signal 34"},
- /* 35 */ {_SigNotify, "signal 35"},
- /* 36 */ {_SigNotify, "signal 36"},
- /* 37 */ {_SigNotify, "signal 37"},
- /* 38 */ {_SigNotify, "signal 38"},
- /* 39 */ {_SigNotify, "signal 39"},
- /* 40 */ {_SigNotify, "signal 40"},
- /* 41 */ {_SigNotify, "signal 41"},
- /* 42 */ {_SigNotify, "signal 42"},
- /* 43 */ {_SigNotify, "signal 43"},
- /* 44 */ {_SigNotify, "signal 44"},
- /* 45 */ {_SigNotify, "signal 45"},
- /* 46 */ {_SigNotify, "signal 46"},
- /* 47 */ {_SigNotify, "signal 47"},
- /* 48 */ {_SigNotify, "signal 48"},
- /* 49 */ {_SigNotify, "signal 49"},
- /* 50 */ {_SigNotify, "signal 50"},
- /* 51 */ {_SigNotify, "signal 51"},
- /* 52 */ {_SigNotify, "signal 52"},
- /* 53 */ {_SigNotify, "signal 53"},
- /* 54 */ {_SigNotify, "signal 54"},
- /* 55 */ {_SigNotify, "signal 55"},
- /* 56 */ {_SigNotify, "signal 56"},
- /* 57 */ {_SigNotify, "signal 57"},
- /* 58 */ {_SigNotify, "signal 58"},
- /* 59 */ {_SigNotify, "signal 59"},
- /* 60 */ {_SigNotify, "signal 60"},
- /* 61 */ {_SigNotify, "signal 61"},
- /* 62 */ {_SigNotify, "signal 62"},
- /* 63 */ {_SigNotify, "signal 63"},
- /* 64 */ {_SigNotify, "signal 64"},
-}
diff --git a/libgo/go/runtime/sizeclasses.go b/libgo/go/runtime/sizeclasses.go
new file mode 100644
index 0000000000..e616e95148
--- /dev/null
+++ b/libgo/go/runtime/sizeclasses.go
@@ -0,0 +1,95 @@
+// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT
+//go:generate go run mksizeclasses.go
+
+package runtime
+
+// class bytes/obj bytes/span objects waste bytes
+// 1 8 8192 1024 0
+// 2 16 8192 512 0
+// 3 32 8192 256 0
+// 4 48 8192 170 32
+// 5 64 8192 128 0
+// 6 80 8192 102 32
+// 7 96 8192 85 32
+// 8 112 8192 73 16
+// 9 128 8192 64 0
+// 10 144 8192 56 128
+// 11 160 8192 51 32
+// 12 176 8192 46 96
+// 13 192 8192 42 128
+// 14 208 8192 39 80
+// 15 224 8192 36 128
+// 16 240 8192 34 32
+// 17 256 8192 32 0
+// 18 288 8192 28 128
+// 19 320 8192 25 192
+// 20 352 8192 23 96
+// 21 384 8192 21 128
+// 22 416 8192 19 288
+// 23 448 8192 18 128
+// 24 480 8192 17 32
+// 25 512 8192 16 0
+// 26 576 8192 14 128
+// 27 640 8192 12 512
+// 28 704 8192 11 448
+// 29 768 8192 10 512
+// 30 896 8192 9 128
+// 31 1024 8192 8 0
+// 32 1152 8192 7 128
+// 33 1280 8192 6 512
+// 34 1408 16384 11 896
+// 35 1536 8192 5 512
+// 36 1792 16384 9 256
+// 37 2048 8192 4 0
+// 38 2304 16384 7 256
+// 39 2688 8192 3 128
+// 40 3072 24576 8 0
+// 41 3200 16384 5 384
+// 42 3456 24576 7 384
+// 43 4096 8192 2 0
+// 44 4864 24576 5 256
+// 45 5376 16384 3 256
+// 46 6144 24576 4 0
+// 47 6528 32768 5 128
+// 48 6784 40960 6 256
+// 49 6912 49152 7 768
+// 50 8192 8192 1 0
+// 51 9472 57344 6 512
+// 52 9728 49152 5 512
+// 53 10240 40960 4 0
+// 54 10880 32768 3 128
+// 55 12288 24576 2 0
+// 56 13568 40960 3 256
+// 57 14336 57344 4 0
+// 58 16384 16384 1 0
+// 59 18432 73728 4 0
+// 60 19072 57344 3 128
+// 61 20480 40960 2 0
+// 62 21760 65536 3 256
+// 63 24576 24576 1 0
+// 64 27264 81920 3 128
+// 65 28672 57344 2 0
+// 66 32768 32768 1 0
+
+const (
+ _MaxSmallSize = 32768
+ smallSizeDiv = 8
+ smallSizeMax = 1024
+ largeSizeDiv = 128
+ _NumSizeClasses = 67
+ _PageShift = 13
+)
+
+var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
+var class_to_allocnpages = [_NumSizeClasses]uint8{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, 3, 1, 3, 2, 3, 4, 5, 6, 1, 7, 6, 5, 4, 3, 5, 7, 2, 9, 7, 5, 8, 3, 10, 7, 4}
+
+type divMagic struct {
+ shift uint8
+ shift2 uint8
+ mul uint16
+ baseMask uint16
+}
+
+var class_to_divmagic = [_NumSizeClasses]divMagic{{0, 0, 0, 0}, {3, 0, 1, 65528}, {4, 0, 1, 65520}, {5, 0, 1, 65504}, {4, 9, 171, 0}, {6, 0, 1, 65472}, {4, 10, 205, 0}, {5, 9, 171, 0}, {4, 11, 293, 0}, {7, 0, 1, 65408}, {4, 9, 57, 0}, {5, 10, 205, 0}, {4, 12, 373, 0}, {6, 7, 43, 0}, {4, 13, 631, 0}, {5, 11, 293, 0}, {4, 13, 547, 0}, {8, 0, 1, 65280}, {5, 9, 57, 0}, {6, 9, 103, 0}, {5, 12, 373, 0}, {7, 7, 43, 0}, {5, 10, 79, 0}, {6, 10, 147, 0}, {5, 11, 137, 0}, {9, 0, 1, 65024}, {6, 9, 57, 0}, {7, 6, 13, 0}, {6, 11, 187, 0}, {8, 5, 11, 0}, {7, 8, 37, 0}, {10, 0, 1, 64512}, {7, 9, 57, 0}, {8, 6, 13, 0}, {7, 11, 187, 0}, {9, 5, 11, 0}, {8, 8, 37, 0}, {11, 0, 1, 63488}, {8, 9, 57, 0}, {7, 10, 49, 0}, {10, 5, 11, 0}, {7, 10, 41, 0}, {7, 9, 19, 0}, {12, 0, 1, 61440}, {8, 9, 27, 0}, {8, 10, 49, 0}, {11, 5, 11, 0}, {7, 13, 161, 0}, {7, 13, 155, 0}, {8, 9, 19, 0}, {13, 0, 1, 57344}, {8, 12, 111, 0}, {9, 9, 27, 0}, {11, 6, 13, 0}, {7, 14, 193, 0}, {12, 3, 3, 0}, {8, 13, 155, 0}, {11, 8, 37, 0}, {14, 0, 1, 49152}, {11, 8, 29, 0}, {7, 13, 55, 0}, {12, 5, 7, 0}, {8, 14, 193, 0}, {13, 3, 3, 0}, {7, 14, 77, 0}, {12, 7, 19, 0}, {15, 0, 1, 32768}}
+var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31}
+var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv + 1]uint8{31, 32, 33, 34, 35, 36, 36, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 48, 48, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66}
diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go
new file mode 100644
index 0000000000..55f4454027
--- /dev/null
+++ b/libgo/go/runtime/slice.go
@@ -0,0 +1,230 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname makeslice runtime.makeslice
+//go:linkname makeslice64 runtime.makeslice64
+//go:linkname growslice runtime.growslice
+//go:linkname slicecopy runtime.slicecopy
+//go:linkname slicestringcopy runtime.slicestringcopy
+
+type slice struct {
+ array unsafe.Pointer
+ len int
+ cap int
+}
+
+// maxElems is a lookup table containing the maximum capacity for a slice.
+// The index is the size of the slice element.
+var maxElems = [...]uintptr{
+ ^uintptr(0),
+ _MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4,
+ _MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8,
+ _MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12,
+ _MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16,
+ _MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20,
+ _MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24,
+ _MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28,
+ _MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32,
+}
+
+// maxSliceCap returns the maximum capacity for a slice.
+func maxSliceCap(elemsize uintptr) uintptr {
+ if elemsize < uintptr(len(maxElems)) {
+ return maxElems[elemsize]
+ }
+ return _MaxMem / elemsize
+}
+
+func makeslice(et *_type, len, cap int) slice {
+ // NOTE: The len > maxElements check here is not strictly necessary,
+ // but it produces a 'len out of range' error instead of a 'cap out of range' error
+ // when someone does make([]T, bignumber). 'cap out of range' is true too,
+ // but since the cap is only being supplied implicitly, saying len is clearer.
+ // See issue 4085.
+ maxElements := maxSliceCap(et.size)
+ if len < 0 || uintptr(len) > maxElements {
+ panic(errorString("makeslice: len out of range"))
+ }
+
+ if cap < len || uintptr(cap) > maxElements {
+ panic(errorString("makeslice: cap out of range"))
+ }
+
+ // gccgo's current garbage collector requires using newarray,
+ // not mallocgc here. This can change back to mallocgc when
+ // we port the garbage collector.
+ p := newarray(et, cap)
+ return slice{p, len, cap}
+}
+
+func makeslice64(et *_type, len64, cap64 int64) slice {
+ len := int(len64)
+ if int64(len) != len64 {
+ panic(errorString("makeslice: len out of range"))
+ }
+
+ cap := int(cap64)
+ if int64(cap) != cap64 {
+ panic(errorString("makeslice: cap out of range"))
+ }
+
+ return makeslice(et, len, cap)
+}
+
+// growslice handles slice growth during append.
+// It is passed the slice element type, the old slice, and the desired new minimum capacity,
+// and it returns a new slice with at least that capacity, with the old data
+// copied into it.
+// The new slice's length is set to the requested capacity.
+func growslice(et *_type, old slice, cap int) slice {
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&et))
+ racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
+ }
+ if msanenabled {
+ msanread(old.array, uintptr(old.len*int(et.size)))
+ }
+
+ if et.size == 0 {
+ if cap < old.cap {
+ panic(errorString("growslice: cap out of range"))
+ }
+ // append should not create a slice with nil pointer but non-zero len.
+ // We assume that append doesn't need to preserve old.array in this case.
+ return slice{unsafe.Pointer(&zerobase), cap, cap}
+ }
+
+ newcap := old.cap
+ doublecap := newcap + newcap
+ if cap > doublecap {
+ newcap = cap
+ } else {
+ if old.len < 1024 {
+ newcap = doublecap
+ } else {
+ for newcap < cap {
+ newcap += newcap / 4
+ }
+ }
+ }
+
+ var lenmem, newlenmem, capmem uintptr
+ const ptrSize = unsafe.Sizeof((*byte)(nil))
+ switch et.size {
+ case 1:
+ lenmem = uintptr(old.len)
+ newlenmem = uintptr(cap)
+ capmem = roundupsize(uintptr(newcap))
+ newcap = int(capmem)
+ case ptrSize:
+ lenmem = uintptr(old.len) * ptrSize
+ newlenmem = uintptr(cap) * ptrSize
+ capmem = roundupsize(uintptr(newcap) * ptrSize)
+ newcap = int(capmem / ptrSize)
+ default:
+ lenmem = uintptr(old.len) * et.size
+ newlenmem = uintptr(cap) * et.size
+ capmem = roundupsize(uintptr(newcap) * et.size)
+ newcap = int(capmem / et.size)
+ }
+
+ if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) {
+ panic(errorString("growslice: cap out of range"))
+ }
+
+ var p unsafe.Pointer
+ if et.kind&kindNoPointers != 0 {
+ // gccgo's current GC requires newarray, not mallocgc.
+ p = newarray(et, newcap)
+ memmove(p, old.array, lenmem)
+ // The call to memclr is not needed for gccgo since
+ // the newarray function will zero the memory.
+ // Calling memclr is also wrong since we allocated
+ // newcap*et.size bytes, which is not the same as capmem.
+ // The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length).
+ // Only clear the part that will not be overwritten.
+ // memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
+ _ = newlenmem
+ } else {
+ // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
+ // gccgo's current GC requires newarray, not mallocgc.
+ p = newarray(et, newcap)
+ if !writeBarrier.enabled {
+ memmove(p, old.array, lenmem)
+ } else {
+ for i := uintptr(0); i < lenmem; i += et.size {
+ typedmemmove(et, add(p, i), add(old.array, i))
+ }
+ }
+ }
+
+ return slice{p, cap, newcap}
+}
+
+func slicecopy(to, fm slice, width uintptr) int {
+ if fm.len == 0 || to.len == 0 {
+ return 0
+ }
+
+ n := fm.len
+ if to.len < n {
+ n = to.len
+ }
+
+ if width == 0 {
+ return n
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&to))
+ pc := funcPC(slicecopy)
+ racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
+ racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
+ }
+ if msanenabled {
+ msanwrite(to.array, uintptr(n*int(width)))
+ msanread(fm.array, uintptr(n*int(width)))
+ }
+
+ size := uintptr(n) * width
+ if size == 1 { // common case worth about 2x to do here
+ // TODO: is this still worth it with new memmove impl?
+ *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
+ } else {
+ memmove(to.array, fm.array, size)
+ }
+ return n
+}
+
+func slicestringcopy(to []byte, fm string) int {
+ if len(fm) == 0 || len(to) == 0 {
+ return 0
+ }
+
+ n := len(fm)
+ if len(to) < n {
+ n = len(to)
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&to))
+ pc := funcPC(slicestringcopy)
+ racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
+ }
+ if msanenabled {
+ msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
+ }
+
+ memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
+ return n
+}
diff --git a/libgo/go/runtime/stack.go b/libgo/go/runtime/stack.go
index 81059965d9..fd99e4d2f6 100644
--- a/libgo/go/runtime/stack.go
+++ b/libgo/go/runtime/stack.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
package runtime
import (
@@ -90,10 +92,10 @@ const (
// The stack guard is a pointer this many bytes above the
// bottom of the stack.
- _StackGuard = 720*sys.StackGuardMultiplier + _StackSystem
+ _StackGuard = 880*sys.StackGuardMultiplier + _StackSystem
// After a stack split check the SP is allowed to be this
- // many bytes below the stack guard. This saves an instruction
+ // many bytes below the stack guard. This saves an instruction
// in the checking sequence for tiny frames.
_StackSmall = 128
@@ -123,11 +125,13 @@ const (
stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
stackCache = 1
+
+ // check the BP links during traceback.
+ debugCheckBP = false
)
const (
uintptrMask = 1<<(8*sys.PtrSize) - 1
- poisonStack = uintptrMask & 0x6868686868686868
// Goroutine preemption request.
// Stored into g->stackguard0 to cause split stack check failure.
@@ -155,9 +159,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")
@@ -180,57 +181,57 @@ func stacklog2(n uintptr) int {
return log2
}
-// Allocates a stack from the free pool. Must be called with
+// Allocates a stack from the free pool. Must be called with
// stackpoolmu held.
func stackpoolalloc(order uint8) gclinkptr {
list := &stackpool[order]
s := list.first
if s == nil {
- // no free stacks. Allocate another span worth.
+ // no free stacks. Allocate another span worth.
s = mheap_.allocStack(_StackCacheSize >> _PageShift)
if s == nil {
throw("out of memory")
}
- if s.ref != 0 {
- throw("bad ref")
+ if s.allocCount != 0 {
+ throw("bad allocCount")
}
- if s.freelist.ptr() != nil {
- throw("bad freelist")
+ if s.stackfreelist.ptr() != nil {
+ throw("bad stackfreelist")
}
for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
- x := gclinkptr(uintptr(s.start)<<_PageShift + i)
- x.ptr().next = s.freelist
- s.freelist = x
+ x := gclinkptr(s.base() + i)
+ x.ptr().next = s.stackfreelist
+ s.stackfreelist = x
}
list.insert(s)
}
- x := s.freelist
+ x := s.stackfreelist
if x.ptr() == nil {
throw("span has no free stacks")
}
- s.freelist = x.ptr().next
- s.ref++
- if s.freelist.ptr() == nil {
+ s.stackfreelist = x.ptr().next
+ s.allocCount++
+ if s.stackfreelist.ptr() == nil {
// all stacks in s are allocated.
list.remove(s)
}
return x
}
-// Adds stack x to the free pool. Must be called with stackpoolmu held.
+// Adds stack x to the free pool. Must be called with stackpoolmu held.
func stackpoolfree(x gclinkptr, order uint8) {
s := mheap_.lookup(unsafe.Pointer(x))
if s.state != _MSpanStack {
throw("freeing stack not in a stack span")
}
- if s.freelist.ptr() == nil {
+ if s.stackfreelist.ptr() == nil {
// s will now have a free stack
stackpool[order].insert(s)
}
- x.ptr().next = s.freelist
- s.freelist = x
- s.ref--
- if gcphase == _GCoff && s.ref == 0 {
+ x.ptr().next = s.stackfreelist
+ s.stackfreelist = x
+ s.allocCount--
+ if gcphase == _GCoff && s.allocCount == 0 {
// Span is completely free. Return it to the heap
// immediately if we're sweeping.
//
@@ -247,13 +248,15 @@ func stackpoolfree(x gclinkptr, order uint8) {
//
// By not freeing, we prevent step #4 until GC is done.
stackpool[order].remove(s)
- s.freelist = 0
+ s.stackfreelist = 0
mheap_.freeStack(s)
}
}
// 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 +278,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 +297,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 +316,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.
@@ -329,6 +340,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
// Compute the size of stack barrier array.
maxstkbar := gcMaxStackBarriers(int(n))
nstkbar := unsafe.Sizeof(stkbar{}) * uintptr(maxstkbar)
+ var stkbarSlice slice
if debug.efence != 0 || stackFromSystem != 0 {
v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys)
@@ -336,7 +348,9 @@ func stackalloc(n uint32) (stack, []stkbar) {
throw("out of memory (stackalloc)")
}
top := uintptr(n) - nstkbar
- stkbarSlice := slice{add(v, top), 0, maxstkbar}
+ if maxstkbar != 0 {
+ stkbarSlice = slice{add(v, top), 0, maxstkbar}
+ }
return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
}
@@ -391,7 +405,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
throw("out of memory")
}
}
- v = unsafe.Pointer(s.start << _PageShift)
+ v = unsafe.Pointer(s.base())
}
if raceenabled {
@@ -404,10 +418,18 @@ func stackalloc(n uint32) (stack, []stkbar) {
print(" allocated ", v, "\n")
}
top := uintptr(n) - nstkbar
- stkbarSlice := slice{add(v, top), 0, maxstkbar}
+ if maxstkbar != 0 {
+ stkbarSlice = slice{add(v, top), 0, maxstkbar}
+ }
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)
@@ -419,7 +441,7 @@ func stackfree(stk stack, n uintptr) {
}
if stackDebug >= 1 {
println("stackfree", v, n)
- memclr(v, n) // for testing, clobber stack data
+ memclrNoHeapPointers(v, n) // for testing, clobber stack data
}
if debug.efence != 0 || stackFromSystem != 0 {
if debug.efence != 0 || stackFaultOnFree != 0 {
@@ -456,7 +478,7 @@ func stackfree(stk stack, n uintptr) {
} else {
s := mheap_.lookup(v)
if s.state != _MSpanStack {
- println(hex(s.start<<_PageShift), v)
+ println(hex(s.base()), v)
throw("bad span state")
}
if gcphase == _GCoff {
@@ -516,20 +538,23 @@ type adjustinfo struct {
old stack
delta uintptr // ptr distance from old to new stack (newbase - oldbase)
cache pcvalueCache
+
+ // sghi is the highest sudog.elem on the stack.
+ sghi uintptr
}
// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
// If so, it rewrites *vpp to point into the new stack.
func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
- pp := (*unsafe.Pointer)(vpp)
+ pp := (*uintptr)(vpp)
p := *pp
if stackDebug >= 4 {
- print(" ", pp, ":", p, "\n")
+ print(" ", pp, ":", hex(p), "\n")
}
- if adjinfo.old.lo <= uintptr(p) && uintptr(p) < adjinfo.old.hi {
- *pp = add(p, adjinfo.delta)
+ if adjinfo.old.lo <= p && p < adjinfo.old.hi {
+ *pp = p + adjinfo.delta
if stackDebug >= 3 {
- print(" adjust ptr ", pp, ":", p, " -> ", *pp, "\n")
+ print(" adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n")
}
}
}
@@ -563,26 +588,40 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
minp := adjinfo.old.lo
maxp := adjinfo.old.hi
delta := adjinfo.delta
- num := uintptr(bv.n)
+ num := bv.n
+ // If this frame might contain channel receive slots, use CAS
+ // to adjust pointers. If the slot hasn't been received into
+ // yet, it may contain stack pointers and a concurrent send
+ // could race with adjusting those pointers. (The sent value
+ // itself can never contain stack pointers.)
+ useCAS := uintptr(scanp) < adjinfo.sghi
for i := uintptr(0); i < num; i++ {
if stackDebug >= 4 {
print(" ", add(scanp, i*sys.PtrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*sys.PtrSize))), " # ", i, " ", bv.bytedata[i/8], "\n")
}
if ptrbit(&bv, i) == 1 {
pp := (*uintptr)(add(scanp, i*sys.PtrSize))
+ retry:
p := *pp
- if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 || p == poisonStack {
+ if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
// Looks like a junk value in a pointer slot.
// Live analysis wrong?
getg().m.traceback = 2
print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
- throw("invalid stack pointer")
+ throw("invalid pointer found on stack")
}
if minp <= p && p < maxp {
if stackDebug >= 3 {
- print("adjust ptr ", p, " ", funcname(f), "\n")
+ print("adjust ptr ", hex(p), " ", funcname(f), "\n")
+ }
+ if useCAS {
+ ppu := (*unsafe.Pointer)(unsafe.Pointer(pp))
+ if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) {
+ goto retry
+ }
+ } else {
+ *pp = p + delta
}
- *pp = p + delta
}
}
}
@@ -617,8 +656,8 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
// Adjust local variables if stack frame has been allocated.
size := frame.varp - frame.sp
var minsize uintptr
- switch sys.TheChar {
- case '7':
+ switch sys.ArchFamily {
+ case sys.ARM64:
minsize = sys.SpAlign
default:
minsize = sys.MinFrameSize
@@ -645,7 +684,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
}
// Adjust saved base pointer if there is one.
- if sys.TheChar == '6' && frame.argp-frame.varp == 2*sys.RegSize {
+ if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*sys.RegSize {
if !framepointer_enabled {
print("runtime: found space for saved base pointer, but no framepointer experiment\n")
print("argp=", hex(frame.argp), " varp=", hex(frame.varp), "\n")
@@ -654,6 +693,16 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
if stackDebug >= 3 {
print(" saved bp\n")
}
+ if debugCheckBP {
+ // Frame pointers should always point to the next higher frame on
+ // the Go stack (or be nil, for the top frame on the stack).
+ bp := *(*uintptr)(unsafe.Pointer(frame.varp))
+ if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
+ println("runtime: found invalid frame pointer")
+ print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
+ throw("bad frame pointer")
+ }
+ }
adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
}
@@ -665,7 +714,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
} else {
stackmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
if stackmap == nil || stackmap.n <= 0 {
- print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", uintptr(frame.arglen), "\n")
+ print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", frame.arglen, "\n")
throw("missing stackmap")
}
if pcdata < 0 || pcdata >= stackmap.n {
@@ -685,6 +734,18 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
func adjustctxt(gp *g, adjinfo *adjustinfo) {
adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt))
+ if !framepointer_enabled {
+ return
+ }
+ if debugCheckBP {
+ bp := gp.sched.bp
+ if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
+ println("runtime: found invalid top frame pointer")
+ print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
+ throw("bad top frame pointer")
+ }
+ }
+ adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp))
}
func adjustdefers(gp *g, adjinfo *adjustinfo) {
@@ -727,9 +788,76 @@ func fillstack(stk stack, b byte) {
}
}
+func findsghi(gp *g, stk stack) uintptr {
+ var sghi uintptr
+ for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+ p := uintptr(sg.elem) + uintptr(sg.c.elemsize)
+ if stk.lo <= p && p < stk.hi && p > sghi {
+ sghi = p
+ }
+ p = uintptr(unsafe.Pointer(sg.selectdone)) + unsafe.Sizeof(sg.selectdone)
+ if stk.lo <= p && p < stk.hi && p > sghi {
+ sghi = p
+ }
+ }
+ return sghi
+}
+
+// syncadjustsudogs adjusts gp's sudogs and copies the part of gp's
+// stack they refer to while synchronizing with concurrent channel
+// operations. It returns the number of bytes of stack copied.
+func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
+ if gp.waiting == nil {
+ return 0
+ }
+
+ // Lock channels to prevent concurrent send/receive.
+ // It's important that we *only* do this for async
+ // copystack; otherwise, gp may be in the middle of
+ // putting itself on wait queues and this would
+ // self-deadlock.
+ var lastc *hchan
+ for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+ if sg.c != lastc {
+ lock(&sg.c.lock)
+ }
+ lastc = sg.c
+ }
+
+ // Adjust sudogs.
+ adjustsudogs(gp, adjinfo)
+
+ // Copy the part of the stack the sudogs point in to
+ // while holding the lock to prevent races on
+ // send/receive slots.
+ var sgsize uintptr
+ if adjinfo.sghi != 0 {
+ oldBot := adjinfo.old.hi - used
+ newBot := oldBot + adjinfo.delta
+ sgsize = adjinfo.sghi - oldBot
+ memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize)
+ }
+
+ // Unlock channels.
+ lastc = nil
+ for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+ if sg.c != lastc {
+ unlock(&sg.c.lock)
+ }
+ lastc = sg.c
+ }
+
+ return sgsize
+}
+
// Copies gp's stack to a new stack of a different size.
// Caller must have changed gp status to Gcopystack.
-func copystack(gp *g, newsize uintptr) {
+//
+// If sync is true, this is a self-triggered stack growth and, in
+// particular, no other G may be writing to gp's stack (e.g., via a
+// channel operation). If sync is false, copystack protects against
+// concurrent channel operations.
+func copystack(gp *g, newsize uintptr, sync bool) {
if gp.syscallsp != 0 {
throw("stack growth not allowed in system call")
}
@@ -748,28 +876,46 @@ func copystack(gp *g, newsize uintptr) {
print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", gp.stackAlloc, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
}
- // Disallow sigprof scans of this stack and block if there's
- // one in progress.
- gcLockStackBarriers(gp)
-
- // adjust pointers in the to-be-copied frames
+ // Compute adjustment.
var adjinfo adjustinfo
adjinfo.old = old
adjinfo.delta = new.hi - old.hi
- gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
- // adjust other miscellaneous things that have pointers into stacks.
+ // Adjust sudogs, synchronizing with channel ops if necessary.
+ ncopy := used
+ if sync {
+ adjustsudogs(gp, &adjinfo)
+ } else {
+ // sudogs can point in to the stack. During concurrent
+ // shrinking, these areas may be written to. Find the
+ // highest such pointer so we can handle everything
+ // there and below carefully. (This shouldn't be far
+ // from the bottom of the stack, so there's little
+ // cost in handling everything below it carefully.)
+ adjinfo.sghi = findsghi(gp, old)
+
+ // Synchronize with channel ops and copy the part of
+ // the stack they may interact with.
+ ncopy -= syncadjustsudogs(gp, used, &adjinfo)
+ }
+
+ // Copy the stack (or the rest of it) to the new location
+ memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy)
+
+ // Disallow sigprof scans of this stack and block if there's
+ // one in progress.
+ gcLockStackBarriers(gp)
+
+ // Adjust remaining structures that have pointers into stacks.
+ // We have to do most of these before we traceback the new
+ // stack because gentraceback uses them.
adjustctxt(gp, &adjinfo)
adjustdefers(gp, &adjinfo)
adjustpanics(gp, &adjinfo)
- adjustsudogs(gp, &adjinfo)
adjuststkbar(gp, &adjinfo)
-
- // copy the stack to the new location
- if stackPoisonCopy != 0 {
- fillstack(new, 0xfb)
+ if adjinfo.sghi != 0 {
+ adjinfo.sghi += adjinfo.delta
}
- memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
// copy old stack barriers to new stack barrier array
newstkbar = newstkbar[:len(gp.stkbar)]
@@ -784,6 +930,9 @@ func copystack(gp *g, newsize uintptr) {
gp.stkbar = newstkbar
gp.stktopsp += adjinfo.delta
+ // Adjust pointers in the new stack.
+ gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
+
gcUnlockStackBarriers(gp)
// free old stack
@@ -808,7 +957,10 @@ func round2(x int32) int32 {
//
// g->atomicstatus will be Grunning or Gscanrunning upon entry.
// If the GC is trying to stop this g then it will set preemptscan to true.
-func newstack() {
+//
+// ctxt is the value of the context register on morestack. newstack
+// will write it to g.sched.ctxt.
+func newstack(ctxt unsafe.Pointer) {
thisg := getg()
// TODO: double check all gp. shouldn't be getg().
if thisg.m.morebuf.g.ptr().stackguard0 == stackFork {
@@ -820,8 +972,13 @@ func newstack() {
traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr())
throw("runtime: wrong goroutine in newstack")
}
+
+ gp := thisg.m.curg
+ // Write ctxt to gp.sched. We do this here instead of in
+ // morestack so it has the necessary write barrier.
+ gp.sched.ctxt = ctxt
+
if thisg.m.curg.throwsplit {
- gp := thisg.m.curg
// Update syscallsp, syscallpc in case traceback uses them.
morebuf := thisg.m.morebuf
gp.syscallsp = morebuf.sp
@@ -834,13 +991,11 @@ func newstack() {
throw("runtime: stack split at bad time")
}
- gp := thisg.m.curg
morebuf := thisg.m.morebuf
thisg.m.morebuf.pc = 0
thisg.m.morebuf.lr = 0
thisg.m.morebuf.sp = 0
thisg.m.morebuf.g = 0
- rewindmorestack(&gp.sched)
// NOTE: stackguard0 may change underfoot, if another thread
// is about to try to preempt gp. Read it just once and use that same
@@ -868,16 +1023,11 @@ func newstack() {
}
}
- // The goroutine must be executing in order to call newstack,
- // so it must be Grunning (or Gscanrunning).
- casgstatus(gp, _Grunning, _Gwaiting)
- gp.waitreason = "stack growth"
-
if gp.stack.lo == 0 {
throw("missing stack in newstack")
}
sp := gp.sched.sp
- if sys.TheChar == '6' || sys.TheChar == '8' {
+ if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 {
// The call to morestack cost a word.
sp -= sys.PtrSize
}
@@ -892,14 +1042,6 @@ func newstack() {
throw("runtime: split stack overflow")
}
- if gp.sched.ctxt != nil {
- // morestack wrote sched.ctxt on its way in here,
- // without a write barrier. Run the write barrier now.
- // It is not possible to be preempted between then
- // and now, so it's okay.
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(&gp.sched.ctxt)), uintptr(gp.sched.ctxt))
- }
-
if preempt {
if gp == thisg.m.g0 {
throw("runtime: preempt g0")
@@ -907,6 +1049,8 @@ func newstack() {
if thisg.m.p == 0 && thisg.m.locks == 0 {
throw("runtime: g is running but p is not")
}
+ // Synchronize with scang.
+ casgstatus(gp, _Grunning, _Gwaiting)
if gp.preemptscan {
for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
// Likely to be racing with the GC as
@@ -916,12 +1060,19 @@ 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
gp.preempt = false
casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
+ // This clears gcscanvalid.
casgstatus(gp, _Gwaiting, _Grunning)
gp.stackguard0 = gp.stack.lo + _StackGuard
gogo(&gp.sched) // never return
@@ -940,11 +1091,13 @@ func newstack() {
throw("stack overflow")
}
- casgstatus(gp, _Gwaiting, _Gcopystack)
+ // The goroutine must be executing in order to call newstack,
+ // so it must be Grunning (or Gscanrunning).
+ casgstatus(gp, _Grunning, _Gcopystack)
// The concurrent GC will not scan the stack while we are doing the copy since
// the gp is in a Gcopystack status.
- copystack(gp, uintptr(newsize))
+ copystack(gp, uintptr(newsize), true)
if stackDebug >= 1 {
print("stack grow done\n")
}
@@ -971,8 +1124,10 @@ func gostartcallfn(gobuf *gobuf, fv *funcval) {
// Maybe shrink the stack being used by gp.
// Called at garbage collection time.
+// gp must be stopped, but the world need not be.
func shrinkstack(gp *g) {
- if readgstatus(gp) == _Gdead {
+ gstatus := readgstatus(gp)
+ if gstatus&^_Gscan == _Gdead {
if gp.stack.lo != 0 {
// Free whole stack - it will get reallocated
// if G is used again.
@@ -987,10 +1142,18 @@ func shrinkstack(gp *g) {
if gp.stack.lo == 0 {
throw("missing stack in shrinkstack")
}
+ if gstatus&_Gscan == 0 {
+ throw("bad status in shrinkstack")
+ }
if debug.gcshrinkstackoff > 0 {
return
}
+ if gp.startpc == gcBgMarkWorkerPC {
+ // We're not allowed to shrink the gcBgMarkWorker
+ // stack (see gcBgMarkWorker for explanation).
+ return
+ }
oldsize := gp.stackAlloc
newsize := oldsize / 2
@@ -1022,9 +1185,7 @@ func shrinkstack(gp *g) {
print("shrinking stack ", oldsize, "->", newsize, "\n")
}
- oldstatus := casgcopystack(gp)
- copystack(gp, newsize)
- casgstatus(gp, _Gcopystack, oldstatus)
+ copystack(gp, newsize, false)
}
// freeStackSpans frees unused stack spans at the end of GC.
@@ -1036,9 +1197,9 @@ func freeStackSpans() {
list := &stackpool[order]
for s := list.first; s != nil; {
next := s.next
- if s.ref == 0 {
+ if s.allocCount == 0 {
list.remove(s)
- s.freelist = 0
+ s.stackfreelist = 0
mheap_.freeStack(s)
}
s = next
diff --git a/libgo/go/runtime/string.go b/libgo/go/runtime/string.go
new file mode 100644
index 0000000000..9cc2873743
--- /dev/null
+++ b/libgo/go/runtime/string.go
@@ -0,0 +1,463 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname concatstrings runtime.concatstrings
+//go:linkname concatstring2 runtime.concatstring2
+//go:linkname concatstring3 runtime.concatstring3
+//go:linkname concatstring4 runtime.concatstring4
+//go:linkname concatstring5 runtime.concatstring5
+//go:linkname slicebytetostring runtime.slicebytetostring
+//go:linkname slicebytetostringtmp runtime.slicebytetostringtmp
+//go:linkname stringtoslicebyte runtime.stringtoslicebyte
+//go:linkname stringtoslicerune runtime.stringtoslicerune
+//go:linkname slicerunetostring runtime.slicerunetostring
+//go:linkname intstring runtime.intstring
+// Temporary for C code to call:
+//go:linkname gostringnocopy runtime.gostringnocopy
+//go:linkname findnull runtime.findnull
+
+// The constant is known to the compiler.
+// There is no fundamental theory behind this number.
+const tmpStringBufSize = 32
+
+type tmpBuf [tmpStringBufSize]byte
+
+// concatstrings implements a Go string concatenation x+y+z+...
+// The operands are passed in the slice a.
+// If buf != nil, the compiler has determined that the result does not
+// escape the calling function, so the string data can be stored in buf
+// if small enough.
+func concatstrings(buf *tmpBuf, a []string) string {
+ // idx := 0
+ l := 0
+ count := 0
+ for _, x := range a {
+ n := len(x)
+ if n == 0 {
+ continue
+ }
+ if l+n < l {
+ throw("string concatenation too long")
+ }
+ l += n
+ count++
+ // idx = i
+ }
+ if count == 0 {
+ return ""
+ }
+
+ // If there is just one string and either it is not on the stack
+ // or our result does not escape the calling frame (buf != nil),
+ // then we can return that string directly.
+ // Commented out for gccgo--no implementation of stringDataOnStack.
+ // if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
+ // return a[idx]
+ // }
+ s, b := rawstringtmp(buf, l)
+ for _, x := range a {
+ copy(b, x)
+ b = b[len(x):]
+ }
+ return s
+}
+
+func concatstring2(buf *tmpBuf, a [2]string) string {
+ return concatstrings(buf, a[:])
+}
+
+func concatstring3(buf *tmpBuf, a [3]string) string {
+ return concatstrings(buf, a[:])
+}
+
+func concatstring4(buf *tmpBuf, a [4]string) string {
+ return concatstrings(buf, a[:])
+}
+
+func concatstring5(buf *tmpBuf, a [5]string) string {
+ return concatstrings(buf, a[:])
+}
+
+// Buf is a fixed-size buffer for the result,
+// it is not nil if the result does not escape.
+func slicebytetostring(buf *tmpBuf, b []byte) string {
+ l := len(b)
+ if l == 0 {
+ // Turns out to be a relatively common case.
+ // Consider that you want to parse out data between parens in "foo()bar",
+ // you find the indices and convert the subslice to string.
+ return ""
+ }
+ if raceenabled && l > 0 {
+ racereadrangepc(unsafe.Pointer(&b[0]),
+ uintptr(l),
+ getcallerpc(unsafe.Pointer(&buf)),
+ funcPC(slicebytetostring))
+ }
+ if msanenabled && l > 0 {
+ msanread(unsafe.Pointer(&b[0]), uintptr(l))
+ }
+ s, c := rawstringtmp(buf, l)
+ copy(c, b)
+ return s
+}
+
+func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
+ if buf != nil && l <= len(buf) {
+ b = buf[:l]
+ s = slicebytetostringtmp(b)
+ } else {
+ s, b = rawstring(l)
+ }
+ return
+}
+
+// slicebytetostringtmp returns a "string" referring to the actual []byte bytes.
+//
+// Callers need to ensure that the returned string will not be used after
+// the calling goroutine modifies the original slice or synchronizes with
+// another goroutine.
+//
+// The function is only called when instrumenting
+// and otherwise intrinsified by the compiler.
+//
+// Some internal compiler optimizations use this function.
+// - Used for m[string(k)] lookup where m is a string-keyed map and k is a []byte.
+// - Used for "<"+string(b)+">" concatenation where b is []byte.
+// - Used for string(b)=="foo" comparison where b is []byte.
+func slicebytetostringtmp(b []byte) string {
+ if raceenabled && len(b) > 0 {
+ racereadrangepc(unsafe.Pointer(&b[0]),
+ uintptr(len(b)),
+ getcallerpc(unsafe.Pointer(&b)),
+ funcPC(slicebytetostringtmp))
+ }
+ if msanenabled && len(b) > 0 {
+ msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
+ }
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+func stringtoslicebyte(buf *tmpBuf, s string) []byte {
+ var b []byte
+ if buf != nil && len(s) <= len(buf) {
+ *buf = tmpBuf{}
+ b = buf[:len(s)]
+ } else {
+ b = rawbyteslice(len(s))
+ }
+ copy(b, s)
+ return b
+}
+
+func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
+ // two passes.
+ // unlike slicerunetostring, no race because strings are immutable.
+ n := 0
+ for range s {
+ n++
+ }
+
+ var a []rune
+ if buf != nil && n <= len(buf) {
+ *buf = [tmpStringBufSize]rune{}
+ a = buf[:n]
+ } else {
+ a = rawruneslice(n)
+ }
+
+ n = 0
+ for _, r := range s {
+ a[n] = r
+ n++
+ }
+ return a
+}
+
+func slicerunetostring(buf *tmpBuf, a []rune) string {
+ if raceenabled && len(a) > 0 {
+ racereadrangepc(unsafe.Pointer(&a[0]),
+ uintptr(len(a))*unsafe.Sizeof(a[0]),
+ getcallerpc(unsafe.Pointer(&buf)),
+ funcPC(slicerunetostring))
+ }
+ if msanenabled && len(a) > 0 {
+ msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
+ }
+ var dum [4]byte
+ size1 := 0
+ for _, r := range a {
+ size1 += encoderune(dum[:], r)
+ }
+ s, b := rawstringtmp(buf, size1+3)
+ size2 := 0
+ for _, r := range a {
+ // check for race
+ if size2 >= size1 {
+ break
+ }
+ size2 += encoderune(b[size2:], r)
+ }
+ return s[:size2]
+}
+
+type stringStruct struct {
+ str unsafe.Pointer
+ len int
+}
+
+// Variant with *byte pointer type for DWARF debugging.
+type stringStructDWARF struct {
+ str *byte
+ len int
+}
+
+func stringStructOf(sp *string) *stringStruct {
+ return (*stringStruct)(unsafe.Pointer(sp))
+}
+
+func intstring(buf *[4]byte, v int64) string {
+ var s string
+ var b []byte
+ if buf != nil {
+ b = buf[:]
+ s = slicebytetostringtmp(b)
+ } else {
+ s, b = rawstring(4)
+ }
+ if int64(rune(v)) != v {
+ v = runeError
+ }
+ n := encoderune(b, rune(v))
+ return s[:n]
+}
+
+// rawstring allocates storage for a new string. The returned
+// string and byte slice both refer to the same storage.
+// The storage is not zeroed. Callers should use
+// b to set the string contents and then drop b.
+func rawstring(size int) (s string, b []byte) {
+ p := mallocgc(uintptr(size), nil, false)
+
+ stringStructOf(&s).str = p
+ stringStructOf(&s).len = size
+
+ *(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
+
+ return
+}
+
+// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
+func rawbyteslice(size int) (b []byte) {
+ cap := roundupsize(uintptr(size))
+ p := mallocgc(cap, nil, false)
+ if cap != uintptr(size) {
+ memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
+ }
+
+ *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
+ return
+}
+
+// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
+func rawruneslice(size int) (b []rune) {
+ if uintptr(size) > _MaxMem/4 {
+ throw("out of memory")
+ }
+ mem := roundupsize(uintptr(size) * 4)
+ p := mallocgc(mem, nil, false)
+ if mem != uintptr(size)*4 {
+ memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
+ }
+
+ *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
+ return
+}
+
+// used by cmd/cgo
+func gobytes(p *byte, n int) []byte {
+ if n == 0 {
+ return make([]byte, 0)
+ }
+ x := make([]byte, n)
+ memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n))
+ return x
+}
+
+func gostring(p *byte) string {
+ l := findnull(p)
+ if l == 0 {
+ return ""
+ }
+ s, b := rawstring(l)
+ memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
+ return s
+}
+
+func gostringn(p *byte, l int) string {
+ if l == 0 {
+ return ""
+ }
+ s, b := rawstring(l)
+ memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
+ return s
+}
+
+func index(s, t string) int {
+ if len(t) == 0 {
+ return 0
+ }
+ for i := 0; i < len(s); i++ {
+ if s[i] == t[0] && hasprefix(s[i:], t) {
+ return i
+ }
+ }
+ return -1
+}
+
+func contains(s, t string) bool {
+ return index(s, t) >= 0
+}
+
+func hasprefix(s, t string) bool {
+ return len(s) >= len(t) && s[:len(t)] == t
+}
+
+const (
+ maxUint = ^uint(0)
+ maxInt = int(maxUint >> 1)
+)
+
+// atoi parses an int from a string s.
+// The bool result reports whether s is a number
+// representable by a value of type int.
+func atoi(s string) (int, bool) {
+ if s == "" {
+ return 0, false
+ }
+
+ neg := false
+ if s[0] == '-' {
+ neg = true
+ s = s[1:]
+ }
+
+ un := uint(0)
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ return 0, false
+ }
+ if un > maxUint/10 {
+ // overflow
+ return 0, false
+ }
+ un *= 10
+ un1 := un + uint(c) - '0'
+ if un1 < un {
+ // overflow
+ return 0, false
+ }
+ un = un1
+ }
+
+ if !neg && un > uint(maxInt) {
+ return 0, false
+ }
+ if neg && un > uint(maxInt)+1 {
+ return 0, false
+ }
+
+ n := int(un)
+ if neg {
+ n = -n
+ }
+
+ return n, true
+}
+
+// atoi32 is like atoi but for integers
+// that fit into an int32.
+func atoi32(s string) (int32, bool) {
+ if n, ok := atoi(s); n == int(int32(n)) {
+ return int32(n), ok
+ }
+ return 0, false
+}
+
+//go:nosplit
+func findnull(s *byte) int {
+ if s == nil {
+ return 0
+ }
+ p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
+ l := 0
+ for p[l] != 0 {
+ l++
+ }
+ return l
+}
+
+func findnullw(s *uint16) int {
+ if s == nil {
+ return 0
+ }
+ p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
+ l := 0
+ for p[l] != 0 {
+ l++
+ }
+ return l
+}
+
+//go:nosplit
+func gostringnocopy(str *byte) string {
+ ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
+ s := *(*string)(unsafe.Pointer(&ss))
+ return s
+}
+
+func gostringw(strw *uint16) string {
+ var buf [8]byte
+ str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
+ n1 := 0
+ for i := 0; str[i] != 0; i++ {
+ n1 += encoderune(buf[:], rune(str[i]))
+ }
+ s, b := rawstring(n1 + 4)
+ n2 := 0
+ for i := 0; str[i] != 0; i++ {
+ // check for race
+ if n2 >= n1 {
+ break
+ }
+ n2 += encoderune(b[n2:], rune(str[i]))
+ }
+ b[n2] = 0 // for luck
+ return s[:n2]
+}
+
+// These two functions are called by code generated by cgo -gccgo.
+
+//go:linkname __go_byte_array_to_string __go_byte_array_to_string
+func __go_byte_array_to_string(p unsafe.Pointer, l int) string {
+ if l == 0 {
+ return ""
+ }
+ s, c := rawstringtmp(nil, l)
+ memmove(unsafe.Pointer(&c[0]), p, uintptr(l))
+ return s
+}
+
+//go:linkname __go_string_to_byte_array __go_string_to_byte_array
+func __go_string_to_byte_array(s string) []byte {
+ return stringtoslicebyte(nil, s)
+}
diff --git a/libgo/go/runtime/string_test.go b/libgo/go/runtime/string_test.go
index 64abd57d28..ee306999e2 100644
--- a/libgo/go/runtime/string_test.go
+++ b/libgo/go/runtime/string_test.go
@@ -5,10 +5,15 @@
package runtime_test
import (
+ "runtime"
"strings"
"testing"
)
+// Strings and slices that don't escape and fit into tmpBuf are stack allocated,
+// which defeats using AllocsPerRun to test other optimizations.
+const sizeNoStack = 100
+
func BenchmarkCompareStringEqual(b *testing.B) {
bytes := []byte("Hello Gophers!")
s1, s2 := string(bytes), string(bytes)
@@ -77,26 +82,59 @@ func BenchmarkCompareStringBig(b *testing.B) {
b.SetBytes(int64(len(s1)))
}
-func BenchmarkRuneIterate(b *testing.B) {
- bytes := make([]byte, 100)
- for i := range bytes {
- bytes[i] = byte('A')
- }
- s := string(bytes)
+func BenchmarkConcatStringAndBytes(b *testing.B) {
+ s1 := []byte("Gophers!")
for i := 0; i < b.N; i++ {
- for range s {
- }
+ _ = "Hello " + string(s1)
}
}
-func BenchmarkRuneIterate2(b *testing.B) {
- bytes := make([]byte, 100)
- for i := range bytes {
- bytes[i] = byte('A')
- }
- s := string(bytes)
+var stringdata = []struct{ name, data string }{
+ {"ASCII", "01234567890"},
+ {"Japanese", "日本語日本語日本語"},
+ {"MixedLength", "$Ѐࠀက퀀ð€€\U00040000\U0010FFFF"},
+}
+
+func BenchmarkRuneIterate(b *testing.B) {
+ b.Run("range", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for range sd.data {
+ }
+ }
+ })
+ }
+ })
+ b.Run("range1", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _ = range sd.data {
+ }
+ }
+ })
+ }
+ })
+ b.Run("range2", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, _ = range sd.data {
+ }
+ }
+ })
+ }
+ })
+}
+
+func BenchmarkArrayEqual(b *testing.B) {
+ a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
- for range s {
+ if a1 != a2 {
+ b.Fatal("not equal")
}
}
}
@@ -134,23 +172,8 @@ func TestLargeStringConcat(t *testing.T) {
}
}
-/*
-func TestGostringnocopy(t *testing.T) {
- max := *runtime.Maxstring
- b := make([]byte, max+10)
- for i := uintptr(0); i < max+9; i++ {
- b[i] = 'a'
- }
- _ = runtime.Gostringnocopy(&b[0])
- newmax := *runtime.Maxstring
- if newmax != max+9 {
- t.Errorf("want %d, got %d", max+9, newmax)
- }
-}
-*/
-
func TestCompareTempString(t *testing.T) {
- s := "foo"
+ s := strings.Repeat("x", sizeNoStack)
b := []byte(s)
n := testing.AllocsPerRun(1000, func() {
if string(b) != s {
@@ -161,7 +184,8 @@ func TestCompareTempString(t *testing.T) {
t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
}
})
- if n != 0 {
+ // was n != 0, changed for gccgo.
+ if n > 2 {
t.Fatalf("want 0 allocs, got %v", n)
}
}
@@ -207,13 +231,15 @@ func TestIntStringAllocs(t *testing.T) {
t.Fatalf("bad")
}
})
- if n != 0 {
+ // was n != 0, changed for gccgo, which currently does one
+ // allocation for each call to string(unknown).
+ if n > 2 {
t.Fatalf("want 0 allocs, got %v", n)
}
}
func TestRangeStringCast(t *testing.T) {
- s := "abc"
+ s := strings.Repeat("x", sizeNoStack)
n := testing.AllocsPerRun(1000, func() {
for i, c := range []byte(s) {
if c != s[i] {
@@ -221,22 +247,135 @@ func TestRangeStringCast(t *testing.T) {
}
}
})
- if n != 0 {
+ // was n != 0, changed for gccgo.
+ if n > 1 {
t.Fatalf("want 0 allocs, got %v", n)
}
}
+func isZeroed(b []byte) bool {
+ for _, x := range b {
+ if x != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func isZeroedR(r []rune) bool {
+ for _, x := range r {
+ if x != 0 {
+ return false
+ }
+ }
+ return true
+}
+
func TestString2Slice(t *testing.T) {
// Make sure we don't return slices that expose
// an unzeroed section of stack-allocated temp buf
- // between len and cap. See issue 14232.
+ // between len and cap. See issue 14232.
s := "foož"
b := ([]byte)(s)
- if cap(b) != 5 {
- t.Errorf("want cap of 5, got %d", cap(b))
+ if !isZeroed(b[len(b):cap(b)]) {
+ t.Errorf("extra bytes not zeroed")
}
r := ([]rune)(s)
- if cap(r) != 4 {
- t.Errorf("want cap of 4, got %d", cap(r))
+ if !isZeroedR(r[len(r):cap(r)]) {
+ t.Errorf("extra runes not zeroed")
+ }
+}
+
+const intSize = 32 << (^uint(0) >> 63)
+
+type atoi64Test struct {
+ in string
+ out int64
+ ok bool
+}
+
+var atoi64tests = []atoi64Test{
+ {"", 0, false},
+ {"0", 0, true},
+ {"-0", 0, true},
+ {"1", 1, true},
+ {"-1", -1, true},
+ {"12345", 12345, true},
+ {"-12345", -12345, true},
+ {"012345", 12345, true},
+ {"-012345", -12345, true},
+ {"12345x", 0, false},
+ {"-12345x", 0, false},
+ {"98765432100", 98765432100, true},
+ {"-98765432100", -98765432100, true},
+ {"20496382327982653440", 0, false},
+ {"-20496382327982653440", 0, false},
+ {"9223372036854775807", 1<<63 - 1, true},
+ {"-9223372036854775807", -(1<<63 - 1), true},
+ {"9223372036854775808", 0, false},
+ {"-9223372036854775808", -1 << 63, true},
+ {"9223372036854775809", 0, false},
+ {"-9223372036854775809", 0, false},
+}
+
+func TestAtoi(t *testing.T) {
+ switch intSize {
+ case 32:
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, ok := runtime.Atoi(test.in)
+ if test.out != int32(out) || test.ok != ok {
+ t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
+ }
+ case 64:
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, ok := runtime.Atoi(test.in)
+ if test.out != int64(out) || test.ok != ok {
+ t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
+ }
+ }
+}
+
+type atoi32Test struct {
+ in string
+ out int32
+ ok bool
+}
+
+var atoi32tests = []atoi32Test{
+ {"", 0, false},
+ {"0", 0, true},
+ {"-0", 0, true},
+ {"1", 1, true},
+ {"-1", -1, true},
+ {"12345", 12345, true},
+ {"-12345", -12345, true},
+ {"012345", 12345, true},
+ {"-012345", -12345, true},
+ {"12345x", 0, false},
+ {"-12345x", 0, false},
+ {"987654321", 987654321, true},
+ {"-987654321", -987654321, true},
+ {"2147483647", 1<<31 - 1, true},
+ {"-2147483647", -(1<<31 - 1), true},
+ {"2147483648", 0, false},
+ {"-2147483648", -1 << 31, true},
+ {"2147483649", 0, false},
+ {"-2147483649", 0, false},
+}
+
+func TestAtoi32(t *testing.T) {
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, ok := runtime.Atoi32(test.in)
+ if test.out != out || test.ok != ok {
+ t.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
}
}
diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go
new file mode 100644
index 0000000000..bf9f62eab2
--- /dev/null
+++ b/libgo/go/runtime/stubs.go
@@ -0,0 +1,642 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// Should be a built-in for unsafe.Pointer?
+//go:nosplit
+func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(p) + x)
+}
+
+// getg returns the pointer to the current g.
+// The compiler rewrites calls to this function into instructions
+// that fetch the g directly (from TLS or from the dedicated register).
+func getg() *g
+
+// mcall switches from the g to the g0 stack and invokes fn(g),
+// where g is the goroutine that made the call.
+// mcall saves g's current PC/SP in g->sched so that it can be restored later.
+// It is up to fn to arrange for that later execution, typically by recording
+// g in a data structure, causing something to call ready(g) later.
+// mcall returns to the original goroutine g later, when g has been rescheduled.
+// fn must not return at all; typically it ends by calling schedule, to let the m
+// run other goroutines.
+//
+// mcall can only be called from g stacks (not g0, not gsignal).
+//
+// This must NOT be go:noescape: if fn is a stack-allocated closure,
+// fn puts g on a run queue, and g executes before fn returns, the
+// closure will be invalidated while it is still executing.
+func mcall(fn func(*g))
+
+// systemstack runs fn on a system stack.
+//
+// It is common to use a func literal as the argument, in order
+// to share inputs and outputs with the code around the call
+// to system stack:
+//
+// ... set up y ...
+// systemstack(func() {
+// x = bigcall(y)
+// })
+// ... use x ...
+//
+// For the gc toolchain this permits running a function that requires
+// additional stack space in a context where the stack can not be
+// split. For gccgo, however, stack splitting is not managed by the
+// Go runtime. In effect, all stacks are system stacks. So this gccgo
+// version just runs the function.
+func systemstack(fn func()) {
+ fn()
+}
+
+func badsystemstack() {
+ throw("systemstack called from unexpected goroutine")
+}
+
+// memclrNoHeapPointers clears n bytes starting at ptr.
+//
+// Usually you should use typedmemclr. memclrNoHeapPointers should be
+// used only when the caller knows that *ptr contains no heap pointers
+// because either:
+//
+// 1. *ptr is initialized memory and its type is pointer-free.
+//
+// 2. *ptr is uninitialized memory (e.g., memory that's being reused
+// for a new allocation) and hence contains only "junk".
+//
+// in memclr_*.s
+//go:noescape
+func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
+
+//go:linkname reflect_memclrNoHeapPointers reflect.memclrNoHeapPointers
+func reflect_memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) {
+ memclrNoHeapPointers(ptr, n)
+}
+
+// memmove copies n bytes from "from" to "to".
+//go:noescape
+func memmove(to, from unsafe.Pointer, n uintptr)
+
+//go:linkname reflect_memmove reflect.memmove
+func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
+ memmove(to, from, n)
+}
+
+//go:noescape
+//extern __builtin_memcmp
+func memcmp(a, b unsafe.Pointer, size uintptr) int32
+
+// exported value for testing
+var hashLoad = loadFactor
+
+// in asm_*.s
+func fastrand() uint32
+
+//go:linkname sync_fastrand sync.fastrand
+func sync_fastrand() uint32 { return fastrand() }
+
+// in asm_*.s
+//go:noescape
+func memequal(a, b unsafe.Pointer, size uintptr) bool
+
+// noescape hides a pointer from escape analysis. noescape is
+// the identity function but escape analysis doesn't think the
+// output depends on the input. noescape is inlined and currently
+// compiles down to zero instructions.
+// USE CAREFULLY!
+//go:nosplit
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+ x := uintptr(p)
+ return unsafe.Pointer(x ^ 0)
+}
+
+//extern mincore
+func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
+
+//go:noescape
+func jmpdefer(fv *funcval, argp uintptr)
+func exit1(code int32)
+func asminit()
+func setg(gg *g)
+func breakpoint()
+
+// reflectcall calls fn with a copy of the n argument bytes pointed at by arg.
+// After fn returns, reflectcall copies n-retoffset result bytes
+// back into arg+retoffset before returning. If copying result bytes back,
+// the caller should pass the argument frame type as argtype, so that
+// call can execute appropriate write barriers during the copy.
+// Package reflect passes a frame type. In package runtime, there is only
+// one call that copies results back, in cgocallbackg1, and it does NOT pass a
+// frame type, meaning there are no write barriers invoked. See that call
+// site for justification.
+func reflectcall(argtype *_type, fn, arg unsafe.Pointer, argsize uint32, retoffset uint32)
+
+func procyield(cycles uint32)
+
+type neverCallThisFunction struct{}
+
+// goexit is the return stub at the top of every goroutine call stack.
+// Each goroutine stack is constructed as if goexit called the
+// goroutine's entry point function, so that when the entry point
+// function returns, it will return to goexit, which will call goexit1
+// to perform the actual exit.
+//
+// This function must never be called directly. Call goexit1 instead.
+// gentraceback assumes that goexit terminates the stack. A direct
+// call on the stack will cause gentraceback to stop walking the stack
+// prematurely and if there are leftover stack barriers it may panic.
+func goexit(neverCallThisFunction)
+
+// publicationBarrier performs a store/store barrier (a "publication"
+// or "export" barrier). Some form of synchronization is required
+// between initializing an object and making that object accessible to
+// another processor. Without synchronization, the initialization
+// writes and the "publication" write may be reordered, allowing the
+// other processor to follow the pointer and observe an uninitialized
+// object. In general, higher-level synchronization should be used,
+// such as locking or an atomic pointer write. publicationBarrier is
+// for when those aren't an option, such as in the implementation of
+// the memory manager.
+//
+// There's no corresponding barrier for the read side because the read
+// side naturally has a data dependency order. All architectures that
+// Go supports or seems likely to ever support automatically enforce
+// data dependency ordering.
+func publicationBarrier()
+
+//go:noescape
+func setcallerpc(argp unsafe.Pointer, pc uintptr)
+
+// getcallerpc returns the program counter (PC) of its caller's caller.
+// getcallersp returns the stack pointer (SP) of its caller's caller.
+// For both, the argp must be a pointer to the caller's first function argument.
+// The implementation may or may not use argp, depending on
+// the architecture.
+//
+// For example:
+//
+// func f(arg1, arg2, arg3 int) {
+// pc := getcallerpc(unsafe.Pointer(&arg1))
+// sp := getcallersp(unsafe.Pointer(&arg1))
+// }
+//
+// These two lines find the PC and SP immediately following
+// the call to f (where f will return).
+//
+// The call to getcallerpc and getcallersp must be done in the
+// frame being asked about. It would not be correct for f to pass &arg1
+// to another function g and let g call getcallerpc/getcallersp.
+// The call inside g might return information about g's caller or
+// information about f's caller or complete garbage.
+//
+// The result of getcallersp is correct at the time of the return,
+// but it may be invalidated by any subsequent call to a function
+// that might relocate the stack in order to grow or shrink it.
+// A general rule is that the result of getcallersp should be used
+// immediately and can only be passed to nosplit functions.
+
+//go:noescape
+func getcallerpc(argp unsafe.Pointer) uintptr
+
+//go:noescape
+func getcallersp(argp unsafe.Pointer) uintptr
+
+// argp used in Defer structs when there is no argp.
+const _NoArgs = ^uintptr(0)
+
+//go:linkname time_now time.now
+func time_now() (sec int64, nsec int32)
+
+// For gccgo, expose this for C callers.
+//go:linkname unixnanotime runtime.unixnanotime
+func unixnanotime() int64 {
+ sec, nsec := time_now()
+ return sec*1e9 + int64(nsec)
+}
+
+// round n up to a multiple of a. a must be a power of 2.
+func round(n, a uintptr) uintptr {
+ return (n + a - 1) &^ (a - 1)
+}
+
+// checkASM returns whether assembly runtime checks have passed.
+func checkASM() bool {
+ return true
+}
+
+func eqstring(x, y string) bool {
+ a := stringStructOf(&x)
+ b := stringStructOf(&y)
+ if a.len != b.len {
+ return false
+ }
+ if a.str == b.str {
+ return true
+ }
+ return memequal(a.str, b.str, uintptr(a.len))
+}
+
+// For gccgo this is in the C code.
+func osyield()
+
+// For gccgo this can be called directly.
+//extern syscall
+func syscall(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) uintptr
+
+// newobject allocates a new object.
+// For gccgo unless and until we port malloc.go.
+func newobject(*_type) unsafe.Pointer
+
+// newarray allocates a new array of objects.
+// For gccgo unless and until we port malloc.go.
+func newarray(*_type, int) unsafe.Pointer
+
+// For gccgo, to communicate from the C code to the Go code.
+//go:linkname setIsCgo runtime.setIsCgo
+func setIsCgo() {
+ iscgo = true
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname makeMainInitDone runtime.makeMainInitDone
+func makeMainInitDone() {
+ main_init_done = make(chan bool)
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname closeMainInitDone runtime.closeMainInitDone
+func closeMainInitDone() {
+ close(main_init_done)
+}
+
+// For gccgo, to communicate from the C code to the Go code.
+//go:linkname setCpuidECX runtime.setCpuidECX
+func setCpuidECX(v uint32) {
+ cpuid_ecx = v
+}
+
+// For gccgo, to communicate from the C code to the Go code.
+//go:linkname setSupportAES runtime.setSupportAES
+func setSupportAES(v bool) {
+ support_aes = v
+}
+
+// typedmemmove copies a typed value.
+// For gccgo for now.
+//go:linkname typedmemmove runtime.typedmemmove
+//go:nosplit
+func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+ memmove(dst, src, typ.size)
+}
+
+// Temporary for gccgo until we port mbarrier.go.
+//go:linkname reflect_typedmemmove reflect.typedmemmove
+func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+ typedmemmove(typ, dst, src)
+}
+
+// Temporary for gccgo until we port mbarrier.go.
+//go:nosplit
+func typedmemclr(typ *_type, ptr unsafe.Pointer) {
+ memclrNoHeapPointers(ptr, typ.size)
+}
+
+// Temporary for gccgo until we port mbarrier.go.
+//go:nosplit
+func memclrHasPointers(ptr unsafe.Pointer, n uintptr) {
+ memclrNoHeapPointers(ptr, n)
+}
+
+// Temporary for gccgo until we port mbarrier.go.
+//go:linkname typedslicecopy runtime.typedslicecopy
+func typedslicecopy(typ *_type, dst, src slice) int {
+ n := dst.len
+ if n > src.len {
+ n = src.len
+ }
+ if n == 0 {
+ return 0
+ }
+ memmove(dst.array, src.array, uintptr(n)*typ.size)
+ return n
+}
+
+// Temporary for gccgo until we port mbarrier.go.
+//go:linkname reflect_typedslicecopy reflect.typedslicecopy
+func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
+ return typedslicecopy(elemType, dst, src)
+}
+
+// Here for gccgo until we port malloc.go.
+const (
+ _64bit = 1 << (^uintptr(0) >> 63) / 2
+ _MHeapMap_TotalBits = (_64bit*sys.GoosWindows)*35 + (_64bit*(1-sys.GoosWindows)*(1-sys.GoosDarwin*sys.GoarchArm64))*39 + sys.GoosDarwin*sys.GoarchArm64*31 + (1-_64bit)*32
+ _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
+ _MaxGcproc = 32
+)
+
+// Here for gccgo until we port malloc.go.
+//extern runtime_mallocgc
+func c_mallocgc(size uintptr, typ uintptr, flag uint32) unsafe.Pointer
+func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
+ flag := uint32(0)
+ if !needzero {
+ flag = 1 << 3
+ }
+ return c_mallocgc(size, uintptr(unsafe.Pointer(typ)), flag)
+}
+
+// Here for gccgo until we port mgc.go.
+var writeBarrier struct {
+ enabled bool // compiler emits a check of this before calling write barrier
+ needed bool // whether we need a write barrier for current GC phase
+ cgo bool // whether we need a write barrier for a cgo check
+ alignme uint64 // guarantee alignment so that compiler can use a 32 or 64-bit load
+}
+
+func queueRescan(*g) {
+}
+
+// Here for gccgo until we port atomic_pointer.go and mgc.go.
+//go:nosplit
+func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
+ if !atomic.Casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new) {
+ return false
+ }
+ return true
+}
+
+// Here for gccgo until we port lock_*.go.
+func lock(l *mutex)
+func unlock(l *mutex)
+
+// Here for gccgo for netpoll and Solaris.
+func errno() int
+
+// Temporary for gccgo until we port proc.go.
+func entersyscall(int32)
+func entersyscallblock(int32)
+func exitsyscall(int32)
+func gopark(func(*g, unsafe.Pointer) bool, unsafe.Pointer, string, byte, int)
+func goparkunlock(*mutex, string, byte, int)
+
+// Temporary hack for gccgo until we port the garbage collector.
+func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) {}
+
+// Here for gccgo until we port msize.go.
+func roundupsize(uintptr) uintptr
+
+// Here for gccgo until we port mgc.go.
+func GC()
+
+// For gccgo to call from C code.
+//go:linkname acquireWorldsema runtime.acquireWorldsema
+func acquireWorldsema() {
+ semacquire(&worldsema, 0)
+}
+
+// For gccgo to call from C code.
+//go:linkname releaseWorldsema runtime.releaseWorldsema
+func releaseWorldsema() {
+ semrelease(&worldsema)
+}
+
+// For gccgo to call from C code, so that the C code and the Go code
+// can share the memstats variable for now.
+//go:linkname getMstats runtime.getMstats
+func getMstats() *mstats {
+ return &memstats
+}
+
+// Temporary for gccgo until we port proc.go.
+func setcpuprofilerate_m(hz int32)
+
+// Temporary for gccgo until we port mem_GOOS.go.
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64)
+
+// Temporary for gccgo until we port proc.go, so that the C signal
+// handler can call into cpuprof.
+//go:linkname cpuprofAdd runtime.cpuprofAdd
+func cpuprofAdd(stk []uintptr) {
+ cpuprof.add(stk)
+}
+
+// For gccgo until we port proc.go.
+func Breakpoint()
+func LockOSThread()
+func UnlockOSThread()
+func lockOSThread()
+func unlockOSThread()
+
+// Temporary for gccgo until we port malloc.go
+func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer
+
+// Temporary for gccgo until we port mheap.go
+func setprofilebucket(p unsafe.Pointer, b *bucket)
+
+// Temporary for gccgo until we port mgc.go.
+func setgcpercent(int32) int32
+
+//go:linkname setGCPercent runtime_debug.setGCPercent
+func setGCPercent(in int32) (out int32) {
+ return setgcpercent(in)
+}
+
+// Temporary for gccgo until we port atomic_pointer.go.
+//go:nosplit
+func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+ atomic.StorepNoWB(noescape(ptr), new)
+}
+
+// Temporary for gccgo until we port mbarrier.go
+func writebarrierptr(dst *uintptr, src uintptr) {
+ *dst = src
+}
+
+// Temporary for gccgo until we port malloc.go
+var zerobase uintptr
+
+//go:linkname getZerobase runtime.getZerobase
+func getZerobase() *uintptr {
+ return &zerobase
+}
+
+// Temporary for gccgo until we port proc.go.
+func sigprof()
+func goexit1()
+
+// Get signal trampoline, written in C.
+func getSigtramp() uintptr
+
+// The sa_handler field is generally hidden in a union, so use C accessors.
+func getSigactionHandler(*_sigaction) uintptr
+func setSigactionHandler(*_sigaction, uintptr)
+
+// Retrieve fields from the siginfo_t and ucontext_t pointers passed
+// to a signal handler using C, as they are often hidden in a union.
+// Returns and, if available, PC where signal occurred.
+func getSiginfo(*_siginfo_t, unsafe.Pointer) (sigaddr uintptr, sigpc uintptr)
+
+// Implemented in C for gccgo.
+func dumpregs(*_siginfo_t, unsafe.Pointer)
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname getsched runtime.getsched
+func getsched() *schedt {
+ return &sched
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname getCgoHasExtraM runtime.getCgoHasExtraM
+func getCgoHasExtraM() *bool {
+ return &cgoHasExtraM
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname getAllP runtime.getAllP
+func getAllP() **p {
+ return &allp[0]
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname allocg runtime.allocg
+func allocg() *g {
+ return new(g)
+}
+
+// Temporary for gccgo until we port the garbage collector.
+//go:linkname getallglen runtime.getallglen
+func getallglen() uintptr {
+ return allglen
+}
+
+// Temporary for gccgo until we port the garbage collector.
+//go:linkname getallg runtime.getallg
+func getallg(i int) *g {
+ return allgs[i]
+}
+
+// Temporary for gccgo until we port the garbage collector.
+//go:linkname getallm runtime.getallm
+func getallm() *m {
+ return allm
+}
+
+// Throw and rethrow an exception.
+func throwException()
+func rethrowException()
+
+// Fetch the size and required alignment of the _Unwind_Exception type
+// used by the stack unwinder.
+func unwindExceptionSize() uintptr
+
+// Temporary for gccgo until C code no longer needs it.
+//go:nosplit
+//go:linkname getPanicking runtime.getPanicking
+func getPanicking() uint32 {
+ return panicking
+}
+
+// Temporary for gccgo until we port mcache.go.
+func allocmcache() *mcache
+func freemcache(*mcache)
+
+// Temporary for gccgo until we port mgc.go.
+// This is just so that allgadd will compile.
+var work struct {
+ rescan struct {
+ lock mutex
+ list []guintptr
+ }
+}
+
+// Temporary for gccgo until we port mgc.go.
+var gcBlackenEnabled uint32
+
+// Temporary for gccgo until we port mgc.go.
+func gcMarkWorkAvailable(p *p) bool {
+ return false
+}
+
+// Temporary for gccgo until we port mgc.go.
+var gcController gcControllerState
+
+// Temporary for gccgo until we port mgc.go.
+type gcControllerState struct {
+}
+
+// Temporary for gccgo until we port mgc.go.
+func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
+ return nil
+}
+
+// Temporary for gccgo until we port mgc.go.
+var gcphase uint32
+
+// Temporary for gccgo until we port mgc.go.
+const (
+ _GCoff = iota
+ _GCmark
+ _GCmarktermination
+)
+
+// Temporary for gccgo until we port mgc.go.
+type gcMarkWorkerMode int
+
+// Temporary for gccgo until we port mgc.go.
+const (
+ gcMarkWorkerDedicatedMode gcMarkWorkerMode = iota
+ gcMarkWorkerFractionalMode
+ gcMarkWorkerIdleMode
+)
+
+// Temporary for gccgo until we port mheap.go.
+type mheap struct {
+}
+
+// Temporary for gccgo until we port mheap.go.
+var mheap_ mheap
+
+// Temporary for gccgo until we port mheap.go.
+func (h *mheap) scavenge(k int32, now, limit uint64) {
+}
+
+// Temporary for gccgo until we initialize ncpu in Go.
+//go:linkname setncpu runtime.setncpu
+func setncpu(n int32) {
+ ncpu = n
+}
+
+// Temporary for gccgo until we port malloc.go.
+var physPageSize uintptr
+
+// Temporary for gccgo until we reliably initialize physPageSize in Go.
+//go:linkname setpagesize runtime.setpagesize
+func setpagesize(s uintptr) {
+ if physPageSize == 0 {
+ physPageSize = s
+ }
+}
+
+// Temporary for gccgo until we port more of proc.go.
+func sigprofNonGoPC(pc uintptr) {
+}
+
+// Temporary for gccgo until we port mgc.go.
+// gcMarkWorkerModeStrings are the strings labels of gcMarkWorkerModes
+// to use in execution traces.
+var gcMarkWorkerModeStrings = [...]string{
+ "GC (dedicated)",
+ "GC (fractional)",
+ "GC (idle)",
+}
diff --git a/libgo/go/runtime/stubs2.go b/libgo/go/runtime/stubs2.go
new file mode 100644
index 0000000000..e891fe5ee7
--- /dev/null
+++ b/libgo/go/runtime/stubs2.go
@@ -0,0 +1,33 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+// +build !windows
+// +build !nacl
+
+package runtime
+
+import "unsafe"
+
+func read(fd int32, p unsafe.Pointer, n int32) int32
+func closefd(fd int32) int32
+
+//extern exit
+func exit(code int32)
+func nanotime() int64
+func usleep(usec uint32)
+
+//extern mmap
+func mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int32, offset uintptr) unsafe.Pointer
+
+//extern munmap
+func munmap(addr unsafe.Pointer, n uintptr) int32
+
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32)
diff --git a/libgo/go/runtime/symtab.go b/libgo/go/runtime/symtab.go
new file mode 100644
index 0000000000..52e2d03d14
--- /dev/null
+++ b/libgo/go/runtime/symtab.go
@@ -0,0 +1,137 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// Frames may be used to get function/file/line information for a
+// slice of PC values returned by Callers.
+type Frames struct {
+ callers []uintptr
+
+ // The last PC we saw.
+ last uintptr
+
+ // The number of times we've seen last.
+ lastCount int
+}
+
+// Frame is the information returned by Frames for each call frame.
+type Frame struct {
+ // Program counter for this frame; multiple frames may have
+ // the same PC value.
+ PC uintptr
+
+ // Func for this frame; may be nil for non-Go code or fully
+ // inlined functions.
+ Func *Func
+
+ // Function name, file name, and line number for this call frame.
+ // May be the empty string or zero if not known.
+ // If Func is not nil then Function == Func.Name().
+ Function string
+ File string
+ Line int
+
+ // Entry point for the function; may be zero if not known.
+ // If Func is not nil then Entry == Func.Entry().
+ Entry uintptr
+}
+
+// CallersFrames takes a slice of PC values returned by Callers and
+// prepares to return function/file/line information.
+// Do not change the slice until you are done with the Frames.
+func CallersFrames(callers []uintptr) *Frames {
+ return &Frames{callers: callers}
+}
+
+// Next returns frame information for the next caller.
+// If more is false, there are no more callers (the Frame value is valid).
+func (ci *Frames) Next() (frame Frame, more bool) {
+ if len(ci.callers) == 0 {
+ return Frame{}, false
+ }
+
+ pc := ci.callers[0]
+ ci.callers = ci.callers[1:]
+
+ i := 0
+ if pc == ci.last {
+ ci.lastCount++
+ i = ci.lastCount
+ } else {
+ ci.last = pc
+ ci.lastCount = 0
+ }
+ more = len(ci.callers) > 0
+
+ // Subtract 1 from PC to undo the 1 we added in callback in
+ // go-callers.c.
+ function, file, line := funcfileline(pc-1, int32(i))
+ if function == "" && file == "" {
+ return Frame{}, more
+ }
+ entry := funcentry(pc - 1)
+ f := &Func{name: function, entry: entry}
+
+ xpc := pc
+ if xpc > entry {
+ xpc--
+ }
+
+ frame = Frame{
+ PC: xpc,
+ Func: f,
+ Function: function,
+ File: file,
+ Line: line,
+ Entry: entry,
+ }
+
+ return frame, more
+}
+
+// NOTE: Func does not expose the actual unexported fields, because we return *Func
+// values to users, and we want to keep them from being able to overwrite the data
+// with (say) *f = Func{}.
+// All code operating on a *Func must call raw to get the *_func instead.
+
+// A Func represents a Go function in the running binary.
+type Func struct {
+ name string
+ entry uintptr
+}
+
+// FuncForPC returns a *Func describing the function that contains the
+// given program counter address, or else nil.
+func FuncForPC(pc uintptr) *Func {
+ name, _, _ := funcfileline(pc, -1)
+ if name == "" {
+ return nil
+ }
+ entry := funcentry(pc)
+ return &Func{name: name, entry: entry}
+}
+
+// Name returns the name of the function.
+func (f *Func) Name() string {
+ return f.name
+}
+
+// Entry returns the entry address of the function.
+func (f *Func) Entry() uintptr {
+ return f.entry
+}
+
+// FileLine returns the file name and line number of the
+// source code corresponding to the program counter pc.
+// The result will not be accurate if pc is not a program
+// counter within f.
+func (f *Func) FileLine(pc uintptr) (file string, line int) {
+ _, file, line = funcfileline(pc, -1)
+ return file, line
+}
+
+// implemented in go-caller.c
+func funcfileline(uintptr, int32) (string, string, int)
+func funcentry(uintptr) uintptr
diff --git a/libgo/go/runtime/sys_mips64x.go b/libgo/go/runtime/sys_mips64x.go
deleted file mode 100644
index 9e7d805d7d..0000000000
--- a/libgo/go/runtime/sys_mips64x.go
+++ /dev/null
@@ -1,43 +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 mips64 mips64le
-
-package runtime
-
-import "unsafe"
-
-// adjust Gobuf as if it executed a call to fn with context ctxt
-// and then did an immediate Gosave.
-func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
- if buf.lr != 0 {
- throw("invalid use of gostartcall")
- }
- buf.lr = buf.pc
- buf.pc = uintptr(fn)
- buf.ctxt = ctxt
-}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint32
- if buf.pc&3 == 0 && buf.pc != 0 {
- inst = *(*uint32)(unsafe.Pointer(buf.pc))
- if inst>>26 == 2 { // JMP addr
- //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc &^ uintptr(1<<28-1) | uintptr((inst&^0xfc000000)<<2)), "\n");
- buf.pc &^= 1<<28 - 1
- buf.pc |= uintptr((inst &^ 0xfc000000) << 2)
- return
- }
- if inst>>16 == 0x1000 { // BEQ R0, R0, offset
- //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc + uintptr(int32(int16(inst&0xffff))<<2 + 4)), "\n");
- buf.pc += uintptr(int32(int16(inst&0xffff))<<2 + 4)
- return
- }
- }
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
diff --git a/libgo/go/runtime/sys_nonppc64x.go b/libgo/go/runtime/sys_nonppc64x.go
deleted file mode 100644
index 440937498f..0000000000
--- a/libgo/go/runtime/sys_nonppc64x.go
+++ /dev/null
@@ -1,10 +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 !ppc64,!ppc64le
-
-package runtime
-
-func prepGoExitFrame(sp uintptr) {
-}
diff --git a/libgo/go/runtime/testdata/testprog/crash.go b/libgo/go/runtime/testdata/testprog/crash.go
index 3d7c7c6aab..4d83132198 100644
--- a/libgo/go/runtime/testdata/testprog/crash.go
+++ b/libgo/go/runtime/testdata/testprog/crash.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprog/deadlock.go b/libgo/go/runtime/testdata/testprog/deadlock.go
index 73fbf6224d..ca2be57911 100644
--- a/libgo/go/runtime/testdata/testprog/deadlock.go
+++ b/libgo/go/runtime/testdata/testprog/deadlock.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -30,6 +30,9 @@ func init() {
register("PanicAfterGoexit", PanicAfterGoexit)
register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
register("PanicTraceback", PanicTraceback)
+ register("GoschedInPanic", GoschedInPanic)
+ register("SyscallInPanic", SyscallInPanic)
+ register("PanicLoop", PanicLoop)
}
func SimpleDeadlock() {
@@ -152,6 +155,29 @@ func GoexitInPanic() {
runtime.Goexit()
}
+type errorThatGosched struct{}
+
+func (errorThatGosched) Error() string {
+ runtime.Gosched()
+ return "errorThatGosched"
+}
+
+func GoschedInPanic() {
+ panic(errorThatGosched{})
+}
+
+type errorThatPrint struct{}
+
+func (errorThatPrint) Error() string {
+ fmt.Println("1")
+ fmt.Println("2")
+ return "3"
+}
+
+func SyscallInPanic() {
+ panic(errorThatPrint{})
+}
+
func PanicAfterGoexit() {
defer func() {
panic("hello")
@@ -189,3 +215,13 @@ func pt2() {
}()
panic("hello")
}
+
+type panicError struct{}
+
+func (*panicError) Error() string {
+ panic("double error")
+}
+
+func PanicLoop() {
+ panic(&panicError{})
+}
diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go
index 9bb367c0d1..744b6108e2 100644
--- a/libgo/go/runtime/testdata/testprog/gc.go
+++ b/libgo/go/runtime/testdata/testprog/gc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -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,49 @@ 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.
+ //
+ // OpenBSD's scheduler makes every usleep() take at least
+ // 20ms, so we need a long time to ensure all goroutines have
+ // run. If they haven't run after 30ms, give it another 1000ms
+ // and check again.
+ time.Sleep(30 * time.Millisecond)
+ var fail bool
+ for i := range count {
+ if atomic.LoadInt64(&count[i]) == 0 {
+ fail = true
+ }
+ }
+ if fail {
+ time.Sleep(1 * time.Second)
+ for i := range count {
+ if atomic.LoadInt64(&count[i]) == 0 {
+ fmt.Printf("goroutine %d did not run\n", i)
+ return
+ }
+ }
+ }
+ fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprog/main.go b/libgo/go/runtime/testdata/testprog/main.go
index 9c227bbf81..ae491a2a97 100644
--- a/libgo/go/runtime/testdata/testprog/main.go
+++ b/libgo/go/runtime/testdata/testprog/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprog/map.go b/libgo/go/runtime/testdata/testprog/map.go
new file mode 100644
index 0000000000..552428957b
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprog/map.go
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func init() {
+ register("concurrentMapWrites", concurrentMapWrites)
+ register("concurrentMapReadWrite", concurrentMapReadWrite)
+ register("concurrentMapIterateWrite", concurrentMapIterateWrite)
+}
+
+func concurrentMapWrites() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[6] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
+
+func concurrentMapReadWrite() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ _ = m[6]
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
+
+func concurrentMapIterateWrite() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ for range m {
+ }
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
diff --git a/libgo/go/runtime/testdata/testprog/memprof.go b/libgo/go/runtime/testdata/testprog/memprof.go
new file mode 100644
index 0000000000..a22fee61d7
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprog/memprof.go
@@ -0,0 +1,49 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "runtime/pprof"
+)
+
+func init() {
+ register("MemProf", MemProf)
+}
+
+var memProfBuf bytes.Buffer
+var memProfStr string
+
+func MemProf() {
+ for i := 0; i < 1000; i++ {
+ fmt.Fprintf(&memProfBuf, "%*d\n", i, i)
+ }
+ memProfStr = memProfBuf.String()
+
+ runtime.GC()
+
+ f, err := ioutil.TempFile("", "memprof")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ if err := pprof.WriteHeapProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ name := f.Name()
+ if err := f.Close(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ fmt.Println(name)
+}
diff --git a/libgo/go/runtime/testdata/testprog/misc.go b/libgo/go/runtime/testdata/testprog/misc.go
index 237680fc87..7ccd389c94 100644
--- a/libgo/go/runtime/testdata/testprog/misc.go
+++ b/libgo/go/runtime/testdata/testprog/misc.go
@@ -1,4 +1,4 @@
-// Copyright 2016 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.
diff --git a/libgo/go/runtime/testdata/testprog/signal.go b/libgo/go/runtime/testdata/testprog/signal.go
index ac2d3e8f6c..2ccbada57b 100644
--- a/libgo/go/runtime/testdata/testprog/signal.go
+++ b/libgo/go/runtime/testdata/testprog/signal.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -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)
}
diff --git a/libgo/go/runtime/testdata/testprog/stringconcat.go b/libgo/go/runtime/testdata/testprog/stringconcat.go
index 9dddf1969f..f233e66206 100644
--- a/libgo/go/runtime/testdata/testprog/stringconcat.go
+++ b/libgo/go/runtime/testdata/testprog/stringconcat.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprog/syscall_windows.go b/libgo/go/runtime/testdata/testprog/syscall_windows.go
index 73165be187..6e6782e987 100644
--- a/libgo/go/runtime/testdata/testprog/syscall_windows.go
+++ b/libgo/go/runtime/testdata/testprog/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/aprof.go b/libgo/go/runtime/testdata/testprogcgo/aprof.go
new file mode 100644
index 0000000000..aabca9e1eb
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/aprof.go
@@ -0,0 +1,53 @@
+// 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
+
+// Test that SIGPROF received in C code does not crash the process
+// looking for the C code's func pointer.
+
+// The test fails when the function is the first C function.
+// The exported functions are the first C functions, so we use that.
+
+// extern void GoNop();
+import "C"
+
+import (
+ "bytes"
+ "fmt"
+ "runtime/pprof"
+ "time"
+)
+
+func init() {
+ register("CgoCCodeSIGPROF", CgoCCodeSIGPROF)
+}
+
+//export GoNop
+func GoNop() {}
+
+func CgoCCodeSIGPROF() {
+ c := make(chan bool)
+ go func() {
+ <-c
+ start := time.Now()
+ for i := 0; i < 1e7; i++ {
+ if i%1000 == 0 {
+ if time.Since(start) > time.Second {
+ break
+ }
+ }
+ C.GoNop()
+ }
+ c <- true
+ }()
+
+ var buf bytes.Buffer
+ pprof.StartCPUProfile(&buf)
+ c <- true
+ <-c
+ pprof.StopCPUProfile()
+
+ fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/callback.go b/libgo/go/runtime/testdata/testprogcgo/callback.go
index 10e248a159..7d9d68ddd1 100644
--- a/libgo/go/runtime/testdata/testprogcgo/callback.go
+++ b/libgo/go/runtime/testdata/testprogcgo/callback.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/cgo.go b/libgo/go/runtime/testdata/testprogcgo/cgo.go
index cf1af8268c..870d4efdea 100644
--- a/libgo/go/runtime/testdata/testprogcgo/cgo.go
+++ b/libgo/go/runtime/testdata/testprogcgo/cgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
@@ -6,17 +6,22 @@ package main
/*
void foo1(void) {}
+void foo2(void* p) {}
*/
import "C"
import (
"fmt"
+ "os"
"runtime"
+ "strconv"
"time"
+ "unsafe"
)
func init() {
register("CgoSignalDeadlock", CgoSignalDeadlock)
register("CgoTraceback", CgoTraceback)
+ register("CgoCheckBytes", CgoCheckBytes)
}
func CgoSignalDeadlock() {
@@ -78,3 +83,18 @@ func CgoTraceback() {
runtime.Stack(buf, true)
fmt.Printf("OK\n")
}
+
+func CgoCheckBytes() {
+ try, _ := strconv.Atoi(os.Getenv("GO_CGOCHECKBYTES_TRY"))
+ if try <= 0 {
+ try = 1
+ }
+ b := make([]byte, 1e6*try)
+ start := time.Now()
+ for i := 0; i < 1e3*try; i++ {
+ C.foo2(unsafe.Pointer(&b[0]))
+ if time.Since(start) > time.Second {
+ break
+ }
+ }
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/crash.go b/libgo/go/runtime/testdata/testprogcgo/crash.go
index 3d7c7c6aab..4d83132198 100644
--- a/libgo/go/runtime/testdata/testprogcgo/crash.go
+++ b/libgo/go/runtime/testdata/testprogcgo/crash.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/deadlock.go b/libgo/go/runtime/testdata/testprogcgo/deadlock.go
new file mode 100644
index 0000000000..2cc68a8927
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/deadlock.go
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+char *geterror() {
+ return "cgo error";
+}
+*/
+import "C"
+import (
+ "fmt"
+)
+
+func init() {
+ register("CgoPanicDeadlock", CgoPanicDeadlock)
+}
+
+type cgoError struct{}
+
+func (cgoError) Error() string {
+ fmt.Print("") // necessary to trigger the deadlock
+ return C.GoString(C.geterror())
+}
+
+func CgoPanicDeadlock() {
+ panic(cgoError{})
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/dll_windows.go b/libgo/go/runtime/testdata/testprogcgo/dll_windows.go
index a0647ef212..aed2410a45 100644
--- a/libgo/go/runtime/testdata/testprogcgo/dll_windows.go
+++ b/libgo/go/runtime/testdata/testprogcgo/dll_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/dropm.go b/libgo/go/runtime/testdata/testprogcgo/dropm.go
index 75984ea75f..9e782f504f 100644
--- a/libgo/go/runtime/testdata/testprogcgo/dropm.go
+++ b/libgo/go/runtime/testdata/testprogcgo/dropm.go
@@ -1,4 +1,4 @@
-// Copyright 2016 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go b/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go
index 4c3f46ade4..f7f142c1fd 100644
--- a/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go
+++ b/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2016 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/exec.go b/libgo/go/runtime/testdata/testprogcgo/exec.go
index 8dc1d517c6..2e948401c8 100644
--- a/libgo/go/runtime/testdata/testprogcgo/exec.go
+++ b/libgo/go/runtime/testdata/testprogcgo/exec.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/main.go b/libgo/go/runtime/testdata/testprogcgo/main.go
index 9c227bbf81..ae491a2a97 100644
--- a/libgo/go/runtime/testdata/testprogcgo/main.go
+++ b/libgo/go/runtime/testdata/testprogcgo/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/pprof.go b/libgo/go/runtime/testdata/testprogcgo/pprof.go
new file mode 100644
index 0000000000..4460b9304e
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/pprof.go
@@ -0,0 +1,97 @@
+// 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
+
+// Run a slow C function saving a CPU profile.
+
+/*
+#include <stdint.h>
+
+int salt1;
+int salt2;
+
+void cpuHog() {
+ int foo = salt1;
+ int i;
+
+ for (i = 0; i < 100000; i++) {
+ if (foo > 0) {
+ foo *= foo;
+ } else {
+ foo *= foo + 1;
+ }
+ }
+ salt2 = foo;
+}
+
+static int cpuHogCount;
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+// pprofCgoTraceback is passed to runtime.SetCgoTraceback.
+// For testing purposes it pretends that all CPU hits in C code are in cpuHog.
+void pprofCgoTraceback(void* parg) {
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ arg->buf[0] = (uintptr_t)(cpuHog) + 0x10;
+ arg->buf[1] = 0;
+ ++cpuHogCount;
+}
+
+// getCpuHogCount fetches the number of times we've seen cpuHog in the
+// traceback.
+int getCpuHogCount() {
+ return cpuHogCount;
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+ "unsafe"
+)
+
+func init() {
+ register("CgoPprof", CgoPprof)
+}
+
+func CgoPprof() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoTraceback), nil, nil)
+
+ f, err := ioutil.TempFile("", "prof")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ t0 := time.Now()
+ for C.getCpuHogCount() < 2 && time.Since(t0) < time.Second {
+ C.cpuHog()
+ }
+
+ pprof.StopCPUProfile()
+
+ name := f.Name()
+ if err := f.Close(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ fmt.Println(name)
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/raceprof.go b/libgo/go/runtime/testdata/testprogcgo/raceprof.go
new file mode 100644
index 0000000000..fe624c541f
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/raceprof.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+
+package main
+
+// Test that we can collect a lot of colliding profiling signals from
+// an external C thread. This used to fail when built with the race
+// detector, because a call of the predeclared function copy was
+// turned into a call to runtime.slicecopy, which is not marked nosplit.
+
+/*
+#include <signal.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+static int raceprofCount;
+
+// We want a bunch of different profile stacks that collide in the
+// hash table maintained in runtime/cpuprof.go. This code knows the
+// size of the hash table (1 << 10) and knows that the hash function
+// is simply multiplicative.
+void raceprofTraceback(void* parg) {
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ raceprofCount++;
+ arg->buf[0] = raceprofCount * (1 << 10);
+ arg->buf[1] = 0;
+}
+
+static void* raceprofThread(void* p) {
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ pthread_kill(pthread_self(), SIGPROF);
+ sched_yield();
+ }
+ return 0;
+}
+
+void runRaceprofThread() {
+ pthread_t tid;
+ pthread_create(&tid, 0, raceprofThread, 0);
+ pthread_join(tid, 0);
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+ "runtime/pprof"
+ "unsafe"
+)
+
+func init() {
+ register("CgoRaceprof", CgoRaceprof)
+}
+
+func CgoRaceprof() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.raceprofTraceback), nil, nil)
+
+ var buf bytes.Buffer
+ pprof.StartCPUProfile(&buf)
+
+ C.runRaceprofThread()
+ fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/racesig.go b/libgo/go/runtime/testdata/testprogcgo/racesig.go
new file mode 100644
index 0000000000..d0c1c3ce54
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/racesig.go
@@ -0,0 +1,102 @@
+// 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 linux,amd64
+
+package main
+
+// Test that an external C thread that is calling malloc can be hit
+// with SIGCHLD signals. This used to fail when built with the race
+// detector, because in that case the signal handler would indirectly
+// call the C malloc function.
+
+/*
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
+
+#define ALLOCERS 100
+#define SIGNALERS 10
+
+static void* signalThread(void* p) {
+ pthread_t* pt = (pthread_t*)(p);
+ int i, j;
+
+ for (i = 0; i < 100; i++) {
+ for (j = 0; j < ALLOCERS; j++) {
+ if (pthread_kill(pt[j], SIGCHLD) < 0) {
+ return NULL;
+ }
+ }
+ usleep(1);
+ }
+ return NULL;
+}
+
+#define CALLS 100
+
+static void* mallocThread(void* p) {
+ int i;
+ void *a[CALLS];
+
+ for (i = 0; i < ALLOCERS; i++) {
+ sched_yield();
+ }
+ for (i = 0; i < CALLS; i++) {
+ a[i] = malloc(i);
+ }
+ for (i = 0; i < CALLS; i++) {
+ free(a[i]);
+ }
+ return NULL;
+}
+
+void runRaceSignalThread() {
+ int i;
+ pthread_t m[ALLOCERS];
+ pthread_t s[SIGNALERS];
+
+ for (i = 0; i < ALLOCERS; i++) {
+ pthread_create(&m[i], NULL, mallocThread, NULL);
+ }
+ for (i = 0; i < SIGNALERS; i++) {
+ pthread_create(&s[i], NULL, signalThread, &m[0]);
+ }
+ for (i = 0; i < SIGNALERS; i++) {
+ pthread_join(s[i], NULL);
+ }
+ for (i = 0; i < ALLOCERS; i++) {
+ pthread_join(m[i], NULL);
+ }
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "time"
+)
+
+func init() {
+ register("CgoRaceSignal", CgoRaceSignal)
+}
+
+func CgoRaceSignal() {
+ // The failure symptom is that the program hangs because of a
+ // deadlock in malloc, so set an alarm.
+ go func() {
+ time.Sleep(5 * time.Second)
+ fmt.Println("Hung for 5 seconds")
+ os.Exit(1)
+ }()
+
+ C.runRaceSignalThread()
+ fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpanic.go b/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
index 3c9baba71a..f9b48a9026 100644
--- a/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpanic_unix.c b/libgo/go/runtime/testdata/testprogcgo/threadpanic_unix.c
new file mode 100644
index 0000000000..c426452c2b
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpanic_unix.c
@@ -0,0 +1,26 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!windows
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+void gopanic(void);
+
+static void*
+die(void* x)
+{
+ gopanic();
+ return 0;
+}
+
+void
+start(void)
+{
+ pthread_t t;
+ if(pthread_create(&t, 0, die, 0) != 0)
+ printf("pthread_create failed\n");
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpanic_windows.c b/libgo/go/runtime/testdata/testprogcgo/threadpanic_windows.c
new file mode 100644
index 0000000000..ba66d0f5c9
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpanic_windows.c
@@ -0,0 +1,23 @@
+// 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.
+
+#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void gopanic(void);
+
+static unsigned int __attribute__((__stdcall__))
+die(void* x)
+{
+ gopanic();
+ return 0;
+}
+
+void
+start(void)
+{
+ if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
+ printf("_beginthreadex failed\n");
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpprof.go b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go
new file mode 100644
index 0000000000..3da82961b9
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go
@@ -0,0 +1,123 @@
+// 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 !plan9,!windows
+
+package main
+
+// Run a slow C function saving a CPU profile.
+
+/*
+#include <stdint.h>
+#include <time.h>
+#include <pthread.h>
+
+int threadSalt1;
+int threadSalt2;
+
+void cpuHogThread() {
+ int foo = threadSalt1;
+ int i;
+
+ for (i = 0; i < 100000; i++) {
+ if (foo > 0) {
+ foo *= foo;
+ } else {
+ foo *= foo + 1;
+ }
+ }
+ threadSalt2 = foo;
+}
+
+static int cpuHogThreadCount;
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+// pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback.
+// For testing purposes it pretends that all CPU hits in C code are in cpuHog.
+void pprofCgoThreadTraceback(void* parg) {
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10;
+ arg->buf[1] = 0;
+ __sync_add_and_fetch(&cpuHogThreadCount, 1);
+}
+
+// getCPUHogThreadCount fetches the number of times we've seen cpuHogThread
+// in the traceback.
+int getCPUHogThreadCount() {
+ return __sync_add_and_fetch(&cpuHogThreadCount, 0);
+}
+
+static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
+ while (1) {
+ cpuHogThread();
+ }
+ return 0;
+}
+
+void runCPUHogThread(void) {
+ pthread_t tid;
+ pthread_create(&tid, 0, cpuHogDriver, 0);
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+ "unsafe"
+)
+
+func init() {
+ register("CgoPprofThread", CgoPprofThread)
+ register("CgoPprofThreadNoTraceback", CgoPprofThreadNoTraceback)
+}
+
+func CgoPprofThread() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil)
+ pprofThread()
+}
+
+func CgoPprofThreadNoTraceback() {
+ pprofThread()
+}
+
+func pprofThread() {
+ f, err := ioutil.TempFile("", "prof")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ C.runCPUHogThread()
+
+ t0 := time.Now()
+ for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second {
+ time.Sleep(100 * time.Millisecond)
+ }
+
+ pprof.StopCPUProfile()
+
+ name := f.Name()
+ if err := f.Close(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ fmt.Println(name)
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadprof.go b/libgo/go/runtime/testdata/testprogcgo/threadprof.go
index 03e35d2a9e..2d4c1039fb 100644
--- a/libgo/go/runtime/testdata/testprogcgo/threadprof.go
+++ b/libgo/go/runtime/testdata/testprogcgo/threadprof.go
@@ -1,8 +1,12 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
+// We only build this file with the tag "threadprof", since it starts
+// a thread running a busy loop at constructor time.
+
// +build !plan9,!windows
+// +build threadprof
package main
@@ -21,6 +25,7 @@ static void *thread1(void *p) {
spinlock = 0;
return NULL;
}
+
__attribute__((constructor)) void issue9456() {
pthread_t tid;
pthread_create(&tid, 0, thread1, NULL);
@@ -84,8 +89,8 @@ func CgoExternalThreadSignal() {
out, err := exec.Command(os.Args[0], "CgoExternalThreadSignal", "crash").CombinedOutput()
if err == nil {
- fmt.Println("C signal did not crash as expected\n")
- fmt.Printf("%s\n", out)
+ fmt.Println("C signal did not crash as expected")
+ fmt.Printf("\n%s\n", out)
os.Exit(1)
}
diff --git a/libgo/go/runtime/testdata/testprogcgo/traceback.go b/libgo/go/runtime/testdata/testprogcgo/traceback.go
new file mode 100644
index 0000000000..2a023f66ca
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/traceback.go
@@ -0,0 +1,81 @@
+// 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
+
+// This program will crash.
+// We want the stack trace to include the C functions.
+// We use a fake traceback, and a symbolizer that dumps a string we recognize.
+
+/*
+#cgo CFLAGS: -g -O0
+
+#include <stdint.h>
+
+char *p;
+
+static int f3(void) {
+ *p = 0;
+ return 0;
+}
+
+static int f2(void) {
+ return f3();
+}
+
+static int f1(void) {
+ return f2();
+}
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+struct cgoSymbolizerArg {
+ uintptr_t pc;
+ const char* file;
+ uintptr_t lineno;
+ const char* func;
+ uintptr_t entry;
+ uintptr_t more;
+ uintptr_t data;
+};
+
+void cgoTraceback(void* parg) {
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ arg->buf[0] = 1;
+ arg->buf[1] = 2;
+ arg->buf[2] = 3;
+ arg->buf[3] = 0;
+}
+
+void cgoSymbolizer(void* parg) {
+ struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
+ if (arg->pc != arg->data + 1) {
+ arg->file = "unexpected data";
+ } else {
+ arg->file = "cgo symbolizer";
+ }
+ arg->lineno = arg->data + 1;
+ arg->data++;
+}
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+func init() {
+ register("CrashTraceback", CrashTraceback)
+}
+
+func CrashTraceback() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.cgoTraceback), nil, unsafe.Pointer(C.cgoSymbolizer))
+ C.f1()
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/tracebackctxt.go b/libgo/go/runtime/testdata/testprogcgo/tracebackctxt.go
new file mode 100644
index 0000000000..51fa4ad25c
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/tracebackctxt.go
@@ -0,0 +1,107 @@
+// 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.
+
+// The __attribute__((weak)) used below doesn't seem to work on Windows.
+
+package main
+
+// Test the context argument to SetCgoTraceback.
+// Use fake context, traceback, and symbolizer functions.
+
+/*
+// Defined in tracebackctxt_c.c.
+extern void C1(void);
+extern void C2(void);
+extern void tcContext(void*);
+extern void tcTraceback(void*);
+extern void tcSymbolizer(void*);
+extern int getContextCount(void);
+*/
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+func init() {
+ register("TracebackContext", TracebackContext)
+}
+
+var tracebackOK bool
+
+func TracebackContext() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
+ C.C1()
+ if got := C.getContextCount(); got != 0 {
+ fmt.Printf("at end contextCount == %d, expected 0\n", got)
+ tracebackOK = false
+ }
+ if tracebackOK {
+ fmt.Println("OK")
+ }
+}
+
+//export G1
+func G1() {
+ C.C2()
+}
+
+//export G2
+func G2() {
+ pc := make([]uintptr, 32)
+ n := runtime.Callers(0, pc)
+ cf := runtime.CallersFrames(pc[:n])
+ var frames []runtime.Frame
+ for {
+ frame, more := cf.Next()
+ frames = append(frames, frame)
+ if !more {
+ break
+ }
+ }
+
+ want := []struct {
+ function string
+ line int
+ }{
+ {"main.G2", 0},
+ {"cFunction", 0x10200},
+ {"cFunction", 0x200},
+ {"cFunction", 0x10201},
+ {"cFunction", 0x201},
+ {"main.G1", 0},
+ {"cFunction", 0x10100},
+ {"cFunction", 0x100},
+ {"main.TracebackContext", 0},
+ }
+
+ ok := true
+ i := 0
+wantLoop:
+ for _, w := range want {
+ for ; i < len(frames); i++ {
+ if w.function == frames[i].Function {
+ if w.line != 0 && w.line != frames[i].Line {
+ fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
+ ok = false
+ }
+ i++
+ continue wantLoop
+ }
+ }
+ fmt.Printf("did not find function %s in\n", w.function)
+ for _, f := range frames {
+ fmt.Println(f)
+ }
+ ok = false
+ break
+ }
+ tracebackOK = ok
+ if got := C.getContextCount(); got != 2 {
+ fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
+ tracebackOK = false
+ }
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/tracebackctxt_c.c b/libgo/go/runtime/testdata/testprogcgo/tracebackctxt_c.c
new file mode 100644
index 0000000000..900cada0d3
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/tracebackctxt_c.c
@@ -0,0 +1,91 @@
+// 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.
+
+// The C definitions for tracebackctxt.go. That file uses //export so
+// it can't put function definitions in the "C" import comment.
+
+#include <stdlib.h>
+#include <stdint.h>
+
+// Functions exported from Go.
+extern void G1(void);
+extern void G2(void);
+
+void C1() {
+ G1();
+}
+
+void C2() {
+ G2();
+}
+
+struct cgoContextArg {
+ uintptr_t context;
+};
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+struct cgoSymbolizerArg {
+ uintptr_t pc;
+ const char* file;
+ uintptr_t lineno;
+ const char* func;
+ uintptr_t entry;
+ uintptr_t more;
+ uintptr_t data;
+};
+
+// Uses atomic adds and subtracts to catch the possibility of
+// erroneous calls from multiple threads; that should be impossible in
+// this test case, but we check just in case.
+static int contextCount;
+
+int getContextCount() {
+ return __sync_add_and_fetch(&contextCount, 0);
+}
+
+void tcContext(void* parg) {
+ struct cgoContextArg* arg = (struct cgoContextArg*)(parg);
+ if (arg->context == 0) {
+ arg->context = __sync_add_and_fetch(&contextCount, 1);
+ } else {
+ if (arg->context != __sync_add_and_fetch(&contextCount, 0)) {
+ abort();
+ }
+ __sync_sub_and_fetch(&contextCount, 1);
+ }
+}
+
+void tcTraceback(void* parg) {
+ int base, i;
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ if (arg->context == 0) {
+ // This shouldn't happen in this program.
+ abort();
+ }
+ // Return a variable number of PC values.
+ base = arg->context << 8;
+ for (i = 0; i < arg->context; i++) {
+ if (i < arg->max) {
+ arg->buf[i] = base + i;
+ }
+ }
+}
+
+void tcSymbolizer(void *parg) {
+ struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
+ if (arg->pc == 0) {
+ return;
+ }
+ // Report two lines per PC returned by traceback, to test more handling.
+ arg->more = arg->file == NULL;
+ arg->file = "tracebackctxt.go";
+ arg->func = "cFunction";
+ arg->lineno = arg->pc + (arg->more << 16);
+}
diff --git a/libgo/go/runtime/testdata/testprognet/main.go b/libgo/go/runtime/testdata/testprognet/main.go
index 9c227bbf81..ae491a2a97 100644
--- a/libgo/go/runtime/testdata/testprognet/main.go
+++ b/libgo/go/runtime/testdata/testprognet/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprognet/net.go b/libgo/go/runtime/testdata/testprognet/net.go
index c1a7f3f132..714b10162e 100644
--- a/libgo/go/runtime/testdata/testprognet/net.go
+++ b/libgo/go/runtime/testdata/testprognet/net.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/runtime/testdata/testprognet/signal.go b/libgo/go/runtime/testdata/testprognet/signal.go
index 24d142403e..a1559fe616 100644
--- a/libgo/go/runtime/testdata/testprognet/signal.go
+++ b/libgo/go/runtime/testdata/testprognet/signal.go
@@ -1,4 +1,4 @@
-// Copyright 2016 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.
diff --git a/libgo/go/runtime/time.go b/libgo/go/runtime/time.go
new file mode 100644
index 0000000000..604ccded89
--- /dev/null
+++ b/libgo/go/runtime/time.go
@@ -0,0 +1,303 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Time-related runtime and pieces of package time.
+
+package runtime
+
+import "unsafe"
+
+// Package time knows the layout of this structure.
+// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
+type timer struct {
+ i int // heap index
+
+ // Timer wakes up at when, and then at when+period, ... (period > 0 only)
+ // each time calling f(arg, now) in the timer goroutine, so f must be
+ // a well-behaved function and not block.
+ when int64
+ period int64
+ f func(interface{}, uintptr)
+ arg interface{}
+ seq uintptr
+}
+
+var timers struct {
+ lock mutex
+ gp *g
+ created bool
+ sleeping bool
+ rescheduling bool
+ waitnote note
+ t []*timer
+}
+
+// nacl fake time support - time in nanoseconds since 1970
+var faketime int64
+
+// Package time APIs.
+// Godoc uses the comments in package time, not these.
+
+// time.now is implemented in assembly.
+
+// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
+//go:linkname timeSleep time.Sleep
+func timeSleep(ns int64) {
+ if ns <= 0 {
+ return
+ }
+
+ t := new(timer)
+ t.when = nanotime() + ns
+ t.f = goroutineReady
+ t.arg = getg()
+ lock(&timers.lock)
+ addtimerLocked(t)
+ goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
+}
+
+// startTimer adds t to the timer heap.
+//go:linkname startTimer time.startTimer
+func startTimer(t *timer) {
+ if raceenabled {
+ racerelease(unsafe.Pointer(t))
+ }
+ addtimer(t)
+}
+
+// stopTimer removes t from the timer heap if it is there.
+// It returns true if t was removed, false if t wasn't even there.
+//go:linkname stopTimer time.stopTimer
+func stopTimer(t *timer) bool {
+ return deltimer(t)
+}
+
+// Go runtime.
+
+// Ready the goroutine arg.
+func goroutineReady(arg interface{}, seq uintptr) {
+ goready(arg.(*g), 0)
+}
+
+func addtimer(t *timer) {
+ lock(&timers.lock)
+ addtimerLocked(t)
+ unlock(&timers.lock)
+}
+
+// Add a timer to the heap and start or kick timerproc if the new timer is
+// earlier than any of the others.
+// Timers are locked.
+func addtimerLocked(t *timer) {
+ // when must never be negative; otherwise timerproc will overflow
+ // during its delta calculation and never expire other runtime timers.
+ if t.when < 0 {
+ t.when = 1<<63 - 1
+ }
+ t.i = len(timers.t)
+ timers.t = append(timers.t, t)
+ siftupTimer(t.i)
+ if t.i == 0 {
+ // siftup moved to top: new earliest deadline.
+ if timers.sleeping {
+ timers.sleeping = false
+ notewakeup(&timers.waitnote)
+ }
+ if timers.rescheduling {
+ timers.rescheduling = false
+ goready(timers.gp, 0)
+ }
+ }
+ if !timers.created {
+ timers.created = true
+ go timerproc()
+ }
+}
+
+// Delete timer t from the heap.
+// Do not need to update the timerproc: if it wakes up early, no big deal.
+func deltimer(t *timer) bool {
+ // Dereference t so that any panic happens before the lock is held.
+ // Discard result, because t might be moving in the heap.
+ _ = t.i
+
+ lock(&timers.lock)
+ // t may not be registered anymore and may have
+ // a bogus i (typically 0, if generated by Go).
+ // Verify it before proceeding.
+ i := t.i
+ last := len(timers.t) - 1
+ if i < 0 || i > last || timers.t[i] != t {
+ unlock(&timers.lock)
+ return false
+ }
+ if i != last {
+ timers.t[i] = timers.t[last]
+ timers.t[i].i = i
+ }
+ timers.t[last] = nil
+ timers.t = timers.t[:last]
+ if i != last {
+ siftupTimer(i)
+ siftdownTimer(i)
+ }
+ unlock(&timers.lock)
+ return true
+}
+
+// Timerproc runs the time-driven events.
+// It sleeps until the next event in the timers heap.
+// If addtimer inserts a new earlier event, it wakes timerproc early.
+func timerproc() {
+ timers.gp = getg()
+ for {
+ lock(&timers.lock)
+ timers.sleeping = false
+ now := nanotime()
+ delta := int64(-1)
+ for {
+ if len(timers.t) == 0 {
+ delta = -1
+ break
+ }
+ t := timers.t[0]
+ delta = t.when - now
+ if delta > 0 {
+ break
+ }
+ if t.period > 0 {
+ // leave in heap but adjust next time to fire
+ t.when += t.period * (1 + -delta/t.period)
+ siftdownTimer(0)
+ } else {
+ // remove from heap
+ last := len(timers.t) - 1
+ if last > 0 {
+ timers.t[0] = timers.t[last]
+ timers.t[0].i = 0
+ }
+ timers.t[last] = nil
+ timers.t = timers.t[:last]
+ if last > 0 {
+ siftdownTimer(0)
+ }
+ t.i = -1 // mark as removed
+ }
+ f := t.f
+ arg := t.arg
+ seq := t.seq
+ unlock(&timers.lock)
+ if raceenabled {
+ raceacquire(unsafe.Pointer(t))
+ }
+ f(arg, seq)
+ lock(&timers.lock)
+ }
+ if delta < 0 || faketime > 0 {
+ // No timers left - put goroutine to sleep.
+ timers.rescheduling = true
+ goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
+ continue
+ }
+ // At least one timer pending. Sleep until then.
+ timers.sleeping = true
+ noteclear(&timers.waitnote)
+ unlock(&timers.lock)
+ notetsleepg(&timers.waitnote, delta)
+ }
+}
+
+func timejump() *g {
+ if faketime == 0 {
+ return nil
+ }
+
+ lock(&timers.lock)
+ if !timers.created || len(timers.t) == 0 {
+ unlock(&timers.lock)
+ return nil
+ }
+
+ var gp *g
+ if faketime < timers.t[0].when {
+ faketime = timers.t[0].when
+ if timers.rescheduling {
+ timers.rescheduling = false
+ gp = timers.gp
+ }
+ }
+ unlock(&timers.lock)
+ return gp
+}
+
+// Heap maintenance algorithms.
+
+func siftupTimer(i int) {
+ t := timers.t
+ when := t[i].when
+ tmp := t[i]
+ for i > 0 {
+ p := (i - 1) / 4 // parent
+ if when >= t[p].when {
+ break
+ }
+ t[i] = t[p]
+ t[i].i = i
+ t[p] = tmp
+ t[p].i = p
+ i = p
+ }
+}
+
+func siftdownTimer(i int) {
+ t := timers.t
+ n := len(t)
+ when := t[i].when
+ tmp := t[i]
+ for {
+ c := i*4 + 1 // left child
+ c3 := c + 2 // mid child
+ if c >= n {
+ break
+ }
+ w := t[c].when
+ if c+1 < n && t[c+1].when < w {
+ w = t[c+1].when
+ c++
+ }
+ if c3 < n {
+ w3 := t[c3].when
+ if c3+1 < n && t[c3+1].when < w3 {
+ w3 = t[c3+1].when
+ c3++
+ }
+ if w3 < w {
+ w = w3
+ c = c3
+ }
+ }
+ if w >= when {
+ break
+ }
+ t[i] = t[c]
+ t[i].i = i
+ t[c] = tmp
+ t[c].i = c
+ i = c
+ }
+}
+
+// Entry points for net, time to call nanotime.
+
+//go:linkname net_runtimeNano net.runtimeNano
+func net_runtimeNano() int64 {
+ return nanotime()
+}
+
+//go:linkname time_runtimeNano time.runtimeNano
+func time_runtimeNano() int64 {
+ return nanotime()
+}
diff --git a/libgo/go/runtime/trace.go b/libgo/go/runtime/trace.go
new file mode 100644
index 0000000000..61cfa8e751
--- /dev/null
+++ b/libgo/go/runtime/trace.go
@@ -0,0 +1,1033 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to a buffer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events.
+// See https://golang.org/s/go15trace for more info.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// Event types in the trace, args are given in square brackets.
+const (
+ traceEvNone = 0 // unused
+ traceEvBatch = 1 // start of per-P batch of events [pid, timestamp]
+ traceEvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)]
+ traceEvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
+ traceEvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
+ traceEvProcStart = 5 // start of P [timestamp, thread id]
+ traceEvProcStop = 6 // stop of P [timestamp]
+ traceEvGCStart = 7 // GC start [timestamp, seq, stack id]
+ traceEvGCDone = 8 // GC done [timestamp]
+ traceEvGCScanStart = 9 // GC mark termination start [timestamp]
+ traceEvGCScanDone = 10 // GC mark termination done [timestamp]
+ traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id]
+ traceEvGCSweepDone = 12 // GC sweep done [timestamp]
+ traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+ traceEvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq]
+ traceEvGoEnd = 15 // goroutine ends [timestamp]
+ traceEvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack]
+ traceEvGoSched = 17 // goroutine calls Gosched [timestamp, stack]
+ traceEvGoPreempt = 18 // goroutine is preempted [timestamp, stack]
+ traceEvGoSleep = 19 // goroutine calls Sleep [timestamp, stack]
+ traceEvGoBlock = 20 // goroutine blocks [timestamp, stack]
+ traceEvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack]
+ traceEvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack]
+ traceEvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack]
+ traceEvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack]
+ traceEvGoBlockSync = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+ traceEvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack]
+ traceEvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack]
+ traceEvGoSysCall = 28 // syscall enter [timestamp, stack]
+ traceEvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
+ traceEvGoSysBlock = 30 // syscall blocks [timestamp]
+ traceEvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+ traceEvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
+ traceEvHeapAlloc = 33 // memstats.heap_live change [timestamp, heap_alloc]
+ traceEvNextGC = 34 // memstats.next_gc change [timestamp, next_gc]
+ traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
+ traceEvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
+ traceEvString = 37 // string dictionary entry [ID, length, string]
+ traceEvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+ traceEvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+ traceEvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+ traceEvGoStartLabel = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
+ traceEvGoBlockGC = 42 // goroutine blocks on GC assist [timestamp, stack]
+ traceEvCount = 43
+)
+
+const (
+ // Timestamps in trace are cputicks/traceTickDiv.
+ // This makes absolute values of timestamp diffs smaller,
+ // and so they are encoded in less number of bytes.
+ // 64 on x86 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
+ // The suggested increment frequency for PowerPC's time base register is
+ // 512 MHz according to Power ISA v2.07 section 6.2, so we use 16 on ppc64
+ // and ppc64le.
+ // Tracing won't work reliably for architectures where cputicks is emulated
+ // by nanotime, so the value doesn't matter for those architectures.
+ traceTickDiv = 16 + 48*(sys.Goarch386|sys.GoarchAmd64|sys.GoarchAmd64p32)
+ // Maximum number of PCs in a single stack trace.
+ // Since events contain only stack id rather than whole stack trace,
+ // we can allow quite large values here.
+ traceStackSize = 128
+ // Identifier of a fake P that is used when we trace without a real P.
+ traceGlobProc = -1
+ // Maximum number of bytes to encode uint64 in base-128.
+ traceBytesPerNumber = 10
+ // Shift of the number of arguments in the first event byte.
+ traceArgCountShift = 6
+ // Flag passed to traceGoPark to denote that the previous wakeup of this
+ // goroutine was futile. For example, a goroutine was unblocked on a mutex,
+ // but another goroutine got ahead and acquired the mutex before the first
+ // goroutine is scheduled, so the first goroutine has to block again.
+ // Such wakeups happen on buffered channels and sync.Mutex,
+ // but are generally not interesting for end user.
+ traceFutileWakeup byte = 128
+)
+
+// trace is global tracing context.
+var trace struct {
+ lock mutex // protects the following members
+ lockOwner *g // to avoid deadlocks during recursive lock locks
+ enabled bool // when set runtime traces events
+ shutdown bool // set when we are waiting for trace reader to finish after setting enabled to false
+ headerWritten bool // whether ReadTrace has emitted trace header
+ footerWritten bool // whether ReadTrace has emitted trace footer
+ shutdownSema uint32 // used to wait for ReadTrace completion
+ seqStart uint64 // sequence number when tracing was started
+ ticksStart int64 // cputicks when tracing was started
+ ticksEnd int64 // cputicks when tracing was stopped
+ timeStart int64 // nanotime when tracing was started
+ timeEnd int64 // nanotime when tracing was stopped
+ seqGC uint64 // GC start/done sequencer
+ reading traceBufPtr // buffer currently handed off to user
+ empty traceBufPtr // stack of empty buffers
+ fullHead traceBufPtr // queue of full buffers
+ fullTail traceBufPtr
+ reader guintptr // goroutine that called ReadTrace, or nil
+ stackTab traceStackTable // maps stack traces to unique ids
+
+ // Dictionary for traceEvString.
+ //
+ // Currently this is used only at trace setup and for
+ // func/file:line info after tracing session, so we assume
+ // single-threaded access.
+ strings map[string]uint64
+ stringSeq uint64
+
+ // markWorkerLabels maps gcMarkWorkerMode to string ID.
+ markWorkerLabels [len(gcMarkWorkerModeStrings)]uint64
+
+ bufLock mutex // protects buf
+ buf traceBufPtr // global trace buffer, used when running without a p
+}
+
+// traceBufHeader is per-P tracing buffer.
+type traceBufHeader struct {
+ link traceBufPtr // in trace.empty/full
+ lastTicks uint64 // when we wrote the last event
+ pos int // next write offset in arr
+ stk [traceStackSize]location // scratch buffer for traceback
+}
+
+// traceBuf is per-P tracing buffer.
+//
+//go:notinheap
+type traceBuf struct {
+ traceBufHeader
+ arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf
+}
+
+// traceBufPtr is a *traceBuf that is not traced by the garbage
+// collector and doesn't have write barriers. traceBufs are not
+// allocated from the GC'd heap, so this is safe, and are often
+// manipulated in contexts where write barriers are not allowed, so
+// this is necessary.
+//
+// TODO: Since traceBuf is now go:notinheap, this isn't necessary.
+type traceBufPtr uintptr
+
+func (tp traceBufPtr) ptr() *traceBuf { return (*traceBuf)(unsafe.Pointer(tp)) }
+func (tp *traceBufPtr) set(b *traceBuf) { *tp = traceBufPtr(unsafe.Pointer(b)) }
+func traceBufPtrOf(b *traceBuf) traceBufPtr {
+ return traceBufPtr(unsafe.Pointer(b))
+}
+
+// StartTrace enables tracing for the current process.
+// While tracing, the data will be buffered and available via ReadTrace.
+// StartTrace returns an error if tracing is already enabled.
+// Most clients should use the runtime/trace package or the testing package's
+// -test.trace flag instead of calling StartTrace directly.
+func StartTrace() error {
+ // Stop the world, so that we can take a consistent snapshot
+ // of all goroutines at the beginning of the trace.
+ stopTheWorld("start tracing")
+
+ // We are in stop-the-world, but syscalls can finish and write to trace concurrently.
+ // Exitsyscall could check trace.enabled long before and then suddenly wake up
+ // and decide to write to trace at a random point in time.
+ // However, such syscall will use the global trace.buf buffer, because we've
+ // acquired all p's by doing stop-the-world. So this protects us from such races.
+ lock(&trace.bufLock)
+
+ if trace.enabled || trace.shutdown {
+ unlock(&trace.bufLock)
+ startTheWorld()
+ return errorString("tracing is already enabled")
+ }
+
+ // Can't set trace.enabled yet. While the world is stopped, exitsyscall could
+ // already emit a delayed event (see exitTicks in exitsyscall) if we set trace.enabled here.
+ // That would lead to an inconsistent trace:
+ // - either GoSysExit appears before EvGoInSyscall,
+ // - or GoSysExit appears for a goroutine for which we don't emit EvGoInSyscall below.
+ // To instruct traceEvent that it must not ignore events below, we set startingtrace.
+ // trace.enabled is set afterwards once we have emitted all preliminary events.
+ _g_ := getg()
+ _g_.m.startingtrace = true
+
+ // Obtain current stack ID to use in all traceEvGoCreate events below.
+ mp := acquirem()
+ stkBuf := make([]location, traceStackSize)
+ stackID := traceStackID(mp, stkBuf, 2)
+ releasem(mp)
+
+ for _, gp := range allgs {
+ status := readgstatus(gp)
+ if status != _Gdead {
+ gp.traceseq = 0
+ gp.tracelastp = getg().m.p
+ // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
+ id := trace.stackTab.put([]location{location{pc: gp.startpc + sys.PCQuantum}})
+ traceEvent(traceEvGoCreate, -1, uint64(gp.goid), uint64(id), stackID)
+ }
+ if status == _Gwaiting {
+ // traceEvGoWaiting is implied to have seq=1.
+ gp.traceseq++
+ traceEvent(traceEvGoWaiting, -1, uint64(gp.goid))
+ }
+ if status == _Gsyscall {
+ gp.traceseq++
+ traceEvent(traceEvGoInSyscall, -1, uint64(gp.goid))
+ } else {
+ gp.sysblocktraced = false
+ }
+ }
+ traceProcStart()
+ traceGoStart()
+ // Note: ticksStart needs to be set after we emit traceEvGoInSyscall events.
+ // If we do it the other way around, it is possible that exitsyscall will
+ // query sysexitticks after ticksStart but before traceEvGoInSyscall timestamp.
+ // It will lead to a false conclusion that cputicks is broken.
+ trace.ticksStart = cputicks()
+ trace.timeStart = nanotime()
+ trace.headerWritten = false
+ trace.footerWritten = false
+ trace.strings = make(map[string]uint64)
+ trace.stringSeq = 0
+ trace.seqGC = 0
+ _g_.m.startingtrace = false
+ trace.enabled = true
+
+ // Register runtime goroutine labels.
+ _, pid, bufp := traceAcquireBuffer()
+ buf := (*bufp).ptr()
+ if buf == nil {
+ buf = traceFlush(0).ptr()
+ (*bufp).set(buf)
+ }
+ for i, label := range gcMarkWorkerModeStrings[:] {
+ trace.markWorkerLabels[i], buf = traceString(buf, label)
+ }
+ traceReleaseBuffer(pid)
+
+ unlock(&trace.bufLock)
+
+ startTheWorld()
+ return nil
+}
+
+// StopTrace stops tracing, if it was previously enabled.
+// StopTrace only returns after all the reads for the trace have completed.
+func StopTrace() {
+ // Stop the world so that we can collect the trace buffers from all p's below,
+ // and also to avoid races with traceEvent.
+ stopTheWorld("stop tracing")
+
+ // See the comment in StartTrace.
+ lock(&trace.bufLock)
+
+ if !trace.enabled {
+ unlock(&trace.bufLock)
+ startTheWorld()
+ return
+ }
+
+ traceGoSched()
+
+ for _, p := range &allp {
+ if p == nil {
+ break
+ }
+ buf := p.tracebuf
+ if buf != 0 {
+ traceFullQueue(buf)
+ p.tracebuf = 0
+ }
+ }
+ if trace.buf != 0 {
+ buf := trace.buf
+ trace.buf = 0
+ if buf.ptr().pos != 0 {
+ traceFullQueue(buf)
+ }
+ }
+
+ for {
+ trace.ticksEnd = cputicks()
+ trace.timeEnd = nanotime()
+ // Windows time can tick only every 15ms, wait for at least one tick.
+ if trace.timeEnd != trace.timeStart {
+ break
+ }
+ osyield()
+ }
+
+ trace.enabled = false
+ trace.shutdown = true
+ unlock(&trace.bufLock)
+
+ startTheWorld()
+
+ // The world is started but we've set trace.shutdown, so new tracing can't start.
+ // Wait for the trace reader to flush pending buffers and stop.
+ semacquire(&trace.shutdownSema, 0)
+ if raceenabled {
+ raceacquire(unsafe.Pointer(&trace.shutdownSema))
+ }
+
+ // The lock protects us from races with StartTrace/StopTrace because they do stop-the-world.
+ lock(&trace.lock)
+ for _, p := range &allp {
+ if p == nil {
+ break
+ }
+ if p.tracebuf != 0 {
+ throw("trace: non-empty trace buffer in proc")
+ }
+ }
+ if trace.buf != 0 {
+ throw("trace: non-empty global trace buffer")
+ }
+ if trace.fullHead != 0 || trace.fullTail != 0 {
+ throw("trace: non-empty full trace buffer")
+ }
+ if trace.reading != 0 || trace.reader != 0 {
+ throw("trace: reading after shutdown")
+ }
+ for trace.empty != 0 {
+ buf := trace.empty
+ trace.empty = buf.ptr().link
+ sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf.ptr()), &memstats.other_sys)
+ }
+ trace.strings = nil
+ trace.shutdown = false
+ unlock(&trace.lock)
+}
+
+// ReadTrace returns the next chunk of binary tracing data, blocking until data
+// is available. If tracing is turned off and all the data accumulated while it
+// was on has been returned, ReadTrace returns nil. The caller must copy the
+// returned data before calling ReadTrace again.
+// ReadTrace must be called from one goroutine at a time.
+func ReadTrace() []byte {
+ // This function may need to lock trace.lock recursively
+ // (goparkunlock -> traceGoPark -> traceEvent -> traceFlush).
+ // To allow this we use trace.lockOwner.
+ // Also this function must not allocate while holding trace.lock:
+ // allocation can call heap allocate, which will try to emit a trace
+ // event while holding heap lock.
+ lock(&trace.lock)
+ trace.lockOwner = getg()
+
+ if trace.reader != 0 {
+ // More than one goroutine reads trace. This is bad.
+ // But we rather do not crash the program because of tracing,
+ // because tracing can be enabled at runtime on prod servers.
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ println("runtime: ReadTrace called from multiple goroutines simultaneously")
+ return nil
+ }
+ // Recycle the old buffer.
+ if buf := trace.reading; buf != 0 {
+ buf.ptr().link = trace.empty
+ trace.empty = buf
+ trace.reading = 0
+ }
+ // Write trace header.
+ if !trace.headerWritten {
+ trace.headerWritten = true
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ return []byte("go 1.8 trace\x00\x00\x00\x00")
+ }
+ // Wait for new data.
+ if trace.fullHead == 0 && !trace.shutdown {
+ trace.reader.set(getg())
+ goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock, 2)
+ lock(&trace.lock)
+ }
+ // Write a buffer.
+ if trace.fullHead != 0 {
+ buf := traceFullDequeue()
+ trace.reading = buf
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ return buf.ptr().arr[:buf.ptr().pos]
+ }
+ // Write footer with timer frequency.
+ if !trace.footerWritten {
+ trace.footerWritten = true
+ // Use float64 because (trace.ticksEnd - trace.ticksStart) * 1e9 can overflow int64.
+ freq := float64(trace.ticksEnd-trace.ticksStart) * 1e9 / float64(trace.timeEnd-trace.timeStart) / traceTickDiv
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ var data []byte
+ data = append(data, traceEvFrequency|0<<traceArgCountShift)
+ data = traceAppend(data, uint64(freq))
+ if timers.gp != nil {
+ data = append(data, traceEvTimerGoroutine|0<<traceArgCountShift)
+ data = traceAppend(data, uint64(timers.gp.goid))
+ }
+ // This will emit a bunch of full buffers, we will pick them up
+ // on the next iteration.
+ trace.stackTab.dump()
+ return data
+ }
+ // Done.
+ if trace.shutdown {
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ if raceenabled {
+ // Model synchronization on trace.shutdownSema, which race
+ // detector does not see. This is required to avoid false
+ // race reports on writer passed to trace.Start.
+ racerelease(unsafe.Pointer(&trace.shutdownSema))
+ }
+ // trace.enabled is already reset, so can call traceable functions.
+ semrelease(&trace.shutdownSema)
+ return nil
+ }
+ // Also bad, but see the comment above.
+ trace.lockOwner = nil
+ unlock(&trace.lock)
+ println("runtime: spurious wakeup of trace reader")
+ return nil
+}
+
+// traceReader returns the trace reader that should be woken up, if any.
+func traceReader() *g {
+ if trace.reader == 0 || (trace.fullHead == 0 && !trace.shutdown) {
+ return nil
+ }
+ lock(&trace.lock)
+ if trace.reader == 0 || (trace.fullHead == 0 && !trace.shutdown) {
+ unlock(&trace.lock)
+ return nil
+ }
+ gp := trace.reader.ptr()
+ trace.reader.set(nil)
+ unlock(&trace.lock)
+ return gp
+}
+
+// traceProcFree frees trace buffer associated with pp.
+func traceProcFree(pp *p) {
+ buf := pp.tracebuf
+ pp.tracebuf = 0
+ if buf == 0 {
+ return
+ }
+ lock(&trace.lock)
+ traceFullQueue(buf)
+ unlock(&trace.lock)
+}
+
+// traceFullQueue queues buf into queue of full buffers.
+func traceFullQueue(buf traceBufPtr) {
+ buf.ptr().link = 0
+ if trace.fullHead == 0 {
+ trace.fullHead = buf
+ } else {
+ trace.fullTail.ptr().link = buf
+ }
+ trace.fullTail = buf
+}
+
+// traceFullDequeue dequeues from queue of full buffers.
+func traceFullDequeue() traceBufPtr {
+ buf := trace.fullHead
+ if buf == 0 {
+ return 0
+ }
+ trace.fullHead = buf.ptr().link
+ if trace.fullHead == 0 {
+ trace.fullTail = 0
+ }
+ buf.ptr().link = 0
+ return buf
+}
+
+// traceEvent writes a single event to trace buffer, flushing the buffer if necessary.
+// ev is event type.
+// If skip > 0, write current stack id as the last argument (skipping skip top frames).
+// If skip = 0, this event type should contain a stack, but we don't want
+// to collect and remember it for this particular call.
+func traceEvent(ev byte, skip int, args ...uint64) {
+ mp, pid, bufp := traceAcquireBuffer()
+ // Double-check trace.enabled now that we've done m.locks++ and acquired bufLock.
+ // This protects from races between traceEvent and StartTrace/StopTrace.
+
+ // The caller checked that trace.enabled == true, but trace.enabled might have been
+ // turned off between the check and now. Check again. traceLockBuffer did mp.locks++,
+ // StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero,
+ // so if we see trace.enabled == true now, we know it's true for the rest of the function.
+ // Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace
+ // during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer.
+ if !trace.enabled && !mp.startingtrace {
+ traceReleaseBuffer(pid)
+ return
+ }
+ buf := (*bufp).ptr()
+ const maxSize = 2 + 5*traceBytesPerNumber // event type, length, sequence, timestamp, stack id and two add params
+ if buf == nil || len(buf.arr)-buf.pos < maxSize {
+ buf = traceFlush(traceBufPtrOf(buf)).ptr()
+ (*bufp).set(buf)
+ }
+
+ ticks := uint64(cputicks()) / traceTickDiv
+ tickDiff := ticks - buf.lastTicks
+ if buf.pos == 0 {
+ buf.byte(traceEvBatch | 1<<traceArgCountShift)
+ buf.varint(uint64(pid))
+ buf.varint(ticks)
+ tickDiff = 0
+ }
+ buf.lastTicks = ticks
+ narg := byte(len(args))
+ if skip >= 0 {
+ narg++
+ }
+ // We have only 2 bits for number of arguments.
+ // If number is >= 3, then the event type is followed by event length in bytes.
+ if narg > 3 {
+ narg = 3
+ }
+ startPos := buf.pos
+ buf.byte(ev | narg<<traceArgCountShift)
+ var lenp *byte
+ if narg == 3 {
+ // Reserve the byte for length assuming that length < 128.
+ buf.varint(0)
+ lenp = &buf.arr[buf.pos-1]
+ }
+ buf.varint(tickDiff)
+ for _, a := range args {
+ buf.varint(a)
+ }
+ if skip == 0 {
+ buf.varint(0)
+ } else if skip > 0 {
+ buf.varint(traceStackID(mp, buf.stk[:], skip))
+ }
+ evSize := buf.pos - startPos
+ if evSize > maxSize {
+ throw("invalid length of trace event")
+ }
+ if lenp != nil {
+ // Fill in actual length.
+ *lenp = byte(evSize - 2)
+ }
+ traceReleaseBuffer(pid)
+}
+
+func traceStackID(mp *m, buf []location, skip int) uint64 {
+ _g_ := getg()
+ gp := mp.curg
+ var nstk int
+ if gp == _g_ {
+ nstk = callers(skip+1, buf[:])
+ } else if gp != nil {
+ // FIXME: get stack trace of different goroutine.
+ }
+ if nstk > 0 {
+ nstk-- // skip runtime.goexit
+ }
+ if nstk > 0 && gp.goid == 1 {
+ nstk-- // skip runtime.main
+ }
+ id := trace.stackTab.put(buf[:nstk])
+ return uint64(id)
+}
+
+// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
+func traceAcquireBuffer() (mp *m, pid int32, bufp *traceBufPtr) {
+ mp = acquirem()
+ if p := mp.p.ptr(); p != nil {
+ return mp, p.id, &p.tracebuf
+ }
+ lock(&trace.bufLock)
+ return mp, traceGlobProc, &trace.buf
+}
+
+// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer.
+func traceReleaseBuffer(pid int32) {
+ if pid == traceGlobProc {
+ unlock(&trace.bufLock)
+ }
+ releasem(getg().m)
+}
+
+// traceFlush puts buf onto stack of full buffers and returns an empty buffer.
+func traceFlush(buf traceBufPtr) traceBufPtr {
+ owner := trace.lockOwner
+ dolock := owner == nil || owner != getg().m.curg
+ if dolock {
+ lock(&trace.lock)
+ }
+ if buf != 0 {
+ traceFullQueue(buf)
+ }
+ if trace.empty != 0 {
+ buf = trace.empty
+ trace.empty = buf.ptr().link
+ } else {
+ buf = traceBufPtr(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
+ if buf == 0 {
+ throw("trace: out of memory")
+ }
+ }
+ bufp := buf.ptr()
+ bufp.link.set(nil)
+ bufp.pos = 0
+ bufp.lastTicks = 0
+ if dolock {
+ unlock(&trace.lock)
+ }
+ return buf
+}
+
+func traceString(buf *traceBuf, s string) (uint64, *traceBuf) {
+ if s == "" {
+ return 0, buf
+ }
+ if id, ok := trace.strings[s]; ok {
+ return id, buf
+ }
+
+ trace.stringSeq++
+ id := trace.stringSeq
+ trace.strings[s] = id
+
+ size := 1 + 2*traceBytesPerNumber + len(s)
+ if len(buf.arr)-buf.pos < size {
+ buf = traceFlush(traceBufPtrOf(buf)).ptr()
+ }
+ buf.byte(traceEvString)
+ buf.varint(id)
+ buf.varint(uint64(len(s)))
+ buf.pos += copy(buf.arr[buf.pos:], s)
+ return id, buf
+}
+
+// traceAppend appends v to buf in little-endian-base-128 encoding.
+func traceAppend(buf []byte, v uint64) []byte {
+ for ; v >= 0x80; v >>= 7 {
+ buf = append(buf, 0x80|byte(v))
+ }
+ buf = append(buf, byte(v))
+ return buf
+}
+
+// varint appends v to buf in little-endian-base-128 encoding.
+func (buf *traceBuf) varint(v uint64) {
+ pos := buf.pos
+ for ; v >= 0x80; v >>= 7 {
+ buf.arr[pos] = 0x80 | byte(v)
+ pos++
+ }
+ buf.arr[pos] = byte(v)
+ pos++
+ buf.pos = pos
+}
+
+// byte appends v to buf.
+func (buf *traceBuf) byte(v byte) {
+ buf.arr[buf.pos] = v
+ buf.pos++
+}
+
+// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids.
+// It is lock-free for reading.
+type traceStackTable struct {
+ lock mutex
+ seq uint32
+ mem traceAlloc
+ tab [1 << 13]traceStackPtr
+}
+
+// traceStack is a single stack in traceStackTable.
+type traceStack struct {
+ link traceStackPtr
+ hash uintptr
+ id uint32
+ n int
+ stk [0]location // real type [n]location
+}
+
+type traceStackPtr uintptr
+
+func (tp traceStackPtr) ptr() *traceStack { return (*traceStack)(unsafe.Pointer(tp)) }
+
+// stack returns slice of PCs.
+func (ts *traceStack) stack() []location {
+ return (*[traceStackSize]location)(unsafe.Pointer(&ts.stk))[:ts.n]
+}
+
+// put returns a unique id for the stack trace pcs and caches it in the table,
+// if it sees the trace for the first time.
+func (tab *traceStackTable) put(pcs []location) uint32 {
+ if len(pcs) == 0 {
+ return 0
+ }
+ var hash uintptr
+ for _, loc := range pcs {
+ hash += loc.pc
+ hash += hash << 10
+ hash ^= hash >> 6
+ }
+ // First, search the hashtable w/o the mutex.
+ if id := tab.find(pcs, hash); id != 0 {
+ return id
+ }
+ // Now, double check under the mutex.
+ lock(&tab.lock)
+ if id := tab.find(pcs, hash); id != 0 {
+ unlock(&tab.lock)
+ return id
+ }
+ // Create new record.
+ tab.seq++
+ stk := tab.newStack(len(pcs))
+ stk.hash = hash
+ stk.id = tab.seq
+ stk.n = len(pcs)
+ stkpc := stk.stack()
+ for i, pc := range pcs {
+ stkpc[i] = pc
+ }
+ part := int(hash % uintptr(len(tab.tab)))
+ stk.link = tab.tab[part]
+ atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk))
+ unlock(&tab.lock)
+ return stk.id
+}
+
+// find checks if the stack trace pcs is already present in the table.
+func (tab *traceStackTable) find(pcs []location, hash uintptr) uint32 {
+ part := int(hash % uintptr(len(tab.tab)))
+Search:
+ for stk := tab.tab[part].ptr(); stk != nil; stk = stk.link.ptr() {
+ if stk.hash == hash && stk.n == len(pcs) {
+ for i, stkpc := range stk.stack() {
+ if stkpc != pcs[i] {
+ continue Search
+ }
+ }
+ return stk.id
+ }
+ }
+ return 0
+}
+
+// newStack allocates a new stack of size n.
+func (tab *traceStackTable) newStack(n int) *traceStack {
+ return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*unsafe.Sizeof(location{})))
+}
+
+// dump writes all previously cached stacks to trace buffers,
+// releases all memory and resets state.
+func (tab *traceStackTable) dump() {
+ var tmp [(2 + 4*traceStackSize) * traceBytesPerNumber]byte
+ buf := traceFlush(0).ptr()
+ for _, stk := range tab.tab {
+ stk := stk.ptr()
+ for ; stk != nil; stk = stk.link.ptr() {
+ tmpbuf := tmp[:0]
+ tmpbuf = traceAppend(tmpbuf, uint64(stk.id))
+ tmpbuf = traceAppend(tmpbuf, uint64(stk.n))
+ for _, pc := range stk.stack() {
+ var frame traceFrame
+ frame, buf = traceFrameForPC(buf, pc)
+ tmpbuf = traceAppend(tmpbuf, uint64(pc.pc))
+ tmpbuf = traceAppend(tmpbuf, uint64(frame.funcID))
+ tmpbuf = traceAppend(tmpbuf, uint64(frame.fileID))
+ tmpbuf = traceAppend(tmpbuf, uint64(frame.line))
+ }
+ // Now copy to the buffer.
+ size := 1 + traceBytesPerNumber + len(tmpbuf)
+ if len(buf.arr)-buf.pos < size {
+ buf = traceFlush(traceBufPtrOf(buf)).ptr()
+ }
+ buf.byte(traceEvStack | 3<<traceArgCountShift)
+ buf.varint(uint64(len(tmpbuf)))
+ buf.pos += copy(buf.arr[buf.pos:], tmpbuf)
+ }
+ }
+
+ lock(&trace.lock)
+ traceFullQueue(traceBufPtrOf(buf))
+ unlock(&trace.lock)
+
+ tab.mem.drop()
+ *tab = traceStackTable{}
+}
+
+type traceFrame struct {
+ funcID uint64
+ fileID uint64
+ line uint64
+}
+
+func traceFrameForPC(buf *traceBuf, loc location) (traceFrame, *traceBuf) {
+ var frame traceFrame
+ fn := loc.function
+ const maxLen = 1 << 10
+ if len(fn) > maxLen {
+ fn = fn[len(fn)-maxLen:]
+ }
+ frame.funcID, buf = traceString(buf, fn)
+ file, line := loc.filename, loc.lineno
+ frame.line = uint64(line)
+ if len(file) > maxLen {
+ file = file[len(file)-maxLen:]
+ }
+ frame.fileID, buf = traceString(buf, file)
+ return frame, buf
+}
+
+// traceAlloc is a non-thread-safe region allocator.
+// It holds a linked list of traceAllocBlock.
+type traceAlloc struct {
+ head traceAllocBlockPtr
+ off uintptr
+}
+
+// traceAllocBlock is a block in traceAlloc.
+//
+// traceAllocBlock is allocated from non-GC'd memory, so it must not
+// contain heap pointers. Writes to pointers to traceAllocBlocks do
+// not need write barriers.
+//
+//go:notinheap
+type traceAllocBlock struct {
+ next traceAllocBlockPtr
+ data [64<<10 - sys.PtrSize]byte
+}
+
+// TODO: Since traceAllocBlock is now go:notinheap, this isn't necessary.
+type traceAllocBlockPtr uintptr
+
+func (p traceAllocBlockPtr) ptr() *traceAllocBlock { return (*traceAllocBlock)(unsafe.Pointer(p)) }
+func (p *traceAllocBlockPtr) set(x *traceAllocBlock) { *p = traceAllocBlockPtr(unsafe.Pointer(x)) }
+
+// alloc allocates n-byte block.
+func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer {
+ n = round(n, sys.PtrSize)
+ if a.head == 0 || a.off+n > uintptr(len(a.head.ptr().data)) {
+ if n > uintptr(len(a.head.ptr().data)) {
+ throw("trace: alloc too large")
+ }
+ // This is only safe because the strings returned by callers
+ // are stored in a location that is not in the Go heap.
+ block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys))
+ if block == nil {
+ throw("trace: out of memory")
+ }
+ block.next.set(a.head.ptr())
+ a.head.set(block)
+ a.off = 0
+ }
+ p := &a.head.ptr().data[a.off]
+ a.off += n
+ return unsafe.Pointer(p)
+}
+
+// drop frees all previously allocated memory and resets the allocator.
+func (a *traceAlloc) drop() {
+ for a.head != 0 {
+ block := a.head.ptr()
+ a.head.set(block.next.ptr())
+ sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)
+ }
+}
+
+// The following functions write specific events to trace.
+
+func traceGomaxprocs(procs int32) {
+ traceEvent(traceEvGomaxprocs, 1, uint64(procs))
+}
+
+func traceProcStart() {
+ traceEvent(traceEvProcStart, -1, uint64(getg().m.id))
+}
+
+func traceProcStop(pp *p) {
+ // Sysmon and stopTheWorld can stop Ps blocked in syscalls,
+ // to handle this we temporary employ the P.
+ mp := acquirem()
+ oldp := mp.p
+ mp.p.set(pp)
+ traceEvent(traceEvProcStop, -1)
+ mp.p = oldp
+ releasem(mp)
+}
+
+func traceGCStart() {
+ traceEvent(traceEvGCStart, 3, trace.seqGC)
+ trace.seqGC++
+}
+
+func traceGCDone() {
+ traceEvent(traceEvGCDone, -1)
+}
+
+func traceGCScanStart() {
+ traceEvent(traceEvGCScanStart, -1)
+}
+
+func traceGCScanDone() {
+ traceEvent(traceEvGCScanDone, -1)
+}
+
+func traceGCSweepStart() {
+ traceEvent(traceEvGCSweepStart, 1)
+}
+
+func traceGCSweepDone() {
+ traceEvent(traceEvGCSweepDone, -1)
+}
+
+func traceGoCreate(newg *g, pc uintptr) {
+ newg.traceseq = 0
+ newg.tracelastp = getg().m.p
+ // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
+ id := trace.stackTab.put([]location{location{pc: pc + sys.PCQuantum}})
+ traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(id))
+}
+
+func traceGoStart() {
+ _g_ := getg().m.curg
+ _p_ := _g_.m.p
+ _g_.traceseq++
+ if _g_ == _p_.ptr().gcBgMarkWorker.ptr() {
+ traceEvent(traceEvGoStartLabel, -1, uint64(_g_.goid), _g_.traceseq, trace.markWorkerLabels[_p_.ptr().gcMarkWorkerMode])
+ } else if _g_.tracelastp == _p_ {
+ traceEvent(traceEvGoStartLocal, -1, uint64(_g_.goid))
+ } else {
+ _g_.tracelastp = _p_
+ traceEvent(traceEvGoStart, -1, uint64(_g_.goid), _g_.traceseq)
+ }
+}
+
+func traceGoEnd() {
+ traceEvent(traceEvGoEnd, -1)
+}
+
+func traceGoSched() {
+ _g_ := getg()
+ _g_.tracelastp = _g_.m.p
+ traceEvent(traceEvGoSched, 1)
+}
+
+func traceGoPreempt() {
+ _g_ := getg()
+ _g_.tracelastp = _g_.m.p
+ traceEvent(traceEvGoPreempt, 1)
+}
+
+func traceGoPark(traceEv byte, skip int, gp *g) {
+ if traceEv&traceFutileWakeup != 0 {
+ traceEvent(traceEvFutileWakeup, -1)
+ }
+ traceEvent(traceEv & ^traceFutileWakeup, skip)
+}
+
+func traceGoUnpark(gp *g, skip int) {
+ _p_ := getg().m.p
+ gp.traceseq++
+ if gp.tracelastp == _p_ {
+ traceEvent(traceEvGoUnblockLocal, skip, uint64(gp.goid))
+ } else {
+ gp.tracelastp = _p_
+ traceEvent(traceEvGoUnblock, skip, uint64(gp.goid), gp.traceseq)
+ }
+}
+
+func traceGoSysCall() {
+ traceEvent(traceEvGoSysCall, 1)
+}
+
+func traceGoSysExit(ts int64) {
+ if ts != 0 && ts < trace.ticksStart {
+ // There is a race between the code that initializes sysexitticks
+ // (in exitsyscall, which runs without a P, and therefore is not
+ // stopped with the rest of the world) and the code that initializes
+ // a new trace. The recorded sysexitticks must therefore be treated
+ // as "best effort". If they are valid for this trace, then great,
+ // use them for greater accuracy. But if they're not valid for this
+ // trace, assume that the trace was started after the actual syscall
+ // exit (but before we actually managed to start the goroutine,
+ // aka right now), and assign a fresh time stamp to keep the log consistent.
+ ts = 0
+ }
+ _g_ := getg().m.curg
+ _g_.traceseq++
+ _g_.tracelastp = _g_.m.p
+ traceEvent(traceEvGoSysExit, -1, uint64(_g_.goid), _g_.traceseq, uint64(ts)/traceTickDiv)
+}
+
+func traceGoSysBlock(pp *p) {
+ // Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked,
+ // to handle this we temporary employ the P.
+ mp := acquirem()
+ oldp := mp.p
+ mp.p.set(pp)
+ traceEvent(traceEvGoSysBlock, -1)
+ mp.p = oldp
+ releasem(mp)
+}
+
+func traceHeapAlloc() {
+ traceEvent(traceEvHeapAlloc, -1, memstats.heap_live)
+}
+
+func traceNextGC() {
+ if memstats.next_gc == ^uint64(0) {
+ // Heap-based triggering is disabled.
+ traceEvent(traceEvNextGC, -1, 0)
+ } else {
+ traceEvent(traceEvNextGC, -1, memstats.next_gc)
+ }
+}
diff --git a/libgo/go/runtime/trace/trace.go b/libgo/go/runtime/trace/trace.go
new file mode 100644
index 0000000000..7cbb8a6e82
--- /dev/null
+++ b/libgo/go/runtime/trace/trace.go
@@ -0,0 +1,42 @@
+// 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.
+
+// Go execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to an io.Writer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events. A trace can be analyzed later with
+// 'go tool trace' command.
+package trace
+
+import (
+ "io"
+ "runtime"
+)
+
+// Start enables tracing for the current program.
+// While tracing, the trace will be buffered and written to w.
+// Start returns an error if tracing is already enabled.
+func Start(w io.Writer) error {
+ if err := runtime.StartTrace(); err != nil {
+ return err
+ }
+ go func() {
+ for {
+ data := runtime.ReadTrace()
+ if data == nil {
+ break
+ }
+ w.Write(data)
+ }
+ }()
+ return nil
+}
+
+// Stop stops the current tracing, if any.
+// Stop only returns after all the writes for the trace have completed.
+func Stop() {
+ runtime.StopTrace()
+}
diff --git a/libgo/go/runtime/trace/trace_stack_test.go b/libgo/go/runtime/trace/trace_stack_test.go
new file mode 100644
index 0000000000..c37b33de86
--- /dev/null
+++ b/libgo/go/runtime/trace/trace_stack_test.go
@@ -0,0 +1,282 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package trace_test
+
+import (
+ "bytes"
+ "internal/testenv"
+ "internal/trace"
+ "net"
+ "os"
+ "runtime"
+ . "runtime/trace"
+ "sync"
+ "testing"
+ "time"
+)
+
+// TestTraceSymbolize tests symbolization and that events has proper stacks.
+// In particular that we strip bottom uninteresting frames like goexit,
+// top uninteresting frames (runtime guts).
+func TestTraceSymbolize(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+ defer Stop() // in case of early return
+
+ // Now we will do a bunch of things for which we verify stacks later.
+ // It is impossible to ensure that a goroutine has actually blocked
+ // on a channel, in a select or otherwise. So we kick off goroutines
+ // that need to block first in the hope that while we are executing
+ // the rest of the test, they will block.
+ go func() {
+ select {}
+ }()
+ go func() {
+ var c chan int
+ c <- 0
+ }()
+ go func() {
+ var c chan int
+ <-c
+ }()
+ done1 := make(chan bool)
+ go func() {
+ <-done1
+ }()
+ done2 := make(chan bool)
+ go func() {
+ done2 <- true
+ }()
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ select {
+ case <-c1:
+ case <-c2:
+ }
+ }()
+ var mu sync.Mutex
+ mu.Lock()
+ go func() {
+ mu.Lock()
+ mu.Unlock()
+ }()
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ wg.Wait()
+ }()
+ cv := sync.NewCond(&sync.Mutex{})
+ go func() {
+ cv.L.Lock()
+ cv.Wait()
+ cv.L.Unlock()
+ }()
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("failed to listen: %v", err)
+ }
+ go func() {
+ c, err := ln.Accept()
+ if err != nil {
+ t.Errorf("failed to accept: %v", err)
+ return
+ }
+ c.Close()
+ }()
+ rp, wp, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("failed to create a pipe: %v", err)
+ }
+ defer rp.Close()
+ defer wp.Close()
+ pipeReadDone := make(chan bool)
+ go func() {
+ var data [1]byte
+ rp.Read(data[:])
+ pipeReadDone <- true
+ }()
+
+ time.Sleep(100 * time.Millisecond)
+ runtime.GC()
+ runtime.Gosched()
+ time.Sleep(100 * time.Millisecond) // the last chance for the goroutines above to block
+ done1 <- true
+ <-done2
+ select {
+ case c1 <- 0:
+ case c2 <- 0:
+ }
+ mu.Unlock()
+ wg.Done()
+ cv.Signal()
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatalf("failed to dial: %v", err)
+ }
+ c.Close()
+ var data [1]byte
+ wp.Write(data[:])
+ <-pipeReadDone
+
+ Stop()
+ events, _ := parseTrace(t, buf)
+
+ // Now check that the stacks are correct.
+ type frame struct {
+ Fn string
+ Line int
+ }
+ type eventDesc struct {
+ Type byte
+ Stk []frame
+ }
+ want := []eventDesc{
+ {trace.EvGCStart, []frame{
+ {"runtime.GC", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 107},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoStart, []frame{
+ {"runtime/trace_test.TestTraceSymbolize.func1", 37},
+ }},
+ {trace.EvGoSched, []frame{
+ {"runtime/trace_test.TestTraceSymbolize", 108},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoCreate, []frame{
+ {"runtime/trace_test.TestTraceSymbolize", 39},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoStop, []frame{
+ {"runtime.block", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func1", 38},
+ }},
+ {trace.EvGoStop, []frame{
+ {"runtime.chansend1", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func2", 42},
+ }},
+ {trace.EvGoStop, []frame{
+ {"runtime.chanrecv1", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func3", 46},
+ }},
+ {trace.EvGoBlockRecv, []frame{
+ {"runtime.chanrecv1", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func4", 50},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"runtime.chansend1", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 110},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoBlockSend, []frame{
+ {"runtime.chansend1", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func5", 54},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"runtime.chanrecv1", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 111},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoBlockSelect, []frame{
+ {"runtime.selectgo", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func6", 59},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"runtime.selectgo", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 112},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoBlockSync, []frame{
+ {"sync.(*Mutex).Lock", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func7", 67},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"sync.(*Mutex).Unlock", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 116},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoBlockSync, []frame{
+ {"sync.(*WaitGroup).Wait", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func8", 73},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"sync.(*WaitGroup).Add", 0},
+ {"sync.(*WaitGroup).Done", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 117},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoBlockCond, []frame{
+ {"sync.(*Cond).Wait", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func9", 78},
+ }},
+ {trace.EvGoUnblock, []frame{
+ {"sync.(*Cond).Signal", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 118},
+ {"testing.tRunner", 0},
+ }},
+ {trace.EvGoSleep, []frame{
+ {"time.Sleep", 0},
+ {"runtime/trace_test.TestTraceSymbolize", 109},
+ {"testing.tRunner", 0},
+ }},
+ }
+ // Stacks for the following events are OS-dependent due to OS-specific code in net package.
+ if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
+ want = append(want, []eventDesc{
+ {trace.EvGoBlockNet, []frame{
+ {"net.(*netFD).accept", 0},
+ {"net.(*TCPListener).accept", 0},
+ {"net.(*TCPListener).Accept", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func10", 86},
+ }},
+ {trace.EvGoSysCall, []frame{
+ {"syscall.read", 0},
+ {"syscall.Read", 0},
+ {"os.(*File).read", 0},
+ {"os.(*File).Read", 0},
+ {"runtime/trace_test.TestTraceSymbolize.func11", 102},
+ }},
+ }...)
+ }
+ matched := make([]bool, len(want))
+ for _, ev := range events {
+ wantLoop:
+ for i, w := range want {
+ if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) {
+ continue
+ }
+
+ for fi, f := range ev.Stk {
+ wf := w.Stk[fi]
+ if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line {
+ continue wantLoop
+ }
+ }
+ matched[i] = true
+ }
+ }
+ for i, m := range matched {
+ if m {
+ continue
+ }
+ w := want[i]
+ t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line)
+ t.Errorf("seen the following events of this type:")
+ for _, ev := range events {
+ if ev.Type != w.Type {
+ continue
+ }
+ for _, f := range ev.Stk {
+ t.Logf(" %v:%v", f.Fn, f.Line)
+ }
+ t.Logf("---")
+ }
+ }
+}
diff --git a/libgo/go/runtime/trace/trace_test.go b/libgo/go/runtime/trace/trace_test.go
new file mode 100644
index 0000000000..c5f64fcf4c
--- /dev/null
+++ b/libgo/go/runtime/trace/trace_test.go
@@ -0,0 +1,489 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package trace_test
+
+import (
+ "bytes"
+ "flag"
+ "internal/trace"
+ "io"
+ "io/ioutil"
+ "net"
+ "os"
+ "runtime"
+ . "runtime/trace"
+ "sync"
+ "testing"
+ "time"
+)
+
+var (
+ saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
+)
+
+func TestTraceStartStop(t *testing.T) {
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+ Stop()
+ size := buf.Len()
+ if size == 0 {
+ t.Fatalf("trace is empty")
+ }
+ time.Sleep(100 * time.Millisecond)
+ if size != buf.Len() {
+ t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
+ }
+ saveTrace(t, buf, "TestTraceStartStop")
+}
+
+func TestTraceDoubleStart(t *testing.T) {
+ Stop()
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+ if err := Start(buf); err == nil {
+ t.Fatalf("succeed to start tracing second time")
+ }
+ Stop()
+ Stop()
+}
+
+func TestTrace(t *testing.T) {
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+ Stop()
+ saveTrace(t, buf, "TestTrace")
+ _, err := trace.Parse(buf, "")
+ if err == trace.ErrTimeOrder {
+ t.Skipf("skipping trace: %v", err)
+ }
+ if err != nil {
+ t.Fatalf("failed to parse trace: %v", err)
+ }
+}
+
+func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc) {
+ events, err := trace.Parse(r, "")
+ if err == trace.ErrTimeOrder {
+ t.Skipf("skipping trace: %v", err)
+ }
+ if err != nil {
+ t.Fatalf("failed to parse trace: %v", err)
+ }
+ gs := trace.GoroutineStats(events)
+ for goid := range gs {
+ // We don't do any particular checks on the result at the moment.
+ // But still check that RelatedGoroutines does not crash, hang, etc.
+ _ = trace.RelatedGoroutines(events, goid)
+ }
+ return events, gs
+}
+
+func testBrokenTimestamps(t *testing.T, data []byte) {
+ // On some processors cputicks (used to generate trace timestamps)
+ // produce non-monotonic timestamps. It is important that the parser
+ // distinguishes logically inconsistent traces (e.g. missing, excessive
+ // or misordered events) from broken timestamps. The former is a bug
+ // in tracer, the latter is a machine issue.
+ // So now that we have a consistent trace, test that (1) parser does
+ // not return a logical error in case of broken timestamps
+ // and (2) broken timestamps are eventually detected and reported.
+ trace.BreakTimestampsForTesting = true
+ defer func() {
+ trace.BreakTimestampsForTesting = false
+ }()
+ for i := 0; i < 1e4; i++ {
+ _, err := trace.Parse(bytes.NewReader(data), "")
+ if err == trace.ErrTimeOrder {
+ return
+ }
+ if err != nil {
+ t.Fatalf("failed to parse trace: %v", err)
+ }
+ }
+}
+
+func TestTraceStress(t *testing.T) {
+ var wg sync.WaitGroup
+ done := make(chan bool)
+
+ // Create a goroutine blocked before tracing.
+ wg.Add(1)
+ go func() {
+ <-done
+ wg.Done()
+ }()
+
+ // Create a goroutine blocked in syscall before tracing.
+ rp, wp, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("failed to create pipe: %v", err)
+ }
+ defer func() {
+ rp.Close()
+ wp.Close()
+ }()
+ wg.Add(1)
+ go func() {
+ var tmp [1]byte
+ rp.Read(tmp[:])
+ <-done
+ wg.Done()
+ }()
+ time.Sleep(time.Millisecond) // give the goroutine above time to block
+
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+
+ procs := runtime.GOMAXPROCS(10)
+ time.Sleep(50 * time.Millisecond) // test proc stop/start events
+
+ go func() {
+ runtime.LockOSThread()
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ runtime.Gosched()
+ }
+ }
+ }()
+
+ runtime.GC()
+ // Trigger GC from malloc.
+ n := int(1e3)
+ if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
+ // Reduce allocation to avoid running out of
+ // memory on the builder - see issue/12032.
+ n = 512
+ }
+ for i := 0; i < n; i++ {
+ _ = make([]byte, 1<<20)
+ }
+
+ // Create a bunch of busy goroutines to load all Ps.
+ for p := 0; p < 10; p++ {
+ wg.Add(1)
+ go func() {
+ // Do something useful.
+ tmp := make([]byte, 1<<16)
+ for i := range tmp {
+ tmp[i]++
+ }
+ _ = tmp
+ <-done
+ wg.Done()
+ }()
+ }
+
+ // Block in syscall.
+ wg.Add(1)
+ go func() {
+ var tmp [1]byte
+ rp.Read(tmp[:])
+ <-done
+ wg.Done()
+ }()
+
+ // Test timers.
+ timerDone := make(chan bool)
+ go func() {
+ time.Sleep(time.Millisecond)
+ timerDone <- true
+ }()
+ <-timerDone
+
+ // A bit of network.
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("listen failed: %v", err)
+ }
+ defer ln.Close()
+ go func() {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ time.Sleep(time.Millisecond)
+ var buf [1]byte
+ c.Write(buf[:])
+ c.Close()
+ }()
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatalf("dial failed: %v", err)
+ }
+ var tmp [1]byte
+ c.Read(tmp[:])
+ c.Close()
+
+ go func() {
+ runtime.Gosched()
+ select {}
+ }()
+
+ // Unblock helper goroutines and wait them to finish.
+ wp.Write(tmp[:])
+ wp.Write(tmp[:])
+ close(done)
+ wg.Wait()
+
+ runtime.GOMAXPROCS(procs)
+
+ Stop()
+ saveTrace(t, buf, "TestTraceStress")
+ trace := buf.Bytes()
+ parseTrace(t, buf)
+ testBrokenTimestamps(t, trace)
+}
+
+// Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
+// And concurrently with all that start/stop trace 3 times.
+func TestTraceStressStartStop(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
+ outerDone := make(chan bool)
+
+ go func() {
+ defer func() {
+ outerDone <- true
+ }()
+
+ var wg sync.WaitGroup
+ done := make(chan bool)
+
+ wg.Add(1)
+ go func() {
+ <-done
+ wg.Done()
+ }()
+
+ rp, wp, err := os.Pipe()
+ if err != nil {
+ t.Errorf("failed to create pipe: %v", err)
+ return
+ }
+ defer func() {
+ rp.Close()
+ wp.Close()
+ }()
+ wg.Add(1)
+ go func() {
+ var tmp [1]byte
+ rp.Read(tmp[:])
+ <-done
+ wg.Done()
+ }()
+ time.Sleep(time.Millisecond)
+
+ go func() {
+ runtime.LockOSThread()
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ runtime.Gosched()
+ }
+ }
+ }()
+
+ runtime.GC()
+ // Trigger GC from malloc.
+ n := int(1e3)
+ if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
+ // Reduce allocation to avoid running out of
+ // memory on the builder - see issue/12032.
+ n = 512
+ }
+ for i := 0; i < n; i++ {
+ _ = make([]byte, 1<<20)
+ }
+
+ // Create a bunch of busy goroutines to load all Ps.
+ for p := 0; p < 10; p++ {
+ wg.Add(1)
+ go func() {
+ // Do something useful.
+ tmp := make([]byte, 1<<16)
+ for i := range tmp {
+ tmp[i]++
+ }
+ _ = tmp
+ <-done
+ wg.Done()
+ }()
+ }
+
+ // Block in syscall.
+ wg.Add(1)
+ go func() {
+ var tmp [1]byte
+ rp.Read(tmp[:])
+ <-done
+ wg.Done()
+ }()
+
+ runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+ // Test timers.
+ timerDone := make(chan bool)
+ go func() {
+ time.Sleep(time.Millisecond)
+ timerDone <- true
+ }()
+ <-timerDone
+
+ // A bit of network.
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Errorf("listen failed: %v", err)
+ return
+ }
+ defer ln.Close()
+ go func() {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ time.Sleep(time.Millisecond)
+ var buf [1]byte
+ c.Write(buf[:])
+ c.Close()
+ }()
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Errorf("dial failed: %v", err)
+ return
+ }
+ var tmp [1]byte
+ c.Read(tmp[:])
+ c.Close()
+
+ go func() {
+ runtime.Gosched()
+ select {}
+ }()
+
+ // Unblock helper goroutines and wait them to finish.
+ wp.Write(tmp[:])
+ wp.Write(tmp[:])
+ close(done)
+ wg.Wait()
+ }()
+
+ for i := 0; i < 3; i++ {
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+ time.Sleep(time.Millisecond)
+ Stop()
+ saveTrace(t, buf, "TestTraceStressStartStop")
+ trace := buf.Bytes()
+ parseTrace(t, buf)
+ testBrokenTimestamps(t, trace)
+ }
+ <-outerDone
+}
+
+func TestTraceFutileWakeup(t *testing.T) {
+ buf := new(bytes.Buffer)
+ if err := Start(buf); err != nil {
+ t.Fatalf("failed to start tracing: %v", err)
+ }
+
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
+ c0 := make(chan int, 1)
+ c1 := make(chan int, 1)
+ c2 := make(chan int, 1)
+ const procs = 2
+ var done sync.WaitGroup
+ done.Add(4 * procs)
+ for p := 0; p < procs; p++ {
+ const iters = 1e3
+ go func() {
+ for i := 0; i < iters; i++ {
+ runtime.Gosched()
+ c0 <- 0
+ }
+ done.Done()
+ }()
+ go func() {
+ for i := 0; i < iters; i++ {
+ runtime.Gosched()
+ <-c0
+ }
+ done.Done()
+ }()
+ go func() {
+ for i := 0; i < iters; i++ {
+ runtime.Gosched()
+ select {
+ case c1 <- 0:
+ case c2 <- 0:
+ }
+ }
+ done.Done()
+ }()
+ go func() {
+ for i := 0; i < iters; i++ {
+ runtime.Gosched()
+ select {
+ case <-c1:
+ case <-c2:
+ }
+ }
+ done.Done()
+ }()
+ }
+ done.Wait()
+
+ Stop()
+ saveTrace(t, buf, "TestTraceFutileWakeup")
+ events, _ := parseTrace(t, buf)
+ // Check that (1) trace does not contain EvFutileWakeup events and
+ // (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events
+ // (we call runtime.Gosched between all operations, so these would be futile wakeups).
+ gs := make(map[uint64]int)
+ for _, ev := range events {
+ switch ev.Type {
+ case trace.EvFutileWakeup:
+ t.Fatalf("found EvFutileWakeup event")
+ case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect:
+ if gs[ev.G] == 2 {
+ t.Fatalf("goroutine %v blocked on %v at %v right after start",
+ ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
+ }
+ if gs[ev.G] == 1 {
+ t.Fatalf("goroutine %v blocked on %v at %v while blocked",
+ ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
+ }
+ gs[ev.G] = 1
+ case trace.EvGoStart:
+ if gs[ev.G] == 1 {
+ gs[ev.G] = 2
+ }
+ default:
+ delete(gs, ev.G)
+ }
+ }
+}
+
+func saveTrace(t *testing.T, buf *bytes.Buffer, name string) {
+ if !*saveTraces {
+ return
+ }
+ if err := ioutil.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
+ t.Errorf("failed to write trace file: %s", err)
+ }
+}
diff --git a/libgo/go/runtime/traceback_gccgo.go b/libgo/go/runtime/traceback_gccgo.go
new file mode 100644
index 0000000000..611aba91a4
--- /dev/null
+++ b/libgo/go/runtime/traceback_gccgo.go
@@ -0,0 +1,228 @@
+// 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.
+
+// Traceback support for gccgo.
+// The actual traceback code is written in C.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ _ "unsafe" // for go:linkname
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+// These are temporary for C runtime code to call.
+//go:linkname traceback runtime.traceback
+//go:linkname printtrace runtime.printtrace
+//go:linkname goroutineheader runtime.goroutineheader
+//go:linkname printcreatedby runtime.printcreatedby
+
+func printcreatedby(gp *g) {
+ // Show what created goroutine, except main goroutine (goid 1).
+ pc := gp.gopc
+ tracepc := pc // back up to CALL instruction for funcfileline.
+ entry := funcentry(tracepc)
+ if entry != 0 && tracepc > entry {
+ tracepc -= sys.PCQuantum
+ }
+ function, file, line := funcfileline(tracepc, -1)
+ if function != "" && showframe(function, gp) && gp.goid != 1 {
+ print("created by ", function, "\n")
+ print("\t", file, ":", line)
+ if entry != 0 && pc > entry {
+ print(" +", hex(pc-entry))
+ }
+ print("\n")
+ }
+}
+
+// tracebackg is used to collect stack traces from other goroutines.
+type tracebackg struct {
+ gp *g
+ locbuf [_TracebackMaxFrames]location
+ c int
+}
+
+// location is a location in the program, used for backtraces.
+type location struct {
+ pc uintptr
+ filename string
+ function string
+ lineno int
+}
+
+//extern runtime_callers
+func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32
+
+// callers returns a stack trace of the current goroutine.
+// The gc version of callers takes []uintptr, but we take []location.
+func callers(skip int, locbuf []location) int {
+ n := c_callers(int32(skip), &locbuf[0], int32(len(locbuf)), false)
+ return int(n)
+}
+
+// traceback prints a traceback of the current goroutine.
+// This differs from the gc version, which is given pc, sp, lr and g and
+// can print a traceback of any goroutine.
+func traceback(skip int32) {
+ var locbuf [100]location
+ c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false)
+ printtrace(locbuf[:c], getg())
+}
+
+// printtrace prints a traceback from locbuf.
+func printtrace(locbuf []location, gp *g) {
+ for i := range locbuf {
+ if showframe(locbuf[i].function, gp) {
+ print(locbuf[i].function, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n")
+ }
+ }
+}
+
+// showframe returns whether to print a frame in a traceback.
+// name is the function name.
+func showframe(name string, gp *g) bool {
+ g := getg()
+ if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
+ return true
+ }
+
+ // Gccgo can trace back through C functions called via cgo.
+ // We want to print those in the traceback.
+ // But unless GOTRACEBACK > 1 (checked below), still skip
+ // internal C functions and cgo-generated functions.
+ if !contains(name, ".") && !hasprefix(name, "__go_") && !hasprefix(name, "_cgo_") {
+ return true
+ }
+
+ level, _, _ := gotraceback()
+
+ // Special case: always show runtime.gopanic frame, so that we can
+ // see where a panic started in the middle of a stack trace.
+ // See golang.org/issue/5832.
+ // __go_panic is the current gccgo name.
+ if name == "runtime.gopanic" || name == "__go_panic" {
+ return true
+ }
+
+ return level > 1 || contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+}
+
+// isExportedRuntime reports whether name is an exported runtime function.
+// It is only for runtime functions, so ASCII A-Z is fine.
+func isExportedRuntime(name string) bool {
+ const n = len("runtime.")
+ return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
+}
+
+var gStatusStrings = [...]string{
+ _Gidle: "idle",
+ _Grunnable: "runnable",
+ _Grunning: "running",
+ _Gsyscall: "syscall",
+ _Gwaiting: "waiting",
+ _Gdead: "dead",
+ _Gcopystack: "copystack",
+}
+
+func goroutineheader(gp *g) {
+ gpstatus := readgstatus(gp)
+
+ isScan := gpstatus&_Gscan != 0
+ gpstatus &^= _Gscan // drop the scan bit
+
+ // Basic string status
+ var status string
+ if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
+ status = gStatusStrings[gpstatus]
+ } else {
+ status = "???"
+ }
+
+ // Override.
+ if gpstatus == _Gwaiting && gp.waitreason != "" {
+ status = gp.waitreason
+ }
+
+ // approx time the G is blocked, in minutes
+ var waitfor int64
+ if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
+ waitfor = (nanotime() - gp.waitsince) / 60e9
+ }
+ print("goroutine ", gp.goid, " [", status)
+ if isScan {
+ print(" (scan)")
+ }
+ if waitfor >= 1 {
+ print(", ", waitfor, " minutes")
+ }
+ if gp.lockedm != nil {
+ print(", locked to thread")
+ }
+ print("]:\n")
+}
+
+// isSystemGoroutine reports whether the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+ // FIXME.
+ return false
+}
+
+func tracebackothers(me *g) {
+ var tb tracebackg
+ tb.gp = me
+
+ level, _, _ := gotraceback()
+
+ // Show the current goroutine first, if we haven't already.
+ g := getg()
+ gp := g.m.curg
+ if gp != nil && gp != me {
+ print("\n")
+ goroutineheader(gp)
+ gp.traceback = &tb
+ getTraceback(me, gp)
+ printtrace(tb.locbuf[:tb.c], nil)
+ printcreatedby(gp)
+ }
+
+ lock(&allglock)
+ for _, gp := range allgs {
+ if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
+ continue
+ }
+ print("\n")
+ goroutineheader(gp)
+
+ // gccgo's only mechanism for doing a stack trace is
+ // _Unwind_Backtrace. And that only works for the
+ // current thread, not for other random goroutines.
+ // So we need to switch context to the goroutine, get
+ // the backtrace, and then switch back.
+ //
+ // This means that if g is running or in a syscall, we
+ // can't reliably print a stack trace. FIXME.
+
+ // Note: gp.m == g.m occurs when tracebackothers is
+ // called from a signal handler initiated during a
+ // systemstack call. The original G is still in the
+ // running state, and we want to print its stack.
+ if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
+ print("\tgoroutine running on other thread; stack unavailable\n")
+ printcreatedby(gp)
+ } else if readgstatus(gp)&^_Gscan == _Gsyscall {
+ print("\tgoroutine in C code; stack unavailable\n")
+ printcreatedby(gp)
+ } else {
+ gp.traceback = &tb
+ getTraceback(me, gp)
+ printtrace(tb.locbuf[:tb.c], nil)
+ printcreatedby(gp)
+ }
+ }
+ unlock(&allglock)
+}
diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go
new file mode 100644
index 0000000000..cfee35a6fe
--- /dev/null
+++ b/libgo/go/runtime/type.go
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Runtime type representation.
+
+package runtime
+
+import "unsafe"
+
+type _type struct {
+ kind uint8
+ align int8
+ fieldAlign uint8
+ _ uint8
+ size uintptr
+ hash uint32
+
+ hashfn func(unsafe.Pointer, uintptr) uintptr
+ equalfn func(unsafe.Pointer, unsafe.Pointer) bool
+
+ gc unsafe.Pointer
+ string *string
+ *uncommontype
+ ptrToThis *_type
+}
+
+// Return whether two type descriptors are equal.
+// This is gccgo-specific, as gccgo, unlike gc, permits multiple
+// independent descriptors for a single type.
+func eqtype(t1, t2 *_type) bool {
+ switch {
+ case t1 == t2:
+ return true
+ case t1 == nil || t2 == nil:
+ return false
+ case t1.kind != t2.kind || t1.hash != t2.hash:
+ return false
+ default:
+ return *t1.string == *t2.string
+ }
+}
+
+type method struct {
+ name *string
+ pkgPath *string
+ mtyp *_type
+ typ *_type
+ tfn unsafe.Pointer
+}
+
+type uncommontype struct {
+ name *string
+ pkgPath *string
+ methods []method
+}
+
+type imethod struct {
+ name *string
+ pkgPath *string
+ typ *_type
+}
+
+type interfacetype struct {
+ typ _type
+ methods []imethod
+}
+
+type maptype struct {
+ typ _type
+ key *_type
+ elem *_type
+ bucket *_type // internal type representing a hash bucket
+ hmap *_type // internal type representing a hmap
+ keysize uint8 // size of key slot
+ indirectkey bool // store ptr to key instead of key itself
+ valuesize uint8 // size of value slot
+ indirectvalue bool // store ptr to value instead of value itself
+ bucketsize uint16 // size of bucket
+ reflexivekey bool // true if k==k for all keys
+ needkeyupdate bool // true if we need to update key on an overwrite
+}
+
+type arraytype struct {
+ typ _type
+ elem *_type
+ slice *_type
+ len uintptr
+}
+
+type chantype struct {
+ typ _type
+ elem *_type
+ dir uintptr
+}
+
+type slicetype struct {
+ typ _type
+ elem *_type
+}
+
+type functype struct {
+ typ _type
+ dotdotdot bool
+ in []*_type
+ out []*_type
+}
+
+type ptrtype struct {
+ typ _type
+ elem *_type
+}
+
+type structfield struct {
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *_type // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
+}
+
+type structtype struct {
+ typ _type
+ fields []structfield
+}
diff --git a/libgo/go/runtime/typekind.go b/libgo/go/runtime/typekind.go
new file mode 100644
index 0000000000..abb27777fe
--- /dev/null
+++ b/libgo/go/runtime/typekind.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ kindBool = 1 + iota
+ kindInt
+ kindInt8
+ kindInt16
+ kindInt32
+ kindInt64
+ kindUint
+ kindUint8
+ kindUint16
+ kindUint32
+ kindUint64
+ kindUintptr
+ kindFloat32
+ kindFloat64
+ kindComplex64
+ kindComplex128
+ kindArray
+ kindChan
+ kindFunc
+ kindInterface
+ kindMap
+ kindPtr
+ kindSlice
+ kindString
+ kindStruct
+ kindUnsafePointer
+
+ kindDirectIface = 1 << 5
+ kindGCProg = 1 << 6
+ kindNoPointers = 1 << 7
+ kindMask = (1 << 5) - 1
+)
+
+// isDirectIface reports whether t is stored directly in an interface value.
+func isDirectIface(t *_type) bool {
+ return t.kind&kindDirectIface != 0
+}
diff --git a/libgo/go/runtime/unaligned1.go b/libgo/go/runtime/unaligned1.go
new file mode 100644
index 0000000000..c94f19eeb9
--- /dev/null
+++ b/libgo/go/runtime/unaligned1.go
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm64 ppc64 ppc64le s390x ppc s390 arm64be
+
+package runtime
+
+import "unsafe"
+
+func readUnaligned32(p unsafe.Pointer) uint32 {
+ return *(*uint32)(p)
+}
+
+func readUnaligned64(p unsafe.Pointer) uint64 {
+ return *(*uint64)(p)
+}
diff --git a/libgo/go/runtime/unaligned2.go b/libgo/go/runtime/unaligned2.go
new file mode 100644
index 0000000000..b8aefb9522
--- /dev/null
+++ b/libgo/go/runtime/unaligned2.go
@@ -0,0 +1,20 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm mips mipsle mips64 mips64le armbe m68k mipso32 mipsn32 sparc alpha ia64 mipso64 mipsn64 mips64p32 mips64p32le sparc64
+
+package runtime
+
+import "unsafe"
+
+// Note: These routines perform the read with an unspecified endianness.
+func readUnaligned32(p unsafe.Pointer) uint32 {
+ q := (*[4]byte)(p)
+ return uint32(q[0]) + uint32(q[1])<<8 + uint32(q[2])<<16 + uint32(q[3])<<24
+}
+
+func readUnaligned64(p unsafe.Pointer) uint64 {
+ q := (*[8]byte)(p)
+ return uint64(q[0]) + uint64(q[1])<<8 + uint64(q[2])<<16 + uint64(q[3])<<24 + uint64(q[4])<<32 + uint64(q[5])<<40 + uint64(q[6])<<48 + uint64(q[7])<<56
+}
diff --git a/libgo/go/runtime/utf8.go b/libgo/go/runtime/utf8.go
new file mode 100644
index 0000000000..e845451672
--- /dev/null
+++ b/libgo/go/runtime/utf8.go
@@ -0,0 +1,130 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import _ "unsafe" // For go:linkname.
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname decoderune runtime.decoderune
+
+// Numbers fundamental to the encoding.
+const (
+ runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
+ runeSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+)
+
+// Code points in the surrogate range are not valid for UTF-8.
+const (
+ surrogateMin = 0xD800
+ surrogateMax = 0xDFFF
+)
+
+const (
+ t1 = 0x00 // 0000 0000
+ tx = 0x80 // 1000 0000
+ t2 = 0xC0 // 1100 0000
+ t3 = 0xE0 // 1110 0000
+ t4 = 0xF0 // 1111 0000
+ t5 = 0xF8 // 1111 1000
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+
+ rune1Max = 1<<7 - 1
+ rune2Max = 1<<11 - 1
+ rune3Max = 1<<16 - 1
+
+ // The default lowest and highest continuation byte.
+ locb = 0x80 // 1000 0000
+ hicb = 0xBF // 1011 1111
+)
+
+// decoderune returns the non-ASCII rune at the start of
+// s[k:] and the index after the rune in s.
+//
+// decoderune assumes that caller has checked that
+// the to be decoded rune is a non-ASCII rune.
+//
+// If the string appears to be incomplete or decoding problems
+// are encountered (runeerror, k + 1) is returned to ensure
+// progress when decoderune is used to iterate over a string.
+func decoderune(s string, k int) (r rune, pos int) {
+ pos = k
+
+ if k >= len(s) {
+ return runeError, k + 1
+ }
+
+ s = s[k:]
+
+ switch {
+ case t2 <= s[0] && s[0] < t3:
+ // 0080-07FF two byte sequence
+ if len(s) > 1 && (locb <= s[1] && s[1] <= hicb) {
+ r = rune(s[0]&mask2)<<6 | rune(s[1]&maskx)
+ pos += 2
+ if rune1Max < r {
+ return
+ }
+ }
+ case t3 <= s[0] && s[0] < t4:
+ // 0800-FFFF three byte sequence
+ if len(s) > 2 && (locb <= s[1] && s[1] <= hicb) && (locb <= s[2] && s[2] <= hicb) {
+ r = rune(s[0]&mask3)<<12 | rune(s[1]&maskx)<<6 | rune(s[2]&maskx)
+ pos += 3
+ if rune2Max < r && !(surrogateMin <= r && r <= surrogateMax) {
+ return
+ }
+ }
+ case t4 <= s[0] && s[0] < t5:
+ // 10000-1FFFFF four byte sequence
+ if len(s) > 3 && (locb <= s[1] && s[1] <= hicb) && (locb <= s[2] && s[2] <= hicb) && (locb <= s[3] && s[3] <= hicb) {
+ r = rune(s[0]&mask4)<<18 | rune(s[1]&maskx)<<12 | rune(s[2]&maskx)<<6 | rune(s[3]&maskx)
+ pos += 4
+ if rune3Max < r && r <= maxRune {
+ return
+ }
+ }
+ }
+
+ return runeError, k + 1
+}
+
+// encoderune writes into p (which must be large enough) the UTF-8 encoding of the rune.
+// It returns the number of bytes written.
+func encoderune(p []byte, r rune) int {
+ // Negative values are erroneous. Making it unsigned addresses the problem.
+ switch i := uint32(r); {
+ case i <= rune1Max:
+ p[0] = byte(r)
+ return 1
+ case i <= rune2Max:
+ _ = p[1] // eliminate bounds checks
+ p[0] = t2 | byte(r>>6)
+ p[1] = tx | byte(r)&maskx
+ return 2
+ case i > maxRune, surrogateMin <= i && i <= surrogateMax:
+ r = runeError
+ fallthrough
+ case i <= rune3Max:
+ _ = p[2] // eliminate bounds checks
+ p[0] = t3 | byte(r>>12)
+ p[1] = tx | byte(r>>6)&maskx
+ p[2] = tx | byte(r)&maskx
+ return 3
+ default:
+ _ = p[3] // eliminate bounds checks
+ p[0] = t4 | byte(r>>18)
+ p[1] = tx | byte(r>>12)&maskx
+ p[2] = tx | byte(r>>6)&maskx
+ p[3] = tx | byte(r)&maskx
+ return 4
+ }
+}
diff --git a/libgo/go/runtime/vdso_none.go b/libgo/go/runtime/vdso_none.go
new file mode 100644
index 0000000000..fc2124040f
--- /dev/null
+++ b/libgo/go/runtime/vdso_none.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !linux
+// +build !darwin
+
+package runtime
+
+func sysargs(argc int32, argv **byte) {
+}
diff --git a/libgo/go/runtime/vlrt.go b/libgo/go/runtime/vlrt.go
deleted file mode 100644
index 6370732ca0..0000000000
--- a/libgo/go/runtime/vlrt.go
+++ /dev/null
@@ -1,258 +0,0 @@
-// Inferno's libkern/vlrt-arm.c
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-arm.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-// Portions Copyright 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// +build arm 386
-
-package runtime
-
-import "unsafe"
-
-const (
- sign32 = 1 << (32 - 1)
- sign64 = 1 << (64 - 1)
-)
-
-func float64toint64(d float64) (y uint64) {
- _d2v(&y, d)
- return
-}
-
-func float64touint64(d float64) (y uint64) {
- _d2v(&y, d)
- return
-}
-
-func int64tofloat64(y int64) float64 {
- if y < 0 {
- return -uint64tofloat64(-uint64(y))
- }
- return uint64tofloat64(uint64(y))
-}
-
-func uint64tofloat64(y uint64) float64 {
- hi := float64(uint32(y >> 32))
- lo := float64(uint32(y))
- d := hi*(1<<32) + lo
- return d
-}
-
-func _d2v(y *uint64, d float64) {
- x := *(*uint64)(unsafe.Pointer(&d))
-
- xhi := uint32(x>>32)&0xfffff | 0x100000
- xlo := uint32(x)
- sh := 1075 - int32(uint32(x>>52)&0x7ff)
-
- var ylo, yhi uint32
- if sh >= 0 {
- sh := uint32(sh)
- /* v = (hi||lo) >> sh */
- if sh < 32 {
- if sh == 0 {
- ylo = xlo
- yhi = xhi
- } else {
- ylo = xlo>>sh | xhi<<(32-sh)
- yhi = xhi >> sh
- }
- } else {
- if sh == 32 {
- ylo = xhi
- } else if sh < 64 {
- ylo = xhi >> (sh - 32)
- }
- }
- } else {
- /* v = (hi||lo) << -sh */
- sh := uint32(-sh)
- if sh <= 11 {
- ylo = xlo << sh
- yhi = xhi<<sh | xlo>>(32-sh)
- } else {
- /* overflow */
- yhi = uint32(d) /* causes something awful */
- }
- }
- if x&sign64 != 0 {
- if ylo != 0 {
- ylo = -ylo
- yhi = ^yhi
- } else {
- yhi = -yhi
- }
- }
-
- *y = uint64(yhi)<<32 | uint64(ylo)
-}
-
-func uint64div(n, d uint64) uint64 {
- // Check for 32 bit operands
- if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
- if uint32(d) == 0 {
- panicdivide()
- }
- return uint64(uint32(n) / uint32(d))
- }
- q, _ := dodiv(n, d)
- return q
-}
-
-func uint64mod(n, d uint64) uint64 {
- // Check for 32 bit operands
- if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
- if uint32(d) == 0 {
- panicdivide()
- }
- return uint64(uint32(n) % uint32(d))
- }
- _, r := dodiv(n, d)
- return r
-}
-
-func int64div(n, d int64) int64 {
- // Check for 32 bit operands
- if int64(int32(n)) == n && int64(int32(d)) == d {
- if int32(n) == -0x80000000 && int32(d) == -1 {
- // special case: 32-bit -0x80000000 / -1 = -0x80000000,
- // but 64-bit -0x80000000 / -1 = 0x80000000.
- return 0x80000000
- }
- if int32(d) == 0 {
- panicdivide()
- }
- return int64(int32(n) / int32(d))
- }
-
- nneg := n < 0
- dneg := d < 0
- if nneg {
- n = -n
- }
- if dneg {
- d = -d
- }
- uq, _ := dodiv(uint64(n), uint64(d))
- q := int64(uq)
- if nneg != dneg {
- q = -q
- }
- return q
-}
-
-func int64mod(n, d int64) int64 {
- // Check for 32 bit operands
- if int64(int32(n)) == n && int64(int32(d)) == d {
- if int32(d) == 0 {
- panicdivide()
- }
- return int64(int32(n) % int32(d))
- }
-
- nneg := n < 0
- if nneg {
- n = -n
- }
- if d < 0 {
- d = -d
- }
- _, ur := dodiv(uint64(n), uint64(d))
- r := int64(ur)
- if nneg {
- r = -r
- }
- return r
-}
-
-//go:noescape
-func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
-
-//go:noescape
-func _div64by32(a uint64, b uint32, r *uint32) (q uint32)
-
-func dodiv(n, d uint64) (q, r uint64) {
- if GOARCH == "arm" {
- // arm doesn't have a division instruction, so
- // slowdodiv is the best that we can do.
- // TODO: revisit for arm64.
- return slowdodiv(n, d)
- }
-
- if d > n {
- return 0, n
- }
-
- if uint32(d>>32) != 0 {
- t := uint32(n>>32) / uint32(d>>32)
- var lo64 uint64
- hi32 := _mul64by32(&lo64, d, t)
- if hi32 != 0 || lo64 > n {
- return slowdodiv(n, d)
- }
- return uint64(t), n - lo64
- }
-
- // d is 32 bit
- var qhi uint32
- if uint32(n>>32) >= uint32(d) {
- if uint32(d) == 0 {
- panicdivide()
- }
- qhi = uint32(n>>32) / uint32(d)
- n -= uint64(uint32(d)*qhi) << 32
- } else {
- qhi = 0
- }
-
- var rlo uint32
- qlo := _div64by32(n, uint32(d), &rlo)
- return uint64(qhi)<<32 + uint64(qlo), uint64(rlo)
-}
-
-func slowdodiv(n, d uint64) (q, r uint64) {
- if d == 0 {
- panicdivide()
- }
-
- // Set up the divisor and find the number of iterations needed.
- capn := n
- if n >= sign64 {
- capn = sign64
- }
- i := 0
- for d < capn {
- d <<= 1
- i++
- }
-
- for ; i >= 0; i-- {
- q <<= 1
- if n >= d {
- n -= d
- q |= 1
- }
- d >>= 1
- }
- return q, n
-}
diff --git a/libgo/go/runtime/write_err_android.go b/libgo/go/runtime/write_err_android.go
index 4411a14755..748dec644c 100644
--- a/libgo/go/runtime/write_err_android.go
+++ b/libgo/go/runtime/write_err_android.go
@@ -75,7 +75,9 @@ func writeErr(b []byte) {
if v == '\n' || writePos == len(dst)-1 {
dst[writePos] = 0
write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
- memclrBytes(dst)
+ for i := range dst {
+ dst[i] = 0
+ }
writePos = 0
}
}
diff --git a/libgo/go/sort/example_search_test.go b/libgo/go/sort/example_search_test.go
new file mode 100644
index 0000000000..6928f0f092
--- /dev/null
+++ b/libgo/go/sort/example_search_test.go
@@ -0,0 +1,42 @@
+// 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 sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+// This example demonstrates searching a list sorted in ascending order.
+func ExampleSearch() {
+ a := []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55}
+ x := 6
+
+ i := sort.Search(len(a), func(i int) bool { return a[i] >= x })
+ if i < len(a) && a[i] == x {
+ fmt.Printf("found %d at index %d in %v\n", x, i, a)
+ } else {
+ fmt.Printf("%d not found in %v\n", x, a)
+ }
+ // Output:
+ // found 6 at index 2 in [1 3 6 10 15 21 28 36 45 55]
+}
+
+// This example demonstrates searching a list sorted in descending order.
+// The approach is the same as searching a list in ascending order,
+// but with the condition inverted.
+func ExampleSearch_descendingOrder() {
+ a := []int{55, 45, 36, 28, 21, 15, 10, 6, 3, 1}
+ x := 6
+
+ i := sort.Search(len(a), func(i int) bool { return a[i] <= x })
+ if i < len(a) && a[i] == x {
+ fmt.Printf("found %d at index %d in %v\n", x, i, a)
+ } else {
+ fmt.Printf("%d not found in %v\n", x, a)
+ }
+ // Output:
+ // found 6 at index 7 in [55 45 36 28 21 15 10 6 3 1]
+}
diff --git a/libgo/go/sort/example_test.go b/libgo/go/sort/example_test.go
index f7372bec37..980c0d0368 100644
--- a/libgo/go/sort/example_test.go
+++ b/libgo/go/sort/example_test.go
@@ -22,3 +22,22 @@ func ExampleReverse() {
fmt.Println(s)
// Output: [6 5 4 3 2 1]
}
+
+func ExampleSlice() {
+ people := []struct {
+ Name string
+ Age int
+ }{
+ {"Gopher", 7},
+ {"Alice", 55},
+ {"Vera", 24},
+ {"Bob", 75},
+ }
+ sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
+ fmt.Println("By name:", people)
+
+ sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
+ fmt.Println("By age:", people)
+ // Output: By name: [{Alice 55} {Bob 75} {Gopher 7} {Vera 24}]
+ // By age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
+}
diff --git a/libgo/go/sort/genzfunc.go b/libgo/go/sort/genzfunc.go
new file mode 100644
index 0000000000..6d2b471b62
--- /dev/null
+++ b/libgo/go/sort/genzfunc.go
@@ -0,0 +1,122 @@
+// 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
+
+// This program is run via "go generate" (via a directive in sort.go)
+// to generate zfuncversion.go.
+//
+// It copies sort.go to zfuncversion.go, only retaining funcs which
+// take a "data Interface" parameter, and renaming each to have a
+// "_func" suffix and taking a "data lessSwap" instead. It then rewrites
+// each internal function call to the appropriate _func variants.
+
+package main
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "log"
+ "regexp"
+)
+
+var fset = token.NewFileSet()
+
+func main() {
+ af, err := parser.ParseFile(fset, "sort.go", nil, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ af.Doc = nil
+ af.Imports = nil
+ af.Comments = nil
+
+ var newDecl []ast.Decl
+ for _, d := range af.Decls {
+ fd, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if fd.Recv != nil || fd.Name.IsExported() {
+ continue
+ }
+ typ := fd.Type
+ if len(typ.Params.List) < 1 {
+ continue
+ }
+ arg0 := typ.Params.List[0]
+ arg0Name := arg0.Names[0].Name
+ arg0Type := arg0.Type.(*ast.Ident)
+ if arg0Name != "data" || arg0Type.Name != "Interface" {
+ continue
+ }
+ arg0Type.Name = "lessSwap"
+
+ newDecl = append(newDecl, fd)
+ }
+ af.Decls = newDecl
+ ast.Walk(visitFunc(rewriteCalls), af)
+
+ var out bytes.Buffer
+ if err := format.Node(&out, fset, af); err != nil {
+ log.Fatalf("format.Node: %v", err)
+ }
+
+ // Get rid of blank lines after removal of comments.
+ src := regexp.MustCompile(`\n{2,}`).ReplaceAll(out.Bytes(), []byte("\n"))
+
+ // Add comments to each func, for the lost reader.
+ // This is so much easier than adding comments via the AST
+ // and trying to get position info correct.
+ src = regexp.MustCompile(`(?m)^func (\w+)`).ReplaceAll(src, []byte("\n// Auto-generated variant of sort.go:$1\nfunc ${1}_func"))
+
+ // Final gofmt.
+ src, err = format.Source(src)
+ if err != nil {
+ log.Fatalf("format.Source: %v on\n%s", err, src)
+ }
+
+ out.Reset()
+ out.WriteString(`// DO NOT EDIT; AUTO-GENERATED from sort.go using genzfunc.go
+
+// 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.
+
+`)
+ out.Write(src)
+
+ const target = "zfuncversion.go"
+ if err := ioutil.WriteFile(target, out.Bytes(), 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+type visitFunc func(ast.Node) ast.Visitor
+
+func (f visitFunc) Visit(n ast.Node) ast.Visitor { return f(n) }
+
+func rewriteCalls(n ast.Node) ast.Visitor {
+ ce, ok := n.(*ast.CallExpr)
+ if ok {
+ rewriteCall(ce)
+ }
+ return visitFunc(rewriteCalls)
+}
+
+func rewriteCall(ce *ast.CallExpr) {
+ ident, ok := ce.Fun.(*ast.Ident)
+ if !ok {
+ // e.g. skip SelectorExpr (data.Less(..) calls)
+ return
+ }
+ if len(ce.Args) < 1 {
+ return
+ }
+ ident.Name += "_func"
+}
diff --git a/libgo/go/sort/search.go b/libgo/go/sort/search.go
index de8178ff48..b9640a40af 100644
--- a/libgo/go/sort/search.go
+++ b/libgo/go/sort/search.go
@@ -8,10 +8,10 @@ package sort
// Search uses binary search to find and return the smallest index i
// in [0, n) at which f(i) is true, assuming that on the range [0, n),
-// f(i) == true implies f(i+1) == true. That is, Search requires that
+// f(i) == true implies f(i+1) == true. That is, Search requires that
// f is false for some (possibly empty) prefix of the input range [0, n)
// and then true for the (possibly empty) remainder; Search returns
-// the first true index. If there is no such index, Search returns n.
+// the first true index. If there is no such index, Search returns n.
// (Note that the "not found" return value is not -1 as in, for instance,
// strings.Index.)
// Search calls f(i) only for i in the range [0, n).
@@ -85,7 +85,7 @@ func SearchInts(a []int, x int) int {
}
// SearchFloat64s searches for x in a sorted slice of float64s and returns the index
-// as specified by Search. The return value is the index to insert x if x is not
+// as specified by Search. The return value is the index to insert x if x is not
// present (it could be len(a)).
// The slice must be sorted in ascending order.
//
@@ -94,7 +94,7 @@ func SearchFloat64s(a []float64, x float64) int {
}
// SearchStrings searches for x in a sorted slice of strings and returns the index
-// as specified by Search. The return value is the index to insert x if x is not
+// as specified by Search. The return value is the index to insert x if x is not
// present (it could be len(a)).
// The slice must be sorted in ascending order.
//
diff --git a/libgo/go/sort/search_test.go b/libgo/go/sort/search_test.go
index 4265b9520a..e75508dbda 100644
--- a/libgo/go/sort/search_test.go
+++ b/libgo/go/sort/search_test.go
@@ -148,7 +148,7 @@ func BenchmarkSearchWrappers(b *testing.B) {
}
// Abstract exhaustive test: all sizes up to 100,
-// all possible return values. If there are any small
+// all possible return values. If there are any small
// corner cases, this test exercises them.
func TestSearchExhaustive(t *testing.T) {
for size := 0; size <= 100; size++ {
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
index ac8f4a661f..72d24efcea 100644
--- a/libgo/go/sort/sort.go
+++ b/libgo/go/sort/sort.go
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:generate go run genzfunc.go
+
// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort
+import "reflect"
+
// A type, typically a collection, that satisfies sort.Interface can be
-// sorted by the routines in this package. The methods require that the
+// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
// Len is the number of elements in the collection.
@@ -19,13 +23,6 @@ type Interface interface {
Swap(i, j int)
}
-func min(a, b int) int {
- if a < b {
- return a
- }
- return b
-}
-
// Insertion sort
func insertionSort(data Interface, a, b int) {
for i := a + 1; i < b; i++ {
@@ -119,15 +116,15 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
pivot := lo
a, c := lo+1, hi-1
- for ; a != c && data.Less(a, pivot); a++ {
+ for ; a < c && data.Less(a, pivot); a++ {
}
b := a
for {
- for ; b != c && !data.Less(pivot, b); b++ { // data[b] <= pivot
+ for ; b < c && !data.Less(pivot, b); b++ { // data[b] <= pivot
}
- for ; b != c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
+ for ; b < c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
}
- if b == c {
+ if b >= c {
break
}
// data[b] > pivot; data[c-1] <= pivot
@@ -167,11 +164,11 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
// data[a <= i < b] unexamined
// data[b <= i < c] = pivot
for {
- for ; a != b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
+ for ; a < b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
}
- for ; a != b && data.Less(a, pivot); a++ { // data[a] < pivot
+ for ; a < b && data.Less(a, pivot); a++ { // data[a] < pivot
}
- if a == b {
+ if a >= b {
break
}
// data[a] == pivot; data[b-1] < pivot
@@ -219,14 +216,63 @@ func quickSort(data Interface, a, b, maxDepth int) {
// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
- // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
n := data.Len()
- maxDepth := 0
+ quickSort(data, 0, n, maxDepth(n))
+}
+
+// maxDepth returns a threshold at which quicksort should switch
+// to heapsort. It returns 2*ceil(lg(n+1)).
+func maxDepth(n int) int {
+ var depth int
for i := n; i > 0; i >>= 1 {
- maxDepth++
+ depth++
}
- maxDepth *= 2
- quickSort(data, 0, n, maxDepth)
+ return depth * 2
+}
+
+// lessSwap is a pair of Less and Swap function for use with the
+// auto-generated func-optimized variant of sort.go in
+// zfuncversion.go.
+type lessSwap struct {
+ Less func(i, j int) bool
+ Swap func(i, j int)
+}
+
+// Slice sorts the provided slice given the provided less function.
+//
+// The sort is not guaranteed to be stable. For a stable sort, use
+// SliceStable.
+//
+// The function panics if the provided interface is not a slice.
+func Slice(slice interface{}, less func(i, j int) bool) {
+ rv := reflect.ValueOf(slice)
+ swap := reflect.Swapper(slice)
+ length := rv.Len()
+ quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
+}
+
+// SliceStable sorts the provided slice given the provided less
+// function while keeping the original order of equal elements.
+//
+// The function panics if the provided interface is not a slice.
+func SliceStable(slice interface{}, less func(i, j int) bool) {
+ rv := reflect.ValueOf(slice)
+ swap := reflect.Swapper(slice)
+ stable_func(lessSwap{less, swap}, rv.Len())
+}
+
+// SliceIsSorted tests whether a slice is sorted.
+//
+// The function panics if the provided interface is not a slice.
+func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
+ rv := reflect.ValueOf(slice)
+ n := rv.Len()
+ for i := n - 1; i > 0; i-- {
+ if less(i, i-1) {
+ return false
+ }
+ }
+ return true
}
type reverse struct {
@@ -315,7 +361,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// Notes on stable sorting:
// The used algorithms are simple and provable correct on all input and use
-// only logarithmic additional stack space. They perform well if compared
+// only logarithmic additional stack space. They perform well if compared
// experimentally to other stable in-place sorting algorithms.
//
// Remarks on other algorithms evaluated:
@@ -335,7 +381,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// unstable or rely on enough different elements in each step to encode the
// performed block rearrangements. See also "In-Place Merging Algorithms",
// Denham Coates-Evely, Department of Computer Science, Kings College,
-// January 2004 and the reverences in there.
+// January 2004 and the references in there.
// - Often "optimal" algorithms are optimal in the number of assignments
// but Interface has only Swap as operation.
@@ -344,7 +390,10 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// It makes one call to data.Len to determine n, O(n*log(n)) calls to
// data.Less and O(n*log(n)*log(n)) calls to data.Swap.
func Stable(data Interface) {
- n := data.Len()
+ stable(data, data.Len())
+}
+
+func stable(data Interface, n int) {
blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go
index 6c36f30e0e..45713a28cc 100644
--- a/libgo/go/sort/sort_test.go
+++ b/libgo/go/sort/sort_test.go
@@ -6,10 +6,12 @@ package sort_test
import (
"fmt"
+ "internal/testenv"
"math"
"math/rand"
. "sort"
"strconv"
+ stringspkg "strings"
"testing"
)
@@ -74,6 +76,17 @@ func TestStrings(t *testing.T) {
}
}
+func TestSlice(t *testing.T) {
+ data := strings
+ Slice(data[:], func(i, j int) bool {
+ return data[i] < data[j]
+ })
+ if !SliceIsSorted(data[:], func(i, j int) bool { return data[i] < data[j] }) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
func TestSortLarge_Random(t *testing.T) {
n := 1000000
if testing.Short() {
@@ -109,26 +122,85 @@ func TestReverseSortIntSlice(t *testing.T) {
}
}
+type nonDeterministicTestingData struct {
+ r *rand.Rand
+}
+
+func (t *nonDeterministicTestingData) Len() int {
+ return 500
+}
+func (t *nonDeterministicTestingData) Less(i, j int) bool {
+ if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
+ panic("nondeterministic comparison out of bounds")
+ }
+ return t.r.Float32() < 0.5
+}
+func (t *nonDeterministicTestingData) Swap(i, j int) {
+ if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
+ panic("nondeterministic comparison out of bounds")
+ }
+}
+
+func TestNonDeterministicComparison(t *testing.T) {
+ // Ensure that sort.Sort does not panic when Less returns inconsistent results.
+ // See https://golang.org/issue/14377.
+ defer func() {
+ if r := recover(); r != nil {
+ t.Error(r)
+ }
+ }()
+
+ td := &nonDeterministicTestingData{
+ r: rand.New(rand.NewSource(0)),
+ }
+
+ for i := 0; i < 10; i++ {
+ Sort(td)
+ }
+}
+
func BenchmarkSortString1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
for i := 0; i < b.N; i++ {
- data := make([]string, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = strconv.Itoa(i ^ 0x2cc)
- }
+ copy(data, unsorted)
b.StartTimer()
Strings(data)
b.StopTimer()
}
}
+func BenchmarkSortString1K_Slice(b *testing.B) {
+ b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
+ for i := 0; i < b.N; i++ {
+ copy(data, unsorted)
+ b.StartTimer()
+ Slice(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkStableString1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := 0; i < len(data); i++ {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
for i := 0; i < b.N; i++ {
- data := make([]string, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = strconv.Itoa(i ^ 0x2cc)
- }
+ copy(data, unsorted)
b.StartTimer()
Stable(StringSlice(data))
b.StopTimer()
@@ -150,17 +222,34 @@ func BenchmarkSortInt1K(b *testing.B) {
func BenchmarkStableInt1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]int, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = i ^ 0x2cc
+ }
+ data := make([]int, len(unsorted))
for i := 0; i < b.N; i++ {
- data := make([]int, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = i ^ 0x2cc
- }
+ copy(data, unsorted)
b.StartTimer()
Stable(IntSlice(data))
b.StopTimer()
}
}
+func BenchmarkStableInt1K_Slice(b *testing.B) {
+ b.StopTimer()
+ unsorted := make([]int, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = i ^ 0x2cc
+ }
+ data := make([]int, len(unsorted))
+ for i := 0; i < b.N; i++ {
+ copy(data, unsorted)
+ b.StartTimer()
+ SliceStable(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkSortInt64K(b *testing.B) {
b.StopTimer()
for i := 0; i < b.N; i++ {
@@ -174,6 +263,19 @@ func BenchmarkSortInt64K(b *testing.B) {
}
}
+func BenchmarkSortInt64K_Slice(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<16)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0xcccc
+ }
+ b.StartTimer()
+ Slice(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkStableInt64K(b *testing.B) {
b.StopTimer()
for i := 0; i < b.N; i++ {
@@ -469,10 +571,10 @@ func TestStability(t *testing.T) {
data.initB()
Stable(data)
if !IsSorted(data) {
- t.Errorf("Stable shuffeled sorted %d ints (order)", n)
+ t.Errorf("Stable shuffled sorted %d ints (order)", n)
}
if !data.inOrder() {
- t.Errorf("Stable shuffeled sorted %d ints (stability)", n)
+ t.Errorf("Stable shuffled sorted %d ints (stability)", n)
}
// sorted reversed
@@ -518,6 +620,9 @@ func TestCountStableOps(t *testing.T) { countOps(t, Stable, "Stable") }
func TestCountSortOps(t *testing.T) { countOps(t, Sort, "Sort ") }
func bench(b *testing.B, size int, algo func(Interface), name string) {
+ if stringspkg.HasSuffix(testenv.Builder(), "-race") && size > 1e4 {
+ b.Skip("skipping slow benchmark on race builder")
+ }
b.StopTimer()
data := make(intPairs, size)
x := ^uint32(0)
diff --git a/libgo/go/sort/zfuncversion.go b/libgo/go/sort/zfuncversion.go
new file mode 100644
index 0000000000..7abb18a24d
--- /dev/null
+++ b/libgo/go/sort/zfuncversion.go
@@ -0,0 +1,265 @@
+// DO NOT EDIT; AUTO-GENERATED from sort.go using genzfunc.go
+
+// 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 sort
+
+// Auto-generated variant of sort.go:insertionSort
+func insertionSort_func(data lessSwap, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+
+// Auto-generated variant of sort.go:siftDown
+func siftDown_func(data lessSwap, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && data.Less(first+child, first+child+1) {
+ child++
+ }
+ if !data.Less(first+root, first+child) {
+ return
+ }
+ data.Swap(first+root, first+child)
+ root = child
+ }
+}
+
+// Auto-generated variant of sort.go:heapSort
+func heapSort_func(data lessSwap, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDown_func(data, i, hi, first)
+ }
+ for i := hi - 1; i >= 0; i-- {
+ data.Swap(first, first+i)
+ siftDown_func(data, lo, i, first)
+ }
+}
+
+// Auto-generated variant of sort.go:medianOfThree
+func medianOfThree_func(data lessSwap, m1, m0, m2 int) {
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ if data.Less(m2, m1) {
+ data.Swap(m2, m1)
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ }
+}
+
+// Auto-generated variant of sort.go:swapRange
+func swapRange_func(data lessSwap, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data.Swap(a+i, b+i)
+ }
+}
+
+// Auto-generated variant of sort.go:doPivot
+func doPivot_func(data lessSwap, lo, hi int) (midlo, midhi int) {
+ m := lo + (hi-lo)/2
+ if hi-lo > 40 {
+ s := (hi - lo) / 8
+ medianOfThree_func(data, lo, lo+s, lo+2*s)
+ medianOfThree_func(data, m, m-s, m+s)
+ medianOfThree_func(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree_func(data, lo, m, hi-1)
+ pivot := lo
+ a, c := lo+1, hi-1
+ for ; a < c && data.Less(a, pivot); a++ {
+ }
+ b := a
+ for {
+ for ; b < c && !data.Less(pivot, b); b++ {
+ }
+ for ; b < c && data.Less(pivot, c-1); c-- {
+ }
+ if b >= c {
+ break
+ }
+ data.Swap(b, c-1)
+ b++
+ c--
+ }
+ protect := hi-c < 5
+ if !protect && hi-c < (hi-lo)/4 {
+ dups := 0
+ if !data.Less(pivot, hi-1) {
+ data.Swap(c, hi-1)
+ c++
+ dups++
+ }
+ if !data.Less(b-1, pivot) {
+ b--
+ dups++
+ }
+ if !data.Less(m, pivot) {
+ data.Swap(m, b-1)
+ b--
+ dups++
+ }
+ protect = dups > 1
+ }
+ if protect {
+ for {
+ for ; a < b && !data.Less(b-1, pivot); b-- {
+ }
+ for ; a < b && data.Less(a, pivot); a++ {
+ }
+ if a >= b {
+ break
+ }
+ data.Swap(a, b-1)
+ a++
+ b--
+ }
+ }
+ data.Swap(pivot, b-1)
+ return b - 1, c
+}
+
+// Auto-generated variant of sort.go:quickSort
+func quickSort_func(data lessSwap, a, b, maxDepth int) {
+ for b-a > 12 {
+ if maxDepth == 0 {
+ heapSort_func(data, a, b)
+ return
+ }
+ maxDepth--
+ mlo, mhi := doPivot_func(data, a, b)
+ if mlo-a < b-mhi {
+ quickSort_func(data, a, mlo, maxDepth)
+ a = mhi
+ } else {
+ quickSort_func(data, mhi, b, maxDepth)
+ b = mlo
+ }
+ }
+ if b-a > 1 {
+ for i := a + 6; i < b; i++ {
+ if data.Less(i, i-6) {
+ data.Swap(i, i-6)
+ }
+ }
+ insertionSort_func(data, a, b)
+ }
+}
+
+// Auto-generated variant of sort.go:stable
+func stable_func(data lessSwap, n int) {
+ blockSize := 20
+ a, b := 0, blockSize
+ for b <= n {
+ insertionSort_func(data, a, b)
+ a = b
+ b += blockSize
+ }
+ insertionSort_func(data, a, n)
+ for blockSize < n {
+ a, b = 0, 2*blockSize
+ for b <= n {
+ symMerge_func(data, a, a+blockSize, b)
+ a = b
+ b += 2 * blockSize
+ }
+ if m := a + blockSize; m < n {
+ symMerge_func(data, a, m, n)
+ }
+ blockSize *= 2
+ }
+}
+
+// Auto-generated variant of sort.go:symMerge
+func symMerge_func(data lessSwap, a, m, b int) {
+ if m-a == 1 {
+ i := m
+ j := b
+ for i < j {
+ h := i + (j-i)/2
+ if data.Less(h, a) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ for k := a; k < i-1; k++ {
+ data.Swap(k, k+1)
+ }
+ return
+ }
+ if b-m == 1 {
+ i := a
+ j := m
+ for i < j {
+ h := i + (j-i)/2
+ if !data.Less(m, h) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ for k := m; k > i; k-- {
+ data.Swap(k, k-1)
+ }
+ return
+ }
+ mid := a + (b-a)/2
+ n := mid + m
+ var start, r int
+ if m > mid {
+ start = n - b
+ r = mid
+ } else {
+ start = a
+ r = m
+ }
+ p := n - 1
+ for start < r {
+ c := start + (r-start)/2
+ if !data.Less(p-c, c) {
+ start = c + 1
+ } else {
+ r = c
+ }
+ }
+ end := n - start
+ if start < m && m < end {
+ rotate_func(data, start, m, end)
+ }
+ if a < start && start < mid {
+ symMerge_func(data, a, start, mid)
+ }
+ if mid < end && end < b {
+ symMerge_func(data, mid, end, b)
+ }
+}
+
+// Auto-generated variant of sort.go:rotate
+func rotate_func(data lessSwap, a, m, b int) {
+ i := m - a
+ j := b - m
+ for i != j {
+ if i > j {
+ swapRange_func(data, m-i, m, j)
+ i -= j
+ } else {
+ swapRange_func(data, m-i, m+j-i, i)
+ j -= i
+ }
+ }
+ swapRange_func(data, m-i, m, i)
+}
diff --git a/libgo/go/strconv/atob.go b/libgo/go/strconv/atob.go
index d0cb097213..879ceb385e 100644
--- a/libgo/go/strconv/atob.go
+++ b/libgo/go/strconv/atob.go
@@ -7,7 +7,7 @@ package strconv
// ParseBool returns the boolean value represented by the string.
// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
// Any other value returns an error.
-func ParseBool(str string) (value bool, err error) {
+func ParseBool(str string) (bool, error) {
switch str {
case "1", "t", "T", "true", "TRUE", "True":
return true, nil
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index a4f4862dba..fdcb8b3d7a 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -245,7 +245,9 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
return
}
- exp = dp - ndMant
+ if mantissa != 0 {
+ exp = dp - ndMant
+ }
ok = true
return
@@ -534,11 +536,10 @@ func atof64(s string) (f float64, err error) {
// If s is syntactically well-formed but is more than 1/2 ULP
// away from the largest floating point number of the given size,
// ParseFloat returns f = ±Inf, err.Err = ErrRange.
-func ParseFloat(s string, bitSize int) (f float64, err error) {
+func ParseFloat(s string, bitSize int) (float64, error) {
if bitSize == 32 {
- f1, err1 := atof32(s)
- return float64(f1), err1
+ f, err := atof32(s)
+ return float64(f), err
}
- f1, err1 := atof64(s)
- return f1, err1
+ return atof64(s)
}
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
index ba4933218b..0a89c3e0bf 100644
--- a/libgo/go/strconv/atof_test.go
+++ b/libgo/go/strconv/atof_test.go
@@ -42,6 +42,30 @@ var atoftests = []atofTest{
{"1e-20", "1e-20", nil},
{"625e-3", "0.625", nil},
+ // zeros
+ {"0", "0", nil},
+ {"0e0", "0", nil},
+ {"-0e0", "-0", nil},
+ {"+0e0", "0", nil},
+ {"0e-0", "0", nil},
+ {"-0e-0", "-0", nil},
+ {"+0e-0", "0", nil},
+ {"0e+0", "0", nil},
+ {"-0e+0", "-0", nil},
+ {"+0e+0", "0", nil},
+ {"0e+01234567890123456789", "0", nil},
+ {"0.00e-01234567890123456789", "0", nil},
+ {"-0e+01234567890123456789", "-0", nil},
+ {"-0.00e-01234567890123456789", "-0", nil},
+ {"0e291", "0", nil}, // issue 15364
+ {"0e292", "0", nil}, // issue 15364
+ {"0e347", "0", nil}, // issue 15364
+ {"0e348", "0", nil}, // issue 15364
+ {"-0e291", "-0", nil},
+ {"-0e292", "-0", nil},
+ {"-0e347", "-0", nil},
+ {"-0e348", "-0", nil},
+
// NaNs
{"nan", "NaN", nil},
{"NaN", "NaN", nil},
@@ -196,7 +220,7 @@ var (
func init() {
// The atof routines return NumErrors wrapping
- // the error and the string. Convert the table above.
+ // the error and the string. Convert the table above.
for i := range atoftests {
test := &atoftests[i]
if test.err != nil {
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
index 965e3a218f..66df149172 100644
--- a/libgo/go/strconv/atoi.go
+++ b/libgo/go/strconv/atoi.go
@@ -39,7 +39,9 @@ const IntSize = intSize
const maxUint64 = (1<<64 - 1)
// ParseUint is like ParseInt but for unsigned numbers.
-func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
+func ParseUint(s string, base int, bitSize int) (uint64, error) {
+ var n uint64
+ var err error
var cutoff, maxVal uint64
if bitSize == 0 {
@@ -136,16 +138,16 @@ Error:
}
// ParseInt interprets a string s in the given base (2 to 36) and
-// returns the corresponding value i. If base == 0, the base is
+// returns the corresponding value i. If base == 0, the base is
// implied by the string's prefix: base 16 for "0x", base 8 for
// "0", and base 10 otherwise.
//
// The bitSize argument specifies the integer type
-// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
+// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
// correspond to int, int8, int16, int32, and int64.
//
// The errors that ParseInt returns have concrete type *NumError
-// and include err.Num = s. If s is empty or contains invalid
+// and include err.Num = s. If s is empty or contains invalid
// digits, err.Err = ErrSyntax and the returned value is 0;
// if the value corresponding to s cannot be represented by a
// signed integer of the given size, err.Err = ErrRange and the
@@ -195,8 +197,12 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) {
return n, nil
}
-// Atoi is shorthand for ParseInt(s, 10, 0).
-func Atoi(s string) (i int, err error) {
+// Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
+func Atoi(s string) (int, error) {
+ const fnAtoi = "Atoi"
i64, err := ParseInt(s, 10, 0)
+ if nerr, ok := err.(*NumError); ok {
+ nerr.Func = fnAtoi
+ }
return int(i64), err
}
diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go
index bd6a6a01fa..d608505da2 100644
--- a/libgo/go/strconv/atoi_test.go
+++ b/libgo/go/strconv/atoi_test.go
@@ -196,7 +196,7 @@ var numErrorTests = []numErrorTest{
func init() {
// The atoi routines return NumErrors wrapping
- // the error and the string. Convert the tables above.
+ // the error and the string. Convert the tables above.
for i := range atoui64tests {
test := &atoui64tests[i]
if test.err != nil {
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
index 5252d6e86e..957acd9891 100644
--- a/libgo/go/strconv/decimal.go
+++ b/libgo/go/strconv/decimal.go
@@ -131,11 +131,13 @@ func rightShift(a *decimal, k uint) {
}
a.dp -= r - 1
+ var mask uint = (1 << k) - 1
+
// Pick up a digit, put down a digit.
for ; r < a.nd; r++ {
c := uint(a.d[r])
dig := n >> k
- n -= dig << k
+ n &= mask
a.d[w] = byte(dig + '0')
w++
n = n*10 + c - '0'
@@ -144,7 +146,7 @@ func rightShift(a *decimal, k uint) {
// Put down extra digits.
for n > 0 {
dig := n >> k
- n -= dig << k
+ n &= mask
if w < len(a.d) {
a.d[w] = byte(dig + '0')
w++
diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go
index 019b4eebdc..7033e96c39 100644
--- a/libgo/go/strconv/extfloat.go
+++ b/libgo/go/strconv/extfloat.go
@@ -311,9 +311,9 @@ func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc boo
var extrabits uint
if f.exp <= denormalExp {
// f.mant * 2^f.exp is smaller than 2^(flt.bias+1).
- extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+ extrabits = 63 - flt.mantbits + 1 + uint(denormalExp-f.exp)
} else {
- extrabits = uint(63 - flt.mantbits)
+ extrabits = 63 - flt.mantbits
}
halfway := uint64(1) << (extrabits - 1)
diff --git a/libgo/go/strconv/fp_test.go b/libgo/go/strconv/fp_test.go
index 6de2f8bc6f..39dd9c4a58 100644
--- a/libgo/go/strconv/fp_test.go
+++ b/libgo/go/strconv/fp_test.go
@@ -41,7 +41,7 @@ func myatof64(s string) (f float64, ok bool) {
}
v := float64(n)
// We expect that v*pow2(e) fits in a float64,
- // but pow2(e) by itself may not. Be careful.
+ // but pow2(e) by itself may not. Be careful.
if e <= -1000 {
v *= pow2(-1000)
e += 1000
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
index 9ff5d1056a..8b3d33e4e7 100644
--- a/libgo/go/strconv/ftoa.go
+++ b/libgo/go/strconv/ftoa.go
@@ -23,7 +23,7 @@ var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}
// FormatFloat converts the floating-point number f to a string,
-// according to the format fmt and precision prec. It rounds the
+// according to the format fmt and precision prec. It rounds the
// result assuming that the original was obtained from a floating-point
// value of bitSize bits (32 for float32, 64 for float64).
//
diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go
index 0b9f0feafa..976bd2c9b8 100644
--- a/libgo/go/strconv/ftoa_test.go
+++ b/libgo/go/strconv/ftoa_test.go
@@ -183,59 +183,53 @@ func TestFtoaRandom(t *testing.T) {
}
}
-func BenchmarkFormatFloatDecimal(b *testing.B) {
- for i := 0; i < b.N; i++ {
- FormatFloat(33909, 'g', -1, 64)
- }
+var ftoaBenches = []struct {
+ name string
+ float float64
+ fmt byte
+ prec int
+ bitSize int
+}{
+ {"Decimal", 33909, 'g', -1, 64},
+ {"Float", 339.7784, 'g', -1, 64},
+ {"Exp", -5.09e75, 'g', -1, 64},
+ {"NegExp", -5.11e-95, 'g', -1, 64},
+
+ {"Big", 123456789123456789123456789, 'g', -1, 64},
+ {"BinaryExp", -1, 'b', -1, 64},
+
+ {"32Integer", 33909, 'g', -1, 32},
+ {"32ExactFraction", 3.375, 'g', -1, 32},
+ {"32Point", 339.7784, 'g', -1, 32},
+ {"32Exp", -5.09e25, 'g', -1, 32},
+ {"32NegExp", -5.11e-25, 'g', -1, 32},
+
+ {"64Fixed1", 123456, 'e', 3, 64},
+ {"64Fixed2", 123.456, 'e', 3, 64},
+ {"64Fixed3", 1.23456e+78, 'e', 3, 64},
+ {"64Fixed4", 1.23456e-78, 'e', 3, 64},
+
+ // Trigger slow path (see issue #15672).
+ {"Slowpath64", 622666234635.3213e-320, 'e', -1, 64},
}
func BenchmarkFormatFloat(b *testing.B) {
- for i := 0; i < b.N; i++ {
- FormatFloat(339.7784, 'g', -1, 64)
- }
-}
-
-func BenchmarkFormatFloatExp(b *testing.B) {
- for i := 0; i < b.N; i++ {
- FormatFloat(-5.09e75, 'g', -1, 64)
- }
-}
-
-func BenchmarkFormatFloatNegExp(b *testing.B) {
- for i := 0; i < b.N; i++ {
- FormatFloat(-5.11e-95, 'g', -1, 64)
- }
-}
-
-func BenchmarkFormatFloatBig(b *testing.B) {
- for i := 0; i < b.N; i++ {
- FormatFloat(123456789123456789123456789, 'g', -1, 64)
+ for _, c := range ftoaBenches {
+ b.Run(c.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(c.float, c.fmt, c.prec, c.bitSize)
+ }
+ })
}
}
-func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) {
+func BenchmarkAppendFloat(b *testing.B) {
dst := make([]byte, 30)
- for i := 0; i < b.N; i++ {
- AppendFloat(dst[:0], f, fmt, prec, bitSize)
+ for _, c := range ftoaBenches {
+ b.Run(c.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst[:0], c.float, c.fmt, c.prec, c.bitSize)
+ }
+ })
}
}
-
-func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) }
-func BenchmarkAppendFloat(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) }
-func BenchmarkAppendFloatExp(b *testing.B) { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) }
-func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) }
-func BenchmarkAppendFloatBig(b *testing.B) {
- benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64)
-}
-func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) }
-
-func BenchmarkAppendFloat32Integer(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 32) }
-func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) }
-func BenchmarkAppendFloat32Point(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 32) }
-func BenchmarkAppendFloat32Exp(b *testing.B) { benchmarkAppendFloat(b, -5.09e25, 'g', -1, 32) }
-func BenchmarkAppendFloat32NegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-25, 'g', -1, 32) }
-
-func BenchmarkAppendFloat64Fixed1(b *testing.B) { benchmarkAppendFloat(b, 123456, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed2(b *testing.B) { benchmarkAppendFloat(b, 123.456, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed3(b *testing.B) { benchmarkAppendFloat(b, 1.23456e+78, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed4(b *testing.B) { benchmarkAppendFloat(b, 1.23456e-78, 'e', 3, 64) }
diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go
index 20a02dec33..a30d8d8b59 100644
--- a/libgo/go/strconv/isprint.go
+++ b/libgo/go/strconv/isprint.go
@@ -7,7 +7,7 @@
package strconv
-// (470+136+73)*2 + (342)*4 = 2726 bytes
+// (462+139+82)*2 + (378)*4 = 2878 bytes
var isPrint16 = []uint16{
0x0020, 0x007e,
@@ -26,8 +26,8 @@ var isPrint16 = []uint16{
0x0800, 0x082d,
0x0830, 0x085b,
0x085e, 0x085e,
- 0x08a0, 0x08b4,
- 0x08e3, 0x098c,
+ 0x08a0, 0x08bd,
+ 0x08d4, 0x098c,
0x098f, 0x0990,
0x0993, 0x09b2,
0x09b6, 0x09b9,
@@ -83,11 +83,9 @@ var isPrint16 = []uint16{
0x0cde, 0x0ce3,
0x0ce6, 0x0cf2,
0x0d01, 0x0d3a,
- 0x0d3d, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
+ 0x0d3d, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
0x0d82, 0x0d96,
0x0d9a, 0x0dbd,
0x0dc0, 0x0dc6,
@@ -153,11 +151,11 @@ var isPrint16 = []uint16{
0x1b80, 0x1bf3,
0x1bfc, 0x1c37,
0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
+ 0x1c4d, 0x1c88,
0x1cc0, 0x1cc7,
0x1cd0, 0x1cf9,
0x1d00, 0x1df5,
- 0x1dfc, 0x1f15,
+ 0x1dfb, 0x1f15,
0x1f18, 0x1f1d,
0x1f20, 0x1f45,
0x1f48, 0x1f4d,
@@ -172,8 +170,7 @@ var isPrint16 = []uint16{
0x20a0, 0x20be,
0x20d0, 0x20f0,
0x2100, 0x218b,
- 0x2190, 0x23fa,
- 0x2400, 0x2426,
+ 0x2190, 0x2426,
0x2440, 0x244a,
0x2460, 0x2b73,
0x2b76, 0x2b95,
@@ -186,7 +183,7 @@ var isPrint16 = []uint16{
0x2d30, 0x2d67,
0x2d6f, 0x2d70,
0x2d7f, 0x2d96,
- 0x2da0, 0x2e42,
+ 0x2da0, 0x2e44,
0x2e80, 0x2ef3,
0x2f00, 0x2fd5,
0x2ff0, 0x2ffb,
@@ -201,12 +198,11 @@ var isPrint16 = []uint16{
0xa490, 0xa4c6,
0xa4d0, 0xa62b,
0xa640, 0xa6f7,
- 0xa700, 0xa7ad,
- 0xa7b0, 0xa7b7,
+ 0xa700, 0xa7b7,
0xa7f7, 0xa82b,
0xa830, 0xa839,
0xa840, 0xa877,
- 0xa880, 0xa8c4,
+ 0xa880, 0xa8c5,
0xa8ce, 0xa8d9,
0xa8e0, 0xa8fd,
0xa900, 0xa953,
@@ -258,6 +254,8 @@ var isNotPrint16 = []uint16{
0x0590,
0x06dd,
0x083f,
+ 0x08b5,
+ 0x08e2,
0x0984,
0x09a9,
0x09b1,
@@ -294,7 +292,6 @@ var isNotPrint16 = []uint16{
0x0c45,
0x0c49,
0x0c57,
- 0x0c80,
0x0c84,
0x0c8d,
0x0c91,
@@ -354,6 +351,7 @@ var isNotPrint16 = []uint16{
0x1fdc,
0x1ff5,
0x208f,
+ 0x23ff,
0x2bc9,
0x2c2f,
0x2c5f,
@@ -371,6 +369,7 @@ var isNotPrint16 = []uint16{
0x318f,
0x321f,
0x32ff,
+ 0xa7af,
0xa9ce,
0xa9ff,
0xab27,
@@ -392,8 +391,7 @@ var isPrint32 = []uint32{
0x010080, 0x0100fa,
0x010100, 0x010102,
0x010107, 0x010133,
- 0x010137, 0x01018c,
- 0x010190, 0x01019b,
+ 0x010137, 0x01019b,
0x0101a0, 0x0101a0,
0x0101d0, 0x0101fd,
0x010280, 0x01029c,
@@ -406,6 +404,8 @@ var isPrint32 = []uint32{
0x0103c8, 0x0103d5,
0x010400, 0x01049d,
0x0104a0, 0x0104a9,
+ 0x0104b0, 0x0104d3,
+ 0x0104d8, 0x0104fb,
0x010500, 0x010527,
0x010530, 0x010563,
0x01056f, 0x01056f,
@@ -451,7 +451,7 @@ var isPrint32 = []uint32{
0x011150, 0x011176,
0x011180, 0x0111cd,
0x0111d0, 0x0111f4,
- 0x011200, 0x01123d,
+ 0x011200, 0x01123e,
0x011280, 0x0112a9,
0x0112b0, 0x0112ea,
0x0112f0, 0x0112f9,
@@ -466,12 +466,14 @@ var isPrint32 = []uint32{
0x01135d, 0x011363,
0x011366, 0x01136c,
0x011370, 0x011374,
+ 0x011400, 0x01145d,
0x011480, 0x0114c7,
0x0114d0, 0x0114d9,
0x011580, 0x0115b5,
0x0115b8, 0x0115dd,
0x011600, 0x011644,
0x011650, 0x011659,
+ 0x011660, 0x01166c,
0x011680, 0x0116b7,
0x0116c0, 0x0116c9,
0x011700, 0x011719,
@@ -480,6 +482,10 @@ var isPrint32 = []uint32{
0x0118a0, 0x0118f2,
0x0118ff, 0x0118ff,
0x011ac0, 0x011af8,
+ 0x011c00, 0x011c45,
+ 0x011c50, 0x011c6c,
+ 0x011c70, 0x011c8f,
+ 0x011c92, 0x011cb6,
0x012000, 0x012399,
0x012400, 0x012474,
0x012480, 0x012543,
@@ -496,6 +502,9 @@ var isPrint32 = []uint32{
0x016f00, 0x016f44,
0x016f50, 0x016f7e,
0x016f8f, 0x016f9f,
+ 0x016fe0, 0x016fe0,
+ 0x017000, 0x0187ec,
+ 0x018800, 0x018af2,
0x01b000, 0x01b001,
0x01bc00, 0x01bc6a,
0x01bc70, 0x01bc7c,
@@ -518,8 +527,13 @@ var isPrint32 = []uint32{
0x01d6a8, 0x01d7cb,
0x01d7ce, 0x01da8b,
0x01da9b, 0x01daaf,
+ 0x01e000, 0x01e018,
+ 0x01e01b, 0x01e02a,
0x01e800, 0x01e8c4,
0x01e8c7, 0x01e8d6,
+ 0x01e900, 0x01e94a,
+ 0x01e950, 0x01e959,
+ 0x01e95e, 0x01e95f,
0x01ee00, 0x01ee24,
0x01ee27, 0x01ee3b,
0x01ee42, 0x01ee42,
@@ -534,14 +548,14 @@ var isPrint32 = []uint32{
0x01f0b1, 0x01f0f5,
0x01f100, 0x01f10c,
0x01f110, 0x01f16b,
- 0x01f170, 0x01f19a,
+ 0x01f170, 0x01f1ac,
0x01f1e6, 0x01f202,
- 0x01f210, 0x01f23a,
+ 0x01f210, 0x01f23b,
0x01f240, 0x01f248,
0x01f250, 0x01f251,
- 0x01f300, 0x01f6d0,
+ 0x01f300, 0x01f6d2,
0x01f6e0, 0x01f6ec,
- 0x01f6f0, 0x01f6f3,
+ 0x01f6f0, 0x01f6f6,
0x01f700, 0x01f773,
0x01f780, 0x01f7d4,
0x01f800, 0x01f80b,
@@ -549,8 +563,11 @@ var isPrint32 = []uint32{
0x01f850, 0x01f859,
0x01f860, 0x01f887,
0x01f890, 0x01f8ad,
- 0x01f910, 0x01f918,
- 0x01f980, 0x01f984,
+ 0x01f910, 0x01f927,
+ 0x01f930, 0x01f930,
+ 0x01f933, 0x01f94b,
+ 0x01f950, 0x01f95e,
+ 0x01f980, 0x01f991,
0x01f9c0, 0x01f9c0,
0x020000, 0x02a6d6,
0x02a700, 0x02b734,
@@ -565,6 +582,7 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x0027,
0x003b,
0x003e,
+ 0x018f,
0x039e,
0x0809,
0x0836,
@@ -585,6 +603,11 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x1329,
0x1331,
0x1334,
+ 0x145a,
+ 0x145c,
+ 0x1c09,
+ 0x1c37,
+ 0x1ca8,
0x246f,
0x6a5f,
0x6b5a,
@@ -603,6 +626,9 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0xd545,
0xd551,
0xdaa0,
+ 0xe007,
+ 0xe022,
+ 0xe025,
0xee04,
0xee20,
0xee23,
@@ -632,8 +658,8 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0xf0c0,
0xf0d0,
0xf12f,
- 0xf57a,
- 0xf5a4,
+ 0xf91f,
+ 0xf93f,
}
// isGraphic lists the graphic runes not matched by IsPrint.
diff --git a/libgo/go/strconv/makeisprint.go b/libgo/go/strconv/makeisprint.go
index 514258060e..0a3e5b20cc 100644
--- a/libgo/go/strconv/makeisprint.go
+++ b/libgo/go/strconv/makeisprint.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
index 40d0667551..76c5c2a1cb 100644
--- a/libgo/go/strconv/quote.go
+++ b/libgo/go/strconv/quote.go
@@ -6,15 +6,19 @@
package strconv
-import (
- "unicode/utf8"
-)
+import "unicode/utf8"
const lowerhex = "0123456789abcdef"
func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
- var runeTmp [utf8.UTFMax]byte
- buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+ return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
+}
+
+func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string {
+ return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly))
+}
+
+func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
@@ -28,64 +32,79 @@ func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
buf = append(buf, lowerhex[s[0]&0xF])
continue
}
- if r == rune(quote) || r == '\\' { // always backslashed
- buf = append(buf, '\\')
+ buf = appendEscapedRune(buf, r, width, quote, ASCIIonly, graphicOnly)
+ }
+ buf = append(buf, quote)
+ return buf
+}
+
+func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
+ buf = append(buf, quote)
+ if !utf8.ValidRune(r) {
+ r = utf8.RuneError
+ }
+ buf = appendEscapedRune(buf, r, utf8.RuneLen(r), quote, ASCIIonly, graphicOnly)
+ buf = append(buf, quote)
+ return buf
+}
+
+func appendEscapedRune(buf []byte, r rune, width int, quote byte, ASCIIonly, graphicOnly bool) []byte {
+ var runeTmp [utf8.UTFMax]byte
+ if r == rune(quote) || r == '\\' { // always backslashed
+ buf = append(buf, '\\')
+ buf = append(buf, byte(r))
+ return buf
+ }
+ if ASCIIonly {
+ if r < utf8.RuneSelf && IsPrint(r) {
buf = append(buf, byte(r))
- continue
+ return buf
}
- if ASCIIonly {
- if r < utf8.RuneSelf && IsPrint(r) {
- buf = append(buf, byte(r))
- continue
+ } else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
+ n := utf8.EncodeRune(runeTmp[:], r)
+ buf = append(buf, runeTmp[:n]...)
+ return buf
+ }
+ switch r {
+ case '\a':
+ buf = append(buf, `\a`...)
+ case '\b':
+ buf = append(buf, `\b`...)
+ case '\f':
+ buf = append(buf, `\f`...)
+ case '\n':
+ buf = append(buf, `\n`...)
+ case '\r':
+ buf = append(buf, `\r`...)
+ case '\t':
+ buf = append(buf, `\t`...)
+ case '\v':
+ buf = append(buf, `\v`...)
+ default:
+ switch {
+ case r < ' ':
+ buf = append(buf, `\x`...)
+ buf = append(buf, lowerhex[byte(r)>>4])
+ buf = append(buf, lowerhex[byte(r)&0xF])
+ case r > utf8.MaxRune:
+ r = 0xFFFD
+ fallthrough
+ case r < 0x10000:
+ buf = append(buf, `\u`...)
+ for s := 12; s >= 0; s -= 4 {
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
- } else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
- n := utf8.EncodeRune(runeTmp[:], r)
- buf = append(buf, runeTmp[:n]...)
- continue
- }
- switch r {
- case '\a':
- buf = append(buf, `\a`...)
- case '\b':
- buf = append(buf, `\b`...)
- case '\f':
- buf = append(buf, `\f`...)
- case '\n':
- buf = append(buf, `\n`...)
- case '\r':
- buf = append(buf, `\r`...)
- case '\t':
- buf = append(buf, `\t`...)
- case '\v':
- buf = append(buf, `\v`...)
default:
- switch {
- case r < ' ':
- buf = append(buf, `\x`...)
- buf = append(buf, lowerhex[s[0]>>4])
- buf = append(buf, lowerhex[s[0]&0xF])
- case r > utf8.MaxRune:
- r = 0xFFFD
- fallthrough
- case r < 0x10000:
- buf = append(buf, `\u`...)
- for s := 12; s >= 0; s -= 4 {
- buf = append(buf, lowerhex[r>>uint(s)&0xF])
- }
- default:
- buf = append(buf, `\U`...)
- for s := 28; s >= 0; s -= 4 {
- buf = append(buf, lowerhex[r>>uint(s)&0xF])
- }
+ buf = append(buf, `\U`...)
+ for s := 28; s >= 0; s -= 4 {
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
- buf = append(buf, quote)
- return string(buf)
-
+ return buf
}
-// Quote returns a double-quoted Go string literal representing s. The
+// Quote returns a double-quoted Go string literal representing s. The
// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
// control characters and non-printable characters as defined by
// IsPrint.
@@ -96,7 +115,7 @@ func Quote(s string) string {
// AppendQuote appends a double-quoted Go string literal representing s,
// as generated by Quote, to dst and returns the extended buffer.
func AppendQuote(dst []byte, s string) []byte {
- return append(dst, Quote(s)...)
+ return appendQuotedWith(dst, s, '"', false, false)
}
// QuoteToASCII returns a double-quoted Go string literal representing s.
@@ -109,7 +128,7 @@ func QuoteToASCII(s string) string {
// AppendQuoteToASCII appends a double-quoted Go string literal representing s,
// as generated by QuoteToASCII, to dst and returns the extended buffer.
func AppendQuoteToASCII(dst []byte, s string) []byte {
- return append(dst, QuoteToASCII(s)...)
+ return appendQuotedWith(dst, s, '"', true, false)
}
// QuoteToGraphic returns a double-quoted Go string literal representing s.
@@ -122,21 +141,20 @@ func QuoteToGraphic(s string) string {
// AppendQuoteToGraphic appends a double-quoted Go string literal representing s,
// as generated by QuoteToGraphic, to dst and returns the extended buffer.
func AppendQuoteToGraphic(dst []byte, s string) []byte {
- return append(dst, QuoteToGraphic(s)...)
+ return appendQuotedWith(dst, s, '"', false, true)
}
// QuoteRune returns a single-quoted Go character literal representing the
// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
// for control characters and non-printable characters as defined by IsPrint.
func QuoteRune(r rune) string {
- // TODO: avoid the allocation here.
- return quoteWith(string(r), '\'', false, false)
+ return quoteRuneWith(r, '\'', false, false)
}
// AppendQuoteRune appends a single-quoted Go character literal representing the rune,
// as generated by QuoteRune, to dst and returns the extended buffer.
func AppendQuoteRune(dst []byte, r rune) []byte {
- return append(dst, QuoteRune(r)...)
+ return appendQuotedRuneWith(dst, r, '\'', false, false)
}
// QuoteRuneToASCII returns a single-quoted Go character literal representing
@@ -144,14 +162,13 @@ func AppendQuoteRune(dst []byte, r rune) []byte {
// \u0100) for non-ASCII characters and non-printable characters as defined
// by IsPrint.
func QuoteRuneToASCII(r rune) string {
- // TODO: avoid the allocation here.
- return quoteWith(string(r), '\'', true, false)
+ return quoteRuneWith(r, '\'', true, false)
}
// AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune,
// as generated by QuoteRuneToASCII, to dst and returns the extended buffer.
func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
- return append(dst, QuoteRuneToASCII(r)...)
+ return appendQuotedRuneWith(dst, r, '\'', true, false)
}
// QuoteRuneToGraphic returns a single-quoted Go character literal representing
@@ -159,14 +176,13 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
// \u0100) for non-ASCII characters and non-printable characters as defined
// by IsGraphic.
func QuoteRuneToGraphic(r rune) string {
- // TODO: avoid the allocation here.
- return quoteWith(string(r), '\'', false, true)
+ return quoteRuneWith(r, '\'', false, true)
}
// AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune,
// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer.
func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte {
- return append(dst, QuoteRuneToGraphic(r)...)
+ return appendQuotedRuneWith(dst, r, '\'', false, true)
}
// CanBackquote reports whether the string s can be represented
@@ -331,7 +347,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
// that s quotes. (If s is single-quoted, it would be a Go
// character literal; Unquote returns the corresponding
// one-character string.)
-func Unquote(s string) (t string, err error) {
+func Unquote(s string) (string, error) {
n := len(s)
if n < 2 {
return "", ErrSyntax
@@ -346,6 +362,16 @@ func Unquote(s string) (t string, err error) {
if contains(s, '`') {
return "", ErrSyntax
}
+ if contains(s, '\r') {
+ // -1 because we know there is at least one \r to remove.
+ buf := make([]byte, 0, len(s)-1)
+ for i := 0; i < len(s); i++ {
+ if s[i] != '\r' {
+ buf = append(buf, s[i])
+ }
+ }
+ return string(buf), nil
+ }
return s, nil
}
if quote != '"' && quote != '\'' {
diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go
index 3e8ec2c98f..a4b5804fc8 100644
--- a/libgo/go/strconv/quote_test.go
+++ b/libgo/go/strconv/quote_test.go
@@ -89,6 +89,34 @@ func TestQuoteToGraphic(t *testing.T) {
}
}
+func BenchmarkQuote(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+ }
+}
+
+func BenchmarkQuoteRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ QuoteRune('\a')
+ }
+}
+
+var benchQuoteBuf []byte
+
+func BenchmarkAppendQuote(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+ }
+}
+
+var benchQuoteRuneBuf []byte
+
+func BenchmarkAppendQuoteRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a')
+ }
+}
+
type quoteRuneTest struct {
in rune
out string
@@ -246,6 +274,7 @@ var unquotetests = []unQuoteTest{
{"`\n`", "\n"},
{"` `", ` `},
{"` `", ` `},
+ {"`a\rb`", "ab"},
}
var misquoted = []string{
@@ -278,7 +307,7 @@ var misquoted = []string{
func TestUnquote(t *testing.T) {
for _, tt := range unquotetests {
- if out, err := Unquote(tt.in); err != nil && out != tt.out {
+ if out, err := Unquote(tt.in); err != nil || out != tt.out {
t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
}
}
diff --git a/libgo/go/strconv/strconv_test.go b/libgo/go/strconv/strconv_test.go
index 207e00e75d..ebec0cc9e8 100644
--- a/libgo/go/strconv/strconv_test.go
+++ b/libgo/go/strconv/strconv_test.go
@@ -4,10 +4,6 @@
package strconv_test
-/*
-
-gccgo does not pass this.
-
import (
"runtime"
. "strconv"
@@ -46,6 +42,9 @@ var (
)
func TestCountMallocs(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping on gccgo until escape analysis is turned on")
+ }
if testing.Short() {
t.Skip("skipping malloc count in short mode")
}
@@ -60,4 +59,33 @@ func TestCountMallocs(t *testing.T) {
}
}
-*/
+func TestErrorPrefixes(t *testing.T) {
+ _, errInt := Atoi("INVALID")
+ _, errBool := ParseBool("INVALID")
+ _, errFloat := ParseFloat("INVALID", 64)
+ _, errInt64 := ParseInt("INVALID", 10, 64)
+ _, errUint64 := ParseUint("INVALID", 10, 64)
+
+ vectors := []struct {
+ err error // Input error
+ want string // Function name wanted
+ }{
+ {errInt, "Atoi"},
+ {errBool, "ParseBool"},
+ {errFloat, "ParseFloat"},
+ {errInt64, "ParseInt"},
+ {errUint64, "ParseUint"},
+ }
+
+ for _, v := range vectors {
+ nerr, ok := v.err.(*NumError)
+ if !ok {
+ t.Errorf("test %s, error was not a *NumError", v.want)
+ continue
+ }
+ if got := nerr.Func; got != v.want {
+ t.Errorf("mismatching Func: got %s, want %s", got, v.want)
+ }
+ }
+
+}
diff --git a/libgo/go/strings/compare.go b/libgo/go/strings/compare.go
index b84dddea74..1fe6b8d89a 100644
--- a/libgo/go/strings/compare.go
+++ b/libgo/go/strings/compare.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/strings/compare_test.go b/libgo/go/strings/compare_test.go
index 68fc88e143..bc12e421b0 100644
--- a/libgo/go/strings/compare_test.go
+++ b/libgo/go/strings/compare_test.go
@@ -56,7 +56,7 @@ func TestCompareStrings(t *testing.T) {
a := make([]byte, n+1)
b := make([]byte, n+1)
for len := 0; len < 128; len++ {
- // randomish but deterministic data. No 0 or 255.
+ // randomish but deterministic data. No 0 or 255.
for i := 0; i < len; i++ {
a[i] = byte(1 + 31*i%254)
b[i] = byte(1 + 31*i%254)
diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go
index 7a872fbcb0..6c1a5064c0 100644
--- a/libgo/go/strings/reader.go
+++ b/libgo/go/strings/reader.go
@@ -35,9 +35,6 @@ func (r *Reader) Len() int {
func (r *Reader) Size() int64 { return int64(len(r.s)) }
func (r *Reader) Read(b []byte) (n int, err error) {
- if len(b) == 0 {
- return 0, nil
- }
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
@@ -62,14 +59,14 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
return
}
-func (r *Reader) ReadByte() (b byte, err error) {
+func (r *Reader) ReadByte() (byte, error) {
r.prevRune = -1
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- b = r.s[r.i]
+ b := r.s[r.i]
r.i++
- return
+ return b, nil
}
func (r *Reader) UnreadByte() error {
@@ -110,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:
- abs = int64(r.i) + offset
- case 2:
+ case io.SeekCurrent:
+ abs = r.i + offset
+ case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("strings.Reader.Seek: invalid whence")
@@ -145,6 +142,9 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
return
}
+// Reset resets the Reader to be reading from s.
+func (r *Reader) Reset(s string) { *r = Reader{s, 0, -1} }
+
// NewReader returns a new Reader reading from s.
// It is similar to bytes.NewBufferString but more efficient and read-only.
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
diff --git a/libgo/go/strings/reader_test.go b/libgo/go/strings/reader_test.go
index 5003a37be4..bf40eb1a31 100644
--- a/libgo/go/strings/reader_test.go
+++ b/libgo/go/strings/reader_test.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "os"
"strings"
"sync"
"testing"
@@ -23,17 +22,18 @@ func TestReader(t *testing.T) {
n int
want string
wantpos int64
+ readerr error
seekerr string
}{
- {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
- {seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
- {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"},
- {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
- {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
- {seek: os.SEEK_SET, n: 5, want: "01234"},
- {seek: os.SEEK_CUR, n: 5, want: "56789"},
- {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+ {seek: io.SeekStart, off: 0, n: 20, want: "0123456789"},
+ {seek: io.SeekStart, off: 1, n: 1, want: "1"},
+ {seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"},
+ {seek: io.SeekStart, off: -1, seekerr: "strings.Reader.Seek: negative position"},
+ {seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF},
+ {seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF},
+ {seek: io.SeekStart, n: 5, want: "01234"},
+ {seek: io.SeekCurrent, n: 5, want: "56789"},
+ {seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"},
}
for i, tt := range tests {
@@ -51,8 +51,8 @@ func TestReader(t *testing.T) {
}
buf := make([]byte, tt.n)
n, err := r.Read(buf)
- if err != nil {
- t.Errorf("%d. read = %v", i, err)
+ if err != tt.readerr {
+ t.Errorf("%d. read = %v; want %v", i, err, tt.readerr)
continue
}
got := string(buf[:n])
@@ -64,7 +64,7 @@ func TestReader(t *testing.T) {
func TestReadAfterBigSeek(t *testing.T) {
r := strings.NewReader("0123456789")
- if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil {
t.Fatal(err)
}
if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
@@ -170,3 +170,23 @@ func TestReaderLenSize(t *testing.T) {
t.Errorf("Size = %d; want 3", r.Size())
}
}
+
+func TestReaderReset(t *testing.T) {
+ r := strings.NewReader("世界")
+ if _, _, err := r.ReadRune(); err != nil {
+ t.Errorf("ReadRune: unexpected error: %v", err)
+ }
+
+ const want = "abcdef"
+ r.Reset(want)
+ if err := r.UnreadRune(); err == nil {
+ t.Errorf("UnreadRune: expected error, got nil")
+ }
+ buf, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("ReadAll: unexpected error: %v", err)
+ }
+ if got := string(buf); got != want {
+ t.Errorf("ReadAll: got %q, want %q", got, want)
+ }
+}
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
index 37d5647ffd..60a281a6ac 100644
--- a/libgo/go/strings/strings.go
+++ b/libgo/go/strings/strings.go
@@ -12,32 +12,25 @@ import (
"unicode/utf8"
)
-// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
-// Invalid UTF-8 sequences become correct encodings of U+FFF8.
+// explode splits s into a slice of UTF-8 strings,
+// one string per Unicode character up to a maximum of n (n < 0 means no limit).
+// Invalid UTF-8 sequences become correct encodings of U+FFFD.
func explode(s string, n int) []string {
- if n == 0 {
- return nil
- }
l := utf8.RuneCountInString(s)
- if n <= 0 || n > l {
+ if n < 0 || n > l {
n = l
}
a := make([]string, n)
- var size int
- var ch rune
- i, cur := 0, 0
- for ; i+1 < n; i++ {
- ch, size = utf8.DecodeRuneInString(s[cur:])
+ for i := 0; i < n-1; i++ {
+ ch, size := utf8.DecodeRuneInString(s)
+ a[i] = s[:size]
+ s = s[size:]
if ch == utf8.RuneError {
a[i] = string(utf8.RuneError)
- } else {
- a[i] = s[cur : cur+size]
}
- cur += size
}
- // add the rest, if there is any
- if cur < len(s) {
- a[i] = s[cur:]
+ if n > 0 {
+ a[n-1] = s
}
return a
}
@@ -84,48 +77,18 @@ func hashStrRev(sep string) (uint32, uint32) {
func Count(s, sep string) int {
n := 0
// special cases
- switch {
- case len(sep) == 0:
+ if len(sep) == 0 {
return utf8.RuneCountInString(s) + 1
- case len(sep) == 1:
- // special case worth making fast
- c := sep[0]
- for i := 0; i < len(s); i++ {
- if s[i] == c {
- n++
- }
- }
- return n
- case len(sep) > len(s):
- return 0
- case len(sep) == len(s):
- if sep == s {
- return 1
- }
- return 0
- }
- // Rabin-Karp search
- hashsep, pow := hashStr(sep)
- h := uint32(0)
- for i := 0; i < len(sep); i++ {
- h = h*primeRK + uint32(s[i])
}
- lastmatch := 0
- if h == hashsep && s[:len(sep)] == sep {
- n++
- lastmatch = len(sep)
- }
- for i := len(sep); i < len(s); {
- h *= primeRK
- h += uint32(s[i])
- h -= pow * uint32(s[i-len(sep)])
- i++
- if h == hashsep && lastmatch <= i-len(sep) && s[i-len(sep):i] == sep {
- n++
- lastmatch = i
+ offset := 0
+ for {
+ i := Index(s[offset:], sep)
+ if i == -1 {
+ return n
}
+ n++
+ offset += i + len(sep)
}
- return n
}
// Contains reports whether substr is within s.
@@ -182,24 +145,40 @@ func LastIndex(s, sep string) int {
// IndexRune returns the index of the first instance of the Unicode code point
// r, or -1 if rune is not present in s.
+// If r is utf8.RuneError, it returns the first instance of any
+// invalid UTF-8 byte sequence.
func IndexRune(s string, r rune) int {
switch {
- case r < utf8.RuneSelf:
+ case 0 <= r && r < utf8.RuneSelf:
return IndexByte(s, byte(r))
- default:
- for i, c := range s {
- if c == r {
+ case r == utf8.RuneError:
+ for i, r := range s {
+ if r == utf8.RuneError {
return i
}
}
+ return -1
+ case !utf8.ValidRune(r):
+ return -1
+ default:
+ return Index(s, string(r))
}
- return -1
}
// IndexAny returns the index of the first instance of any Unicode code point
// from chars in s, or -1 if no Unicode code point from chars is present in s.
func IndexAny(s, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := 0; i < len(s); i++ {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i, c := range s {
for _, m := range chars {
if c == m {
@@ -216,11 +195,21 @@ func IndexAny(s, chars string) int {
// present in s.
func LastIndexAny(s, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := len(s) - 1; i >= 0; i-- {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i := len(s); i > 0; {
- rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ r, size := utf8.DecodeLastRuneInString(s[:i])
i -= size
- for _, m := range chars {
- if rune == m {
+ for _, c := range chars {
+ if r == c {
return i
}
}
@@ -346,14 +335,22 @@ func FieldsFunc(s string, f func(rune) bool) []string {
return a
}
-// Join concatenates the elements of a to create a single string. The separator string
+// Join concatenates the elements of a to create a single string. The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
- if len(a) == 0 {
+ switch len(a) {
+ case 0:
return ""
- }
- if len(a) == 1 {
+ case 1:
return a[0]
+ case 2:
+ // Special case for common small values.
+ // Remove if golang.org/issue/6714 is fixed
+ return a[0] + sep + a[1]
+ case 3:
+ // Special case for common small values.
+ // Remove if golang.org/issue/6714 is fixed
+ return a[0] + sep + a[1] + sep + a[2]
}
n := len(sep) * (len(a) - 1)
for i := 0; i < len(a); i++ {
@@ -384,8 +381,8 @@ func HasSuffix(s, suffix string) bool {
// dropped from the string with no replacement.
func Map(mapping func(rune) rune, s string) string {
// In the worst case, the string can grow when mapped, making
- // things unpleasant. But it's so rare we barge in assuming it's
- // fine. It could also shrink but that falls out naturally.
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
maxbytes := len(s) // length of b
nbytes := 0 // number of bytes encoded in b
// The output buffer b is initialized on demand, the first
@@ -423,7 +420,20 @@ func Map(mapping func(rune) rune, s string) string {
}
// Repeat returns a new string consisting of count copies of the string s.
+//
+// It panics if count is negative or if
+// the result of (len(s) * count) overflows.
func Repeat(s string, count int) string {
+ // Since we cannot return an error on overflow,
+ // we should panic if the repeat will generate
+ // an overflow.
+ // See Issue golang.org/issue/16237
+ if count < 0 {
+ panic("strings: negative Repeat count")
+ } else if count > 0 && len(s)*count/count != len(s) {
+ panic("strings: Repeat count causes overflow")
+ }
+
b := make([]byte, len(s)*count)
bp := copy(b, s)
for bp < len(b) {
@@ -444,20 +454,20 @@ func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
-func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
+func ToUpperSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
-func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToLower(r) }, s)
+func ToLowerSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
-func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
+func ToTitleSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToTitle(r) }, s)
}
// isSeparator reports whether the rune could mark a word boundary.
@@ -580,7 +590,43 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
return -1
}
+// asciiSet is a 32-byte value, where each bit represents the presence of a
+// given ASCII character in the set. The 128-bits of the lower 16 bytes,
+// starting with the least-significant bit of the lowest word to the
+// most-significant bit of the highest word, map to the full range of all
+// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
+// ensuring that any non-ASCII character will be reported as not in the set.
+type asciiSet [8]uint32
+
+// makeASCIISet creates a set of ASCII characters and reports whether all
+// characters in chars are ASCII.
+func makeASCIISet(chars string) (as asciiSet, ok bool) {
+ for i := 0; i < len(chars); i++ {
+ c := chars[i]
+ if c >= utf8.RuneSelf {
+ return as, false
+ }
+ as[c>>5] |= 1 << uint(c&31)
+ }
+ return as, true
+}
+
+// contains reports whether c is inside the set.
+func (as *asciiSet) contains(c byte) bool {
+ return (as[c>>5] & (1 << uint(c&31))) != 0
+}
+
func makeCutsetFunc(cutset string) func(rune) bool {
+ if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+ return func(r rune) bool {
+ return r == rune(cutset[0])
+ }
+ }
+ if as, isASCII := makeASCIISet(cutset); isASCII {
+ return func(r rune) bool {
+ return r < utf8.RuneSelf && as.contains(byte(r))
+ }
+ }
return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}
@@ -714,7 +760,7 @@ func EqualFold(s, t string) bool {
return false
}
- // General case. SimpleFold(x) returns the next equivalent rune > x
+ // General case. SimpleFold(x) returns the next equivalent rune > x
// or wraps around to smaller values.
r := unicode.SimpleFold(sr)
for r != sr && r < tr {
@@ -726,6 +772,6 @@ func EqualFold(s, t string) bool {
return false
}
- // One string is empty. Are both?
+ // One string is empty. Are both?
return s == t
}
diff --git a/libgo/go/strings/strings_amd64.go b/libgo/go/strings/strings_amd64.go
index 376113f0a2..e55afd53d0 100644
--- a/libgo/go/strings/strings_amd64.go
+++ b/libgo/go/strings/strings_amd64.go
@@ -1,13 +1,27 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 ignore
+
package strings
+//go:noescape
+
// 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
+func supportAVX2() bool // ../runtime/asm_$GOARCH.s
+
+var shortStringLen int
+
+func init() {
+ if supportAVX2() {
+ shortStringLen = 63
+ } else {
+ shortStringLen = 31
+ }
+}
// 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 {
@@ -17,8 +31,6 @@ func Index(s, sep string) int {
return 0
case n == 1:
return IndexByte(s, sep[0])
- case n <= shortStringLen:
- return indexShortStr(s, sep)
case n == len(s):
if sep == s {
return 0
@@ -26,6 +38,42 @@ func Index(s, sep string) int {
return -1
case n > len(s):
return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if s[i:i+n] == sep {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // Too many means more that 1 error per 8 characters.
+ // Allow some errors in the beginning.
+ if fails > (i+16)/8 {
+ r := indexShortStr(s[i:], sep)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
}
// Rabin-Karp search
hashsep, pow := hashStr(sep)
diff --git a/libgo/go/strings/strings_decl.go b/libgo/go/strings/strings_decl.go
index 810a696af2..3bae8448c3 100644
--- a/libgo/go/strings/strings_decl.go
+++ b/libgo/go/strings/strings_decl.go
@@ -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.
diff --git a/libgo/go/strings/strings_generic.go b/libgo/go/strings/strings_generic.go
index 811cb80316..a3ad515444 100644
--- a/libgo/go/strings/strings_generic.go
+++ b/libgo/go/strings/strings_generic.go
@@ -1,8 +1,8 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 !amd64
+// -build !amd64,!s390x
package strings
diff --git a/libgo/go/strings/strings_s390x.go b/libgo/go/strings/strings_s390x.go
new file mode 100644
index 0000000000..b47702fd51
--- /dev/null
+++ b/libgo/go/strings/strings_s390x.go
@@ -0,0 +1,100 @@
+// 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 strings
+
+//go:noescape
+
+// indexShortStr returns the index of the first instance of sep in s,
+// or -1 if sep is not present in s.
+// indexShortStr requires 2 <= len(sep) <= shortStringLen
+func indexShortStr(s, sep string) int // ../runtime/asm_$GOARCH.s
+
+// supportsVX reports whether the vector facility is available.
+// indexShortStr must not be called if the vector facility is not
+// available.
+func supportsVX() bool // ../runtime/asm_s390x.s
+
+var shortStringLen = -1
+
+func init() {
+ if supportsVX() {
+ shortStringLen = 64
+ }
+}
+
+// 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 {
+ n := len(sep)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if sep == s {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if s[i:i+n] == sep {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // Too many means more that 1 error per 8 characters.
+ // Allow some errors in the beginning.
+ if fails > (i+16)/8 {
+ r := indexShortStr(s[i:], sep)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && s[:n] == sep {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && s[i-n:i] == sep {
+ return i - n
+ }
+ }
+ return -1
+}
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index 49f55fe38c..449fb502d6 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -6,9 +6,11 @@ package strings_test
import (
"bytes"
+ "fmt"
"io"
"math/rand"
"reflect"
+ "runtime"
. "strings"
"testing"
"unicode"
@@ -86,32 +88,44 @@ var indexTests = []IndexTest{
{"32145678", "01234567", -1},
{"01234567", "01234567", 0},
{"x01234567", "01234567", 1},
+ {"x0123456x01234567", "01234567", 9},
{"xx01234567"[:9], "01234567", -1},
{"", "0123456789", -1},
{"3214567844", "0123456789", -1},
{"0123456789", "0123456789", 0},
{"x0123456789", "0123456789", 1},
+ {"x012345678x0123456789", "0123456789", 11},
{"xyz0123456789"[:12], "0123456789", -1},
{"x01234567x89", "0123456789", -1},
{"", "0123456789012345", -1},
{"3214567889012345", "0123456789012345", -1},
{"0123456789012345", "0123456789012345", 0},
{"x0123456789012345", "0123456789012345", 1},
+ {"x012345678901234x0123456789012345", "0123456789012345", 17},
{"", "01234567890123456789", -1},
{"32145678890123456789", "01234567890123456789", -1},
{"01234567890123456789", "01234567890123456789", 0},
{"x01234567890123456789", "01234567890123456789", 1},
+ {"x0123456789012345678x01234567890123456789", "01234567890123456789", 21},
{"xyz01234567890123456789"[:22], "01234567890123456789", -1},
{"", "0123456789012345678901234567890", -1},
{"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},
{"0123456789012345678901234567890", "0123456789012345678901234567890", 0},
{"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},
+ {"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32},
{"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},
{"", "01234567890123456789012345678901", -1},
{"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},
{"01234567890123456789012345678901", "01234567890123456789012345678901", 0},
{"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},
+ {"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33},
{"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},
+ {"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6},
+ {"", "0123456789012345678901234567890123456789", -1},
+ {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2},
+ {"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1},
+ {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1},
+ {"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65},
}
var lastIndexTests = []IndexTest{
@@ -139,10 +153,15 @@ var indexAnyTests = []IndexTest{
{"aaa", "a", 0},
{"abc", "xyz", -1},
{"abc", "xcz", 2},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"aRegExp*", ".(|)*+?^$[]", 7},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 4},
+ {"012\x80bcb\x80210", "\xffb", 3},
}
+
var lastIndexAnyTests = []IndexTest{
{"", "", -1},
{"", "a", -1},
@@ -152,9 +171,13 @@ var lastIndexAnyTests = []IndexTest{
{"aaa", "a", 2},
{"abc", "xyz", -1},
{"abc", "ab", 1},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"a.RegExp*", ".(|)*+?^$[]", 8},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 6},
+ {"012\x80bcb\x80210", "\xffb", 7},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -190,22 +213,93 @@ func TestLastIndexByte(t *testing.T) {
}
}
-var indexRuneTests = []struct {
- s string
- rune rune
- out int
-}{
- {"a A x", 'A', 2},
- {"some_text=some_value", '=', 9},
- {"☺a", 'a', 3},
- {"a☻☺b", '☺', 4},
+func simpleIndex(s, sep string) int {
+ n := len(sep)
+ for i := n; i <= len(s); i++ {
+ if s[i-n:i] == sep {
+ return i - n
+ }
+ }
+ return -1
+}
+
+func TestIndexRandom(t *testing.T) {
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
+ for times := 0; times < 10; times++ {
+ for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary
+ s1 := make([]byte, strLen)
+ for i := range s1 {
+ s1[i] = chars[rand.Intn(len(chars))]
+ }
+ s := string(s1)
+ for i := 0; i < 50; i++ {
+ begin := rand.Intn(len(s) + 1)
+ end := begin + rand.Intn(len(s)+1-begin)
+ sep := s[begin:end]
+ if i%4 == 0 {
+ pos := rand.Intn(len(sep) + 1)
+ sep = sep[:pos] + "A" + sep[pos:]
+ }
+ want := simpleIndex(s, sep)
+ res := Index(s, sep)
+ if res != want {
+ t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want)
+ }
+ }
+ }
+ }
}
func TestIndexRune(t *testing.T) {
- for _, test := range indexRuneTests {
- if actual := IndexRune(test.s, test.rune); actual != test.out {
- t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out)
+ tests := []struct {
+ in string
+ rune rune
+ want int
+ }{
+ {"", 'a', -1},
+ {"", '☺', -1},
+ {"foo", '☹', -1},
+ {"foo", 'o', 1},
+ {"foo☺bar", '☺', 3},
+ {"foo☺☻☹bar", '☹', 9},
+ {"a A x", 'A', 2},
+ {"some_text=some_value", '=', 9},
+ {"☺a", 'a', 3},
+ {"a☻☺b", '☺', 4},
+
+ // RuneError should match any invalid UTF-8 byte sequence.
+ {"�", '�', 0},
+ {"\xff", '�', 0},
+ {"☻x�", '�', len("☻x")},
+ {"☻x\xe2\x98", '�', len("☻x")},
+ {"☻x\xe2\x98�", '�', len("☻x")},
+ {"☻x\xe2\x98x", '�', len("☻x")},
+
+ // Invalid rune values should never match.
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},
+ }
+ for _, tt := range tests {
+ if got := IndexRune(tt.in, tt.rune); got != tt.want {
+ t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)
+ }
+ }
+
+ haystack := "test世界"
+ allocs := testing.AllocsPerRun(1000, func() {
+ if i := IndexRune(haystack, 's'); i != 2 {
+ t.Fatalf("'s' at %d; want 2", i)
+ }
+ if i := IndexRune(haystack, '世'); i != 4 {
+ t.Fatalf("'世' at %d; want 4", i)
}
+ })
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping allocations test for gccgo until escape analysis is enabled")
+ }
+ if allocs != 0 && testing.CoverMode() == "" {
+ t.Errorf("expected no allocations, got %f", allocs)
}
}
@@ -220,6 +314,17 @@ func BenchmarkIndexRune(b *testing.B) {
}
}
+var benchmarkLongString = Repeat(" ", 100) + benchmarkString
+
+func BenchmarkIndexRuneLongString(b *testing.B) {
+ if got := IndexRune(benchmarkLongString, '☺'); got != 114 {
+ b.Fatalf("wrong index: expected 114, got=%d", got)
+ }
+ for i := 0; i < b.N; i++ {
+ IndexRune(benchmarkLongString, '☺')
+ }
+}
+
func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 {
b.Fatalf("wrong index: expected 17, got=%d", got)
@@ -256,31 +361,6 @@ func BenchmarkIndexByte(b *testing.B) {
}
}
-var explodetests = []struct {
- s string
- n int
- a []string
-}{
- {"", -1, []string{}},
- {abcd, 4, []string{"a", "b", "c", "d"}},
- {faces, 3, []string{"☺", "☻", "☹"}},
- {abcd, 2, []string{"a", "bcd"}},
-}
-
-func TestExplode(t *testing.T) {
- for _, tt := range explodetests {
- a := SplitN(tt.s, "", tt.n)
- if !eq(a, tt.a) {
- t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
- continue
- }
- s := Join(a, "")
- if s != tt.s {
- t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s)
- }
- }
-}
-
type SplitTest struct {
s string
sep string
@@ -289,19 +369,23 @@ type SplitTest struct {
}
var splittests = []SplitTest{
+ {"", "", -1, []string{}},
+ {abcd, "", 2, []string{"a", "bcd"}},
+ {abcd, "", 4, []string{"a", "b", "c", "d"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {faces, "", 3, []string{"☺", "☻", "☹"}},
+ {faces, "", 17, []string{"☺", "☻", "☹"}},
+ {"☺�☹", "", -1, []string{"☺", "�", "☹"}},
{abcd, "a", 0, nil},
{abcd, "a", -1, []string{"", "bcd"}},
{abcd, "z", -1, []string{"abcd"}},
- {abcd, "", -1, []string{"a", "b", "c", "d"}},
{commas, ",", -1, []string{"1", "2", "3", "4"}},
{dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
{faces, "☹", -1, []string{"☺☻", ""}},
{faces, "~", -1, []string{faces}},
- {faces, "", -1, []string{"☺", "☻", "☹"}},
{"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
{"1 2", " ", 3, []string{"1", "2"}},
- {"123", "", 2, []string{"1", "23"}},
- {"123", "", 17, []string{"1", "2", "3"}},
}
func TestSplit(t *testing.T) {
@@ -492,7 +576,7 @@ func rot13(r rune) rune {
func TestMap(t *testing.T) {
// Run a couple of awful growth/shrinkage tests
a := tenRunes('a')
- // 1. Grow. This triggers two reallocations in Map.
+ // 1. Grow. This triggers two reallocations in Map.
maxRune := func(rune) rune { return unicode.MaxRune }
m := Map(maxRune, a)
expect := tenRunes(unicode.MaxRune)
@@ -597,6 +681,9 @@ var trimTests = []struct {
{"Trim", "* listitem", " *", "listitem"},
{"Trim", `"quote"`, `"`, "quote"},
{"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "\x80test\xff", "\xff", "test"},
+ {"Trim", " Ä  ", " ", "Ä "},
+ {"Trim", " Ä Ä°0", "0 ", "Ä Ä°"},
//empty string tests
{"Trim", "abba", "", "abba"},
{"Trim", "", "123", ""},
@@ -839,6 +926,54 @@ func TestRepeat(t *testing.T) {
}
}
+func repeat(s string, count int) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ switch v := r.(type) {
+ case error:
+ err = v
+ default:
+ err = fmt.Errorf("%s", v)
+ }
+ }
+ }()
+
+ Repeat(s, count)
+
+ return
+}
+
+// See Issue golang.org/issue/16237
+func TestRepeatCatchesOverflow(t *testing.T) {
+ tests := [...]struct {
+ s string
+ count int
+ errStr string
+ }{
+ 0: {"--", -2147483647, "negative"},
+ 1: {"", int(^uint(0) >> 1), ""},
+ 2: {"-", 10, ""},
+ 3: {"gopher", 0, ""},
+ 4: {"-", -1, "negative"},
+ 5: {"--", -102, "negative"},
+ 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
+ }
+
+ for i, tt := range tests {
+ err := repeat(tt.s, tt.count)
+ if tt.errStr == "" {
+ if err != nil {
+ t.Errorf("#%d panicked %v", i, err)
+ }
+ continue
+ }
+
+ if err == nil || !Contains(err.Error(), tt.errStr) {
+ t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
+ }
+ }
+}
+
func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
@@ -973,7 +1108,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{}) }},
}
@@ -1057,6 +1192,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) {
@@ -1210,6 +1409,9 @@ func benchmarkCountHard(b *testing.B, sep string) {
func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, "<>") }
func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, "</pre>") }
func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, "<b>hello world</b>") }
+func BenchmarkIndexHard4(b *testing.B) {
+ benchmarkIndexHard(b, "<pre><b>hello</b><strong>world</strong></pre>")
+}
func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, "<>") }
func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, "</pre>") }
@@ -1301,3 +1503,31 @@ func BenchmarkRepeat(b *testing.B) {
Repeat("-", 80)
}
}
+
+func BenchmarkIndexAnyASCII(b *testing.B) {
+ x := Repeat("#", 4096) // Never matches set
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ IndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
+func BenchmarkTrimASCII(b *testing.B) {
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ x := Repeat(cs[:j], k) // Always matches set
+ for i := 0; i < b.N; i++ {
+ Trim(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
diff --git a/libgo/go/sync/atomic/64bit_arm.go b/libgo/go/sync/atomic/64bit_arm.go
index b98e60827e..4ef11747bb 100644
--- a/libgo/go/sync/atomic/64bit_arm.go
+++ b/libgo/go/sync/atomic/64bit_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/sync/atomic/atomic.c b/libgo/go/sync/atomic/atomic.c
index f0ba57b3cc..7e04027c3f 100644
--- a/libgo/go/sync/atomic/atomic.c
+++ b/libgo/go/sync/atomic/atomic.c
@@ -25,6 +25,8 @@ int64_t SwapInt64 (int64_t *, int64_t)
int64_t
SwapInt64 (int64_t *addr, int64_t new)
{
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
return __atomic_exchange_n (addr, new, __ATOMIC_SEQ_CST);
}
@@ -45,6 +47,8 @@ uint64_t SwapUint64 (uint64_t *, uint64_t)
uint64_t
SwapUint64 (uint64_t *addr, uint64_t new)
{
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
return __atomic_exchange_n (addr, new, __ATOMIC_SEQ_CST);
}
@@ -85,6 +89,8 @@ _Bool CompareAndSwapInt64 (int64_t *, int64_t, int64_t)
_Bool
CompareAndSwapInt64 (int64_t *val, int64_t old, int64_t new)
{
+ if (((uintptr_t) val & 7) != 0)
+ val = NULL;
return __sync_bool_compare_and_swap (val, old, new);
}
@@ -105,6 +111,8 @@ _Bool CompareAndSwapUint64 (uint64_t *, uint64_t, uint64_t)
_Bool
CompareAndSwapUint64 (uint64_t *val, uint64_t old, uint64_t new)
{
+ if (((uintptr_t) val & 7) != 0)
+ val = NULL;
return __sync_bool_compare_and_swap (val, old, new);
}
@@ -155,6 +163,8 @@ int64_t AddInt64 (int64_t *, int64_t)
int64_t
AddInt64 (int64_t *val, int64_t delta)
{
+ if (((uintptr_t) val & 7) != 0)
+ val = NULL;
return __sync_add_and_fetch (val, delta);
}
@@ -165,6 +175,8 @@ uint64_t AddUint64 (uint64_t *, uint64_t)
uint64_t
AddUint64 (uint64_t *val, uint64_t delta)
{
+ if (((uintptr_t) val & 7) != 0)
+ val = NULL;
return __sync_add_and_fetch (val, delta);
}
@@ -202,6 +214,8 @@ LoadInt64 (int64_t *addr)
{
int64_t v;
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
v = *addr;
while (! __sync_bool_compare_and_swap (addr, v, v))
v = *addr;
@@ -232,6 +246,8 @@ LoadUint64 (uint64_t *addr)
{
uint64_t v;
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
v = *addr;
while (! __sync_bool_compare_and_swap (addr, v, v))
v = *addr;
@@ -291,6 +307,8 @@ StoreInt64 (int64_t *addr, int64_t val)
{
int64_t v;
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
v = *addr;
while (! __sync_bool_compare_and_swap (addr, v, val))
v = *addr;
@@ -319,6 +337,8 @@ StoreUint64 (uint64_t *addr, uint64_t val)
{
uint64_t v;
+ if (((uintptr_t) addr & 7) != 0)
+ addr = NULL;
v = *addr;
while (! __sync_bool_compare_and_swap (addr, v, val))
v = *addr;
diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go
index 6dae0fd8e7..6d0831c3f9 100644
--- a/libgo/go/sync/atomic/atomic_test.go
+++ b/libgo/go/sync/atomic/atomic_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -747,7 +747,7 @@ func TestStorePointer(t *testing.T) {
// (Is the function atomic?)
//
// For each function, we write a "hammer" function that repeatedly
-// uses the atomic operation to add 1 to a value. After running
+// uses the atomic operation to add 1 to a value. After running
// multiple hammers in parallel, check that we end with the correct
// total.
// Swap can't add 1, so it uses a different scheme.
@@ -1226,10 +1226,12 @@ func TestStoreLoadSeqCst32(t *testing.T) {
}
his := LoadInt32(&ack[he][i%3])
if (my != i && my != i-1) || (his != i && his != i-1) {
- t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ t.Errorf("invalid values: %d/%d (%d)", my, his, i)
+ break
}
if my != i && his != i {
- t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ break
}
StoreInt32(&ack[me][(i-1)%3], -1)
}
@@ -1269,10 +1271,12 @@ func TestStoreLoadSeqCst64(t *testing.T) {
}
his := LoadInt64(&ack[he][i%3])
if (my != i && my != i-1) || (his != i && his != i-1) {
- t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ t.Errorf("invalid values: %d/%d (%d)", my, his, i)
+ break
}
if my != i && his != i {
- t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ break
}
StoreInt64(&ack[me][(i-1)%3], -1)
}
@@ -1317,7 +1321,8 @@ func TestStoreLoadRelAcq32(t *testing.T) {
d1 := X.data1
d2 := X.data2
if d1 != i || d2 != float32(i) {
- t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i)
+ t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i)
+ break
}
}
}
@@ -1365,7 +1370,8 @@ func TestStoreLoadRelAcq64(t *testing.T) {
d1 := X.data1
d2 := X.data2
if d1 != i || d2 != float64(i) {
- t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i)
+ t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i)
+ break
}
}
}
@@ -1389,11 +1395,16 @@ func TestUnaligned64(t *testing.T) {
// Unaligned 64-bit atomics on 32-bit systems are
// a continual source of pain. Test that on 32-bit systems they crash
// instead of failing silently.
- if unsafe.Sizeof(int(0)) != 4 {
- t.Skip("test only runs on 32-bit systems")
- }
- t.Skip("skipping test for gccgo")
+ switch runtime.GOARCH {
+ default:
+ if unsafe.Sizeof(int(0)) != 4 {
+ t.Skip("test only runs on 32-bit systems")
+ }
+ case "amd64p32":
+ // amd64p32 can handle unaligned atomics.
+ t.Skipf("test not needed on %v", runtime.GOARCH)
+ }
x := make([]uint32, 4)
p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned
diff --git a/libgo/go/sync/atomic/doc.go b/libgo/go/sync/atomic/doc.go
index 10fb8c9177..302ff43070 100644
--- a/libgo/go/sync/atomic/doc.go
+++ b/libgo/go/sync/atomic/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/sync/atomic/value.go b/libgo/go/sync/atomic/value.go
index ab3aa11285..30abf72634 100644
--- a/libgo/go/sync/atomic/value.go
+++ b/libgo/go/sync/atomic/value.go
@@ -12,7 +12,11 @@ import (
// Values can be created as part of other data structures.
// The zero value for a Value returns nil from Load.
// Once Store has been called, a Value must not be copied.
+//
+// A Value must not be copied after first use.
type Value struct {
+ noCopy noCopy
+
v interface{}
}
@@ -83,3 +87,13 @@ func (v *Value) Store(x interface{}) {
// Disable/enable preemption, implemented in runtime.
func runtime_procPin()
func runtime_procUnpin()
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
diff --git a/libgo/go/sync/atomic/value_test.go b/libgo/go/sync/atomic/value_test.go
index 382dc6854d..fd90451dd8 100644
--- a/libgo/go/sync/atomic/value_test.go
+++ b/libgo/go/sync/atomic/value_test.go
@@ -86,6 +86,11 @@ func TestValueConcurrent(t *testing.T) {
{complex(0, 0), complex(1, 2), complex(3, 4), complex(5, 6)},
}
p := 4 * runtime.GOMAXPROCS(0)
+ N := int(1e5)
+ if testing.Short() {
+ p /= 2
+ N = 1e3
+ }
for _, test := range tests {
var v Value
done := make(chan bool)
@@ -93,7 +98,7 @@ func TestValueConcurrent(t *testing.T) {
go func() {
r := rand.New(rand.NewSource(rand.Int63()))
loop:
- for j := 0; j < 1e5; j++ {
+ for j := 0; j < N; j++ {
x := test[r.Intn(len(test))]
v.Store(x)
x = v.Load()
diff --git a/libgo/go/sync/cond.go b/libgo/go/sync/cond.go
index 0aefcda908..c070d9d84e 100644
--- a/libgo/go/sync/cond.go
+++ b/libgo/go/sync/cond.go
@@ -5,7 +5,6 @@
package sync
import (
- "internal/race"
"sync/atomic"
"unsafe"
)
@@ -21,11 +20,12 @@ 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
- sema syncSema
- waiters uint32 // number of waiters
+ notify notifyList
checker copyChecker
}
@@ -35,13 +35,13 @@ func NewCond(l Locker) *Cond {
}
// Wait atomically unlocks c.L and suspends execution
-// of the calling goroutine. After later resuming execution,
-// Wait locks c.L before returning. Unlike in other systems,
+// of the calling goroutine. After later resuming execution,
+// Wait locks c.L before returning. Unlike in other systems,
// Wait cannot return unless awoken by Broadcast or Signal.
//
// Because c.L is not locked when Wait first resumes, the caller
// typically cannot assume that the condition is true when
-// Wait returns. Instead, the caller should Wait in a loop:
+// Wait returns. Instead, the caller should Wait in a loop:
//
// c.L.Lock()
// for !condition() {
@@ -52,15 +52,9 @@ func NewCond(l Locker) *Cond {
//
func (c *Cond) Wait() {
c.checker.check()
- if race.Enabled {
- race.Disable()
- }
- atomic.AddUint32(&c.waiters, 1)
- if race.Enabled {
- race.Enable()
- }
+ t := runtime_notifyListAdd(&c.notify)
c.L.Unlock()
- runtime_Syncsemacquire(&c.sema)
+ runtime_notifyListWait(&c.notify, t)
c.L.Lock()
}
@@ -69,7 +63,8 @@ func (c *Cond) Wait() {
// It is allowed but not required for the caller to hold c.L
// during the call.
func (c *Cond) Signal() {
- c.signalImpl(false)
+ c.checker.check()
+ runtime_notifyListNotifyOne(&c.notify)
}
// Broadcast wakes all goroutines waiting on c.
@@ -77,34 +72,8 @@ func (c *Cond) Signal() {
// It is allowed but not required for the caller to hold c.L
// during the call.
func (c *Cond) Broadcast() {
- c.signalImpl(true)
-}
-
-func (c *Cond) signalImpl(all bool) {
c.checker.check()
- if race.Enabled {
- race.Disable()
- }
- for {
- old := atomic.LoadUint32(&c.waiters)
- if old == 0 {
- if race.Enabled {
- race.Enable()
- }
- return
- }
- new := old - 1
- if all {
- new = 0
- }
- if atomic.CompareAndSwapUint32(&c.waiters, old, new) {
- if race.Enabled {
- race.Enable()
- }
- runtime_Syncsemrelease(&c.sema, old-new)
- return
- }
- }
+ runtime_notifyListNotifyAll(&c.notify)
}
// copyChecker holds back pointer to itself to detect object copying.
@@ -117,3 +86,13 @@ func (c *copyChecker) check() {
panic("sync.Cond is copied")
}
}
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
diff --git a/libgo/go/sync/cond_test.go b/libgo/go/sync/cond_test.go
index 467c80621d..9019f8f102 100644
--- a/libgo/go/sync/cond_test.go
+++ b/libgo/go/sync/cond_test.go
@@ -8,6 +8,7 @@ import (
"runtime"
"testing"
+ "time"
)
func TestCondSignal(t *testing.T) {
@@ -136,7 +137,7 @@ func TestRace(t *testing.T) {
x = 1
c.Wait()
if x != 2 {
- t.Fatal("want 2")
+ t.Error("want 2")
}
x = 3
c.Signal()
@@ -164,7 +165,7 @@ func TestRace(t *testing.T) {
if x == 2 {
c.Wait()
if x != 3 {
- t.Fatal("want 3")
+ t.Error("want 3")
}
break
}
@@ -183,6 +184,64 @@ func TestRace(t *testing.T) {
<-done
}
+func TestCondSignalStealing(t *testing.T) {
+ for iters := 0; iters < 1000; iters++ {
+ var m Mutex
+ cond := NewCond(&m)
+
+ // Start a waiter.
+ ch := make(chan struct{})
+ go func() {
+ m.Lock()
+ ch <- struct{}{}
+ cond.Wait()
+ m.Unlock()
+
+ ch <- struct{}{}
+ }()
+
+ <-ch
+ m.Lock()
+ m.Unlock()
+
+ // We know that the waiter is in the cond.Wait() call because we
+ // synchronized with it, then acquired/released the mutex it was
+ // holding when we synchronized.
+ //
+ // Start two goroutines that will race: one will broadcast on
+ // the cond var, the other will wait on it.
+ //
+ // The new waiter may or may not get notified, but the first one
+ // has to be notified.
+ done := false
+ go func() {
+ cond.Broadcast()
+ }()
+
+ go func() {
+ m.Lock()
+ for !done {
+ cond.Wait()
+ }
+ m.Unlock()
+ }()
+
+ // Check that the first waiter does get signaled.
+ select {
+ case <-ch:
+ case <-time.After(2 * time.Second):
+ t.Fatalf("First waiter didn't get broadcast.")
+ }
+
+ // Release the second waiter in case it didn't get the
+ // broadcast.
+ m.Lock()
+ done = true
+ m.Unlock()
+ cond.Broadcast()
+ }
+}
+
func TestCondCopy(t *testing.T) {
defer func() {
err := recover()
diff --git a/libgo/go/sync/example_pool_test.go b/libgo/go/sync/example_pool_test.go
new file mode 100644
index 0000000000..8288d41e8c
--- /dev/null
+++ b/libgo/go/sync/example_pool_test.go
@@ -0,0 +1,45 @@
+// 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 sync_test
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "sync"
+ "time"
+)
+
+var bufPool = sync.Pool{
+ New: func() interface{} {
+ // The Pool's New function should generally only return pointer
+ // types, since a pointer can be put into the return interface
+ // value without an allocation:
+ return new(bytes.Buffer)
+ },
+}
+
+// timeNow is a fake version of time.Now for tests.
+func timeNow() time.Time {
+ return time.Unix(1136214245, 0)
+}
+
+func Log(w io.Writer, key, val string) {
+ b := bufPool.Get().(*bytes.Buffer)
+ b.Reset()
+ // Replace this with time.Now() in a real logger.
+ b.WriteString(timeNow().UTC().Format(time.RFC3339))
+ b.WriteByte(' ')
+ b.WriteString(key)
+ b.WriteByte('=')
+ b.WriteString(val)
+ w.Write(b.Bytes())
+ bufPool.Put(b)
+}
+
+func ExamplePool() {
+ Log(os.Stdout, "path", "/search?q=flowers")
+ // Output: 2006-01-02T15:04:05Z path=/search?q=flowers
+}
diff --git a/libgo/go/sync/export_test.go b/libgo/go/sync/export_test.go
index fa5983a2d1..6ed38dad89 100644
--- a/libgo/go/sync/export_test.go
+++ b/libgo/go/sync/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
index eb526144c5..8c9366f4fe 100644
--- a/libgo/go/sync/mutex.go
+++ b/libgo/go/sync/mutex.go
@@ -3,8 +3,8 @@
// license that can be found in the LICENSE file.
// Package sync provides basic synchronization primitives such as mutual
-// exclusion locks. Other than the Once and WaitGroup types, most are intended
-// for use by low-level library routines. Higher-level synchronization is
+// exclusion locks. Other than the Once and WaitGroup types, most are intended
+// for use by low-level library routines. Higher-level synchronization is
// better done via channels and communication.
//
// Values containing the types defined in this package should not be copied.
@@ -16,9 +16,13 @@ import (
"unsafe"
)
+func throw(string) // provided by runtime
+
// 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
@@ -72,7 +76,7 @@ func (m *Mutex) Lock() {
// The goroutine has been woken from sleep,
// so we need to reset the flag in either case.
if new&mutexWoken == 0 {
- panic("sync: inconsistent mutex state")
+ throw("sync: inconsistent mutex state")
}
new &^= mutexWoken
}
@@ -80,7 +84,7 @@ func (m *Mutex) Lock() {
if old&mutexLocked == 0 {
break
}
- runtime_Semacquire(&m.sema)
+ runtime_SemacquireMutex(&m.sema)
awoke = true
iter = 0
}
@@ -106,7 +110,7 @@ func (m *Mutex) Unlock() {
// Fast path: drop lock bit.
new := atomic.AddInt32(&m.state, -mutexLocked)
if (new+mutexLocked)&mutexLocked == 0 {
- panic("sync: unlock of unlocked mutex")
+ throw("sync: unlock of unlocked mutex")
}
old := new
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
index 91a4855cb1..88dbccf3ad 100644
--- a/libgo/go/sync/mutex_test.go
+++ b/libgo/go/sync/mutex_test.go
@@ -7,7 +7,12 @@
package sync_test
import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ "os/exec"
"runtime"
+ "strings"
. "sync"
"testing"
)
@@ -61,6 +66,10 @@ func HammerMutex(m *Mutex, loops int, cdone chan bool) {
}
func TestMutex(t *testing.T) {
+ if n := runtime.SetMutexProfileFraction(1); n != 0 {
+ t.Logf("got mutexrate %d expected 0", n)
+ }
+ defer runtime.SetMutexProfileFraction(0)
m := new(Mutex)
c := make(chan bool)
for i := 0; i < 10; i++ {
@@ -71,17 +80,98 @@ func TestMutex(t *testing.T) {
}
}
-func TestMutexPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked mutex did not panic")
+var misuseTests = []struct {
+ name string
+ f func()
+}{
+ {
+ "Mutex.Unlock",
+ func() {
+ var mu Mutex
+ mu.Unlock()
+ },
+ },
+ {
+ "Mutex.Unlock2",
+ func() {
+ var mu Mutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock",
+ func() {
+ var mu RWMutex
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock2",
+ func() {
+ var mu RWMutex
+ mu.RLock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock3",
+ func() {
+ var mu RWMutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock",
+ func() {
+ var mu RWMutex
+ mu.RUnlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock2",
+ func() {
+ var mu RWMutex
+ mu.Lock()
+ mu.RUnlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock3",
+ func() {
+ var mu RWMutex
+ mu.RLock()
+ mu.RUnlock()
+ mu.RUnlock()
+ },
+ },
+}
+
+func init() {
+ if len(os.Args) == 3 && os.Args[1] == "TESTMISUSE" {
+ for _, test := range misuseTests {
+ if test.name == os.Args[2] {
+ test.f()
+ fmt.Printf("test completed\n")
+ os.Exit(0)
+ }
}
- }()
+ fmt.Printf("unknown test\n")
+ os.Exit(0)
+ }
+}
- var mu Mutex
- mu.Lock()
- mu.Unlock()
- mu.Unlock()
+func TestMutexMisuse(t *testing.T) {
+ testenv.MustHaveExec(t)
+ for _, test := range misuseTests {
+ out, err := exec.Command(os.Args[0], "TESTMISUSE", test.name).CombinedOutput()
+ if err == nil || !strings.Contains(string(out), "unlocked") {
+ t.Errorf("%s: did not find failure with message about unlocked lock: %s\n%s\n", test.name, err, out)
+ }
+ }
}
func BenchmarkMutexUncontended(b *testing.B) {
diff --git a/libgo/go/sync/once.go b/libgo/go/sync/once.go
index 10b42fddc2..d8ef952ea5 100644
--- a/libgo/go/sync/once.go
+++ b/libgo/go/sync/once.go
@@ -18,10 +18,10 @@ type Once struct {
// first time for this instance of Once. In other words, given
// var once Once
// if once.Do(f) is called multiple times, only the first call will invoke f,
-// even if f has a different value in each invocation. A new instance of
+// even if f has a different value in each invocation. A new instance of
// Once is required for each function to execute.
//
-// Do is intended for initialization that must be run exactly once. Since f
+// Do is intended for initialization that must be run exactly once. Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
// config.once.Do(func() { config.init(filename) })
diff --git a/libgo/go/sync/pool.go b/libgo/go/sync/pool.go
index 381af0bead..0acdbde096 100644
--- a/libgo/go/sync/pool.go
+++ b/libgo/go/sync/pool.go
@@ -40,7 +40,10 @@ import (
// that scenario. It is more efficient to have such objects implement their own
// free list.
//
+// A Pool must not be copied after first use.
type Pool struct {
+ noCopy noCopy
+
local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
localSize uintptr // size of the local array
@@ -58,29 +61,49 @@ type poolLocal struct {
pad [128]byte // Prevents false sharing.
}
+// from runtime
+func fastrand() uint32
+
+var poolRaceHash [128]uint64
+
+// poolRaceAddr returns an address to use as the synchronization point
+// for race detector logic. We don't use the actual pointer stored in x
+// directly, for fear of conflicting with other synchronization on that address.
+// Instead, we hash the pointer to get an index into poolRaceHash.
+// See discussion on golang.org/cl/31589.
+func poolRaceAddr(x interface{}) unsafe.Pointer {
+ ptr := uintptr((*[2]unsafe.Pointer)(unsafe.Pointer(&x))[1])
+ h := uint32((uint64(uint32(ptr)) * 0x85ebca6b) >> 16)
+ return unsafe.Pointer(&poolRaceHash[h%uint32(len(poolRaceHash))])
+}
+
// Put adds x to the pool.
func (p *Pool) Put(x interface{}) {
- if race.Enabled {
- // Under race detector the Pool degenerates into no-op.
- // It's conforming, simple and does not introduce excessive
- // happens-before edges between unrelated goroutines.
- return
- }
if x == nil {
return
}
+ if race.Enabled {
+ if fastrand()%4 == 0 {
+ // Randomly drop x on floor.
+ return
+ }
+ race.ReleaseMerge(poolRaceAddr(x))
+ race.Disable()
+ }
l := p.pin()
if l.private == nil {
l.private = x
x = nil
}
runtime_procUnpin()
- if x == nil {
- return
+ if x != nil {
+ l.Lock()
+ l.shared = append(l.shared, x)
+ l.Unlock()
+ }
+ if race.Enabled {
+ race.Enable()
}
- l.Lock()
- l.shared = append(l.shared, x)
- l.Unlock()
}
// Get selects an arbitrary item from the Pool, removes it from the
@@ -93,29 +116,34 @@ func (p *Pool) Put(x interface{}) {
// the result of calling p.New.
func (p *Pool) Get() interface{} {
if race.Enabled {
- if p.New != nil {
- return p.New()
- }
- return nil
+ race.Disable()
}
l := p.pin()
x := l.private
l.private = nil
runtime_procUnpin()
- if x != nil {
- return x
+ if x == nil {
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ }
+ l.Unlock()
+ if x == nil {
+ x = p.getSlow()
+ }
}
- l.Lock()
- last := len(l.shared) - 1
- if last >= 0 {
- x = l.shared[last]
- l.shared = l.shared[:last]
+ if race.Enabled {
+ race.Enable()
+ if x != nil {
+ race.Acquire(poolRaceAddr(x))
+ }
}
- l.Unlock()
- if x != nil {
- return x
+ if x == nil && p.New != nil {
+ x = p.New()
}
- return p.getSlow()
+ return x
}
func (p *Pool) getSlow() (x interface{}) {
@@ -137,10 +165,6 @@ func (p *Pool) getSlow() (x interface{}) {
}
l.Unlock()
}
-
- if x == nil && p.New != nil {
- x = p.New()
- }
return x
}
@@ -149,7 +173,7 @@ func (p *Pool) getSlow() (x interface{}) {
func (p *Pool) pin() *poolLocal {
pid := runtime_procPin()
// In pinSlow we store to localSize and then to local, here we load in opposite order.
- // Since we've disabled preemption, GC can not happen in between.
+ // Since we've disabled preemption, GC cannot happen in between.
// Thus here we must observe local at least as large localSize.
// We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
s := atomic.LoadUintptr(&p.localSize) // load-acquire
@@ -179,8 +203,8 @@ func (p *Pool) pinSlow() *poolLocal {
// If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
size := runtime.GOMAXPROCS(0)
local := make([]poolLocal, size)
- atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release
- atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release
+ atomic.StorePointer(&p.local, unsafe.Pointer(&local[0])) // store-release
+ atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release
return &local[pid]
}
diff --git a/libgo/go/sync/pool_test.go b/libgo/go/sync/pool_test.go
index 051bb17533..f92e181a6b 100644
--- a/libgo/go/sync/pool_test.go
+++ b/libgo/go/sync/pool_test.go
@@ -128,7 +128,8 @@ func TestPoolStress(t *testing.T) {
p.Put(v)
v = p.Get()
if v != nil && v.(int) != 0 {
- t.Fatalf("expect 0, got %v", v)
+ t.Errorf("expect 0, got %v", v)
+ break
}
}
done <- true
diff --git a/libgo/go/sync/runtime.go b/libgo/go/sync/runtime.go
index c66d2deb4c..4d22ce6b0d 100644
--- a/libgo/go/sync/runtime.go
+++ b/libgo/go/sync/runtime.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -13,30 +13,42 @@ import "unsafe"
// library and should not be used directly.
func runtime_Semacquire(s *uint32)
+// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
+func runtime_SemacquireMutex(*uint32)
+
// Semrelease atomically increments *s and notifies a waiting goroutine
// if one is blocked in Semacquire.
// It is intended as a simple wakeup primitive for use by the synchronization
// library and should not be used directly.
func runtime_Semrelease(s *uint32)
-// Approximation of syncSema in runtime/sema.go.
-type syncSema struct {
- lock uintptr
- head unsafe.Pointer
- tail unsafe.Pointer
+// Approximation of notifyList in runtime/sema.go. Size and alignment must
+// agree.
+type notifyList struct {
+ wait uint32
+ notify uint32
+ lock uintptr
+ head unsafe.Pointer
+ tail unsafe.Pointer
}
-// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s.
-func runtime_Syncsemacquire(s *syncSema)
+// See runtime/sema.go for documentation.
+func runtime_notifyListAdd(l *notifyList) uint32
+
+// See runtime/sema.go for documentation.
+func runtime_notifyListWait(l *notifyList, t uint32)
+
+// See runtime/sema.go for documentation.
+func runtime_notifyListNotifyAll(l *notifyList)
-// Syncsemrelease waits for n pairing Syncsemacquire on the same semaphore s.
-func runtime_Syncsemrelease(s *syncSema, n uint32)
+// See runtime/sema.go for documentation.
+func runtime_notifyListNotifyOne(l *notifyList)
-// Ensure that sync and runtime agree on size of syncSema.
-func runtime_Syncsemcheck(size uintptr)
+// Ensure that sync and runtime agree on size of notifyList.
+func runtime_notifyListCheck(size uintptr)
func init() {
- var s syncSema
- runtime_Syncsemcheck(unsafe.Sizeof(s))
+ var n notifyList
+ runtime_notifyListCheck(unsafe.Sizeof(n))
}
// Active spinning runtime support.
diff --git a/libgo/go/sync/runtime_sema_test.go b/libgo/go/sync/runtime_sema_test.go
index 5b7dd3df3f..a2382f4655 100644
--- a/libgo/go/sync/runtime_sema_test.go
+++ b/libgo/go/sync/runtime_sema_test.go
@@ -25,6 +25,9 @@ func BenchmarkSemaUncontended(b *testing.B) {
}
func benchmarkSema(b *testing.B, block, work bool) {
+ if b.N == 0 {
+ return
+ }
sem := uint32(0)
if block {
done := make(chan bool)
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
index d438c93c88..71064eeeba 100644
--- a/libgo/go/sync/rwmutex.go
+++ b/libgo/go/sync/rwmutex.go
@@ -11,11 +11,17 @@ import (
)
// An RWMutex is a reader/writer mutual exclusion lock.
-// The lock can be held by an arbitrary number of readers
-// or a single writer.
-// RWMutexes can be created as part of other
-// structures; the zero value for a RWMutex is
-// an unlocked mutex.
+// The lock can be held by an arbitrary number of readers or a single writer.
+// 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.
+//
+// If a goroutine holds a RWMutex for reading, it must not expect this or any
+// other goroutine to be able to also take the read lock until the first read
+// lock is released. In particular, this prohibits recursive read locking.
+// This is to ensure that the lock eventually becomes available;
+// a blocked Lock call excludes new readers from acquiring the lock.
type RWMutex struct {
w Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
@@ -55,7 +61,7 @@ func (rw *RWMutex) RUnlock() {
if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
race.Enable()
- panic("sync: RUnlock of unlocked RWMutex")
+ throw("sync: RUnlock of unlocked RWMutex")
}
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
@@ -71,9 +77,6 @@ func (rw *RWMutex) RUnlock() {
// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
-// To ensure that the lock eventually becomes available,
-// a blocked Lock call excludes new readers from acquiring
-// the lock.
func (rw *RWMutex) Lock() {
if race.Enabled {
_ = rw.w.state
@@ -94,11 +97,11 @@ func (rw *RWMutex) Lock() {
}
}
-// Unlock unlocks rw for writing. It is a run-time error if rw is
+// Unlock unlocks rw for writing. It is a run-time error if rw is
// not locked for writing on entry to Unlock.
//
// As with Mutexes, a locked RWMutex is not associated with a particular
-// goroutine. One goroutine may RLock (Lock) an RWMutex and then
+// goroutine. One goroutine may RLock (Lock) an RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {
if race.Enabled {
@@ -112,7 +115,7 @@ func (rw *RWMutex) Unlock() {
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
if r >= rwmutexMaxReaders {
race.Enable()
- panic("sync: Unlock of unlocked RWMutex")
+ throw("sync: Unlock of unlocked RWMutex")
}
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
index f625bc3a58..0436f97239 100644
--- a/libgo/go/sync/rwmutex_test.go
+++ b/libgo/go/sync/rwmutex_test.go
@@ -155,48 +155,6 @@ func TestRLocker(t *testing.T) {
}
}
-func TestUnlockPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.Unlock()
-}
-
-func TestUnlockPanic2(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.RLock()
- mu.Unlock()
-}
-
-func TestRUnlockPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("read unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.RUnlock()
-}
-
-func TestRUnlockPanic2(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("read unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.Lock()
- mu.RUnlock()
-}
-
func BenchmarkRWMutexUncontended(b *testing.B) {
type PaddedRWMutex struct {
RWMutex
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index c77fec306c..b386e1fec2 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -12,10 +12,14 @@ import (
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
-// goroutines to wait for. Then each of the goroutines
-// runs and calls Done when finished. At the same time,
+// 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
diff --git a/libgo/go/syscall/bpf_bsd.go b/libgo/go/syscall/bpf_bsd.go
index cc6c1e77c5..8b587559ed 100644
--- a/libgo/go/syscall/bpf_bsd.go
+++ b/libgo/go/syscall/bpf_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -12,14 +12,17 @@ import (
"unsafe"
)
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfStmt(code, k int) *BpfInsn {
return &BpfInsn{Code: uint16(code), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfJump(code, k, jt, jf int) *BpfInsn {
return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfBuflen(fd int) (int, error) {
var l int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
@@ -29,6 +32,7 @@ func BpfBuflen(fd int) (int, error) {
return l, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfBuflen(fd, l int) (int, error) {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
if err != 0 {
@@ -37,6 +41,7 @@ func SetBpfBuflen(fd, l int) (int, error) {
return l, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfDatalink(fd int) (int, error) {
var t int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
@@ -46,6 +51,7 @@ func BpfDatalink(fd int) (int, error) {
return t, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfDatalink(fd, t int) (int, error) {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
if err != 0 {
@@ -54,6 +60,7 @@ func SetBpfDatalink(fd, t int) (int, error) {
return t, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfPromisc(fd, m int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
if err != 0 {
@@ -62,6 +69,7 @@ func SetBpfPromisc(fd, m int) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func FlushBpf(fd int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
if err != 0 {
@@ -75,6 +83,7 @@ type ivalue struct {
value int16
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfInterface(fd int, name string) (string, error) {
var iv ivalue
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
@@ -84,6 +93,7 @@ func BpfInterface(fd int, name string) (string, error) {
return name, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfInterface(fd int, name string) error {
var iv ivalue
copy(iv.name[:], []byte(name))
@@ -94,6 +104,7 @@ func SetBpfInterface(fd int, name string) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfTimeout(fd int) (*Timeval, error) {
var tv Timeval
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
@@ -103,6 +114,7 @@ func BpfTimeout(fd int) (*Timeval, error) {
return &tv, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfTimeout(fd int, tv *Timeval) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
if err != 0 {
@@ -111,6 +123,7 @@ func SetBpfTimeout(fd int, tv *Timeval) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfStats(fd int) (*BpfStat, error) {
var s BpfStat
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
@@ -120,6 +133,7 @@ func BpfStats(fd int) (*BpfStat, error) {
return &s, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfImmediate(fd, m int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
if err != 0 {
@@ -128,6 +142,7 @@ func SetBpfImmediate(fd, m int) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpf(fd int, i []BpfInsn) error {
var p BpfProgram
p.Len = uint32(len(i))
@@ -139,6 +154,7 @@ func SetBpf(fd int, i []BpfInsn) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func CheckBpfVersion(fd int) error {
var v BpfVersion
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
@@ -151,6 +167,7 @@ func CheckBpfVersion(fd int) error {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfHeadercmpl(fd int) (int, error) {
var f int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
@@ -160,6 +177,7 @@ func BpfHeadercmpl(fd int) (int, error) {
return f, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfHeadercmpl(fd, f int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
if err != 0 {
diff --git a/libgo/go/syscall/clone_linux.c b/libgo/go/syscall/clone_linux.c
new file mode 100644
index 0000000000..30753e6269
--- /dev/null
+++ b/libgo/go/syscall/clone_linux.c
@@ -0,0 +1,102 @@
+/* clone_linux.c -- consistent wrapper around Linux clone syscall
+
+ 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 <errno.h>
+#include <sys/syscall.h>
+
+#include "runtime.h"
+
+long rawClone (unsigned long flags, void *child_stack, void *ptid,
+ void *ctid, void *regs)
+ __asm__ (GOSYM_PREFIX "syscall.rawClone")
+ __attribute__ ((no_split_stack));
+
+long
+rawClone (unsigned long flags, void *child_stack, void *ptid, void *ctid, void *regs)
+{
+#if defined(__arc__) || defined(__aarch64__) || defined(__arm__) || defined(__mips__) || defined(__hppa__) || defined(__powerpc__) || defined(__score__) || defined(__i386__) || defined(__xtensa__)
+ // CLONE_BACKWARDS
+ return syscall(__NR_clone, flags, child_stack, ptid, regs, ctid);
+#elif defined(__s390__) || defined(__cris__)
+ // CLONE_BACKWARDS2
+ return syscall(__NR_clone, child_stack, flags, ptid, ctid, regs);
+#elif defined(__microblaze__)
+ // CLONE_BACKWARDS3
+ return syscall(__NR_clone, flags, child_stack, 0, ptid, ctid, regs);
+#elif defined(__sparc__)
+
+ /* SPARC has a unique return value convention:
+
+ Parent --> %o0 == child's pid, %o1 == 0
+ Child --> %o0 == parent's pid, %o1 == 1
+
+ Translate this to look like a normal clone. */
+
+# if defined(__arch64__)
+
+# define SYSCALL_STRING \
+ "ta 0x6d;" \
+ "bcc,pt %%xcc, 1f;" \
+ " mov 0, %%g1;" \
+ "sub %%g0, %%o0, %%o0;" \
+ "mov 1, %%g1;" \
+ "1:"
+
+# define SYSCALL_CLOBBERS \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \
+ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \
+ "cc", "memory"
+
+# else /* __arch64__ */
+
+# define SYSCALL_STRING \
+ "ta 0x10;" \
+ "bcc 1f;" \
+ " mov 0, %%g1;" \
+ "sub %%g0, %%o0, %%o0;" \
+ "mov 1, %%g1;" \
+ "1:"
+
+# define SYSCALL_CLOBBERS \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "cc", "memory"
+
+# endif /* __arch64__ */
+
+ register long o0 __asm__ ("o0") = (long)flags;
+ register long o1 __asm__ ("o1") = (long)child_stack;
+ register long o2 __asm__ ("o2") = (long)ptid;
+ register long o3 __asm__ ("o3") = (long)ctid;
+ register long o4 __asm__ ("o4") = (long)regs;
+ register long g1 __asm__ ("g1") = __NR_clone;
+
+ __asm __volatile (SYSCALL_STRING :
+ "=r" (g1), "=r" (o0), "=r" (o1) :
+ "0" (g1), "1" (o0), "2" (o1),
+ "r" (o2), "r" (o3), "r" (o4) :
+ SYSCALL_CLOBBERS);
+
+ if (__builtin_expect(g1 != 0, 0))
+ {
+ errno = -o0;
+ o0 = -1L;
+ }
+ else
+ o0 &= (o1 - 1);
+
+ return o0;
+
+#else
+ return syscall(__NR_clone, flags, child_stack, ptid, ctid, regs);
+#endif
+}
diff --git a/libgo/go/syscall/const_plan9.go b/libgo/go/syscall/const_plan9.go
index ba26f123de..063d5dfd7c 100644
--- a/libgo/go/syscall/const_plan9.go
+++ b/libgo/go/syscall/const_plan9.go
@@ -12,6 +12,17 @@ const (
O_EXCL = 0x1000
)
+// Bind flags
+const (
+ MORDER = 0x0003 // mask for bits defining order of mounting
+ MREPL = 0x0000 // mount replaces object
+ MBEFORE = 0x0001 // mount goes before others in union directory
+ MAFTER = 0x0002 // mount goes after others in union directory
+ MCREATE = 0x0004 // permit creation in mounted directory
+ MCACHE = 0x0010 // cache some data
+ MMASK = 0x0017 // all bits on
+)
+
// Rfork flags
const (
RFNAMEG = 1 << 0
diff --git a/libgo/go/syscall/creds_test.go b/libgo/go/syscall/creds_test.go
index b4a14ff4dd..7c6ab1de1d 100644
--- a/libgo/go/syscall/creds_test.go
+++ b/libgo/go/syscall/creds_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/syscall/dir_plan9.go b/libgo/go/syscall/dir_plan9.go
index 697bf5499c..4ed052de76 100644
--- a/libgo/go/syscall/dir_plan9.go
+++ b/libgo/go/syscall/dir_plan9.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Plan 9 directory marshalling. See intro(5).
+// Plan 9 directory marshaling. See intro(5).
package syscall
@@ -184,6 +184,7 @@ func gbit8(b []byte) (uint8, []byte) {
}
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
+//go:nosplit
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
diff --git a/libgo/go/syscall/dirent.go b/libgo/go/syscall/dirent.go
new file mode 100644
index 0000000000..4db2d4355b
--- /dev/null
+++ b/libgo/go/syscall/dirent.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package syscall
+
+import "unsafe"
+
+// readInt returns the size-bytes unsigned integer in native byte order at offset off.
+func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
+ if len(b) < int(off+size) {
+ return 0, false
+ }
+ if isBigEndian {
+ return readIntBE(b[off:], size), true
+ }
+ return readIntLE(b[off:], size), true
+}
+
+func readIntBE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[1]) | uint64(b[0])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
+ case 8:
+ _ = 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
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+func readIntLE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8
+ case 4:
+ _ = b[3] // 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
+ case 8:
+ _ = 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
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number of
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ reclen, ok := direntReclen(buf)
+ if !ok || reclen > uint64(len(buf)) {
+ return origlen, count, names
+ }
+ rec := buf[:reclen]
+ buf = buf[reclen:]
+ ino, ok := direntIno(rec)
+ if !ok {
+ break
+ }
+ if ino == 0 { // File absent in directory.
+ continue
+ }
+ const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
+ namlen, ok := direntNamlen(rec)
+ if !ok || namoff+namlen > uint64(len(rec)) {
+ break
+ }
+ name := rec[namoff : namoff+namlen]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ max--
+ count++
+ names = append(names, string(name))
+ }
+ return origlen - len(buf), count, names
+}
diff --git a/libgo/go/syscall/endian_big.go b/libgo/go/syscall/endian_big.go
new file mode 100644
index 0000000000..b96594ec28
--- /dev/null
+++ b/libgo/go/syscall/endian_big.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build ppc64 s390x mips mips64 armbe arm64be m68k ppc mipso32 mipsn32 mipso64 mipsn64 mips64p32 s390 sparc sparc64
+
+package syscall
+
+const isBigEndian = true
diff --git a/libgo/go/syscall/endian_little.go b/libgo/go/syscall/endian_little.go
new file mode 100644
index 0000000000..b6c9ed0f9f
--- /dev/null
+++ b/libgo/go/syscall/endian_little.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build 386 amd64 amd64p32 arm arm64 ppc64le mips64le mipsle alpha ia64 mips64p32le
+
+package syscall
+
+const isBigEndian = false
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
index cbf7f41092..9a8a837e7d 100644
--- a/libgo/go/syscall/env_plan9.go
+++ b/libgo/go/syscall/env_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
index b5ded9c763..5bf3336ce5 100644
--- a/libgo/go/syscall/env_unix.go
+++ b/libgo/go/syscall/env_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go
index 1cb475428d..1606b424ca 100644
--- a/libgo/go/syscall/env_windows.go
+++ b/libgo/go/syscall/env_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -60,7 +60,7 @@ func Clearenv() {
// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
for j := 1; j < len(s); j++ {
if s[j] == '=' {
- Setenv(s[0:j], "")
+ Unsetenv(s[0:j])
break
}
}
diff --git a/libgo/go/syscall/errors_plan9.go b/libgo/go/syscall/errors_plan9.go
index d7634c995e..6952562c69 100644
--- a/libgo/go/syscall/errors_plan9.go
+++ b/libgo/go/syscall/errors_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
diff --git a/libgo/go/syscall/errstr.go b/libgo/go/syscall/errstr.go
index aa656ca7cb..25b0063e76 100644
--- a/libgo/go/syscall/errstr.go
+++ b/libgo/go/syscall/errstr.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !linux
+
package syscall
//sysnb strerror_r(errnum int, buf []byte) (err Errno)
diff --git a/libgo/go/syscall/errstr_linux.go b/libgo/go/syscall/errstr_linux.go
index d10476d3cb..7156b790da 100644
--- a/libgo/go/syscall/errstr_linux.go
+++ b/libgo/go/syscall/errstr_linux.go
@@ -1,9 +1,12 @@
-// errstr_rtems.go -- RTEMS specific error strings.
+// errstr_linux.go -- GNU/Linux specific error strings.
// 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.
+// We use this rather than errstr.go because on GNU/Linux sterror_r
+// returns a pointer to the error message, and may not use buf at all.
+
package syscall
import "unsafe"
diff --git a/libgo/go/syscall/errstr_nor.go b/libgo/go/syscall/errstr_nor.go
deleted file mode 100644
index 796561adda..0000000000
--- a/libgo/go/syscall/errstr_nor.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// errstr.go -- Error strings when there is no strerror_r.
-
-// 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 syscall
-
-import (
- "sync"
- "unsafe"
-)
-
-//sysnb strerror(errnum int) (buf *byte)
-//strerror(errnum _C_int) *byte
-
-var errstr_lock sync.Mutex
-
-func Errstr(errno int) string {
- errstr_lock.Lock()
-
- bp := strerror(errno)
- b := (*[1000]byte)(unsafe.Pointer(bp))
- i := 0
- for b[i] != 0 {
- i++
- }
-
- // Lowercase first letter: Bad -> bad, but STREAM -> STREAM.
- var s string
- if i > 1 && 'A' <= b[0] && b[0] <= 'Z' && 'a' <= b[1] && b[1] <= 'z' {
- c := b[0] + 'a' - 'A'
- s = string(c) + string(b[1:i])
- } else {
- s = string(b[:i])
- }
-
- errstr_lock.Unlock()
-
- return s
-}
diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go
index 75126730f5..af025e4c04 100644
--- a/libgo/go/syscall/exec_bsd.go
+++ b/libgo/go/syscall/exec_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd netbsd openbsd solaris
package syscall
@@ -31,7 +31,7 @@ func runtime_AfterFork()
// If a dup or exec fails, write the errno error to pipe.
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
// In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork. This means
+// they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments.
// For the same reason compiler does not race instrument it.
// The calls to RawSyscall are okay because they are assembly
@@ -181,6 +181,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
for i = 0; i < len(fd); i++ {
if fd[i] >= 0 && fd[i] < int(i) {
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
err1 = raw_dup2(fd[i], nextfd)
if err1 != 0 {
goto childerror
@@ -188,9 +191,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
fd[i] = nextfd
nextfd++
- if nextfd == pipe { // don't stomp on pipe
- nextfd++
- }
}
}
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 6987bc1f4e..8d6467a872 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -7,7 +7,6 @@
package syscall
import (
- "runtime"
"unsafe"
)
@@ -23,20 +22,21 @@ type SysProcIDMap struct {
}
type SysProcAttr struct {
- Chroot string // Chroot.
- Credential *Credential // Credential.
- Ptrace bool // Enable tracing.
- Setsid bool // Create session.
- Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
- Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
- Noctty bool // Detach fd 0 from controlling terminal
- Ctty int // Controlling TTY fd
- Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
- 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)
- UidMappings []SysProcIDMap // User ID mappings for user namespaces.
- GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
+ Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
+ Noctty bool // Detach fd 0 from controlling terminal
+ Ctty int // Controlling TTY fd
+ Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+ 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)
+ Unshareflags 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.
// If false, then setgroups syscall will be disabled for the child process.
// This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
@@ -48,11 +48,14 @@ type SysProcAttr struct {
func runtime_BeforeFork()
func runtime_AfterFork()
+// Implemented in clone_linux.c
+func rawClone(flags _C_ulong, child_stack *byte, ptid *Pid_t, ctid *Pid_t, regs unsafe.Pointer) _C_long
+
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
// If a dup or exec fails, write the errno error to pipe.
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
// In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork. This means
+// they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments.
// For the same reason compiler does not race instrument it.
// The calls to RawSyscall are okay because they are assembly
@@ -63,6 +66,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// declarations require heap allocation (e.g., err1).
var (
r1 uintptr
+ r2 _C_long
err1 Errno
err2 Errno
nextfd int
@@ -97,20 +101,16 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// About to call fork.
// No more allocation or calls of non-assembly functions.
runtime_BeforeFork()
- if runtime.GOARCH == "s390x" || runtime.GOARCH == "s390" {
- r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0)
- } else {
- r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
- }
- if err1 != 0 {
+ r2 = rawClone(_C_ulong(uintptr(SIGCHLD)|sys.Cloneflags), nil, nil, nil, unsafe.Pointer(nil))
+ if r2 < 0 {
runtime_AfterFork()
- return 0, err1
+ return 0, GetErrno()
}
- if r1 != 0 {
+ if r2 != 0 {
// parent; return PID
runtime_AfterFork()
- pid = int(r1)
+ pid = int(r2)
if sys.UidMappings != nil || sys.GidMappings != nil {
Close(p[0])
@@ -192,21 +192,35 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
+ // Unshare
+ if sys.Unshareflags != 0 {
+ _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := len(cred.Groups)
+ var groups unsafe.Pointer
if ngroups > 0 {
- groups := unsafe.Pointer(&cred.Groups[0])
+ groups = unsafe.Pointer(&cred.Groups[0])
+ }
+ // Don't call setgroups in case of user namespace, gid mappings
+ // and disabled setgroups, because otherwise unprivileged user namespace
+ // will fail with any non-empty SysProcAttr.Credential.
+ if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) {
err1 = raw_setgroups(ngroups, groups)
if err1 != 0 {
goto childerror
}
}
- _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+ _, _, err1 = RawSyscall(sys_SETGID, uintptr(cred.Gid), 0, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+ _, _, err1 = RawSyscall(sys_SETUID, uintptr(cred.Uid), 0, 0)
if err1 != 0 {
goto childerror
}
@@ -253,6 +267,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
for i = 0; i < len(fd); i++ {
if fd[i] >= 0 && fd[i] < int(i) {
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
err1 = raw_dup2(fd[i], nextfd)
if err1 != 0 {
goto childerror
@@ -260,9 +277,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
fd[i] = nextfd
nextfd++
- if nextfd == pipe { // don't stomp on pipe
- nextfd++
- }
}
}
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
index 6d31941184..7a4b571760 100644
--- a/libgo/go/syscall/exec_linux_test.go
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -26,11 +26,14 @@ func isChrooted(t *testing.T) bool {
return root.Sys().(*syscall.Stat_t).Ino != 2
}
-func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+func checkUserNS(t *testing.T) {
if _, err := os.Stat("/proc/self/ns/user"); err != nil {
if os.IsNotExist(err) {
t.Skip("kernel doesn't support user namespaces")
}
+ if os.IsPermission(err) {
+ t.Skip("unable to test user namespaces due to permissions")
+ }
t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
}
if isChrooted(t) {
@@ -53,6 +56,10 @@ func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
}
+}
+
+func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+ checkUserNS(t)
cmd := exec.Command("whoami")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUSER,
@@ -122,3 +129,127 @@ 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")
+ }
+
+ path := "/proc/net/dev"
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support proc filesystem")
+ }
+ if os.IsPermission(err) {
+ t.Skip("unable to test proc filesystem due to permissions")
+ }
+ t.Fatal(err)
+ }
+ if _, err := os.Stat("/proc/self/ns/net"); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support net namespace")
+ }
+ t.Fatal(err)
+ }
+
+ orig, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ origLines := strings.Split(strings.TrimSpace(string(orig)), "\n")
+
+ cmd := exec.Command("cat", path)
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Unshareflags: 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) >= len(origLines) {
+ t.Fatalf("Got %d lines of output, want <%d", len(lines), len(origLines))
+ }
+}
+
+func TestGroupCleanup(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("we need root for credential")
+ }
+ cmd := exec.Command("id")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Credential: &syscall.Credential{
+ Uid: 0,
+ Gid: 0,
+ },
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+ strOut := strings.TrimSpace(string(out))
+ expected := "uid=0(root) gid=0(root) groups=0(root)"
+ // Just check prefix because some distros reportedly output a
+ // context parameter; see https://golang.org/issue/16224.
+ if !strings.HasPrefix(strOut, expected) {
+ t.Errorf("id command output: %q, expected prefix: %q", strOut, expected)
+ }
+}
+
+func TestGroupCleanupUserNamespace(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("we need root for credential")
+ }
+ checkUserNS(t)
+ cmd := exec.Command("id")
+ uid, gid := os.Getuid(), os.Getgid()
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Cloneflags: syscall.CLONE_NEWUSER,
+ Credential: &syscall.Credential{
+ Uid: uint32(uid),
+ Gid: uint32(gid),
+ },
+ UidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: uid, Size: 1},
+ },
+ GidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: gid, Size: 1},
+ },
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+ strOut := strings.TrimSpace(string(out))
+
+ // Strings we've seen in the wild.
+ expected := []string{
+ "uid=0(root) gid=0(root) groups=0(root)",
+ "uid=0(root) gid=0(root) groups=0(root),65534(nobody)",
+ "uid=0(root) gid=0(root) groups=0(root),65534(nogroup)",
+ "uid=0(root) gid=0(root) groups=0(root),65534",
+ }
+ for _, e := range expected {
+ if strOut == e {
+ return
+ }
+ }
+ t.Errorf("id command output: %q, expected one of %q", strOut, expected)
+}
diff --git a/libgo/go/syscall/exec_solaris_test.go b/libgo/go/syscall/exec_solaris_test.go
deleted file mode 100644
index 6b8f1ad383..0000000000
--- a/libgo/go/syscall/exec_solaris_test.go
+++ /dev/null
@@ -1,37 +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 solaris
-
-package syscall
-
-import "unsafe"
-
-//go:cgo_import_dynamic libc_Getpgid getpgid "libc.so"
-//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.so"
-
-//go:linkname libc_Getpgid libc_Getpgid
-//go:linkname libc_Getpgrp libc_Getpgrp
-
-var (
- libc_Getpgid,
- libc_Getpgrp libcFunc
-)
-
-func Getpgid(pid int) (pgid int, err error) {
- r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0)
- pgid = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-func Getpgrp() (pgrp int) {
- r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0)
- pgrp = int(r0)
- return
-}
-
-var Ioctl = ioctl
diff --git a/libgo/go/syscall/exec_stubs.go b/libgo/go/syscall/exec_stubs.go
index 35bb17487b..e95b4158e1 100644
--- a/libgo/go/syscall/exec_stubs.go
+++ b/libgo/go/syscall/exec_stubs.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build rtems
+
// Stubs for fork, exec and wait.
package syscall
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index 3b772e6ddb..c04005cdd6 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_unix.go
@@ -68,31 +68,31 @@ import (
// 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
+// 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
+// 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.
+// 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
+// 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
+// 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
+// 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
@@ -102,13 +102,13 @@ import (
// 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.
+// 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 (GNU/Linux).
+// 4) Open. Can block. Use O_CLOEXEC if available (GNU/Linux).
// Otherwise, live with the race.
-// 5) Dup. Does not block. Use the ForkLock.
+// 5) Dup. Does not block. Use the ForkLock.
// On GNU/Linux, could use fcntl F_DUPFD_CLOEXEC
// instead of the ForkLock, but only for dup(fd, -1).
@@ -154,7 +154,7 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
if nonblocking {
flag |= O_NONBLOCK
} else {
- flag &= ^O_NONBLOCK
+ flag &^= O_NONBLOCK
}
_, err = fcntl(fd, F_SETFL, flag)
return err
@@ -292,7 +292,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
return pid, 0, err
}
-// Ordinary exec.
+// Exec invokes the execve(2) system call.
func Exec(argv0 string, argv []string, envv []string) (err error) {
argv0p, err := BytePtrFromString(argv0)
if err != nil {
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 5a01843d2b..cafce1eff6 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -209,8 +209,6 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return FullPath(d + "\\" + p)
}
}
- // we shouldn't be here
- return "", EINVAL
}
type ProcAttr struct {
diff --git a/libgo/go/syscall/export_test.go b/libgo/go/syscall/export_test.go
index c9774622c8..55c09e667e 100644
--- a/libgo/go/syscall/export_test.go
+++ b/libgo/go/syscall/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/syscall/export_unix_test.go b/libgo/go/syscall/export_unix_test.go
index b41fe2f86b..47ec544339 100644
--- a/libgo/go/syscall/export_unix_test.go
+++ b/libgo/go/syscall/export_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall
diff --git a/libgo/go/syscall/libcall_bsd.go b/libgo/go/syscall/libcall_bsd.go
index fe6a3e3a27..9a4b2d6582 100644
--- a/libgo/go/syscall/libcall_bsd.go
+++ b/libgo/go/syscall/libcall_bsd.go
@@ -2,6 +2,8 @@
// 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 solaris
+
// BSD library calls.
package syscall
diff --git a/libgo/go/syscall/libcall_irix.go b/libgo/go/syscall/libcall_irix.go
index 50863fadf1..9b6cdcca2c 100644
--- a/libgo/go/syscall/libcall_irix.go
+++ b/libgo/go/syscall/libcall_irix.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build irix
+
package syscall
//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno)
diff --git a/libgo/go/syscall/libcall_linux.go b/libgo/go/syscall/libcall_linux.go
index ff81f54710..b58b2ddd6e 100644
--- a/libgo/go/syscall/libcall_linux.go
+++ b/libgo/go/syscall/libcall_linux.go
@@ -251,27 +251,6 @@ func ReadDirent(fd int, buf []byte) (n int, err error) {
return Getdents(fd, buf)
}
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- count = 0
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- buf = buf[dirent.Reclen:]
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes[:])])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
-}
-
//sys Getxattr(path string, attr string, dest []byte) (sz int, err error)
//getxattr(path *byte, attr *byte, buf *byte, count Size_t) Ssize_t
diff --git a/libgo/go/syscall/libcall_linux_ustat.go b/libgo/go/syscall/libcall_linux_ustat.go
index f7f3406a6a..261f086f47 100644
--- a/libgo/go/syscall/libcall_linux_ustat.go
+++ b/libgo/go/syscall/libcall_linux_ustat.go
@@ -4,6 +4,7 @@
// GNU/Linux library ustat call.
// This is not supported on some kernels, such as arm64.
+// +build !arm64
package syscall
diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go
index d3580a1bc0..76941c89b6 100644
--- a/libgo/go/syscall/libcall_posix.go
+++ b/libgo/go/syscall/libcall_posix.go
@@ -226,9 +226,6 @@ func FDZero(set *FdSet) {
//sysnb Getgid() (gid int)
//getgid() Gid_t
-//sysnb Getpagesize() (pagesize int)
-//getpagesize() _C_int
-
//sysnb Getpgid(pid int) (pgid int, err error)
//getpgid(pid Pid_t) Pid_t
@@ -377,21 +374,12 @@ func Settimeofday(tv *Timeval) (err error) {
//sys Munlockall() (err error)
//munlockall() _C_int
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = Timespec_sec_t(nsec / 1e9)
- ts.Nsec = Timespec_nsec_t(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: Timespec_sec_t(sec), Nsec: Timespec_nsec_t(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = Timeval_sec_t(nsec / 1e9)
- tv.Usec = Timeval_usec_t(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: Timeval_sec_t(sec), Usec: Timeval_usec_t(usec)}
}
//sysnb Tcgetattr(fd int, p *Termios) (err error)
@@ -399,3 +387,17 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//sys Tcsetattr(fd int, actions int, p *Termios) (err error)
//tcsetattr(fd _C_int, actions _C_int, p *Termios) _C_int
+
+//sys sysconf(name int) (ret int64, err error)
+//sysconf(name _C_int) _C_long
+
+func Sysconf(name int) (ret int64, err error) {
+ // If an option is not available, sysconf returns -1 without
+ // changing errno. Detect this case and return err == nil.
+ SetErrno(0)
+ ret, err = sysconf(name)
+ if err == Errno(0) {
+ err = nil
+ }
+ return ret, err
+}
diff --git a/libgo/go/syscall/libcall_posix_largefile.go b/libgo/go/syscall/libcall_posix_largefile.go
index c05d3d2a5e..1f437b41fb 100644
--- a/libgo/go/syscall/libcall_posix_largefile.go
+++ b/libgo/go/syscall/libcall_posix_largefile.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux solaris,386 solaris,sparc
+
// POSIX library calls on systems which use the largefile interface.
package syscall
diff --git a/libgo/go/syscall/libcall_posix_regfile.go b/libgo/go/syscall/libcall_posix_regfile.go
index 7de5800939..d106a7b6f6 100644
--- a/libgo/go/syscall/libcall_posix_regfile.go
+++ b/libgo/go/syscall/libcall_posix_regfile.go
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !linux
+// +build !solaris !386
+// +build !solaris !sparc
+
// POSIX library calls on systems which do not use the largefile
// interface.
diff --git a/libgo/go/syscall/libcall_posix_utimesnano.go b/libgo/go/syscall/libcall_posix_utimesnano.go
index e0751f5467..5d9d02eba3 100644
--- a/libgo/go/syscall/libcall_posix_utimesnano.go
+++ b/libgo/go/syscall/libcall_posix_utimesnano.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin dragonfly freebsd openbsd netbsd solaris
+
// General POSIX version of UtimesNano.
package syscall
diff --git a/libgo/go/syscall/libcall_uname.go b/libgo/go/syscall/libcall_uname.go
index 1e164ef1a5..165b3251b6 100644
--- a/libgo/go/syscall/libcall_uname.go
+++ b/libgo/go/syscall/libcall_uname.go
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Build on all systems other than solaris/386.
+// 32-bit Solaris 2/x86 needs _nuname, handled in libcall_solaris_386.go.
+// +build !386 !solaris
+
package syscall
//sysnb Uname(buf *Utsname) (err error)
diff --git a/libgo/go/syscall/libcall_waitpid.go b/libgo/go/syscall/libcall_waitpid.go
deleted file mode 100644
index b0e04b5bab..0000000000
--- a/libgo/go/syscall/libcall_waitpid.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// For systems with the waitpid library call.
-
-package syscall
-
-//sys waitpid(pid Pid_t, status *_C_int, options int) (wpid Pid_t, err error)
-//waitpid(pid Pid_t, status *_C_int, options _C_int) Pid_t
-
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
- var status _C_int
- r, err := waitpid(Pid_t(pid), &status, options)
- wpid = int(r)
- if wstatus != nil {
- *wstatus = WaitStatus(status)
- }
- return
-}
diff --git a/libgo/go/syscall/lsf_linux.go b/libgo/go/syscall/lsf_linux.go
index 48ba191c6d..16b702a984 100644
--- a/libgo/go/syscall/lsf_linux.go
+++ b/libgo/go/syscall/lsf_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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 {
@@ -56,7 +60,7 @@ func SetLsfPromisc(name string, m bool) error {
if m {
ifl.flags |= uint16(IFF_PROMISC)
} else {
- ifl.flags &= ^uint16(IFF_PROMISC)
+ ifl.flags &^= uint16(IFF_PROMISC)
}
_, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
if ep != 0 {
@@ -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), Socklen_t(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), Socklen_t(unsafe.Sizeof(dummy)))
diff --git a/libgo/go/syscall/msan.go b/libgo/go/syscall/msan.go
deleted file mode 100644
index edd8d1ebd5..0000000000
--- a/libgo/go/syscall/msan.go
+++ /dev/null
@@ -1,22 +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 msan
-
-package syscall
-
-import (
- "runtime"
- "unsafe"
-)
-
-const msanenabled = true
-
-func msanRead(addr unsafe.Pointer, len int) {
- runtime.MSanRead(addr, len)
-}
-
-func msanWrite(addr unsafe.Pointer, len int) {
- runtime.MSanWrite(addr, len)
-}
diff --git a/libgo/go/syscall/msan0.go b/libgo/go/syscall/msan0.go
index 7617494e86..ff10be9d25 100644
--- a/libgo/go/syscall/msan0.go
+++ b/libgo/go/syscall/msan0.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go
index 1b73dce827..1cda8c7704 100644
--- a/libgo/go/syscall/netlink_linux.go
+++ b/libgo/go/syscall/netlink_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -129,10 +129,11 @@ func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) {
func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) {
h := (*NlMsghdr)(unsafe.Pointer(&b[0]))
- if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) {
+ l := nlmAlignOf(int(h.Len))
+ if int(h.Len) < NLMSG_HDRLEN || l > len(b) {
return nil, nil, 0, EINVAL
}
- return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
+ return h, b[NLMSG_HDRLEN:], l, nil
}
// NetlinkRouteAttr represents a netlink route attribute.
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index c635a1385e..b364eeaba5 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -138,7 +138,7 @@ func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
//
// - The kernel form appends leading bytes to the prefix field
// to make the <length, prefix> tuple to be conformed with
- // the routing messeage boundary
+ // the routing message boundary
l := int(rsaAlignOf(int(b[0])))
if len(b) < l {
return nil, EINVAL
@@ -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/libgo/go/syscall/route_bsd_test.go b/libgo/go/syscall/route_bsd_test.go
deleted file mode 100644
index 74d11f9f0a..0000000000
--- a/libgo/go/syscall/route_bsd_test.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd netbsd openbsd
-
-package syscall_test
-
-import (
- "fmt"
- "net"
- "os"
- "syscall"
- "testing"
- "time"
-)
-
-func TestRouteRIB(t *testing.T) {
- for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
- for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
- var err error
- var b []byte
- // The VM allocator wrapper functions can
- // return ENOMEM easily.
- for i := 0; i < 3; i++ {
- b, err = syscall.RouteRIB(facility, param)
- if err != nil {
- time.Sleep(5 * time.Millisecond)
- continue
- }
- break
- }
- if err != nil {
- t.Error(facility, param, err)
- continue
- }
- msgs, err := syscall.ParseRoutingMessage(b)
- if err != nil {
- t.Error(facility, param, err)
- continue
- }
- var ipv4loopback, ipv6loopback bool
- for _, m := range msgs {
- flags, err := parseRoutingMessageHeader(m)
- if err != nil {
- t.Error(err)
- continue
- }
- sas, err := parseRoutingSockaddrs(m)
- if err != nil {
- t.Error(err)
- continue
- }
- if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
- sa := sas[syscall.RTAX_DST]
- if sa == nil {
- sa = sas[syscall.RTAX_IFA]
- }
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- if net.IP(sa.Addr[:]).IsLoopback() {
- ipv4loopback = true
- }
- case *syscall.SockaddrInet6:
- if net.IP(sa.Addr[:]).IsLoopback() {
- ipv6loopback = true
- }
- }
- }
- t.Log(facility, param, flags, sockaddrs(sas))
- }
- if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
- t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
- continue
- }
- }
- }
-}
-
-func TestRouteMonitor(t *testing.T) {
- if testing.Short() || os.Getuid() != 0 {
- t.Skip("must be root")
- }
-
- s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
- if err != nil {
- t.Fatal(err)
- }
- defer syscall.Close(s)
-
- tmo := time.After(30 * time.Second)
- go func() {
- b := make([]byte, os.Getpagesize())
- for {
- n, err := syscall.Read(s, b)
- if err != nil {
- return
- }
- msgs, err := syscall.ParseRoutingMessage(b[:n])
- if err != nil {
- t.Error(err)
- return
- }
- for _, m := range msgs {
- flags, err := parseRoutingMessageHeader(m)
- if err != nil {
- t.Error(err)
- continue
- }
- sas, err := parseRoutingSockaddrs(m)
- if err != nil {
- t.Error(err)
- continue
- }
- t.Log(flags, sockaddrs(sas))
- }
- }
- }()
- <-tmo
-}
-
-var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
- // with link-layer address
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
- 0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
- 0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- },
- },
- // without link-layer address
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
- 0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
- },
- },
- // no data
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
- },
- },
-}
-
-func TestParseInterfaceMessage(t *testing.T) {
- for i, tt := range parseInterfaceMessageTests {
- if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
- t.Errorf("#%d: %v", i, err)
- }
- }
-}
-
-type addrFamily byte
-
-func (f addrFamily) String() string {
- switch f {
- case syscall.AF_UNSPEC:
- return "unspec"
- case syscall.AF_LINK:
- return "link"
- case syscall.AF_INET:
- return "inet4"
- case syscall.AF_INET6:
- return "inet6"
- default:
- return fmt.Sprintf("unknown %d", f)
- }
-}
-
-type addrFlags uint32
-
-var addrFlagNames = [...]string{
- "dst",
- "gateway",
- "netmask",
- "genmask",
- "ifp",
- "ifa",
- "author",
- "brd",
- "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
- "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
- "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
-}
-
-func (f addrFlags) String() string {
- var s string
- for i, name := range addrFlagNames {
- if f&(1<<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
-}
diff --git a/libgo/go/syscall/route_darwin.go b/libgo/go/syscall/route_darwin.go
index 89bca12f3e..b0636ed07c 100644
--- a/libgo/go/syscall/route_darwin.go
+++ b/libgo/go/syscall/route_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -26,6 +26,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMulticastAddrMessage struct {
Header IfmaMsghdr2
Data []byte
diff --git a/libgo/go/syscall/route_dragonfly.go b/libgo/go/syscall/route_dragonfly.go
index 5226f7f2e4..b562400be8 100644
--- a/libgo/go/syscall/route_dragonfly.go
+++ b/libgo/go/syscall/route_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -31,6 +31,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
// InterfaceAnnounceMessage represents a routing message containing
// network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
@@ -39,6 +41,8 @@ func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil,
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMulticastAddrMessage struct {
Header IfmaMsghdr
Data []byte
diff --git a/libgo/go/syscall/route_freebsd.go b/libgo/go/syscall/route_freebsd.go
index 0e18103855..2c2de7474a 100644
--- a/libgo/go/syscall/route_freebsd.go
+++ b/libgo/go/syscall/route_freebsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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/libgo/go/syscall/route_ifma_test.go b/libgo/go/syscall/route_ifma_test.go
deleted file mode 100644
index af2b67dc24..0000000000
--- a/libgo/go/syscall/route_ifma_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd
-
-package syscall_test
-
-import (
- "fmt"
- "syscall"
-)
-
-func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- errno := syscall.Errno(uintptr(m.Header.Errno))
- if errno != 0 {
- return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
- }
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMulticastAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
-
-func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMulticastAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go
index d605ffa30f..a10c8b65d9 100644
--- a/libgo/go/syscall/route_netbsd.go
+++ b/libgo/go/syscall/route_netbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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/libgo/go/syscall/route_noifma_test.go b/libgo/go/syscall/route_noifma_test.go
deleted file mode 100644
index 19d5d8ebbf..0000000000
--- a/libgo/go/syscall/route_noifma_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build netbsd openbsd
-
-package syscall_test
-
-import (
- "fmt"
- "syscall"
-)
-
-func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- errno := syscall.Errno(uintptr(m.Header.Errno))
- if errno != 0 {
- return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
- }
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
-
-func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
diff --git a/libgo/go/syscall/route_openbsd.go b/libgo/go/syscall/route_openbsd.go
index 7804a08910..fe173adda8 100644
--- a/libgo/go/syscall/route_openbsd.go
+++ b/libgo/go/syscall/route_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -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/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go
index 1625b07ae4..e2a9dc5f9d 100644
--- a/libgo/go/syscall/security_windows.go
+++ b/libgo/go/syscall/security_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/syscall/setuidgid_32_linux.go b/libgo/go/syscall/setuidgid_32_linux.go
new file mode 100644
index 0000000000..182f5d26a9
--- /dev/null
+++ b/libgo/go/syscall/setuidgid_32_linux.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build 386 arm
+
+package syscall
+
+const (
+ sys_SETGID = SYS_SETGID32
+ sys_SETUID = SYS_SETUID32
+)
diff --git a/libgo/go/syscall/setuidgid_linux.go b/libgo/go/syscall/setuidgid_linux.go
new file mode 100644
index 0000000000..bf40d2d882
--- /dev/null
+++ b/libgo/go/syscall/setuidgid_linux.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build !386,!arm
+
+package syscall
+
+const (
+ sys_SETGID = SYS_SETGID
+ sys_SETUID = SYS_SETUID
+)
diff --git a/libgo/go/syscall/sleep_rtems.go b/libgo/go/syscall/sleep_rtems.go
index 9d72203e8e..480c775565 100644
--- a/libgo/go/syscall/sleep_rtems.go
+++ b/libgo/go/syscall/sleep_rtems.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build rtems
+
package syscall
func Sleep(nsec int64) (err error) {
diff --git a/libgo/go/syscall/sleep_select.go b/libgo/go/syscall/sleep_select.go
index 533f554da0..bb1694fcee 100644
--- a/libgo/go/syscall/sleep_select.go
+++ b/libgo/go/syscall/sleep_select.go
@@ -4,10 +4,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !rtems
+
package syscall
func Sleep(nsec int64) (err error) {
- tv := NsecToTimeval(nsec);
- _, err = Select(0, nil, nil, nil, &tv);
- return err;
+ tv := NsecToTimeval(nsec)
+ _, err = Select(0, nil, nil, nil, &tv)
+ return err
}
diff --git a/libgo/go/syscall/sockcmsg_linux.go b/libgo/go/syscall/sockcmsg_linux.go
index a2e26a1f47..4cb9075ba8 100644
--- a/libgo/go/syscall/sockcmsg_linux.go
+++ b/libgo/go/syscall/sockcmsg_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -31,6 +31,9 @@ func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
if m.Header.Type != SCM_CREDENTIALS {
return nil, EINVAL
}
+ if uintptr(len(m.Data)) < unsafe.Sizeof(Ucred{}) {
+ return nil, EINVAL
+ }
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
return &ucred, nil
}
diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go
index bf32c987a9..016169929b 100644
--- a/libgo/go/syscall/sockcmsg_unix.go
+++ b/libgo/go/syscall/sockcmsg_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -16,9 +16,10 @@ import (
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := int(sizeofPtr)
- // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
- // still require 32-bit aligned access to network subsystem.
- if darwin64Bit || dragonfly64Bit {
+ // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
+ // Solaris kernels still require 32-bit aligned access to
+ // network subsystem.
+ if darwin64Bit || dragonfly64Bit || solaris64Bit {
salign = 4
}
// NOTE: Solaris always uses 32-bit alignment,
@@ -70,7 +71,7 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
- if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
+ if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
return nil, nil, EINVAL
}
return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
diff --git a/libgo/go/syscall/socket_bsd.go b/libgo/go/syscall/socket_bsd.go
index c8da102221..0f0962729e 100644
--- a/libgo/go/syscall/socket_bsd.go
+++ b/libgo/go/syscall/socket_bsd.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin dragonfly freebsd openbsd netbsd
+
package syscall
const SizeofSockaddrInet4 = 16
diff --git a/libgo/go/syscall/socket_irix.go b/libgo/go/syscall/socket_irix.go
index bcd1781d57..dc50fdd24f 100644
--- a/libgo/go/syscall/socket_irix.go
+++ b/libgo/go/syscall/socket_irix.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build irix
+
package syscall
const SizeofSockaddrInet4 = 16
diff --git a/libgo/go/syscall/socket_linux_ppc64x_type.go b/libgo/go/syscall/socket_linux_ppc64x_type.go
index 8a707ce49d..96afdeb85f 100644
--- a/libgo/go/syscall/socket_linux_ppc64x_type.go
+++ b/libgo/go/syscall/socket_linux_ppc64x_type.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux,ppc64 linux,ppc64le
+
package syscall
// Type needed on ppc64le & ppc64
diff --git a/libgo/go/syscall/socket_linux_type.go b/libgo/go/syscall/socket_linux_type.go
index 45b8c6ec1d..190c11cc27 100644
--- a/libgo/go/syscall/socket_linux_type.go
+++ b/libgo/go/syscall/socket_linux_type.go
@@ -4,6 +4,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux
+// +build !ppc64
+// +build !ppc64le
+
package syscall
// Type needed if not on ppc64le or ppc64
diff --git a/libgo/go/syscall/socket_posix.go b/libgo/go/syscall/socket_posix.go
index fda7dc65e4..fe835d3c43 100644
--- a/libgo/go/syscall/socket_posix.go
+++ b/libgo/go/syscall/socket_posix.go
@@ -4,6 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !solaris
+
package syscall
//sys bind(fd int, sa *RawSockaddrAny, len Socklen_t) (err error)
diff --git a/libgo/go/syscall/socket_xnet.go b/libgo/go/syscall/socket_xnet.go
index 3c5b6b4180..c0699c44a8 100644
--- a/libgo/go/syscall/socket_xnet.go
+++ b/libgo/go/syscall/socket_xnet.go
@@ -5,6 +5,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build solaris
+
package syscall
//sys bind(fd int, sa *RawSockaddrAny, len Socklen_t) (err error)
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index 7d42ad5dce..91dfa9a049 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -3,10 +3,10 @@
// license that can be found in the LICENSE file.
// Package syscall contains an interface to the low-level operating system
-// primitives. The details vary depending on the underlying system, and
+// primitives. The details vary depending on the underlying system, and
// by default, godoc will display the syscall documentation for the current
-// system. If you want godoc to display syscall documentation for another
-// system, set $GOOS and $GOARCH to the desired system. For example, if
+// system. If you want godoc to display syscall documentation for another
+// system, set $GOOS and $GOARCH to the desired system. For example, if
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
// to freebsd and $GOARCH to arm.
// The primary use of syscall is inside other packages that provide a more
@@ -28,6 +28,8 @@ package syscall
import "unsafe"
+//go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
+
// StringByteSlice converts a string to a NUL-terminated []byte,
// If s contains a NUL byte this function panics instead of
// returning an error.
@@ -97,6 +99,10 @@ func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
+// Getpagesize is provided by the runtime.
+
+func Getpagesize() int
+
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
// This was needed until Go 1.6 to call syscall.Syscall correctly.
diff --git a/libgo/go/syscall/syscall_darwin.go b/libgo/go/syscall/syscall_darwin.go
new file mode 100644
index 0000000000..2847d2b8e3
--- /dev/null
+++ b/libgo/go/syscall/syscall_darwin.go
@@ -0,0 +1,19 @@
+// Copyright 2009,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 syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_dragonfly.go b/libgo/go/syscall/syscall_dragonfly.go
new file mode 100644
index 0000000000..c2fc67f44a
--- /dev/null
+++ b/libgo/go/syscall/syscall_dragonfly.go
@@ -0,0 +1,23 @@
+// Copyright 2009,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 syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ namlen, ok := direntNamlen(buf)
+ if !ok {
+ return 0, false
+ }
+ return (16 + namlen + 1 + 7) & ^uint64(7), true
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_freebsd.go b/libgo/go/syscall/syscall_freebsd.go
new file mode 100644
index 0000000000..c67550a011
--- /dev/null
+++ b/libgo/go/syscall/syscall_freebsd.go
@@ -0,0 +1,19 @@
+// Copyright 2009,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 syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_linux.go b/libgo/go/syscall/syscall_linux.go
new file mode 100644
index 0000000000..338a9717f0
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux.go
@@ -0,0 +1,23 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
diff --git a/libgo/go/syscall/syscall_linux_mipsx.go b/libgo/go/syscall/syscall_linux_mipsx.go
new file mode 100644
index 0000000000..af319ac345
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_mipsx.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips mipsle
+
+package syscall
+
+func (r *PtraceRegs) PC() uint64 { return uint64(r.Regs[64]) }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Regs[64] = uint32(pc) }
diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go
index 4cabf6c9c9..2c4d953561 100644
--- a/libgo/go/syscall/syscall_linux_test.go
+++ b/libgo/go/syscall/syscall_linux_test.go
@@ -138,3 +138,31 @@ func deathSignalChild() {
fmt.Println("not ok")
os.Exit(1)
}
+
+func TestParseNetlinkMessage(t *testing.T) {
+ for i, b := range [][]byte{
+ {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3,
+ 0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0,
+ 1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86,
+ 53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10,
+ },
+ {106, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 3, 8, 0, 3,
+ 0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0,
+ 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0,
+ 0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10,
+ },
+ {102, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 1, 8, 0, 3, 0,
+ 8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127,
+ 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8,
+ 10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10,
+ },
+ } {
+ m, err := syscall.ParseNetlinkMessage(b)
+ if err != syscall.EINVAL {
+ t.Errorf("#%d: got %v; want EINVAL", i, err)
+ }
+ if m != nil {
+ t.Errorf("#%d: got %v; want nil", i, m)
+ }
+ }
+}
diff --git a/libgo/go/syscall/syscall_netbsd.go b/libgo/go/syscall/syscall_netbsd.go
new file mode 100644
index 0000000000..c67550a011
--- /dev/null
+++ b/libgo/go/syscall/syscall_netbsd.go
@@ -0,0 +1,19 @@
+// Copyright 2009,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 syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_openbsd.go b/libgo/go/syscall/syscall_openbsd.go
new file mode 100644
index 0000000000..c67550a011
--- /dev/null
+++ b/libgo/go/syscall/syscall_openbsd.go
@@ -0,0 +1,19 @@
+// Copyright 2009,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 syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_solaris.go b/libgo/go/syscall/syscall_solaris.go
index c1919171b7..673ba8223f 100644
--- a/libgo/go/syscall/syscall_solaris.go
+++ b/libgo/go/syscall/syscall_solaris.go
@@ -4,6 +4,8 @@
package syscall
+import "unsafe"
+
func (ts *Timestruc) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec)
}
@@ -11,3 +13,36 @@ func (ts *Timestruc) Unix() (sec int64, nsec int64) {
func (ts *Timestruc) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
}
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
+
+//sysnb getexecname() (execname unsafe.Pointer, err error)
+//getexecname() *byte
+
+func Getexecname() (path string, err error) {
+ ptr, err := getexecname()
+ if err != nil {
+ return "", err
+ }
+ bytes := (*[1 << 29]byte)(ptr)[:]
+ for i, b := range bytes {
+ if b == 0 {
+ return string(bytes[:i]), nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/syscall/syscall_stubs.go b/libgo/go/syscall/syscall_stubs.go
index 76c05cb546..00288ee5ea 100644
--- a/libgo/go/syscall/syscall_stubs.go
+++ b/libgo/go/syscall/syscall_stubs.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build rtems
+
// These are stubs.
package syscall
diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go
index 846c4873d2..c3fffda2df 100644
--- a/libgo/go/syscall/syscall_test.go
+++ b/libgo/go/syscall/syscall_test.go
@@ -6,6 +6,9 @@ package syscall_test
import (
"fmt"
+ "internal/testenv"
+ "os"
+ "runtime"
"syscall"
"testing"
)
@@ -45,3 +48,28 @@ func TestItoa(t *testing.T) {
t.Fatalf("itoa(%d) = %s, want %s", i, s, f)
}
}
+
+// Check that permuting child process fds doesn't interfere with
+// reporting of fork/exec status. See Issue 14979.
+func TestExecErrPermutedFds(t *testing.T) {
+ testenv.MustHaveExec(t)
+
+ attr := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stderr, os.Stdout}}
+ _, err := os.StartProcess("/", []string{"/"}, attr)
+ if err == nil {
+ t.Fatalf("StartProcess of invalid program returned err = nil")
+ }
+}
+
+func TestGettimeofday(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("not implemented on nacl")
+ }
+ tv := &syscall.Timeval{}
+ if err := syscall.Gettimeofday(tv); err != nil {
+ t.Fatal(err)
+ }
+ if tv.Sec == 0 && tv.Usec == 0 {
+ t.Fatal("Sec and Usec both zero")
+ }
+}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index c47050d2ad..ddf7303df1 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -29,6 +29,7 @@ const (
darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ solaris64Bit = runtime.GOOS == "solaris" && sizeofPtr == 8
)
// Do a system call. We look at the size of uintptr to see how to pass
diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go
index c7b4560b76..2f25d18bca 100644
--- a/libgo/go/syscall/syscall_unix_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -10,6 +10,7 @@ import (
"flag"
"fmt"
"internal/testenv"
+ "io"
"io/ioutil"
"net"
"os"
@@ -124,15 +125,6 @@ func TestFcntlFlock(t *testing.T) {
// "-test.run=^TestPassFD$" and an environment variable used to signal
// that the test should become the child process instead.
func TestPassFD(t *testing.T) {
- switch runtime.GOOS {
- case "dragonfly":
- // TODO(jsing): Figure out why sendmsg is returning EINVAL.
- t.Skip("skipping test on dragonfly")
- case "solaris":
- // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
- t.Skip("skipping test on solaris, see issue 7402")
- }
-
testenv.MustHaveExec(t)
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
@@ -244,7 +236,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 +336,7 @@ func TestRlimit(t *testing.T) {
}
func TestSeekFailure(t *testing.T) {
- _, err := syscall.Seek(-1, 0, 0)
+ _, err := syscall.Seek(-1, 0, io.SeekStart)
if err == nil {
t.Fatalf("Seek(-1, 0, 0) did not fail")
}
diff --git a/libgo/go/syscall/timestruct.go b/libgo/go/syscall/timestruct.go
new file mode 100644
index 0000000000..49c3383b4f
--- /dev/null
+++ b/libgo/go/syscall/timestruct.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package syscall
+
+// TimespecToNsec converts a Timespec value into a number of
+// nanoseconds since the Unix epoch.
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+// NsecToTimespec takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timespec value.
+func NsecToTimespec(nsec int64) Timespec {
+ sec := nsec / 1e9
+ nsec = nsec % 1e9
+ if nsec < 0 {
+ nsec += 1e9
+ sec--
+ }
+ return setTimespec(sec, nsec)
+}
+
+// TimevalToNsec converts a Timeval value into a number of nanoseconds
+// since the Unix epoch.
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+// NsecToTimeval takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timeval value.
+func NsecToTimeval(nsec int64) Timeval {
+ nsec += 999 // round up to microsecond
+ usec := nsec % 1e9 / 1e3
+ sec := nsec / 1e9
+ if usec < 0 {
+ usec += 1e6
+ sec--
+ }
+ return setTimeval(sec, usec)
+}
diff --git a/libgo/go/testing/allocs.go b/libgo/go/testing/allocs.go
index 9ec47bd460..1eeb2d4802 100644
--- a/libgo/go/testing/allocs.go
+++ b/libgo/go/testing/allocs.go
@@ -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.
@@ -12,7 +12,7 @@ import (
// Although the return value has type float64, it will always be an integral value.
//
// To compute the number of allocations, the function will first be run once as
-// a warm-up. The average number of allocations over the specified number of
+// a warm-up. The average number of allocations over the specified number of
// runs will then be measured and returned.
//
// AllocsPerRun sets GOMAXPROCS to 1 during its measurement and will restore
diff --git a/libgo/go/testing/allocs_test.go b/libgo/go/testing/allocs_test.go
index ec17daa2b1..5b346aaf83 100644
--- a/libgo/go/testing/allocs_test.go
+++ b/libgo/go/testing/allocs_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index 85178c2f86..bcebb418c4 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -7,6 +7,7 @@ package testing
import (
"flag"
"fmt"
+ "internal/race"
"os"
"runtime"
"sync"
@@ -14,8 +15,8 @@ import (
"time"
)
-var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
-var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark")
+var matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`")
+var benchTime = flag.Duration("test.benchtime", 1*time.Second, "run each benchmark for duration `d`")
var benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks")
// Global lock to ensure only one benchmark runs at a time.
@@ -46,11 +47,14 @@ type InternalBenchmark struct {
// affecting benchmark results.
type B struct {
common
+ context *benchContext
N int
previousN int // number of iterations in the previous run
previousDuration time.Duration // total duration of the previous run
- benchmark InternalBenchmark
+ benchFunc func(b *B)
+ benchTime time.Duration
bytes int64
+ missingBytes bool // one of the subbenchmarks does not have bytes set.
timerOn bool
showAllocResult bool
result BenchmarkResult
@@ -63,7 +67,7 @@ type B struct {
netBytes uint64
}
-// StartTimer starts timing a test. This function is called automatically
+// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (b *B) StartTimer() {
@@ -76,7 +80,7 @@ func (b *B) StartTimer() {
}
}
-// StopTimer stops timing a test. This can be used to pause the timer
+// StopTimer stops timing a test. This can be used to pause the timer
// while performing complex initialization that you don't
// want to measure.
func (b *B) StopTimer() {
@@ -128,14 +132,19 @@ func (b *B) runN(n int) {
// Try to get a comparable environment for each run
// by clearing garbage from previous runs.
runtime.GC()
+ b.raceErrors = -race.Errors()
b.N = n
b.parallelism = 1
b.ResetTimer()
b.StartTimer()
- b.benchmark.F(b)
+ b.benchFunc(b)
b.StopTimer()
b.previousN = n
b.previousDuration = b.duration
+ b.raceErrors += race.Errors()
+ if b.raceErrors > 0 {
+ b.Errorf("race detected during execution of benchmark")
+ }
}
func min(x, y int) int {
@@ -185,38 +194,83 @@ func roundUp(n int) int {
}
}
-// run times the benchmark function in a separate goroutine.
+// run1 runs the first iteration of benchFunc. It returns whether more
+// iterations of this benchmarks should be run.
+func (b *B) run1() bool {
+ if ctx := b.context; ctx != nil {
+ // Extend maxLen, if needed.
+ if n := len(b.name) + ctx.extLen + 1; n > ctx.maxLen {
+ ctx.maxLen = n + 8 // Add additional slack to avoid too many jumps in size.
+ }
+ }
+ go func() {
+ // Signal that we're done whether we return normally
+ // or by FailNow's runtime.Goexit.
+ defer func() {
+ b.signal <- true
+ }()
+
+ b.runN(1)
+ }()
+ <-b.signal
+ if b.failed {
+ fmt.Fprintf(b.w, "--- FAIL: %s\n%s", b.name, b.output)
+ return false
+ }
+ // Only print the output if we know we are not going to proceed.
+ // Otherwise it is printed in processBench.
+ if atomic.LoadInt32(&b.hasSub) != 0 || b.finished {
+ tag := "BENCH"
+ if b.skipped {
+ tag = "SKIP"
+ }
+ if b.chatty && (len(b.output) > 0 || b.finished) {
+ b.trimOutput()
+ fmt.Fprintf(b.w, "--- %s: %s\n%s", tag, b.name, b.output)
+ }
+ return false
+ }
+ return true
+}
+
+// run executes the benchmark in a separate goroutine, including all of its
+// subbenchmarks. b must not have subbenchmarks.
func (b *B) run() BenchmarkResult {
+ if b.context != nil {
+ // Running go test --test.bench
+ b.context.processBench(b) // Must call doBench.
+ } else {
+ // Running func Benchmark.
+ b.doBench()
+ }
+ return b.result
+}
+
+func (b *B) doBench() BenchmarkResult {
go b.launch()
<-b.signal
return b.result
}
-// launch launches the benchmark function. It gradually increases the number
+// launch launches the benchmark function. It gradually increases the number
// of benchmark iterations until the benchmark runs for the requested benchtime.
-// It prints timing information in this form
-// testing.BenchmarkHello 100000 19 ns/op
-// launch is run by the run function as a separate goroutine.
+// launch is run by the doBench function as a separate goroutine.
+// run1 must have been called on b.
func (b *B) launch() {
- // Run the benchmark for a single iteration in case it's expensive.
- n := 1
-
// Signal that we're done whether we return normally
// or by FailNow's runtime.Goexit.
defer func() {
- b.signal <- b
+ b.signal <- true
}()
- b.runN(n)
// Run the benchmark for at least the specified amount of time.
- d := *benchTime
- for !b.failed && b.duration < d && n < 1e9 {
+ d := b.benchTime
+ for n := 1; !b.failed && b.duration < d && n < 1e9; {
last := n
// Predict required iterations.
- if b.nsPerOp() == 0 {
- n = 1e9
- } else {
- n = int(d.Nanoseconds() / b.nsPerOp())
+ n = int(d.Nanoseconds())
+ if nsop := b.nsPerOp(); nsop != 0 {
+ n /= int(nsop)
}
// Run more iterations than we think we'll need (1.2x).
// Don't grow too fast in case we had timing errors previously.
@@ -299,12 +353,23 @@ func benchmarkName(name string, n int) string {
return name
}
+type benchContext struct {
+ match *matcher
+
+ maxLen int // The largest recorded benchmark name.
+ extLen int // Maximum extension length.
+}
+
// An internal function but exported because it is cross-package; part of the implementation
// of the "go test" command.
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
+ runBenchmarks(matchString, benchmarks)
+}
+
+func runBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
// If no flag was specified, don't run benchmarks.
if len(*matchBenchmarks) == 0 {
- return
+ return true
}
// Collect matching benchmarks and determine longest name.
maxprocs := 1
@@ -313,57 +378,145 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
maxprocs = procs
}
}
- maxlen := 0
+ ctx := &benchContext{
+ match: newMatcher(matchString, *matchBenchmarks, "-test.bench"),
+ extLen: len(benchmarkName("", maxprocs)),
+ }
var bs []InternalBenchmark
for _, Benchmark := range benchmarks {
- matched, err := matchString(*matchBenchmarks, Benchmark.Name)
- if err != nil {
- fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
- os.Exit(1)
- }
- if matched {
+ if _, matched := ctx.match.fullName(nil, Benchmark.Name); matched {
bs = append(bs, Benchmark)
benchName := benchmarkName(Benchmark.Name, maxprocs)
- if l := len(benchName); l > maxlen {
- maxlen = l
+ if l := len(benchName) + ctx.extLen + 1; l > ctx.maxLen {
+ ctx.maxLen = l
}
}
}
- for _, Benchmark := range bs {
- for _, procs := range cpuList {
- runtime.GOMAXPROCS(procs)
- b := &B{
+ main := &B{
+ common: common{
+ name: "Main",
+ w: os.Stdout,
+ chatty: *chatty,
+ },
+ benchFunc: func(b *B) {
+ for _, Benchmark := range bs {
+ b.Run(Benchmark.Name, Benchmark.F)
+ }
+ },
+ benchTime: *benchTime,
+ context: ctx,
+ }
+ main.runN(1)
+ return !main.failed
+}
+
+// processBench runs bench b for the configured CPU counts and prints the results.
+func (ctx *benchContext) processBench(b *B) {
+ for i, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ benchName := benchmarkName(b.name, procs)
+ fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName)
+ // Recompute the running time for all but the first iteration.
+ if i > 0 {
+ b = &B{
common: common{
- signal: make(chan interface{}),
+ signal: make(chan bool),
+ name: b.name,
+ w: b.w,
+ chatty: b.chatty,
},
- benchmark: Benchmark,
- }
- benchName := benchmarkName(Benchmark.Name, procs)
- fmt.Printf("%-*s\t", maxlen, benchName)
- r := b.run()
- if b.failed {
- // The output could be very long here, but probably isn't.
- // We print it all, regardless, because we don't want to trim the reason
- // the benchmark failed.
- fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
- continue
- }
- results := r.String()
- if *benchmarkMemory || b.showAllocResult {
- results += "\t" + r.MemString()
- }
- fmt.Println(results)
- // Unlike with tests, we ignore the -chatty flag and always print output for
- // benchmarks since the output generation time will skew the results.
- if len(b.output) > 0 {
- b.trimOutput()
- fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
- }
- if p := runtime.GOMAXPROCS(-1); p != procs {
- fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
+ benchFunc: b.benchFunc,
+ benchTime: b.benchTime,
}
+ b.run1()
+ }
+ r := b.doBench()
+ if b.failed {
+ // The output could be very long here, but probably isn't.
+ // We print it all, regardless, because we don't want to trim the reason
+ // the benchmark failed.
+ fmt.Fprintf(b.w, "--- FAIL: %s\n%s", benchName, b.output)
+ continue
}
+ results := r.String()
+ if *benchmarkMemory || b.showAllocResult {
+ results += "\t" + r.MemString()
+ }
+ fmt.Fprintln(b.w, results)
+ // Unlike with tests, we ignore the -chatty flag and always print output for
+ // benchmarks since the output generation time will skew the results.
+ if len(b.output) > 0 {
+ b.trimOutput()
+ fmt.Fprintf(b.w, "--- BENCH: %s\n%s", benchName, b.output)
+ }
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
+ }
+ }
+}
+
+// Run benchmarks f as a subbenchmark with the given name. It reports
+// whether there were any failures.
+//
+// A subbenchmark is like any other benchmark. A benchmark that calls Run at
+// least once will not be measured itself and will be called once with N=1.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer benchmark function for b returns.
+func (b *B) Run(name string, f func(b *B)) bool {
+ // Since b has subbenchmarks, we will no longer run it as a benchmark itself.
+ // Release the lock and acquire it on exit to ensure locks stay paired.
+ atomic.StoreInt32(&b.hasSub, 1)
+ benchmarkLock.Unlock()
+ defer benchmarkLock.Lock()
+
+ benchName, ok := b.name, true
+ if b.context != nil {
+ benchName, ok = b.context.match.fullName(&b.common, name)
+ }
+ if !ok {
+ return true
+ }
+ sub := &B{
+ common: common{
+ signal: make(chan bool),
+ name: benchName,
+ parent: &b.common,
+ level: b.level + 1,
+ w: b.w,
+ chatty: b.chatty,
+ },
+ benchFunc: f,
+ benchTime: b.benchTime,
+ context: b.context,
+ }
+ if sub.run1() {
+ sub.run()
}
+ b.add(sub.result)
+ return !sub.failed
+}
+
+// add simulates running benchmarks in sequence in a single iteration. It is
+// used to give some meaningful results in case func Benchmark is used in
+// combination with Run.
+func (b *B) add(other BenchmarkResult) {
+ r := &b.result
+ // The aggregated BenchmarkResults resemble running all subbenchmarks as
+ // in sequence in a single benchmark.
+ r.N = 1
+ r.T += time.Duration(other.NsPerOp())
+ if other.Bytes == 0 {
+ // Summing Bytes is meaningless in aggregate if not all subbenchmarks
+ // set it.
+ b.missingBytes = true
+ r.Bytes = 0
+ }
+ if !b.missingBytes {
+ r.Bytes += other.Bytes
+ }
+ r.MemAllocs += uint64(other.AllocsPerOp())
+ r.MemBytes += uint64(other.AllocedBytesPerOp())
}
// trimOutput shortens the output from a benchmark, which can be very long.
@@ -416,8 +569,11 @@ func (pb *PB) Next() bool {
// The body function will be run in each goroutine. It should set up any
// goroutine-local state and then iterate until pb.Next returns false.
// It should not use the StartTimer, StopTimer, or ResetTimer functions,
-// because they have global effect.
+// because they have global effect. It should also not call Run.
func (b *B) RunParallel(body func(*PB)) {
+ if b.N == 0 {
+ return // Nothing to do when probing.
+ }
// Calculate grain size as number of iterations that take ~100µs.
// 100µs is enough to amortize the overhead and provide sufficient
// dynamic load balancing.
@@ -466,12 +622,24 @@ func (b *B) SetParallelism(p int) {
// Benchmark benchmarks a single function. Useful for creating
// custom benchmarks that do not use the "go test" command.
+//
+// If f calls Run, the result will be an estimate of running all its
+// subbenchmarks that don't call Run in sequence in a single benchmark.
func Benchmark(f func(b *B)) BenchmarkResult {
b := &B{
common: common{
- signal: make(chan interface{}),
+ signal: make(chan bool),
+ w: discard{},
},
- benchmark: InternalBenchmark{"", f},
+ benchFunc: f,
+ benchTime: *benchTime,
+ }
+ if !b.run1() {
+ return BenchmarkResult{}
}
return b.run()
}
+
+type discard struct{}
+
+func (discard) Write(b []byte) (n int, err error) { return len(b), nil }
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index 30baf27030..e5bce7af4e 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -9,17 +9,26 @@ import (
"fmt"
"io"
"os"
+ "sort"
"strings"
"time"
)
type InternalExample struct {
- Name string
- F func()
- Output string
+ Name string
+ F func()
+ Output string
+ Unordered bool
}
+// An internal function but exported because it is cross-package; part of the implementation
+// of the "go test" command.
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
+ _, ok = runExamples(matchString, examples)
+ return ok
+}
+
+func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
ok = true
var eg InternalExample
@@ -33,12 +42,19 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
if !matched {
continue
}
+ ran = true
if !runExample(eg) {
ok = false
}
}
- return
+ return ran, ok
+}
+
+func sortLines(output string) string {
+ lines := strings.Split(output, "\n")
+ sort.Strings(lines)
+ return strings.Join(lines, "\n")
}
func runExample(eg InternalExample) (ok bool) {
@@ -80,8 +96,16 @@ func runExample(eg InternalExample) (ok bool) {
var fail string
err := recover()
- if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e && err == nil {
- fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", g, e)
+ got := strings.TrimSpace(out)
+ want := strings.TrimSpace(eg.Output)
+ if eg.Unordered {
+ if sortLines(got) != sortLines(want) && err == nil {
+ fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", out, eg.Output)
+ }
+ } else {
+ if got != want && err == nil {
+ fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
+ }
}
if fail != "" || err != nil {
fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
diff --git a/libgo/go/testing/internal/testdeps/deps.go b/libgo/go/testing/internal/testdeps/deps.go
new file mode 100644
index 0000000000..b08300b5d6
--- /dev/null
+++ b/libgo/go/testing/internal/testdeps/deps.go
@@ -0,0 +1,51 @@
+// 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 testdeps provides access to dependencies needed by test execution.
+//
+// This package is imported by the generated main package, which passes
+// TestDeps into testing.Main. This allows tests to use packages at run time
+// without making those packages direct dependencies of package testing.
+// Direct dependencies of package testing are harder to write tests for.
+package testdeps
+
+import (
+ "io"
+ "regexp"
+ "runtime/pprof"
+)
+
+// TestDeps is an implementation of the testing.testDeps interface,
+// suitable for passing to testing.MainStart.
+type TestDeps struct{}
+
+var matchPat string
+var matchRe *regexp.Regexp
+
+func (TestDeps) MatchString(pat, str string) (result bool, err error) {
+ if matchRe == nil || matchPat != pat {
+ matchPat = pat
+ matchRe, err = regexp.Compile(matchPat)
+ if err != nil {
+ return
+ }
+ }
+ return matchRe.MatchString(str), nil
+}
+
+func (TestDeps) StartCPUProfile(w io.Writer) error {
+ return pprof.StartCPUProfile(w)
+}
+
+func (TestDeps) StopCPUProfile() {
+ pprof.StopCPUProfile()
+}
+
+func (TestDeps) WriteHeapProfile(w io.Writer) error {
+ return pprof.WriteHeapProfile(w)
+}
+
+func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error {
+ return pprof.Lookup(name).WriteTo(w, debug)
+}
diff --git a/libgo/go/testing/iotest/reader.go b/libgo/go/testing/iotest/reader.go
index a5bccca906..8d82018fd6 100644
--- a/libgo/go/testing/iotest/reader.go
+++ b/libgo/go/testing/iotest/reader.go
@@ -71,7 +71,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err error) {
var ErrTimeout = errors.New("timeout")
// TimeoutReader returns ErrTimeout on the second read
-// with no data. Subsequent calls to read succeed.
+// with no data. Subsequent calls to read succeed.
func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
type timeoutReader struct {
diff --git a/libgo/go/testing/match.go b/libgo/go/testing/match.go
new file mode 100644
index 0000000000..7751035760
--- /dev/null
+++ b/libgo/go/testing/match.go
@@ -0,0 +1,167 @@
+// 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 testing
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// matcher sanitizes, uniques, and filters names of subtests and subbenchmarks.
+type matcher struct {
+ filter []string
+ matchFunc func(pat, str string) (bool, error)
+
+ mu sync.Mutex
+ subNames map[string]int64
+}
+
+// TODO: fix test_main to avoid race and improve caching, also allowing to
+// eliminate this Mutex.
+var matchMutex sync.Mutex
+
+func newMatcher(matchString func(pat, str string) (bool, error), patterns, name string) *matcher {
+ var filter []string
+ if patterns != "" {
+ filter = splitRegexp(patterns)
+ for i, s := range filter {
+ filter[i] = rewrite(s)
+ }
+ // Verify filters before doing any processing.
+ for i, s := range filter {
+ if _, err := matchString(s, "non-empty"); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for element %d of %s (%q): %s\n", i, name, s, err)
+ os.Exit(1)
+ }
+ }
+ }
+ return &matcher{
+ filter: filter,
+ matchFunc: matchString,
+ subNames: map[string]int64{},
+ }
+}
+
+func (m *matcher) fullName(c *common, subname string) (name string, ok bool) {
+ name = subname
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if c != nil && c.level > 0 {
+ name = m.unique(c.name, rewrite(subname))
+ }
+
+ matchMutex.Lock()
+ defer matchMutex.Unlock()
+
+ // We check the full array of paths each time to allow for the case that
+ // a pattern contains a '/'.
+ for i, s := range strings.Split(name, "/") {
+ if i >= len(m.filter) {
+ break
+ }
+ if ok, _ := m.matchFunc(m.filter[i], s); !ok {
+ return name, false
+ }
+ }
+ return name, true
+}
+
+func splitRegexp(s string) []string {
+ a := make([]string, 0, strings.Count(s, "/"))
+ cs := 0
+ cp := 0
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '[':
+ cs++
+ case ']':
+ if cs--; cs < 0 { // An unmatched ']' is legal.
+ cs = 0
+ }
+ case '(':
+ if cs == 0 {
+ cp++
+ }
+ case ')':
+ if cs == 0 {
+ cp--
+ }
+ case '\\':
+ i++
+ case '/':
+ if cs == 0 && cp == 0 {
+ a = append(a, s[:i])
+ s = s[i+1:]
+ i = 0
+ continue
+ }
+ }
+ i++
+ }
+ return append(a, s)
+}
+
+// unique creates a unique name for the given parent and subname by affixing it
+// with one ore more counts, if necessary.
+func (m *matcher) unique(parent, subname string) string {
+ name := fmt.Sprintf("%s/%s", parent, subname)
+ empty := subname == ""
+ for {
+ next, exists := m.subNames[name]
+ if !empty && !exists {
+ m.subNames[name] = 1 // next count is 1
+ return name
+ }
+ // Name was already used. We increment with the count and append a
+ // string with the count.
+ m.subNames[name] = next + 1
+
+ // Add a count to guarantee uniqueness.
+ name = fmt.Sprintf("%s#%02d", name, next)
+ empty = false
+ }
+}
+
+// rewrite rewrites a subname to having only printable characters and no white
+// space.
+func rewrite(s string) string {
+ b := []byte{}
+ for _, r := range s {
+ switch {
+ case isSpace(r):
+ b = append(b, '_')
+ case !strconv.IsPrint(r):
+ s := strconv.QuoteRune(r)
+ b = append(b, s[1:len(s)-1]...)
+ default:
+ b = append(b, string(r)...)
+ }
+ }
+ return string(b)
+}
+
+func isSpace(r rune) bool {
+ if r < 0x2000 {
+ switch r {
+ // Note: not the same as Unicode Z class.
+ case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680:
+ return true
+ }
+ } else {
+ if r <= 0x200a {
+ return true
+ }
+ switch r {
+ case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000:
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/testing/match_test.go b/libgo/go/testing/match_test.go
new file mode 100644
index 0000000000..8c1c5f4452
--- /dev/null
+++ b/libgo/go/testing/match_test.go
@@ -0,0 +1,185 @@
+// 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 testing
+
+import (
+ "reflect"
+ "regexp"
+ "unicode"
+)
+
+// Verify that our IsSpace agrees with unicode.IsSpace.
+func TestIsSpace(t *T) {
+ n := 0
+ for r := rune(0); r <= unicode.MaxRune; r++ {
+ if isSpace(r) != unicode.IsSpace(r) {
+ t.Errorf("IsSpace(%U)=%t incorrect", r, isSpace(r))
+ n++
+ if n > 10 {
+ return
+ }
+ }
+ }
+}
+
+func TestSplitRegexp(t *T) {
+ res := func(s ...string) []string { return s }
+ testCases := []struct {
+ pattern string
+ result []string
+ }{
+ // Correct patterns
+ // If a regexp pattern is correct, all split regexps need to be correct
+ // as well.
+ {"", res("")},
+ {"/", res("", "")},
+ {"//", res("", "", "")},
+ {"A", res("A")},
+ {"A/B", res("A", "B")},
+ {"A/B/", res("A", "B", "")},
+ {"/A/B/", res("", "A", "B", "")},
+ {"[A]/(B)", res("[A]", "(B)")},
+ {"[/]/[/]", res("[/]", "[/]")},
+ {"[/]/[:/]", res("[/]", "[:/]")},
+ {"/]", res("", "]")},
+ {"]/", res("]", "")},
+ {"]/[/]", res("]", "[/]")},
+ {`([)/][(])`, res(`([)/][(])`)},
+ {"[(]/[)]", res("[(]", "[)]")},
+
+ // Faulty patterns
+ // Errors in original should produce at least one faulty regexp in results.
+ {")/", res(")/")},
+ {")/(/)", res(")/(", ")")},
+ {"a[/)b", res("a[/)b")},
+ {"(/]", res("(/]")},
+ {"(/", res("(/")},
+ {"[/]/[/", res("[/]", "[/")},
+ {`\p{/}`, res(`\p{`, "}")},
+ {`\p/`, res(`\p`, "")},
+ {`[[:/:]]`, res(`[[:/:]]`)},
+ }
+ for _, tc := range testCases {
+ a := splitRegexp(tc.pattern)
+ if !reflect.DeepEqual(a, tc.result) {
+ t.Errorf("splitRegexp(%q) = %#v; want %#v", tc.pattern, a, tc.result)
+ }
+
+ // If there is any error in the pattern, one of the returned subpatterns
+ // needs to have an error as well.
+ if _, err := regexp.Compile(tc.pattern); err != nil {
+ ok := true
+ for _, re := range a {
+ if _, err := regexp.Compile(re); err != nil {
+ ok = false
+ }
+ }
+ if ok {
+ t.Errorf("%s: expected error in any of %q", tc.pattern, a)
+ }
+ }
+ }
+}
+
+func TestMatcher(t *T) {
+ testCases := []struct {
+ pattern string
+ parent, sub string
+ ok bool
+ }{
+ // Behavior without subtests.
+ {"", "", "TestFoo", true},
+ {"TestFoo", "", "TestFoo", true},
+ {"TestFoo/", "", "TestFoo", true},
+ {"TestFoo/bar/baz", "", "TestFoo", true},
+ {"TestFoo", "", "TestBar", false},
+ {"TestFoo/", "", "TestBar", false},
+ {"TestFoo/bar/baz", "", "TestBar/bar/baz", false},
+
+ // with subtests
+ {"", "TestFoo", "x", true},
+ {"TestFoo", "TestFoo", "x", true},
+ {"TestFoo/", "TestFoo", "x", true},
+ {"TestFoo/bar/baz", "TestFoo", "bar", true},
+ // Subtest with a '/' in its name still allows for copy and pasted names
+ // to match.
+ {"TestFoo/bar/baz", "TestFoo", "bar/baz", true},
+ {"TestFoo/bar/baz", "TestFoo/bar", "baz", true},
+ {"TestFoo/bar/baz", "TestFoo", "x", false},
+ {"TestFoo", "TestBar", "x", false},
+ {"TestFoo/", "TestBar", "x", false},
+ {"TestFoo/bar/baz", "TestBar", "x/bar/baz", false},
+
+ // subtests only
+ {"", "TestFoo", "x", true},
+ {"/", "TestFoo", "x", true},
+ {"./", "TestFoo", "x", true},
+ {"./.", "TestFoo", "x", true},
+ {"/bar/baz", "TestFoo", "bar", true},
+ {"/bar/baz", "TestFoo", "bar/baz", true},
+ {"//baz", "TestFoo", "bar/baz", true},
+ {"//", "TestFoo", "bar/baz", true},
+ {"/bar/baz", "TestFoo/bar", "baz", true},
+ {"//foo", "TestFoo", "bar/baz", false},
+ {"/bar/baz", "TestFoo", "x", false},
+ {"/bar/baz", "TestBar", "x/bar/baz", false},
+ }
+
+ for _, tc := range testCases {
+ m := newMatcher(regexp.MatchString, tc.pattern, "-test.run")
+
+ parent := &common{name: tc.parent}
+ if tc.parent != "" {
+ parent.level = 1
+ }
+ if n, ok := m.fullName(parent, tc.sub); ok != tc.ok {
+ 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)
+ }
+ }
+}
+
+func TestNaming(t *T) {
+ m := newMatcher(regexp.MatchString, "", "")
+
+ parent := &common{name: "x", level: 1} // top-level test.
+
+ // Rig the matcher with some preloaded values.
+ m.subNames["x/b"] = 1000
+
+ testCases := []struct {
+ name, want string
+ }{
+ // Uniqueness
+ {"", "x/#00"},
+ {"", "x/#01"},
+
+ {"t", "x/t"},
+ {"t", "x/t#01"},
+ {"t", "x/t#02"},
+
+ {"a#01", "x/a#01"}, // user has subtest with this name.
+ {"a", "x/a"}, // doesn't conflict with this name.
+ {"a", "x/a#01#01"}, // conflict, add disambiguating string.
+ {"a", "x/a#02"}, // This string is claimed now, so resume
+ {"a", "x/a#03"}, // with counting.
+ {"a#02", "x/a#02#01"},
+
+ {"b", "x/b#1000"}, // rigged, see above
+ {"b", "x/b#1001"},
+
+ // // Sanitizing
+ {"A:1 B:2", "x/A:1_B:2"},
+ {"s\t\r\u00a0", "x/s___"},
+ {"\x01", `x/\x01`},
+ {"\U0010ffff", `x/\U0010ffff`},
+ }
+
+ for i, tc := range testCases {
+ if got, _ := m.fullName(parent, tc.name); got != tc.want {
+ t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
+ }
+ }
+}
diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go
index 187195c759..95860fda0f 100644
--- a/libgo/go/testing/quick/quick.go
+++ b/libgo/go/testing/quick/quick.go
@@ -3,6 +3,8 @@
// license that can be found in the LICENSE file.
// Package quick implements utility functions to help with black box testing.
+//
+// The testing/quick package is frozen and is not accepting new features.
package quick
import (
@@ -239,8 +241,8 @@ func (s *CheckEqualError) Error() string {
}
// Check looks for an input to f, any function that returns bool,
-// such that f returns false. It calls f repeatedly, with arbitrary
-// values for each argument. If f returns false on a given input,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
// Check returns that input as a *CheckError.
// For example:
//
@@ -253,24 +255,21 @@ func (s *CheckEqualError) Error() string {
// t.Error(err)
// }
// }
-func Check(f interface{}, config *Config) (err error) {
+func Check(f interface{}, config *Config) error {
if config == nil {
config = &defaultConfig
}
fVal, fType, ok := functionAndType(f)
if !ok {
- err = SetupError("argument is not a function")
- return
+ return SetupError("argument is not a function")
}
if fType.NumOut() != 1 {
- err = SetupError("function does not return one value")
- return
+ return SetupError("function does not return one value")
}
if fType.Out(0).Kind() != reflect.Bool {
- err = SetupError("function does not return a bool")
- return
+ return SetupError("function does not return a bool")
}
arguments := make([]reflect.Value, fType.NumIn())
@@ -278,43 +277,39 @@ func Check(f interface{}, config *Config) (err error) {
maxCount := config.getMaxCount()
for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, fType, config, rand)
+ err := arbitraryValues(arguments, fType, config, rand)
if err != nil {
- return
+ return err
}
if !fVal.Call(arguments)[0].Bool() {
- err = &CheckError{i + 1, toInterfaces(arguments)}
- return
+ return &CheckError{i + 1, toInterfaces(arguments)}
}
}
- return
+ return nil
}
// CheckEqual looks for an input on which f and g return different results.
// It calls f and g repeatedly with arbitrary values for each argument.
// If f and g return different answers, CheckEqual returns a *CheckEqualError
// describing the input and the outputs.
-func CheckEqual(f, g interface{}, config *Config) (err error) {
+func CheckEqual(f, g interface{}, config *Config) error {
if config == nil {
config = &defaultConfig
}
x, xType, ok := functionAndType(f)
if !ok {
- err = SetupError("f is not a function")
- return
+ return SetupError("f is not a function")
}
y, yType, ok := functionAndType(g)
if !ok {
- err = SetupError("g is not a function")
- return
+ return SetupError("g is not a function")
}
if xType != yType {
- err = SetupError("functions have different types")
- return
+ return SetupError("functions have different types")
}
arguments := make([]reflect.Value, xType.NumIn())
@@ -322,21 +317,20 @@ func CheckEqual(f, g interface{}, config *Config) (err error) {
maxCount := config.getMaxCount()
for i := 0; i < maxCount; i++ {
- err = arbitraryValues(arguments, xType, config, rand)
+ err := arbitraryValues(arguments, xType, config, rand)
if err != nil {
- return
+ return err
}
xOut := toInterfaces(x.Call(arguments))
yOut := toInterfaces(y.Call(arguments))
if !reflect.DeepEqual(xOut, yOut) {
- err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
- return
+ return &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
}
}
- return
+ return nil
}
// arbitraryValues writes Values to args such that args contains Values
diff --git a/libgo/go/testing/sub_test.go b/libgo/go/testing/sub_test.go
new file mode 100644
index 0000000000..bb7b3e0925
--- /dev/null
+++ b/libgo/go/testing/sub_test.go
@@ -0,0 +1,534 @@
+// 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 testing
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "strings"
+ "sync/atomic"
+ "time"
+)
+
+func TestTestContext(t *T) {
+ const (
+ add1 = 0
+ done = 1
+ )
+ // After each of the calls are applied to the context, the
+ type call struct {
+ typ int // run or done
+ // result from applying the call
+ running int
+ waiting int
+ started bool
+ }
+ testCases := []struct {
+ max int
+ run []call
+ }{{
+ max: 1,
+ run: []call{
+ {typ: add1, running: 1, waiting: 0, started: true},
+ {typ: done, running: 0, waiting: 0, started: false},
+ },
+ }, {
+ max: 1,
+ run: []call{
+ {typ: add1, running: 1, waiting: 0, started: true},
+ {typ: add1, running: 1, waiting: 1, started: false},
+ {typ: done, running: 1, waiting: 0, started: true},
+ {typ: done, running: 0, waiting: 0, started: false},
+ {typ: add1, running: 1, waiting: 0, started: true},
+ },
+ }, {
+ max: 3,
+ run: []call{
+ {typ: add1, running: 1, waiting: 0, started: true},
+ {typ: add1, running: 2, waiting: 0, started: true},
+ {typ: add1, running: 3, waiting: 0, started: true},
+ {typ: add1, running: 3, waiting: 1, started: false},
+ {typ: add1, running: 3, waiting: 2, started: false},
+ {typ: add1, running: 3, waiting: 3, started: false},
+ {typ: done, running: 3, waiting: 2, started: true},
+ {typ: add1, running: 3, waiting: 3, started: false},
+ {typ: done, running: 3, waiting: 2, started: true},
+ {typ: done, running: 3, waiting: 1, started: true},
+ {typ: done, running: 3, waiting: 0, started: true},
+ {typ: done, running: 2, waiting: 0, started: false},
+ {typ: done, running: 1, waiting: 0, started: false},
+ {typ: done, running: 0, waiting: 0, started: false},
+ },
+ }}
+ for i, tc := range testCases {
+ ctx := &testContext{
+ startParallel: make(chan bool),
+ maxParallel: tc.max,
+ }
+ for j, call := range tc.run {
+ doCall := func(f func()) chan bool {
+ done := make(chan bool)
+ go func() {
+ f()
+ done <- true
+ }()
+ return done
+ }
+ started := false
+ switch call.typ {
+ case add1:
+ signal := doCall(ctx.waitParallel)
+ select {
+ case <-signal:
+ started = true
+ case ctx.startParallel <- true:
+ <-signal
+ }
+ case done:
+ signal := doCall(ctx.release)
+ select {
+ case <-signal:
+ case <-ctx.startParallel:
+ started = true
+ <-signal
+ }
+ }
+ if started != call.started {
+ t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started)
+ }
+ if ctx.running != call.running {
+ t.Errorf("%d:%d:running: got %v; want %v", i, j, ctx.running, call.running)
+ }
+ if ctx.numWaiting != call.waiting {
+ t.Errorf("%d:%d:waiting: got %v; want %v", i, j, ctx.numWaiting, call.waiting)
+ }
+ }
+ }
+}
+
+func TestTRun(t *T) {
+ realTest := t
+ testCases := []struct {
+ desc string
+ ok bool
+ maxPar int
+ chatty bool
+ output string
+ f func(*T)
+ }{{
+ desc: "failnow skips future sequential and parallel tests at same level",
+ ok: false,
+ maxPar: 1,
+ output: `
+--- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs)
+ --- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs)
+ `,
+ f: func(t *T) {
+ ranSeq := false
+ ranPar := false
+ t.Run("", func(t *T) {
+ t.Run("par", func(t *T) {
+ t.Parallel()
+ ranPar = true
+ })
+ t.Run("seq", func(t *T) {
+ ranSeq = true
+ })
+ t.FailNow()
+ t.Run("seq", func(t *T) {
+ realTest.Error("test must be skipped")
+ })
+ t.Run("par", func(t *T) {
+ t.Parallel()
+ realTest.Error("test must be skipped.")
+ })
+ })
+ if !ranPar {
+ realTest.Error("parallel test was not run")
+ }
+ if !ranSeq {
+ realTest.Error("sequential test was not run")
+ }
+ },
+ }, {
+ desc: "failure in parallel test propagates upwards",
+ ok: false,
+ maxPar: 1,
+ output: `
+--- FAIL: failure in parallel test propagates upwards (N.NNs)
+ --- FAIL: failure in parallel test propagates upwards/#00 (N.NNs)
+ --- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs)
+ `,
+ f: func(t *T) {
+ t.Run("", func(t *T) {
+ t.Parallel()
+ t.Run("par", func(t *T) {
+ t.Parallel()
+ t.Fail()
+ })
+ })
+ },
+ }, {
+ desc: "skipping without message, chatty",
+ ok: true,
+ chatty: true,
+ output: `
+=== RUN skipping without message, chatty
+--- SKIP: skipping without message, chatty (N.NNs)`,
+ f: func(t *T) { t.SkipNow() },
+ }, {
+ desc: "chatty with recursion",
+ ok: true,
+ chatty: true,
+ output: `
+=== RUN chatty with recursion
+=== RUN chatty with recursion/#00
+=== RUN chatty with recursion/#00/#00
+--- PASS: chatty with recursion (N.NNs)
+ --- PASS: chatty with recursion/#00 (N.NNs)
+ --- PASS: chatty with recursion/#00/#00 (N.NNs)`,
+ f: func(t *T) {
+ t.Run("", func(t *T) {
+ t.Run("", func(t *T) {})
+ })
+ },
+ }, {
+ desc: "skipping without message, not chatty",
+ ok: true,
+ f: func(t *T) { t.SkipNow() },
+ }, {
+ desc: "skipping after error",
+ output: `
+--- FAIL: skipping after error (N.NNs)
+ sub_test.go:NNN: an error
+ sub_test.go:NNN: skipped`,
+ f: func(t *T) {
+ t.Error("an error")
+ t.Skip("skipped")
+ },
+ }, {
+ desc: "use Run to locally synchronize parallelism",
+ ok: true,
+ maxPar: 1,
+ f: func(t *T) {
+ var count uint32
+ t.Run("waitGroup", func(t *T) {
+ for i := 0; i < 4; i++ {
+ t.Run("par", func(t *T) {
+ t.Parallel()
+ atomic.AddUint32(&count, 1)
+ })
+ }
+ })
+ if count != 4 {
+ t.Errorf("count was %d; want 4", count)
+ }
+ },
+ }, {
+ desc: "alternate sequential and parallel",
+ // Sequential tests should partake in the counting of running threads.
+ // Otherwise, if one runs parallel subtests in sequential tests that are
+ // itself subtests of parallel tests, the counts can get askew.
+ ok: true,
+ maxPar: 1,
+ f: func(t *T) {
+ t.Run("a", func(t *T) {
+ t.Parallel()
+ t.Run("b", func(t *T) {
+ // Sequential: ensure running count is decremented.
+ t.Run("c", func(t *T) {
+ t.Parallel()
+ })
+
+ })
+ })
+ },
+ }, {
+ desc: "alternate sequential and parallel 2",
+ // Sequential tests should partake in the counting of running threads.
+ // Otherwise, if one runs parallel subtests in sequential tests that are
+ // itself subtests of parallel tests, the counts can get askew.
+ ok: true,
+ maxPar: 2,
+ f: func(t *T) {
+ for i := 0; i < 2; i++ {
+ t.Run("a", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 2; i++ {
+ t.Run("b", func(t *T) {
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 2; i++ {
+ t.Run("c", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ })
+ }
+
+ })
+ }
+ })
+ }
+ },
+ }, {
+ desc: "stress test",
+ ok: true,
+ maxPar: 4,
+ f: func(t *T) {
+ t.Parallel()
+ for i := 0; i < 12; i++ {
+ t.Run("a", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 12; i++ {
+ t.Run("b", func(t *T) {
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 12; i++ {
+ t.Run("c", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ t.Run("d1", func(t *T) {})
+ t.Run("d2", func(t *T) {})
+ t.Run("d3", func(t *T) {})
+ t.Run("d4", func(t *T) {})
+ })
+ }
+ })
+ }
+ })
+ }
+ },
+ }, {
+ desc: "skip output",
+ ok: true,
+ maxPar: 4,
+ 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, "", ""))
+ buf := &bytes.Buffer{}
+ root := &T{
+ common: common{
+ signal: make(chan bool),
+ name: "Test",
+ w: buf,
+ chatty: tc.chatty,
+ },
+ context: ctx,
+ }
+ ok := root.Run(tc.desc, tc.f)
+ ctx.release()
+
+ if ok != tc.ok {
+ t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
+ }
+ if ok != !root.Failed() {
+ t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+ }
+ if ctx.running != 0 || ctx.numWaiting != 0 {
+ t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
+ }
+ got := strings.TrimSpace(buf.String())
+ want := strings.TrimSpace(tc.output)
+ re := makeRegexp(want)
+ if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+ t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+ }
+ }
+}
+
+func TestBRun(t *T) {
+ work := func(b *B) {
+ for i := 0; i < b.N; i++ {
+ time.Sleep(time.Nanosecond)
+ }
+ }
+ testCases := []struct {
+ desc string
+ failed bool
+ chatty bool
+ output string
+ f func(*B)
+ }{{
+ desc: "simulate sequential run of subbenchmarks.",
+ f: func(b *B) {
+ b.Run("", func(b *B) { work(b) })
+ time1 := b.result.NsPerOp()
+ b.Run("", func(b *B) { work(b) })
+ time2 := b.result.NsPerOp()
+ if time1 >= time2 {
+ t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2)
+ }
+ },
+ }, {
+ desc: "bytes set by all benchmarks",
+ f: func(b *B) {
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ if b.result.Bytes != 20 {
+ t.Errorf("bytes: got: %d; want 20", b.result.Bytes)
+ }
+ },
+ }, {
+ desc: "bytes set by some benchmarks",
+ // In this case the bytes result is meaningless, so it must be 0.
+ f: func(b *B) {
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ b.Run("", func(b *B) { work(b) })
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ if b.result.Bytes != 0 {
+ t.Errorf("bytes: got: %d; want 0", b.result.Bytes)
+ }
+ },
+ }, {
+ desc: "failure carried over to root",
+ failed: true,
+ output: "--- FAIL: root",
+ f: func(b *B) { b.Fail() },
+ }, {
+ desc: "skipping without message, chatty",
+ chatty: true,
+ output: "--- SKIP: root",
+ f: func(b *B) { b.SkipNow() },
+ }, {
+ desc: "skipping with message, chatty",
+ chatty: true,
+ output: `
+--- SKIP: root
+ sub_test.go:NNN: skipping`,
+ f: func(b *B) { b.Skip("skipping") },
+ }, {
+ desc: "chatty with recursion",
+ chatty: true,
+ f: func(b *B) {
+ b.Run("", func(b *B) {
+ b.Run("", func(b *B) {})
+ })
+ },
+ }, {
+ desc: "skipping without message, not chatty",
+ f: func(b *B) { b.SkipNow() },
+ }, {
+ desc: "skipping after error",
+ failed: true,
+ output: `
+--- FAIL: root
+ sub_test.go:NNN: an error
+ sub_test.go:NNN: skipped`,
+ f: func(b *B) {
+ b.Error("an error")
+ b.Skip("skipped")
+ },
+ }, {
+ desc: "memory allocation",
+ f: func(b *B) {
+ const bufSize = 256
+ alloc := func(b *B) {
+ var buf [bufSize]byte
+ for i := 0; i < b.N; i++ {
+ _ = append([]byte(nil), buf[:]...)
+ }
+ }
+ b.Run("", func(b *B) { alloc(b) })
+ b.Run("", func(b *B) { alloc(b) })
+ // runtime.MemStats sometimes reports more allocations than the
+ // benchmark is responsible for. Luckily the point of this test is
+ // to ensure that the results are not underreported, so we can
+ // simply verify the lower bound.
+ if got := b.result.MemAllocs; got < 2 {
+ t.Errorf("MemAllocs was %v; want 2", got)
+ }
+ if got := b.result.MemBytes; got < 2*bufSize {
+ t.Errorf("MemBytes was %v; want %v", got, 2*bufSize)
+ }
+ },
+ }}
+ for _, tc := range testCases {
+ var ok bool
+ buf := &bytes.Buffer{}
+ // This is almost like the Benchmark function, except that we override
+ // the benchtime and catch the failure result of the subbenchmark.
+ root := &B{
+ common: common{
+ signal: make(chan bool),
+ name: "root",
+ w: buf,
+ chatty: tc.chatty,
+ },
+ benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
+ benchTime: time.Microsecond,
+ }
+ root.runN(1)
+ if ok != !tc.failed {
+ t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
+ }
+ if !ok != root.Failed() {
+ t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+ }
+ // All tests are run as subtests
+ if root.result.N != 1 {
+ t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
+ }
+ got := strings.TrimSpace(buf.String())
+ want := strings.TrimSpace(tc.output)
+ re := makeRegexp(want)
+ if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+ t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+ }
+ }
+}
+
+func makeRegexp(s string) string {
+ s = strings.Replace(s, ":NNN:", `:\d\d\d:`, -1)
+ s = strings.Replace(s, "(N.NNs)", `\(\d*\.\d*s\)`, -1)
+ return s
+}
+
+func TestBenchmarkOutput(t *T) {
+ // Ensure Benchmark initialized common.w by invoking it with an error and
+ // normal case.
+ Benchmark(func(b *B) { b.Error("do not print this output") })
+ Benchmark(func(b *B) {})
+}
+
+func TestParallelSub(t *T) {
+ c := make(chan int)
+ block := make(chan int)
+ for i := 0; i < 10; i++ {
+ go func(i int) {
+ <-block
+ t.Run(fmt.Sprint(i), func(t *T) {})
+ c <- 1
+ }(i)
+ }
+ close(block)
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index bcbe8f15c5..b002aa0bf1 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -45,7 +45,7 @@
//
// The benchmark function must run the target code b.N times.
// During benchmark execution, b.N is adjusted until the benchmark function lasts
-// long enough to be timed reliably. The output
+// long enough to be timed reliably. The output
// BenchmarkHello 10000000 282 ns/op
// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
@@ -118,6 +118,65 @@
// 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 an unanchored regular
+// expression that matches the test's name. For tests with multiple slash-separated
+// elements, such as subtests, the argument is itself slash-separated, with
+// expressions matching each name element in turn. Because it is unanchored, an
+// empty expression matches any string.
+// For example, using "matching" to mean "whose name contains":
+//
+// go test -run '' # Run all tests.
+// go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar".
+// go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=".
+// go test -run /A=1 # For all top-level tests, run subtests 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
@@ -137,7 +196,7 @@
// A simple implementation of TestMain is:
//
// func TestMain(m *testing.M) {
-// flag.Parse()
+// // call flag.Parse() here if TestMain uses flags
// os.Exit(m.Run())
// }
//
@@ -145,22 +204,26 @@ package testing
import (
"bytes"
+ "errors"
"flag"
"fmt"
+ "internal/race"
+ "io"
"os"
"runtime"
"runtime/debug"
- "runtime/pprof"
+ "runtime/trace"
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
)
var (
// The short flag requests that tests run more quickly, but its functionality
- // is provided by test writers themselves. The testing package is just its
- // home. The all.bash installation script sets it to make installation more
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
// efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -169,22 +232,24 @@ var (
// "go test", the binary always runs in the source directory for the package;
// this flag lets "go test" tell the binary to write the files in the directory where
// the "go test" command is run.
- outputDir = flag.String("test.outputdir", "", "directory in which to write profiles")
+ outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
// Report as tests are run; default is silent for success.
- chatty = flag.Bool("test.v", false, "verbose: print additional output")
- count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
- coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution")
- match = flag.String("test.run", "", "regular expression to select tests and examples to run")
- memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
- memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
- cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
- blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
- blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
- traceFile = flag.String("test.trace", "", "write an execution trace to the named file after execution")
- timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
- cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
- parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+ chatty = flag.Bool("test.v", false, "verbose: print additional output")
+ count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
+ coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
+ match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
+ memProfile = flag.String("test.memprofile", "", "write a memory profile to `file`")
+ memProfileRate = flag.Int("test.memprofilerate", 0, "set memory profiling `rate` (see runtime.MemProfileRate)")
+ cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
+ blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
+ blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
+ mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
+ mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
+ traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
+ timeout = flag.Duration("test.timeout", 0, "fail test binary execution after duration `d` (0 means unlimited)")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
+ parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
haveExamples bool // are there examples?
@@ -194,16 +259,26 @@ 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
- output []byte // Output generated by test or benchmark.
- failed bool // Test or benchmark has failed.
- skipped bool // Test of benchmark has been skipped.
- finished bool
+ 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.
+ ran bool // Test or benchmark (or one of its subtests) was executed.
+ failed bool // Test or benchmark has failed.
+ skipped bool // Test of benchmark has been skipped.
+ finished bool // Test function has completed.
+ done bool // Test is finished and all subtests have completed.
+ hasSub int32 // written atomically
+ raceErrors int // number of races detected during test
+ parent *common
+ level int // Nesting depth of test or benchmark.
+ name string // Name of test or benchmark.
start time.Time // Time test or benchmark started
duration time.Duration
- self interface{} // To be sent on signal channel when done.
- signal chan interface{} // Output for serial tests.
+ barrier chan bool // To signal parallel subtests they may start.
+ signal chan bool // To signal a test is done.
+ sub []*T // Queue of subtests to be run in parallel.
}
// Short reports whether the -test.short flag is set.
@@ -211,6 +286,13 @@ func Short() bool {
return *short
}
+// CoverMode reports what the test coverage mode is set to. The
+// values are "set", "count", or "atomic". The return value will be
+// empty if test coverage is not enabled.
+func CoverMode() string {
+ return cover.Mode
+}
+
// Verbose reports whether the -test.v flag is set.
func Verbose() bool {
return *chatty
@@ -250,6 +332,44 @@ func decorate(s string) string {
return buf.String()
}
+// flushToParent writes c.output to the parent after first writing the header
+// with the given format and arguments.
+func (c *common) flushToParent(format string, args ...interface{}) {
+ p := c.parent
+ p.mu.Lock()
+ defer p.mu.Unlock()
+
+ fmt.Fprintf(p.w, format, args...)
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ io.Copy(p.w, bytes.NewReader(c.output))
+ c.output = c.output[:0]
+}
+
+type indenter struct {
+ c *common
+}
+
+func (w indenter) Write(b []byte) (n int, err error) {
+ n = len(b)
+ for len(b) > 0 {
+ end := bytes.IndexByte(b, '\n')
+ if end == -1 {
+ end = len(b)
+ } else {
+ end++
+ }
+ // An indent of 4 spaces will neatly align the dashes with the status
+ // indicator of the parent.
+ const indent = " "
+ w.c.output = append(w.c.output, indent...)
+ w.c.output = append(w.c.output, b[:end]...)
+ b = b[end:]
+ }
+ return
+}
+
// fmtDuration returns a string representing d in the form "87.00s".
func fmtDuration(d time.Duration) string {
return fmt.Sprintf("%.2fs", d.Seconds())
@@ -266,6 +386,7 @@ type TB interface {
Fatalf(format string, args ...interface{})
Log(args ...interface{})
Logf(format string, args ...interface{})
+ Name() string
Skip(args ...interface{})
SkipNow()
Skipf(format string, args ...interface{})
@@ -281,7 +402,7 @@ var _ TB = (*T)(nil)
var _ TB = (*B)(nil)
// T is a type passed to Test functions to manage test state and support formatted test logs.
-// Logs are accumulated during execution and dumped to standard error when done.
+// Logs are accumulated during execution and dumped to standard output when done.
//
// A test ends when its Test function returns or calls any of the methods
// FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods, as well as
@@ -292,17 +413,37 @@ var _ TB = (*B)(nil)
// may be called simultaneously from multiple goroutines.
type T struct {
common
- name string // Name of test.
- isParallel bool
- startParallel chan bool // Parallel tests will wait on this.
+ isParallel bool
+ context *testContext // For running tests and subtests.
}
func (c *common) private() {}
+// Name returns the name of the running test or benchmark.
+func (c *common) Name() string {
+ return c.name
+}
+
+func (c *common) setRan() {
+ if c.parent != nil {
+ c.parent.setRan()
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.ran = true
+}
+
// Fail marks the function as having failed but continues execution.
func (c *common) Fail() {
+ if c.parent != nil {
+ c.parent.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
}
@@ -336,9 +477,9 @@ func (c *common) FailNow() {
// This previous version duplicated code (those lines are in
// tRunner no matter what), but worse the goroutine teardown
// implicit in runtime.Goexit was not guaranteed to complete
- // before the test exited. If a test deferred an important cleanup
+ // before the test exited. If a test deferred an important cleanup
// function (like removing temporary files), there was no guarantee
- // it would run on a test failure. Because we send on c.signal during
+ // it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
c.finished = true
@@ -358,10 +499,11 @@ func (c *common) log(s string) {
// printed to avoid having performance depend on the value of the -test.v flag.
func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
-// Logf formats its arguments according to the format, analogous to Printf,
-// and records the text in the error log. For tests, the text will be printed only if
-// the test fails or the -test.v flag is set. For benchmarks, the text is always
-// printed to avoid having performance depend on the value of the -test.v flag.
+// Logf formats its arguments according to the format, analogous to Printf, and
+// records the text in the error log. A final newline is added if not provided. For
+// tests, the text will be printed only if the test fails or the -test.v flag is
+// set. For benchmarks, the text is always printed to avoid having performance
+// depend on the value of the -test.v flag.
func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log followed by Fail.
@@ -401,6 +543,8 @@ func (c *common) Skipf(format string, args ...interface{}) {
}
// SkipNow marks the test as having been skipped and stops its execution.
+// If a test fails (see Error, Errorf, Fail) and is then skipped,
+// it is still considered to have failed.
// Execution will continue at the next test or benchmark. See also FailNow.
// SkipNow must be called from the goroutine running the test, not from
// other goroutines created during the test. Calling SkipNow does not stop
@@ -436,9 +580,16 @@ func (t *T) Parallel() {
// in the test duration. Record the elapsed time thus far and reset the
// timer afterwards.
t.duration += time.Since(t.start)
- t.signal <- (*T)(nil) // Release main testing loop
- <-t.startParallel // Wait for serial tests to finish
+
+ // Add to the list of tests to be released by the parent.
+ t.parent.sub = append(t.parent.sub, t)
+ t.raceErrors += race.Errors()
+
+ t.signal <- true // Release calling test.
+ <-t.parent.barrier // Wait for the parent test to complete.
+ t.context.waitParallel()
t.start = time.Now()
+ t.raceErrors += -race.Errors()
}
// An internal type but exported because it is cross-package; part of the implementation
@@ -448,12 +599,17 @@ type InternalTest struct {
F func(*T)
}
-func tRunner(t *T, test *InternalTest) {
- // When this goroutine is done, either because test.F(t)
+func tRunner(t *T, fn func(t *T)) {
+ // When this goroutine is done, either because fn(t)
// returned normally or because a test failure triggered
// a call to runtime.Goexit, record the duration and send
// a signal saying that the test is done.
defer func() {
+ t.raceErrors += race.Errors()
+ if t.raceErrors > 0 {
+ t.Errorf("race detected during execution of test")
+ }
+
t.duration += time.Now().Sub(t.start)
// If the test panicked, print any test output before dying.
err := recover()
@@ -465,37 +621,189 @@ func tRunner(t *T, test *InternalTest) {
t.report()
panic(err)
}
- t.signal <- t
+
+ if len(t.sub) > 0 {
+ // Run parallel subtests.
+ // Decrease the running count for this test.
+ t.context.release()
+ // Release the parallel subtests.
+ close(t.barrier)
+ // Wait for subtests to complete.
+ for _, sub := range t.sub {
+ <-sub.signal
+ }
+ if !t.isParallel {
+ // Reacquire the count for sequential tests. See comment in Run.
+ t.context.waitParallel()
+ }
+ } else if t.isParallel {
+ // Only release the count for this test if it was run as a parallel
+ // test. See comment in Run method.
+ t.context.release()
+ }
+ 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
+ if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
+ t.setRan()
+ }
+ t.signal <- true
}()
t.start = time.Now()
- test.F(t)
+ t.raceErrors = -race.Errors()
+ fn(t)
t.finished = true
}
-// An internal function but exported because it is cross-package; part of the implementation
-// of the "go test" command.
+// Run runs f as a subtest of t called name. It reports whether f succeeded.
+// Run will block until all its parallel subtests have completed.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer test function for t returns.
+func (t *T) Run(name string, f func(t *T)) bool {
+ atomic.StoreInt32(&t.hasSub, 1)
+ testName, ok := t.context.match.fullName(&t.common, name)
+ if !ok {
+ return true
+ }
+ t = &T{
+ common: common{
+ barrier: make(chan bool),
+ signal: make(chan bool),
+ name: testName,
+ parent: &t.common,
+ level: t.level + 1,
+ chatty: t.chatty,
+ },
+ context: t.context,
+ }
+ t.w = indenter{&t.common}
+
+ if t.chatty {
+ // Print directly to root's io.Writer so there is no delay.
+ root := t.parent
+ for ; root.parent != nil; root = root.parent {
+ }
+ fmt.Fprintf(root.w, "=== RUN %s\n", t.name)
+ }
+ // Instead of reducing the running count of this test before calling the
+ // tRunner and increasing it afterwards, we rely on tRunner keeping the
+ // count correct. This ensures that a sequence of sequential tests runs
+ // without being preempted, even when their parent is a parallel test. This
+ // may especially reduce surprises if *parallel == 1.
+ go tRunner(t, f)
+ <-t.signal
+ return !t.failed
+}
+
+// testContext holds all fields that are common to all tests. This includes
+// synchronization primitives to run at most *parallel tests.
+type testContext struct {
+ match *matcher
+
+ mu sync.Mutex
+
+ // Channel used to signal tests that are ready to be run in parallel.
+ startParallel chan bool
+
+ // running is the number of tests currently running in parallel.
+ // This does not include tests that are waiting for subtests to complete.
+ running int
+
+ // numWaiting is the number tests waiting to be run in parallel.
+ numWaiting int
+
+ // maxParallel is a copy of the parallel flag.
+ maxParallel int
+}
+
+func newTestContext(maxParallel int, m *matcher) *testContext {
+ return &testContext{
+ match: m,
+ startParallel: make(chan bool),
+ maxParallel: maxParallel,
+ running: 1, // Set the count to 1 for the main (sequential) test.
+ }
+}
+
+func (c *testContext) waitParallel() {
+ c.mu.Lock()
+ if c.running < c.maxParallel {
+ c.running++
+ c.mu.Unlock()
+ return
+ }
+ c.numWaiting++
+ c.mu.Unlock()
+ <-c.startParallel
+}
+
+func (c *testContext) release() {
+ c.mu.Lock()
+ if c.numWaiting == 0 {
+ c.running--
+ c.mu.Unlock()
+ return
+ }
+ c.numWaiting--
+ c.mu.Unlock()
+ c.startParallel <- true // Pick a waiting test to be run.
+}
+
+// No one should be using func Main anymore.
+// See the doc comment on func Main and use MainStart instead.
+var errMain = errors.New("testing: unexpected use of func Main")
+
+type matchStringOnly func(pat, str string) (bool, error)
+
+func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
+func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
+func (f matchStringOnly) StopCPUProfile() {}
+func (f matchStringOnly) WriteHeapProfile(w io.Writer) error { return errMain }
+func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
+
+// Main is an internal function, part of the implementation of the "go test" command.
+// It was exported because it is cross-package and predates "internal" packages.
+// It is no longer used by "go test" but preserved, as much as possible, for other
+// systems that simulate "go test" using Main, but Main sometimes cannot be updated as
+// new functionality is added to the testing package.
+// Systems simulating "go test" should be updated to use MainStart.
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
- os.Exit(MainStart(matchString, tests, benchmarks, examples).Run())
+ os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
}
// M is a type passed to a TestMain function to run the actual tests.
type M struct {
- matchString func(pat, str string) (bool, error)
- tests []InternalTest
- benchmarks []InternalBenchmark
- examples []InternalExample
+ deps testDeps
+ tests []InternalTest
+ benchmarks []InternalBenchmark
+ examples []InternalExample
+}
+
+// testDeps is an internal interface of functionality that is
+// passed into this package by a test's generated main package.
+// The canonical implementation of this interface is
+// testing/internal/testdeps's TestDeps.
+type testDeps interface {
+ MatchString(pat, str string) (bool, error)
+ StartCPUProfile(io.Writer) error
+ StopCPUProfile()
+ WriteHeapProfile(io.Writer) error
+ WriteProfileTo(string, io.Writer, int) error
}
// MainStart is meant for use by tests generated by 'go test'.
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
// It may change signature from release to release.
-func MainStart(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
+func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
return &M{
- matchString: matchString,
- tests: tests,
- benchmarks: benchmarks,
- examples: examples,
+ deps: deps,
+ tests: tests,
+ benchmarks: benchmarks,
+ examples: examples,
}
}
@@ -508,119 +816,95 @@ func (m *M) Run() int {
parseCpuList()
- before()
+ m.before()
startAlarm()
haveExamples = len(m.examples) > 0
- testOk := RunTests(m.matchString, m.tests)
- exampleOk := RunExamples(m.matchString, m.examples)
+ testRan, testOk := runTests(m.deps.MatchString, m.tests)
+ exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
stopAlarm()
- if !testOk || !exampleOk {
+ if !testRan && !exampleRan && *matchBenchmarks == "" {
+ fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
+ }
+ if !testOk || !exampleOk || !runBenchmarks(m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
fmt.Println("FAIL")
- after()
+ m.after()
return 1
}
+
fmt.Println("PASS")
- RunBenchmarks(m.matchString, m.benchmarks)
- after()
+ m.after()
return 0
}
func (t *T) report() {
+ if t.parent == nil {
+ return
+ }
dstr := fmtDuration(t.duration)
- format := "--- %s: %s (%s)\n%s"
+ format := "--- %s: %s (%s)\n"
if t.Failed() {
- fmt.Printf(format, "FAIL", t.name, dstr, t.output)
- } else if *chatty {
+ t.flushToParent(format, "FAIL", t.name, dstr)
+ } else if t.chatty {
if t.Skipped() {
- fmt.Printf(format, "SKIP", t.name, dstr, t.output)
+ t.flushToParent(format, "SKIP", t.name, dstr)
} else {
- fmt.Printf(format, "PASS", t.name, dstr, t.output)
+ t.flushToParent(format, "PASS", t.name, dstr)
}
}
}
+// An internal function but exported because it is cross-package; part of the implementation
+// of the "go test" command.
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
- ok = true
- if len(tests) == 0 && !haveExamples {
+ ran, ok := runTests(matchString, tests)
+ if !ran && !haveExamples {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
- return
}
+ return ok
+}
+
+func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
+ ok = true
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
- // We build a new channel tree for each run of the loop.
- // collector merges in one channel all the upstream signals from parallel tests.
- // If all tests pump to the same channel, a bug can occur where a test
- // kicks off a goroutine that Fails, yet the test still delivers a completion signal,
- // which skews the counting.
- var collector = make(chan interface{})
-
- numParallel := 0
- startParallel := make(chan bool)
-
- for i := 0; i < len(tests); i++ {
- matched, err := matchString(*match, tests[i].Name)
- if err != nil {
- fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
- os.Exit(1)
- }
- if !matched {
- continue
- }
- testName := tests[i].Name
- t := &T{
- common: common{
- signal: make(chan interface{}),
- },
- name: testName,
- startParallel: startParallel,
- }
- t.self = t
- if *chatty {
- fmt.Printf("=== RUN %s\n", t.name)
- }
- go tRunner(t, &tests[i])
- out := (<-t.signal).(*T)
- if out == nil { // Parallel run.
- go func() {
- collector <- <-t.signal
- }()
- numParallel++
- continue
- }
- t.report()
- ok = ok && !out.Failed()
+ ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
+ t := &T{
+ common: common{
+ signal: make(chan bool),
+ barrier: make(chan bool),
+ w: os.Stdout,
+ chatty: *chatty,
+ },
+ context: ctx,
}
-
- running := 0
- for numParallel+running > 0 {
- if running < *parallel && numParallel > 0 {
- startParallel <- true
- running++
- numParallel--
- continue
+ tRunner(t, func(t *T) {
+ for _, test := range tests {
+ t.Run(test.Name, test.F)
}
- t := (<-collector).(*T)
- t.report()
- ok = ok && !t.Failed()
- running--
- }
+ // Run catching the signal rather than the tRunner as a separate
+ // goroutine to avoid adding a goroutine during the sequential
+ // phase as this pollutes the stacktrace output when aborting.
+ go func() { <-t.signal }()
+ })
+ ok = ok && !t.Failed()
+ ran = ran || t.ran
}
- return
+ return ran, ok
}
// before runs before all testing.
-func before() {
+func (m *M) before() {
if *memProfileRate > 0 {
runtime.MemProfileRate = *memProfileRate
}
if *cpuProfile != "" {
f, err := os.Create(toOutputDir(*cpuProfile))
if err != nil {
- fmt.Fprintf(os.Stderr, "testing: %s", err)
+ fmt.Fprintf(os.Stderr, "testing: %s\n", err)
return
}
- if err := pprof.StartCPUProfile(f); err != nil {
- fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
+ if err := m.deps.StartCPUProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
f.Close()
return
}
@@ -629,22 +913,22 @@ func before() {
if *traceFile != "" {
f, err := os.Create(toOutputDir(*traceFile))
if err != nil {
- fmt.Fprintf(os.Stderr, "testing: %s", err)
+ fmt.Fprintf(os.Stderr, "testing: %s\n", err)
+ return
+ }
+ if err := trace.Start(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
+ f.Close()
return
}
- /*
- if err := trace.Start(f); err != nil {
- fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err)
- f.Close()
- return
- }
- */
- _ = f
// Could save f so after can call f.Close; not worth the effort.
}
if *blockProfile != "" && *blockProfileRate >= 0 {
runtime.SetBlockProfileRate(*blockProfileRate)
}
+ if *mutexProfile != "" && *mutexProfileFraction >= 0 {
+ runtime.SetMutexProfileFraction(*mutexProfileFraction)
+ }
if *coverProfile != "" && cover.Mode == "" {
fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
os.Exit(2)
@@ -652,14 +936,12 @@ func before() {
}
// after runs after all testing.
-func after() {
+func (m *M) after() {
if *cpuProfile != "" {
- pprof.StopCPUProfile() // flushes profile to disk
+ m.deps.StopCPUProfile() // flushes profile to disk
}
if *traceFile != "" {
- /*
- trace.Stop() // flushes trace to disk
- */
+ // trace.Stop() // flushes trace to disk
}
if *memProfile != "" {
f, err := os.Create(toOutputDir(*memProfile))
@@ -668,7 +950,7 @@ func after() {
os.Exit(2)
}
runtime.GC() // materialize all statistics
- if err = pprof.WriteHeapProfile(f); err != nil {
+ if err = m.deps.WriteHeapProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
os.Exit(2)
}
@@ -680,7 +962,19 @@ func after() {
fmt.Fprintf(os.Stderr, "testing: %s\n", err)
os.Exit(2)
}
- if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
+ if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
+ os.Exit(2)
+ }
+ f.Close()
+ }
+ if *mutexProfile != "" && *mutexProfileFraction >= 0 {
+ f, err := os.Create(toOutputDir(*mutexProfile))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s\n", err)
+ os.Exit(2)
+ }
+ if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
os.Exit(2)
}
diff --git a/libgo/go/testing/testing_test.go b/libgo/go/testing/testing_test.go
index 87a5c16d6e..45e44683b4 100644
--- a/libgo/go/testing/testing_test.go
+++ b/libgo/go/testing/testing_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/text/scanner/example_test.go b/libgo/go/text/scanner/example_test.go
index f8b51b7322..f48c31daa0 100644
--- a/libgo/go/text/scanner/example_test.go
+++ b/libgo/go/text/scanner/example_test.go
@@ -19,6 +19,7 @@ func Example() {
someParsable = text
}`
var s scanner.Scanner
+ s.Filename = "example"
s.Init(strings.NewReader(src))
var tok rune
for tok != scanner.EOF {
@@ -27,14 +28,14 @@ func Example() {
}
// Output:
- // At position 3:4 : if
- // At position 3:6 : a
- // At position 3:8 : >
- // At position 3:11 : 10
- // At position 3:13 : {
- // At position 4:15 : someParsable
- // At position 4:17 : =
- // At position 4:22 : text
- // At position 5:3 : }
- // At position 5:3 :
+ // At position example:3:4 : if
+ // At position example:3:6 : a
+ // At position example:3:8 : >
+ // At position example:3:11 : 10
+ // At position example:3:13 : {
+ // At position example:4:15 : someParsable
+ // At position example:4:17 : =
+ // At position example:4:22 : text
+ // At position example:5:3 : }
+ // At position example:5:3 :
}
diff --git a/libgo/go/text/scanner/scanner.go b/libgo/go/text/scanner/scanner.go
index 0155800f34..e085f8a7d9 100644
--- a/libgo/go/text/scanner/scanner.go
+++ b/libgo/go/text/scanner/scanner.go
@@ -4,12 +4,12 @@
// Package scanner provides a scanner and tokenizer for UTF-8-encoded text.
// It takes an io.Reader providing the source, which then can be tokenized
-// through repeated calls to the Scan function. For compatibility with
+// through repeated calls to the Scan function. For compatibility with
// existing tools, the NUL character is not allowed. If the first character
// in the source is a UTF-8 encoded byte order mark (BOM), it is discarded.
//
// By default, a Scanner skips white space and Go comments and recognizes all
-// literals as defined by the Go language specification. It may be
+// literals as defined by the Go language specification. It may be
// customized to recognize only a subset of those literals and to recognize
// different identifier and white space characters.
package scanner
@@ -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
}
diff --git a/libgo/go/text/scanner/scanner_test.go b/libgo/go/text/scanner/scanner_test.go
index 798bed7e92..3e92d659ca 100644
--- a/libgo/go/text/scanner/scanner_test.go
+++ b/libgo/go/text/scanner/scanner_test.go
@@ -451,37 +451,37 @@ func testError(t *testing.T, src, pos, msg string, tok rune) {
}
func TestError(t *testing.T) {
- testError(t, "\x00", "1:1", "illegal character NUL", 0)
- testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
- testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
-
- testError(t, "a\x00", "1:2", "illegal character NUL", Ident)
- testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident)
- testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident)
-
- testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String)
- testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String)
- testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
- testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String)
- testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String)
- testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
- testError(t, `'\"'`, "1:3", "illegal char escape", Char)
- testError(t, `"\'"`, "1:3", "illegal char escape", String)
-
- testError(t, `01238`, "1:6", "illegal octal number", Int)
- testError(t, `01238123`, "1:9", "illegal octal number", Int)
- testError(t, `0x`, "1:3", "illegal hexadecimal number", Int)
- testError(t, `0xg`, "1:3", "illegal hexadecimal number", Int)
- testError(t, `'aa'`, "1:4", "illegal char literal", Char)
-
- testError(t, `'`, "1:2", "literal not terminated", Char)
- testError(t, `'`+"\n", "1:2", "literal not terminated", Char)
- testError(t, `"abc`, "1:5", "literal not terminated", String)
- testError(t, `"abc`+"\n", "1:5", "literal not terminated", String)
- testError(t, "`abc\n", "2:1", "literal not terminated", String)
- testError(t, `/*/`, "1:4", "comment not terminated", EOF)
+ testError(t, "\x00", "<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.
diff --git a/libgo/go/text/tabwriter/example_test.go b/libgo/go/text/tabwriter/example_test.go
index 20443cb1ff..422ec117ad 100644
--- a/libgo/go/text/tabwriter/example_test.go
+++ b/libgo/go/text/tabwriter/example_test.go
@@ -36,3 +36,38 @@ func ExampleWriter_Init() {
// a b c d.
// 123 12345 1234567 123456789.
}
+
+func Example_elastic() {
+ // Observe how the b's and the d's, despite appearing in the
+ // second cell of each line, belong to different columns.
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, '.', tabwriter.AlignRight|tabwriter.Debug)
+ fmt.Fprintln(w, "a\tb\tc")
+ fmt.Fprintln(w, "aa\tbb\tcc")
+ fmt.Fprintln(w, "aaa\t") // trailing tab
+ fmt.Fprintln(w, "aaaa\tdddd\teeee")
+ w.Flush()
+
+ // output:
+ // ....a|..b|c
+ // ...aa|.bb|cc
+ // ..aaa|
+ // .aaaa|.dddd|eeee
+}
+
+func Example_trailingTab() {
+ // Observe that the third line has no trailing tab,
+ // so its final cell is not part of an aligned column.
+ const padding = 3
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, '-', tabwriter.AlignRight|tabwriter.Debug)
+ fmt.Fprintln(w, "a\tb\taligned\t")
+ fmt.Fprintln(w, "aa\tbb\taligned\t")
+ fmt.Fprintln(w, "aaa\tbbb\tunaligned") // no trailing tab
+ fmt.Fprintln(w, "aaaa\tbbbb\taligned\t")
+ w.Flush()
+
+ // output:
+ // ------a|------b|---aligned|
+ // -----aa|-----bb|---aligned|
+ // ----aaa|----bbb|unaligned
+ // ---aaaa|---bbbb|---aligned|
+}
diff --git a/libgo/go/text/tabwriter/tabwriter.go b/libgo/go/text/tabwriter/tabwriter.go
index c0c32d5dec..752c9b8e9f 100644
--- a/libgo/go/text/tabwriter/tabwriter.go
+++ b/libgo/go/text/tabwriter/tabwriter.go
@@ -8,6 +8,7 @@
// The package is using the Elastic Tabstops algorithm described at
// http://nickgravgaard.com/elastictabstops/index.html.
//
+// The text/tabwriter package is frozen and is not accepting new features.
package tabwriter
import (
@@ -33,18 +34,32 @@ type cell struct {
// A Writer is a filter that inserts padding around tab-delimited
// columns in its input to align them in the output.
//
-// The Writer treats incoming bytes as UTF-8 encoded text consisting
-// of cells terminated by (horizontal or vertical) tabs or line
-// breaks (newline or formfeed characters). Cells in adjacent lines
-// constitute a column. The Writer inserts padding as needed to
-// make all cells in a column have the same width, effectively
-// aligning the columns. It assumes that all characters have the
-// same width except for tabs for which a tabwidth must be specified.
-// Note that cells are tab-terminated, not tab-separated: trailing
-// non-tab text at the end of a line does not form a column cell.
+// The Writer treats incoming bytes as UTF-8-encoded text consisting
+// of cells terminated by horizontal ('\t') or vertical ('\v') tabs,
+// and newline ('\n') or formfeed ('\f') characters; both newline and
+// formfeed act as line breaks.
+//
+// Tab-terminated cells in contiguous lines constitute a column. The
+// Writer inserts padding as needed to make all cells in a column have
+// the same width, effectively aligning the columns. It assumes that
+// all characters have the same width, except for tabs for which a
+// tabwidth must be specified. Column cells must be tab-terminated, not
+// tab-separated: non-tab terminated trailing text at the end of a line
+// forms a cell but that cell is not part of an aligned column.
+// For instance, in this example (where | stands for a horizontal tab):
+//
+// aaaa|bbb|d
+// aa |b |dd
+// a |
+// aa |cccc|eee
+//
+// the b and c are in distinct columns (the b column is not contiguous
+// all the way). The d and e are not in a column at all (there's no
+// terminating tab, nor would the column be contiguous).
//
// The Writer assumes that all Unicode code points have the same width;
-// this may not be true in some fonts.
+// this may not be true in some fonts or if the string contains combining
+// characters.
//
// If DiscardEmptyColumns is set, empty columns that are terminated
// entirely by vertical (or "soft") tabs are discarded. Columns
@@ -64,9 +79,9 @@ type cell struct {
// width of the escaped text is always computed excluding the Escape
// characters.
//
-// The formfeed character ('\f') acts like a newline but it also
-// terminates all columns in the current line (effectively calling
-// Flush). Cells in the next line start new columns. Unless found
+// The formfeed character acts like a newline but it also terminates
+// all columns in the current line (effectively calling Flush). Tab-
+// terminated cells in the next line start new columns. Unless found
// inside an HTML tag or inside an escaped text segment, formfeed
// characters appear as newlines in the output.
//
@@ -448,8 +463,11 @@ func handlePanic(err *error, op string) {
// that any data buffered in the Writer is written to output. Any
// incomplete escape sequence at the end is considered
// complete for formatting purposes.
-//
-func (b *Writer) Flush() (err error) {
+func (b *Writer) Flush() error {
+ return b.flush()
+}
+
+func (b *Writer) flush() (err error) {
defer b.reset() // even in the presence of errors
defer handlePanic(&err, "Flush")
@@ -464,8 +482,7 @@ func (b *Writer) Flush() (err error) {
// format contents of buffer
b.format(0, 0, len(b.lines))
-
- return
+ return nil
}
var hbar = []byte("---\n")
diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go
index df8c95f8c8..fe59e3f74e 100644
--- a/libgo/go/text/template/doc.go
+++ b/libgo/go/text/template/doc.go
@@ -74,8 +74,9 @@ data, defined in detail in the corresponding sections that follow.
/*
{{pipeline}}
- The default textual representation of the value of the pipeline
- is copied to the output.
+ The default textual representation (the same as would be
+ printed by fmt.Print) of the value of the pipeline is copied
+ to the output.
{{if pipeline}} T1 {{end}}
If the value of the pipeline is empty, no output is generated;
@@ -220,7 +221,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.
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index efe1817173..89d3e379b4 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -15,14 +15,23 @@ 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.
+// For gccgo we make this 1000 rather than 100000 to avoid stack overflow
+// on non-split-stack systems.
+const maxExecDepth = 1000
+
// 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.
@@ -164,16 +173,26 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// execution stops, but partial results may already have been written to
// the output writer.
// A template may be executed safely in parallel.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
+//
+// If data is a reflect.Value, the template applies to the concrete
+// value that the reflect.Value holds, as in fmt.Print.
+func (t *Template) Execute(wr io.Writer, data interface{}) error {
+ return t.execute(wr, data)
+}
+
+func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
defer errRecover(&err)
- value := reflect.ValueOf(data)
+ value, ok := data.(reflect.Value)
+ if !ok {
+ value = reflect.ValueOf(data)
+ }
state := &state{
tmpl: t,
wr: wr,
vars: []variable{{"$", value}},
}
if t.Tree == nil || t.Root == nil {
- state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
+ state.errorf("%q is an incomplete or empty template", t.Name())
}
state.walk(value, t.Root)
return
@@ -359,9 +378,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}}
@@ -436,7 +459,7 @@ func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final ref
// idealConstant is called to return the value of a number in a context where
// we don't know the type. In that case, the syntax of the number tells us
-// its type, and we use Go rules to resolve. Note there is no such thing as
+// its type, and we use Go rules to resolve. Note there is no such thing as
// a uint ideal constant in this situation - the value must be of int type.
func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
// These are ideal constants but we don't know the type
@@ -446,7 +469,7 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
switch {
case constant.IsComplex:
return reflect.ValueOf(constant.Complex128) // incontrovertible.
- case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0:
+ case constant.IsFloat && !isHexConstant(constant.Text) && strings.ContainsAny(constant.Text, ".eE"):
return reflect.ValueOf(constant.Float64)
case constant.IsInt:
n := int(constant.Int64)
@@ -520,6 +543,9 @@ func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd
// value of the pipeline, if any.
func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value {
if !receiver.IsValid() {
+ if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key.
+ s.errorf("nil data; no entry for key %q", fieldName)
+ }
return zero
}
typ := receiver.Type()
@@ -534,14 +560,14 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
return s.evalCall(dot, method, node, fieldName, args, final)
}
hasArgs := len(args) > 1 || final.IsValid()
- // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
- if isNil {
- s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
- }
+ // It's not a method; must be a field of a struct or an element of a map.
switch receiver.Kind() {
case reflect.Struct:
tField, ok := receiver.Type().FieldByName(fieldName)
if ok {
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
field := receiver.FieldByIndex(tField.Index)
if tField.PkgPath != "" { // field is unexported
s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
@@ -552,8 +578,10 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
}
return field
}
- s.errorf("%s is not a field of struct type %s", fieldName, typ)
case reflect.Map:
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
// If it's a map, attempt to use the field name as a key.
nameVal := reflect.ValueOf(fieldName)
if nameVal.Type().AssignableTo(receiver.Type().Key()) {
@@ -579,12 +607,13 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
}
var (
- errorType = reflect.TypeOf((*error)(nil)).Elem()
- fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
)
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
-// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
+// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
// as the function itself.
func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
if args != nil {
@@ -644,7 +673,11 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
s.at(node)
s.errorf("error calling %s: %s", name, result[1].Interface().(error))
}
- return result[0]
+ v := result[0]
+ if v.Type() == reflectValueType {
+ v = v.Interface().(reflect.Value)
+ }
+ return v
}
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
@@ -652,6 +685,8 @@ func canBeNil(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return true
+ case reflect.Struct:
+ return typ == reflectValueType
}
return false
}
@@ -665,6 +700,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
}
s.errorf("invalid value; expected %s", typ)
}
+ if typ == reflectValueType && value.Type() != typ {
+ return reflect.ValueOf(value)
+ }
if typ != nil && !value.Type().AssignableTo(typ) {
if value.Kind() == reflect.Interface && !value.IsNil() {
value = value.Elem()
@@ -726,6 +764,10 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
if typ.NumMethod() == 0 {
return s.evalEmptyInterface(dot, n)
}
+ case reflect.Struct:
+ if typ == reflectValueType {
+ return reflect.ValueOf(s.evalEmptyInterface(dot, n))
+ }
case reflect.String:
return s.evalString(typ, n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -837,6 +879,20 @@ func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
return v, false
}
+// indirectInterface returns the concrete value in an interface value,
+// or else the zero reflect.Value.
+// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
+// the fact that x was an interface value is forgotten.
+func indirectInterface(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Interface {
+ return v
+ }
+ if v.IsNil() {
+ return reflect.Value{}
+ }
+ return v.Elem()
+}
+
// printValue writes the textual representation of the value to the output of
// the template.
func (s *state) printValue(n parse.Node, v reflect.Value) {
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index e507e917fe..5892b27391 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -932,7 +932,7 @@ func TestMessageForExecuteEmpty(t *testing.T) {
t.Fatal("expected second error")
}
got = err.Error()
- want = `template: empty: "empty" is an incomplete or empty template; defined templates are: "secondary"`
+ want = `template: empty: "empty" is an incomplete or empty template`
if got != want {
t.Errorf("expected error %s got %s", want, got)
}
@@ -1142,6 +1142,12 @@ func TestMissingMapKey(t *testing.T) {
if err == nil {
t.Errorf("expected error; got none")
}
+ // same Option, but now a nil interface: ask for an error
+ err = tmpl.Execute(&b, nil)
+ t.Log(err)
+ if err == nil {
+ t.Errorf("expected error for nil-interface; got none")
+ }
}
// Test that the error message for multiline unterminated string
@@ -1152,7 +1158,7 @@ func TestUnterminatedStringError(t *testing.T) {
t.Fatal("expected error")
}
str := err.Error()
- if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
+ if !strings.Contains(str, "X:3: unexpected unterminated raw quoted string") {
t.Fatalf("unexpected error: %s", str)
}
}
@@ -1280,3 +1286,129 @@ func TestBlock(t *testing.T) {
t.Errorf("got %q, want %q", got, want2)
}
}
+
+// Check that calling an invalid field on nil pointer prints
+// a field error instead of a distracting nil pointer error.
+// https://golang.org/issue/15125
+func TestMissingFieldOnNil(t *testing.T) {
+ tmpl := Must(New("tmpl").Parse("{{.MissingField}}"))
+ var d *T
+ err := tmpl.Execute(ioutil.Discard, d)
+ got := "<nil>"
+ if err != nil {
+ got = err.Error()
+ }
+ want := "can't evaluate field MissingField in type *template.T"
+ if !strings.HasSuffix(got, want) {
+ 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)
+ }
+}
+
+func TestAddrOfIndex(t *testing.T) {
+ // golang.org/issue/14916.
+ // Before index worked on reflect.Values, the .String could not be
+ // found on the (incorrectly unaddressable) V value,
+ // in contrast to range, which worked fine.
+ // Also testing that passing a reflect.Value to tmpl.Execute works.
+ texts := []string{
+ `{{range .}}{{.String}}{{end}}`,
+ `{{with index . 0}}{{.String}}{{end}}`,
+ }
+ for _, text := range texts {
+ tmpl := Must(New("tmpl").Parse(text))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, reflect.ValueOf([]V{{1}}))
+ if err != nil {
+ t.Fatalf("%s: Execute: %v", text, err)
+ }
+ if buf.String() != "<1>" {
+ t.Fatalf("%s: template output = %q, want %q", text, &buf, "<1>")
+ }
+ }
+}
+
+func TestInterfaceValues(t *testing.T) {
+ // golang.org/issue/17714.
+ // Before index worked on reflect.Values, interface values
+ // were always implicitly promoted to the underlying value,
+ // except that nil interfaces were promoted to the zero reflect.Value.
+ // Eliminating a round trip to interface{} and back to reflect.Value
+ // eliminated this promotion, breaking these cases.
+ tests := []struct {
+ text string
+ out string
+ }{
+ {`{{index .Nil 1}}`, "ERROR: index of untyped nil"},
+ {`{{index .Slice 2}}`, "2"},
+ {`{{index .Slice .Two}}`, "2"},
+ {`{{call .Nil 1}}`, "ERROR: call of nil"},
+ {`{{call .PlusOne 1}}`, "2"},
+ {`{{call .PlusOne .One}}`, "2"},
+ {`{{and (index .Slice 0) true}}`, "0"},
+ {`{{and .Zero true}}`, "0"},
+ {`{{and (index .Slice 1) false}}`, "false"},
+ {`{{and .One false}}`, "false"},
+ {`{{or (index .Slice 0) false}}`, "false"},
+ {`{{or .Zero false}}`, "false"},
+ {`{{or (index .Slice 1) true}}`, "1"},
+ {`{{or .One true}}`, "1"},
+ {`{{not (index .Slice 0)}}`, "true"},
+ {`{{not .Zero}}`, "true"},
+ {`{{not (index .Slice 1)}}`, "false"},
+ {`{{not .One}}`, "false"},
+ {`{{eq (index .Slice 0) .Zero}}`, "true"},
+ {`{{eq (index .Slice 1) .One}}`, "true"},
+ {`{{ne (index .Slice 0) .Zero}}`, "false"},
+ {`{{ne (index .Slice 1) .One}}`, "false"},
+ {`{{ge (index .Slice 0) .One}}`, "false"},
+ {`{{ge (index .Slice 1) .Zero}}`, "true"},
+ {`{{gt (index .Slice 0) .One}}`, "false"},
+ {`{{gt (index .Slice 1) .Zero}}`, "true"},
+ {`{{le (index .Slice 0) .One}}`, "true"},
+ {`{{le (index .Slice 1) .Zero}}`, "false"},
+ {`{{lt (index .Slice 0) .One}}`, "true"},
+ {`{{lt (index .Slice 1) .Zero}}`, "false"},
+ }
+
+ for _, tt := range tests {
+ tmpl := Must(New("tmpl").Parse(tt.text))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, map[string]interface{}{
+ "PlusOne": func(n int) int {
+ return n + 1
+ },
+ "Slice": []int{0, 1, 2, 3},
+ "One": 1,
+ "Two": 2,
+ "Nil": nil,
+ "Zero": 0,
+ })
+ if strings.HasPrefix(tt.out, "ERROR:") {
+ e := strings.TrimSpace(strings.TrimPrefix(tt.out, "ERROR:"))
+ if err == nil || !strings.Contains(err.Error(), e) {
+ t.Errorf("%s: Execute: %v, want error %q", tt.text, err, e)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%s: Execute: %v", tt.text, err)
+ continue
+ }
+ if buf.String() != tt.out {
+ t.Errorf("%s: template output = %q, want %q", tt.text, &buf, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go
index 49e9e7419a..3047b272e5 100644
--- a/libgo/go/text/template/funcs.go
+++ b/libgo/go/text/template/funcs.go
@@ -21,6 +21,12 @@ import (
// which the second has type error. In that case, if the second (error)
// return value evaluates to non-nil during execution, execution terminates and
// Execute returns that error.
+//
+// When template execution invokes a function with an argument list, that list
+// must be assignable to the function's parameter types. Functions meant to
+// apply to arguments of arbitrary type can use parameters of type interface{} or
+// of type reflect.Value. Similarly, functions meant to return a result of arbitrary
+// type can return interface{} or reflect.Value.
type FuncMap map[string]interface{}
var builtins = FuncMap{
@@ -142,18 +148,18 @@ func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error
// Indexing.
// index returns the result of indexing its first argument by the following
-// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
-func index(item interface{}, indices ...interface{}) (interface{}, error) {
- v := reflect.ValueOf(item)
+func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
+ v := indirectInterface(item)
if !v.IsValid() {
- return nil, fmt.Errorf("index of untyped nil")
+ return reflect.Value{}, fmt.Errorf("index of untyped nil")
}
for _, i := range indices {
- index := reflect.ValueOf(i)
+ index := indirectInterface(i)
var isNil bool
if v, isNil = indirect(v); isNil {
- return nil, fmt.Errorf("index of nil pointer")
+ return reflect.Value{}, fmt.Errorf("index of nil pointer")
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
@@ -164,18 +170,18 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
case reflect.Invalid:
- return nil, fmt.Errorf("cannot index slice/array with nil")
+ return reflect.Value{}, fmt.Errorf("cannot index slice/array with nil")
default:
- return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+ return reflect.Value{}, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if x < 0 || x >= int64(v.Len()) {
- return nil, fmt.Errorf("index out of range: %d", x)
+ return reflect.Value{}, fmt.Errorf("index out of range: %d", x)
}
v = v.Index(int(x))
case reflect.Map:
index, err := prepareArg(index, v.Type().Key())
if err != nil {
- return nil, err
+ return reflect.Value{}, err
}
if x := v.MapIndex(index); x.IsValid() {
v = x
@@ -186,10 +192,10 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
// the loop holds invariant: v.IsValid()
panic("unreachable")
default:
- return nil, fmt.Errorf("can't index item of type %s", v.Type())
+ return reflect.Value{}, fmt.Errorf("can't index item of type %s", v.Type())
}
}
- return v.Interface(), nil
+ return v, nil
}
// Length
@@ -215,33 +221,33 @@ func length(item interface{}) (int, error) {
// call returns the result of evaluating the first argument as a function.
// The function must return 1 result, or 2 results, the second of which is an error.
-func call(fn interface{}, args ...interface{}) (interface{}, error) {
- v := reflect.ValueOf(fn)
+func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) {
+ v := indirectInterface(fn)
if !v.IsValid() {
- return nil, fmt.Errorf("call of nil")
+ return reflect.Value{}, fmt.Errorf("call of nil")
}
typ := v.Type()
if typ.Kind() != reflect.Func {
- return nil, fmt.Errorf("non-function of type %s", typ)
+ return reflect.Value{}, fmt.Errorf("non-function of type %s", typ)
}
if !goodFunc(typ) {
- return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
+ return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
}
numIn := typ.NumIn()
var dddType reflect.Type
if typ.IsVariadic() {
if len(args) < numIn-1 {
- return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
+ return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
}
dddType = typ.In(numIn - 1).Elem()
} else {
if len(args) != numIn {
- return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
+ return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
}
}
argv := make([]reflect.Value, len(args))
for i, arg := range args {
- value := reflect.ValueOf(arg)
+ value := indirectInterface(arg)
// Compute the expected type. Clumsy because of variadics.
var argType reflect.Type
if !typ.IsVariadic() || i < numIn-1 {
@@ -252,26 +258,26 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) {
var err error
if argv[i], err = prepareArg(value, argType); err != nil {
- return nil, fmt.Errorf("arg %d: %s", i, err)
+ return reflect.Value{}, fmt.Errorf("arg %d: %s", i, err)
}
}
result := v.Call(argv)
if len(result) == 2 && !result[1].IsNil() {
- return result[0].Interface(), result[1].Interface().(error)
+ return result[0], result[1].Interface().(error)
}
- return result[0].Interface(), nil
+ return result[0], nil
}
// Boolean logic.
-func truth(a interface{}) bool {
- t, _ := IsTrue(a)
+func truth(arg reflect.Value) bool {
+ t, _ := isTrue(indirectInterface(arg))
return t
}
// and computes the Boolean AND of its arguments, returning
// the first false argument it encounters, or the last argument.
-func and(arg0 interface{}, args ...interface{}) interface{} {
+func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
if !truth(arg0) {
return arg0
}
@@ -286,7 +292,7 @@ func and(arg0 interface{}, args ...interface{}) interface{} {
// or computes the Boolean OR of its arguments, returning
// the first true argument it encounters, or the last argument.
-func or(arg0 interface{}, args ...interface{}) interface{} {
+func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
if truth(arg0) {
return arg0
}
@@ -300,7 +306,7 @@ func or(arg0 interface{}, args ...interface{}) interface{} {
}
// not returns the Boolean negation of its argument.
-func not(arg interface{}) bool {
+func not(arg reflect.Value) bool {
return !truth(arg)
}
@@ -322,7 +328,6 @@ const (
complexKind
intKind
floatKind
- integerKind
stringKind
uintKind
)
@@ -346,8 +351,8 @@ func basicKind(v reflect.Value) (kind, error) {
}
// eq evaluates the comparison a == b || a == c || ...
-func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
- v1 := reflect.ValueOf(arg1)
+func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) {
+ v1 := indirectInterface(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
@@ -356,7 +361,7 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
return false, errNoComparison
}
for _, arg := range arg2 {
- v2 := reflect.ValueOf(arg)
+ v2 := indirectInterface(arg)
k2, err := basicKind(v2)
if err != nil {
return false, err
@@ -398,20 +403,20 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
}
// ne evaluates the comparison a != b.
-func ne(arg1, arg2 interface{}) (bool, error) {
+func ne(arg1, arg2 reflect.Value) (bool, error) {
// != is the inverse of ==.
equal, err := eq(arg1, arg2)
return !equal, err
}
// lt evaluates the comparison a < b.
-func lt(arg1, arg2 interface{}) (bool, error) {
- v1 := reflect.ValueOf(arg1)
+func lt(arg1, arg2 reflect.Value) (bool, error) {
+ v1 := indirectInterface(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
- v2 := reflect.ValueOf(arg2)
+ v2 := indirectInterface(arg2)
k2, err := basicKind(v2)
if err != nil {
return false, err
@@ -447,7 +452,7 @@ func lt(arg1, arg2 interface{}) (bool, error) {
}
// le evaluates the comparison <= b.
-func le(arg1, arg2 interface{}) (bool, error) {
+func le(arg1, arg2 reflect.Value) (bool, error) {
// <= is < or ==.
lessThan, err := lt(arg1, arg2)
if lessThan || err != nil {
@@ -457,7 +462,7 @@ func le(arg1, arg2 interface{}) (bool, error) {
}
// gt evaluates the comparison a > b.
-func gt(arg1, arg2 interface{}) (bool, error) {
+func gt(arg1, arg2 reflect.Value) (bool, error) {
// > is the inverse of <=.
lessOrEqual, err := le(arg1, arg2)
if err != nil {
@@ -467,7 +472,7 @@ func gt(arg1, arg2 interface{}) (bool, error) {
}
// ge evaluates the comparison a >= b.
-func ge(arg1, arg2 interface{}) (bool, error) {
+func ge(arg1, arg2 reflect.Value) (bool, error) {
// >= is the inverse of <.
lessThan, err := lt(arg1, arg2)
if err != nil {
@@ -515,7 +520,7 @@ func HTMLEscape(w io.Writer, b []byte) {
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
func HTMLEscapeString(s string) string {
// Avoid allocation if we can.
- if strings.IndexAny(s, `'"&<>`) < 0 {
+ if !strings.ContainsAny(s, `'"&<>`) {
return s
}
var b bytes.Buffer
diff --git a/libgo/go/text/template/helper.go b/libgo/go/text/template/helper.go
index 787ca62e5f..9e0200c352 100644
--- a/libgo/go/text/template/helper.go
+++ b/libgo/go/text/template/helper.go
@@ -29,6 +29,11 @@ func Must(t *Template, err error) *Template {
// the named files. The returned template's name will have the base name and
// parsed contents of the first file. There must be at least one file.
// If an error occurs, parsing stops and the returned *Template is nil.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
+// named "foo", while "a/foo" is unavailable.
func ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(nil, filenames...)
}
@@ -41,6 +46,9 @@ func ParseFiles(filenames ...string) (*Template, error) {
// of the (base) names of the files. If it does not, depending on t's
// contents before calling ParseFiles, t.Execute may fail. In that
// case use t.ExecuteTemplate to execute a valid template.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
t.init()
return parseFiles(t, filenames...)
@@ -88,6 +96,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) {
// returned template will have the (base) name and (parsed) contents of the
// first file matched by the pattern. ParseGlob is equivalent to calling
// ParseFiles with the list of files matched by the pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func ParseGlob(pattern string) (*Template, error) {
return parseGlob(nil, pattern)
}
@@ -97,6 +108,9 @@ func ParseGlob(pattern string) (*Template, error) {
// processed by filepath.Glob and must match at least one file. ParseGlob is
// equivalent to calling t.ParseFiles with the list of files matched by the
// pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func (t *Template) ParseGlob(pattern string) (*Template, error) {
t.init()
return parseGlob(t, pattern)
diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go
index a8342f50aa..5d8c08f06f 100644
--- a/libgo/go/text/template/multi_test.go
+++ b/libgo/go/text/template/multi_test.go
@@ -4,7 +4,7 @@
package template
-// Tests for mulitple-template parsing and execution.
+// Tests for multiple-template parsing and execution.
import (
"bytes"
@@ -349,3 +349,72 @@ func TestParse(t *testing.T) {
t.Fatalf("parsing test: %s", err)
}
}
+
+func TestEmptyTemplate(t *testing.T) {
+ cases := []struct {
+ defn []string
+ in string
+ want string
+ }{
+ {[]string{""}, "once", ""},
+ {[]string{"", ""}, "twice", ""},
+ {[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
+ {[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
+ {[]string{"{{.}}", ""}, "twice", ""},
+ }
+
+ for i, c := range cases {
+ root := New("root")
+
+ var (
+ m *Template
+ err error
+ )
+ for _, d := range c.defn {
+ m, err = root.New(c.in).Parse(d)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ buf := &bytes.Buffer{}
+ if err := m.Execute(buf, c.in); err != nil {
+ t.Error(i, err)
+ continue
+ }
+ if buf.String() != c.want {
+ t.Errorf("expected string %q: got %q", c.want, buf.String())
+ }
+ }
+}
+
+// Issue 19249 was a regression in 1.8 caused by the handling of empty
+// templates added in that release, which got different answers depending
+// on the order templates appeared in the internal map.
+func TestIssue19294(t *testing.T) {
+ // The empty block in "xhtml" should be replaced during execution
+ // by the contents of "stylesheet", but if the internal map associating
+ // names with templates is built in the wrong order, the empty block
+ // looks non-empty and this doesn't happen.
+ var inlined = map[string]string{
+ "stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
+ "xhtml": `{{block "stylesheet" .}}{{end}}`,
+ }
+ all := []string{"stylesheet", "xhtml"}
+ for i := 0; i < 100; i++ {
+ res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, name := range all {
+ _, err := res.New(name).Parse(inlined[name])
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ var buf bytes.Buffer
+ res.Execute(&buf, 0)
+ if buf.String() != "stylesheet" {
+ t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet")
+ }
+ }
+}
diff --git a/libgo/go/text/template/parse/lex.go b/libgo/go/text/template/parse/lex.go
index ea93e05142..6fbf36d7a4 100644
--- a/libgo/go/text/template/parse/lex.go
+++ b/libgo/go/text/template/parse/lex.go
@@ -13,9 +13,10 @@ import (
// item represents a token or text string returned from the scanner.
type item struct {
- typ itemType // The type of this item.
- pos Pos // The starting position, in bytes, of this item in the input string.
- val string // The value of this item.
+ typ itemType // The type of this item.
+ pos Pos // The starting position, in bytes, of this item in the input string.
+ val string // The value of this item.
+ line int // The line number at the start of this item.
}
func (i item) String() string {
@@ -116,6 +117,7 @@ type lexer struct {
lastPos Pos // position of most recent item returned by nextItem
items chan item // channel of scanned items
parenDepth int // nesting depth of ( ) exprs
+ line int // 1+number of newlines seen
}
// next returns the next rune in the input.
@@ -127,6 +129,9 @@ func (l *lexer) next() rune {
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.width = Pos(w)
l.pos += l.width
+ if r == '\n' {
+ l.line++
+ }
return r
}
@@ -140,11 +145,20 @@ func (l *lexer) peek() rune {
// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
l.pos -= l.width
+ // Correct newline count.
+ if l.width == 1 && l.input[l.pos] == '\n' {
+ l.line--
+ }
}
// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
- l.items <- item{t, l.start, l.input[l.start:l.pos]}
+ l.items <- item{t, l.start, l.input[l.start:l.pos], l.line}
+ // Some items contain text internally. If so, count their newlines.
+ switch t {
+ case itemText, itemRawString, itemLeftDelim, itemRightDelim:
+ l.line += strings.Count(l.input[l.start:l.pos], "\n")
+ }
l.start = l.pos
}
@@ -155,7 +169,7 @@ func (l *lexer) ignore() {
// accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool {
- if strings.IndexRune(valid, l.next()) >= 0 {
+ if strings.ContainsRune(valid, l.next()) {
return true
}
l.backup()
@@ -164,22 +178,15 @@ func (l *lexer) accept(valid string) bool {
// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
- for strings.IndexRune(valid, l.next()) >= 0 {
+ for strings.ContainsRune(valid, l.next()) {
}
l.backup()
}
-// lineNumber reports which line we're on, based on the position of
-// the previous item returned by nextItem. Doing it this way
-// means we don't have to worry about peek double counting.
-func (l *lexer) lineNumber() int {
- return 1 + strings.Count(l.input[:l.lastPos], "\n")
-}
-
// errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state, terminating l.nextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
- l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+ l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.line}
return nil
}
@@ -212,6 +219,7 @@ func lex(name, input, left, right string) *lexer {
leftDelim: left,
rightDelim: right,
items: make(chan item),
+ line: 1,
}
go l.run()
return l
@@ -236,24 +244,23 @@ const (
// lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn {
- for {
- delim, trimSpace := l.atLeftDelim()
- if delim {
- trimLength := Pos(0)
- if trimSpace {
- trimLength = rightTrimLength(l.input[l.start:l.pos])
- }
- l.pos -= trimLength
- if l.pos > l.start {
- l.emit(itemText)
- }
- l.pos += trimLength
- l.ignore()
- return lexLeftDelim
+ l.width = 0
+ if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 {
+ ldn := Pos(len(l.leftDelim))
+ l.pos += Pos(x)
+ trimLength := Pos(0)
+ if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) {
+ trimLength = rightTrimLength(l.input[l.start:l.pos])
}
- if l.next() == eof {
- break
+ l.pos -= trimLength
+ if l.pos > l.start {
+ l.emit(itemText)
}
+ l.pos += trimLength
+ l.ignore()
+ return lexLeftDelim
+ } else {
+ l.pos = Pos(len(l.input))
}
// Correctly reached EOF.
if l.pos > l.start {
@@ -263,16 +270,6 @@ func lexText(l *lexer) stateFn {
return nil
}
-// atLeftDelim reports whether the lexer is at a left delimiter, possibly followed by a trim marker.
-func (l *lexer) atLeftDelim() (delim, trimSpaces bool) {
- if !strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
- return false, false
- }
- // The left delim might have the marker afterwards.
- trimSpaces = strings.HasPrefix(l.input[l.pos+Pos(len(l.leftDelim)):], leftTrimMarker)
- return true, trimSpaces
-}
-
// rightTrimLength returns the length of the spaces at the end of the string.
func rightTrimLength(s string) Pos {
return Pos(len(s) - len(strings.TrimRight(s, spaceChars)))
@@ -613,10 +610,14 @@ Loop:
// lexRawQuote scans a raw quoted string.
func lexRawQuote(l *lexer) stateFn {
+ startLine := l.line
Loop:
for {
switch l.next() {
case eof:
+ // Restore line number to location of opening quote.
+ // We will error out so it's ok just to overwrite the field.
+ l.line = startLine
return l.errorf("unterminated raw quoted string")
case '`':
break Loop
diff --git a/libgo/go/text/template/parse/lex_test.go b/libgo/go/text/template/parse/lex_test.go
index e35ebf1a85..d655d788b3 100644
--- a/libgo/go/text/template/parse/lex_test.go
+++ b/libgo/go/text/template/parse/lex_test.go
@@ -58,39 +58,46 @@ type lexTest struct {
items []item
}
+func mkItem(typ itemType, text string) item {
+ return item{
+ typ: typ,
+ val: text,
+ }
+}
+
var (
- tDot = item{itemDot, 0, "."}
- tBlock = item{itemBlock, 0, "block"}
- tEOF = item{itemEOF, 0, ""}
- tFor = item{itemIdentifier, 0, "for"}
- tLeft = item{itemLeftDelim, 0, "{{"}
- tLpar = item{itemLeftParen, 0, "("}
- tPipe = item{itemPipe, 0, "|"}
- tQuote = item{itemString, 0, `"abc \n\t\" "`}
- tRange = item{itemRange, 0, "range"}
- tRight = item{itemRightDelim, 0, "}}"}
- tRpar = item{itemRightParen, 0, ")"}
- tSpace = item{itemSpace, 0, " "}
+ tDot = mkItem(itemDot, ".")
+ tBlock = mkItem(itemBlock, "block")
+ tEOF = mkItem(itemEOF, "")
+ tFor = mkItem(itemIdentifier, "for")
+ tLeft = mkItem(itemLeftDelim, "{{")
+ tLpar = mkItem(itemLeftParen, "(")
+ tPipe = mkItem(itemPipe, "|")
+ tQuote = mkItem(itemString, `"abc \n\t\" "`)
+ tRange = mkItem(itemRange, "range")
+ tRight = mkItem(itemRightDelim, "}}")
+ tRpar = mkItem(itemRightParen, ")")
+ tSpace = mkItem(itemSpace, " ")
raw = "`" + `abc\n\t\" ` + "`"
rawNL = "`now is{{\n}}the time`" // Contains newline inside raw quote.
- tRawQuote = item{itemRawString, 0, raw}
- tRawQuoteNL = item{itemRawString, 0, rawNL}
+ tRawQuote = mkItem(itemRawString, raw)
+ tRawQuoteNL = mkItem(itemRawString, rawNL)
)
var lexTests = []lexTest{
{"empty", "", []item{tEOF}},
- {"spaces", " \t\n", []item{{itemText, 0, " \t\n"}, tEOF}},
- {"text", `now is the time`, []item{{itemText, 0, "now is the time"}, tEOF}},
+ {"spaces", " \t\n", []item{mkItem(itemText, " \t\n"), tEOF}},
+ {"text", `now is the time`, []item{mkItem(itemText, "now is the time"), tEOF}},
{"text with comment", "hello-{{/* this is a comment */}}-world", []item{
- {itemText, 0, "hello-"},
- {itemText, 0, "-world"},
+ mkItem(itemText, "hello-"),
+ mkItem(itemText, "-world"),
tEOF,
}},
{"punctuation", "{{,@% }}", []item{
tLeft,
- {itemChar, 0, ","},
- {itemChar, 0, "@"},
- {itemChar, 0, "%"},
+ mkItem(itemChar, ","),
+ mkItem(itemChar, "@"),
+ mkItem(itemChar, "%"),
tSpace,
tRight,
tEOF,
@@ -99,7 +106,7 @@ var lexTests = []lexTest{
tLeft,
tLpar,
tLpar,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRpar,
tRpar,
tRight,
@@ -108,54 +115,54 @@ var lexTests = []lexTest{
{"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
{"block", `{{block "foo" .}}`, []item{
- tLeft, tBlock, tSpace, {itemString, 0, `"foo"`}, tSpace, tDot, tRight, tEOF,
+ tLeft, tBlock, tSpace, mkItem(itemString, `"foo"`), tSpace, tDot, tRight, tEOF,
}},
{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
tLeft,
- {itemNumber, 0, "1"},
+ mkItem(itemNumber, "1"),
tSpace,
- {itemNumber, 0, "02"},
+ mkItem(itemNumber, "02"),
tSpace,
- {itemNumber, 0, "0x14"},
+ mkItem(itemNumber, "0x14"),
tSpace,
- {itemNumber, 0, "-7.2i"},
+ mkItem(itemNumber, "-7.2i"),
tSpace,
- {itemNumber, 0, "1e3"},
+ mkItem(itemNumber, "1e3"),
tSpace,
- {itemNumber, 0, "+1.2e-4"},
+ mkItem(itemNumber, "+1.2e-4"),
tSpace,
- {itemNumber, 0, "4.2i"},
+ mkItem(itemNumber, "4.2i"),
tSpace,
- {itemComplex, 0, "1+2i"},
+ mkItem(itemComplex, "1+2i"),
tRight,
tEOF,
}},
{"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
tLeft,
- {itemCharConstant, 0, `'a'`},
+ mkItem(itemCharConstant, `'a'`),
tSpace,
- {itemCharConstant, 0, `'\n'`},
+ mkItem(itemCharConstant, `'\n'`),
tSpace,
- {itemCharConstant, 0, `'\''`},
+ mkItem(itemCharConstant, `'\''`),
tSpace,
- {itemCharConstant, 0, `'\\'`},
+ mkItem(itemCharConstant, `'\\'`),
tSpace,
- {itemCharConstant, 0, `'\u00FF'`},
+ mkItem(itemCharConstant, `'\u00FF'`),
tSpace,
- {itemCharConstant, 0, `'\xFF'`},
+ mkItem(itemCharConstant, `'\xFF'`),
tSpace,
- {itemCharConstant, 0, `'本'`},
+ mkItem(itemCharConstant, `'本'`),
tRight,
tEOF,
}},
{"bools", "{{true false}}", []item{
tLeft,
- {itemBool, 0, "true"},
+ mkItem(itemBool, "true"),
tSpace,
- {itemBool, 0, "false"},
+ mkItem(itemBool, "false"),
tRight,
tEOF,
}},
@@ -167,178 +174,178 @@ var lexTests = []lexTest{
}},
{"nil", "{{nil}}", []item{
tLeft,
- {itemNil, 0, "nil"},
+ mkItem(itemNil, "nil"),
tRight,
tEOF,
}},
{"dots", "{{.x . .2 .x.y.z}}", []item{
tLeft,
- {itemField, 0, ".x"},
+ mkItem(itemField, ".x"),
tSpace,
tDot,
tSpace,
- {itemNumber, 0, ".2"},
+ mkItem(itemNumber, ".2"),
tSpace,
- {itemField, 0, ".x"},
- {itemField, 0, ".y"},
- {itemField, 0, ".z"},
+ mkItem(itemField, ".x"),
+ mkItem(itemField, ".y"),
+ mkItem(itemField, ".z"),
tRight,
tEOF,
}},
{"keywords", "{{range if else end with}}", []item{
tLeft,
- {itemRange, 0, "range"},
+ mkItem(itemRange, "range"),
tSpace,
- {itemIf, 0, "if"},
+ mkItem(itemIf, "if"),
tSpace,
- {itemElse, 0, "else"},
+ mkItem(itemElse, "else"),
tSpace,
- {itemEnd, 0, "end"},
+ mkItem(itemEnd, "end"),
tSpace,
- {itemWith, 0, "with"},
+ mkItem(itemWith, "with"),
tRight,
tEOF,
}},
{"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
tLeft,
- {itemVariable, 0, "$c"},
+ mkItem(itemVariable, "$c"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemIdentifier, 0, "printf"},
+ mkItem(itemIdentifier, "printf"),
tSpace,
- {itemVariable, 0, "$"},
+ mkItem(itemVariable, "$"),
tSpace,
- {itemVariable, 0, "$hello"},
+ mkItem(itemVariable, "$hello"),
tSpace,
- {itemVariable, 0, "$23"},
+ mkItem(itemVariable, "$23"),
tSpace,
- {itemVariable, 0, "$"},
+ mkItem(itemVariable, "$"),
tSpace,
- {itemVariable, 0, "$var"},
- {itemField, 0, ".Field"},
+ mkItem(itemVariable, "$var"),
+ mkItem(itemField, ".Field"),
tSpace,
- {itemField, 0, ".Method"},
+ mkItem(itemField, ".Method"),
tRight,
tEOF,
}},
{"variable invocation", "{{$x 23}}", []item{
tLeft,
- {itemVariable, 0, "$x"},
+ mkItem(itemVariable, "$x"),
tSpace,
- {itemNumber, 0, "23"},
+ mkItem(itemNumber, "23"),
tRight,
tEOF,
}},
{"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
- {itemText, 0, "intro "},
+ mkItem(itemText, "intro "),
tLeft,
- {itemIdentifier, 0, "echo"},
+ mkItem(itemIdentifier, "echo"),
tSpace,
- {itemIdentifier, 0, "hi"},
+ mkItem(itemIdentifier, "hi"),
tSpace,
- {itemNumber, 0, "1.2"},
+ mkItem(itemNumber, "1.2"),
tSpace,
tPipe,
- {itemIdentifier, 0, "noargs"},
+ mkItem(itemIdentifier, "noargs"),
tPipe,
- {itemIdentifier, 0, "args"},
+ mkItem(itemIdentifier, "args"),
tSpace,
- {itemNumber, 0, "1"},
+ mkItem(itemNumber, "1"),
tSpace,
- {itemString, 0, `"hi"`},
+ mkItem(itemString, `"hi"`),
tRight,
- {itemText, 0, " outro"},
+ mkItem(itemText, " outro"),
tEOF,
}},
{"declaration", "{{$v := 3}}", []item{
tLeft,
- {itemVariable, 0, "$v"},
+ mkItem(itemVariable, "$v"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
tEOF,
}},
{"2 declarations", "{{$v , $w := 3}}", []item{
tLeft,
- {itemVariable, 0, "$v"},
+ mkItem(itemVariable, "$v"),
tSpace,
- {itemChar, 0, ","},
+ mkItem(itemChar, ","),
tSpace,
- {itemVariable, 0, "$w"},
+ mkItem(itemVariable, "$w"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
tEOF,
}},
{"field of parenthesized expression", "{{(.X).Y}}", []item{
tLeft,
tLpar,
- {itemField, 0, ".X"},
+ mkItem(itemField, ".X"),
tRpar,
- {itemField, 0, ".Y"},
+ mkItem(itemField, ".Y"),
tRight,
tEOF,
}},
{"trimming spaces before and after", "hello- {{- 3 -}} -world", []item{
- {itemText, 0, "hello-"},
+ mkItem(itemText, "hello-"),
tLeft,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
- {itemText, 0, "-world"},
+ mkItem(itemText, "-world"),
tEOF,
}},
{"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{
- {itemText, 0, "hello-"},
- {itemText, 0, "-world"},
+ mkItem(itemText, "hello-"),
+ mkItem(itemText, "-world"),
tEOF,
}},
// errors
{"badchar", "#{{\x01}}", []item{
- {itemText, 0, "#"},
+ mkItem(itemText, "#"),
tLeft,
- {itemError, 0, "unrecognized character in action: U+0001"},
+ mkItem(itemError, "unrecognized character in action: U+0001"),
}},
{"unclosed action", "{{\n}}", []item{
tLeft,
- {itemError, 0, "unclosed action"},
+ mkItem(itemError, "unclosed action"),
}},
{"EOF in action", "{{range", []item{
tLeft,
tRange,
- {itemError, 0, "unclosed action"},
+ mkItem(itemError, "unclosed action"),
}},
{"unclosed quote", "{{\"\n\"}}", []item{
tLeft,
- {itemError, 0, "unterminated quoted string"},
+ mkItem(itemError, "unterminated quoted string"),
}},
{"unclosed raw quote", "{{`xx}}", []item{
tLeft,
- {itemError, 0, "unterminated raw quoted string"},
+ mkItem(itemError, "unterminated raw quoted string"),
}},
{"unclosed char constant", "{{'\n}}", []item{
tLeft,
- {itemError, 0, "unterminated character constant"},
+ mkItem(itemError, "unterminated character constant"),
}},
{"bad number", "{{3k}}", []item{
tLeft,
- {itemError, 0, `bad number syntax: "3k"`},
+ mkItem(itemError, `bad number syntax: "3k"`),
}},
{"unclosed paren", "{{(3}}", []item{
tLeft,
tLpar,
- {itemNumber, 0, "3"},
- {itemError, 0, `unclosed left paren`},
+ mkItem(itemNumber, "3"),
+ mkItem(itemError, `unclosed left paren`),
}},
{"extra right paren", "{{3)}}", []item{
tLeft,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRpar,
- {itemError, 0, `unexpected right paren U+0029 ')'`},
+ mkItem(itemError, `unexpected right paren U+0029 ')'`),
}},
// Fixed bugs
@@ -355,17 +362,17 @@ var lexTests = []lexTest{
tEOF,
}},
{"text with bad comment", "hello-{{/*/}}-world", []item{
- {itemText, 0, "hello-"},
- {itemError, 0, `unclosed comment`},
+ mkItem(itemText, "hello-"),
+ mkItem(itemError, `unclosed comment`),
}},
{"text with comment close separated from delim", "hello-{{/* */ }}-world", []item{
- {itemText, 0, "hello-"},
- {itemError, 0, `comment ends before closing delimiter`},
+ mkItem(itemText, "hello-"),
+ mkItem(itemError, `comment ends before closing delimiter`),
}},
// This one is an error that we can't catch because it breaks templates with
// minimized JavaScript. Should have fixed it before Go 1.1.
{"unmatched right delimiter", "hello-{.}}-world", []item{
- {itemText, 0, "hello-{.}}-world"},
+ mkItem(itemText, "hello-{.}}-world"),
tEOF,
}},
}
@@ -414,13 +421,13 @@ func TestLex(t *testing.T) {
var lexDelimTests = []lexTest{
{"punctuation", "$$,@%{{}}@@", []item{
tLeftDelim,
- {itemChar, 0, ","},
- {itemChar, 0, "@"},
- {itemChar, 0, "%"},
- {itemChar, 0, "{"},
- {itemChar, 0, "{"},
- {itemChar, 0, "}"},
- {itemChar, 0, "}"},
+ mkItem(itemChar, ","),
+ mkItem(itemChar, "@"),
+ mkItem(itemChar, "%"),
+ mkItem(itemChar, "{"),
+ mkItem(itemChar, "{"),
+ mkItem(itemChar, "}"),
+ mkItem(itemChar, "}"),
tRightDelim,
tEOF,
}},
@@ -431,8 +438,8 @@ var lexDelimTests = []lexTest{
}
var (
- tLeftDelim = item{itemLeftDelim, 0, "$$"}
- tRightDelim = item{itemRightDelim, 0, "@@"}
+ tLeftDelim = mkItem(itemLeftDelim, "$$")
+ tRightDelim = mkItem(itemRightDelim, "@@")
)
func TestDelims(t *testing.T) {
@@ -447,21 +454,21 @@ func TestDelims(t *testing.T) {
var lexPosTests = []lexTest{
{"empty", "", []item{tEOF}},
{"punctuation", "{{,@%#}}", []item{
- {itemLeftDelim, 0, "{{"},
- {itemChar, 2, ","},
- {itemChar, 3, "@"},
- {itemChar, 4, "%"},
- {itemChar, 5, "#"},
- {itemRightDelim, 6, "}}"},
- {itemEOF, 8, ""},
+ {itemLeftDelim, 0, "{{", 1},
+ {itemChar, 2, ",", 1},
+ {itemChar, 3, "@", 1},
+ {itemChar, 4, "%", 1},
+ {itemChar, 5, "#", 1},
+ {itemRightDelim, 6, "}}", 1},
+ {itemEOF, 8, "", 1},
}},
{"sample", "0123{{hello}}xyz", []item{
- {itemText, 0, "0123"},
- {itemLeftDelim, 4, "{{"},
- {itemIdentifier, 6, "hello"},
- {itemRightDelim, 11, "}}"},
- {itemText, 13, "xyz"},
- {itemEOF, 16, ""},
+ {itemText, 0, "0123", 1},
+ {itemLeftDelim, 4, "{{", 1},
+ {itemIdentifier, 6, "hello", 1},
+ {itemRightDelim, 11, "}}", 1},
+ {itemText, 13, "xyz", 1},
+ {itemEOF, 16, "", 1},
}},
}
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index dc56cf7aa0..6060c6d74b 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -48,12 +48,12 @@ func (t *Tree) Copy() *Tree {
// templates described in the argument string. The top-level template will be
// given the specified name. If an error is encountered, parsing stops and an
// empty map is returned with the error.
-func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
- treeSet = make(map[string]*Tree)
+func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) {
+ treeSet := make(map[string]*Tree)
t := New(name)
t.text = text
- _, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
- return
+ _, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
+ return treeSet, err
}
// next returns the next token.
@@ -157,7 +157,7 @@ func (t *Tree) ErrorContext(n Node) (location, context string) {
// errorf formats the error and terminates processing.
func (t *Tree) errorf(format string, args ...interface{}) {
t.Root = nil
- format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
+ format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
panic(fmt.Errorf(format, args...))
}
@@ -277,7 +277,7 @@ func IsEmptyTree(n Node) bool {
// parse is the top-level parser for a template, essentially the same
// as itemList except it also parses {{define}} actions.
// It runs to EOF.
-func (t *Tree) parse() (next Node) {
+func (t *Tree) parse() {
t.Root = t.newList(t.peek().pos)
for t.peek().typ != itemEOF {
if t.peek().typ == itemLeftDelim {
@@ -299,7 +299,6 @@ func (t *Tree) parse() (next Node) {
t.Root.append(n)
}
}
- return nil
}
// parseDefinition parses a {{define}} ... {{end}} template definition and
@@ -377,15 +376,17 @@ func (t *Tree) action() (n Node) {
return t.withControl()
}
t.backup()
+ token := t.peek()
// Do not pop variables; they persist until "end".
- return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
+ return t.newAction(token.pos, token.line, t.pipeline("command"))
}
// Pipeline:
// declarations? command ('|' command)*
func (t *Tree) pipeline(context string) (pipe *PipeNode) {
var decl []*VariableNode
- pos := t.peekNonSpace().pos
+ token := t.peekNonSpace()
+ pos := token.pos
// Are there declarations?
for {
if v := t.peekNonSpace(); v.typ == itemVariable {
@@ -414,7 +415,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
}
break
}
- pipe = t.newPipeline(pos, t.lex.lineNumber(), decl)
+ pipe = t.newPipeline(pos, token.line, decl)
for {
switch token := t.nextNonSpace(); token.typ {
case itemRightDelim, itemRightParen:
@@ -451,7 +452,6 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
defer t.popVars(len(t.vars))
- line = t.lex.lineNumber()
pipe = t.pipeline(context)
var next Node
list, next = t.itemList()
@@ -480,7 +480,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
t.errorf("expected end; found %s", next)
}
}
- return pipe.Position(), line, pipe, list, elseList
+ return pipe.Position(), pipe.Line, pipe, list, elseList
}
// If:
@@ -522,9 +522,10 @@ func (t *Tree) elseControl() Node {
peek := t.peekNonSpace()
if peek.typ == itemIf {
// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
- return t.newElse(peek.pos, t.lex.lineNumber())
+ return t.newElse(peek.pos, peek.line)
}
- return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
+ token := t.expect(itemRightDelim, "else")
+ return t.newElse(token.pos, token.line)
}
// Block:
@@ -551,12 +552,12 @@ func (t *Tree) blockControl() Node {
block.add()
block.stopParse()
- return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+ return t.newTemplate(token.pos, token.line, name, pipe)
}
// Template:
// {{template stringValue pipeline}}
-// Template keyword is past. The name must be something that can evaluate
+// Template keyword is past. The name must be something that can evaluate
// to a string.
func (t *Tree) templateControl() Node {
const context = "template clause"
@@ -568,7 +569,7 @@ func (t *Tree) templateControl() Node {
// Do not pop variables; they persist until "end".
pipe = t.pipeline(context)
}
- return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+ return t.newTemplate(token.pos, token.line, name, pipe)
}
func (t *Tree) parseTemplateName(token item, context string) (name string) {
diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go
index b4512d3160..81f14aca98 100644
--- a/libgo/go/text/template/parse/parse_test.go
+++ b/libgo/go/text/template/parse/parse_test.go
@@ -76,7 +76,7 @@ var numberTests = []numberTest{
func TestNumberParse(t *testing.T) {
for _, test := range numberTests {
- // If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
+ // If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
// because imaginary comes out as a number.
var c complex128
typ := itemNumber
@@ -484,3 +484,37 @@ func TestBlock(t *testing.T) {
t.Errorf("inner template = %q, want %q", g, w)
}
}
+
+func TestLineNum(t *testing.T) {
+ const count = 100
+ text := strings.Repeat("{{printf 1234}}\n", count)
+ tree, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Check the line numbers. Each line is an action containing a template, followed by text.
+ // That's two nodes per line.
+ nodes := tree.Root.Nodes
+ for i := 0; i < len(nodes); i += 2 {
+ line := 1 + i/2
+ // Action first.
+ action := nodes[i].(*ActionNode)
+ if action.Line != line {
+ t.Fatalf("line %d: action is line %d", line, action.Line)
+ }
+ pipe := action.Pipe
+ if pipe.Line != line {
+ t.Fatalf("line %d: pipe is line %d", line, pipe.Line)
+ }
+ }
+}
+
+func BenchmarkParseLarge(b *testing.B) {
+ text := strings.Repeat("{{1234}}\n", 10000)
+ for i := 0; i < b.N; i++ {
+ _, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go
index 7a7f42a715..3b4f34b4db 100644
--- a/libgo/go/text/template/template.go
+++ b/libgo/go/text/template/template.go
@@ -127,7 +127,7 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error
// Even if nt == t, we need to install it in the common.tmpl map.
if replace, err := t.associate(nt, tree); err != nil {
return nil, err
- } else if replace {
+ } else if replace || nt.Tree == nil {
nt.Tree = tree
}
return nt, nil
@@ -181,9 +181,16 @@ func (t *Template) Lookup(name string) *Template {
return t.tmpl[name]
}
-// Parse defines the template by parsing the text. Nested template definitions will be
-// associated with the top-level template t. Parse may be called multiple times
-// to parse definitions of templates to associate with t.
+// Parse parses text as a template body for t.
+// Named template definitions ({{define ...}} or {{block ...}} statements) in text
+// define additional templates associated with t and are removed from the
+// definition of t itself.
+//
+// Templates can be redefined in successive calls to Parse.
+// A template definition with a body containing only white space and comments
+// is considered empty and will not replace an existing template's body.
+// This allows using Parse to add new named template definitions without
+// overwriting the main template body.
func (t *Template) Parse(text string) (*Template, error) {
t.init()
t.muFuncs.RLock()
@@ -208,7 +215,7 @@ func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
if new.common != t.common {
panic("internal error: associate not common")
}
- if t.tmpl[new.name] != nil && parse.IsEmptyTree(tree.Root) {
+ if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil {
// If a template by that name exists,
// don't replace it with an empty template.
return false, nil
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index f76fdcd4d0..7dc2bb5e7e 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 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.
@@ -251,20 +251,18 @@ func ExampleTime_Truncate() {
2 * time.Second,
time.Minute,
10 * time.Minute,
- time.Hour,
}
for _, d := range trunc {
- fmt.Printf("t.Truncate(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
+ fmt.Printf("t.Truncate(%5s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
}
// Output:
- // t.Truncate( 1ns) = 12:15:30.918273645
- // t.Truncate( 1µs) = 12:15:30.918273
- // t.Truncate( 1ms) = 12:15:30.918
- // t.Truncate( 1s) = 12:15:30
- // t.Truncate( 2s) = 12:15:30
- // t.Truncate( 1m0s) = 12:15:00
- // t.Truncate( 10m0s) = 12:10:00
- // t.Truncate(1h0m0s) = 12:00:00
+ // t.Truncate( 1ns) = 12:15:30.918273645
+ // t.Truncate( 1µs) = 12:15:30.918273
+ // t.Truncate( 1ms) = 12:15:30.918
+ // t.Truncate( 1s) = 12:15:30
+ // t.Truncate( 2s) = 12:15:30
+ // t.Truncate( 1m0s) = 12:15:00
+ // t.Truncate(10m0s) = 12:10:00
}
diff --git a/libgo/go/time/export_android_test.go b/libgo/go/time/export_android_test.go
new file mode 100644
index 0000000000..fa6a058a73
--- /dev/null
+++ b/libgo/go/time/export_android_test.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func ForceAndroidTzdataForTest(tzdata bool) {
+ tzdataPaths = origTzdataPaths
+ if tzdata {
+ tzdataPaths = tzdataPaths[:1]
+ }
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index e616feb048..b903e1485c 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -23,7 +23,7 @@ import "errors"
// compatibility with fixed-width Unix time formats.
//
// A decimal point followed by one or more zeros represents a fractional
-// second, printed to the given number of decimal places. A decimal point
+// second, printed to the given number of decimal places. A decimal point
// followed by one or more nines represents a fractional second, printed to
// the given number of decimal places, with trailing zeros removed.
// When parsing (only), the input may contain a fractional second
@@ -37,11 +37,18 @@ import "errors"
// -07 ±hh
// Replacing the sign in the format with a Z triggers
// the ISO 8601 behavior of printing Z instead of an
-// offset for the UTC zone. Thus:
+// offset for the UTC zone. Thus:
// Z0700 Z or ±hhmm
// Z07:00 Z or ±hh:mm
// Z07 Z or ±hh
//
+// The recognized day of week formats are "Mon" and "Monday".
+// The recognized month formats are "Jan" and "January".
+//
+// Text in the format string that is not recognized as part of the reference
+// time is echoed verbatim during Format and expected to appear verbatim
+// in the input to Parse.
+//
// The executable example for time.Format demonstrates the working
// of the layout string in detail and is a good reference.
//
@@ -51,6 +58,9 @@ import "errors"
// use of "GMT" in that case.
// In general RFC1123Z should be used instead of RFC1123 for servers
// that insist on that format, and RFC3339 should be preferred for new protocols.
+// RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
+// when used with time.Parse they do not accept all the time formats
+// permitted by the RFCs.
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
@@ -551,7 +561,7 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
b = append(b, "am"...)
}
case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
- // Ugly special case. We cheat and take the "Z" variants
+ // Ugly special case. We cheat and take the "Z" variants
// to mean "the time zone as formatted for ISO 8601".
if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
b = append(b, 'Z')
@@ -841,6 +851,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
sec, value, err = getnum(value, std == stdZeroSecond)
if sec < 0 || 60 <= sec {
rangeErrString = "second"
+ break
}
// Special case: do we have a fractional second but no
// fractional second in the format?
@@ -1001,7 +1012,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
}
// Validate the day of the month.
- if day > daysIn(Month(month), year) {
+ if day < 1 || day > daysIn(Month(month), year) {
return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
}
@@ -1017,12 +1028,12 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
// If that zone was in effect at the given time, use it.
name, offset, _, _, _ := local.lookup(t.sec + internalToUnix)
if offset == zoneOffset && (zoneName == "" || name == zoneName) {
- t.loc = local
+ t.setLoc(local)
return t, nil
}
// Otherwise create fake zone to record offset.
- t.loc = FixedZone(zoneName, zoneOffset)
+ t.setLoc(FixedZone(zoneName, zoneOffset))
return t, nil
}
@@ -1033,7 +1044,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _, ok := local.lookupName(zoneName, t.sec+internalToUnix)
if ok {
t.sec -= int64(offset)
- t.loc = local
+ t.setLoc(local)
return t, nil
}
@@ -1042,7 +1053,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT.
offset *= 3600
}
- t.loc = FixedZone(zoneName, offset)
+ t.setLoc(FixedZone(zoneName, offset))
return t, nil
}
@@ -1090,8 +1101,9 @@ func parseTimeZone(value string) (length int, ok bool) {
if value[4] == 'T' {
return 5, true
}
- case 4: // Must end in T to match.
- if value[3] == 'T' {
+ case 4:
+ // Must end in T, except one special case.
+ if value[3] == 'T' || value[:4] == "WITA" {
return 4, true
}
case 3:
@@ -1170,6 +1182,37 @@ func leadingInt(s string) (x int64, rem string, err error) {
return x, s[i:], nil
}
+// leadingFraction consumes the leading [0-9]* from s.
+// It is used only for fractions, so does not return an error on overflow,
+// it just stops accumulating precision.
+func leadingFraction(s string) (x int64, scale float64, rem string) {
+ i := 0
+ scale = 1
+ overflow := false
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if overflow {
+ continue
+ }
+ if x > (1<<63-1)/10 {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true
+ continue
+ }
+ y := x*10 + int64(c) - '0'
+ if y < 0 {
+ overflow = true
+ continue
+ }
+ x = y
+ scale *= 10
+ }
+ return x, scale, s[i:]
+}
+
var unitMap = map[string]int64{
"ns": int64(Nanosecond),
"us": int64(Microsecond),
@@ -1232,13 +1275,7 @@ func ParseDuration(s string) (Duration, error) {
if s != "" && s[0] == '.' {
s = s[1:]
pl := len(s)
- f, s, err = leadingInt(s)
- if err != nil {
- return 0, errors.New("time: invalid duration " + orig)
- }
- for n := pl - len(s); n > 0; n-- {
- scale *= 10
- }
+ f, scale, s = leadingFraction(s)
post = pl != len(s)
}
if !pre && !post {
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
index a2592e2ceb..0e4a417430 100644
--- a/libgo/go/time/format_test.go
+++ b/libgo/go/time/format_test.go
@@ -224,6 +224,7 @@ var dayOutOfRangeTests = []struct {
{"Thu Nov 31 21:00:57 2010", false},
{"Thu Dec 31 21:00:57 2010", true},
{"Thu Dec 32 21:00:57 2010", false},
+ {"Thu Dec 00 21:00:57 2010", false},
}
func TestParseDayOutOfRange(t *testing.T) {
@@ -244,27 +245,45 @@ func TestParseDayOutOfRange(t *testing.T) {
}
}
+// TestParseInLocation checks that the Parse and ParseInLocation
+// functions do not get confused by the fact that AST (Arabia Standard
+// Time) and AST (Atlantic Standard Time) are different time zones,
+// even though they have the same abbreviation.
+//
+// ICANN has been slowly phasing out invented abbreviation in favor of
+// numeric time zones (for example, the Asia/Baghdad time zone
+// abbreviation got changed from AST to +03 in the 2017a tzdata
+// release); but we still want to make sure that the time package does
+// not get confused on systems with slightly older tzdata packages.
func TestParseInLocation(t *testing.T) {
- // Check that Parse (and ParseInLocation) understand that
- // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time)
- // are in different time zones even though both are called AST
baghdad, err := LoadLocation("Asia/Baghdad")
if err != nil {
t.Fatal(err)
}
- t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
+ var t1, t2 Time
+
+ t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
if err != nil {
t.Fatal(err)
}
- t2 := Date(2013, February, 1, 00, 00, 00, 0, baghdad)
- if t1 != t2 {
- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
- }
+
_, offset := t1.Zone()
- if offset != 3*60*60 {
- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
+
+ // A zero offset means that ParseInLocation did not recognize the
+ // 'AST' abbreviation as matching the current location (Baghdad,
+ // where we'd expect a +03 hrs offset); likely because we're using
+ // a recent tzdata release (2017a or newer).
+ // If it happens, skip the Baghdad test.
+ if offset != 0 {
+ t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad)
+ if t1 != t2 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
+ }
+ if offset != 3*60*60 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
+ }
}
blancSablon, err := LoadLocation("America/Blanc-Sablon")
@@ -272,6 +291,9 @@ func TestParseInLocation(t *testing.T) {
t.Fatal(err)
}
+ // In this case 'AST' means 'Atlantic Standard Time', and we
+ // expect the abbreviation to correctly match the american
+ // location.
t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
if err != nil {
t.Fatal(err)
@@ -406,6 +428,7 @@ var parseTimeZoneTests = []ParseTimeZoneTest{
{"ESAST hi", 5, true},
{"ESASTT hi", 0, false}, // run of upper-case letters too long.
{"ESATY hi", 0, false}, // five letters must end in T.
+ {"WITA hi", 4, true}, // Issue #18251
}
func TestParseTimeZone(t *testing.T) {
@@ -442,6 +465,8 @@ var parseErrorTests = []ParseErrorTest{
{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+ // invalid second followed by optional fractional seconds
+ {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
}
func TestParseErrors(t *testing.T) {
@@ -449,7 +474,7 @@ func TestParseErrors(t *testing.T) {
_, err := Parse(test.format, test.value)
if err == nil {
t.Errorf("expected error for %q %q", test.format, test.value)
- } else if strings.Index(err.Error(), test.expect) < 0 {
+ } else if !strings.Contains(err.Error(), test.expect) {
t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
}
}
diff --git a/libgo/go/time/genzabbrs.go b/libgo/go/time/genzabbrs.go
index 9eb0728a42..6281f73ce4 100644
--- a/libgo/go/time/genzabbrs.go
+++ b/libgo/go/time/genzabbrs.go
@@ -30,7 +30,7 @@ var filename = flag.String("output", "zoneinfo_abbrs_windows.go", "output file n
// getAbbrs finds timezone abbreviations (standard and daylight saving time)
// for location l.
func getAbbrs(l *time.Location) (st, dt string) {
- t := time.Date(time.Now().Year(), 0, 0, 0, 0, 0, 0, l)
+ t := time.Date(time.Now().Year(), 0, 1, 0, 0, 0, 0, l)
abbr1, off1 := t.Zone()
for i := 0; i < 12; i++ {
t = t.AddDate(0, 1, 0)
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index e7a2ee2059..4b01404896 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -12,7 +12,7 @@ func Sleep(d Duration)
func runtimeNano() int64
// Interface to timers implemented in package runtime.
-// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Must be in sync with ../runtime/time.go:/^type timer
type runtimeTimer struct {
i int
when int64
@@ -24,7 +24,7 @@ type runtimeTimer struct {
// when is a helper function for setting the 'when' field of a runtimeTimer.
// It returns what the time will be, in nanoseconds, Duration d in the future.
-// If d is negative, it is ignored. If the returned value would be less than
+// If d is negative, it is ignored. If the returned value would be less than
// zero because of an overflow, MaxInt64 is returned.
func when(d Duration) int64 {
if d <= 0 {
@@ -54,6 +54,23 @@ type Timer struct {
// expired or been stopped.
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
+//
+// To prevent a timer created with NewTimer from firing after a call to Stop,
+// check the return value and drain the channel.
+// For example, assuming the program has not received from t.C already:
+//
+// if !t.Stop() {
+// <-t.C
+// }
+//
+// This cannot be done concurrent to other receives from the Timer's
+// channel.
+//
+// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer
+// has already expired and the function f has been started in its own goroutine;
+// Stop does not wait for f to complete before returning.
+// If the caller needs to know whether f is completed, it must coordinate
+// with f explicitly.
func (t *Timer) Stop() bool {
if t.r.f == nil {
panic("time: Stop called on uninitialized Timer")
@@ -80,6 +97,27 @@ func NewTimer(d Duration) *Timer {
// Reset changes the timer to expire after duration d.
// It returns true if the timer had been active, false if the timer had
// expired or been stopped.
+//
+// Resetting a timer must take care not to race with the send into t.C
+// that happens when the current timer expires.
+// If a program has already received a value from t.C, the timer is known
+// to have expired, and t.Reset can be used directly.
+// If a program has not yet received a value from t.C, however,
+// the timer must be stopped and—if Stop reports that the timer expired
+// before being stopped—the channel explicitly drained:
+//
+// if !t.Stop() {
+// <-t.C
+// }
+// t.Reset(d)
+//
+// This should not be done concurrent to other receives from the Timer's
+// channel.
+//
+// Note that it is not possible to use Reset's return value correctly, as there
+// is a race condition between draining the channel and the new timer expiring.
+// Reset should always be invoked on stopped or expired channels, as described above.
+// The return value exists to preserve compatibility with existing programs.
func (t *Timer) Reset(d Duration) bool {
if t.r.f == nil {
panic("time: Reset called on uninitialized Timer")
@@ -106,6 +144,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
}
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
index 8484729448..11365a791f 100644
--- a/libgo/go/time/sys_plan9.go
+++ b/libgo/go/time/sys_plan9.go
@@ -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
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index e592415daa..91d54c9ffd 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -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
diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go
index de63b4bf4b..a4a068f784 100644
--- a/libgo/go/time/sys_windows.go
+++ b/libgo/go/time/sys_windows.go
@@ -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
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index 196e8ac61a..3d693206a5 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -39,7 +39,7 @@ func NewTicker(d Duration) *Ticker {
return t
}
-// Stop turns off a ticker. After Stop, no more ticks will be sent.
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
func (t *Ticker) Stop() {
@@ -50,6 +50,7 @@ func (t *Ticker) Stop() {
// channel only. While Tick is useful for clients that have no need to shut down
// the Ticker, be aware that without a way to shut it down the underlying
// Ticker cannot be recovered by the garbage collector; it "leaks".
+// Unlike NewTicker, Tick will return nil if d <= 0.
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
index 32f4740ad9..2ab77f6025 100644
--- a/libgo/go/time/tick_test.go
+++ b/libgo/go/time/tick_test.go
@@ -35,7 +35,7 @@ func TestTicker(t *testing.T) {
}
}
-// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
+// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
func TestTeardown(t *testing.T) {
Delta := 100 * Millisecond
if testing.Short() {
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index ef4ba5842d..10b32461e1 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -4,7 +4,8 @@
// Package time provides functionality for measuring and displaying time.
//
-// The calendrical calculations always assume a Gregorian calendar.
+// The calendrical calculations always assume a Gregorian calendar, with
+// no leap seconds.
package time
import "errors"
@@ -12,8 +13,8 @@ import "errors"
// A Time represents an instant in time with nanosecond precision.
//
// Programs using times should typically store and pass them as values,
-// not pointers. That is, time variables and struct fields should be of
-// type time.Time, not *time.Time. A Time value can be used by
+// not pointers. That is, time variables and struct fields should be of
+// type time.Time, not *time.Time. A Time value can be used by
// multiple goroutines simultaneously.
//
// Time instants can be compared using the Before, After, and Equal methods.
@@ -49,11 +50,18 @@ type Time struct {
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
// that correspond to this Time.
- // Only the zero Time has a nil Location.
- // In that case it is interpreted to mean UTC.
+ // The nil location means UTC.
+ // All UTC times are represented with loc==nil, never loc==&utcLoc.
loc *Location
}
+func (t *Time) setLoc(loc *Location) {
+ if loc == &utcLoc {
+ loc = nil
+ }
+ t.loc = loc
+}
+
// After reports whether the time instant t is after u.
func (t Time) After(u Time) bool {
return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec
@@ -67,8 +75,7 @@ func (t Time) Before(u Time) bool {
// Equal reports whether t and u represent the same time instant.
// Two times can be equal even if they are in different locations.
// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
-// This comparison is different from using t == u, which also compares
-// the locations.
+// Do not use == with Time values.
func (t Time) Equal(u Time) bool {
return t.sec == u.sec && t.nsec == u.nsec
}
@@ -107,7 +114,14 @@ var months = [...]string{
}
// String returns the English name of the month ("January", "February", ...).
-func (m Month) String() string { return months[m-1] }
+func (m Month) String() string {
+ if January <= m && m <= December {
+ return months[m-1]
+ }
+ buf := make([]byte, 20)
+ n := fmtInt(buf, uint64(m))
+ return "%!Month(" + string(buf[n:]) + ")"
+}
// A Weekday specifies a day of the week (Sunday = 0, ...).
type Weekday int
@@ -146,7 +160,7 @@ func (d Weekday) String() string { return days[d] }
// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York.
//
// The zero Time value does not force a specific epoch for the time
-// representation. For example, to use the Unix epoch internally, we
+// representation. For example, to use the Unix epoch internally, we
// could define that to distinguish a zero value from Jan 1 1970, that
// time would be represented by sec=-1, nsec=1e9. However, it does
// suggest a representation, namely using 1-1-1 00:00:00 UTC as the
@@ -155,17 +169,17 @@ func (d Weekday) String() string { return days[d] }
// The Add and Sub computations are oblivious to the choice of epoch.
//
// The presentation computations - year, month, minute, and so on - all
-// rely heavily on division and modulus by positive constants. For
+// rely heavily on division and modulus by positive constants. For
// calendrical calculations we want these divisions to round down, even
// for negative values, so that the remainder is always positive, but
// Go's division (like most hardware division instructions) rounds to
-// zero. We can still do those computations and then adjust the result
+// zero. We can still do those computations and then adjust the result
// for a negative numerator, but it's annoying to write the adjustment
-// over and over. Instead, we can change to a different epoch so long
+// over and over. Instead, we can change to a different epoch so long
// ago that all the times we care about will be positive, and then round
-// to zero and round down coincide. These presentation routines already
+// to zero and round down coincide. These presentation routines already
// have to add the zone offset, so adding the translation to the
-// alternate epoch is cheap. For example, having a non-negative time t
+// alternate epoch is cheap. For example, having a non-negative time t
// means that we can write
//
// sec = t % 60
@@ -181,9 +195,9 @@ func (d Weekday) String() string { return days[d] }
//
// The calendar runs on an exact 400 year cycle: a 400-year calendar
// printed for 1970-2469 will apply as well to 2370-2769. Even the days
-// of the week match up. It simplifies the computations to choose the
+// of the week match up. It simplifies the computations to choose the
// cycle boundaries so that the exceptional years are always delayed as
-// long as possible. That means choosing a year equal to 1 mod 400, so
+// long as possible. That means choosing a year equal to 1 mod 400, so
// that the first leap year is the 4th year, the first missed leap year
// is the 100th year, and the missed missed leap year is the 400th year.
// So we'd prefer instead to print a calendar for 2001-2400 and reuse it
@@ -209,7 +223,7 @@ func (d Weekday) String() string { return days[d] }
// routines would then be invalid when displaying the epoch in time zones
// west of UTC, since it is year 0. It doesn't seem tenable to say that
// printing the zero time correctly isn't supported in half the time
-// zones. By comparison, it's reasonable to mishandle some times in
+// zones. By comparison, it's reasonable to mishandle some times in
// the year -292277022399.
//
// All this is opaque to clients of the API and can be changed if a
@@ -225,9 +239,6 @@ const (
// Assumed by the unixToInternal computation below.
internalYear = 1
- // The year of the zero Unix time.
- unixYear = 1970
-
// Offsets to convert between internal and absolute or Unix times.
absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay
internalToAbsolute = -absoluteToInternal
@@ -425,7 +436,7 @@ func (t Time) YearDay() int {
}
// A Duration represents the elapsed time between two instants
-// as an int64 nanosecond count. The representation limits the
+// as an int64 nanosecond count. The representation limits the
// largest representable duration to approximately 290 years.
type Duration int64
@@ -434,7 +445,7 @@ const (
maxDuration Duration = 1<<63 - 1
)
-// Common durations. There is no definition for units of Day or larger
+// Common durations. There is no definition for units of Day or larger
// to avoid confusion across daylight savings time zone transitions.
//
// To count the number of units in a Duration, divide:
@@ -455,10 +466,9 @@ const (
)
// String returns a string representing the duration in the form "72h3m0.5s".
-// Leading zero units are omitted. As a special case, durations less than one
+// Leading zero units are omitted. As a special case, durations less than one
// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
-// that the leading digit is non-zero. The zero duration formats as 0,
-// with no unit.
+// that the leading digit is non-zero. The zero duration formats as 0s.
func (d Duration) String() string {
// Largest time is 2540400h10m10.000000000s
var buf [32]byte
@@ -479,7 +489,7 @@ func (d Duration) String() string {
w--
switch {
case u == 0:
- return "0"
+ return "0s"
case u < uint64(Microsecond):
// print nanoseconds
prec = 0
@@ -589,27 +599,27 @@ func (d Duration) Nanoseconds() int64 { return int64(d) }
func (d Duration) Seconds() float64 {
sec := d / Second
nsec := d % Second
- return float64(sec) + float64(nsec)*1e-9
+ return float64(sec) + float64(nsec)/1e9
}
// Minutes returns the duration as a floating point number of minutes.
func (d Duration) Minutes() float64 {
min := d / Minute
nsec := d % Minute
- return float64(min) + float64(nsec)*(1e-9/60)
+ return float64(min) + float64(nsec)/(60*1e9)
}
// Hours returns the duration as a floating point number of hours.
func (d Duration) Hours() float64 {
hour := d / Hour
nsec := d % Hour
- return float64(hour) + float64(nsec)*(1e-9/60/60)
+ return float64(hour) + float64(nsec)/(60*60*1e9)
}
// Add returns the time t+d.
func (t Time) Add(d Duration) Time {
t.sec += int64(d / 1e9)
- nsec := int32(t.nsec) + int32(d%1e9)
+ nsec := t.nsec + int32(d%1e9)
if nsec >= 1e9 {
t.sec++
nsec -= 1e9
@@ -626,7 +636,7 @@ func (t Time) Add(d Duration) Time {
// will be returned.
// To compute t-d for a duration d, use t.Add(-d).
func (t Time) Sub(u Time) Duration {
- d := Duration(t.sec-u.sec)*Second + Duration(int32(t.nsec)-int32(u.nsec))
+ d := Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
// Check for overflow or underflow.
switch {
case u.Add(d).Equal(t):
@@ -644,6 +654,12 @@ func Since(t Time) Duration {
return Now().Sub(t)
}
+// Until returns the duration until t.
+// It is shorthand for t.Sub(time.Now()).
+func Until(t Time) Duration {
+ return t.Sub(Now())
+}
+
// AddDate returns the time corresponding to adding the
// given number of years, months, and days to t.
// For example, AddDate(-1, 2, 3) applied to January 1, 2011
@@ -655,7 +671,7 @@ func Since(t Time) Duration {
func (t Time) AddDate(years int, months int, days int) Time {
year, month, day := t.Date()
hour, min, sec := t.Clock()
- return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc)
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.Location())
}
const (
@@ -749,7 +765,7 @@ func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
}
// daysBefore[m] counts the number of days in a non-leap year
-// before month m begins. There is an entry for m=12, counting
+// before month m begins. There is an entry for m=12, counting
// the number of days before January of next year (365).
var daysBefore = [...]int32{
0,
@@ -785,13 +801,13 @@ func Now() Time {
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
- t.loc = UTC
+ t.setLoc(&utcLoc)
return t
}
// Local returns t with the location set to local time.
func (t Time) Local() Time {
- t.loc = Local
+ t.setLoc(Local)
return t
}
@@ -802,7 +818,7 @@ func (t Time) In(loc *Location) Time {
if loc == nil {
panic("time: missing Location in call to Time.In")
}
- t.loc = loc
+ t.setLoc(loc)
return t
}
@@ -830,8 +846,9 @@ func (t Time) Unix() int64 {
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC. The result is undefined if the Unix time
-// in nanoseconds cannot be represented by an int64. Note that this
-// means the result of calling UnixNano on the zero Time is undefined.
+// in nanoseconds cannot be represented by an int64 (a date before the year
+// 1678 or after 2262). Note that this means the result of calling UnixNano
+// on the zero Time is undefined.
func (t Time) UnixNano() int64 {
return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
}
@@ -842,7 +859,7 @@ const timeBinaryVersion byte = 1
func (t Time) MarshalBinary() ([]byte, error) {
var offsetMin int16 // minutes east of UTC. -1 is UTC.
- if t.Location() == &utcLoc {
+ if t.Location() == UTC {
offsetMin = -1
} else {
_, offset := t.Zone()
@@ -903,11 +920,11 @@ func (t *Time) UnmarshalBinary(data []byte) error {
offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
if offset == -1*60 {
- t.loc = &utcLoc
+ t.setLoc(&utcLoc)
} else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
- t.loc = Local
+ t.setLoc(Local)
} else {
- t.loc = FixedZone("", offset)
+ t.setLoc(FixedZone("", offset))
}
return nil
@@ -945,10 +962,15 @@ func (t Time) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
-func (t *Time) UnmarshalJSON(data []byte) (err error) {
+func (t *Time) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
// Fractional seconds are handled implicitly by Parse.
+ var err error
*t, err = Parse(`"`+RFC3339+`"`, string(data))
- return
+ return err
}
// MarshalText implements the encoding.TextMarshaler interface.
@@ -964,10 +986,11 @@ func (t Time) MarshalText() ([]byte, error) {
// UnmarshalText implements the encoding.TextUnmarshaler interface.
// The time is expected to be in RFC 3339 format.
-func (t *Time) UnmarshalText(data []byte) (err error) {
+func (t *Time) UnmarshalText(data []byte) error {
// Fractional seconds are handled implicitly by Parse.
+ var err error
*t, err = Parse(RFC3339, string(data))
- return
+ return err
}
// Unix returns the local Time corresponding to the given Unix time,
@@ -1019,7 +1042,7 @@ func norm(hi, lo, base int) (nhi, nlo int) {
//
// A daylight savings time transition skips or repeats times.
// For example, in the United States, March 13, 2011 2:15am never occurred,
-// while November 6, 2011 1:15am occurred twice. In such cases, the
+// while November 6, 2011 1:15am occurred twice. In such cases, the
// choice of time zone, and therefore the time, is not well-defined.
// Date returns a time that is correct in one of the two zones involved
// in the transition, but it does not guarantee which.
@@ -1094,11 +1117,18 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
unix -= int64(offset)
}
- return Time{unix + unixToInternal, int32(nsec), loc}
+ t := Time{unix + unixToInternal, int32(nsec), nil}
+ t.setLoc(loc)
+ return t
}
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
// If d <= 0, Truncate returns t unchanged.
+//
+// Truncate operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// time. Thus, Truncate(Hour) may return a time with a non-zero
+// minute, depending on the time's Location.
func (t Time) Truncate(d Duration) Time {
if d <= 0 {
return t
@@ -1110,6 +1140,11 @@ func (t Time) Truncate(d Duration) Time {
// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
// The rounding behavior for halfway values is to round up.
// If d <= 0, Round returns t unchanged.
+//
+// Round operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// time. Thus, Round(Hour) may return a time with a non-zero
+// minute, depending on the time's Location.
func (t Time) Round(d Duration) Time {
if d <= 0 {
return t
@@ -1126,7 +1161,7 @@ func (t Time) Round(d Duration) Time {
// but it's still here in case we change our minds.
func div(t Time, d Duration) (qmod2 int, r Duration) {
neg := false
- nsec := int32(t.nsec)
+ nsec := t.nsec
if t.sec < 0 {
// Operate on absolute value.
neg = true
@@ -1160,7 +1195,7 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
tmp := (sec >> 32) * 1e9
u1 := tmp >> 32
u0 := tmp << 32
- tmp = uint64(sec&0xFFFFFFFF) * 1e9
+ tmp = (sec & 0xFFFFFFFF) * 1e9
u0x, u0 := u0, u0+tmp
if u0 < u0x {
u1++
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index a925e98a83..2922560f09 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -22,7 +22,7 @@ import (
// the subsequent tests fail.
func TestZoneData(t *testing.T) {
lt := Now()
- // PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique.
+ // PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique.
if name, off := lt.Zone(); off != -8*60*60 && off != -7*60*60 {
t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", name, off)
t.Error("Likely problem: the time zone files have not been installed.")
@@ -533,7 +533,7 @@ var durationTests = []struct {
str string
d Duration
}{
- {"0", 0},
+ {"0s", 0},
{"1ns", 1 * Nanosecond},
{"1.1µs", 1100 * Nanosecond},
{"2.2ms", 2200 * Microsecond},
@@ -840,6 +840,10 @@ var parseDurationTests = []struct {
{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
// large negative value
{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
+ // huge string; issue 15011.
+ {"0.100000000000000000000h", true, 6 * Minute},
+ // This value tests the first overflow check in leadingFraction.
+ {"0.830103483285477580700h", true, 49*Minute + 48*Second + 372539827*Nanosecond},
// errors
{"", false, 0},
@@ -891,7 +895,7 @@ func TestLocationRace(t *testing.T) {
go func() {
c <- Now().String()
}()
- Now().String()
+ _ = Now().String()
<-c
Sleep(100 * Millisecond)
@@ -939,8 +943,11 @@ func TestLoadFixed(t *testing.T) {
// but Go and most other systems use "east is positive".
// So GMT+1 corresponds to -3600 in the Go zone, not +3600.
name, offset := Now().In(loc).Zone()
- if name != "GMT+1" || offset != -1*60*60 {
- t.Errorf("Now().In(loc).Zone() = %q, %d, want %q, %d", name, offset, "GMT+1", -1*60*60)
+ // The zone abbreviation is "-01" since tzdata-2016g, and "GMT+1"
+ // on earlier versions; we accept both. (Issue #17276).
+ if !(name == "GMT+1" || name == "-01") || offset != -1*60*60 {
+ t.Errorf("Now().In(loc).Zone() = %q, %d, want %q or %q, %d",
+ name, offset, "GMT+1", "-01", -1*60*60)
}
}
@@ -996,6 +1003,21 @@ func TestDurationNanoseconds(t *testing.T) {
}
}
+var secDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(300000000), 0.3},
+}
+
+func TestDurationSeconds(t *testing.T) {
+ for _, tt := range secDurationTests {
+ if got := tt.d.Seconds(); got != tt.want {
+ t.Errorf("d.Seconds() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
var minDurationTests = []struct {
d Duration
want float64
@@ -1004,6 +1026,7 @@ var minDurationTests = []struct {
{Duration(-1), -1 / 60e9},
{Duration(1), 1 / 60e9},
{Duration(60000000000), 1},
+ {Duration(3000), 5e-8},
}
func TestDurationMinutes(t *testing.T) {
@@ -1022,6 +1045,7 @@ var hourDurationTests = []struct {
{Duration(-1), -1 / 3600e9},
{Duration(1), 1 / 3600e9},
{Duration(3600000000000), 1},
+ {Duration(36), 1e-11},
}
func TestDurationHours(t *testing.T) {
@@ -1032,6 +1056,100 @@ func TestDurationHours(t *testing.T) {
}
}
+var defaultLocTests = []struct {
+ name string
+ f func(t1, t2 Time) bool
+}{
+ {"After", func(t1, t2 Time) bool { return t1.After(t2) == t2.After(t1) }},
+ {"Before", func(t1, t2 Time) bool { return t1.Before(t2) == t2.Before(t1) }},
+ {"Equal", func(t1, t2 Time) bool { return t1.Equal(t2) == t2.Equal(t1) }},
+
+ {"IsZero", func(t1, t2 Time) bool { return t1.IsZero() == t2.IsZero() }},
+ {"Date", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Date()
+ a2, b2, c2 := t2.Date()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Year", func(t1, t2 Time) bool { return t1.Year() == t2.Year() }},
+ {"Month", func(t1, t2 Time) bool { return t1.Month() == t2.Month() }},
+ {"Day", func(t1, t2 Time) bool { return t1.Day() == t2.Day() }},
+ {"Weekday", func(t1, t2 Time) bool { return t1.Weekday() == t2.Weekday() }},
+ {"ISOWeek", func(t1, t2 Time) bool {
+ a1, b1 := t1.ISOWeek()
+ a2, b2 := t2.ISOWeek()
+ return a1 == a2 && b1 == b2
+ }},
+ {"Clock", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Clock()
+ a2, b2, c2 := t2.Clock()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Hour", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"Minute", func(t1, t2 Time) bool { return t1.Minute() == t2.Minute() }},
+ {"Second", func(t1, t2 Time) bool { return t1.Second() == t2.Second() }},
+ {"Nanosecond", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"YearDay", func(t1, t2 Time) bool { return t1.YearDay() == t2.YearDay() }},
+
+ // Using Equal since Add don't modify loc using "==" will cause a fail
+ {"Add", func(t1, t2 Time) bool { return t1.Add(Hour).Equal(t2.Add(Hour)) }},
+ {"Sub", func(t1, t2 Time) bool { return t1.Sub(t2) == t2.Sub(t1) }},
+
+ //Original caus for this test case bug 15852
+ {"AddDate", func(t1, t2 Time) bool { return t1.AddDate(1991, 9, 3) == t2.AddDate(1991, 9, 3) }},
+
+ {"UTC", func(t1, t2 Time) bool { return t1.UTC() == t2.UTC() }},
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"In", func(t1, t2 Time) bool { return t1.In(UTC) == t2.In(UTC) }},
+
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"Zone", func(t1, t2 Time) bool {
+ a1, b1 := t1.Zone()
+ a2, b2 := t2.Zone()
+ return a1 == a2 && b1 == b2
+ }},
+
+ {"Unix", func(t1, t2 Time) bool { return t1.Unix() == t2.Unix() }},
+ {"UnixNano", func(t1, t2 Time) bool { return t1.UnixNano() == t2.UnixNano() }},
+
+ {"MarshalBinary", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalBinary()
+ a2, b2 := t2.MarshalBinary()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"GobEncode", func(t1, t2 Time) bool {
+ a1, b1 := t1.GobEncode()
+ a2, b2 := t2.GobEncode()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalJSON", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalJSON()
+ a2, b2 := t2.MarshalJSON()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalText", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalText()
+ a2, b2 := t2.MarshalText()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+
+ {"Truncate", func(t1, t2 Time) bool { return t1.Truncate(Hour).Equal(t2.Truncate(Hour)) }},
+ {"Round", func(t1, t2 Time) bool { return t1.Round(Hour).Equal(t2.Round(Hour)) }},
+
+ {"== Time{}", func(t1, t2 Time) bool { return (t1 == Time{}) == (t2 == Time{}) }},
+}
+
+func TestDefaultLoc(t *testing.T) {
+ //This test verifyes that all Time's methods behaves identical if loc is set
+ //as nil or UTC
+ for _, tt := range defaultLocTests {
+ t1 := Time{}
+ t2 := Time{}.UTC()
+ if !tt.f(t1, t2) {
+ t.Errorf("Time{} and Time{}.UTC() behave differently for %s", tt.name)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
t = Now()
@@ -1114,3 +1232,25 @@ func BenchmarkDay(b *testing.B) {
_ = t.Day()
}
}
+
+func TestMarshalBinaryZeroTime(t *testing.T) {
+ t0 := Time{}
+ enc, err := t0.MarshalBinary()
+ if err != nil {
+ t.Fatal(err)
+ }
+ t1 := Now() // not zero
+ if err := t1.UnmarshalBinary(enc); err != nil {
+ t.Fatal(err)
+ }
+ if t1 != t0 {
+ t.Errorf("t0=%#v\nt1=%#v\nwant identical structures", t0, t1)
+ }
+}
+
+// Issue 17720: Zero value of time.Month fails to print
+func TestZeroMonthString(t *testing.T) {
+ if got, want := Month(0).String(), "%!Month(0)"; got != want {
+ t.Errorf("zero month = %q; want %q", got, want)
+ }
+}
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index c56743933f..fb0aa39240 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -9,6 +9,8 @@ import (
"syscall"
)
+//go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go
+
// A Location maps time instants to the zone in use at that time.
// Typically, the Location represents the collection of time offsets
// in use in a geographical area, such as CEST and CET for central Europe.
diff --git a/libgo/go/time/zoneinfo_abbrs_windows.go b/libgo/go/time/zoneinfo_abbrs_windows.go
index 51a1a2f66d..9425db844c 100644
--- a/libgo/go/time/zoneinfo_abbrs_windows.go
+++ b/libgo/go/time/zoneinfo_abbrs_windows.go
@@ -13,104 +13,133 @@ type abbr struct {
}
var abbrs = map[string]abbr{
- "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
- "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
- "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
- "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
- "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
- "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
- "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
- "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota
- "Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires
- "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
- "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
- "Central Standard Time": {"CST", "CDT"}, // America/Chicago
- "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
- "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
- "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
- "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
- "Central America Standard Time": {"CST", "CST"}, // America/Guatemala
- "Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
- "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
- "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
- "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
- "Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
- "Arabic Standard Time": {"AST", "AST"}, // Asia/Baghdad
- "Azerbaijan Standard Time": {"AZT", "AZST"}, // Asia/Baku
- "SE Asia Standard Time": {"ICT", "ICT"}, // Asia/Bangkok
- "Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut
- "India Standard Time": {"IST", "IST"}, // Asia/Calcutta
- "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo
- "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
- "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
- "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai
- "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk
- "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
- "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
- "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
- "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
- "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
- "Korea Standard Time": {"KST", "KST"}, // Asia/Seoul
- "China Standard Time": {"CST", "CST"}, // Asia/Shanghai
- "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore
- "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
- "Vladivostok Standard Time": {"VLAT", "VLAT"}, // Asia/Vladivostok
- "Yakutsk Standard Time": {"YAKT", "YAKT"}, // Asia/Yakutsk
- "Ekaterinburg Standard Time": {"YEKT", "YEKT"}, // Asia/Yekaterinburg
- "Caucasus Standard Time": {"AMT", "AMT"}, // Asia/Yerevan
- "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
+ "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
+ "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
+ "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
+ "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
+ "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
+ "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
+ "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
+ "Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
+ "Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
+ "Tocantins Standard Time": {"BRT", "BRT"}, // America/Araguaina
+ "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
+ "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
+ "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
+ "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
+ "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
+ "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
+ "Turks And Caicos Standard Time": {"AST", "AST"}, // America/Grand_Turk
+ "Central America Standard Time": {"CST", "CST"}, // America/Guatemala
+ "Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
+ "Cuba Standard Time": {"CST", "CDT"}, // America/Havana
+ "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
+ "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
+ "Saint Pierre Standard Time": {"PMST", "PMDT"}, // America/Miquelon
+ "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo
+ "Eastern Standard Time": {"EST", "EDT"}, // America/New_York
+ "US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix
+ "Haiti Standard Time": {"EST", "EST"}, // America/Port-au-Prince
+ "Canada Central Standard Time": {"CST", "CST"}, // America/Regina
+ "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
+ "Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Tijuana
+ "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", "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
+ "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai
+ "West Bank Standard Time": {"EET", "EEST"}, // Asia/Hebron
+ "W. Mongolia Standard Time": {"HOVT", "HOVST"}, // Asia/Hovd
+ "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": {"+06", "+07"}, // 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
+ "Tomsk Standard Time": {"+06", "+07"}, // Asia/Tomsk
+ "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
+ "Caucasus Standard Time": {"AMT", "AMT"}, // Asia/Yerevan
+ "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": {"ACST", "ACDT"}, // Australia/Adelaide
+ "E. Australia Standard Time": {"AEST", "AEST"}, // Australia/Brisbane
+ "AUS Central Standard Time": {"ACST", "ACST"}, // Australia/Darwin
+ "Aus Central W. Standard Time": {"ACWST", "ACWST"}, // Australia/Eucla
+ "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
+ "Lord Howe Standard Time": {"LHST", "LHDT"}, // Australia/Lord_Howe
+ "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-08": {"GMT+8", "GMT+8"}, // Etc/GMT+8
+ "UTC-09": {"GMT+9", "GMT+9"}, // Etc/GMT+9
"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
+ "Bougainville Standard Time": {"BST", "BST"}, // Pacific/Bougainville
+ "Chatham Islands Standard Time": {"CHAST", "CHADT"}, // Pacific/Chatham
+ "Easter Island Standard Time": {"EAST", "EASST"}, // Pacific/Easter
+ "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
+ "Marquesas Standard Time": {"MART", "MART"}, // Pacific/Marquesas
+ "Norfolk Standard Time": {"NFT", "NFT"}, // Pacific/Norfolk
"West Pacific Standard Time": {"PGT", "PGT"}, // Pacific/Port_Moresby
"Tonga Standard Time": {"TOT", "TOT"}, // Pacific/Tongatapu
}
diff --git a/libgo/go/time/zoneinfo_android.go b/libgo/go/time/zoneinfo_android.go
new file mode 100644
index 0000000000..695a8adfaa
--- /dev/null
+++ b/libgo/go/time/zoneinfo_android.go
@@ -0,0 +1,119 @@
+// 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.
+
+// Parse the "tzdata" packed timezone file used on Android.
+// The format is lifted from ZoneInfoDB.java and ZoneInfo.java in
+// java/libcore/util in the AOSP.
+
+package time
+
+import (
+ "errors"
+ "runtime"
+)
+
+var tzdataPaths = []string{
+ "/system/usr/share/zoneinfo/tzdata",
+ "/data/misc/zoneinfo/current/tzdata",
+ runtime.GOROOT() + "/lib/time/zoneinfo.zip",
+}
+
+var origTzdataPaths = tzdataPaths
+
+func forceZipFileForTesting(zipOnly bool) {
+ tzdataPaths = make([]string, len(origTzdataPaths))
+ copy(tzdataPaths, origTzdataPaths)
+ if zipOnly {
+ for i := 0; i < len(tzdataPaths)-1; i++ {
+ tzdataPaths[i] = "/XXXNOEXIST"
+ }
+ }
+}
+
+func initTestingZone() {
+ z, err := loadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
+ }
+ z.name = "Local"
+ localLoc = *z
+}
+
+func initLocal() {
+ // TODO(elias.naur): getprop persist.sys.timezone
+ localLoc = *UTC
+}
+
+func loadLocation(name string) (*Location, error) {
+ var firstErr error
+ for _, path := range tzdataPaths {
+ var z *Location
+ var err error
+ if len(path) > 4 && path[len(path)-4:] == ".zip" {
+ z, err = loadZoneZip(path, name)
+ } else {
+ z, err = loadTzdataFile(path, name)
+ }
+ if err == nil {
+ z.name = name
+ return z, nil
+ } else if firstErr == nil && !isNotExist(err) {
+ firstErr = err
+ }
+ }
+ if firstErr != nil {
+ return nil, firstErr
+ }
+ return nil, errors.New("unknown time zone " + name)
+}
+
+func loadTzdataFile(file, name string) (*Location, error) {
+ const (
+ headersize = 12 + 3*4
+ namesize = 40
+ entrysize = namesize + 3*4
+ )
+ if len(name) > namesize {
+ return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
+ }
+ fd, err := open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer closefd(fd)
+
+ buf := make([]byte, headersize)
+ if err := preadn(fd, buf, 0); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d := data{buf, false}
+ if magic := d.read(6); string(magic) != "tzdata" {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d = data{buf[12:], false}
+ indexOff, _ := d.big4()
+ dataOff, _ := d.big4()
+ indexSize := dataOff - indexOff
+ entrycount := indexSize / entrysize
+ buf = make([]byte, indexSize)
+ if err := preadn(fd, buf, int(indexOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ for i := 0; i < int(entrycount); i++ {
+ entry := buf[i*entrysize : (i+1)*entrysize]
+ // len(name) <= namesize is checked at function entry
+ if string(entry[:len(name)]) != name {
+ continue
+ }
+ d := data{entry[namesize:], false}
+ off, _ := d.big4()
+ size, _ := d.big4()
+ buf := make([]byte, size)
+ if err := preadn(fd, buf, int(off+dataOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ return loadZoneData(buf)
+ }
+ return nil, errors.New("cannot find " + name + " in tzdata file " + file)
+}
diff --git a/libgo/go/time/zoneinfo_android_test.go b/libgo/go/time/zoneinfo_android_test.go
new file mode 100644
index 0000000000..ba065d10a6
--- /dev/null
+++ b/libgo/go/time/zoneinfo_android_test.go
@@ -0,0 +1,18 @@
+// 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 time_test
+
+import (
+ "testing"
+ . "time"
+)
+
+func TestAndroidTzdata(t *testing.T) {
+ ForceAndroidTzdataForTest(true)
+ defer ForceAndroidTzdataForTest(false)
+ if _, err := LoadLocation("America/Los_Angeles"); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go
index de9ebb41c8..19cd40d847 100644
--- a/libgo/go/time/zoneinfo_read.go
+++ b/libgo/go/time/zoneinfo_read.go
@@ -11,6 +11,13 @@ package time
import "errors"
+// Copies of io.Seek* constants to avoid importing "io":
+const (
+ seekStart = 0
+ seekCurrent = 1
+ seekEnd = 2
+)
+
// Simple I/O interface to binary blob of data.
type data struct {
p []byte
@@ -210,10 +217,10 @@ func loadZoneFile(dir, name string) (l *Location, err error) {
return loadZoneData(buf)
}
-// There are 500+ zoneinfo files. Rather than distribute them all
+// There are 500+ zoneinfo files. Rather than distribute them all
// individually, we ship them in an uncompressed zip file.
// Used this way, the zip file format serves as a commonly readable
-// container for the individual small files. We choose zip over tar
+// container for the individual small files. We choose zip over tar
// because zip files have a contiguous table of contents, making
// individual file lookups faster, and because the per-file overhead
// in a zip file is considerably less than tar's 512 bytes.
diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go
index ede5330f5c..5b6a4dc4e4 100644
--- a/libgo/go/time/zoneinfo_test.go
+++ b/libgo/go/time/zoneinfo_test.go
@@ -20,7 +20,7 @@ func TestVersion3(t *testing.T) {
}
// Test that we get the correct results for times before the first
-// transition time. To do this we explicitly check early dates in a
+// transition time. To do this we explicitly check early dates in a
// couple of specific timezones.
func TestFirstZone(t *testing.T) {
t.Skip("gccgo does not use the zip file")
@@ -64,3 +64,12 @@ func TestFirstZone(t *testing.T) {
}
}
}
+
+func TestLocationNames(t *testing.T) {
+ if time.Local.String() != "Local" {
+ t.Errorf(`invalid Local location name: got %q want "Local"`, time.Local)
+ }
+ if time.UTC.String() != "UTC" {
+ t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC)
+ }
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 5fc669e478..772748818a 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin,386 darwin,amd64 dragonfly freebsd linux,!android nacl netbsd openbsd solaris
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
@@ -18,8 +18,12 @@ import (
)
func initTestingZone() {
- syscall.Setenv("TZ", "America/Los_Angeles")
- initLocal()
+ z, err := loadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
+ }
+ z.name = "Local"
+ localLoc = *z
}
// Many systems use /usr/share/zoneinfo, Solaris 2 has
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index bcb8ccd563..a6e227b5b0 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -11,8 +11,6 @@ import (
"syscall"
)
-//go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
-
// TODO(rsc): Fall back to copy of zoneinfo files.
// BUG(brainman,rsc): On Windows, the operating system does not provide complete
@@ -83,7 +81,7 @@ func extractCAPS(desc string) string {
var short []rune
for _, c := range desc {
if 'A' <= c && c <= 'Z' {
- short = append(short, rune(c))
+ short = append(short, c)
}
}
return string(short)
@@ -140,6 +138,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++
diff --git a/libgo/go/unicode/graphic.go b/libgo/go/unicode/graphic.go
index 81eae3e762..ca6241949a 100644
--- a/libgo/go/unicode/graphic.go
+++ b/libgo/go/unicode/graphic.go
@@ -45,7 +45,7 @@ func IsGraphic(r rune) bool {
// IsPrint reports whether the rune is defined as printable by Go. Such
// characters include letters, marks, numbers, punctuation, symbols, and the
// ASCII space character, from categories L, M, N, P, S and the ASCII space
-// character. This categorization is the same as IsGraphic except that the
+// character. This categorization is the same as IsGraphic except that the
// only spacing character is ASCII space, U+0020.
func IsPrint(r rune) bool {
if uint32(r) <= MaxLatin1 {
diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go
index 7fe4241edd..b43cc66e7d 100644
--- a/libgo/go/unicode/letter.go
+++ b/libgo/go/unicode/letter.go
@@ -27,7 +27,7 @@ type RangeTable struct {
LatinOffset int // number of entries in R16 with Hi <= MaxLatin1
}
-// Range16 represents of a range of 16-bit Unicode code points. The range runs from Lo to Hi
+// Range16 represents of a range of 16-bit Unicode code points. The range runs from Lo to Hi
// inclusive and has the specified stride.
type Range16 struct {
Lo uint16
@@ -36,7 +36,7 @@ type Range16 struct {
}
// Range32 represents of a range of Unicode code points and is used when one or
-// more of the values will not fit in 16 bits. The range runs from Lo to Hi
+// more of the values will not fit in 16 bits. The range runs from Lo to Hi
// inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
type Range32 struct {
Lo uint32
@@ -48,10 +48,10 @@ type Range32 struct {
// code point to one code point) case conversion.
// The range runs from Lo to Hi inclusive, with a fixed stride of 1. Deltas
// are the number to add to the code point to reach the code point for a
-// different case for that character. They may be negative. If zero, it
+// different case for that character. They may be negative. If zero, it
// means the character is in the corresponding case. There is a special
// case representing sequences of alternating corresponding Upper and Lower
-// pairs. It appears with a fixed Delta of
+// pairs. It appears with a fixed Delta of
// {UpperLower, UpperLower, UpperLower}
// The constant UpperLower has an otherwise impossible delta value.
type CaseRange struct {
@@ -217,7 +217,7 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
m := lo + (hi-lo)/2
cr := caseRange[m]
if rune(cr.Lo) <= r && r <= rune(cr.Hi) {
- delta := rune(cr.Delta[_case])
+ delta := cr.Delta[_case]
if delta > MaxRune {
// In an Upper-Lower sequence, which always starts with
// an UpperCase letter, the real deltas always look like:
@@ -307,7 +307,7 @@ func (special SpecialCase) ToLower(r rune) rune {
return r1
}
-// caseOrbit is defined in tables.go as []foldPair. Right now all the
+// caseOrbit is defined in tables.go as []foldPair. Right now all the
// entries fit in uint16, so use uint16. If that changes, compilation
// will fail (the constants in the composite literal will not fit in uint16)
// and the types here can change to uint32.
@@ -317,9 +317,10 @@ type foldPair struct {
}
// SimpleFold iterates over Unicode code points equivalent under
-// the Unicode-defined simple case folding. Among the code points
+// the Unicode-defined simple case folding. Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
// smallest rune > r if one exists, or else the smallest rune >= 0.
+// If r is not a valid Unicode code point, SimpleFold(r) returns r.
//
// For example:
// SimpleFold('A') = 'a'
@@ -331,7 +332,17 @@ type foldPair struct {
//
// SimpleFold('1') = '1'
//
+// SimpleFold(-2) = -2
+//
func SimpleFold(r rune) rune {
+ if r < 0 || r > MaxRune {
+ return r
+ }
+
+ if int(r) < len(asciiFold) {
+ return rune(asciiFold[r])
+ }
+
// Consult caseOrbit table for special cases.
lo := 0
hi := len(caseOrbit)
@@ -347,7 +358,7 @@ func SimpleFold(r rune) rune {
return rune(caseOrbit[lo].To)
}
- // No folding specified. This is a one- or two-element
+ // No folding specified. This is a one- or two-element
// equivalence class containing rune and ToLower(rune)
// and ToUpper(rune) if they are different from rune.
if l := ToLower(r); l != r {
diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go
index a40b412f66..3fe72ff13d 100644
--- a/libgo/go/unicode/letter_test.go
+++ b/libgo/go/unicode/letter_test.go
@@ -73,7 +73,6 @@ var letterTest = []rune{
0x1200,
0x1312,
0x1401,
- 0x1885,
0x2c00,
0xa800,
0xf900,
@@ -94,6 +93,7 @@ var notletterTest = []rune{
0x375,
0x619,
0x700,
+ 0x1885,
0xfffe,
0x1ffff,
0x10ffff,
@@ -432,6 +432,10 @@ func TestSimpleFold(t *testing.T) {
r = out
}
}
+
+ if r := SimpleFold(-42); r != -42 {
+ t.Errorf("SimpleFold(-42) = %v, want -42", r)
+ }
}
// Running 'go test -calibrate' runs the calibration to find a plausible
diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go
index 935c225c37..1fe4581e6c 100644
--- a/libgo/go/unicode/script_test.go
+++ b/libgo/go/unicode/script_test.go
@@ -18,10 +18,12 @@ type T struct {
// mostly to discover when new scripts and categories arise.
var inTest = []T{
{0x11711, "Ahom"},
+ {0x1e900, "Adlam"},
{0x14646, "Anatolian_Hieroglyphs"},
{0x06e2, "Arabic"},
{0x0567, "Armenian"},
{0x10b20, "Avestan"},
+ {0x11c00, "Bhaiksuki"},
{0x1b37, "Balinese"},
{0xa6af, "Bamum"},
{0x16ada, "Bassa_Vah"},
@@ -89,6 +91,7 @@ var inTest = []T{
{0x0d42, "Malayalam"},
{0x0843, "Mandaic"},
{0x10ac8, "Manichaean"},
+ {0x11cB6, "Marchen"},
{0xabd0, "Meetei_Mayek"},
{0x1e800, "Mende_Kikakui"},
{0x1099f, "Meroitic_Hieroglyphs"},
@@ -100,6 +103,7 @@ var inTest = []T{
{0x11293, "Multani"},
{0x104c, "Myanmar"},
{0x10880, "Nabataean"},
+ {0x11400, "Newa"},
{0x19c3, "New_Tai_Lue"},
{0x07f8, "Nko"},
{0x169b, "Ogham"},
@@ -112,6 +116,7 @@ var inTest = []T{
{0x10a6f, "Old_South_Arabian"},
{0x10c20, "Old_Turkic"},
{0x0b3e, "Oriya"},
+ {0x104d9, "Osage"},
{0x10491, "Osmanya"},
{0x16b2b, "Pahawh_Hmong"},
{0x10876, "Palmyrene"},
@@ -139,6 +144,7 @@ var inTest = []T{
{0xaadc, "Tai_Viet"},
{0x116c9, "Takri"},
{0x0bbf, "Tamil"},
+ {0x17000, "Tangut"},
{0x0c55, "Telugu"},
{0x07a7, "Thaana"},
{0x0e46, "Thai"},
@@ -220,9 +226,11 @@ var inPropTest = []T{
{0x216F, "Other_Uppercase"},
{0x0027, "Pattern_Syntax"},
{0x0020, "Pattern_White_Space"},
+ {0x06DD, "Prepended_Concatenation_Mark"},
{0x300D, "Quotation_Mark"},
{0x2EF3, "Radical"},
- {0x061F, "STerm"},
+ {0x061F, "STerm"}, // Deprecated alias of Sentence_Terminal
+ {0x061F, "Sentence_Terminal"},
{0x2071, "Soft_Dotted"},
{0x003A, "Terminal_Punctuation"},
{0x9FC3, "Unified_Ideograph"},
diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go
index 8bb42062f9..15fecd954f 100644
--- a/libgo/go/unicode/tables.go
+++ b/libgo/go/unicode/tables.go
@@ -3,13 +3,13 @@
// license that can be found in the LICENSE file.
// Generated by running
-// maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
+// maketables --tables=all --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
package unicode
// Version is the Unicode edition from which the tables are derived.
-const Version = "8.0.0"
+const Version = "9.0.0"
// Categories is the set of Unicode category tables.
var Categories = map[string]*RangeTable{
@@ -58,8 +58,9 @@ var _C = &RangeTable{
{0x00ad, 0x0600, 1363},
{0x0601, 0x0605, 1},
{0x061c, 0x06dd, 193},
- {0x070f, 0x180e, 4351},
- {0x200b, 0x200f, 1},
+ {0x070f, 0x08e2, 467},
+ {0x180e, 0x200b, 2045},
+ {0x200c, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
{0x2066, 0x206f, 1},
@@ -92,8 +93,9 @@ var _Cf = &RangeTable{
{0x00ad, 0x0600, 1363},
{0x0601, 0x0605, 1},
{0x061c, 0x06dd, 193},
- {0x070f, 0x180e, 4351},
- {0x200b, 0x200f, 1},
+ {0x070f, 0x08e2, 467},
+ {0x180e, 0x200b, 2045},
+ {0x200c, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
{0x2066, 0x206f, 1},
@@ -171,6 +173,7 @@ var _L = &RangeTable{
{0x0828, 0x0840, 24},
{0x0841, 0x0858, 1},
{0x08a0, 0x08b4, 1},
+ {0x08b6, 0x08bd, 1},
{0x0904, 0x0939, 1},
{0x093d, 0x0950, 19},
{0x0958, 0x0961, 1},
@@ -231,7 +234,8 @@ var _L = &RangeTable{
{0x0c3d, 0x0c58, 27},
{0x0c59, 0x0c5a, 1},
{0x0c60, 0x0c61, 1},
- {0x0c85, 0x0c8c, 1},
+ {0x0c80, 0x0c85, 5},
+ {0x0c86, 0x0c8c, 1},
{0x0c8e, 0x0c90, 1},
{0x0c92, 0x0ca8, 1},
{0x0caa, 0x0cb3, 1},
@@ -242,8 +246,9 @@ var _L = &RangeTable{
{0x0d05, 0x0d0c, 1},
{0x0d0e, 0x0d10, 1},
{0x0d12, 0x0d3a, 1},
- {0x0d3d, 0x0d5f, 17},
- {0x0d60, 0x0d61, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d54, 0x0d56, 1},
+ {0x0d5f, 0x0d61, 1},
{0x0d7a, 0x0d7f, 1},
{0x0d85, 0x0d96, 1},
{0x0d9a, 0x0db1, 1},
@@ -317,7 +322,8 @@ var _L = &RangeTable{
{0x1780, 0x17b3, 1},
{0x17d7, 0x17dc, 5},
{0x1820, 0x1877, 1},
- {0x1880, 0x18a8, 1},
+ {0x1880, 0x1884, 1},
+ {0x1887, 0x18a8, 1},
{0x18aa, 0x18b0, 6},
{0x18b1, 0x18f5, 1},
{0x1900, 0x191e, 1},
@@ -336,6 +342,7 @@ var _L = &RangeTable{
{0x1c00, 0x1c23, 1},
{0x1c4d, 0x1c4f, 1},
{0x1c5a, 0x1c7d, 1},
+ {0x1c80, 0x1c88, 1},
{0x1ce9, 0x1cec, 1},
{0x1cee, 0x1cf1, 1},
{0x1cf5, 0x1cf6, 1},
@@ -412,7 +419,7 @@ var _L = &RangeTable{
{0xa6a0, 0xa6e5, 1},
{0xa717, 0xa71f, 1},
{0xa722, 0xa788, 1},
- {0xa78b, 0xa7ad, 1},
+ {0xa78b, 0xa7ae, 1},
{0xa7b0, 0xa7b7, 1},
{0xa7f7, 0xa801, 1},
{0xa803, 0xa805, 1},
@@ -498,6 +505,8 @@ var _L = &RangeTable{
{0x103a0, 0x103c3, 1},
{0x103c8, 0x103cf, 1},
{0x10400, 0x1049d, 1},
+ {0x104b0, 0x104d3, 1},
+ {0x104d8, 0x104fb, 1},
{0x10500, 0x10527, 1},
{0x10530, 0x10563, 1},
{0x10600, 0x10736, 1},
@@ -557,6 +566,8 @@ var _L = &RangeTable{
{0x11335, 0x11339, 1},
{0x1133d, 0x11350, 19},
{0x1135d, 0x11361, 1},
+ {0x11400, 0x11434, 1},
+ {0x11447, 0x1144a, 1},
{0x11480, 0x114af, 1},
{0x114c4, 0x114c5, 1},
{0x114c7, 0x11580, 185},
@@ -569,6 +580,10 @@ var _L = &RangeTable{
{0x118a0, 0x118df, 1},
{0x118ff, 0x11ac0, 449},
{0x11ac1, 0x11af8, 1},
+ {0x11c00, 0x11c08, 1},
+ {0x11c0a, 0x11c2e, 1},
+ {0x11c40, 0x11c72, 50},
+ {0x11c73, 0x11c8f, 1},
{0x12000, 0x12399, 1},
{0x12480, 0x12543, 1},
{0x13000, 0x1342e, 1},
@@ -583,6 +598,9 @@ var _L = &RangeTable{
{0x16f00, 0x16f44, 1},
{0x16f50, 0x16f93, 67},
{0x16f94, 0x16f9f, 1},
+ {0x16fe0, 0x17000, 32},
+ {0x17001, 0x187ec, 1},
+ {0x18800, 0x18af2, 1},
{0x1b000, 0x1b001, 1},
{0x1bc00, 0x1bc6a, 1},
{0x1bc70, 0x1bc7c, 1},
@@ -619,6 +637,7 @@ var _L = &RangeTable{
{0x1d7aa, 0x1d7c2, 1},
{0x1d7c4, 0x1d7cb, 1},
{0x1e800, 0x1e8c4, 1},
+ {0x1e900, 0x1e943, 1},
{0x1ee00, 0x1ee03, 1},
{0x1ee05, 0x1ee1f, 1},
{0x1ee21, 0x1ee22, 1},
@@ -706,6 +725,7 @@ var _Ll = &RangeTable{
{0x04cf, 0x052f, 2},
{0x0561, 0x0587, 1},
{0x13f8, 0x13fd, 1},
+ {0x1c80, 0x1c88, 1},
{0x1d00, 0x1d2b, 1},
{0x1d6b, 0x1d77, 1},
{0x1d79, 0x1d9a, 1},
@@ -773,6 +793,7 @@ var _Ll = &RangeTable{
},
R32: []Range32{
{0x10428, 0x1044f, 1},
+ {0x104d8, 0x104fb, 1},
{0x10cc0, 0x10cf2, 1},
{0x118c0, 0x118df, 1},
{0x1d41a, 0x1d433, 1},
@@ -802,7 +823,8 @@ var _Ll = &RangeTable{
{0x1d78a, 0x1d78f, 1},
{0x1d7aa, 0x1d7c2, 1},
{0x1d7c4, 0x1d7c9, 1},
- {0x1d7cb, 0x1d7cb, 1},
+ {0x1d7cb, 0x1e922, 4439},
+ {0x1e923, 0x1e943, 1},
},
LatinOffset: 4,
}
@@ -854,6 +876,7 @@ var _Lm = &RangeTable{
{0x16b40, 0x16b40, 1},
{0x16b41, 0x16b43, 1},
{0x16f93, 0x16f9f, 1},
+ {0x16fe0, 0x16fe0, 1},
},
}
@@ -880,6 +903,7 @@ var _Lo = &RangeTable{
{0x0800, 0x0815, 1},
{0x0840, 0x0858, 1},
{0x08a0, 0x08b4, 1},
+ {0x08b6, 0x08bd, 1},
{0x0904, 0x0939, 1},
{0x093d, 0x0950, 19},
{0x0958, 0x0961, 1},
@@ -940,7 +964,8 @@ var _Lo = &RangeTable{
{0x0c3d, 0x0c58, 27},
{0x0c59, 0x0c5a, 1},
{0x0c60, 0x0c61, 1},
- {0x0c85, 0x0c8c, 1},
+ {0x0c80, 0x0c85, 5},
+ {0x0c86, 0x0c8c, 1},
{0x0c8e, 0x0c90, 1},
{0x0c92, 0x0ca8, 1},
{0x0caa, 0x0cb3, 1},
@@ -951,8 +976,9 @@ var _Lo = &RangeTable{
{0x0d05, 0x0d0c, 1},
{0x0d0e, 0x0d10, 1},
{0x0d12, 0x0d3a, 1},
- {0x0d3d, 0x0d5f, 17},
- {0x0d60, 0x0d61, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d54, 0x0d56, 1},
+ {0x0d5f, 0x0d61, 1},
{0x0d7a, 0x0d7f, 1},
{0x0d85, 0x0d96, 1},
{0x0d9a, 0x0db1, 1},
@@ -1022,7 +1048,8 @@ var _Lo = &RangeTable{
{0x17dc, 0x1820, 68},
{0x1821, 0x1842, 1},
{0x1844, 0x1877, 1},
- {0x1880, 0x18a8, 1},
+ {0x1880, 0x1884, 1},
+ {0x1887, 0x18a8, 1},
{0x18aa, 0x18b0, 6},
{0x18b1, 0x18f5, 1},
{0x1900, 0x191e, 1},
@@ -1211,6 +1238,8 @@ var _Lo = &RangeTable{
{0x11335, 0x11339, 1},
{0x1133d, 0x11350, 19},
{0x1135d, 0x11361, 1},
+ {0x11400, 0x11434, 1},
+ {0x11447, 0x1144a, 1},
{0x11480, 0x114af, 1},
{0x114c4, 0x114c5, 1},
{0x114c7, 0x11580, 185},
@@ -1222,6 +1251,10 @@ var _Lo = &RangeTable{
{0x11700, 0x11719, 1},
{0x118ff, 0x11ac0, 449},
{0x11ac1, 0x11af8, 1},
+ {0x11c00, 0x11c08, 1},
+ {0x11c0a, 0x11c2e, 1},
+ {0x11c40, 0x11c72, 50},
+ {0x11c73, 0x11c8f, 1},
{0x12000, 0x12399, 1},
{0x12480, 0x12543, 1},
{0x13000, 0x1342e, 1},
@@ -1233,9 +1266,11 @@ var _Lo = &RangeTable{
{0x16b63, 0x16b77, 1},
{0x16b7d, 0x16b8f, 1},
{0x16f00, 0x16f44, 1},
- {0x16f50, 0x1b000, 16560},
- {0x1b001, 0x1bc00, 3071},
- {0x1bc01, 0x1bc6a, 1},
+ {0x16f50, 0x17000, 176},
+ {0x17001, 0x187ec, 1},
+ {0x18800, 0x18af2, 1},
+ {0x1b000, 0x1b001, 1},
+ {0x1bc00, 0x1bc6a, 1},
{0x1bc70, 0x1bc7c, 1},
{0x1bc80, 0x1bc88, 1},
{0x1bc90, 0x1bc99, 1},
@@ -1386,13 +1421,14 @@ var _Lu = &RangeTable{
{0xa78b, 0xa78d, 2},
{0xa790, 0xa792, 2},
{0xa796, 0xa7aa, 2},
- {0xa7ab, 0xa7ad, 1},
+ {0xa7ab, 0xa7ae, 1},
{0xa7b0, 0xa7b4, 1},
{0xa7b6, 0xff21, 22379},
{0xff22, 0xff3a, 1},
},
R32: []Range32{
{0x10400, 0x10427, 1},
+ {0x104b0, 0x104d3, 1},
{0x10c80, 0x10cb2, 1},
{0x118a0, 0x118bf, 1},
{0x1d400, 0x1d419, 1},
@@ -1424,7 +1460,8 @@ var _Lu = &RangeTable{
{0x1d71c, 0x1d734, 1},
{0x1d756, 0x1d76e, 1},
{0x1d790, 0x1d7a8, 1},
- {0x1d7ca, 0x1d7ca, 1},
+ {0x1d7ca, 0x1e900, 4406},
+ {0x1e901, 0x1e921, 1},
},
LatinOffset: 3,
}
@@ -1453,6 +1490,7 @@ var _M = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082d, 1},
{0x0859, 0x085b, 1},
+ {0x08d4, 0x08e1, 1},
{0x08e3, 0x0903, 1},
{0x093a, 0x093c, 1},
{0x093e, 0x094f, 1},
@@ -1546,6 +1584,7 @@ var _M = &RangeTable{
{0x17b4, 0x17d3, 1},
{0x17dd, 0x180b, 46},
{0x180c, 0x180d, 1},
+ {0x1885, 0x1886, 1},
{0x18a9, 0x1920, 119},
{0x1921, 0x192b, 1},
{0x1930, 0x193b, 1},
@@ -1567,7 +1606,7 @@ var _M = &RangeTable{
{0x1cf3, 0x1cf4, 1},
{0x1cf8, 0x1cf9, 1},
{0x1dc0, 0x1df5, 1},
- {0x1dfc, 0x1dff, 1},
+ {0x1dfb, 0x1dff, 1},
{0x20d0, 0x20f0, 1},
{0x2cef, 0x2cf1, 1},
{0x2d7f, 0x2de0, 97},
@@ -1582,7 +1621,7 @@ var _M = &RangeTable{
{0xa80b, 0xa823, 24},
{0xa824, 0xa827, 1},
{0xa880, 0xa881, 1},
- {0xa8b4, 0xa8c4, 1},
+ {0xa8b4, 0xa8c5, 1},
{0xa8e0, 0xa8f1, 1},
{0xa926, 0xa92d, 1},
{0xa947, 0xa953, 1},
@@ -1626,7 +1665,8 @@ var _M = &RangeTable{
{0x111b3, 0x111c0, 1},
{0x111ca, 0x111cc, 1},
{0x1122c, 0x11237, 1},
- {0x112df, 0x112ea, 1},
+ {0x1123e, 0x112df, 161},
+ {0x112e0, 0x112ea, 1},
{0x11300, 0x11303, 1},
{0x1133c, 0x1133e, 2},
{0x1133f, 0x11344, 1},
@@ -1636,6 +1676,7 @@ var _M = &RangeTable{
{0x11363, 0x11366, 3},
{0x11367, 0x1136c, 1},
{0x11370, 0x11374, 1},
+ {0x11435, 0x11446, 1},
{0x114b0, 0x114c3, 1},
{0x115af, 0x115b5, 1},
{0x115b8, 0x115c0, 1},
@@ -1643,6 +1684,10 @@ var _M = &RangeTable{
{0x11630, 0x11640, 1},
{0x116ab, 0x116b7, 1},
{0x1171d, 0x1172b, 1},
+ {0x11c2f, 0x11c36, 1},
+ {0x11c38, 0x11c3f, 1},
+ {0x11c92, 0x11ca7, 1},
+ {0x11ca9, 0x11cb6, 1},
{0x16af0, 0x16af4, 1},
{0x16b30, 0x16b36, 1},
{0x16f51, 0x16f7e, 1},
@@ -1659,7 +1704,13 @@ var _M = &RangeTable{
{0x1da75, 0x1da84, 15},
{0x1da9b, 0x1da9f, 1},
{0x1daa1, 0x1daaf, 1},
+ {0x1e000, 0x1e006, 1},
+ {0x1e008, 0x1e018, 1},
+ {0x1e01b, 0x1e021, 1},
+ {0x1e023, 0x1e024, 1},
+ {0x1e026, 0x1e02a, 1},
{0x1e8d0, 0x1e8d6, 1},
+ {0x1e944, 0x1e94a, 1},
{0xe0100, 0xe01ef, 1},
},
}
@@ -1781,7 +1832,10 @@ var _Mc = &RangeTable{
{0x11347, 0x11348, 1},
{0x1134b, 0x1134d, 1},
{0x11357, 0x11362, 11},
- {0x11363, 0x114b0, 333},
+ {0x11363, 0x11435, 210},
+ {0x11436, 0x11437, 1},
+ {0x11440, 0x11441, 1},
+ {0x11445, 0x114b0, 107},
{0x114b1, 0x114b2, 1},
{0x114b9, 0x114bb, 2},
{0x114bc, 0x114be, 1},
@@ -1795,7 +1849,10 @@ var _Mc = &RangeTable{
{0x116ae, 0x116af, 1},
{0x116b6, 0x11720, 106},
{0x11721, 0x11726, 5},
- {0x16f51, 0x16f7e, 1},
+ {0x11c2f, 0x11c3e, 15},
+ {0x11ca9, 0x11cb1, 8},
+ {0x11cb4, 0x16f51, 21149},
+ {0x16f52, 0x16f7e, 1},
{0x1d165, 0x1d166, 1},
{0x1d16d, 0x1d172, 1},
},
@@ -1835,6 +1892,7 @@ var _Mn = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082d, 1},
{0x0859, 0x085b, 1},
+ {0x08d4, 0x08e1, 1},
{0x08e3, 0x0902, 1},
{0x093a, 0x093c, 2},
{0x0941, 0x0948, 1},
@@ -1913,6 +1971,7 @@ var _Mn = &RangeTable{
{0x17ca, 0x17d3, 1},
{0x17dd, 0x180b, 46},
{0x180c, 0x180d, 1},
+ {0x1885, 0x1886, 1},
{0x18a9, 0x1920, 119},
{0x1921, 0x1922, 1},
{0x1927, 0x1928, 1},
@@ -1946,7 +2005,7 @@ var _Mn = &RangeTable{
{0x1ced, 0x1cf4, 7},
{0x1cf8, 0x1cf9, 1},
{0x1dc0, 0x1df5, 1},
- {0x1dfc, 0x1dff, 1},
+ {0x1dfb, 0x1dff, 1},
{0x20d0, 0x20dc, 1},
{0x20e1, 0x20e5, 4},
{0x20e6, 0x20f0, 1},
@@ -1962,7 +2021,8 @@ var _Mn = &RangeTable{
{0xa802, 0xa806, 4},
{0xa80b, 0xa825, 26},
{0xa826, 0xa8c4, 158},
- {0xa8e0, 0xa8f1, 1},
+ {0xa8c5, 0xa8e0, 27},
+ {0xa8e1, 0xa8f1, 1},
{0xa926, 0xa92d, 1},
{0xa947, 0xa951, 1},
{0xa980, 0xa982, 1},
@@ -2006,13 +2066,17 @@ var _Mn = &RangeTable{
{0x111ca, 0x111cc, 1},
{0x1122f, 0x11231, 1},
{0x11234, 0x11236, 2},
- {0x11237, 0x112df, 168},
- {0x112e3, 0x112ea, 1},
+ {0x11237, 0x1123e, 7},
+ {0x112df, 0x112e3, 4},
+ {0x112e4, 0x112ea, 1},
{0x11300, 0x11301, 1},
{0x1133c, 0x11340, 4},
{0x11366, 0x1136c, 1},
{0x11370, 0x11374, 1},
- {0x114b3, 0x114b8, 1},
+ {0x11438, 0x1143f, 1},
+ {0x11442, 0x11444, 1},
+ {0x11446, 0x114b3, 109},
+ {0x114b4, 0x114b8, 1},
{0x114ba, 0x114bf, 5},
{0x114c0, 0x114c2, 2},
{0x114c3, 0x115b2, 239},
@@ -2029,6 +2093,13 @@ var _Mn = &RangeTable{
{0x1171e, 0x1171f, 1},
{0x11722, 0x11725, 1},
{0x11727, 0x1172b, 1},
+ {0x11c30, 0x11c36, 1},
+ {0x11c38, 0x11c3d, 1},
+ {0x11c3f, 0x11c92, 83},
+ {0x11c93, 0x11ca7, 1},
+ {0x11caa, 0x11cb0, 1},
+ {0x11cb2, 0x11cb3, 1},
+ {0x11cb5, 0x11cb6, 1},
{0x16af0, 0x16af4, 1},
{0x16b30, 0x16b36, 1},
{0x16f8f, 0x16f92, 1},
@@ -2043,7 +2114,13 @@ var _Mn = &RangeTable{
{0x1da75, 0x1da84, 15},
{0x1da9b, 0x1da9f, 1},
{0x1daa1, 0x1daaf, 1},
+ {0x1e000, 0x1e006, 1},
+ {0x1e008, 0x1e018, 1},
+ {0x1e01b, 0x1e021, 1},
+ {0x1e023, 0x1e024, 1},
+ {0x1e026, 0x1e02a, 1},
{0x1e8d0, 0x1e8d6, 1},
+ {0x1e944, 0x1e94a, 1},
{0xe0100, 0xe01ef, 1},
},
}
@@ -2068,7 +2145,8 @@ var _N = &RangeTable{
{0x0c66, 0x0c6f, 1},
{0x0c78, 0x0c7e, 1},
{0x0ce6, 0x0cef, 1},
- {0x0d66, 0x0d75, 1},
+ {0x0d58, 0x0d5e, 1},
+ {0x0d66, 0x0d78, 1},
{0x0de6, 0x0def, 1},
{0x0e50, 0x0e59, 1},
{0x0ed0, 0x0ed9, 1},
@@ -2148,11 +2226,13 @@ var _N = &RangeTable{
{0x111d0, 0x111d9, 1},
{0x111e1, 0x111f4, 1},
{0x112f0, 0x112f9, 1},
+ {0x11450, 0x11459, 1},
{0x114d0, 0x114d9, 1},
{0x11650, 0x11659, 1},
{0x116c0, 0x116c9, 1},
{0x11730, 0x1173b, 1},
{0x118e0, 0x118f2, 1},
+ {0x11c50, 0x11c6c, 1},
{0x12400, 0x1246e, 1},
{0x16a60, 0x16a69, 1},
{0x16b50, 0x16b59, 1},
@@ -2160,6 +2240,7 @@ var _N = &RangeTable{
{0x1d360, 0x1d371, 1},
{0x1d7ce, 0x1d7ff, 1},
{0x1e8c7, 0x1e8cf, 1},
+ {0x1e950, 0x1e959, 1},
{0x1f100, 0x1f10c, 1},
},
LatinOffset: 4,
@@ -2212,14 +2293,17 @@ var _Nd = &RangeTable{
{0x11136, 0x1113f, 1},
{0x111d0, 0x111d9, 1},
{0x112f0, 0x112f9, 1},
+ {0x11450, 0x11459, 1},
{0x114d0, 0x114d9, 1},
{0x11650, 0x11659, 1},
{0x116c0, 0x116c9, 1},
{0x11730, 0x11739, 1},
{0x118e0, 0x118e9, 1},
+ {0x11c50, 0x11c59, 1},
{0x16a60, 0x16a69, 1},
{0x16b50, 0x16b59, 1},
{0x1d7ce, 0x1d7ff, 1},
+ {0x1e950, 0x1e959, 1},
},
LatinOffset: 1,
}
@@ -2251,7 +2335,8 @@ var _No = &RangeTable{
{0x0b72, 0x0b77, 1},
{0x0bf0, 0x0bf2, 1},
{0x0c78, 0x0c7e, 1},
- {0x0d70, 0x0d75, 1},
+ {0x0d58, 0x0d5e, 1},
+ {0x0d70, 0x0d78, 1},
{0x0f2a, 0x0f33, 1},
{0x1369, 0x137c, 1},
{0x17f0, 0x17f9, 1},
@@ -2299,6 +2384,7 @@ var _No = &RangeTable{
{0x111e1, 0x111f4, 1},
{0x1173a, 0x1173b, 1},
{0x118ea, 0x118f2, 1},
+ {0x11c5a, 0x11c6c, 1},
{0x16b5b, 0x16b61, 1},
{0x1d360, 0x1d371, 1},
{0x1e8c7, 0x1e8cf, 1},
@@ -2385,7 +2471,7 @@ var _P = &RangeTable{
{0x2cfe, 0x2cff, 1},
{0x2d70, 0x2e00, 144},
{0x2e01, 0x2e2e, 1},
- {0x2e30, 0x2e42, 1},
+ {0x2e30, 0x2e44, 1},
{0x3001, 0x3003, 1},
{0x3008, 0x3011, 1},
{0x3014, 0x301f, 1},
@@ -2441,16 +2527,23 @@ var _P = &RangeTable{
{0x111cd, 0x111db, 14},
{0x111dd, 0x111df, 1},
{0x11238, 0x1123d, 1},
- {0x112a9, 0x114c6, 541},
- {0x115c1, 0x115d7, 1},
+ {0x112a9, 0x1144b, 418},
+ {0x1144c, 0x1144f, 1},
+ {0x1145b, 0x1145d, 2},
+ {0x114c6, 0x115c1, 251},
+ {0x115c2, 0x115d7, 1},
{0x11641, 0x11643, 1},
+ {0x11660, 0x1166c, 1},
{0x1173c, 0x1173e, 1},
+ {0x11c41, 0x11c45, 1},
+ {0x11c70, 0x11c71, 1},
{0x12470, 0x12474, 1},
{0x16a6e, 0x16a6f, 1},
{0x16af5, 0x16b37, 66},
{0x16b38, 0x16b3b, 1},
{0x16b44, 0x1bc9f, 20827},
{0x1da87, 0x1da8b, 1},
+ {0x1e95e, 0x1e95f, 1},
},
LatinOffset: 11,
}
@@ -2605,7 +2698,8 @@ var _Po = &RangeTable{
{0x2e2b, 0x2e2e, 1},
{0x2e30, 0x2e39, 1},
{0x2e3c, 0x2e3f, 1},
- {0x2e41, 0x3001, 448},
+ {0x2e41, 0x2e43, 2},
+ {0x2e44, 0x3001, 445},
{0x3002, 0x3003, 1},
{0x303d, 0x30fb, 190},
{0xa4fe, 0xa4ff, 1},
@@ -2661,16 +2755,23 @@ var _Po = &RangeTable{
{0x111cd, 0x111db, 14},
{0x111dd, 0x111df, 1},
{0x11238, 0x1123d, 1},
- {0x112a9, 0x114c6, 541},
- {0x115c1, 0x115d7, 1},
+ {0x112a9, 0x1144b, 418},
+ {0x1144c, 0x1144f, 1},
+ {0x1145b, 0x1145d, 2},
+ {0x114c6, 0x115c1, 251},
+ {0x115c2, 0x115d7, 1},
{0x11641, 0x11643, 1},
+ {0x11660, 0x1166c, 1},
{0x1173c, 0x1173e, 1},
+ {0x11c41, 0x11c45, 1},
+ {0x11c70, 0x11c71, 1},
{0x12470, 0x12474, 1},
{0x16a6e, 0x16a6f, 1},
{0x16af5, 0x16b37, 66},
{0x16b38, 0x16b3b, 1},
{0x16b44, 0x1bc9f, 20827},
{0x1da87, 0x1da8b, 1},
+ {0x1e95e, 0x1e95f, 1},
},
LatinOffset: 8,
}
@@ -2736,9 +2837,9 @@ var _S = &RangeTable{
{0x09fa, 0x09fb, 1},
{0x0af1, 0x0b70, 127},
{0x0bf3, 0x0bfa, 1},
- {0x0c7f, 0x0d79, 250},
- {0x0e3f, 0x0f01, 194},
- {0x0f02, 0x0f03, 1},
+ {0x0c7f, 0x0d4f, 208},
+ {0x0d79, 0x0e3f, 198},
+ {0x0f01, 0x0f03, 1},
{0x0f13, 0x0f15, 2},
{0x0f16, 0x0f17, 1},
{0x0f1a, 0x0f1f, 1},
@@ -2778,7 +2879,7 @@ var _S = &RangeTable{
{0x218b, 0x2190, 5},
{0x2191, 0x2307, 1},
{0x230c, 0x2328, 1},
- {0x232b, 0x23fa, 1},
+ {0x232b, 0x23fe, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
{0x249c, 0x24e9, 1},
@@ -2839,8 +2940,8 @@ var _S = &RangeTable{
R32: []Range32{
{0x10137, 0x1013f, 1},
{0x10179, 0x10189, 1},
- {0x1018c, 0x10190, 4},
- {0x10191, 0x1019b, 1},
+ {0x1018c, 0x1018e, 1},
+ {0x10190, 0x1019b, 1},
{0x101a0, 0x101d0, 48},
{0x101d1, 0x101fc, 1},
{0x10877, 0x10878, 1},
@@ -2876,16 +2977,14 @@ var _S = &RangeTable{
{0x1f0d1, 0x1f0f5, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
- {0x1f170, 0x1f19a, 1},
+ {0x1f170, 0x1f1ac, 1},
{0x1f1e6, 0x1f202, 1},
- {0x1f210, 0x1f23a, 1},
+ {0x1f210, 0x1f23b, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f579, 1},
- {0x1f57b, 0x1f5a3, 1},
- {0x1f5a5, 0x1f6d0, 1},
+ {0x1f300, 0x1f6d2, 1},
{0x1f6e0, 0x1f6ec, 1},
- {0x1f6f0, 0x1f6f3, 1},
+ {0x1f6f0, 0x1f6f6, 1},
{0x1f700, 0x1f773, 1},
{0x1f780, 0x1f7d4, 1},
{0x1f800, 0x1f80b, 1},
@@ -2893,8 +2992,13 @@ var _S = &RangeTable{
{0x1f850, 0x1f859, 1},
{0x1f860, 0x1f887, 1},
{0x1f890, 0x1f8ad, 1},
- {0x1f910, 0x1f918, 1},
- {0x1f980, 0x1f984, 1},
+ {0x1f910, 0x1f91e, 1},
+ {0x1f920, 0x1f927, 1},
+ {0x1f930, 0x1f933, 3},
+ {0x1f934, 0x1f93e, 1},
+ {0x1f940, 0x1f94b, 1},
+ {0x1f950, 0x1f95e, 1},
+ {0x1f980, 0x1f991, 1},
{0x1f9c0, 0x1f9c0, 1},
},
LatinOffset: 10,
@@ -3020,8 +3124,8 @@ var _So = &RangeTable{
{0x09fa, 0x0b70, 374},
{0x0bf3, 0x0bf8, 1},
{0x0bfa, 0x0c7f, 133},
- {0x0d79, 0x0f01, 392},
- {0x0f02, 0x0f03, 1},
+ {0x0d4f, 0x0d79, 42},
+ {0x0f01, 0x0f03, 1},
{0x0f13, 0x0f15, 2},
{0x0f16, 0x0f17, 1},
{0x0f1a, 0x0f1f, 1},
@@ -3063,7 +3167,7 @@ var _So = &RangeTable{
{0x232b, 0x237b, 1},
{0x237d, 0x239a, 1},
{0x23b4, 0x23db, 1},
- {0x23e2, 0x23fa, 1},
+ {0x23e2, 0x23fe, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
{0x249c, 0x24e9, 1},
@@ -3116,8 +3220,8 @@ var _So = &RangeTable{
{0x10137, 0x10137, 1},
{0x10138, 0x1013f, 1},
{0x10179, 0x10189, 1},
- {0x1018c, 0x10190, 4},
- {0x10191, 0x1019b, 1},
+ {0x1018c, 0x1018e, 1},
+ {0x10190, 0x1019b, 1},
{0x101a0, 0x101d0, 48},
{0x101d1, 0x101fc, 1},
{0x10877, 0x10878, 1},
@@ -3147,17 +3251,15 @@ var _So = &RangeTable{
{0x1f0d1, 0x1f0f5, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
- {0x1f170, 0x1f19a, 1},
+ {0x1f170, 0x1f1ac, 1},
{0x1f1e6, 0x1f202, 1},
- {0x1f210, 0x1f23a, 1},
+ {0x1f210, 0x1f23b, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
{0x1f300, 0x1f3fa, 1},
- {0x1f400, 0x1f579, 1},
- {0x1f57b, 0x1f5a3, 1},
- {0x1f5a5, 0x1f6d0, 1},
+ {0x1f400, 0x1f6d2, 1},
{0x1f6e0, 0x1f6ec, 1},
- {0x1f6f0, 0x1f6f3, 1},
+ {0x1f6f0, 0x1f6f6, 1},
{0x1f700, 0x1f773, 1},
{0x1f780, 0x1f7d4, 1},
{0x1f800, 0x1f80b, 1},
@@ -3165,8 +3267,13 @@ var _So = &RangeTable{
{0x1f850, 0x1f859, 1},
{0x1f860, 0x1f887, 1},
{0x1f890, 0x1f8ad, 1},
- {0x1f910, 0x1f918, 1},
- {0x1f980, 0x1f984, 1},
+ {0x1f910, 0x1f91e, 1},
+ {0x1f920, 0x1f927, 1},
+ {0x1f930, 0x1f933, 3},
+ {0x1f934, 0x1f93e, 1},
+ {0x1f940, 0x1f94b, 1},
+ {0x1f950, 0x1f95e, 1},
+ {0x1f980, 0x1f991, 1},
{0x1f9c0, 0x1f9c0, 1},
},
LatinOffset: 2,
@@ -3259,11 +3366,12 @@ var (
)
// Generated by running
-// maketables --scripts=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+// maketables --scripts=all --url=http://www.unicode.org/Public/9.0.0/ucd/
// DO NOT EDIT
// Scripts is the set of Unicode script tables.
var Scripts = map[string]*RangeTable{
+ "Adlam": Adlam,
"Ahom": Ahom,
"Anatolian_Hieroglyphs": Anatolian_Hieroglyphs,
"Arabic": Arabic,
@@ -3274,6 +3382,7 @@ var Scripts = map[string]*RangeTable{
"Bassa_Vah": Bassa_Vah,
"Batak": Batak,
"Bengali": Bengali,
+ "Bhaiksuki": Bhaiksuki,
"Bopomofo": Bopomofo,
"Brahmi": Brahmi,
"Braille": Braille,
@@ -3335,6 +3444,7 @@ var Scripts = map[string]*RangeTable{
"Malayalam": Malayalam,
"Mandaic": Mandaic,
"Manichaean": Manichaean,
+ "Marchen": Marchen,
"Meetei_Mayek": Meetei_Mayek,
"Mende_Kikakui": Mende_Kikakui,
"Meroitic_Cursive": Meroitic_Cursive,
@@ -3347,6 +3457,7 @@ var Scripts = map[string]*RangeTable{
"Myanmar": Myanmar,
"Nabataean": Nabataean,
"New_Tai_Lue": New_Tai_Lue,
+ "Newa": Newa,
"Nko": Nko,
"Ogham": Ogham,
"Ol_Chiki": Ol_Chiki,
@@ -3358,6 +3469,7 @@ var Scripts = map[string]*RangeTable{
"Old_South_Arabian": Old_South_Arabian,
"Old_Turkic": Old_Turkic,
"Oriya": Oriya,
+ "Osage": Osage,
"Osmanya": Osmanya,
"Pahawh_Hmong": Pahawh_Hmong,
"Palmyrene": Palmyrene,
@@ -3385,6 +3497,7 @@ var Scripts = map[string]*RangeTable{
"Tai_Viet": Tai_Viet,
"Takri": Takri,
"Tamil": Tamil,
+ "Tangut": Tangut,
"Telugu": Telugu,
"Thaana": Thaana,
"Thai": Thai,
@@ -3397,6 +3510,15 @@ var Scripts = map[string]*RangeTable{
"Yi": Yi,
}
+var _Adlam = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x1e900, 0x1e94a, 1},
+ {0x1e950, 0x1e959, 1},
+ {0x1e95e, 0x1e95f, 1},
+ },
+}
+
var _Ahom = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -3426,6 +3548,8 @@ var _Arabic = &RangeTable{
{0x06de, 0x06ff, 1},
{0x0750, 0x077f, 1},
{0x08a0, 0x08b4, 1},
+ {0x08b6, 0x08bd, 1},
+ {0x08d4, 0x08e1, 1},
{0x08e3, 0x08ff, 1},
{0xfb50, 0xfbc1, 1},
{0xfbd3, 0xfd3d, 1},
@@ -3543,6 +3667,16 @@ var _Bengali = &RangeTable{
},
}
+var _Bhaiksuki = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11c00, 0x11c08, 1},
+ {0x11c0a, 0x11c36, 1},
+ {0x11c38, 0x11c45, 1},
+ {0x11c50, 0x11c6c, 1},
+ },
+}
+
var _Bopomofo = &RangeTable{
R16: []Range16{
{0x02ea, 0x02eb, 1},
@@ -3649,6 +3783,7 @@ var _Common = &RangeTable{
{0x061f, 0x061f, 1},
{0x0640, 0x0640, 1},
{0x06dd, 0x06dd, 1},
+ {0x08e2, 0x08e2, 1},
{0x0964, 0x0965, 1},
{0x0e3f, 0x0e3f, 1},
{0x0fd5, 0x0fd8, 1},
@@ -3674,7 +3809,7 @@ var _Common = &RangeTable{
{0x2133, 0x214d, 1},
{0x214f, 0x215f, 1},
{0x2189, 0x218b, 1},
- {0x2190, 0x23fa, 1},
+ {0x2190, 0x23fe, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
{0x2460, 0x27ff, 1},
@@ -3684,7 +3819,7 @@ var _Common = &RangeTable{
{0x2bbd, 0x2bc8, 1},
{0x2bca, 0x2bd1, 1},
{0x2bec, 0x2bef, 1},
- {0x2e00, 0x2e42, 1},
+ {0x2e00, 0x2e44, 1},
{0x2ff0, 0x2ffb, 1},
{0x3000, 0x3004, 1},
{0x3006, 0x3006, 1},
@@ -3768,17 +3903,15 @@ var _Common = &RangeTable{
{0x1f100, 0x1f10c, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
- {0x1f170, 0x1f19a, 1},
+ {0x1f170, 0x1f1ac, 1},
{0x1f1e6, 0x1f1ff, 1},
{0x1f201, 0x1f202, 1},
- {0x1f210, 0x1f23a, 1},
+ {0x1f210, 0x1f23b, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f579, 1},
- {0x1f57b, 0x1f5a3, 1},
- {0x1f5a5, 0x1f6d0, 1},
+ {0x1f300, 0x1f6d2, 1},
{0x1f6e0, 0x1f6ec, 1},
- {0x1f6f0, 0x1f6f3, 1},
+ {0x1f6f0, 0x1f6f6, 1},
{0x1f700, 0x1f773, 1},
{0x1f780, 0x1f7d4, 1},
{0x1f800, 0x1f80b, 1},
@@ -3786,8 +3919,13 @@ var _Common = &RangeTable{
{0x1f850, 0x1f859, 1},
{0x1f860, 0x1f887, 1},
{0x1f890, 0x1f8ad, 1},
- {0x1f910, 0x1f918, 1},
- {0x1f980, 0x1f984, 1},
+ {0x1f910, 0x1f91e, 1},
+ {0x1f920, 0x1f927, 1},
+ {0x1f930, 0x1f930, 1},
+ {0x1f933, 0x1f93e, 1},
+ {0x1f940, 0x1f94b, 1},
+ {0x1f950, 0x1f95e, 1},
+ {0x1f980, 0x1f991, 1},
{0x1f9c0, 0x1f9c0, 1},
{0xe0001, 0xe0001, 1},
{0xe0020, 0xe007f, 1},
@@ -3829,6 +3967,7 @@ var _Cyrillic = &RangeTable{
R16: []Range16{
{0x0400, 0x0484, 1},
{0x0487, 0x052f, 1},
+ {0x1c80, 0x1c88, 1},
{0x1d2b, 0x1d2b, 1},
{0x1d78, 0x1d78, 1},
{0x2de0, 0x2dff, 1},
@@ -3933,6 +4072,13 @@ var _Glagolitic = &RangeTable{
{0x2c00, 0x2c2e, 1},
{0x2c30, 0x2c5e, 1},
},
+ R32: []Range32{
+ {0x1e000, 0x1e006, 1},
+ {0x1e008, 0x1e018, 1},
+ {0x1e01b, 0x1e021, 1},
+ {0x1e023, 0x1e024, 1},
+ {0x1e026, 0x1e02a, 1},
+ },
}
var _Gothic = &RangeTable{
@@ -4000,7 +4146,7 @@ var _Greek = &RangeTable{
{0xab65, 0xab65, 1},
},
R32: []Range32{
- {0x10140, 0x1018c, 1},
+ {0x10140, 0x1018e, 1},
{0x101a0, 0x101a0, 1},
{0x1d200, 0x1d245, 1},
},
@@ -4151,7 +4297,7 @@ var _Inherited = &RangeTable{
{0x1cf4, 0x1cf4, 1},
{0x1cf8, 0x1cf9, 1},
{0x1dc0, 0x1df5, 1},
- {0x1dfc, 0x1dff, 1},
+ {0x1dfb, 0x1dff, 1},
{0x200c, 0x200d, 1},
{0x20d0, 0x20f0, 1},
{0x302a, 0x302d, 1},
@@ -4203,7 +4349,7 @@ var _Kaithi = &RangeTable{
var _Kannada = &RangeTable{
R16: []Range16{
- {0x0c81, 0x0c83, 1},
+ {0x0c80, 0x0c83, 1},
{0x0c85, 0x0c8c, 1},
{0x0c8e, 0x0c90, 1},
{0x0c92, 0x0ca8, 1},
@@ -4269,7 +4415,7 @@ var _Khojki = &RangeTable{
R16: []Range16{},
R32: []Range32{
{0x11200, 0x11211, 1},
- {0x11213, 0x1123d, 1},
+ {0x11213, 0x1123e, 1},
},
}
@@ -4329,7 +4475,7 @@ var _Latin = &RangeTable{
{0x2160, 0x2188, 1},
{0x2c60, 0x2c7f, 1},
{0xa722, 0xa787, 1},
- {0xa78b, 0xa7ad, 1},
+ {0xa78b, 0xa7ae, 1},
{0xa7b0, 0xa7b7, 1},
{0xa7f7, 0xa7ff, 1},
{0xab30, 0xab5a, 1},
@@ -4417,11 +4563,9 @@ var _Malayalam = &RangeTable{
{0x0d12, 0x0d3a, 1},
{0x0d3d, 0x0d44, 1},
{0x0d46, 0x0d48, 1},
- {0x0d4a, 0x0d4e, 1},
- {0x0d57, 0x0d57, 1},
- {0x0d5f, 0x0d63, 1},
- {0x0d66, 0x0d75, 1},
- {0x0d79, 0x0d7f, 1},
+ {0x0d4a, 0x0d4f, 1},
+ {0x0d54, 0x0d63, 1},
+ {0x0d66, 0x0d7f, 1},
},
}
@@ -4440,6 +4584,15 @@ var _Manichaean = &RangeTable{
},
}
+var _Marchen = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11c70, 0x11c8f, 1},
+ {0x11c92, 0x11ca7, 1},
+ {0x11ca9, 0x11cb6, 1},
+ },
+}
+
var _Meetei_Mayek = &RangeTable{
R16: []Range16{
{0xaae0, 0xaaf6, 1},
@@ -4498,6 +4651,9 @@ var _Mongolian = &RangeTable{
{0x1820, 0x1877, 1},
{0x1880, 0x18aa, 1},
},
+ R32: []Range32{
+ {0x11660, 0x1166c, 1},
+ },
}
var _Mro = &RangeTable{
@@ -4545,6 +4701,15 @@ var _New_Tai_Lue = &RangeTable{
},
}
+var _Newa = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11400, 0x11459, 1},
+ {0x1145b, 0x1145b, 1},
+ {0x1145d, 0x1145d, 1},
+ },
+}
+
var _Nko = &RangeTable{
R16: []Range16{
{0x07c0, 0x07fa, 1},
@@ -4634,6 +4799,14 @@ var _Oriya = &RangeTable{
},
}
+var _Osage = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x104b0, 0x104d3, 1},
+ {0x104d8, 0x104fb, 1},
+ },
+}
+
var _Osmanya = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -4713,7 +4886,7 @@ var _Samaritan = &RangeTable{
var _Saurashtra = &RangeTable{
R16: []Range16{
- {0xa880, 0xa8c4, 1},
+ {0xa880, 0xa8c5, 1},
{0xa8ce, 0xa8d9, 1},
},
}
@@ -4867,6 +5040,15 @@ var _Tamil = &RangeTable{
},
}
+var _Tangut = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x16fe0, 0x16fe0, 1},
+ {0x17000, 0x187ec, 1},
+ {0x18800, 0x18af2, 1},
+ },
+}
+
var _Telugu = &RangeTable{
R16: []Range16{
{0x0c00, 0x0c03, 1},
@@ -4957,6 +5139,7 @@ var _Yi = &RangeTable{
// These variables have type *RangeTable.
var (
+ Adlam = _Adlam // Adlam is the set of Unicode characters in script Adlam.
Ahom = _Ahom // Ahom is the set of Unicode characters in script Ahom.
Anatolian_Hieroglyphs = _Anatolian_Hieroglyphs // Anatolian_Hieroglyphs is the set of Unicode characters in script Anatolian_Hieroglyphs.
Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic.
@@ -4967,6 +5150,7 @@ var (
Bassa_Vah = _Bassa_Vah // Bassa_Vah is the set of Unicode characters in script Bassa_Vah.
Batak = _Batak // Batak is the set of Unicode characters in script Batak.
Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali.
+ Bhaiksuki = _Bhaiksuki // Bhaiksuki is the set of Unicode characters in script Bhaiksuki.
Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo.
Brahmi = _Brahmi // Brahmi is the set of Unicode characters in script Brahmi.
Braille = _Braille // Braille is the set of Unicode characters in script Braille.
@@ -5028,6 +5212,7 @@ var (
Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam.
Mandaic = _Mandaic // Mandaic is the set of Unicode characters in script Mandaic.
Manichaean = _Manichaean // Manichaean is the set of Unicode characters in script Manichaean.
+ Marchen = _Marchen // Marchen is the set of Unicode characters in script Marchen.
Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
Mende_Kikakui = _Mende_Kikakui // Mende_Kikakui is the set of Unicode characters in script Mende_Kikakui.
Meroitic_Cursive = _Meroitic_Cursive // Meroitic_Cursive is the set of Unicode characters in script Meroitic_Cursive.
@@ -5040,6 +5225,7 @@ var (
Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar.
Nabataean = _Nabataean // Nabataean is the set of Unicode characters in script Nabataean.
New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
+ Newa = _Newa // Newa is the set of Unicode characters in script Newa.
Nko = _Nko // Nko is the set of Unicode characters in script Nko.
Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham.
Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
@@ -5051,6 +5237,7 @@ var (
Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic.
Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya.
+ Osage = _Osage // Osage is the set of Unicode characters in script Osage.
Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya.
Pahawh_Hmong = _Pahawh_Hmong // Pahawh_Hmong is the set of Unicode characters in script Pahawh_Hmong.
Palmyrene = _Palmyrene // Palmyrene is the set of Unicode characters in script Palmyrene.
@@ -5078,6 +5265,7 @@ var (
Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet.
Takri = _Takri // Takri is the set of Unicode characters in script Takri.
Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil.
+ Tangut = _Tangut // Tangut is the set of Unicode characters in script Tangut.
Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu.
Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana.
Thai = _Thai // Thai is the set of Unicode characters in script Thai.
@@ -5091,7 +5279,7 @@ var (
)
// Generated by running
-// maketables --props=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+// maketables --props=all --url=http://www.unicode.org/Public/9.0.0/ucd/
// DO NOT EDIT
// Properties is the set of Unicode property tables.
@@ -5120,9 +5308,11 @@ var Properties = map[string]*RangeTable{
"Other_Uppercase": Other_Uppercase,
"Pattern_Syntax": Pattern_Syntax,
"Pattern_White_Space": Pattern_White_Space,
+ "Prepended_Concatenation_Mark": Prepended_Concatenation_Mark,
"Quotation_Mark": Quotation_Mark,
"Radical": Radical,
- "STerm": STerm,
+ "Sentence_Terminal": Sentence_Terminal,
+ "STerm": Sentence_Terminal,
"Soft_Dotted": Soft_Dotted,
"Terminal_Punctuation": Terminal_Punctuation,
"Unified_Ideograph": Unified_Ideograph,
@@ -5187,7 +5377,6 @@ var _Deprecated = &RangeTable{
},
R32: []Range32{
{0xe0001, 0xe0001, 1},
- {0xe007f, 0xe007f, 1},
},
}
@@ -5329,11 +5518,14 @@ var _Diacritic = &RangeTable{
{0x1134d, 0x1134d, 1},
{0x11366, 0x1136c, 1},
{0x11370, 0x11374, 1},
+ {0x11442, 0x11442, 1},
+ {0x11446, 0x11446, 1},
{0x114c2, 0x114c3, 1},
{0x115bf, 0x115c0, 1},
{0x1163f, 0x1163f, 1},
{0x116b6, 0x116b7, 1},
{0x1172b, 0x1172b, 1},
+ {0x11c3f, 0x11c3f, 1},
{0x16af0, 0x16af4, 1},
{0x16f8f, 0x16f9f, 1},
{0x1d167, 0x1d169, 1},
@@ -5342,6 +5534,8 @@ var _Diacritic = &RangeTable{
{0x1d185, 0x1d18b, 1},
{0x1d1aa, 0x1d1ad, 1},
{0x1e8d0, 0x1e8d6, 1},
+ {0x1e944, 0x1e946, 1},
+ {0x1e948, 0x1e94a, 1},
},
LatinOffset: 6,
}
@@ -5376,6 +5570,8 @@ var _Extender = &RangeTable{
{0x1135d, 0x1135d, 1},
{0x115c6, 0x115c8, 1},
{0x16b42, 0x16b43, 1},
+ {0x16fe0, 0x16fe0, 1},
+ {0x1e944, 0x1e946, 1},
},
LatinOffset: 1,
}
@@ -5432,6 +5628,8 @@ var _Ideographic = &RangeTable{
{0xfa70, 0xfad9, 1},
},
R32: []Range32{
+ {0x17000, 0x187ec, 1},
+ {0x18800, 0x18af2, 1},
{0x20000, 0x2a6d6, 1},
{0x2a700, 0x2b734, 1},
{0x2b740, 0x2b81d, 1},
@@ -5506,6 +5704,7 @@ var _Other_Alphabetic = &RangeTable{
{0x081b, 0x0823, 1},
{0x0825, 0x0827, 1},
{0x0829, 0x082c, 1},
+ {0x08d4, 0x08df, 1},
{0x08e3, 0x08e9, 1},
{0x08f0, 0x0903, 1},
{0x093a, 0x093b, 1},
@@ -5591,6 +5790,7 @@ var _Other_Alphabetic = &RangeTable{
{0x1752, 0x1753, 1},
{0x1772, 0x1773, 1},
{0x17b6, 0x17c8, 1},
+ {0x1885, 0x1886, 1},
{0x18a9, 0x18a9, 1},
{0x1920, 0x192b, 1},
{0x1930, 0x1938, 1},
@@ -5613,6 +5813,7 @@ var _Other_Alphabetic = &RangeTable{
{0xa823, 0xa827, 1},
{0xa880, 0xa881, 1},
{0xa8b4, 0xa8c3, 1},
+ {0xa8c5, 0xa8c5, 1},
{0xa926, 0xa92a, 1},
{0xa947, 0xa952, 1},
{0xa980, 0xa983, 1},
@@ -5644,6 +5845,7 @@ var _Other_Alphabetic = &RangeTable{
{0x111b3, 0x111bf, 1},
{0x1122c, 0x11234, 1},
{0x11237, 0x11237, 1},
+ {0x1123e, 0x1123e, 1},
{0x112df, 0x112e8, 1},
{0x11300, 0x11303, 1},
{0x1133e, 0x11344, 1},
@@ -5651,6 +5853,8 @@ var _Other_Alphabetic = &RangeTable{
{0x1134b, 0x1134c, 1},
{0x11357, 0x11357, 1},
{0x11362, 0x11363, 1},
+ {0x11435, 0x11441, 1},
+ {0x11443, 0x11445, 1},
{0x114b0, 0x114c1, 1},
{0x115af, 0x115b5, 1},
{0x115b8, 0x115be, 1},
@@ -5659,9 +5863,19 @@ var _Other_Alphabetic = &RangeTable{
{0x11640, 0x11640, 1},
{0x116ab, 0x116b5, 1},
{0x1171d, 0x1172a, 1},
+ {0x11c2f, 0x11c36, 1},
+ {0x11c38, 0x11c3e, 1},
+ {0x11c92, 0x11ca7, 1},
+ {0x11ca9, 0x11cb6, 1},
{0x16b30, 0x16b36, 1},
{0x16f51, 0x16f7e, 1},
{0x1bc9e, 0x1bc9e, 1},
+ {0x1e000, 0x1e006, 1},
+ {0x1e008, 0x1e018, 1},
+ {0x1e01b, 0x1e021, 1},
+ {0x1e023, 0x1e024, 1},
+ {0x1e026, 0x1e02a, 1},
+ {0x1e947, 0x1e947, 1},
{0x1f130, 0x1f149, 1},
{0x1f150, 0x1f169, 1},
{0x1f170, 0x1f189, 1},
@@ -5700,7 +5914,7 @@ var _Other_Grapheme_Extend = &RangeTable{
{0x0d57, 0x0d57, 1},
{0x0dcf, 0x0dcf, 1},
{0x0ddf, 0x0ddf, 1},
- {0x200c, 0x200d, 1},
+ {0x200c, 0x200c, 1},
{0x302e, 0x302f, 1},
{0xff9e, 0xff9f, 1},
},
@@ -5712,6 +5926,7 @@ var _Other_Grapheme_Extend = &RangeTable{
{0x115af, 0x115af, 1},
{0x1d165, 0x1d165, 1},
{0x1d16e, 0x1d172, 1},
+ {0xe0020, 0xe007f, 1},
},
}
@@ -5727,6 +5942,7 @@ var _Other_ID_Continue = &RangeTable{
var _Other_ID_Start = &RangeTable{
R16: []Range16{
+ {0x1885, 0x1886, 1},
{0x2118, 0x2118, 1},
{0x212e, 0x212e, 1},
{0x309b, 0x309c, 1},
@@ -5958,6 +6174,18 @@ var _Pattern_White_Space = &RangeTable{
LatinOffset: 3,
}
+var _Prepended_Concatenation_Mark = &RangeTable{
+ R16: []Range16{
+ {0x0600, 0x0605, 1},
+ {0x06dd, 0x06dd, 1},
+ {0x070f, 0x070f, 1},
+ {0x08e2, 0x08e2, 1},
+ },
+ R32: []Range32{
+ {0x110bd, 0x110bd, 1},
+ },
+}
+
var _Quotation_Mark = &RangeTable{
R16: []Range16{
{0x0022, 0x0022, 1},
@@ -5985,7 +6213,7 @@ var _Radical = &RangeTable{
},
}
-var _STerm = &RangeTable{
+var _Sentence_Terminal = &RangeTable{
R16: []Range16{
{0x0021, 0x0021, 1},
{0x002e, 0x002e, 1},
@@ -6043,10 +6271,12 @@ var _STerm = &RangeTable{
{0x11238, 0x11239, 1},
{0x1123b, 0x1123c, 1},
{0x112a9, 0x112a9, 1},
+ {0x1144b, 0x1144c, 1},
{0x115c2, 0x115c3, 1},
{0x115c9, 0x115d7, 1},
{0x11641, 0x11642, 1},
{0x1173c, 0x1173e, 1},
+ {0x11c41, 0x11c42, 1},
{0x16a6e, 0x16a6f, 1},
{0x16af5, 0x16af5, 1},
{0x16b37, 0x16b38, 1},
@@ -6179,10 +6409,14 @@ var _Terminal_Punctuation = &RangeTable{
{0x111de, 0x111df, 1},
{0x11238, 0x1123c, 1},
{0x112a9, 0x112a9, 1},
+ {0x1144b, 0x1144d, 1},
+ {0x1145b, 0x1145b, 1},
{0x115c2, 0x115c5, 1},
{0x115c9, 0x115d7, 1},
{0x11641, 0x11642, 1},
{0x1173c, 0x1173e, 1},
+ {0x11c41, 0x11c43, 1},
+ {0x11c71, 0x11c71, 1},
{0x12470, 0x12474, 1},
{0x16a6e, 0x16a6f, 1},
{0x16af5, 0x16af5, 1},
@@ -6266,9 +6500,11 @@ var (
Other_Uppercase = _Other_Uppercase // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
Pattern_Syntax = _Pattern_Syntax // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
Pattern_White_Space = _Pattern_White_Space // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
+ Prepended_Concatenation_Mark = _Prepended_Concatenation_Mark // Prepended_Concatenation_Mark is the set of Unicode characters with property Prepended_Concatenation_Mark.
Quotation_Mark = _Quotation_Mark // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
Radical = _Radical // Radical is the set of Unicode characters with property Radical.
- STerm = _STerm // STerm is the set of Unicode characters with property STerm.
+ STerm = _Sentence_Terminal // STerm is an alias for Sentence_Terminal.
+ Sentence_Terminal = _Sentence_Terminal // Sentence_Terminal is the set of Unicode characters with property Sentence_Terminal.
Soft_Dotted = _Soft_Dotted // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
Terminal_Punctuation = _Terminal_Punctuation // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
Unified_Ideograph = _Unified_Ideograph // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
@@ -6277,7 +6513,7 @@ var (
)
// Generated by running
-// maketables --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
+// maketables --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -6383,6 +6619,7 @@ var _CaseRanges = []CaseRange{
{0x0266, 0x0266, d{42308, 0, 42308}},
{0x0268, 0x0268, d{-209, 0, -209}},
{0x0269, 0x0269, d{-211, 0, -211}},
+ {0x026A, 0x026A, d{42308, 0, 42308}},
{0x026B, 0x026B, d{10743, 0, 10743}},
{0x026C, 0x026C, d{42305, 0, 42305}},
{0x026F, 0x026F, d{-211, 0, -211}},
@@ -6453,6 +6690,14 @@ var _CaseRanges = []CaseRange{
{0x13A0, 0x13EF, d{0, 38864, 0}},
{0x13F0, 0x13F5, d{0, 8, 0}},
{0x13F8, 0x13FD, d{-8, 0, -8}},
+ {0x1C80, 0x1C80, d{-6254, 0, -6254}},
+ {0x1C81, 0x1C81, d{-6253, 0, -6253}},
+ {0x1C82, 0x1C82, d{-6244, 0, -6244}},
+ {0x1C83, 0x1C84, d{-6242, 0, -6242}},
+ {0x1C85, 0x1C85, d{-6243, 0, -6243}},
+ {0x1C86, 0x1C86, d{-6236, 0, -6236}},
+ {0x1C87, 0x1C87, d{-6181, 0, -6181}},
+ {0x1C88, 0x1C88, d{35266, 0, 35266}},
{0x1D79, 0x1D79, d{35332, 0, 35332}},
{0x1D7D, 0x1D7D, d{3814, 0, 3814}},
{0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
@@ -6559,6 +6804,7 @@ var _CaseRanges = []CaseRange{
{0xA7AB, 0xA7AB, d{0, -42319, 0}},
{0xA7AC, 0xA7AC, d{0, -42315, 0}},
{0xA7AD, 0xA7AD, d{0, -42305, 0}},
+ {0xA7AE, 0xA7AE, d{0, -42308, 0}},
{0xA7B0, 0xA7B0, d{0, -42258, 0}},
{0xA7B1, 0xA7B1, d{0, -42282, 0}},
{0xA7B2, 0xA7B2, d{0, -42261, 0}},
@@ -6570,10 +6816,14 @@ var _CaseRanges = []CaseRange{
{0xFF41, 0xFF5A, d{-32, 0, -32}},
{0x10400, 0x10427, d{0, 40, 0}},
{0x10428, 0x1044F, d{-40, 0, -40}},
+ {0x104B0, 0x104D3, d{0, 40, 0}},
+ {0x104D8, 0x104FB, d{-40, 0, -40}},
{0x10C80, 0x10CB2, d{0, 64, 0}},
{0x10CC0, 0x10CF2, d{-64, 0, -64}},
{0x118A0, 0x118BF, d{0, 32, 0}},
{0x118C0, 0x118DF, d{-32, 0, -32}},
+ {0x1E900, 0x1E921, d{0, 34, 0}},
+ {0x1E922, 0x1E943, d{-34, 0, -34}},
}
var properties = [MaxLatin1 + 1]uint8{
0x00: pC, // '\x00'
@@ -6834,6 +7084,137 @@ var properties = [MaxLatin1 + 1]uint8{
0xFF: pLl | pp, // 'ÿ'
}
+var asciiFold = [MaxASCII + 1]uint16{
+ 0x0000,
+ 0x0001,
+ 0x0002,
+ 0x0003,
+ 0x0004,
+ 0x0005,
+ 0x0006,
+ 0x0007,
+ 0x0008,
+ 0x0009,
+ 0x000A,
+ 0x000B,
+ 0x000C,
+ 0x000D,
+ 0x000E,
+ 0x000F,
+ 0x0010,
+ 0x0011,
+ 0x0012,
+ 0x0013,
+ 0x0014,
+ 0x0015,
+ 0x0016,
+ 0x0017,
+ 0x0018,
+ 0x0019,
+ 0x001A,
+ 0x001B,
+ 0x001C,
+ 0x001D,
+ 0x001E,
+ 0x001F,
+ 0x0020,
+ 0x0021,
+ 0x0022,
+ 0x0023,
+ 0x0024,
+ 0x0025,
+ 0x0026,
+ 0x0027,
+ 0x0028,
+ 0x0029,
+ 0x002A,
+ 0x002B,
+ 0x002C,
+ 0x002D,
+ 0x002E,
+ 0x002F,
+ 0x0030,
+ 0x0031,
+ 0x0032,
+ 0x0033,
+ 0x0034,
+ 0x0035,
+ 0x0036,
+ 0x0037,
+ 0x0038,
+ 0x0039,
+ 0x003A,
+ 0x003B,
+ 0x003C,
+ 0x003D,
+ 0x003E,
+ 0x003F,
+ 0x0040,
+ 0x0061,
+ 0x0062,
+ 0x0063,
+ 0x0064,
+ 0x0065,
+ 0x0066,
+ 0x0067,
+ 0x0068,
+ 0x0069,
+ 0x006A,
+ 0x006B,
+ 0x006C,
+ 0x006D,
+ 0x006E,
+ 0x006F,
+ 0x0070,
+ 0x0071,
+ 0x0072,
+ 0x0073,
+ 0x0074,
+ 0x0075,
+ 0x0076,
+ 0x0077,
+ 0x0078,
+ 0x0079,
+ 0x007A,
+ 0x005B,
+ 0x005C,
+ 0x005D,
+ 0x005E,
+ 0x005F,
+ 0x0060,
+ 0x0041,
+ 0x0042,
+ 0x0043,
+ 0x0044,
+ 0x0045,
+ 0x0046,
+ 0x0047,
+ 0x0048,
+ 0x0049,
+ 0x004A,
+ 0x212A,
+ 0x004C,
+ 0x004D,
+ 0x004E,
+ 0x004F,
+ 0x0050,
+ 0x0051,
+ 0x0052,
+ 0x017F,
+ 0x0054,
+ 0x0055,
+ 0x0056,
+ 0x0057,
+ 0x0058,
+ 0x0059,
+ 0x005A,
+ 0x007B,
+ 0x007C,
+ 0x007D,
+ 0x007E,
+ 0x007F,
+}
+
var caseOrbit = []foldPair{
{0x004B, 0x006B},
{0x0053, 0x0073},
@@ -6890,6 +7271,29 @@ var caseOrbit = []foldPair{
{0x03F1, 0x03A1},
{0x03F4, 0x0398},
{0x03F5, 0x0395},
+ {0x0412, 0x0432},
+ {0x0414, 0x0434},
+ {0x041E, 0x043E},
+ {0x0421, 0x0441},
+ {0x0422, 0x0442},
+ {0x042A, 0x044A},
+ {0x0432, 0x1C80},
+ {0x0434, 0x1C81},
+ {0x043E, 0x1C82},
+ {0x0441, 0x1C83},
+ {0x0442, 0x1C84},
+ {0x044A, 0x1C86},
+ {0x0462, 0x0463},
+ {0x0463, 0x1C87},
+ {0x1C80, 0x0412},
+ {0x1C81, 0x0414},
+ {0x1C82, 0x041E},
+ {0x1C83, 0x0421},
+ {0x1C84, 0x1C85},
+ {0x1C85, 0x0422},
+ {0x1C86, 0x042A},
+ {0x1C87, 0x0462},
+ {0x1C88, 0xA64A},
{0x1E60, 0x1E61},
{0x1E61, 0x1E9B},
{0x1E9B, 0x1E60},
@@ -6898,6 +7302,8 @@ var caseOrbit = []foldPair{
{0x2126, 0x03A9},
{0x212A, 0x004B},
{0x212B, 0x00C5},
+ {0xA64A, 0xA64B},
+ {0xA64B, 0x1C88},
}
// FoldCategory maps a category name to a table of
@@ -7041,15 +7447,17 @@ var foldLl = &RangeTable{
{0xa78b, 0xa78d, 2},
{0xa790, 0xa792, 2},
{0xa796, 0xa7aa, 2},
- {0xa7ab, 0xa7ad, 1},
+ {0xa7ab, 0xa7ae, 1},
{0xa7b0, 0xa7b4, 1},
{0xa7b6, 0xff21, 22379},
{0xff22, 0xff3a, 1},
},
R32: []Range32{
{0x10400, 0x10427, 1},
+ {0x104b0, 0x104d3, 1},
{0x10c80, 0x10cb2, 1},
{0x118a0, 0x118bf, 1},
+ {0x1e900, 0x1e921, 1},
},
LatinOffset: 3,
}
@@ -7108,11 +7516,10 @@ var foldLu = &RangeTable{
{0x025c, 0x0260, 4},
{0x0261, 0x0265, 2},
{0x0266, 0x0268, 2},
- {0x0269, 0x026b, 2},
- {0x026c, 0x026f, 3},
- {0x0271, 0x0272, 1},
- {0x0275, 0x027d, 8},
- {0x0280, 0x0283, 3},
+ {0x0269, 0x026c, 1},
+ {0x026f, 0x0271, 2},
+ {0x0272, 0x0275, 3},
+ {0x027d, 0x0283, 3},
{0x0287, 0x028c, 1},
{0x0292, 0x029d, 11},
{0x029e, 0x0345, 167},
@@ -7133,6 +7540,7 @@ var foldLu = &RangeTable{
{0x04cf, 0x052f, 2},
{0x0561, 0x0586, 1},
{0x13f8, 0x13fd, 1},
+ {0x1c80, 0x1c88, 1},
{0x1d79, 0x1d7d, 4},
{0x1e01, 0x1e95, 2},
{0x1e9b, 0x1ea1, 6},
@@ -7175,8 +7583,10 @@ var foldLu = &RangeTable{
},
R32: []Range32{
{0x10428, 0x1044f, 1},
+ {0x104d8, 0x104fb, 1},
{0x10cc0, 0x10cf2, 1},
{0x118c0, 0x118df, 1},
+ {0x1e922, 0x1e943, 1},
},
LatinOffset: 4,
}
@@ -7201,7 +7611,7 @@ var foldMn = &RangeTable{
// If there is no entry for a script name, there are no such points.
var FoldScript = map[string]*RangeTable{}
-// Range entries: 3546 16-bit, 1306 32-bit, 4852 total.
-// Range bytes: 21276 16-bit, 15672 32-bit, 36948 total.
+// Range entries: 3576 16-bit, 1454 32-bit, 5030 total.
+// Range bytes: 21456 16-bit, 17448 32-bit, 38904 total.
-// Fold orbit bytes: 63 pairs, 252 bytes
+// Fold orbit bytes: 88 pairs, 352 bytes
diff --git a/libgo/go/unicode/utf16/export_test.go b/libgo/go/unicode/utf16/export_test.go
index 306247e48f..e0c57f52ae 100644
--- a/libgo/go/unicode/utf16/export_test.go
+++ b/libgo/go/unicode/utf16/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/unicode/utf16/utf16.go b/libgo/go/unicode/utf16/utf16.go
index b497500778..1a881aa769 100644
--- a/libgo/go/unicode/utf16/utf16.go
+++ b/libgo/go/unicode/utf16/utf16.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
// the Unicode replacement code point U+FFFD.
func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
- return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
+ return (r1-surr1)<<10 | (r2 - surr2) + surrSelf
}
return replacementChar
}
@@ -45,7 +45,7 @@ func DecodeRune(r1, r2 rune) rune {
// If the rune is not a valid Unicode code point or does not need encoding,
// EncodeRune returns U+FFFD, U+FFFD.
func EncodeRune(r rune) (r1, r2 rune) {
- if r < surrSelf || r > maxRune || IsSurrogate(r) {
+ if r < surrSelf || r > maxRune {
return replacementChar, replacementChar
}
r -= surrSelf
@@ -65,20 +65,22 @@ func Encode(s []rune) []uint16 {
n = 0
for _, v := range s {
switch {
- case v < 0, surr1 <= v && v < surr3, v > maxRune:
- v = replacementChar
- fallthrough
- case v < surrSelf:
+ case 0 <= v && v < surr1, surr3 <= v && v < surrSelf:
+ // normal rune
a[n] = uint16(v)
n++
- default:
+ case surrSelf <= v && v <= maxRune:
+ // needs surrogate sequence
r1, r2 := EncodeRune(v)
a[n] = uint16(r1)
a[n+1] = uint16(r2)
n += 2
+ default:
+ a[n] = uint16(replacementChar)
+ n++
}
}
- return a[0:n]
+ return a[:n]
}
// Decode returns the Unicode code point sequence represented
@@ -88,21 +90,19 @@ func Decode(s []uint16) []rune {
n := 0
for i := 0; i < len(s); i++ {
switch r := s[i]; {
+ case r < surr1, surr3 <= r:
+ // normal rune
+ a[n] = rune(r)
case surr1 <= r && r < surr2 && i+1 < len(s) &&
surr2 <= s[i+1] && s[i+1] < surr3:
// valid surrogate sequence
a[n] = DecodeRune(rune(r), rune(s[i+1]))
i++
- n++
- case surr1 <= r && r < surr3:
+ default:
// invalid surrogate sequence
a[n] = replacementChar
- n++
- default:
- // normal rune
- a[n] = rune(r)
- n++
}
+ n++
}
- return a[0:n]
+ return a[:n]
}
diff --git a/libgo/go/unicode/utf16/utf16_test.go b/libgo/go/unicode/utf16/utf16_test.go
index 3dca472bbe..d258f0bc7b 100644
--- a/libgo/go/unicode/utf16/utf16_test.go
+++ b/libgo/go/unicode/utf16/utf16_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 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.
@@ -147,3 +147,56 @@ func TestIsSurrogate(t *testing.T) {
}
}
}
+
+func BenchmarkDecodeValidASCII(b *testing.B) {
+ // "hello world"
+ data := []uint16{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
+ for i := 0; i < b.N; i++ {
+ Decode(data)
+ }
+}
+
+func BenchmarkDecodeValidJapaneseChars(b *testing.B) {
+ // "日本語日本語日本語"
+ data := []uint16{26085, 26412, 35486, 26085, 26412, 35486, 26085, 26412, 35486}
+ for i := 0; i < b.N; i++ {
+ Decode(data)
+ }
+}
+
+func BenchmarkDecodeRune(b *testing.B) {
+ rs := make([]rune, 10)
+ // U+1D4D0 to U+1D4D4: MATHEMATICAL BOLD SCRIPT CAPITAL LETTERS
+ for i, u := range []rune{'ð“', 'ð“‘', 'ð“’', 'ð““', 'ð“”'} {
+ rs[2*i], rs[2*i+1] = EncodeRune(u)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < 5; j++ {
+ DecodeRune(rs[2*j], rs[2*j+1])
+ }
+ }
+}
+
+func BenchmarkEncodeValidASCII(b *testing.B) {
+ data := []rune{'h', 'e', 'l', 'l', 'o'}
+ for i := 0; i < b.N; i++ {
+ Encode(data)
+ }
+}
+
+func BenchmarkEncodeValidJapaneseChars(b *testing.B) {
+ data := []rune{'日', '本', '語'}
+ for i := 0; i < b.N; i++ {
+ Encode(data)
+ }
+}
+
+func BenchmarkEncodeRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, u := range []rune{'ð“', 'ð“‘', 'ð“’', 'ð““', 'ð“”'} {
+ EncodeRune(u)
+ }
+ }
+}
diff --git a/libgo/go/unicode/utf8/utf8.go b/libgo/go/unicode/utf8/utf8.go
index bbaf14aab8..6ccd464373 100644
--- a/libgo/go/unicode/utf8/utf8.go
+++ b/libgo/go/unicode/utf8/utf8.go
@@ -341,12 +341,13 @@ func RuneLen(r rune) int {
// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func EncodeRune(p []byte, r rune) int {
- // Negative values are erroneous. Making it unsigned addresses the problem.
+ // Negative values are erroneous. Making it unsigned addresses the problem.
switch i := uint32(r); {
case i <= rune1Max:
p[0] = byte(r)
return 1
case i <= rune2Max:
+ _ = p[1] // eliminate bounds checks
p[0] = t2 | byte(r>>6)
p[1] = tx | byte(r)&maskx
return 2
@@ -354,11 +355,13 @@ func EncodeRune(p []byte, r rune) int {
r = RuneError
fallthrough
case i <= rune3Max:
+ _ = p[2] // eliminate bounds checks
p[0] = t3 | byte(r>>12)
p[1] = tx | byte(r>>6)&maskx
p[2] = tx | byte(r)&maskx
return 3
default:
+ _ = p[3] // eliminate bounds checks
p[0] = t4 | byte(r>>18)
p[1] = tx | byte(r>>12)&maskx
p[2] = tx | byte(r>>6)&maskx
@@ -367,7 +370,7 @@ func EncodeRune(p []byte, r rune) int {
}
}
-// RuneCount returns the number of runes in p. Erroneous and short
+// RuneCount returns the number of runes in p. Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
np := len(p)
@@ -441,7 +444,7 @@ func RuneCountInString(s string) (n int) {
}
// RuneStart reports whether the byte could be the first byte of an encoded,
-// possibly invalid rune. Second and subsequent bytes always have the top two
+// possibly invalid rune. Second and subsequent bytes always have the top two
// bits set to 10.
func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
@@ -513,12 +516,10 @@ func ValidString(s string) bool {
// Code points that are out of range or a surrogate half are illegal.
func ValidRune(r rune) bool {
switch {
- case r < 0:
- return false
- case surrogateMin <= r && r <= surrogateMax:
- return false
- case r > MaxRune:
- return false
+ case 0 <= r && r < surrogateMin:
+ return true
+ case surrogateMax < r && r <= MaxRune:
+ return true
}
- return true
+ return false
}
diff --git a/libgo/go/unicode/utf8/utf8_test.go b/libgo/go/unicode/utf8/utf8_test.go
index 51571b61eb..dc9c4251bd 100644
--- a/libgo/go/unicode/utf8/utf8_test.go
+++ b/libgo/go/unicode/utf8/utf8_test.go
@@ -54,14 +54,18 @@ var utf8map = []Utf8Map{
{0x00ff, "\xc3\xbf"},
{0x0100, "\xc4\x80"},
{0x07ff, "\xdf\xbf"},
+ {0x0400, "\xd0\x80"},
{0x0800, "\xe0\xa0\x80"},
{0x0801, "\xe0\xa0\x81"},
+ {0x1000, "\xe1\x80\x80"},
+ {0xd000, "\xed\x80\x80"},
{0xd7ff, "\xed\x9f\xbf"}, // last code point before surrogate half.
{0xe000, "\xee\x80\x80"}, // first code point after surrogate half.
{0xfffe, "\xef\xbf\xbe"},
{0xffff, "\xef\xbf\xbf"},
{0x10000, "\xf0\x90\x80\x80"},
{0x10001, "\xf0\x90\x80\x81"},
+ {0x40000, "\xf1\x80\x80\x80"},
{0x10fffe, "\xf4\x8f\xbf\xbe"},
{0x10ffff, "\xf4\x8f\xbf\xbf"},
{0xFFFD, "\xef\xbf\xbd"},
@@ -228,6 +232,93 @@ func TestIntConversion(t *testing.T) {
}
}
+var invalidSequenceTests = []string{
+ "\xed\xa0\x80\x80", // surrogate min
+ "\xed\xbf\xbf\x80", // surrogate max
+
+ // xx
+ "\x91\x80\x80\x80",
+
+ // s1
+ "\xC2\x7F\x80\x80",
+ "\xC2\xC0\x80\x80",
+ "\xDF\x7F\x80\x80",
+ "\xDF\xC0\x80\x80",
+
+ // s2
+ "\xE0\x9F\xBF\x80",
+ "\xE0\xA0\x7F\x80",
+ "\xE0\xBF\xC0\x80",
+ "\xE0\xC0\x80\x80",
+
+ // s3
+ "\xE1\x7F\xBF\x80",
+ "\xE1\x80\x7F\x80",
+ "\xE1\xBF\xC0\x80",
+ "\xE1\xC0\x80\x80",
+
+ //s4
+ "\xED\x7F\xBF\x80",
+ "\xED\x80\x7F\x80",
+ "\xED\x9F\xC0\x80",
+ "\xED\xA0\x80\x80",
+
+ // s5
+ "\xF0\x8F\xBF\xBF",
+ "\xF0\x90\x7F\xBF",
+ "\xF0\x90\x80\x7F",
+ "\xF0\xBF\xBF\xC0",
+ "\xF0\xBF\xC0\x80",
+ "\xF0\xC0\x80\x80",
+
+ // s6
+ "\xF1\x7F\xBF\xBF",
+ "\xF1\x80\x7F\xBF",
+ "\xF1\x80\x80\x7F",
+ "\xF1\xBF\xBF\xC0",
+ "\xF1\xBF\xC0\x80",
+ "\xF1\xC0\x80\x80",
+
+ // s7
+ "\xF4\x7F\xBF\xBF",
+ "\xF4\x80\x7F\xBF",
+ "\xF4\x80\x80\x7F",
+ "\xF4\x8F\xBF\xC0",
+ "\xF4\x8F\xC0\x80",
+ "\xF4\x90\x80\x80",
+}
+
+func runtimeDecodeRune(s string) rune {
+ for _, r := range s {
+ return r
+ }
+ return -1
+}
+
+func TestDecodeInvalidSequence(t *testing.T) {
+ for _, s := range invalidSequenceTests {
+ r1, _ := DecodeRune([]byte(s))
+ if want := RuneError; r1 != want {
+ t.Errorf("DecodeRune(%#x) = %#04x, want %#04x", s, r1, want)
+ return
+ }
+ r2, _ := DecodeRuneInString(s)
+ if want := RuneError; r2 != want {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s, r2, want)
+ return
+ }
+ if r1 != r2 {
+ t.Errorf("DecodeRune(%#x) = %#04x mismatch with DecodeRuneInString(%q) = %#04x", s, r1, s, r2)
+ return
+ }
+ r3 := runtimeDecodeRune(s)
+ if r2 != r3 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x mismatch with runtime.decoderune(%q) = %#04x", s, r2, s, r3)
+ return
+ }
+ }
+}
+
func testSequence(t *testing.T, s string) {
type info struct {
index int
diff --git a/libgo/godeps.sh b/libgo/godeps.sh
index 7ae5af93bf..0da5d07bdf 100644
--- a/libgo/godeps.sh
+++ b/libgo/godeps.sh
@@ -22,11 +22,12 @@ fi
output=$1
shift
-deps=`for f in $*; do cat $f; done |
+files=$*
+deps=`for f in $files; do cat $f; done |
sed -n -e '/^import.*"/p; /^import[ ]*(/,/^)/p' |
grep '"' |
grep -v '"unsafe"' |
sed -e 's/^.*"\([^"]*\)".*$/\1/' -e 's/$/.gox/' |
sort -u`
-echo $output: $deps
+echo $output: $files $deps
diff --git a/libgo/match.sh b/libgo/match.sh
new file mode 100755
index 0000000000..94bcbc83c6
--- /dev/null
+++ b/libgo/match.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+
+# 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.
+
+# Given a source directory, returns the non-test Go files that should
+# be built for this target. This implements Go's build constraints in
+# a shell script. There is similar code in testsuite/gotest.
+
+set -e
+
+LANG=C
+LC_ALL=C
+LC_CTYPE=C
+export LANG LC_ALL LC_CTYPE
+
+srcdir=""
+goarch=""
+goos=""
+extrafiles=""
+cmdlinetag="nosuchtag"
+cgotag="cgo"
+
+for arg; do
+ case "x$arg" in
+ x--srcdir)
+ srcdir=$2
+ shift
+ shift
+ ;;
+ x--srcdir=*)
+ srcdir=`echo $1 | sed -e 's/^--srcdir=//'`
+ shift
+ ;;
+ x--goarch)
+ goarch=$2
+ shift
+ shift
+ ;;
+ x--goarch=*)
+ goarch=`echo $1 | sed -e 's/^--goarch=//'`
+ shift
+ ;;
+ x--goos)
+ goos=$2
+ shift
+ shift
+ ;;
+ x--goos=*)
+ goos=`echo $1 | sed -e 's/^--goos=//'`
+ shift
+ ;;
+ x--extrafiles)
+ extrafiles=$2
+ shift
+ shift
+ ;;
+ x--extrafiles=*)
+ extrafiles=`echo $1 | sed -e 's/^--extrafiles=//'`
+ shift
+ ;;
+ x--tag)
+ cmdlinetag=$2
+ shift
+ shift
+ ;;
+ x--tag=*)
+ cmdlinetag=`echo $1 | sed -e 's/^--tag=//'`
+ shift
+ ;;
+ x--nocgo)
+ cgotag="nosuchtag"
+ shift
+ ;;
+ *)
+ echo 1>&2 "unknown argument $arg"
+ exit 1
+ ;;
+ esac
+done
+
+cd $srcdir
+
+gofiles=
+for f in *.go; do
+ case $f in
+ *_test.go)
+ ;;
+ *.go)
+ gofiles="$gofiles $f"
+ ;;
+ esac
+done
+
+if test "$gofiles" = ""; then
+ echo 1>&2 "no non-test .go files in $srcdir"
+ exit 1
+fi
+
+matched=
+for f in $gofiles; do
+ tag1=`echo $f | sed -e 's/^.*_\([^_]*\).go$/\1/'`
+ tag2=`echo $f | sed -e 's/^.*_\([^_]*\)_[^_]*.go$/\1/'`
+ if test x$tag1 = x$f; then
+ tag1=
+ fi
+ if test x$tag2 = x$f; then
+ tag2=
+ fi
+
+ case "$tag1" in
+ "") ;;
+ $goarch) ;;
+ $goos) ;;
+ android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows)
+ tag1=nonmatchingtag
+ ;;
+ 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
+ tag1=nonmatchingtag
+ ;;
+ esac
+
+ case "$tag2" in
+ "") ;;
+ $goarch) ;;
+ $goos) ;;
+ android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows)
+ tag2=nonmatchingtag
+ ;;
+ 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
+ tag2=nonmatchingtag
+ ;;
+ esac
+
+ if test x$tag1 != xnonmatchingtag -a x$tag2 != xnonmatchingtag; then
+ # Pipe through cat so that `set -e` doesn't affect fgrep.
+ tags=`sed '/^package /q' < $f | grep '^// +build ' | cat`
+ omatch=true
+ first=true
+ match=false
+ for tag in $tags; do
+ case $tag in
+ "//")
+ ;;
+ "+build")
+ if test "$first" = "true"; then
+ first=false
+ elif test "$match" = "false"; then
+ omatch=false
+ fi
+ match=false
+ ;;
+ $goos | $goarch | $cgotag | $cmdlinetag | "gccgo")
+ match=true
+ ;;
+ "!"$goos | "!"$goarch | "!"$cgotag | "!"$cmdlinetag | "!gccgo")
+ ;;
+ *,*)
+ cmatch=true
+ for ctag in `echo $tag | sed -e 's/,/ /g'`; do
+ case $ctag in
+ $goos | $goarch | $cgotag | $cmdlinetag | "gccgo")
+ ;;
+ "!"$goos | "!"$goarch | "!"$cgotag | "!"$cmdlinetag | "!gccgo")
+ cmatch=false
+ ;;
+ "!"*)
+ ;;
+ *)
+ cmatch=false
+ ;;
+ esac
+ done
+ if test "$cmatch" = "true"; then
+ match=true
+ fi
+ ;;
+ "!"*)
+ match=true
+ ;;
+ esac
+ done
+
+ if test "$match" = "false" -a "$first" = "false"; then
+ omatch=false
+ fi
+
+ if test "$omatch" = "true"; then
+ matched="$matched $srcdir/$f"
+ fi
+ fi
+done
+
+echo $matched $extrafiles
+
+exit 0
diff --git a/libgo/merge.sh b/libgo/merge.sh
index 24f63d9df6..bdf0043f12 100755
--- a/libgo/merge.sh
+++ b/libgo/merge.sh
@@ -71,7 +71,9 @@ merge() {
elif test -f ${old}; then
# The file exists in the old version.
if ! test -f ${libgo}; then
- echo "merge.sh: $name: skipping: exists in old and new git, but not in libgo"
+ if ! cmp -s ${old} ${new}; then
+ echo "merge.sh: $name: skipping: exists in old and new git, but not in libgo"
+ fi
continue
fi
if cmp -s ${old} ${libgo}; then
@@ -99,8 +101,7 @@ merge() {
mv ${libgo}.tmp ${libgo}
;;
*)
- echo 1>&2 "merge.sh: $name: diff3 failure"
- exit 1
+ echo 1>&2 "merge.sh: $name: DIFF3 FAILURE"
;;
esac
fi
@@ -122,43 +123,51 @@ merge() {
fi
}
-merge_c() {
- from=$1
- to=$2
- oldfile=${OLDDIR}/src/runtime/$from
- if test -f ${oldfile}; then
- sed -e 's/·/_/g' < ${oldfile} > ${oldfile}.tmp
- oldfile=${oldfile}.tmp
- newfile=${NEWDIR}/src/runtime/$from
- sed -e 's/·/_/g' < ${newfile} > ${newfile}.tmp
- newfile=${newfile}.tmp
- libgofile=runtime/$to
- merge $from ${oldfile} ${newfile} ${libgofile}
- fi
-}
+echo ${rev} > VERSION
-if test -f VERSION; then
- if ! cmp -s ${NEWDIR}/VERSION VERSION; then
- cp ${NEWDIR}/VERSION .
- fi
-else
- if test -f ${NEWDIR}/VERSION; then
- cp ${NEWDIR}/VERSION .
+(cd ${NEWDIR}/src && find . -name '*.go' -print) | while read f; do
+ skip=false
+ case "$f" in
+ ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/internal/browser/*)
+ ;;
+ ./cmd/*)
+ skip=true
+ ;;
+ ./runtime/race/*)
+ skip=true
+ ;;
+ esac
+ if test "$skip" = "true"; then
+ continue
fi
-fi
-(cd ${NEWDIR}/src && find . -name '*.go' -print) | while read f; do
oldfile=${OLDDIR}/src/$f
newfile=${NEWDIR}/src/$f
- libgofile=go/$f
+ libgofile=go/`echo $f | sed -e 's|/vendor/|/|'`
merge $f ${oldfile} ${newfile} ${libgofile}
done
(cd ${NEWDIR}/src && find . -name testdata -print) | while read d; do
+ skip=false
+ case "$d" in
+ ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/internal/browser/*)
+ ;;
+ ./cmd/*)
+ skip=true
+ ;;
+ ./runtime/race/*)
+ skip=true
+ ;;
+ esac
+ if test "$skip" = "true"; then
+ continue
+ fi
+
oldtd=${OLDDIR}/src/$d
newtd=${NEWDIR}/src/$d
libgotd=go/$d
if ! test -d ${oldtd}; then
+ echo "merge.sh: $d: NEWDIR"
continue
fi
(cd ${oldtd} && git ls-files .) | while read f; do
@@ -173,15 +182,6 @@ done
done
done
-runtime="chan.goc chan.h cpuprof.goc env_posix.c heapdump.c lock_futex.c lfstack.goc lock_sema.c mcache.c mcentral.c mfixalloc.c mgc0.c mgc0.h mheap.c msize.c netpoll.goc netpoll_epoll.c netpoll_kqueue.c netpoll_stub.c panic.c print.c proc.c race.h rdebug.goc runtime.c runtime.h signal_unix.c signal_unix.h malloc.h malloc.goc mprof.goc parfor.c runtime1.goc sema.goc sigqueue.goc string.goc time.goc"
-for f in $runtime; do
- # merge_c $f $f
- true
-done
-
-# merge_c os_linux.c thread-linux.c
-# merge_c mem_linux.c mem.c
-
(cd ${OLDDIR}/src && find . -name '*.go' -print) | while read f; do
oldfile=${OLDDIR}/src/$f
newfile=${NEWDIR}/src/$f
diff --git a/libgo/mkrsysinfo.sh b/libgo/mkrsysinfo.sh
new file mode 100755
index 0000000000..af18594501
--- /dev/null
+++ b/libgo/mkrsysinfo.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+
+# 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.
+
+# Create runtime_sysinfo.go from gen-sysinfo.go and errno.i.
+
+OUT=tmp-runtime_sysinfo.go
+
+set -e
+
+echo 'package runtime' > ${OUT}
+
+# Get all the consts and types, skipping ones which could not be
+# represented in Go and ones which we need to rewrite. We also skip
+# function declarations, as we don't need them here. All the symbols
+# will all have a leading underscore.
+grep -v '^// ' gen-sysinfo.go | \
+ grep -v '^func' | \
+ grep -v '^var ' | \
+ grep -v '^type _timeval ' | \
+ grep -v '^type _timespec_t ' | \
+ grep -v '^type _timespec ' | \
+ grep -v '^type _epoll_' | \
+ grep -v 'in6_addr' | \
+ grep -v 'sockaddr_in6' | \
+ sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1timeval\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timespec_t\([^a-zA-Z0-9_]\)/\1timespec\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1timespec\2/g' \
+ >> ${OUT}
+
+# The time structures need special handling: we need to name the
+# types, so that we can cast integers to the right types when
+# assigning to the structures.
+timeval=`grep '^type _timeval ' gen-sysinfo.go`
+timeval_sec=`echo $timeval | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timeval_usec=`echo $timeval | sed -n -e 's/^.*tv_usec \([^ ]*\);.*$/\1/p'`
+echo "type timeval_sec_t $timeval_sec" >> ${OUT}
+echo "type timeval_usec_t $timeval_usec" >> ${OUT}
+echo $timeval | \
+ sed -e 's/type _timeval /type timeval /' \
+ -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timeval_sec_t/' \
+ -e 's/tv_usec *[a-zA-Z0-9_]*/tv_usec timeval_usec_t/' >> ${OUT}
+echo >> ${OUT}
+echo "func (tv *timeval) set_usec(x int32) {" >> ${OUT}
+echo " tv.tv_usec = timeval_usec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+
+timespec=`grep '^type _timespec ' gen-sysinfo.go || true`
+if test "$timespec" = ""; then
+ # IRIX 6.5 has __timespec instead.
+ timespec=`grep '^type ___timespec ' gen-sysinfo.go || true`
+fi
+timespec_sec=`echo $timespec | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timespec_nsec=`echo $timespec | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'`
+echo "type timespec_sec_t $timespec_sec" >> ${OUT}
+echo "type timespec_nsec_t $timespec_nsec" >> ${OUT}
+echo $timespec | \
+ sed -e 's/^type ___timespec /type timespec /' \
+ -e 's/^type _timespec /type timespec /' \
+ -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timespec_sec_t/' \
+ -e 's/tv_nsec *[a-zA-Z0-9_]*/tv_nsec timespec_nsec_t/' >> ${OUT}
+echo >> ${OUT}
+echo "func (ts *timespec) set_sec(x int64) {" >> ${OUT}
+echo " ts.tv_sec = timespec_sec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+echo >> ${OUT}
+echo "func (ts *timespec) set_nsec(x int32) {" >> ${OUT}
+echo " ts.tv_nsec = timespec_nsec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+
+# Define the epollevent struct. This needs special attention because
+# the C definition uses a union and is sometimes packed.
+if grep '^const _epoll_data_offset ' ${OUT} >/dev/null 2>&1; then
+ val=`grep '^const _epoll_data_offset ' ${OUT} | sed -e 's/const _epoll_data_offset = \(.*\)$/\1/'`
+ if test "$val" = "4"; then
+ echo 'type epollevent struct { events uint32; data [8]byte }' >> ${OUT}
+ elif test "$val" = "8"; then
+ echo 'type epollevent struct { events uint32; pad [4]byte; data [8]byte }' >> ${OUT}
+ else
+ echo 1>&2 "unknown epoll data offset value ${val}"
+ exit 1
+ fi
+fi
+# Make sure EPOLLET is positive.
+if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go > /dev/null 2>&1; then
+ echo "const _EPOLLETpos = _EPOLLET" >> ${OUT}
+else
+ echo "const _EPOLLETpos = 0x80000000" >> ${OUT}
+fi
+# Make sure EPOLLRDHUP and EPOLL_CLOEXEC are defined.
+if ! grep '^const _EPOLLRDHUP' ${OUT} >/dev/null 2>&1; then
+ echo "const _EPOLLRDHUP = 0x2000" >> ${OUT}
+fi
+if ! grep '^const _EPOLL_CLOEXEC' ${OUT} >/dev/null 2>&1; then
+ echo "const _EPOLL_CLOEXEC = 02000000" >> ${OUT}
+fi
+
+# The semt structure, for Solaris.
+grep '^type _sem_t ' gen-sysinfo.go | \
+ sed -e 's/_sem_t/semt/' >> ${OUT}
+
+# Solaris 2 needs _u?pad128_t, but its default definition in terms of long
+# double is commented by -fdump-go-spec.
+if grep "^// type _pad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+ echo "type _pad128_t struct { _l [4]int32; }" >> ${OUT}
+fi
+if grep "^// type _upad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+ echo "type _upad128_t struct { _l [4]uint32; }" >> ${OUT}
+fi
+
+# The Solaris 11 Update 1 _zone_net_addr_t struct.
+grep '^type _zone_net_addr_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr/[16]byte/' \
+ >> ${OUT}
+
+# The Solaris 12 _flow_arp_desc_t struct.
+grep '^type _flow_arp_desc_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr_t/[16]byte/g' \
+ >> ${OUT}
+
+# The Solaris 12 _flow_l3_desc_t struct.
+grep '^type _flow_l3_desc_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr_t/[16]byte/g' \
+ >> ${OUT}
+
+# The Solaris 12 _mac_ipaddr_t struct.
+grep '^type _mac_ipaddr_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr_t/[16]byte/g' \
+ >> ${OUT}
+
+# The Solaris 12 _mactun_info_t struct.
+grep '^type _mactun_info_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr_t/[16]byte/g' \
+ >> ${OUT}
+
+# The Solaris port_event_t struct.
+grep '^type _port_event_t ' gen-sysinfo.go | \
+ sed -e s'/_port_event_t/portevent/' \
+ >> ${OUT}
+
+# The *BSD kevent struct.
+grep '^type _kevent ' gen-sysinfo.go | \
+ sed -e s'/_kevent/keventt/' \
+ -e 's/ udata [^;}]*/ udata *byte/' \
+ >> ${OUT}
diff --git a/libgo/mksigtab.sh b/libgo/mksigtab.sh
new file mode 100644
index 0000000000..fd31022824
--- /dev/null
+++ b/libgo/mksigtab.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+# 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.
+
+# Create sigtab.go from gen-sysinfo.go.
+
+# This shell scripts creates the sigtab.go file, which maps signals to
+# their dispositions. We generate a file so that we can build a
+# composite literal that only refers to signals that are defined on
+# this system.
+
+# This script simply writes to standard output.
+
+set -e
+
+echo '// Generated by mksigtab.sh. Do not edit.'
+echo
+echo 'package runtime'
+echo
+echo 'var sigtable = [...]sigTabT{'
+
+# Handle signals valid on all Unix systems.
+
+echo ' 0: {0, "SIGNONE: no trap"},'
+echo ' _SIGHUP: {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},'
+echo ' _SIGINT: {_SigNotify + _SigKill, "SIGINT: interrupt"},'
+echo ' _SIGQUIT: {_SigNotify + _SigThrow, "SIGQUIT: quit"},'
+echo ' _SIGILL: {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},'
+echo ' _SIGTRAP: {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},'
+echo ' _SIGABRT: {_SigNotify + _SigThrow, "SIGABRT: abort"},'
+echo ' _SIGBUS: {_SigPanic + _SigUnblock, "SIGBUS: bus error"},'
+echo ' _SIGFPE: {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},'
+echo ' _SIGKILL: {0, "SIGKILL: kill"},'
+echo ' _SIGUSR1: {_SigNotify, "SIGUSR1: user-defined signal 1"},'
+echo ' _SIGSEGV: {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},'
+echo ' _SIGUSR2: {_SigNotify, "SIGUSR2: user-defined signal 2"},'
+echo ' _SIGPIPE: {_SigNotify, "SIGPIPE: write to broken pipe"},'
+echo ' _SIGALRM: {_SigNotify, "SIGALRM: alarm clock"},'
+echo ' _SIGTERM: {_SigNotify + _SigKill, "SIGTERM: termination"},'
+echo ' _SIGCHLD: {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},'
+echo ' _SIGCONT: {_SigNotify + _SigDefault, "SIGCONT: continue"},'
+echo ' _SIGSTOP: {0, "SIGSTOP: stop"},'
+echo ' _SIGTSTP: {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},'
+echo ' _SIGTTIN: {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},'
+echo ' _SIGTTOU: {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},'
+echo ' _SIGURG: {_SigNotify, "SIGURG: urgent condition on socket"},'
+echo ' _SIGXCPU: {_SigNotify, "SIGXCPU: cpu limit exceeded"},'
+echo ' _SIGXFSZ: {_SigNotify, "SIGXFSZ: file size limit exceeded"},'
+echo ' _SIGVTALRM: {_SigNotify, "SIGVTALRM: virtual alarm clock"},'
+echo ' _SIGPROF: {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},'
+echo ' _SIGWINCH: {_SigNotify, "SIGWINCH: window size change"},'
+echo ' _SIGSYS: {_SigThrow, "SIGSYS: bad system call"},'
+
+# Handle signals that are not supported on all systems.
+
+checksig() {
+ if grep "const $1 = " gen-sysinfo.go >/dev/null 2>&1 \
+ && ! grep "const $1 = _SIG" gen-sysinfo.go > /dev/null 2>&1; then
+ echo " $1: $2,"
+ fi
+}
+
+checksig _SIGSTKFLT ' {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"}'
+checksig _SIGIO ' {_SigNotify, "SIGIO: i/o now possible"}'
+checksig _SIGPWR ' {_SigNotify, "SIGPWR: power failure restart"}'
+checksig _SIGEMT ' {_SigThrow, "SIGEMT: emulate instruction executed"}'
+checksig _SIGINFO ' {_SigNotify, "SIGINFO: status request from keyboard"}'
+checksig _SIGTHR ' {_SigNotify, "SIGTHR: reserved"}'
+checksig _SIGPOLL ' {_SigNotify, "SIGPOLL: pollable event occurred"}'
+checksig _SIGWAITING '{_SigNotify, "SIGWAITING: reserved signal no longer used by"}'
+checksig _SIGLWP ' {_SigNotify, "SIGLWP: reserved signal no longer used by"}'
+checksig _SIGFREEZE ' {_SigNotify, "SIGFREEZE: special signal used by CPR"}'
+checksig _SIGTHAW ' {_SigNotify, "SIGTHAW: special signal used by CPR"}'
+checksig _SIGCANCEL ' {_SigSetStack + _SigUnblock, "SIGCANCEL: reserved signal for thread cancellation"}'
+checksig _SIGXRES ' {_SigNotify, "SIGXRES: resource control exceeded"}'
+checksig _SIGJVM1 ' {_SigNotify, "SIGJVM1: reserved signal for Java Virtual Machine"}'
+checksig _SIGJVM2 ' {_SigNotify, "SIGJVM2: reserved signal for Java Virtual Machine"}'
+
+# Special handling of signals 32 and 33 on GNU/Linux systems,
+# because they are special to glibc.
+if test "${GOOS}" = "linux"; then
+ echo ' 32: {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */'
+ echo ' 33: {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */'
+fi
+
+nsig=`grep 'const _*NSIG = [0-9]*$' gen-sysinfo.go | sed -e 's/.* = \([0-9]*\)/\1/'`
+i=1
+while test "$i" -lt "$nsig"; do
+ if ! grep "const _SIG.* = $i" gen-sysinfo.go >/dev/null 2>&1; then
+ if test "${GOOS}" != "linux" || test "$i" -ne 32 -a "$i" -ne 33; then
+ echo " $i: {_SigNotify, \"signal $i\"},"
+ fi
+ fi
+ i=`expr "$i" + 1`
+done
+
+echo '}'
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index 1271e1a550..ec2224db2b 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -4,278 +4,21 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# Create sysinfo.go.
+# Create sysinfo.go from gen-sysinfo.go and errno.i.
# This shell script creates the sysinfo.go file which holds types and
-# constants extracted from the system header files. This relies on a
-# hook in gcc: the -fdump-go-spec option will generate debugging
-# information in Go syntax.
+# constants extracted from the system header files. This reads the
+# raw data from gen-sysinfo.go which is generated using the
+# -fdump-go-spec option.
-# We currently #include all the files at once, which works, but leads
-# to exposing some names which ideally should not be exposed, as they
-# match grep patterns. E.g., WCHAR_MIN gets exposed because it starts
-# with W, like the wait flags.
+# This currently exposes some names that ideally should not be
+# exposed, as they match grep patterns. E.g., WCHAR_MIN gets exposed
+# because it starts with W, like the wait flags.
-CC=${CC:-gcc}
OUT=tmp-sysinfo.go
set -e
-rm -f sysinfo.c
-cat > sysinfo.c <<EOF
-#include "config.h"
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-/* <netinet/tcp.h> needs u_char/u_short, but <sys/bsd_types> is only
- included by <netinet/in.h> if _SGIAPI (i.e. _SGI_SOURCE
- && !_XOPEN_SOURCE.
- <sys/termios.h> only defines TIOCNOTTY if !_XOPEN_SOURCE, while
- <sys/ttold.h> does so unconditionally. */
-#ifdef __sgi__
-#include <sys/bsd_types.h>
-#include <sys/ttold.h>
-#endif
-#include <netinet/tcp.h>
-#if defined(HAVE_NETINET_IN_SYSTM_H)
-#include <netinet/in_systm.h>
-#endif
-#if defined(HAVE_NETINET_IP_H)
-#include <netinet/ip.h>
-#endif
-#if defined(HAVE_NETINET_IP_MROUTE_H)
-#include <netinet/ip_mroute.h>
-#endif
-#if defined(HAVE_NETINET_IF_ETHER_H)
-#include <netinet/if_ether.h>
-#endif
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#if defined(HAVE_SYSCALL_H)
-#include <syscall.h>
-#endif
-#if defined(HAVE_SYS_SYSCALL_H)
-#include <sys/syscall.h>
-#endif
-#if defined(HAVE_SYS_EPOLL_H)
-#include <sys/epoll.h>
-#endif
-#if defined(HAVE_SYS_FILE_H)
-#include <sys/file.h>
-#endif
-#if defined(HAVE_SYS_MMAN_H)
-#include <sys/mman.h>
-#endif
-#if defined(HAVE_SYS_PRCTL_H)
-#include <sys/prctl.h>
-#endif
-#if defined(HAVE_SYS_PTRACE_H)
-#include <sys/ptrace.h>
-#endif
-#include <sys/resource.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-#if defined(HAVE_SYS_USER_H)
-#include <sys/user.h>
-#endif
-#if defined(HAVE_SYS_UTSNAME_H)
-#include <sys/utsname.h>
-#endif
-#if defined(HAVE_SYS_SELECT_H)
-#include <sys/select.h>
-#endif
-#include <time.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <pwd.h>
-#if defined(HAVE_LINUX_FILTER_H)
-#include <linux/filter.h>
-#endif
-#if defined(HAVE_LINUX_IF_ADDR_H)
-#include <linux/if_addr.h>
-#endif
-#if defined(HAVE_LINUX_IF_ETHER_H)
-#include <linux/if_ether.h>
-#endif
-#if defined(HAVE_LINUX_IF_TUN_H)
-#include <linux/if_tun.h>
-#endif
-#if defined(HAVE_LINUX_NETLINK_H)
-#include <linux/netlink.h>
-#endif
-#if defined(HAVE_LINUX_RTNETLINK_H)
-#include <linux/rtnetlink.h>
-#endif
-#if defined(HAVE_NET_IF_H)
-#include <net/if.h>
-#endif
-#if defined(HAVE_NET_IF_ARP_H)
-#include <net/if_arp.h>
-#endif
-#if defined(HAVE_NET_ROUTE_H)
-#include <net/route.h>
-#endif
-#if defined (HAVE_NETPACKET_PACKET_H)
-#include <netpacket/packet.h>
-#endif
-#if defined(HAVE_SYS_MOUNT_H)
-#include <sys/mount.h>
-#endif
-#if defined(HAVE_SYS_VFS_H)
-#include <sys/vfs.h>
-#endif
-#if defined(HAVE_STATFS_H)
-#include <sys/statfs.h>
-#endif
-#if defined(HAVE_SYS_TIMEX_H)
-#include <sys/timex.h>
-#endif
-#if defined(HAVE_SYS_SYSINFO_H)
-#include <sys/sysinfo.h>
-#endif
-#if defined(HAVE_USTAT_H)
-#include <ustat.h>
-#endif
-#if defined(HAVE_UTIME_H)
-#include <utime.h>
-#endif
-#if defined(HAVE_LINUX_ETHER_H)
-#include <linux/ether.h>
-#endif
-#if defined(HAVE_LINUX_FS_H)
-#include <linux/fs.h>
-#endif
-#if defined(HAVE_LINUX_REBOOT_H)
-#include <linux/reboot.h>
-#endif
-#if defined(HAVE_SYS_INOTIFY_H)
-#include <sys/inotify.h>
-#endif
-#if defined(HAVE_NETINET_ICMP6_H)
-#include <netinet/icmp6.h>
-#endif
-#if defined(HAVE_SCHED_H)
-#include <sched.h>
-#endif
-
-/* Constants that may only be defined as expressions on some systems,
- expressions too complex for -fdump-go-spec to handle. These are
- handled specially below. */
-enum {
-#ifdef TIOCGWINSZ
- TIOCGWINSZ_val = TIOCGWINSZ,
-#endif
-#ifdef TIOCSWINSZ
- TIOCSWINSZ_val = TIOCSWINSZ,
-#endif
-#ifdef TIOCNOTTY
- TIOCNOTTY_val = TIOCNOTTY,
-#endif
-#ifdef TIOCSCTTY
- TIOCSCTTY_val = TIOCSCTTY,
-#endif
-#ifdef TIOCGPGRP
- TIOCGPGRP_val = TIOCGPGRP,
-#endif
-#ifdef TIOCSPGRP
- TIOCSPGRP_val = TIOCSPGRP,
-#endif
-#ifdef TIOCGPTN
- TIOCGPTN_val = TIOCGPTN,
-#endif
-#ifdef TIOCSPTLCK
- TIOCSPTLCK_val = TIOCSPTLCK,
-#endif
-#ifdef TIOCGDEV
- TIOCGDEV_val = TIOCGDEV,
-#endif
-#ifdef TIOCSIG
- TIOCSIG_val = TIOCSIG,
-#endif
-#ifdef TCGETS
- TCGETS_val = TCGETS,
-#endif
-#ifdef TCSETS
- TCSETS_val = TCSETS,
-#endif
-#ifdef TUNSETIFF
- TUNSETIFF_val = TUNSETIFF,
-#endif
-#ifdef TUNSETNOCSUM
- TUNSETNOCSUM_val = TUNSETNOCSUM,
-#endif
-#ifdef TUNSETDEBUG
- TUNSETDEBUG_val = TUNSETDEBUG,
-#endif
-#ifdef TUNSETPERSIST
- TUNSETPERSIST_val = TUNSETPERSIST,
-#endif
-#ifdef TUNSETOWNER
- TUNSETOWNER_val = TUNSETOWNER,
-#endif
-#ifdef TUNSETLINK
- TUNSETLINK_val = TUNSETLINK,
-#endif
-#ifdef TUNSETGROUP
- TUNSETGROUP_val = TUNSETGROUP,
-#endif
-#ifdef TUNGETFEATURES
- TUNGETFEATURES_val = TUNGETFEATURES,
-#endif
-#ifdef TUNSETOFFLOAD
- TUNSETOFFLOAD_val = TUNSETOFFLOAD,
-#endif
-#ifdef TUNSETTXFILTER
- TUNSETTXFILTER_val = TUNSETTXFILTER,
-#endif
-#ifdef TUNGETIFF
- TUNGETIFF_val = TUNGETIFF,
-#endif
-#ifdef TUNGETSNDBUF
- TUNGETSNDBUF_val = TUNGETSNDBUF,
-#endif
-#ifdef TUNSETSNDBUF
- TUNSETSNDBUF_val = TUNSETSNDBUF,
-#endif
-#ifdef TUNATTACHFILTER
- TUNATTACHFILTER_val = TUNATTACHFILTER,
-#endif
-#ifdef TUNDETACHFILTER
- TUNDETACHFILTER_val = TUNDETACHFILTER,
-#endif
-#ifdef TUNGETVNETHDRSZ
- TUNGETVNETHDRSZ_val = TUNGETVNETHDRSZ,
-#endif
-#ifdef TUNSETVNETHDRSZ
- TUNSETVNETHDRSZ_val = TUNSETVNETHDRSZ,
-#endif
-#ifdef TUNSETQUEUE
- TUNSETQUEUE_val = TUNSETQUEUE,
-#endif
-#ifdef TUNSETIFINDEX
- TUNSETIFINDEX_val = TUNSETIFINDEX,
-#endif
-#ifdef TUNGETFILTER
- TUNGETFILTER_val = TUNGETFILTER,
-#endif
-#ifdef NLA_HDRLEN
- NLA_HDRLEN_val = NLA_HDRLEN,
-#endif
-
-};
-EOF
-
-${CC} -fdump-go-spec=gen-sysinfo.go -std=gnu99 -S -o sysinfo.s sysinfo.c
-
echo 'package syscall' > ${OUT}
echo 'import "unsafe"' >> ${OUT}
echo 'type _ unsafe.Pointer' >> ${OUT}
@@ -300,8 +43,7 @@ grep -v '^// ' gen-sysinfo.go | \
>> ${OUT}
# The errno constants. These get type Errno.
-echo '#include <errno.h>' | ${CC} -x c - -E -dM | \
- egrep '#define E[A-Z0-9_]+ ' | \
+ egrep '#define E[A-Z0-9_]+ ' errno.i | \
sed -e 's/^#define \(E[A-Z0-9_]*\) .*$/const \1 = Errno(_\1)/' >> ${OUT}
# The O_xxx flags.
@@ -428,6 +170,10 @@ if ! grep '^const AF_LOCAL ' ${OUT} >/dev/null 2>&1; then
fi
fi
+# sysconf constants.
+grep '^const __SC' gen-sysinfo.go |
+ sed -e 's/^\(const \)__\(SC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT}
+
# pathconf constants.
grep '^const __PC' gen-sysinfo.go |
sed -e 's/^\(const \)__\(PC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT}
@@ -439,7 +185,15 @@ fi
# epoll constants.
grep '^const _EPOLL' gen-sysinfo.go |
+ grep -v EPOLLET |
sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# Make sure EPOLLET is positive.
+if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go >/dev/null 2>&1; then
+ grep '^const _EPOLLET ' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+else
+ echo "const EPOLLET = 0x80000000" >> ${OUT}
+fi
# Make sure EPOLLRDHUP and EPOLL_CLOEXEC are defined.
if ! grep '^const EPOLLRDHUP' ${OUT} >/dev/null 2>&1; then
echo "const EPOLLRDHUP = 0x2000" >> ${OUT}
@@ -514,7 +268,7 @@ fi
# is not empty, the structure or type is renamed to $2.
upcase_fields () {
name="$1"
- def=`grep "^type $name" gen-sysinfo.go`
+ def=`grep "^type $name " gen-sysinfo.go`
fields=`echo $def | sed -e 's/^[^{]*{\(.*\)}$/\1/'`
prefix=`echo $def | sed -e 's/{.*//'`
if test "$2" != ""; then
@@ -603,8 +357,10 @@ fi
sizeof_long=`grep '^const ___SIZEOF_LONG__ = ' gen-sysinfo.go | sed -e 's/.*= //'`
if test "$sizeof_long" = "4"; then
echo "type _C_long int32" >> ${OUT}
+ echo "type _C_ulong uint32" >> ${OUT}
elif test "$sizeof_long" = "8"; then
echo "type _C_long int64" >> ${OUT}
+ echo "type _C_ulong uint64" >> ${OUT}
else
echo 1>&2 "mksysinfo.sh: could not determine size of long (got $sizeof_long)"
exit 1
@@ -906,6 +662,12 @@ grep '^type _passwd ' gen-sysinfo.go | \
-e 's/ pw_/ Pw_/g' \
>> ${OUT}
+# The group struct.
+grep '^type _group ' gen-sysinfo.go | \
+ sed -e 's/_group/Group/' \
+ -e 's/ gr_/ Gr_/g' \
+ >> ${OUT}
+
# The ioctl flags for the controlling TTY.
grep '^const _TIOC' gen-sysinfo.go | \
grep -v '_val =' | \
@@ -1464,6 +1226,9 @@ grep '^const _CLONE_' gen-sysinfo.go | \
if ! grep '^const CLONE_NEWUSER ' ${OUT} > /dev/null 2>&1; then
echo "const CLONE_NEWUSER = 0x10000000" >> ${OUT}
fi
+if ! grep '^const CLONE_NEWNET ' ${OUT} > /dev/null 2>&1; then
+ echo "const CLONE_NEWNET = 0x40000000" >> ${OUT}
+fi
# Struct sizes.
set cmsghdr Cmsghdr ip_mreq IPMreq ip_mreqn IPMreqn ipv6_mreq IPv6Mreq \
diff --git a/libgo/runtime/aeshash.c b/libgo/runtime/aeshash.c
new file mode 100644
index 0000000000..7f29baa07b
--- /dev/null
+++ b/libgo/runtime/aeshash.c
@@ -0,0 +1,586 @@
+// 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.
+
+// Hash code using AES intrinsics.
+
+#include "runtime.h"
+
+uintptr aeshashbody(void*, uintptr, uintptr, Slice)
+ __asm__(GOSYM_PREFIX "runtime.aeshashbody");
+
+uintptr aeshashbody(void*, uintptr, uintptr, Slice)
+ __attribute__((no_split_stack));
+
+#if (defined(__i386__) || defined(__x86_64__)) && defined(HAVE_AS_X86_AES)
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+#include <wmmintrin.h>
+
+// Force appropriate CPU level. We won't call here unless the CPU
+// supports it.
+
+#pragma GCC target("ssse3", "aes")
+
+#ifdef __x86_64__
+
+// aeshashbody implements a hash function using AES instructions
+// available in recent x86 processors. Note this is not encryption,
+// just hashing.
+//
+// This is written to produce exactly the same results as the gc
+// implementation, not because that matters, but just to ensure that
+// this does something reasonable.
+uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) {
+ __m128i mseed, mseed2, mseed3, mseed4, mseed5, mseed6, mseed7, mseed8;
+ __m128i mval, mval2, mval3, mval4, mval5, mval6, mval7, mval8;
+
+ // Start with hash seed.
+ mseed = _mm_cvtsi64_si128(seed);
+ // Get 16 bits of length.
+ mseed = _mm_insert_epi16(mseed, size, 4);
+ // Repeat length 4 times total.
+ mseed = _mm_shufflehi_epi16(mseed, 0);
+ // Save unscrambled seed.
+ mseed2 = mseed;
+ // XOR in per-process seed.
+ mseed ^= _mm_loadu_si128(aeskeysched.__values);
+ // Scramble seed.
+ mseed = _mm_aesenc_si128(mseed, mseed);
+
+ if (size <= 16) {
+ if (size == 0) {
+ // Return scrambled input seed.
+ return _mm_cvtsi128_si64(_mm_aesenc_si128(mseed, mseed));
+ } else if (size < 16) {
+ if ((((uintptr)(p) + 16) & 0xff0) != 0) {
+ static const uint64 masks[32]
+ __attribute__ ((aligned(16))) =
+ {
+ 0x0000000000000000, 0x0000000000000000,
+ 0x00000000000000ff, 0x0000000000000000,
+ 0x000000000000ffff, 0x0000000000000000,
+ 0x0000000000ffffff, 0x0000000000000000,
+ 0x00000000ffffffff, 0x0000000000000000,
+ 0x000000ffffffffff, 0x0000000000000000,
+ 0x0000ffffffffffff, 0x0000000000000000,
+ 0x00ffffffffffffff, 0x0000000000000000,
+ 0xffffffffffffffff, 0x0000000000000000,
+ 0xffffffffffffffff, 0x00000000000000ff,
+ 0xffffffffffffffff, 0x000000000000ffff,
+ 0xffffffffffffffff, 0x0000000000ffffff,
+ 0xffffffffffffffff, 0x00000000ffffffff,
+ 0xffffffffffffffff, 0x000000ffffffffff,
+ 0xffffffffffffffff, 0x0000ffffffffffff,
+ 0xffffffffffffffff, 0x00ffffffffffffff
+ };
+
+ // 16 bytes loaded at p won't cross a page
+ // boundary, so we can load directly.
+ mval = _mm_loadu_si128(p);
+ mval &= *(const __m128i*)(&masks[size*2]);
+ } else {
+ static const uint64 shifts[32]
+ __attribute__ ((aligned(16))) =
+ {
+ 0x0000000000000000, 0x0000000000000000,
+ 0xffffffffffffff0f, 0xffffffffffffffff,
+ 0xffffffffffff0f0e, 0xffffffffffffffff,
+ 0xffffffffff0f0e0d, 0xffffffffffffffff,
+ 0xffffffff0f0e0d0c, 0xffffffffffffffff,
+ 0xffffff0f0e0d0c0b, 0xffffffffffffffff,
+ 0xffff0f0e0d0c0b0a, 0xffffffffffffffff,
+ 0xff0f0e0d0c0b0a09, 0xffffffffffffffff,
+ 0x0f0e0d0c0b0a0908, 0xffffffffffffffff,
+ 0x0e0d0c0b0a090807, 0xffffffffffffff0f,
+ 0x0d0c0b0a09080706, 0xffffffffffff0f0e,
+ 0x0c0b0a0908070605, 0xffffffffff0f0e0d,
+ 0x0b0a090807060504, 0xffffffff0f0e0d0c,
+ 0x0a09080706050403, 0xffffff0f0e0d0c0b,
+ 0x0908070605040302, 0xffff0f0e0d0c0b0a,
+ 0x0807060504030201, 0xff0f0e0d0c0b0a09,
+ };
+
+ // address ends in 1111xxxx. Might be
+ // up against a page boundary, so load
+ // ending at last byte. Then shift
+ // bytes down using pshufb.
+ mval = _mm_loadu_si128((void*)((char*)p - 16 + size));
+ mval = _mm_shuffle_epi8(mval, *(const __m128i*)(&shifts[size*2]));
+ }
+ } else {
+ mval = _mm_loadu_si128(p);
+ }
+
+ // XOR data with seed.
+ mval ^= mseed;
+ // Scramble combo 3 times.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval = _mm_aesenc_si128(mval, mval);
+ return _mm_cvtsi128_si64(mval);
+ } else if (size <= 32) {
+ // Make second starting seed.
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ // Load data to be hashed.
+ mval = _mm_loadu_si128(p);
+ mval2 = _mm_loadu_si128((void*)((char*)p + size - 16));
+ // XOR with seed.
+ mval ^= mseed;
+ mval2 ^= mseed2;
+ // Scramble 3 times.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ // Combine results.
+ mval ^= mval2;
+ return _mm_cvtsi128_si64(mval);
+ } else if (size <= 64) {
+ // Make 3 more starting seeds.
+ mseed3 = mseed2;
+ mseed4 = mseed2;
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed3 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 32));
+ mseed4 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 48));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ mseed3 = _mm_aesenc_si128(mseed3, mseed3);
+ mseed4 = _mm_aesenc_si128(mseed4, mseed4);
+
+ mval = _mm_loadu_si128(p);
+ mval2 = _mm_loadu_si128((void*)((char*)p + 16));
+ mval3 = _mm_loadu_si128((void*)((char*)p + size - 32));
+ mval4 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ mval ^= mseed;
+ mval2 ^= mseed2;
+ mval3 ^= mseed3;
+ mval4 ^= mseed4;
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval ^= mval3;
+ mval2 ^= mval4;
+ mval ^= mval2;
+ return _mm_cvtsi128_si64(mval);
+ } else if (size <= 128) {
+ // Make 7 more starting seeds.
+ mseed3 = mseed2;
+ mseed4 = mseed2;
+ mseed5 = mseed2;
+ mseed6 = mseed2;
+ mseed7 = mseed2;
+ mseed8 = mseed2;
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed3 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 32));
+ mseed4 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 48));
+ mseed5 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 64));
+ mseed6 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 80));
+ mseed7 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 96));
+ mseed8 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 112));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ mseed3 = _mm_aesenc_si128(mseed3, mseed3);
+ mseed4 = _mm_aesenc_si128(mseed4, mseed4);
+ mseed5 = _mm_aesenc_si128(mseed5, mseed5);
+ mseed6 = _mm_aesenc_si128(mseed6, mseed6);
+ mseed7 = _mm_aesenc_si128(mseed7, mseed7);
+ mseed8 = _mm_aesenc_si128(mseed8, mseed8);
+
+ // Load data.
+ mval = _mm_loadu_si128(p);
+ mval2 = _mm_loadu_si128((void*)((char*)p + 16));
+ mval3 = _mm_loadu_si128((void*)((char*)p + 32));
+ mval4 = _mm_loadu_si128((void*)((char*)p + 48));
+ mval5 = _mm_loadu_si128((void*)((char*)p + size - 64));
+ mval6 = _mm_loadu_si128((void*)((char*)p + size - 48));
+ mval7 = _mm_loadu_si128((void*)((char*)p + size - 32));
+ mval8 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ // XOR with seed.
+ mval ^= mseed;
+ mval2 ^= mseed2;
+ mval3 ^= mseed3;
+ mval4 ^= mseed4;
+ mval5 ^= mseed5;
+ mval6 ^= mseed6;
+ mval7 ^= mseed7;
+ mval8 ^= mseed8;
+
+ // Scramble 3 times.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+
+ // Combine results.
+ mval ^= mval5;
+ mval2 ^= mval6;
+ mval3 ^= mval7;
+ mval4 ^= mval8;
+ mval ^= mval3;
+ mval2 ^= mval4;
+ mval ^= mval2;
+ return _mm_cvtsi128_si64(mval);
+ } else {
+ // Make 7 more starting seeds.
+ mseed3 = mseed2;
+ mseed4 = mseed2;
+ mseed5 = mseed2;
+ mseed6 = mseed2;
+ mseed7 = mseed2;
+ mseed8 = mseed2;
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed3 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 32));
+ mseed4 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 48));
+ mseed5 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 64));
+ mseed6 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 80));
+ mseed7 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 96));
+ mseed8 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 112));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ mseed3 = _mm_aesenc_si128(mseed3, mseed3);
+ mseed4 = _mm_aesenc_si128(mseed4, mseed4);
+ mseed5 = _mm_aesenc_si128(mseed5, mseed5);
+ mseed6 = _mm_aesenc_si128(mseed6, mseed6);
+ mseed7 = _mm_aesenc_si128(mseed7, mseed7);
+ mseed8 = _mm_aesenc_si128(mseed8, mseed8);
+
+ // Start with last (possibly overlapping) block.
+ mval = _mm_loadu_si128((void*)((char*)p + size - 128));
+ mval2 = _mm_loadu_si128((void*)((char*)p + size - 112));
+ mval3 = _mm_loadu_si128((void*)((char*)p + size - 96));
+ mval4 = _mm_loadu_si128((void*)((char*)p + size - 80));
+ mval5 = _mm_loadu_si128((void*)((char*)p + size - 64));
+ mval6 = _mm_loadu_si128((void*)((char*)p + size - 48));
+ mval7 = _mm_loadu_si128((void*)((char*)p + size - 32));
+ mval8 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ // XOR in seed.
+ mval ^= mseed;
+ mval2 ^= mseed2;
+ mval3 ^= mseed3;
+ mval4 ^= mseed4;
+ mval5 ^= mseed5;
+ mval6 ^= mseed6;
+ mval7 ^= mseed7;
+ mval8 ^= mseed8;
+
+ // Compute number of remaining 128-byte blocks.
+ size--;
+ size >>= 7;
+ do {
+ // Scramble state.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+
+ // Scramble state, XOR in a block.
+ mval = _mm_aesenc_si128(mval, _mm_loadu_si128(p));
+ mval2 = _mm_aesenc_si128(mval2, _mm_loadu_si128((void*)((char*)p + 16)));
+ mval3 = _mm_aesenc_si128(mval3, _mm_loadu_si128((void*)((char*)p + 32)));
+ mval4 = _mm_aesenc_si128(mval4, _mm_loadu_si128((void*)((char*)p + 48)));
+ mval5 = _mm_aesenc_si128(mval5, _mm_loadu_si128((void*)((char*)p + 64)));
+ mval6 = _mm_aesenc_si128(mval6, _mm_loadu_si128((void*)((char*)p + 80)));
+ mval7 = _mm_aesenc_si128(mval7, _mm_loadu_si128((void*)((char*)p + 96)));
+ mval8 = _mm_aesenc_si128(mval8, _mm_loadu_si128((void*)((char*)p + 112)));
+
+ p = (void*)((char*)p + 128);
+ } while (--size > 0);
+
+ // 3 more scrambles to finish.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+ mval5 = _mm_aesenc_si128(mval5, mval5);
+ mval6 = _mm_aesenc_si128(mval6, mval6);
+ mval7 = _mm_aesenc_si128(mval7, mval7);
+ mval8 = _mm_aesenc_si128(mval8, mval8);
+
+ mval ^= mval5;
+ mval2 ^= mval6;
+ mval3 ^= mval7;
+ mval4 ^= mval8;
+ mval ^= mval3;
+ mval2 ^= mval4;
+ mval ^= mval2;
+ return _mm_cvtsi128_si64(mval);
+ }
+}
+
+#else // !defined(__x86_64__)
+
+// The 32-bit version of aeshashbody.
+
+uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) {
+ __m128i mseed, mseed2, mseed3, mseed4;
+ __m128i mval, mval2, mval3, mval4;
+
+ // Start with hash seed.
+ mseed = _mm_cvtsi32_si128(seed);
+ // Get 16 bits of length.
+ mseed = _mm_insert_epi16(mseed, size, 4);
+ // Replace size with its low 2 bytes repeated 4 times.
+ mseed = _mm_shufflehi_epi16(mseed, 0);
+ // Save unscrambled seed.
+ mseed2 = mseed;
+ // XOR in per-process seed.
+ mseed ^= _mm_loadu_si128(aeskeysched.__values);
+ // Scramble seed.
+ mseed = _mm_aesenc_si128(mseed, mseed);
+
+ if (size <= 16) {
+ if (size == 0) {
+ // Return scrambled input seed.
+ return _mm_cvtsi128_si32(_mm_aesenc_si128(mseed, mseed));
+ } else if (size < 16) {
+ if ((((uintptr)(p) + 16) & 0xff0) != 0) {
+ static const uint64 masks[32]
+ __attribute__ ((aligned(16))) =
+ {
+ 0x0000000000000000, 0x0000000000000000,
+ 0x00000000000000ff, 0x0000000000000000,
+ 0x000000000000ffff, 0x0000000000000000,
+ 0x0000000000ffffff, 0x0000000000000000,
+ 0x00000000ffffffff, 0x0000000000000000,
+ 0x000000ffffffffff, 0x0000000000000000,
+ 0x0000ffffffffffff, 0x0000000000000000,
+ 0x00ffffffffffffff, 0x0000000000000000,
+ 0xffffffffffffffff, 0x0000000000000000,
+ 0xffffffffffffffff, 0x00000000000000ff,
+ 0xffffffffffffffff, 0x000000000000ffff,
+ 0xffffffffffffffff, 0x0000000000ffffff,
+ 0xffffffffffffffff, 0x00000000ffffffff,
+ 0xffffffffffffffff, 0x000000ffffffffff,
+ 0xffffffffffffffff, 0x0000ffffffffffff,
+ 0xffffffffffffffff, 0x00ffffffffffffff
+ };
+
+ // 16 bytes loaded at p won't cross a page
+ // boundary, so we can load it directly.
+ mval = _mm_loadu_si128(p);
+ mval &= *(const __m128i*)(&masks[size*2]);
+ } else {
+ static const uint64 shifts[32]
+ __attribute__ ((aligned(16))) =
+ {
+ 0x0000000000000000, 0x0000000000000000,
+ 0xffffffffffffff0f, 0xffffffffffffffff,
+ 0xffffffffffff0f0e, 0xffffffffffffffff,
+ 0xffffffffff0f0e0d, 0xffffffffffffffff,
+ 0xffffffff0f0e0d0c, 0xffffffffffffffff,
+ 0xffffff0f0e0d0c0b, 0xffffffffffffffff,
+ 0xffff0f0e0d0c0b0a, 0xffffffffffffffff,
+ 0xff0f0e0d0c0b0a09, 0xffffffffffffffff,
+ 0x0f0e0d0c0b0a0908, 0xffffffffffffffff,
+ 0x0e0d0c0b0a090807, 0xffffffffffffff0f,
+ 0x0d0c0b0a09080706, 0xffffffffffff0f0e,
+ 0x0c0b0a0908070605, 0xffffffffff0f0e0d,
+ 0x0b0a090807060504, 0xffffffff0f0e0d0c,
+ 0x0a09080706050403, 0xffffff0f0e0d0c0b,
+ 0x0908070605040302, 0xffff0f0e0d0c0b0a,
+ 0x0807060504030201, 0xff0f0e0d0c0b0a09,
+ };
+
+ // address ends in 1111xxxx. Might be
+ // up against a page boundary, so load
+ // ending at last byte. Then shift
+ // bytes down using pshufb.
+ mval = _mm_loadu_si128((void*)((char*)p - 16 + size));
+ mval = _mm_shuffle_epi8(mval, *(const __m128i*)(&shifts[size*2]));
+ }
+ } else {
+ mval = _mm_loadu_si128(p);
+ }
+
+ // Scramble input, XOR in seed.
+ mval = _mm_aesenc_si128(mval, mseed);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval = _mm_aesenc_si128(mval, mval);
+ return _mm_cvtsi128_si32(mval);
+ } else if (size <= 32) {
+ // Make second starting seed.
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ // Load data to be hashed.
+ mval = _mm_loadu_si128(p);
+ mval2 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ // Scramble 3 times.
+ mval = _mm_aesenc_si128(mval, mseed);
+ mval2 = _mm_aesenc_si128(mval2, mseed2);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+
+ // Combine results.
+ mval ^= mval2;
+ return _mm_cvtsi128_si32(mval);
+ } else if (size <= 64) {
+ // Make 3 more starting seeds.
+ mseed3 = mseed2;
+ mseed4 = mseed2;
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed3 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 32));
+ mseed4 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 48));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ mseed3 = _mm_aesenc_si128(mseed3, mseed3);
+ mseed4 = _mm_aesenc_si128(mseed4, mseed4);
+
+ mval = _mm_loadu_si128(p);
+ mval2 = _mm_loadu_si128((void*)((char*)p + 16));
+ mval3 = _mm_loadu_si128((void*)((char*)p + size - 32));
+ mval4 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ mval = _mm_aesenc_si128(mval, mseed);
+ mval2 = _mm_aesenc_si128(mval2, mseed2);
+ mval3 = _mm_aesenc_si128(mval3, mseed3);
+ mval4 = _mm_aesenc_si128(mval4, mseed4);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval ^= mval3;
+ mval2 ^= mval4;
+ mval ^= mval2;
+ return _mm_cvtsi128_si32(mval);
+ } else {
+ // Make 3 more starting seeds.
+ mseed3 = mseed2;
+ mseed4 = mseed2;
+ mseed2 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 16));
+ mseed3 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 32));
+ mseed4 ^= _mm_loadu_si128((void*)((char*)aeskeysched.__values + 48));
+ mseed2 = _mm_aesenc_si128(mseed2, mseed2);
+ mseed3 = _mm_aesenc_si128(mseed3, mseed3);
+ mseed4 = _mm_aesenc_si128(mseed4, mseed4);
+
+ // Start with last (possibly overlapping) block.
+ mval = _mm_loadu_si128((void*)((char*)p + size - 64));
+ mval2 = _mm_loadu_si128((void*)((char*)p + size - 48));
+ mval3 = _mm_loadu_si128((void*)((char*)p + size - 32));
+ mval4 = _mm_loadu_si128((void*)((char*)p + size - 16));
+
+ // Scramble state once.
+ mval = _mm_aesenc_si128(mval, mseed);
+ mval2 = _mm_aesenc_si128(mval2, mseed2);
+ mval3 = _mm_aesenc_si128(mval3, mseed3);
+ mval4 = _mm_aesenc_si128(mval4, mseed4);
+
+ // Compute number of remaining 64-byte blocks.
+ size--;
+ size >>= 6;
+ do {
+ // Scramble state, XOR in a block.
+ mval = _mm_aesenc_si128(mval, _mm_loadu_si128(p));
+ mval2 = _mm_aesenc_si128(mval2, _mm_loadu_si128((void*)((char*)p + 16)));
+ mval3 = _mm_aesenc_si128(mval3, _mm_loadu_si128((void*)((char*)p + 32)));
+ mval4 = _mm_aesenc_si128(mval4, _mm_loadu_si128((void*)((char*)p + 48)));
+
+ // Scramble state.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ p = (void*)((char*)p + 64);
+ } while (--size > 0);
+
+ // 2 more scrambles to finish.
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval = _mm_aesenc_si128(mval, mval);
+ mval2 = _mm_aesenc_si128(mval2, mval2);
+ mval3 = _mm_aesenc_si128(mval3, mval3);
+ mval4 = _mm_aesenc_si128(mval4, mval4);
+
+ mval ^= mval3;
+ mval2 ^= mval4;
+ mval ^= mval2;
+ return _mm_cvtsi128_si32(mval);
+ }
+}
+
+#endif // !defined(__x86_64__)
+
+#else // !defined(__i386__) && !defined(__x86_64__) || !defined(HAVE_AS_X86_AES)
+
+uintptr aeshashbody(void* p __attribute__((unused)),
+ uintptr seed __attribute__((unused)),
+ uintptr size __attribute__((unused)),
+ Slice aeskeysched __attribute__((unused))) {
+ // We should never get here on a non-x86 system.
+ runtime_throw("impossible call to aeshashbody");
+}
+
+#endif // !defined(__i386__) && !defined(__x86_64__) || !defined(HAVE_AS_X86_AES)
diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc
deleted file mode 100644
index 0cc823d8ac..0000000000
--- a/libgo/runtime/chan.goc
+++ /dev/null
@@ -1,1136 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-#include "go-type.h"
-#include "malloc.h"
-#include "chan.h"
-
-uint32 runtime_Hchansize = sizeof(Hchan);
-
-static void dequeueg(WaitQ*);
-static SudoG* dequeue(WaitQ*);
-static void enqueue(WaitQ*, SudoG*);
-
-static Hchan*
-makechan(ChanType *t, int64 hint)
-{
- Hchan *c;
- uintptr n;
- const Type *elem;
-
- elem = t->__element_type;
-
- // compiler checks this but be safe.
- if(elem->__size >= (1<<16))
- runtime_throw("makechan: invalid channel element type");
-
- if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > (MaxMem - sizeof(*c)) / elem->__size))
- runtime_panicstring("makechan: size out of range");
-
- n = sizeof(*c);
- n = ROUND(n, elem->__align);
-
- // allocate memory in one call
- c = (Hchan*)runtime_mallocgc(sizeof(*c) + hint*elem->__size, (uintptr)t | TypeInfo_Chan, 0);
- c->elemsize = elem->__size;
- c->elemtype = elem;
- c->dataqsiz = hint;
-
- if(debug)
- runtime_printf("makechan: chan=%p; elemsize=%D; dataqsiz=%D\n",
- c, (int64)elem->__size, (int64)c->dataqsiz);
-
- return c;
-}
-
-func reflect.makechan(t *ChanType, size uint64) (c *Hchan) {
- c = makechan(t, size);
-}
-
-Hchan*
-__go_new_channel(ChanType *t, uintptr hint)
-{
- return makechan(t, hint);
-}
-
-Hchan*
-__go_new_channel_big(ChanType *t, uint64 hint)
-{
- return makechan(t, hint);
-}
-
-/*
- * generic single channel send/recv
- * if the bool pointer is nil,
- * then the full exchange will
- * occur. if pres is not nil,
- * then the protocol will not
- * sleep but return if it could
- * not complete.
- *
- * sleep can wake up with g->param == nil
- * when a channel involved in the sleep has
- * been closed. it is easiest to loop and re-run
- * the operation; we'll see that it's now closed.
- */
-static bool
-chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc)
-{
- USED(pc);
- SudoG *sg;
- SudoG mysg;
- G* gp;
- int64 t0;
- G* g;
-
- g = runtime_g();
-
- if(c == nil) {
- USED(t);
- if(!block)
- return false;
- runtime_park(nil, nil, "chan send (nil chan)");
- return false; // not reached
- }
-
- if(runtime_gcwaiting())
- runtime_gosched();
-
- if(debug) {
- runtime_printf("chansend: chan=%p\n", c);
- }
-
- t0 = 0;
- mysg.releasetime = 0;
- if(runtime_blockprofilerate > 0) {
- t0 = runtime_cputicks();
- mysg.releasetime = -1;
- }
-
- runtime_lock(c);
- if(c->closed)
- goto closed;
-
- if(c->dataqsiz > 0)
- goto asynch;
-
- sg = dequeue(&c->recvq);
- if(sg != nil) {
- runtime_unlock(c);
-
- gp = sg->g;
- gp->param = sg;
- if(sg->elem != nil)
- runtime_memmove(sg->elem, ep, c->elemsize);
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- return true;
- }
-
- if(!block) {
- runtime_unlock(c);
- return false;
- }
-
- mysg.elem = ep;
- mysg.g = g;
- mysg.selectdone = nil;
- g->param = nil;
- enqueue(&c->sendq, &mysg);
- runtime_parkunlock(c, "chan send");
-
- if(g->param == nil) {
- runtime_lock(c);
- if(!c->closed)
- runtime_throw("chansend: spurious wakeup");
- goto closed;
- }
-
- if(mysg.releasetime > 0)
- runtime_blockevent(mysg.releasetime - t0, 2);
-
- return true;
-
-asynch:
- if(c->closed)
- goto closed;
-
- if(c->qcount >= c->dataqsiz) {
- if(!block) {
- runtime_unlock(c);
- return false;
- }
- mysg.g = g;
- mysg.elem = nil;
- mysg.selectdone = nil;
- enqueue(&c->sendq, &mysg);
- runtime_parkunlock(c, "chan send");
-
- runtime_lock(c);
- goto asynch;
- }
-
- runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize);
- if(++c->sendx == c->dataqsiz)
- c->sendx = 0;
- c->qcount++;
-
- sg = dequeue(&c->recvq);
- if(sg != nil) {
- gp = sg->g;
- runtime_unlock(c);
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- } else
- runtime_unlock(c);
- if(mysg.releasetime > 0)
- runtime_blockevent(mysg.releasetime - t0, 2);
- return true;
-
-closed:
- runtime_unlock(c);
- runtime_panicstring("send on closed channel");
- return false; // not reached
-}
-
-
-static bool
-chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received)
-{
- SudoG *sg;
- SudoG mysg;
- G *gp;
- int64 t0;
- G *g;
-
- if(runtime_gcwaiting())
- runtime_gosched();
-
- if(debug)
- runtime_printf("chanrecv: chan=%p\n", c);
-
- g = runtime_g();
-
- if(c == nil) {
- USED(t);
- if(!block)
- return false;
- runtime_park(nil, nil, "chan receive (nil chan)");
- return false; // not reached
- }
-
- t0 = 0;
- mysg.releasetime = 0;
- if(runtime_blockprofilerate > 0) {
- t0 = runtime_cputicks();
- mysg.releasetime = -1;
- }
-
- runtime_lock(c);
- if(c->dataqsiz > 0)
- goto asynch;
-
- if(c->closed)
- goto closed;
-
- sg = dequeue(&c->sendq);
- if(sg != nil) {
- runtime_unlock(c);
-
- if(ep != nil)
- runtime_memmove(ep, sg->elem, c->elemsize);
- gp = sg->g;
- gp->param = sg;
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
-
- if(received != nil)
- *received = true;
- return true;
- }
-
- if(!block) {
- runtime_unlock(c);
- return false;
- }
-
- mysg.elem = ep;
- mysg.g = g;
- mysg.selectdone = nil;
- g->param = nil;
- enqueue(&c->recvq, &mysg);
- runtime_parkunlock(c, "chan receive");
-
- if(g->param == nil) {
- runtime_lock(c);
- if(!c->closed)
- runtime_throw("chanrecv: spurious wakeup");
- goto closed;
- }
-
- if(received != nil)
- *received = true;
- if(mysg.releasetime > 0)
- runtime_blockevent(mysg.releasetime - t0, 2);
- return true;
-
-asynch:
- if(c->qcount <= 0) {
- if(c->closed)
- goto closed;
-
- if(!block) {
- runtime_unlock(c);
- if(received != nil)
- *received = false;
- return false;
- }
- mysg.g = g;
- mysg.elem = nil;
- mysg.selectdone = nil;
- enqueue(&c->recvq, &mysg);
- runtime_parkunlock(c, "chan receive");
-
- runtime_lock(c);
- goto asynch;
- }
-
- if(ep != nil)
- runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize);
- runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
- if(++c->recvx == c->dataqsiz)
- c->recvx = 0;
- c->qcount--;
-
- sg = dequeue(&c->sendq);
- if(sg != nil) {
- gp = sg->g;
- runtime_unlock(c);
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- } else
- runtime_unlock(c);
-
- if(received != nil)
- *received = true;
- if(mysg.releasetime > 0)
- runtime_blockevent(mysg.releasetime - t0, 2);
- return true;
-
-closed:
- if(ep != nil)
- runtime_memclr(ep, c->elemsize);
- if(received != nil)
- *received = false;
- runtime_unlock(c);
- if(mysg.releasetime > 0)
- runtime_blockevent(mysg.releasetime - t0, 2);
- return true;
-}
-
-// The compiler generates a call to __go_send_small to send a value 8
-// bytes or smaller.
-void
-__go_send_small(ChanType *t, Hchan* c, uint64 val)
-{
- union
- {
- byte b[sizeof(uint64)];
- uint64 v;
- } u;
- byte *v;
-
- u.v = val;
-#ifndef WORDS_BIGENDIAN
- v = u.b;
-#else
- v = u.b + sizeof(uint64) - t->__element_type->__size;
-#endif
- chansend(t, c, v, true, runtime_getcallerpc(&t));
-}
-
-// The compiler generates a call to __go_send_big to send a value
-// larger than 8 bytes or smaller.
-void
-__go_send_big(ChanType *t, Hchan* c, byte* v)
-{
- chansend(t, c, v, true, runtime_getcallerpc(&t));
-}
-
-// The compiler generates a call to __go_receive to receive a
-// value from a channel.
-void
-__go_receive(ChanType *t, Hchan* c, byte* v)
-{
- chanrecv(t, c, v, true, nil);
-}
-
-_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
- __asm__ (GOSYM_PREFIX "runtime.chanrecv2");
-
-_Bool
-runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
-{
- bool received = false;
-
- chanrecv(t, c, v, true, &received);
- return received;
-}
-
-// compiler implements
-//
-// select {
-// case c <- v:
-// ... foo
-// default:
-// ... bar
-// }
-//
-// as
-//
-// if selectnbsend(c, v) {
-// ... foo
-// } else {
-// ... bar
-// }
-//
-func selectnbsend(t *ChanType, c *Hchan, elem *byte) (selected bool) {
- selected = chansend(t, c, elem, false, runtime_getcallerpc(&t));
-}
-
-// compiler implements
-//
-// select {
-// case v = <-c:
-// ... foo
-// default:
-// ... bar
-// }
-//
-// as
-//
-// if selectnbrecv(&v, c) {
-// ... foo
-// } else {
-// ... bar
-// }
-//
-func selectnbrecv(t *ChanType, elem *byte, c *Hchan) (selected bool) {
- selected = chanrecv(t, c, elem, false, nil);
-}
-
-// compiler implements
-//
-// select {
-// case v, ok = <-c:
-// ... foo
-// default:
-// ... bar
-// }
-//
-// as
-//
-// if c != nil && selectnbrecv2(&v, &ok, c) {
-// ... foo
-// } else {
-// ... bar
-// }
-//
-func selectnbrecv2(t *ChanType, elem *byte, received *bool, c *Hchan) (selected bool) {
- bool r;
-
- selected = chanrecv(t, c, elem, false, received == nil ? nil : &r);
- if(received != nil)
- *received = r;
-}
-
-func reflect.chansend(t *ChanType, c *Hchan, elem *byte, nb bool) (selected bool) {
- selected = chansend(t, c, elem, !nb, runtime_getcallerpc(&t));
-}
-
-func reflect.chanrecv(t *ChanType, c *Hchan, nb bool, elem *byte) (selected bool, received bool) {
- received = false;
- selected = chanrecv(t, c, elem, !nb, &received);
-}
-
-static Select* newselect(int32);
-
-func newselect(size int32) (sel *byte) {
- sel = (byte*)newselect(size);
-}
-
-static Select*
-newselect(int32 size)
-{
- int32 n;
- Select *sel;
-
- n = 0;
- if(size > 1)
- n = size-1;
-
- // allocate all the memory we need in a single allocation
- // start with Select with size cases
- // then lockorder with size entries
- // then pollorder with size entries
- sel = runtime_mal(sizeof(*sel) +
- n*sizeof(sel->scase[0]) +
- size*sizeof(sel->lockorder[0]) +
- size*sizeof(sel->pollorder[0]));
-
- sel->tcase = size;
- sel->ncase = 0;
- sel->lockorder = (void*)(sel->scase + size);
- sel->pollorder = (void*)(sel->lockorder + size);
-
- if(debug)
- runtime_printf("newselect s=%p size=%d\n", sel, size);
- return sel;
-}
-
-// cut in half to give stack a chance to split
-static void selectsend(Select *sel, Hchan *c, int index, void *elem);
-
-func selectsend(sel *Select, c *Hchan, elem *byte, index int32) {
- // nil cases do not compete
- if(c != nil)
- selectsend(sel, c, index, elem);
-}
-
-static void
-selectsend(Select *sel, Hchan *c, int index, void *elem)
-{
- int32 i;
- Scase *cas;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- runtime_throw("selectsend: too many cases");
- sel->ncase = i+1;
- cas = &sel->scase[i];
-
- cas->index = index;
- cas->chan = c;
- cas->kind = CaseSend;
- cas->sg.elem = elem;
-
- if(debug)
- runtime_printf("selectsend s=%p index=%d chan=%p\n",
- sel, cas->index, cas->chan);
-}
-
-// cut in half to give stack a chance to split
-static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*);
-
-func selectrecv(sel *Select, c *Hchan, elem *byte, index int32) {
- // nil cases do not compete
- if(c != nil)
- selectrecv(sel, c, index, elem, nil);
-}
-
-func selectrecv2(sel *Select, c *Hchan, elem *byte, received *bool, index int32) {
- // nil cases do not compete
- if(c != nil)
- selectrecv(sel, c, index, elem, received);
-}
-
-static void
-selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received)
-{
- int32 i;
- Scase *cas;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- runtime_throw("selectrecv: too many cases");
- sel->ncase = i+1;
- cas = &sel->scase[i];
- cas->index = index;
- cas->chan = c;
-
- cas->kind = CaseRecv;
- cas->sg.elem = elem;
- cas->receivedp = received;
-
- if(debug)
- runtime_printf("selectrecv s=%p index=%d chan=%p\n",
- sel, cas->index, cas->chan);
-}
-
-// cut in half to give stack a chance to split
-static void selectdefault(Select*, int);
-
-func selectdefault(sel *Select, index int32) {
- selectdefault(sel, index);
-}
-
-static void
-selectdefault(Select *sel, int32 index)
-{
- int32 i;
- Scase *cas;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- runtime_throw("selectdefault: too many cases");
- sel->ncase = i+1;
- cas = &sel->scase[i];
- cas->index = index;
- cas->chan = nil;
-
- cas->kind = CaseDefault;
-
- if(debug)
- runtime_printf("selectdefault s=%p index=%d\n",
- sel, cas->index);
-}
-
-static void
-sellock(Select *sel)
-{
- uint32 i;
- Hchan *c, *c0;
-
- c = nil;
- for(i=0; i<sel->ncase; i++) {
- c0 = sel->lockorder[i];
- if(c0 && c0 != c) {
- c = sel->lockorder[i];
- runtime_lock(c);
- }
- }
-}
-
-static void
-selunlock(Select *sel)
-{
- int32 i, n, r;
- Hchan *c;
-
- // We must be very careful here to not touch sel after we have unlocked
- // the last lock, because sel can be freed right after the last unlock.
- // Consider the following situation.
- // First M calls runtime_park() in runtime_selectgo() passing the sel.
- // Once runtime_park() has unlocked the last lock, another M makes
- // the G that calls select runnable again and schedules it for execution.
- // When the G runs on another M, it locks all the locks and frees sel.
- // Now if the first M touches sel, it will access freed memory.
- n = (int32)sel->ncase;
- r = 0;
- // skip the default case
- if(n>0 && sel->lockorder[0] == nil)
- r = 1;
- for(i = n-1; i >= r; i--) {
- c = sel->lockorder[i];
- if(i>0 && sel->lockorder[i-1] == c)
- continue; // will unlock it on the next iteration
- runtime_unlock(c);
- }
-}
-
-static bool
-selparkcommit(G *gp, void *sel)
-{
- USED(gp);
- selunlock(sel);
- return true;
-}
-
-func block() {
- runtime_park(nil, nil, "select (no cases)"); // forever
-}
-
-static int selectgo(Select**);
-
-// selectgo(sel *byte);
-
-func selectgo(sel *Select) (ret int32) {
- return selectgo(&sel);
-}
-
-static int
-selectgo(Select **selp)
-{
- Select *sel;
- uint32 o, i, j, k, done;
- int64 t0;
- Scase *cas, *dfl;
- Hchan *c;
- SudoG *sg;
- G *gp;
- int index;
- G *g;
-
- sel = *selp;
- if(runtime_gcwaiting())
- runtime_gosched();
-
- if(debug)
- runtime_printf("select: sel=%p\n", sel);
-
- g = runtime_g();
-
- t0 = 0;
- if(runtime_blockprofilerate > 0) {
- t0 = runtime_cputicks();
- for(i=0; i<sel->ncase; i++)
- sel->scase[i].sg.releasetime = -1;
- }
-
- // The compiler rewrites selects that statically have
- // only 0 or 1 cases plus default into simpler constructs.
- // The only way we can end up with such small sel->ncase
- // values here is for a larger select in which most channels
- // have been nilled out. The general code handles those
- // cases correctly, and they are rare enough not to bother
- // optimizing (and needing to test).
-
- // generate permuted order
- for(i=0; i<sel->ncase; i++)
- sel->pollorder[i] = i;
- for(i=1; i<sel->ncase; i++) {
- o = sel->pollorder[i];
- j = runtime_fastrand1()%(i+1);
- sel->pollorder[i] = sel->pollorder[j];
- sel->pollorder[j] = o;
- }
-
- // sort the cases by Hchan address to get the locking order.
- // simple heap sort, to guarantee n log n time and constant stack footprint.
- for(i=0; i<sel->ncase; i++) {
- j = i;
- c = sel->scase[j].chan;
- while(j > 0 && sel->lockorder[k=(j-1)/2] < c) {
- sel->lockorder[j] = sel->lockorder[k];
- j = k;
- }
- sel->lockorder[j] = c;
- }
- for(i=sel->ncase; i-->0; ) {
- c = sel->lockorder[i];
- sel->lockorder[i] = sel->lockorder[0];
- j = 0;
- for(;;) {
- k = j*2+1;
- if(k >= i)
- break;
- if(k+1 < i && sel->lockorder[k] < sel->lockorder[k+1])
- k++;
- if(c < sel->lockorder[k]) {
- sel->lockorder[j] = sel->lockorder[k];
- j = k;
- continue;
- }
- break;
- }
- sel->lockorder[j] = c;
- }
- /*
- for(i=0; i+1<sel->ncase; i++)
- if(sel->lockorder[i] > sel->lockorder[i+1]) {
- runtime_printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]);
- runtime_throw("select: broken sort");
- }
- */
- sellock(sel);
-
-loop:
- // pass 1 - look for something already waiting
- dfl = nil;
- for(i=0; i<sel->ncase; i++) {
- o = sel->pollorder[i];
- cas = &sel->scase[o];
- c = cas->chan;
-
- switch(cas->kind) {
- case CaseRecv:
- if(c->dataqsiz > 0) {
- if(c->qcount > 0)
- goto asyncrecv;
- } else {
- sg = dequeue(&c->sendq);
- if(sg != nil)
- goto syncrecv;
- }
- if(c->closed)
- goto rclose;
- break;
-
- case CaseSend:
- if(c->closed)
- goto sclose;
- if(c->dataqsiz > 0) {
- if(c->qcount < c->dataqsiz)
- goto asyncsend;
- } else {
- sg = dequeue(&c->recvq);
- if(sg != nil)
- goto syncsend;
- }
- break;
-
- case CaseDefault:
- dfl = cas;
- break;
- }
- }
-
- if(dfl != nil) {
- selunlock(sel);
- cas = dfl;
- goto retc;
- }
-
-
- // pass 2 - enqueue on all chans
- done = 0;
- for(i=0; i<sel->ncase; i++) {
- o = sel->pollorder[i];
- cas = &sel->scase[o];
- c = cas->chan;
- sg = &cas->sg;
- sg->g = g;
- sg->selectdone = &done;
-
- switch(cas->kind) {
- case CaseRecv:
- enqueue(&c->recvq, sg);
- break;
-
- case CaseSend:
- enqueue(&c->sendq, sg);
- break;
- }
- }
-
- g->param = nil;
- runtime_park(selparkcommit, sel, "select");
-
- sellock(sel);
- sg = g->param;
-
- // pass 3 - dequeue from unsuccessful chans
- // otherwise they stack up on quiet channels
- for(i=0; i<sel->ncase; i++) {
- cas = &sel->scase[i];
- if(cas != (Scase*)sg) {
- c = cas->chan;
- if(cas->kind == CaseSend)
- dequeueg(&c->sendq);
- else
- dequeueg(&c->recvq);
- }
- }
-
- if(sg == nil)
- goto loop;
-
- cas = (Scase*)sg;
- c = cas->chan;
-
- if(c->dataqsiz > 0)
- runtime_throw("selectgo: shouldn't happen");
-
- if(debug)
- runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
- sel, c, cas, cas->kind);
-
- if(cas->kind == CaseRecv) {
- if(cas->receivedp != nil)
- *cas->receivedp = true;
- }
-
- selunlock(sel);
- goto retc;
-
-asyncrecv:
- // can receive from buffer
- if(cas->receivedp != nil)
- *cas->receivedp = true;
- if(cas->sg.elem != nil)
- runtime_memmove(cas->sg.elem, chanbuf(c, c->recvx), c->elemsize);
- runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
- if(++c->recvx == c->dataqsiz)
- c->recvx = 0;
- c->qcount--;
- sg = dequeue(&c->sendq);
- if(sg != nil) {
- gp = sg->g;
- selunlock(sel);
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- } else {
- selunlock(sel);
- }
- goto retc;
-
-asyncsend:
- // can send to buffer
- runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize);
- if(++c->sendx == c->dataqsiz)
- c->sendx = 0;
- c->qcount++;
- sg = dequeue(&c->recvq);
- if(sg != nil) {
- gp = sg->g;
- selunlock(sel);
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- } else {
- selunlock(sel);
- }
- goto retc;
-
-syncrecv:
- // can receive from sleeping sender (sg)
- selunlock(sel);
- if(debug)
- runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
- if(cas->receivedp != nil)
- *cas->receivedp = true;
- if(cas->sg.elem != nil)
- runtime_memmove(cas->sg.elem, sg->elem, c->elemsize);
- gp = sg->g;
- gp->param = sg;
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- goto retc;
-
-rclose:
- // read at end of closed channel
- selunlock(sel);
- if(cas->receivedp != nil)
- *cas->receivedp = false;
- if(cas->sg.elem != nil)
- runtime_memclr(cas->sg.elem, c->elemsize);
- goto retc;
-
-syncsend:
- // can send to sleeping receiver (sg)
- selunlock(sel);
- if(debug)
- runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
- if(sg->elem != nil)
- runtime_memmove(sg->elem, cas->sg.elem, c->elemsize);
- gp = sg->g;
- gp->param = sg;
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
-
-retc:
- // return index corresponding to chosen case
- index = cas->index;
- if(cas->sg.releasetime > 0)
- runtime_blockevent(cas->sg.releasetime - t0, 2);
- runtime_free(sel);
- return index;
-
-sclose:
- // send on closed channel
- selunlock(sel);
- runtime_panicstring("send on closed channel");
- return 0; // not reached
-}
-
-// This struct must match ../reflect/value.go:/runtimeSelect.
-typedef struct runtimeSelect runtimeSelect;
-struct runtimeSelect
-{
- uintptr dir;
- ChanType *typ;
- Hchan *ch;
- byte *val;
-};
-
-// This enum must match ../reflect/value.go:/SelectDir.
-enum SelectDir {
- SelectSend = 1,
- SelectRecv,
- SelectDefault,
-};
-
-func reflect.rselect(cases Slice) (chosen int, recvOK bool) {
- int32 i;
- Select *sel;
- runtimeSelect* rcase, *rc;
-
- chosen = -1;
- recvOK = false;
-
- rcase = (runtimeSelect*)cases.__values;
-
- sel = newselect(cases.__count);
- for(i=0; i<cases.__count; i++) {
- rc = &rcase[i];
- switch(rc->dir) {
- case SelectDefault:
- selectdefault(sel, i);
- break;
- case SelectSend:
- if(rc->ch == nil)
- break;
- selectsend(sel, rc->ch, i, rc->val);
- break;
- case SelectRecv:
- if(rc->ch == nil)
- break;
- selectrecv(sel, rc->ch, i, rc->val, &recvOK);
- break;
- }
- }
-
- chosen = (intgo)(uintptr)selectgo(&sel);
-}
-
-static void closechan(Hchan *c, void *pc);
-
-func closechan(c *Hchan) {
- closechan(c, runtime_getcallerpc(&c));
-}
-
-func reflect.chanclose(c *Hchan) {
- closechan(c, runtime_getcallerpc(&c));
-}
-
-static void
-closechan(Hchan *c, void *pc)
-{
- USED(pc);
- SudoG *sg;
- G* gp;
-
- if(c == nil)
- runtime_panicstring("close of nil channel");
-
- if(runtime_gcwaiting())
- runtime_gosched();
-
- runtime_lock(c);
- if(c->closed) {
- runtime_unlock(c);
- runtime_panicstring("close of closed channel");
- }
- c->closed = true;
-
- // release all readers
- for(;;) {
- sg = dequeue(&c->recvq);
- if(sg == nil)
- break;
- gp = sg->g;
- gp->param = nil;
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- }
-
- // release all writers
- for(;;) {
- sg = dequeue(&c->sendq);
- if(sg == nil)
- break;
- gp = sg->g;
- gp->param = nil;
- if(sg->releasetime)
- sg->releasetime = runtime_cputicks();
- runtime_ready(gp);
- }
-
- runtime_unlock(c);
-}
-
-void
-__go_builtin_close(Hchan *c)
-{
- runtime_closechan(c);
-}
-
-func reflect.chanlen(c *Hchan) (len int) {
- if(c == nil)
- len = 0;
- else
- len = c->qcount;
-}
-
-intgo
-__go_chan_len(Hchan *c)
-{
- return reflect_chanlen(c);
-}
-
-func reflect.chancap(c *Hchan) (cap int) {
- if(c == nil)
- cap = 0;
- else
- cap = c->dataqsiz;
-}
-
-intgo
-__go_chan_cap(Hchan *c)
-{
- return reflect_chancap(c);
-}
-
-static SudoG*
-dequeue(WaitQ *q)
-{
- SudoG *sgp;
-
-loop:
- sgp = q->first;
- if(sgp == nil)
- return nil;
- q->first = sgp->link;
-
- // if sgp participates in a select and is already signaled, ignore it
- if(sgp->selectdone != nil) {
- // claim the right to signal
- if(*sgp->selectdone != 0 || !runtime_cas(sgp->selectdone, 0, 1))
- goto loop;
- }
-
- return sgp;
-}
-
-static void
-dequeueg(WaitQ *q)
-{
- SudoG **l, *sgp, *prevsgp;
- G *g;
-
- g = runtime_g();
- prevsgp = nil;
- for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
- if(sgp->g == g) {
- *l = sgp->link;
- if(q->last == sgp)
- q->last = prevsgp;
- break;
- }
- }
-}
-
-static void
-enqueue(WaitQ *q, SudoG *sgp)
-{
- sgp->link = nil;
- if(q->first == nil) {
- q->first = sgp;
- q->last = sgp;
- return;
- }
- q->last->link = sgp;
- q->last = sgp;
-}
diff --git a/libgo/runtime/chan.h b/libgo/runtime/chan.h
deleted file mode 100644
index 70b0b9d909..0000000000
--- a/libgo/runtime/chan.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-typedef struct WaitQ WaitQ;
-typedef struct SudoG SudoG;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-typedef struct __go_type_descriptor Type;
-typedef struct __go_channel_type ChanType;
-
-struct SudoG
-{
- G* g;
- uint32* selectdone;
- SudoG* link;
- int64 releasetime;
- byte* elem; // data element
-};
-
-struct WaitQ
-{
- SudoG* first;
- SudoG* last;
-};
-
-// The garbage collector is assuming that Hchan can only contain pointers into the stack
-// and cannot contain pointers into the heap.
-struct Hchan
-{
- uintgo qcount; // total data in the q
- uintgo dataqsiz; // size of the circular q
- uint16 elemsize;
- uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
- bool closed;
- const Type* elemtype; // element type
- uintgo sendx; // send index
- uintgo recvx; // receive index
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- Lock;
-};
-
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
-
-enum
-{
- debug = 0,
-
- // Scase.kind
- CaseRecv,
- CaseSend,
- CaseDefault,
-};
-
-struct Scase
-{
- SudoG sg; // must be first member (cast to Scase)
- Hchan* chan; // chan
- uint16 kind;
- uint16 index; // index to return
- bool* receivedp; // pointer to received bool (recv2)
-};
-
-struct Select
-{
- uint16 tcase; // total count of scase[]
- uint16 ncase; // currently filled scase[]
- uint16* pollorder; // case poll order
- Hchan** lockorder; // channel lock order
- Scase scase[1]; // one per case (in order of appearance)
-};
diff --git a/libgo/runtime/cpuprof.goc b/libgo/runtime/cpuprof.goc
deleted file mode 100644
index 7d27bc6a43..0000000000
--- a/libgo/runtime/cpuprof.goc
+++ /dev/null
@@ -1,442 +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.
-
-// CPU profiling.
-// Based on algorithms and data structures used in
-// http://code.google.com/p/google-perftools/.
-//
-// The main difference between this code and the google-perftools
-// code is that this code is written to allow copying the profile data
-// to an arbitrary io.Writer, while the google-perftools code always
-// writes to an operating system file.
-//
-// The signal handler for the profiling clock tick adds a new stack trace
-// to a hash table tracking counts for recent traces. Most clock ticks
-// hit in the cache. In the event of a cache miss, an entry must be
-// evicted from the hash table, copied to a log that will eventually be
-// written as profile data. The google-perftools code flushed the
-// log itself during the signal handler. This code cannot do that, because
-// the io.Writer might block or need system calls or locks that are not
-// safe to use from within the signal handler. Instead, we split the log
-// into two halves and let the signal handler fill one half while a goroutine
-// is writing out the other half. When the signal handler fills its half, it
-// offers to swap with the goroutine. If the writer is not done with its half,
-// we lose the stack trace for this clock tick (and record that loss).
-// The goroutine interacts with the signal handler by calling getprofile() to
-// get the next log piece to write, implicitly handing back the last log
-// piece it obtained.
-//
-// The state of this dance between the signal handler and the goroutine
-// is encoded in the Profile.handoff field. If handoff == 0, then the goroutine
-// is not using either log half and is waiting (or will soon be waiting) for
-// a new piece by calling notesleep(&p->wait). If the signal handler
-// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait)
-// to wake the goroutine. The value indicates the number of entries in the
-// log half being handed off. The goroutine leaves the non-zero value in
-// place until it has finished processing the log half and then flips the number
-// back to zero. Setting the high bit in handoff means that the profiling is over,
-// and the goroutine is now in charge of flushing the data left in the hash table
-// to the log and returning that data.
-//
-// The handoff field is manipulated using atomic operations.
-// For the most part, the manipulation of handoff is orderly: if handoff == 0
-// then the signal handler owns it and can change it to non-zero.
-// If handoff != 0 then the goroutine owns it and can change it to zero.
-// If that were the end of the story then we would not need to manipulate
-// handoff using atomic operations. The operations are needed, however,
-// in order to let the log closer set the high bit to indicate "EOF" safely
-// in the situation when normally the goroutine "owns" handoff.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-#include "array.h"
-typedef struct __go_open_array Slice;
-#define array __values
-#define len __count
-#define cap __capacity
-
-enum
-{
- HashSize = 1<<10,
- LogSize = 1<<17,
- Assoc = 4,
- MaxStack = 64,
-};
-
-typedef struct Profile Profile;
-typedef struct Bucket Bucket;
-typedef struct Entry Entry;
-
-struct Entry {
- uintptr count;
- uintptr depth;
- uintptr stack[MaxStack];
-};
-
-struct Bucket {
- Entry entry[Assoc];
-};
-
-struct Profile {
- bool on; // profiling is on
- Note wait; // goroutine waits here
- uintptr count; // tick count
- uintptr evicts; // eviction count
- uintptr lost; // lost ticks that need to be logged
-
- // Active recent stack traces.
- Bucket hash[HashSize];
-
- // Log of traces evicted from hash.
- // Signal handler has filled log[toggle][:nlog].
- // Goroutine is writing log[1-toggle][:handoff].
- uintptr log[2][LogSize/2];
- uintptr nlog;
- int32 toggle;
- uint32 handoff;
-
- // Writer state.
- // Writer maintains its own toggle to avoid races
- // looking at signal handler's toggle.
- uint32 wtoggle;
- bool wholding; // holding & need to release a log half
- bool flushing; // flushing hash table - profile is over
- bool eod_sent; // special end-of-data record sent; => flushing
-};
-
-static Lock lk;
-static Profile *prof;
-
-static void tick(uintptr*, int32);
-static void add(Profile*, uintptr*, int32);
-static bool evict(Profile*, Entry*);
-static bool flushlog(Profile*);
-
-static uintptr eod[3] = {0, 1, 0};
-
-// LostProfileData is a no-op function used in profiles
-// to mark the number of profiling stack traces that were
-// discarded due to slow data writers.
-static void
-LostProfileData(void)
-{
-}
-
-extern void runtime_SetCPUProfileRate(intgo)
- __asm__ (GOSYM_PREFIX "runtime.SetCPUProfileRate");
-
-// SetCPUProfileRate sets the CPU profiling rate.
-// The user documentation is in debug.go.
-void
-runtime_SetCPUProfileRate(intgo hz)
-{
- uintptr *p;
- uintptr n;
-
- // Clamp hz to something reasonable.
- if(hz < 0)
- hz = 0;
- if(hz > 1000000)
- hz = 1000000;
-
- runtime_lock(&lk);
- if(hz > 0) {
- if(prof == nil) {
- prof = runtime_SysAlloc(sizeof *prof, &mstats.other_sys);
- if(prof == nil) {
- runtime_printf("runtime: cpu profiling cannot allocate memory\n");
- runtime_unlock(&lk);
- return;
- }
- }
- if(prof->on || prof->handoff != 0) {
- runtime_printf("runtime: cannot set cpu profile rate until previous profile has finished.\n");
- runtime_unlock(&lk);
- return;
- }
-
- prof->on = true;
- p = prof->log[0];
- // pprof binary header format.
- // http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117
- *p++ = 0; // count for header
- *p++ = 3; // depth for header
- *p++ = 0; // version number
- *p++ = 1000000 / hz; // period (microseconds)
- *p++ = 0;
- prof->nlog = p - prof->log[0];
- prof->toggle = 0;
- prof->wholding = false;
- prof->wtoggle = 0;
- prof->flushing = false;
- prof->eod_sent = false;
- runtime_noteclear(&prof->wait);
-
- runtime_setcpuprofilerate(tick, hz);
- } else if(prof != nil && prof->on) {
- runtime_setcpuprofilerate(nil, 0);
- prof->on = false;
-
- // Now add is not running anymore, and getprofile owns the entire log.
- // Set the high bit in prof->handoff to tell getprofile.
- for(;;) {
- n = prof->handoff;
- if(n&0x80000000)
- runtime_printf("runtime: setcpuprofile(off) twice");
- if(runtime_cas(&prof->handoff, n, n|0x80000000))
- break;
- }
- if(n == 0) {
- // we did the transition from 0 -> nonzero so we wake getprofile
- runtime_notewakeup(&prof->wait);
- }
- }
- runtime_unlock(&lk);
-}
-
-static void
-tick(uintptr *pc, int32 n)
-{
- add(prof, pc, n);
-}
-
-// add adds the stack trace to the profile.
-// It is called from signal handlers and other limited environments
-// and cannot allocate memory or acquire locks that might be
-// held at the time of the signal, nor can it use substantial amounts
-// of stack. It is allowed to call evict.
-static void
-add(Profile *p, uintptr *pc, int32 n)
-{
- int32 i, j;
- uintptr h, x;
- Bucket *b;
- Entry *e;
-
- if(n > MaxStack)
- n = MaxStack;
-
- // Compute hash.
- h = 0;
- for(i=0; i<n; i++) {
- h = h<<8 | (h>>(8*(sizeof(h)-1)));
- x = pc[i];
- h += x*31 + x*7 + x*3;
- }
- p->count++;
-
- // Add to entry count if already present in table.
- b = &p->hash[h%HashSize];
- for(i=0; i<Assoc; i++) {
- e = &b->entry[i];
- if(e->depth != (uintptr)n)
- continue;
- for(j=0; j<n; j++)
- if(e->stack[j] != pc[j])
- goto ContinueAssoc;
- e->count++;
- return;
- ContinueAssoc:;
- }
-
- // Evict entry with smallest count.
- e = &b->entry[0];
- for(i=1; i<Assoc; i++)
- if(b->entry[i].count < e->count)
- e = &b->entry[i];
- if(e->count > 0) {
- if(!evict(p, e)) {
- // Could not evict entry. Record lost stack.
- p->lost++;
- return;
- }
- p->evicts++;
- }
-
- // Reuse the newly evicted entry.
- e->depth = n;
- e->count = 1;
- for(i=0; i<n; i++)
- e->stack[i] = pc[i];
-}
-
-// evict copies the given entry's data into the log, so that
-// the entry can be reused. evict is called from add, which
-// is called from the profiling signal handler, so it must not
-// allocate memory or block. It is safe to call flushLog.
-// evict returns true if the entry was copied to the log,
-// false if there was no room available.
-static bool
-evict(Profile *p, Entry *e)
-{
- int32 i, d, nslot;
- uintptr *log, *q;
-
- d = e->depth;
- nslot = d+2;
- log = p->log[p->toggle];
- if(p->nlog+nslot > nelem(p->log[0])) {
- if(!flushlog(p))
- return false;
- log = p->log[p->toggle];
- }
-
- q = log+p->nlog;
- *q++ = e->count;
- *q++ = d;
- for(i=0; i<d; i++)
- *q++ = e->stack[i];
- p->nlog = q - log;
- e->count = 0;
- return true;
-}
-
-// flushlog tries to flush the current log and switch to the other one.
-// flushlog is called from evict, called from add, called from the signal handler,
-// so it cannot allocate memory or block. It can try to swap logs with
-// the writing goroutine, as explained in the comment at the top of this file.
-static bool
-flushlog(Profile *p)
-{
- uintptr *log, *q;
-
- if(!runtime_cas(&p->handoff, 0, p->nlog))
- return false;
- runtime_notewakeup(&p->wait);
-
- p->toggle = 1 - p->toggle;
- log = p->log[p->toggle];
- q = log;
- if(p->lost > 0) {
- *q++ = p->lost;
- *q++ = 1;
- *q++ = (uintptr)LostProfileData;
- p->lost = 0;
- }
- p->nlog = q - log;
- return true;
-}
-
-// getprofile blocks until the next block of profiling data is available
-// and returns it as a []byte. It is called from the writing goroutine.
-Slice
-getprofile(Profile *p)
-{
- uint32 i, j, n;
- Slice ret;
- Bucket *b;
- Entry *e;
-
- ret.array = nil;
- ret.len = 0;
- ret.cap = 0;
-
- if(p == nil)
- return ret;
-
- if(p->wholding) {
- // Release previous log to signal handling side.
- // Loop because we are racing against SetCPUProfileRate(0).
- for(;;) {
- n = p->handoff;
- if(n == 0) {
- runtime_printf("runtime: phase error during cpu profile handoff\n");
- return ret;
- }
- if(n & 0x80000000) {
- p->wtoggle = 1 - p->wtoggle;
- p->wholding = false;
- p->flushing = true;
- goto flush;
- }
- if(runtime_cas(&p->handoff, n, 0))
- break;
- }
- p->wtoggle = 1 - p->wtoggle;
- p->wholding = false;
- }
-
- if(p->flushing)
- goto flush;
-
- if(!p->on && p->handoff == 0)
- return ret;
-
- // Wait for new log.
- runtime_notetsleepg(&p->wait, -1);
- runtime_noteclear(&p->wait);
-
- n = p->handoff;
- if(n == 0) {
- runtime_printf("runtime: phase error during cpu profile wait\n");
- return ret;
- }
- if(n == 0x80000000) {
- p->flushing = true;
- goto flush;
- }
- n &= ~0x80000000;
-
- // Return new log to caller.
- p->wholding = true;
-
- ret.array = (byte*)p->log[p->wtoggle];
- ret.len = n*sizeof(uintptr);
- ret.cap = ret.len;
- return ret;
-
-flush:
- // In flush mode.
- // Add is no longer being called. We own the log.
- // Also, p->handoff is non-zero, so flushlog will return false.
- // Evict the hash table into the log and return it.
- for(i=0; i<HashSize; i++) {
- b = &p->hash[i];
- for(j=0; j<Assoc; j++) {
- e = &b->entry[j];
- if(e->count > 0 && !evict(p, e)) {
- // Filled the log. Stop the loop and return what we've got.
- goto breakflush;
- }
- }
- }
-breakflush:
-
- // Return pending log data.
- if(p->nlog > 0) {
- // Note that we're using toggle now, not wtoggle,
- // because we're working on the log directly.
- ret.array = (byte*)p->log[p->toggle];
- ret.len = p->nlog*sizeof(uintptr);
- ret.cap = ret.len;
- p->nlog = 0;
- return ret;
- }
-
- // Made it through the table without finding anything to log.
- if(!p->eod_sent) {
- // We may not have space to append this to the partial log buf,
- // so we always return a new slice for the end-of-data marker.
- p->eod_sent = true;
- ret.array = (byte*)eod;
- ret.len = sizeof eod;
- ret.cap = ret.len;
- return ret;
- }
-
- // Finally done. Clean up and return nil.
- p->flushing = false;
- if(!runtime_cas(&p->handoff, p->handoff, 0))
- runtime_printf("runtime: profile flush racing with something\n");
- return ret; // set to nil at top of function
-}
-
-// CPUProfile returns the next cpu profile block as a []byte.
-// The user documentation is in debug.go.
-func CPUProfile() (ret Slice) {
- ret = getprofile(prof);
-}
diff --git a/libgo/runtime/env_posix.c b/libgo/runtime/env_posix.c
index b93edd65a6..3a60682597 100644
--- a/libgo/runtime/env_posix.c
+++ b/libgo/runtime/env_posix.c
@@ -9,7 +9,7 @@
#include "arch.h"
#include "malloc.h"
-extern Slice envs;
+extern Slice runtime_get_envs(void);
String
runtime_getenv(const char *s)
@@ -17,12 +17,14 @@ runtime_getenv(const char *s)
int32 i, j;
intgo len;
const byte *v, *bs;
+ Slice envs;
String* envv;
int32 envc;
String ret;
bs = (const byte*)s;
len = runtime_findnull(bs);
+ envs = runtime_get_envs();
envv = (String*)envs.__values;
envc = envs.__count;
for(i=0; i<envc; i++){
diff --git a/libgo/runtime/go-alloc.h b/libgo/runtime/go-alloc.h
deleted file mode 100644
index c880a043ea..0000000000
--- a/libgo/runtime/go-alloc.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* go-alloc.h -- allocate memory for Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-#include <stdint.h>
-
-extern void *__go_alloc (unsigned int __attribute__ ((mode (pointer))));
-extern void __go_free (void *);
diff --git a/libgo/runtime/go-append.c b/libgo/runtime/go-append.c
deleted file mode 100644
index 1b2d49e53c..0000000000
--- a/libgo/runtime/go-append.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* go-append.c -- the go builtin append function.
-
- 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. */
-
-#include "runtime.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-/* We should be OK if we don't split the stack here, since the only
- libc functions we call are memcpy and memmove. If we don't do
- this, we will always split the stack, because of memcpy and
- memmove. */
-extern struct __go_open_array
-__go_append (struct __go_open_array, void *, uintptr_t, uintptr_t)
- __attribute__ ((no_split_stack));
-
-struct __go_open_array
-__go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
- uintptr_t element_size)
-{
- uintptr_t ucount;
- intgo count;
-
- if (bvalues == NULL || bcount == 0)
- return a;
-
- ucount = (uintptr_t) a.__count + bcount;
- count = (intgo) ucount;
- if ((uintptr_t) count != ucount || count <= a.__count)
- runtime_panicstring ("append: slice overflow");
-
- if (count > a.__capacity)
- {
- intgo m;
- uintptr capmem;
- void *n;
-
- m = a.__capacity;
- if (m + m < count)
- m = count;
- else
- {
- do
- {
- if (a.__count < 1024)
- m += m;
- else
- m += m / 4;
- }
- while (m < count);
- }
-
- if (element_size > 0 && (uintptr) m > MaxMem / element_size)
- runtime_panicstring ("growslice: cap out of range");
-
- capmem = runtime_roundupsize (m * element_size);
-
- n = __go_alloc (capmem);
- __builtin_memcpy (n, a.__values, a.__count * element_size);
-
- a.__values = n;
- a.__capacity = m;
- }
-
- __builtin_memmove ((char *) a.__values + a.__count * element_size,
- bvalues, bcount * element_size);
- a.__count = count;
- return a;
-}
diff --git a/libgo/runtime/go-assert-interface.c b/libgo/runtime/go-assert-interface.c
deleted file mode 100644
index 427916f8c4..0000000000
--- a/libgo/runtime/go-assert-interface.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* go-assert-interface.c -- interface type assertion for Go.
-
- 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. */
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* This is called by the compiler to implement a type assertion from
- one interface type to another. This returns the value that should
- go in the first field of the result tuple. The result may be an
- empty or a non-empty interface. */
-
-const void *
-__go_assert_interface (const struct __go_type_descriptor *lhs_descriptor,
- const struct __go_type_descriptor *rhs_descriptor)
-{
- const struct __go_interface_type *lhs_interface;
-
- if (rhs_descriptor == NULL)
- {
- struct __go_empty_interface panic_arg;
-
- /* A type assertion is not permitted with a nil interface. */
-
- runtime_newTypeAssertionError (NULL, NULL, lhs_descriptor->__reflection,
- NULL, &panic_arg);
- __go_panic (panic_arg);
- }
-
- /* A type assertion to an empty interface just returns the object
- descriptor. */
-
- __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
- lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
- if (lhs_interface->__methods.__count == 0)
- return rhs_descriptor;
-
- return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
-}
diff --git a/libgo/runtime/go-byte-array-to-string.c b/libgo/runtime/go-byte-array-to-string.c
deleted file mode 100644
index 088b78690f..0000000000
--- a/libgo/runtime/go-byte-array-to-string.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* go-byte-array-to-string.c -- convert an array of bytes to a string in Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-String
-__go_byte_array_to_string (const void* p, intgo len)
-{
- const unsigned char *bytes;
- unsigned char *retdata;
- String ret;
-
- bytes = (const unsigned char *) p;
- retdata = runtime_mallocgc ((uintptr) len, 0, FlagNoScan);
- __builtin_memcpy (retdata, bytes, len);
- ret.str = retdata;
- ret.len = len;
- return ret;
-}
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index d6901e0737..a35d8d73f4 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -1,4 +1,4 @@
-/* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go.
+/* go-caller.c -- look up function/file/line/entry info
Copyright 2009 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
@@ -25,6 +25,7 @@ struct caller
String fn;
String file;
intgo line;
+ intgo index;
};
/* Collect file/line information for a PC value. If this is called
@@ -45,6 +46,12 @@ callback (void *data, uintptr_t pc __attribute__ ((unused)),
c->file = runtime_gostringnocopy ((const byte *) filename);
c->line = lineno;
+ if (c->index == 0)
+ return 1;
+
+ if (c->index > 0)
+ --c->index;
+
return 0;
}
@@ -69,6 +76,10 @@ static void *back_state;
static Lock back_state_lock;
+/* The program arguments. */
+
+extern Slice runtime_get_args(void);
+
/* Fetch back_state, creating it if necessary. */
struct backtrace_state *
@@ -77,15 +88,19 @@ __go_get_backtrace_state ()
runtime_lock (&back_state_lock);
if (back_state == NULL)
{
+ Slice args;
const char *filename;
struct stat s;
- filename = (const char *) runtime_progname ();
+ args = runtime_get_args();
+ filename = NULL;
+ if (args.__count > 0)
+ filename = (const char*)((String*)args.__values)[0].str;
/* If there is no '/' in FILENAME, it was found on PATH, and
might not be the same as the file with the same name in the
current directory. */
- if (__builtin_strchr (filename, '/') == NULL)
+ if (filename != NULL && __builtin_strchr (filename, '/') == NULL)
filename = NULL;
/* If the file is small, then it's not the real executable.
@@ -102,14 +117,17 @@ __go_get_backtrace_state ()
return back_state;
}
-/* Return function/file/line information for PC. */
+/* Return function/file/line information for PC. The index parameter
+ is the entry on the stack of inlined functions; -1 means the last
+ one. */
_Bool
-__go_file_line (uintptr pc, String *fn, String *file, intgo *line)
+__go_file_line (uintptr pc, int index, String *fn, String *file, intgo *line)
{
struct caller c;
runtime_memclr (&c, sizeof c);
+ c.index = index;
backtrace_pcinfo (__go_get_backtrace_state (), pc, callback,
error_callback, &c);
*fn = c.fn;
@@ -153,8 +171,6 @@ struct caller_ret
struct caller_ret Caller (int n) __asm__ (GOSYM_PREFIX "runtime.Caller");
-Func *FuncForPC (uintptr_t) __asm__ (GOSYM_PREFIX "runtime.FuncForPC");
-
/* Implement runtime.Caller. */
struct caller_ret
@@ -175,73 +191,40 @@ Caller (int skip)
return ret;
}
-/* Implement runtime.FuncForPC. */
+/* Look up the function name, file name, and line number for a PC. */
-Func *
-FuncForPC (uintptr_t pc)
-{
- Func *ret;
- String fn;
- String file;
- intgo line;
- uintptr_t val;
-
- if (!__go_file_line (pc, &fn, &file, &line))
- return NULL;
-
- ret = (Func *) runtime_malloc (sizeof (*ret));
- ret->name = fn;
-
- if (__go_symbol_value (pc, &val))
- ret->entry = val;
- else
- ret->entry = 0;
-
- return ret;
-}
-
-/* Look up the file and line information for a PC within a
- function. */
-
-struct funcline_go_return
+struct funcfileline_return
{
+ String retfn;
String retfile;
intgo retline;
};
-struct funcline_go_return
-runtime_funcline_go (Func *f, uintptr targetpc)
- __asm__ (GOSYM_PREFIX "runtime.funcline_go");
+struct funcfileline_return
+runtime_funcfileline (uintptr targetpc, int32 index)
+ __asm__ (GOSYM_PREFIX "runtime.funcfileline");
-struct funcline_go_return
-runtime_funcline_go (Func *f __attribute__((unused)), uintptr targetpc)
+struct funcfileline_return
+runtime_funcfileline (uintptr targetpc, int32 index)
{
- struct funcline_go_return ret;
- String fn;
+ struct funcfileline_return ret;
- if (!__go_file_line (targetpc, &fn, &ret.retfile, &ret.retline))
+ if (!__go_file_line (targetpc, index, &ret.retfn, &ret.retfile,
+ &ret.retline))
runtime_memclr (&ret, sizeof ret);
return ret;
}
-/* Return the name of a function. */
-String runtime_funcname_go (Func *f)
- __asm__ (GOSYM_PREFIX "runtime.funcname_go");
-
-String
-runtime_funcname_go (Func *f)
-{
- if (f == NULL)
- return runtime_gostringnocopy ((const byte *) "");
- return f->name;
-}
-
/* Return the entry point of a function. */
-uintptr runtime_funcentry_go(Func *f)
- __asm__ (GOSYM_PREFIX "runtime.funcentry_go");
+uintptr runtime_funcentry(uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.funcentry");
uintptr
-runtime_funcentry_go (Func *f)
+runtime_funcentry (uintptr pc)
{
- return f->entry;
+ uintptr val;
+
+ if (!__go_symbol_value (pc, &val))
+ return 0;
+ return val;
}
diff --git a/libgo/runtime/go-can-convert-interface.c b/libgo/runtime/go-can-convert-interface.c
deleted file mode 100644
index aac889d346..0000000000
--- a/libgo/runtime/go-can-convert-interface.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* go-can-convert-interface.c -- can we convert to an interface?
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-assert.h"
-#include "go-string.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Return whether we can convert from the type in FROM_DESCRIPTOR to
- the interface in TO_DESCRIPTOR. This is used for type
- switches. */
-
-_Bool
-__go_can_convert_to_interface (
- const struct __go_type_descriptor *to_descriptor,
- const struct __go_type_descriptor *from_descriptor)
-{
- const struct __go_interface_type *to_interface;
- int to_method_count;
- const struct __go_interface_method *to_method;
- const struct __go_uncommon_type *from_uncommon;
- int from_method_count;
- const struct __go_method *from_method;
- int i;
-
- /* In a type switch FROM_DESCRIPTOR can be NULL. */
- if (from_descriptor == NULL)
- return 0;
-
- __go_assert ((to_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
- to_interface = (const struct __go_interface_type *) to_descriptor;
- to_method_count = to_interface->__methods.__count;
- to_method = ((const struct __go_interface_method *)
- to_interface->__methods.__values);
-
- from_uncommon = from_descriptor->__uncommon;
- if (from_uncommon == NULL)
- {
- from_method_count = 0;
- from_method = NULL;
- }
- else
- {
- from_method_count = from_uncommon->__methods.__count;
- from_method = ((const struct __go_method *)
- from_uncommon->__methods.__values);
- }
-
- for (i = 0; i < to_method_count; ++i)
- {
- while (from_method_count > 0
- && (!__go_ptr_strings_equal (from_method->__name,
- to_method->__name)
- || !__go_ptr_strings_equal (from_method->__pkg_path,
- to_method->__pkg_path)))
- {
- ++from_method;
- --from_method_count;
- }
-
- if (from_method_count == 0)
- return 0;
-
- if (!__go_type_descriptors_equal (from_method->__mtype,
- to_method->__type))
- return 0;
-
- ++to_method;
- ++from_method;
- --from_method_count;
- }
-
- return 1;
-}
diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c
index 610bcf5ec4..e80b6b519e 100644
--- a/libgo/runtime/go-cgo.c
+++ b/libgo/runtime/go-cgo.c
@@ -5,194 +5,6 @@
license that can be found in the LICENSE file. */
#include "runtime.h"
-#include "go-alloc.h"
-#include "interface.h"
-#include "go-panic.h"
-#include "go-type.h"
-
-extern void __go_receive (ChanType *, Hchan *, byte *);
-
-/* Prepare to call from code written in Go to code written in C or
- C++. This takes the current goroutine out of the Go scheduler, as
- though it were making a system call. Otherwise the program can
- lock up if the C code goes to sleep on a mutex or for some other
- reason. This idea is to call this function, then immediately call
- the C/C++ function. After the C/C++ function returns, call
- syscall_cgocalldone. The usual Go code would look like
-
- syscall.Cgocall()
- defer syscall.Cgocalldone()
- cfunction()
-
- */
-
-/* We let Go code call these via the syscall package. */
-void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
-void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
-void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
-void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
-
-void
-syscall_cgocall ()
-{
- M* m;
- G* g;
-
- if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
- runtime_newextram ();
-
- runtime_lockOSThread();
-
- m = runtime_m ();
- ++m->ncgocall;
- g = runtime_g ();
- ++g->ncgo;
- runtime_entersyscall ();
-}
-
-/* Prepare to return to Go code from C/C++ code. */
-
-void
-syscall_cgocalldone ()
-{
- G* g;
-
- g = runtime_g ();
- __go_assert (g != NULL);
- --g->ncgo;
- if (g->ncgo == 0)
- {
- /* We are going back to Go, and we are not in a recursive call.
- Let the garbage collector clean up any unreferenced
- memory. */
- g->cgomal = NULL;
- }
-
- /* If we are invoked because the C function called _cgo_panic, then
- _cgo_panic will already have exited syscall mode. */
- if (g->status == Gsyscall)
- runtime_exitsyscall ();
-
- runtime_unlockOSThread();
-}
-
-/* Call back from C/C++ code to Go code. */
-
-void
-syscall_cgocallback ()
-{
- M *mp;
-
- mp = runtime_m ();
- if (mp == NULL)
- {
- runtime_needm ();
- mp = runtime_m ();
- mp->dropextram = true;
- }
-
- runtime_exitsyscall ();
-
- if (runtime_g ()->ncgo == 0)
- {
- /* The C call to Go came from a thread not currently running any
- Go. In the case of -buildmode=c-archive or c-shared, this
- call may be coming in before package initialization is
- complete. Wait until it is. */
- __go_receive (NULL, runtime_main_init_done, NULL);
- }
-
- mp = runtime_m ();
- if (mp->needextram)
- {
- mp->needextram = 0;
- runtime_newextram ();
- }
-}
-
-/* Prepare to return to C/C++ code from a callback to Go code. */
-
-void
-syscall_cgocallbackdone ()
-{
- M *mp;
-
- runtime_entersyscall ();
- mp = runtime_m ();
- if (mp->dropextram && runtime_g ()->ncgo == 0)
- {
- mp->dropextram = false;
- runtime_dropm ();
- }
-}
-
-/* Allocate memory and save it in a list visible to the Go garbage
- collector. */
-
-void *
-alloc_saved (size_t n)
-{
- void *ret;
- G *g;
- CgoMal *c;
-
- ret = __go_alloc (n);
-
- g = runtime_g ();
- c = (CgoMal *) __go_alloc (sizeof (CgoMal));
- c->next = g->cgomal;
- c->alloc = ret;
- g->cgomal = c;
-
- return ret;
-}
-
-/* These are routines used by SWIG. The gc runtime library provides
- the same routines under the same name, though in that case the code
- is required to import runtime/cgo. */
-
-void *
-_cgo_allocate (size_t n)
-{
- void *ret;
-
- runtime_exitsyscall ();
- ret = alloc_saved (n);
- runtime_entersyscall ();
- return ret;
-}
-
-extern const struct __go_type_descriptor string_type_descriptor
- __asm__ (GOSYM_PREFIX "__go_tdn_string");
-
-void
-_cgo_panic (const char *p)
-{
- intgo len;
- unsigned char *data;
- String *ps;
- struct __go_empty_interface e;
-
- runtime_exitsyscall ();
- len = __builtin_strlen (p);
- data = alloc_saved (len);
- __builtin_memcpy (data, p, len);
- ps = alloc_saved (sizeof *ps);
- ps->str = data;
- ps->len = len;
- e.__type_descriptor = &string_type_descriptor;
- e.__object = ps;
-
- /* We don't call runtime_entersyscall here, because normally what
- will happen is that we will walk up the stack to a Go deferred
- function that calls recover. However, this will do the wrong
- thing if this panic is recovered and the stack unwinding is
- caught by a C++ exception handler. It might be possible to
- handle this by calling runtime_entersyscall in the personality
- function in go-unwind.c. FIXME. */
-
- __go_panic (e);
-}
/* Used for _cgo_wait_runtime_init_done. This is based on code in
runtime/cgo/gcc_libinit.c in the master library. */
@@ -250,8 +62,3 @@ _cgo_notify_runtime_init_done (void)
// runtime_iscgo is set to true if some cgo code is linked in.
// This is done by a constructor in the cgo generated code.
_Bool runtime_iscgo;
-
-// runtime_cgoHasExtraM is set on startup when an extra M is created
-// for cgo. The extra M must be created before any C/C++ code calls
-// cgocallback.
-_Bool runtime_cgoHasExtraM;
diff --git a/libgo/runtime/go-check-interface.c b/libgo/runtime/go-check-interface.c
deleted file mode 100644
index 722a4219ab..0000000000
--- a/libgo/runtime/go-check-interface.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* go-check-interface.c -- check an interface type for a conversion
-
- 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. */
-
-#include "runtime.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Check that an interface type matches for a conversion to a
- non-interface type. This panics if the types are bad. The actual
- extraction of the object is inlined. */
-
-void
-__go_check_interface_type (
- const struct __go_type_descriptor *lhs_descriptor,
- const struct __go_type_descriptor *rhs_descriptor,
- const struct __go_type_descriptor *rhs_inter_descriptor)
-{
- if (rhs_descriptor == NULL)
- {
- struct __go_empty_interface panic_arg;
-
- runtime_newTypeAssertionError(NULL, NULL, lhs_descriptor->__reflection,
- NULL, &panic_arg);
- __go_panic(panic_arg);
- }
-
- if (lhs_descriptor != rhs_descriptor
- && !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor)
- && ((lhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER
- || !__go_is_pointer_type (rhs_descriptor))
- && ((rhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER
- || !__go_is_pointer_type (lhs_descriptor)))
- {
- struct __go_empty_interface panic_arg;
-
- runtime_newTypeAssertionError(rhs_inter_descriptor->__reflection,
- rhs_descriptor->__reflection,
- lhs_descriptor->__reflection,
- NULL, &panic_arg);
- __go_panic(panic_arg);
- }
-}
diff --git a/libgo/runtime/go-construct-map.c b/libgo/runtime/go-construct-map.c
index 4bd79d2005..9a48d5733e 100644
--- a/libgo/runtime/go-construct-map.c
+++ b/libgo/runtime/go-construct-map.c
@@ -9,25 +9,33 @@
#include <stdlib.h>
#include "runtime.h"
-#include "map.h"
+#include "go-type.h"
-struct __go_map *
-__go_construct_map (const struct __go_map_descriptor *descriptor,
+extern void *makemap (const struct __go_map_type *, int64_t hint,
+ void *, void *)
+ __asm__ (GOSYM_PREFIX "runtime.makemap");
+
+extern void *mapassign (const struct __go_map_type *, void *hmap,
+ const void *key)
+ __asm__ (GOSYM_PREFIX "runtime.mapassign");
+
+void *
+__go_construct_map (const struct __go_map_type *type,
uintptr_t count, uintptr_t entry_size,
- uintptr_t val_offset, uintptr_t val_size,
- const void *ventries)
+ uintptr_t val_offset, const void *ventries)
{
- struct __go_map *ret;
+ void *ret;
const unsigned char *entries;
uintptr_t i;
+ void *p;
- ret = __go_new_map (descriptor, count);
+ ret = makemap(type, (int64_t) count, NULL, NULL);
entries = (const unsigned char *) ventries;
for (i = 0; i < count; ++i)
{
- void *val = __go_map_index (ret, entries, 1);
- __builtin_memcpy (val, entries + val_offset, val_size);
+ p = mapassign (type, ret, entries);
+ typedmemmove (type->__val_type, p, entries + val_offset);
entries += entry_size;
}
diff --git a/libgo/runtime/go-convert-interface.c b/libgo/runtime/go-convert-interface.c
deleted file mode 100644
index 0e8a306243..0000000000
--- a/libgo/runtime/go-convert-interface.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* go-convert-interface.c -- convert interfaces for Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "go-string.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* This is called when converting one interface type into another
- interface type. LHS_DESCRIPTOR is the type descriptor of the
- resulting interface. RHS_DESCRIPTOR is the type descriptor of the
- object being converted. This builds and returns a new interface
- method table. If any method in the LHS_DESCRIPTOR interface is not
- implemented by the object, the conversion fails. If the conversion
- fails, then if MAY_FAIL is true this returns NULL; otherwise, it
- panics. */
-
-void *
-__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
- const struct __go_type_descriptor *rhs_descriptor,
- _Bool may_fail)
-{
- const struct __go_interface_type *lhs_interface;
- int lhs_method_count;
- const struct __go_interface_method* lhs_methods;
- const void **methods;
- const struct __go_uncommon_type *rhs_uncommon;
- int rhs_method_count;
- const struct __go_method *p_rhs_method;
- int i;
-
- if (rhs_descriptor == NULL)
- {
- /* A nil value always converts to nil. */
- return NULL;
- }
-
- __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
- lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
- lhs_method_count = lhs_interface->__methods.__count;
- lhs_methods = ((const struct __go_interface_method *)
- lhs_interface->__methods.__values);
-
- /* This should not be called for an empty interface. */
- __go_assert (lhs_method_count > 0);
-
- rhs_uncommon = rhs_descriptor->__uncommon;
- if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
- {
- struct __go_empty_interface panic_arg;
-
- if (may_fail)
- return NULL;
-
- runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
- lhs_descriptor->__reflection,
- lhs_methods[0].__name,
- &panic_arg);
- __go_panic (panic_arg);
- }
-
- rhs_method_count = rhs_uncommon->__methods.__count;
- p_rhs_method = ((const struct __go_method *)
- rhs_uncommon->__methods.__values);
-
- methods = NULL;
-
- for (i = 0; i < lhs_method_count; ++i)
- {
- const struct __go_interface_method *p_lhs_method;
-
- p_lhs_method = &lhs_methods[i];
-
- while (rhs_method_count > 0
- && (!__go_ptr_strings_equal (p_lhs_method->__name,
- p_rhs_method->__name)
- || !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
- p_rhs_method->__pkg_path)))
- {
- ++p_rhs_method;
- --rhs_method_count;
- }
-
- if (rhs_method_count == 0
- || !__go_type_descriptors_equal (p_lhs_method->__type,
- p_rhs_method->__mtype))
- {
- struct __go_empty_interface panic_arg;
-
- if (methods != NULL)
- __go_free (methods);
-
- if (may_fail)
- return NULL;
-
- runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
- lhs_descriptor->__reflection,
- p_lhs_method->__name, &panic_arg);
- __go_panic (panic_arg);
- }
-
- if (methods == NULL)
- {
- methods = (const void **) __go_alloc ((lhs_method_count + 1)
- * sizeof (void *));
-
- /* The first field in the method table is always the type of
- the object. */
- methods[0] = rhs_descriptor;
- }
-
- methods[i + 1] = p_rhs_method->__function;
- }
-
- return methods;
-}
-
-/* This is called by the compiler to convert a value from one
- interface type to another. */
-
-void *
-__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
- const struct __go_type_descriptor *rhs_descriptor)
-{
- return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
-}
diff --git a/libgo/runtime/go-copy.c b/libgo/runtime/go-copy.c
deleted file mode 100644
index 05e16acbf1..0000000000
--- a/libgo/runtime/go-copy.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* go-append.c -- the go builtin copy function.
-
- 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. */
-
-#include <stddef.h>
-#include <stdint.h>
-
-/* We should be OK if we don't split the stack here, since we are just
- calling memmove which shouldn't need much stack. If we don't do
- this we will always split the stack, because of memmove. */
-
-extern void
-__go_copy (void *, void *, uintptr_t)
- __attribute__ ((no_split_stack));
-
-void
-__go_copy (void *a, void *b, uintptr_t len)
-{
- __builtin_memmove (a, b, len);
-}
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
deleted file mode 100644
index 3a48fe1130..0000000000
--- a/libgo/runtime/go-defer.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* go-defer.c -- manage the defer stack.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-panic.h"
-#include "go-defer.h"
-
-/* This function is called each time we need to defer a call. */
-
-void
-__go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
-{
- G *g;
- struct __go_defer_stack *n;
-
- g = runtime_g ();
- n = runtime_newdefer ();
- n->__next = g->defer;
- n->__frame = frame;
- n->__panic = g->panic;
- n->__pfn = pfn;
- n->__arg = arg;
- n->__retaddr = NULL;
- n->__makefunc_can_recover = 0;
- n->__special = 0;
- g->defer = n;
-}
-
-/* This function is called when we want to undefer the stack. */
-
-void
-__go_undefer (_Bool *frame)
-{
- G *g;
-
- g = runtime_g ();
- while (g->defer != NULL && g->defer->__frame == frame)
- {
- struct __go_defer_stack *d;
- void (*pfn) (void *);
-
- d = g->defer;
- pfn = d->__pfn;
- d->__pfn = NULL;
-
- if (pfn != NULL)
- (*pfn) (d->__arg);
-
- g->defer = d->__next;
-
- /* This may be called by a cgo callback routine to defer the
- call to syscall.CgocallBackDone, in which case we will not
- have a memory context. Don't try to free anything in that
- case--the GC will release it later. */
- if (runtime_m () != NULL)
- runtime_freedefer (d);
-
- /* Since we are executing a defer function here, we know we are
- returning from the calling function. If the calling
- function, or one of its callees, paniced, then the defer
- functions would be executed by __go_panic. */
- *frame = 1;
- }
-}
-
-/* This function is called to record the address to which the deferred
- function returns. This may in turn be checked by __go_can_recover.
- The frontend relies on this function returning false. */
-
-_Bool
-__go_set_defer_retaddr (void *retaddr)
-{
- G *g;
-
- g = runtime_g ();
- if (g->defer != NULL)
- g->defer->__retaddr = __builtin_extract_return_addr (retaddr);
- return 0;
-}
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
deleted file mode 100644
index acf2d40c69..0000000000
--- a/libgo/runtime/go-defer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* go-defer.h -- the defer stack.
-
- 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. */
-
-struct __go_panic_stack;
-
-/* The defer stack is a list of these structures. */
-
-struct __go_defer_stack
-{
- /* The next entry in the stack. */
- struct __go_defer_stack *__next;
-
- /* The stack variable for the function which called this defer
- statement. This is set to 1 if we are returning from that
- function, 0 if we are panicing through it. */
- _Bool *__frame;
-
- /* The value of the panic stack when this function is deferred.
- This function can not recover this value from the panic stack.
- This can happen if a deferred function has a defer statement
- itself. */
- struct __go_panic_stack *__panic;
-
- /* The function to call. */
- void (*__pfn) (void *);
-
- /* The argument to pass to the function. */
- void *__arg;
-
- /* The return address that a recover thunk matches against. This is
- set by __go_set_defer_retaddr which is called by the thunks
- created by defer statements. */
- const void *__retaddr;
-
- /* Set to true if a function created by reflect.MakeFunc is
- permitted to recover. The return address of such a function
- function will be somewhere in libffi, so __retaddr is not
- useful. */
- _Bool __makefunc_can_recover;
-
- /* Set to true if this defer stack entry is not part of the defer
- pool. */
- _Bool __special;
-};
diff --git a/libgo/runtime/go-deferred-recover.c b/libgo/runtime/go-deferred-recover.c
deleted file mode 100644
index 78ef287cf0..0000000000
--- a/libgo/runtime/go-deferred-recover.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/* go-deferred-recover.c -- support for a deferred recover function.
-
- 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. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-panic.h"
-#include "go-defer.h"
-
-/* This is called when a call to recover is deferred. That is,
- something like
- defer recover()
-
- We need to handle this specially. In 6g/8g, the recover function
- looks up the stack frame. In particular, that means that a
- deferred recover will not recover a panic thrown in the same
- function that defers the recover. It will only recover a panic
- thrown in a function that defers the deferred call to recover.
-
- In other words:
-
- func f1() {
- defer recover() // does not stop panic
- panic(0)
- }
-
- func f2() {
- defer func() {
- defer recover() // stops panic(0)
- }()
- panic(0)
- }
-
- func f3() {
- defer func() {
- defer recover() // does not stop panic
- panic(0)
- }()
- panic(1)
- }
-
- func f4() {
- defer func() {
- defer func() {
- defer recover() // stops panic(0)
- }()
- panic(0)
- }()
- panic(1)
- }
-
- The interesting case here is f3. As can be seen from f2, the
- deferred recover could pick up panic(1). However, this does not
- happen because it is blocked by the panic(0).
-
- When a function calls recover, then when we invoke it we pass a
- hidden parameter indicating whether it should recover something.
- This parameter is set based on whether the function is being
- invoked directly from defer. The parameter winds up determining
- whether __go_recover or __go_deferred_recover is called at all.
-
- In the case of a deferred recover, the hidden parameter which
- controls the call is actually the one set up for the function which
- runs the defer recover() statement. That is the right thing in all
- the cases above except for f3. In f3 the function is permitted to
- call recover, but the deferred recover call is not. We address
- that here by checking for that specific case before calling
- recover. If this function was deferred when there is already a
- panic on the panic stack, then we can only recover that panic, not
- any other.
-
- Note that we can get away with using a special function here
- because you are not permitted to take the address of a predeclared
- function like recover. */
-
-struct __go_empty_interface
-__go_deferred_recover ()
-{
- G *g;
-
- g = runtime_g ();
- if (g->defer == NULL || g->defer->__panic != g->panic)
- {
- struct __go_empty_interface ret;
-
- ret.__type_descriptor = NULL;
- ret.__object = NULL;
- return ret;
- }
- return __go_recover ();
-}
diff --git a/libgo/runtime/go-eface-compare.c b/libgo/runtime/go-eface-compare.c
deleted file mode 100644
index 40b716eb4a..0000000000
--- a/libgo/runtime/go-eface-compare.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* go-eface-compare.c -- compare two empty values.
-
- 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. */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Compare two interface values. Return 0 for equal, not zero for not
- equal (return value is like strcmp). */
-
-intgo
-__go_empty_interface_compare (struct __go_empty_interface left,
- struct __go_empty_interface right)
-{
- const struct __go_type_descriptor *left_descriptor;
-
- left_descriptor = left.__type_descriptor;
-
- if (left_descriptor == NULL && right.__type_descriptor == NULL)
- return 0;
- if (left_descriptor == NULL || right.__type_descriptor == NULL)
- return 1;
- if (!__go_type_descriptors_equal (left_descriptor,
- right.__type_descriptor))
- return 1;
- if (__go_is_pointer_type (left_descriptor))
- return left.__object == right.__object ? 0 : 1;
- if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object,
- right.__object, left_descriptor->__size))
- return 1;
- return 0;
-}
diff --git a/libgo/runtime/go-eface-val-compare.c b/libgo/runtime/go-eface-val-compare.c
deleted file mode 100644
index e810750d5d..0000000000
--- a/libgo/runtime/go-eface-val-compare.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* go-eface-val-compare.c -- compare an empty interface with a value.
-
- 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. */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Compare an empty interface with a value. Return 0 for equal, not
- zero for not equal (return value is like strcmp). */
-
-intgo
-__go_empty_interface_value_compare (
- struct __go_empty_interface left,
- const struct __go_type_descriptor *right_descriptor,
- const void *val)
-{
- const struct __go_type_descriptor *left_descriptor;
-
- left_descriptor = left.__type_descriptor;
- if (left_descriptor == NULL)
- return 1;
- if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
- return 1;
- if (__go_is_pointer_type (left_descriptor))
- return left.__object == val ? 0 : 1;
- if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, val,
- left_descriptor->__size))
- return 1;
- return 0;
-}
diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c
index aafc7b205e..b030f5e918 100644
--- a/libgo/runtime/go-ffi.c
+++ b/libgo/runtime/go-ffi.c
@@ -1,346 +1,152 @@
-/* go-ffi.c -- convert Go type description to libffi.
+/* go-ffi.c -- libffi support functions.
Copyright 2009 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
-#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-type.h"
#ifdef USE_LIBFFI
#include "ffi.h"
-/* The functions in this file are only called from reflect_call and
- reflect.ffi. As these functions call libffi functions, which will
- be compiled without -fsplit-stack, they will always run with a
- large stack. */
-
-static ffi_type *go_array_to_ffi (const struct __go_array_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_struct_to_ffi (const struct __go_struct_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
-static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
-static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_func_return_ffi (const struct __go_func_type *)
- __attribute__ ((no_split_stack));
-
-/* Return an ffi_type for a Go array type. The libffi library does
- not have any builtin support for passing arrays as values. We work
- around this by pretending that the array is a struct. */
-
-static ffi_type *
-go_array_to_ffi (const struct __go_array_type *descriptor)
+/* The functions in this file are called by the Go runtime code to get
+ the libffi type values. */
+
+ffi_type *go_ffi_type_pointer(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_pointer(void) __asm__ ("runtime.ffi_type_pointer");
+ffi_type *go_ffi_type_sint8(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_sint8(void) __asm__ ("runtime.ffi_type_sint8");
+ffi_type *go_ffi_type_sint16(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_sint16(void) __asm__ ("runtime.ffi_type_sint16");
+ffi_type *go_ffi_type_sint32(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_sint32(void) __asm__ ("runtime.ffi_type_sint32");
+ffi_type *go_ffi_type_sint64(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_sint64(void) __asm__ ("runtime.ffi_type_sint64");
+ffi_type *go_ffi_type_uint8(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_uint8(void) __asm__ ("runtime.ffi_type_uint8");
+ffi_type *go_ffi_type_uint16(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_uint16(void) __asm__ ("runtime.ffi_type_uint16");
+ffi_type *go_ffi_type_uint32(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_uint32(void) __asm__ ("runtime.ffi_type_uint32");
+ffi_type *go_ffi_type_uint64(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_uint64(void) __asm__ ("runtime.ffi_type_uint64");
+ffi_type *go_ffi_type_float(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_float(void) __asm__ ("runtime.ffi_type_float");
+ffi_type *go_ffi_type_double(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_double(void) __asm__ ("runtime.ffi_type_double");
+ffi_type *go_ffi_type_complex_float(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_complex_float(void) __asm__ ("runtime.ffi_type_complex_float");
+ffi_type *go_ffi_type_complex_double(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_complex_double(void) __asm__ ("runtime.ffi_type_complex_double");
+ffi_type *go_ffi_type_void(void) __attribute__ ((no_split_stack));
+ffi_type *go_ffi_type_void(void) __asm__ ("runtime.ffi_type_void");
+
+_Bool go_ffi_supports_complex(void) __attribute__ ((no_split_stack));
+_Bool go_ffi_supports_complex(void) __asm__ ("runtime.ffi_supports_complex");
+
+ffi_type *
+go_ffi_type_pointer(void)
{
- ffi_type *ret;
- uintptr_t len;
- ffi_type *element;
- uintptr_t i;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- len = descriptor->__len;
- if (len == 0)
- {
- /* The libffi library won't accept an empty struct. */
- ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_void;
- ret->elements[1] = NULL;
- return ret;
- }
- ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
- element = go_type_to_ffi (descriptor->__element_type);
- for (i = 0; i < len; ++i)
- ret->elements[i] = element;
- ret->elements[len] = NULL;
- return ret;
+ return &ffi_type_pointer;
}
-/* Return an ffi_type for a Go slice type. This describes the
- __go_open_array type defines in array.h. */
-
-static ffi_type *
-go_slice_to_ffi (
- const struct __go_slice_type *descriptor __attribute__ ((unused)))
+ffi_type *
+go_ffi_type_sint8(void)
{
- ffi_type *ret;
- ffi_type *ffi_intgo;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- ret->elements[1] = ffi_intgo;
- ret->elements[2] = ffi_intgo;
- ret->elements[3] = NULL;
- return ret;
+ return &ffi_type_sint8;
}
-/* Return an ffi_type for a Go struct type. */
-
-static ffi_type *
-go_struct_to_ffi (const struct __go_struct_type *descriptor)
+ffi_type *
+go_ffi_type_sint16(void)
{
- ffi_type *ret;
- int field_count;
- const struct __go_struct_field *fields;
- int i;
-
- field_count = descriptor->__fields.__count;
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- if (field_count == 0)
- {
- /* The libffi library won't accept an empty struct. */
- ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_void;
- ret->elements[1] = NULL;
- return ret;
- }
- fields = (const struct __go_struct_field *) descriptor->__fields.__values;
- ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
- * sizeof (ffi_type *));
- for (i = 0; i < field_count; ++i)
- ret->elements[i] = go_type_to_ffi (fields[i].__type);
- ret->elements[field_count] = NULL;
- return ret;
+ return &ffi_type_sint16;
}
-/* Return an ffi_type for a Go string type. This describes the String
- struct. */
-
-static ffi_type *
-go_string_to_ffi (void)
+ffi_type *
+go_ffi_type_sint32(void)
{
- ffi_type *ret;
- ffi_type *ffi_intgo;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- ret->elements[1] = ffi_intgo;
- ret->elements[2] = NULL;
- return ret;
+ return &ffi_type_sint32;
}
-/* Return an ffi_type for a Go interface type. This describes the
- __go_interface and __go_empty_interface structs. */
-
-static ffi_type *
-go_interface_to_ffi (void)
+ffi_type *
+go_ffi_type_sint64(void)
{
- ffi_type *ret;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ret->elements[1] = &ffi_type_pointer;
- ret->elements[2] = NULL;
- return ret;
+ return &ffi_type_sint64;
}
+ffi_type *
+go_ffi_type_uint8(void)
+{
+ return &ffi_type_uint8;
+}
-#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
-/* If libffi hasn't been updated for this target to support complex,
- pretend complex is a structure. Warning: This does not work for
- all ABIs. Eventually libffi should be updated for all targets
- and this should go away. */
-
-static ffi_type *go_complex_to_ffi (ffi_type *)
- __attribute__ ((no_split_stack));
-
-static ffi_type *
-go_complex_to_ffi (ffi_type *float_type)
+ffi_type *
+go_ffi_type_uint16(void)
{
- ffi_type *ret;
+ return &ffi_type_uint16;
+}
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = float_type;
- ret->elements[1] = float_type;
- ret->elements[2] = NULL;
- return ret;
+ffi_type *
+go_ffi_type_uint32(void)
+{
+ return &ffi_type_uint32;
}
-#endif
-/* Return an ffi_type for a type described by a
- __go_type_descriptor. */
+ffi_type *
+go_ffi_type_uint64(void)
+{
+ return &ffi_type_uint64;
+}
-static ffi_type *
-go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+ffi_type *
+go_ffi_type_float(void)
{
- switch (descriptor->__code & GO_CODE_MASK)
- {
- case GO_BOOL:
- if (sizeof (_Bool) == 1)
- return &ffi_type_uint8;
- else if (sizeof (_Bool) == sizeof (int))
- return &ffi_type_uint;
- abort ();
- case GO_FLOAT32:
- if (sizeof (float) == 4)
return &ffi_type_float;
- abort ();
- case GO_FLOAT64:
- if (sizeof (double) == 8)
+}
+
+ffi_type *
+go_ffi_type_double(void)
+{
return &ffi_type_double;
- abort ();
- case GO_COMPLEX64:
- if (sizeof (float) == 4)
- {
+}
+
+_Bool
+go_ffi_supports_complex(void)
+{
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
- return &ffi_type_complex_float;
+ return true;
#else
- return go_complex_to_ffi (&ffi_type_float);
+ return false;
#endif
- }
- abort ();
- case GO_COMPLEX128:
- if (sizeof (double) == 8)
- {
+}
+
+ffi_type *
+go_ffi_type_complex_float(void)
+{
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
- return &ffi_type_complex_double;
+ return &ffi_type_complex_float;
#else
- return go_complex_to_ffi (&ffi_type_double);
+ abort();
#endif
- }
- abort ();
- case GO_INT16:
- return &ffi_type_sint16;
- case GO_INT32:
- return &ffi_type_sint32;
- case GO_INT64:
- return &ffi_type_sint64;
- case GO_INT8:
- return &ffi_type_sint8;
- case GO_INT:
- return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- case GO_UINT16:
- return &ffi_type_uint16;
- case GO_UINT32:
- return &ffi_type_uint32;
- case GO_UINT64:
- return &ffi_type_uint64;
- case GO_UINT8:
- return &ffi_type_uint8;
- case GO_UINT:
- return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64;
- case GO_UINTPTR:
- if (sizeof (void *) == 2)
- return &ffi_type_uint16;
- else if (sizeof (void *) == 4)
- return &ffi_type_uint32;
- else if (sizeof (void *) == 8)
- return &ffi_type_uint64;
- abort ();
- case GO_ARRAY:
- return go_array_to_ffi ((const struct __go_array_type *) descriptor);
- case GO_SLICE:
- return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
- case GO_STRUCT:
- return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
- case GO_STRING:
- return go_string_to_ffi ();
- case GO_INTERFACE:
- return go_interface_to_ffi ();
- case GO_CHAN:
- case GO_FUNC:
- case GO_MAP:
- case GO_PTR:
- case GO_UNSAFE_POINTER:
- /* These types are always pointers, and for FFI purposes nothing
- else matters. */
- return &ffi_type_pointer;
- default:
- abort ();
- }
}
-/* Return the return type for a function, given the number of out
- parameters and their types. */
-
-static ffi_type *
-go_func_return_ffi (const struct __go_func_type *func)
+ffi_type *
+go_ffi_type_complex_double(void)
{
- int count;
- const struct __go_type_descriptor **types;
- ffi_type *ret;
- int i;
-
- count = func->__out.__count;
- if (count == 0)
- return &ffi_type_void;
-
- types = (const struct __go_type_descriptor **) func->__out.__values;
-
- if (count == 1)
- return go_type_to_ffi (types[0]);
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
- for (i = 0; i < count; ++i)
- ret->elements[i] = go_type_to_ffi (types[i]);
- ret->elements[count] = NULL;
- return ret;
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+ return &ffi_type_complex_double;
+#else
+ abort();
+#endif
}
-/* Build an ffi_cif structure for a function described by a
- __go_func_type structure. */
-
-void
-__go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
- _Bool is_method, ffi_cif *cif)
+ffi_type *
+go_ffi_type_void(void)
{
- int num_params;
- const struct __go_type_descriptor **in_types;
- size_t num_args;
- ffi_type **args;
- int off;
- int i;
- ffi_type *rettype;
- ffi_status status;
-
- num_params = func->__in.__count;
- in_types = ((const struct __go_type_descriptor **)
- func->__in.__values);
-
- num_args = num_params + (is_interface ? 1 : 0);
- args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
- i = 0;
- off = 0;
- if (is_interface)
- {
- args[0] = &ffi_type_pointer;
- off = 1;
- }
- else if (is_method)
- {
- args[0] = &ffi_type_pointer;
- i = 1;
- }
- for (; i < num_params; ++i)
- args[i + off] = go_type_to_ffi (in_types[i]);
-
- rettype = go_func_return_ffi (func);
-
- status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
- __go_assert (status == FFI_OK);
+ return &ffi_type_void;
}
#endif /* defined(USE_LIBFFI) */
diff --git a/libgo/runtime/go-ffi.h b/libgo/runtime/go-ffi.h
deleted file mode 100644
index afae4b6d6e..0000000000
--- a/libgo/runtime/go-ffi.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* go-ffi.c -- convert Go type description to libffi.
-
- Copyright 2014 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "config.h"
-#include "go-type.h"
-
-#ifdef USE_LIBFFI
-
-#include "ffi.h"
-
-void __go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, ffi_cif *);
-
-#endif
diff --git a/libgo/runtime/go-fieldtrack.c b/libgo/runtime/go-fieldtrack.c
index a7e2c13344..c4f27ef079 100644
--- a/libgo/runtime/go-fieldtrack.c
+++ b/libgo/runtime/go-fieldtrack.c
@@ -6,7 +6,6 @@
#include "runtime.h"
#include "go-type.h"
-#include "map.h"
/* The compiler will track fields that have the tag go:"track". Any
function that refers to such a field will call this function with a
@@ -34,16 +33,26 @@ extern const char _edata[] __attribute__ ((weak));
extern const char __edata[] __attribute__ ((weak));
extern const char __bss_start[] __attribute__ ((weak));
-void runtime_Fieldtrack (struct __go_map *) __asm__ (GOSYM_PREFIX "runtime.Fieldtrack");
+extern void *mapassign (const struct __go_map_type *, void *hmap,
+ const void *key)
+ __asm__ (GOSYM_PREFIX "runtime.mapassign");
+
+// The type descriptor for map[string] bool. */
+extern const char __go_td_MN6_string__N4_bool[] __attribute__ ((weak));
+
+void runtime_Fieldtrack (void *) __asm__ (GOSYM_PREFIX "runtime.Fieldtrack");
void
-runtime_Fieldtrack (struct __go_map *m)
+runtime_Fieldtrack (void *m)
{
const char *p;
const char *pend;
const char *prefix;
size_t prefix_len;
+ if (__go_td_MN6_string__N4_bool == NULL)
+ return;
+
p = __data_start;
if (p == NULL)
p = __etext;
@@ -86,14 +95,12 @@ runtime_Fieldtrack (struct __go_map *m)
if (__builtin_memchr (q1, '\0', q2 - q1) == NULL)
{
String s;
- void *v;
- _Bool *pb;
+ void *p;
s.str = (const byte *) q1;
s.len = q2 - q1;
- v = __go_map_index (m, &s, 1);
- pb = (_Bool *) v;
- *pb = 1;
+ p = mapassign((const void*) __go_td_MN6_string__N4_bool, m, &s);
+ *(_Bool*)p = 1;
}
p = q2;
diff --git a/libgo/runtime/go-iface.goc b/libgo/runtime/go-iface.goc
deleted file mode 100644
index 0d5cb5e97a..0000000000
--- a/libgo/runtime/go-iface.goc
+++ /dev/null
@@ -1,130 +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
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-typedef struct __go_type_descriptor descriptor;
-typedef const struct __go_type_descriptor const_descriptor;
-typedef struct __go_interface interface;
-typedef struct __go_empty_interface empty_interface;
-
-// Compare two type descriptors.
-func ifacetypeeq(a *descriptor, b *descriptor) (eq bool) {
- eq = __go_type_descriptors_equal(a, b);
-}
-
-// Return the descriptor for an empty interface type.n
-func efacetype(e empty_interface) (d *const_descriptor) {
- return e.__type_descriptor;
-}
-
-// Return the descriptor for a non-empty interface type.
-func ifacetype(i interface) (d *const_descriptor) {
- if (i.__methods == nil) {
- return nil;
- }
- d = i.__methods[0];
-}
-
-// Convert an empty interface to an empty interface.
-func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) {
- ret = e;
- ok = ret.__type_descriptor != nil;
-}
-
-// Convert a non-empty interface to an empty interface.
-func ifaceI2E2(i interface) (ret empty_interface, ok bool) {
- if (i.__methods == nil) {
- ret.__type_descriptor = nil;
- ret.__object = nil;
- ok = 0;
- } else {
- ret.__type_descriptor = i.__methods[0];
- ret.__object = i.__object;
- ok = 1;
- }
-}
-
-// Convert an empty interface to a non-empty interface.
-func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) {
- if (e.__type_descriptor == nil) {
- ret.__methods = nil;
- ret.__object = nil;
- ok = 0;
- } else {
- ret.__methods = __go_convert_interface_2(inter,
- e.__type_descriptor,
- 1);
- ret.__object = e.__object;
- ok = ret.__methods != nil;
- }
-}
-
-// Convert a non-empty interface to a non-empty interface.
-func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) {
- if (i.__methods == nil) {
- ret.__methods = nil;
- ret.__object = nil;
- ok = 0;
- } else {
- ret.__methods = __go_convert_interface_2(inter,
- i.__methods[0], 1);
- ret.__object = i.__object;
- ok = ret.__methods != nil;
- }
-}
-
-// Convert an empty interface to a pointer type.
-func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) {
- if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
- ret = nil;
- ok = 0;
- } else {
- ret = e.__object;
- ok = 1;
- }
-}
-
-// Convert a non-empty interface to a pointer type.
-func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) {
- if (i.__methods == nil
- || !__go_type_descriptors_equal(inter, i.__methods[0])) {
- ret = nil;
- ok = 0;
- } else {
- ret = i.__object;
- ok = 1;
- }
-}
-
-// Convert an empty interface to a non-pointer type.
-func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) {
- if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
- __builtin_memset(ret, 0, inter->__size);
- ok = 0;
- } else {
- __builtin_memcpy(ret, e.__object, inter->__size);
- ok = 1;
- }
-}
-
-// Convert a non-empty interface to a non-pointer type.
-func ifaceI2T2(inter *descriptor, i interface, ret *void) (ok bool) {
- if (i.__methods == nil
- || !__go_type_descriptors_equal(inter, i.__methods[0])) {
- __builtin_memset(ret, 0, inter->__size);
- ok = 0;
- } else {
- __builtin_memcpy(ret, i.__object, inter->__size);
- ok = 1;
- }
-}
-
-// Return whether we can convert an interface to a type.
-func ifaceI2Tp(to *descriptor, from *descriptor) (ok bool) {
- ok = __go_can_convert_to_interface(to, from);
-}
diff --git a/libgo/runtime/go-int-array-to-string.c b/libgo/runtime/go-int-array-to-string.c
deleted file mode 100644
index f37213125a..0000000000
--- a/libgo/runtime/go-int-array-to-string.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* go-int-array-to-string.c -- convert an array of ints to a string in Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "go-assert.h"
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-String
-__go_int_array_to_string (const void* p, intgo len)
-{
- const int32 *ints;
- intgo slen;
- intgo i;
- unsigned char *retdata;
- String ret;
- unsigned char *s;
-
- ints = (const int32 *) p;
-
- slen = 0;
- for (i = 0; i < len; ++i)
- {
- int32 v;
-
- v = ints[i];
-
- if (v < 0 || v > 0x10ffff)
- v = 0xfffd;
- else if (0xd800 <= v && v <= 0xdfff)
- v = 0xfffd;
-
- if (v <= 0x7f)
- slen += 1;
- else if (v <= 0x7ff)
- slen += 2;
- else if (v <= 0xffff)
- slen += 3;
- else
- slen += 4;
- }
-
- retdata = runtime_mallocgc ((uintptr) slen, 0, FlagNoScan);
- ret.str = retdata;
- ret.len = slen;
-
- s = retdata;
- for (i = 0; i < len; ++i)
- {
- int32 v;
-
- v = ints[i];
-
- /* If V is out of range for UTF-8, substitute the replacement
- character. */
- if (v < 0 || v > 0x10ffff)
- v = 0xfffd;
- else if (0xd800 <= v && v <= 0xdfff)
- v = 0xfffd;
-
- if (v <= 0x7f)
- *s++ = v;
- else if (v <= 0x7ff)
- {
- *s++ = 0xc0 | ((v >> 6) & 0x1f);
- *s++ = 0x80 | (v & 0x3f);
- }
- else if (v <= 0xffff)
- {
- *s++ = 0xe0 | ((v >> 12) & 0xf);
- *s++ = 0x80 | ((v >> 6) & 0x3f);
- *s++ = 0x80 | (v & 0x3f);
- }
- else
- {
- *s++ = 0xf0 | ((v >> 18) & 0x7);
- *s++ = 0x80 | ((v >> 12) & 0x3f);
- *s++ = 0x80 | ((v >> 6) & 0x3f);
- *s++ = 0x80 | (v & 0x3f);
- }
- }
-
- __go_assert (s - retdata == slen);
-
- return ret;
-}
diff --git a/libgo/runtime/go-int-to-string.c b/libgo/runtime/go-int-to-string.c
deleted file mode 100644
index d90b1ddfed..0000000000
--- a/libgo/runtime/go-int-to-string.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* go-int-to-string.c -- convert an integer to a string in Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-String
-__go_int_to_string (intgo v)
-{
- char buf[4];
- int len;
- unsigned char *retdata;
- String ret;
-
- /* A negative value is not valid UTF-8; turn it into the replacement
- character. */
- if (v < 0)
- v = 0xfffd;
-
- if (v <= 0x7f)
- {
- buf[0] = v;
- len = 1;
- }
- else if (v <= 0x7ff)
- {
- buf[0] = 0xc0 + (v >> 6);
- buf[1] = 0x80 + (v & 0x3f);
- len = 2;
- }
- else
- {
- /* If the value is out of range for UTF-8, turn it into the
- "replacement character". */
- if (v > 0x10ffff)
- v = 0xfffd;
- /* If the value is a surrogate pair, which is invalid in UTF-8,
- turn it into the replacement character. */
- if (v >= 0xd800 && v < 0xe000)
- v = 0xfffd;
-
- if (v <= 0xffff)
- {
- buf[0] = 0xe0 + (v >> 12);
- buf[1] = 0x80 + ((v >> 6) & 0x3f);
- buf[2] = 0x80 + (v & 0x3f);
- len = 3;
- }
- else
- {
- buf[0] = 0xf0 + (v >> 18);
- buf[1] = 0x80 + ((v >> 12) & 0x3f);
- buf[2] = 0x80 + ((v >> 6) & 0x3f);
- buf[3] = 0x80 + (v & 0x3f);
- len = 4;
- }
- }
-
- retdata = runtime_mallocgc (len, 0, FlagNoScan);
- __builtin_memcpy (retdata, buf, len);
- ret.str = retdata;
- ret.len = len;
-
- return ret;
-}
diff --git a/libgo/runtime/go-interface-compare.c b/libgo/runtime/go-interface-compare.c
deleted file mode 100644
index 1d367753a1..0000000000
--- a/libgo/runtime/go-interface-compare.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* go-interface-compare.c -- compare two interface values.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Compare two interface values. Return 0 for equal, not zero for not
- equal (return value is like strcmp). */
-
-int
-__go_interface_compare (struct __go_interface left,
- struct __go_interface right)
-{
- const struct __go_type_descriptor *left_descriptor;
-
- if (left.__methods == NULL && right.__methods == NULL)
- return 0;
- if (left.__methods == NULL || right.__methods == NULL)
- return 1;
- left_descriptor = left.__methods[0];
- if (!__go_type_descriptors_equal (left_descriptor, right.__methods[0]))
- return 1;
- if (__go_is_pointer_type (left_descriptor))
- return left.__object == right.__object ? 0 : 1;
- if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object,
- right.__object, left_descriptor->__size))
- return 1;
- return 0;
-}
diff --git a/libgo/runtime/go-interface-eface-compare.c b/libgo/runtime/go-interface-eface-compare.c
deleted file mode 100644
index d1e6fd084d..0000000000
--- a/libgo/runtime/go-interface-eface-compare.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* go-interface-eface-compare.c -- compare non-empty and empty interface.
-
- 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. */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Compare a non-empty interface value with an empty interface value.
- Return 0 for equal, not zero for not equal (return value is like
- strcmp). */
-
-intgo
-__go_interface_empty_compare (struct __go_interface left,
- struct __go_empty_interface right)
-{
- const struct __go_type_descriptor *left_descriptor;
-
- if (left.__methods == NULL && right.__type_descriptor == NULL)
- return 0;
- if (left.__methods == NULL || right.__type_descriptor == NULL)
- return 1;
- left_descriptor = left.__methods[0];
- if (!__go_type_descriptors_equal (left_descriptor, right.__type_descriptor))
- return 1;
- if (__go_is_pointer_type (left_descriptor))
- return left.__object == right.__object ? 0 : 1;
- if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object,
- right.__object, left_descriptor->__size))
- return 1;
- return 0;
-}
diff --git a/libgo/runtime/go-interface-val-compare.c b/libgo/runtime/go-interface-val-compare.c
deleted file mode 100644
index 36b6efdc9f..0000000000
--- a/libgo/runtime/go-interface-val-compare.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* go-interface-val-compare.c -- compare an interface to a value.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-
-/* Compare two interface values. Return 0 for equal, not zero for not
- equal (return value is like strcmp). */
-
-intgo
-__go_interface_value_compare (
- struct __go_interface left,
- const struct __go_type_descriptor *right_descriptor,
- const void *val)
-{
- const struct __go_type_descriptor *left_descriptor;
-
- if (left.__methods == NULL)
- return 1;
- left_descriptor = left.__methods[0];
- if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
- return 1;
- if (__go_is_pointer_type (left_descriptor))
- return left.__object == val ? 0 : 1;
- if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, val,
- left_descriptor->__size))
- return 1;
- return 0;
-}
diff --git a/libgo/runtime/go-libmain.c b/libgo/runtime/go-libmain.c
index 6884f3a5f5..8e07e90178 100644
--- a/libgo/runtime/go-libmain.c
+++ b/libgo/runtime/go-libmain.c
@@ -13,7 +13,6 @@
#include <unistd.h>
#include "runtime.h"
-#include "go-alloc.h"
#include "array.h"
#include "arch.h"
#include "malloc.h"
@@ -61,6 +60,8 @@ initfn (int argc, char **argv, char** env __attribute__ ((unused)))
runtime_isarchive = true;
+ setIsCgo ();
+ runtime_cpuinit ();
runtime_initsig(true);
a = (struct args *) malloc (sizeof *a);
diff --git a/libgo/runtime/go-main.c b/libgo/runtime/go-main.c
index ff2958c239..dba8085260 100644
--- a/libgo/runtime/go-main.c
+++ b/libgo/runtime/go-main.c
@@ -15,7 +15,6 @@
#endif
#include "runtime.h"
-#include "go-alloc.h"
#include "array.h"
#include "arch.h"
#include "malloc.h"
@@ -46,7 +45,11 @@ main (int argc, char **argv)
return 0;
runtime_isstarted = true;
+ if (runtime_iscgo)
+ setIsCgo ();
+
__go_end = (uintptr)_end;
+ runtime_cpuinit ();
runtime_check ();
runtime_args (argc, (byte **) argv);
runtime_osinit ();
diff --git a/libgo/runtime/go-make-slice.c b/libgo/runtime/go-make-slice.c
deleted file mode 100644
index ccd07e5ac5..0000000000
--- a/libgo/runtime/go-make-slice.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* go-make-slice.c -- make a slice.
-
- 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. */
-
-#include <stdint.h>
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-/* Dummy word to use as base pointer for make([]T, 0).
- Since you cannot take the address of such a slice,
- you can't tell that they all have the same base pointer. */
-uintptr runtime_zerobase;
-
-struct __go_open_array
-__go_make_slice2 (const struct __go_type_descriptor *td, uintptr_t len,
- uintptr_t cap)
-{
- const struct __go_slice_type* std;
- intgo ilen;
- intgo icap;
- uintptr_t size;
- struct __go_open_array ret;
-
- __go_assert ((td->__code & GO_CODE_MASK) == GO_SLICE);
- std = (const struct __go_slice_type *) td;
-
- ilen = (intgo) len;
- if (ilen < 0
- || (uintptr_t) ilen != len
- || (std->__element_type->__size > 0
- && len > MaxMem / std->__element_type->__size))
- runtime_panicstring ("makeslice: len out of range");
-
- icap = (intgo) cap;
- if (cap < len
- || (uintptr_t) icap != cap
- || (std->__element_type->__size > 0
- && cap > MaxMem / std->__element_type->__size))
- runtime_panicstring ("makeslice: cap out of range");
-
- ret.__count = ilen;
- ret.__capacity = icap;
-
- size = cap * std->__element_type->__size;
-
- if (size == 0)
- ret.__values = &runtime_zerobase;
- else if ((std->__element_type->__code & GO_NO_POINTERS) != 0)
- ret.__values =
- runtime_mallocgc (size,
- (uintptr) std->__element_type | TypeInfo_Array,
- FlagNoScan);
- else
- ret.__values =
- runtime_mallocgc (size,
- (uintptr) std->__element_type | TypeInfo_Array,
- 0);
-
- return ret;
-}
-
-struct __go_open_array
-__go_make_slice1 (const struct __go_type_descriptor *td, uintptr_t len)
-{
- return __go_make_slice2 (td, len, len);
-}
-
-struct __go_open_array
-__go_make_slice2_big (const struct __go_type_descriptor *td, uint64_t len,
- uint64_t cap)
-{
- uintptr_t slen;
- uintptr_t scap;
-
- slen = (uintptr_t) len;
- if ((uint64_t) slen != len)
- runtime_panicstring ("makeslice: len out of range");
-
- scap = (uintptr_t) cap;
- if ((uint64_t) scap != cap)
- runtime_panicstring ("makeslice: cap out of range");
-
- return __go_make_slice2 (td, slen, scap);
-}
-
-struct __go_open_array
-__go_make_slice1_big (const struct __go_type_descriptor *td, uint64_t len)
-{
- return __go_make_slice2_big (td, len, len);
-}
diff --git a/libgo/runtime/go-map-delete.c b/libgo/runtime/go-map-delete.c
deleted file mode 100644
index fb7c331856..0000000000
--- a/libgo/runtime/go-map-delete.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* go-map-delete.c -- delete an entry from a map.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-#include <stdlib.h>
-
-#include "runtime.h"
-#include "malloc.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "map.h"
-
-/* Delete the entry matching KEY from MAP. */
-
-void
-__go_map_delete (struct __go_map *map, const void *key)
-{
- const struct __go_map_descriptor *descriptor;
- const struct __go_type_descriptor *key_descriptor;
- uintptr_t key_offset;
- const FuncVal *equalfn;
- size_t key_hash;
- size_t key_size;
- size_t bucket_index;
- void **pentry;
-
- if (map == NULL)
- return;
-
- descriptor = map->__descriptor;
-
- key_descriptor = descriptor->__map_descriptor->__key_type;
- key_offset = descriptor->__key_offset;
- key_size = key_descriptor->__size;
- if (key_size == 0)
- return;
-
- __go_assert (key_size != -1UL);
- equalfn = key_descriptor->__equalfn;
-
- key_hash = __go_call_hashfn (key_descriptor->__hashfn, key, key_size);
- bucket_index = key_hash % map->__bucket_count;
-
- pentry = map->__buckets + bucket_index;
- while (*pentry != NULL)
- {
- char *entry = (char *) *pentry;
- if (__go_call_equalfn (equalfn, key, entry + key_offset, key_size))
- {
- *pentry = *(void **) entry;
- if (descriptor->__entry_size >= TinySize)
- __go_free (entry);
- map->__element_count -= 1;
- break;
- }
- pentry = (void **) entry;
- }
-}
diff --git a/libgo/runtime/go-map-index.c b/libgo/runtime/go-map-index.c
deleted file mode 100644
index 353041db6c..0000000000
--- a/libgo/runtime/go-map-index.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* go-map-index.c -- find or insert an entry in a map.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-#include <stdlib.h>
-
-#include "runtime.h"
-#include "malloc.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "map.h"
-
-/* Rehash MAP to a larger size. */
-
-static void
-__go_map_rehash (struct __go_map *map)
-{
- const struct __go_map_descriptor *descriptor;
- const struct __go_type_descriptor *key_descriptor;
- uintptr_t key_offset;
- size_t key_size;
- const FuncVal *hashfn;
- uintptr_t old_bucket_count;
- void **old_buckets;
- uintptr_t new_bucket_count;
- void **new_buckets;
- uintptr_t i;
-
- descriptor = map->__descriptor;
-
- key_descriptor = descriptor->__map_descriptor->__key_type;
- key_offset = descriptor->__key_offset;
- key_size = key_descriptor->__size;
- hashfn = key_descriptor->__hashfn;
-
- old_bucket_count = map->__bucket_count;
- old_buckets = map->__buckets;
-
- new_bucket_count = __go_map_next_prime (old_bucket_count * 2);
- new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *));
- __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *));
-
- for (i = 0; i < old_bucket_count; ++i)
- {
- char* entry;
- char* next;
-
- for (entry = old_buckets[i]; entry != NULL; entry = next)
- {
- size_t key_hash;
- size_t new_bucket_index;
-
- /* We could speed up rehashing at the cost of memory space
- by caching the hash code. */
- key_hash = __go_call_hashfn (hashfn, entry + key_offset, key_size);
- new_bucket_index = key_hash % new_bucket_count;
-
- next = *(char **) entry;
- *(char **) entry = new_buckets[new_bucket_index];
- new_buckets[new_bucket_index] = entry;
- }
- }
-
- if (old_bucket_count * sizeof (void *) >= TinySize)
- __go_free (old_buckets);
-
- map->__bucket_count = new_bucket_count;
- map->__buckets = new_buckets;
-}
-
-/* Find KEY in MAP, return a pointer to the value. If KEY is not
- present, then if INSERT is false, return NULL, and if INSERT is
- true, insert a new value and zero-initialize it before returning a
- pointer to it. */
-
-void *
-__go_map_index (struct __go_map *map, const void *key, _Bool insert)
-{
- const struct __go_map_descriptor *descriptor;
- const struct __go_type_descriptor *key_descriptor;
- uintptr_t key_offset;
- const FuncVal *equalfn;
- size_t key_hash;
- size_t key_size;
- size_t bucket_index;
- char *entry;
-
- if (map == NULL)
- {
- if (insert)
- runtime_panicstring ("assignment to entry in nil map");
- return NULL;
- }
-
- descriptor = map->__descriptor;
-
- key_descriptor = descriptor->__map_descriptor->__key_type;
- key_offset = descriptor->__key_offset;
- key_size = key_descriptor->__size;
- __go_assert (key_size != -1UL);
- equalfn = key_descriptor->__equalfn;
-
- key_hash = __go_call_hashfn (key_descriptor->__hashfn, key, key_size);
- bucket_index = key_hash % map->__bucket_count;
-
- entry = (char *) map->__buckets[bucket_index];
- while (entry != NULL)
- {
- if (__go_call_equalfn (equalfn, key, entry + key_offset, key_size))
- return entry + descriptor->__val_offset;
- entry = *(char **) entry;
- }
-
- if (!insert)
- return NULL;
-
- if (map->__element_count >= map->__bucket_count)
- {
- __go_map_rehash (map);
- bucket_index = key_hash % map->__bucket_count;
- }
-
- entry = (char *) __go_alloc (descriptor->__entry_size);
- __builtin_memset (entry, 0, descriptor->__entry_size);
-
- __builtin_memcpy (entry + key_offset, key, key_size);
-
- *(char **) entry = map->__buckets[bucket_index];
- map->__buckets[bucket_index] = entry;
-
- map->__element_count += 1;
-
- return entry + descriptor->__val_offset;
-}
diff --git a/libgo/runtime/go-map-len.c b/libgo/runtime/go-map-len.c
deleted file mode 100644
index 7da10c2494..0000000000
--- a/libgo/runtime/go-map-len.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* go-map-len.c -- return the length of a map.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-assert.h"
-#include "map.h"
-
-/* Return the length of a map. This could be done inline, of course,
- but I'm doing it as a function for now to make it easy to change
- the map structure. */
-
-intgo
-__go_map_len (struct __go_map *map)
-{
- if (map == NULL)
- return 0;
- __go_assert (map->__element_count
- == (uintptr_t) (intgo) map->__element_count);
- return map->__element_count;
-}
diff --git a/libgo/runtime/go-map-range.c b/libgo/runtime/go-map-range.c
deleted file mode 100644
index 5dbb92ccb8..0000000000
--- a/libgo/runtime/go-map-range.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/* go-map-range.c -- implement a range clause over a map.
-
- Copyright 2009, 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. */
-
-#include "runtime.h"
-#include "go-assert.h"
-#include "map.h"
-
-/* Initialize a range over a map. */
-
-void
-__go_mapiterinit (const struct __go_map *h, struct __go_hash_iter *it)
-{
- it->entry = NULL;
- if (h != NULL)
- {
- it->map = h;
- it->next_entry = NULL;
- it->bucket = 0;
- --it->bucket;
- __go_mapiternext(it);
- }
-}
-
-/* Move to the next iteration, updating *HITER. */
-
-void
-__go_mapiternext (struct __go_hash_iter *it)
-{
- const void *entry;
-
- entry = it->next_entry;
- if (entry == NULL)
- {
- const struct __go_map *map;
- uintptr_t bucket;
-
- map = it->map;
- bucket = it->bucket;
- while (1)
- {
- ++bucket;
- if (bucket >= map->__bucket_count)
- {
- /* Map iteration is complete. */
- it->entry = NULL;
- return;
- }
- entry = map->__buckets[bucket];
- if (entry != NULL)
- break;
- }
- it->bucket = bucket;
- }
- it->entry = entry;
- it->next_entry = *(const void * const *) entry;
-}
-
-/* Get the key of the current iteration. */
-
-void
-__go_mapiter1 (struct __go_hash_iter *it, unsigned char *key)
-{
- const struct __go_map *map;
- const struct __go_map_descriptor *descriptor;
- const struct __go_type_descriptor *key_descriptor;
- const char *p;
-
- map = it->map;
- descriptor = map->__descriptor;
- key_descriptor = descriptor->__map_descriptor->__key_type;
- p = it->entry;
- __go_assert (p != NULL);
- __builtin_memcpy (key, p + descriptor->__key_offset, key_descriptor->__size);
-}
-
-/* Get the key and value of the current iteration. */
-
-void
-__go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
- unsigned char *val)
-{
- const struct __go_map *map;
- const struct __go_map_descriptor *descriptor;
- const struct __go_map_type *map_descriptor;
- const struct __go_type_descriptor *key_descriptor;
- const struct __go_type_descriptor *val_descriptor;
- const char *p;
-
- map = it->map;
- descriptor = map->__descriptor;
- map_descriptor = descriptor->__map_descriptor;
- key_descriptor = map_descriptor->__key_type;
- val_descriptor = map_descriptor->__val_type;
- p = it->entry;
- __go_assert (p != NULL);
- __builtin_memcpy (key, p + descriptor->__key_offset,
- key_descriptor->__size);
- __builtin_memcpy (val, p + descriptor->__val_offset,
- val_descriptor->__size);
-}
diff --git a/libgo/runtime/go-memclr.c b/libgo/runtime/go-memclr.c
new file mode 100644
index 0000000000..e478b658b9
--- /dev/null
+++ b/libgo/runtime/go-memclr.c
@@ -0,0 +1,16 @@
+/* go-memclr.c -- clear a memory buffer
+
+ 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 "runtime.h"
+
+void memclrNoHeapPointers(void *, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.memclrNoHeapPointers");
+
+void
+memclrNoHeapPointers (void *p1, uintptr len)
+{
+ __builtin_memset (p1, 0, len);
+}
diff --git a/libgo/runtime/go-memequal.c b/libgo/runtime/go-memequal.c
new file mode 100644
index 0000000000..5f514aaae0
--- /dev/null
+++ b/libgo/runtime/go-memequal.c
@@ -0,0 +1,16 @@
+/* go-memequal.c -- compare memory buffers for equality
+
+ 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 "runtime.h"
+
+_Bool memequal (void *, void *, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.memequal");
+
+_Bool
+memequal (void *p1, void *p2, uintptr len)
+{
+ return __builtin_memcmp (p1, p2, len) == 0;
+}
diff --git a/libgo/runtime/go-memmove.c b/libgo/runtime/go-memmove.c
new file mode 100644
index 0000000000..a6fda08c47
--- /dev/null
+++ b/libgo/runtime/go-memmove.c
@@ -0,0 +1,16 @@
+/* go-memmove.c -- move one memory buffer to another
+
+ 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 "runtime.h"
+
+void move(void *, void *, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.memmove");
+
+void
+move (void *p1, void *p2, uintptr len)
+{
+ __builtin_memmove (p1, p2, len);
+}
diff --git a/libgo/runtime/go-nanotime.c b/libgo/runtime/go-nanotime.c
index 7e5e3e098a..d221847ada 100644
--- a/libgo/runtime/go-nanotime.c
+++ b/libgo/runtime/go-nanotime.c
@@ -14,8 +14,8 @@ int64 runtime_nanotime (void)
int64
runtime_nanotime (void)
{
- struct timeval tv;
+ struct timespec ts;
- gettimeofday (&tv, NULL);
- return (int64) tv.tv_sec * 1000000000 + (int64) tv.tv_usec * 1000;
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ return (int64) ts.tv_sec * 1000000000 + (int64) ts.tv_nsec;
}
diff --git a/libgo/runtime/go-new-map.c b/libgo/runtime/go-new-map.c
deleted file mode 100644
index c289bc0bea..0000000000
--- a/libgo/runtime/go-new-map.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* go-new-map.c -- allocate a new map.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "map.h"
-
-/* List of prime numbers, copied from libstdc++/src/hashtable.c. */
-
-static const unsigned long prime_list[] = /* 256 + 1 or 256 + 48 + 1 */
-{
- 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul,
- 37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
- 83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul,
- 157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul,
- 277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul,
- 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul,
- 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul,
- 1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul,
- 3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul,
- 5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul,
- 11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul,
- 19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul,
- 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul,
- 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul,
- 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul,
- 159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul,
- 256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul,
- 410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul,
- 658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul,
- 1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul,
- 1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul,
- 2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul,
- 4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul,
- 6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul,
- 11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul,
- 16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul,
- 24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul,
- 36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
- 54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul,
- 80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul,
- 118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul,
- 176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul,
- 260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul,
- 386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
- 573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul,
- 849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul,
- 1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul, 1725587117ul,
- 1866894511ul, 2019773507ul, 2185171673ul, 2364114217ul, 2557710269ul,
- 2767159799ul, 2993761039ul, 3238918481ul, 3504151727ul, 3791104843ul,
- 4101556399ul, 4294967291ul,
-#if __SIZEOF_LONG__ >= 8
- 6442450933ul, 8589934583ul, 12884901857ul, 17179869143ul,
- 25769803693ul, 34359738337ul, 51539607367ul, 68719476731ul,
- 103079215087ul, 137438953447ul, 206158430123ul, 274877906899ul,
- 412316860387ul, 549755813881ul, 824633720731ul, 1099511627689ul,
- 1649267441579ul, 2199023255531ul, 3298534883309ul, 4398046511093ul,
- 6597069766607ul, 8796093022151ul, 13194139533241ul, 17592186044399ul,
- 26388279066581ul, 35184372088777ul, 52776558133177ul, 70368744177643ul,
- 105553116266399ul, 140737488355213ul, 211106232532861ul, 281474976710597ul,
- 562949953421231ul, 1125899906842597ul, 2251799813685119ul,
- 4503599627370449ul, 9007199254740881ul, 18014398509481951ul,
- 36028797018963913ul, 72057594037927931ul, 144115188075855859ul,
- 288230376151711717ul, 576460752303423433ul,
- 1152921504606846883ul, 2305843009213693951ul,
- 4611686018427387847ul, 9223372036854775783ul,
- 18446744073709551557ul
-#endif
-};
-
-/* Return the next number from PRIME_LIST >= N. */
-
-uintptr_t
-__go_map_next_prime (uintptr_t n)
-{
- size_t low;
- size_t high;
-
- low = 0;
- high = sizeof prime_list / sizeof prime_list[0];
- while (low < high)
- {
- size_t mid;
-
- mid = (low + high) / 2;
-
- /* Here LOW <= MID < HIGH. */
-
- if (prime_list[mid] < n)
- low = mid + 1;
- else if (prime_list[mid] > n)
- high = mid;
- else
- return n;
- }
- if (low >= sizeof prime_list / sizeof prime_list[0])
- return n;
- return prime_list[low];
-}
-
-/* Allocate a new map. */
-
-struct __go_map *
-__go_new_map (const struct __go_map_descriptor *descriptor, uintptr_t entries)
-{
- int32 ientries;
- struct __go_map *ret;
-
- /* The master library limits map entries to int32, so we do too. */
- ientries = (int32) entries;
- if (ientries < 0 || (uintptr_t) ientries != entries)
- runtime_panicstring ("map size out of range");
-
- if (entries == 0)
- entries = 5;
- else
- entries = __go_map_next_prime (entries);
- ret = (struct __go_map *) __go_alloc (sizeof (struct __go_map));
- ret->__descriptor = descriptor;
- ret->__element_count = 0;
- ret->__bucket_count = entries;
- ret->__buckets = (void **) __go_alloc (entries * sizeof (void *));
- __builtin_memset (ret->__buckets, 0, entries * sizeof (void *));
- return ret;
-}
-
-/* Allocate a new map when the argument to make is a large type. */
-
-struct __go_map *
-__go_new_map_big (const struct __go_map_descriptor *descriptor,
- uint64_t entries)
-{
- uintptr_t sentries;
-
- sentries = (uintptr_t) entries;
- if ((uint64_t) sentries != entries)
- runtime_panicstring ("map size out of range");
- return __go_new_map (descriptor, sentries);
-}
diff --git a/libgo/runtime/go-new.c b/libgo/runtime/go-new.c
index 01bc2af312..da44074a5d 100644
--- a/libgo/runtime/go-new.c
+++ b/libgo/runtime/go-new.c
@@ -4,7 +4,6 @@
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
-#include "go-alloc.h"
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
diff --git a/libgo/runtime/go-nosys.c b/libgo/runtime/go-nosys.c
index 0a94de0523..be8fb3ef19 100644
--- a/libgo/runtime/go-nosys.c
+++ b/libgo/runtime/go-nosys.c
@@ -14,11 +14,16 @@
#include <errno.h>
#include <fcntl.h>
#include <math.h>
+#include <pthread.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
+#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@@ -448,3 +453,54 @@ log1pl (long double a)
return (long double) log1p ((double) a);
}
#endif
+
+#ifndef HAVE_STRERROR_R
+
+/* Some old systems do not have strerror_r. This is a replacement.
+ It assumes that nothing else in the program calls strerror. */
+
+static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
+
+int
+strerror_r (int errnum, char *buf, size_t buflen)
+{
+ int i;
+ char *errmsg;
+ size_t len;
+ int ret;
+
+ i = pthread_mutex_lock (&strerror_lock);
+ if (i != 0)
+ abort ();
+
+ errmsg = strerror (errnum);
+ len = strlen (errmsg);
+ if (len >= buflen)
+ ret = ERANGE;
+ else
+ {
+ memcpy (buf, errmsg, len + 1);
+ ret = 0;
+ }
+
+ i = pthread_mutex_unlock (&strerror_lock);
+ if (i != 0)
+ abort ();
+
+ return ret;
+}
+
+#endif /* ! HAVE_STRERROR_R */
+
+#ifndef HAVE_WAIT4
+
+/* Some old systems do not have wait4. This is a replacement that
+ uses waitpid. */
+
+pid_t
+wait4 (pid_t pid, int *status, int options, struct rusage *rusage __attribute__ ((unused)))
+{
+ return waitpid (pid, status, options);
+}
+
+#endif
diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c
deleted file mode 100644
index 77975c6e08..0000000000
--- a/libgo/runtime/go-panic.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* go-panic.c -- support for the go panic function.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "go-alloc.h"
-#include "go-defer.h"
-#include "go-panic.h"
-#include "interface.h"
-
-/* Print the panic stack. This is used when there is no recover. */
-
-static void
-__printpanics (struct __go_panic_stack *p)
-{
- if (p->__next != NULL)
- {
- __printpanics (p->__next);
- runtime_printf ("\t");
- }
- runtime_printf ("panic: ");
- runtime_printany (p->__arg);
- if (p->__was_recovered)
- runtime_printf (" [recovered]");
- runtime_printf ("\n");
-}
-
-/* This implements __go_panic which is used for the panic
- function. */
-
-void
-__go_panic (struct __go_empty_interface arg)
-{
- G *g;
- struct __go_panic_stack *n;
-
- g = runtime_g ();
-
- n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
- n->__arg = arg;
- n->__next = g->panic;
- g->panic = n;
-
- /* Run all the defer functions. */
-
- while (1)
- {
- struct __go_defer_stack *d;
- void (*pfn) (void *);
-
- d = g->defer;
- if (d == NULL)
- break;
-
- pfn = d->__pfn;
- d->__pfn = NULL;
-
- if (pfn != NULL)
- {
- (*pfn) (d->__arg);
-
- if (n->__was_recovered)
- {
- /* Some defer function called recover. That means that
- we should stop running this panic. */
-
- g->panic = n->__next;
- __go_free (n);
-
- /* Now unwind the stack by throwing an exception. The
- compiler has arranged to create exception handlers in
- each function which uses a defer statement. These
- exception handlers will check whether the entry on
- the top of the defer stack is from the current
- function. If it is, we have unwound the stack far
- enough. */
- __go_unwind_stack ();
-
- /* __go_unwind_stack should not return. */
- abort ();
- }
-
- /* Because we executed that defer function by a panic, and
- it did not call recover, we know that we are not
- returning from the calling function--we are panicing
- through it. */
- *d->__frame = 0;
- }
-
- g->defer = d->__next;
-
- /* This may be called by a cgo callback routine to defer the
- call to syscall.CgocallBackDone, in which case we will not
- have a memory context. Don't try to free anything in that
- case--the GC will release it later. */
- if (runtime_m () != NULL)
- runtime_freedefer (d);
- }
-
- /* The panic was not recovered. */
-
- runtime_startpanic ();
- __printpanics (g->panic);
- runtime_dopanic (0);
-}
diff --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h
deleted file mode 100644
index d29fe88b57..0000000000
--- a/libgo/runtime/go-panic.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* go-panic.h -- declare the go panic functions.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#ifndef LIBGO_GO_PANIC_H
-#define LIBGO_GO_PANIC_H
-
-#include "interface.h"
-
-struct String;
-struct __go_type_descriptor;
-struct __go_defer_stack;
-
-/* The stack of panic calls. */
-
-struct __go_panic_stack
-{
- /* The next entry in the stack. */
- struct __go_panic_stack *__next;
-
- /* The value associated with this panic. */
- struct __go_empty_interface __arg;
-
- /* Whether this panic has been recovered. */
- _Bool __was_recovered;
-
- /* Whether this panic was pushed on the stack because of an
- exception thrown in some other language. */
- _Bool __is_foreign;
-};
-
-extern void __go_panic (struct __go_empty_interface)
- __attribute__ ((noreturn));
-
-extern void __go_print_string (struct String);
-
-extern struct __go_empty_interface __go_recover (void);
-
-extern _Bool __go_can_recover (void *);
-
-extern void __go_makefunc_can_recover (void *retaddr);
-
-struct Location;
-extern void __go_makefunc_ffi_can_recover (struct Location *, int);
-
-extern void __go_makefunc_returning (void);
-
-extern void __go_unwind_stack (void);
-
-#endif /* !defined(LIBGO_GO_PANIC_H) */
diff --git a/libgo/runtime/go-print.c b/libgo/runtime/go-print.c
deleted file mode 100644
index 4c520de3ce..0000000000
--- a/libgo/runtime/go-print.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* go-print.c -- support for the go print statement.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "runtime.h"
-#include "array.h"
-#include "go-panic.h"
-#include "interface.h"
-
-/* This implements the various little functions which are called by
- the predeclared functions print/println/panic/panicln. */
-
-void
-__go_print_empty_interface (struct __go_empty_interface e)
-{
- runtime_printf ("(%p,%p)", e.__type_descriptor, e.__object);
-}
-
-void
-__go_print_interface (struct __go_interface i)
-{
- runtime_printf ("(%p,%p)", i.__methods, i.__object);
-}
-
-void
-__go_print_slice (struct __go_open_array val)
-{
- runtime_printf ("[%d/%d]", val.__count, val.__capacity);
- runtime_printpointer (val.__values);
-}
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
deleted file mode 100644
index fc66f61cab..0000000000
--- a/libgo/runtime/go-recover.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* go-recover.c -- support for the go recover function.
-
- 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. */
-
-#include "runtime.h"
-#include "interface.h"
-#include "go-panic.h"
-#include "go-defer.h"
-
-/* If the top of the defer stack can be recovered, then return it.
- Otherwise return NULL. */
-
-static struct __go_defer_stack *
-current_defer ()
-{
- G *g;
- struct __go_defer_stack *d;
-
- g = runtime_g ();
-
- d = g->defer;
- if (d == NULL)
- return NULL;
-
- /* The panic which would be recovered is the one on the top of the
- panic stack. We do not want to recover it if that panic was on
- the top of the panic stack when this function was deferred. */
- if (d->__panic == g->panic)
- return NULL;
-
- /* The deferred thunk will call _go_set_defer_retaddr. If this has
- not happened, then we have not been called via defer, and we can
- not recover. */
- if (d->__retaddr == NULL)
- return NULL;
-
- return d;
-}
-
-/* This is called by a thunk to see if the real function should be
- permitted to recover a panic value. Recovering a value is
- permitted if the thunk was called directly by defer. RETADDR is
- the return address of the function which is calling
- __go_can_recover--this is, the thunk. */
-
-_Bool
-__go_can_recover (void *retaddr)
-{
- struct __go_defer_stack *d;
- const char* ret;
- const char* dret;
- Location locs[16];
- const byte *name;
- intgo len;
- int n;
- int i;
- _Bool found_ffi_callback;
-
- d = current_defer ();
- if (d == NULL)
- return 0;
-
- ret = (const char *) __builtin_extract_return_addr (retaddr);
-
- dret = (const char *) d->__retaddr;
- if (ret <= dret && ret + 16 >= dret)
- return 1;
-
- /* On some systems, in some cases, the return address does not work
- reliably. See http://gcc.gnu.org/PR60406. If we are permitted
- to call recover, the call stack will look like this:
- __go_panic, __go_undefer, etc.
- thunk to call deferred function (calls __go_set_defer_retaddr)
- function that calls __go_can_recover (passing return address)
- __go_can_recover
- Calling runtime_callers will skip the thunks. So if our caller's
- caller starts with __go, then we are permitted to call
- recover. */
-
- if (runtime_callers (1, &locs[0], 2, false) < 2)
- return 0;
-
- name = locs[1].function.str;
- len = locs[1].function.len;
-
- /* Although locs[1].function is a Go string, we know it is
- NUL-terminated. */
- if (len > 4
- && __builtin_strchr ((const char *) name, '.') == NULL
- && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
- return 1;
-
- /* If we are called from __go_makefunc_can_recover, then we need to
- look one level higher. */
- if (locs[0].function.len > 0
- && __builtin_strcmp ((const char *) locs[0].function.str,
- "__go_makefunc_can_recover") == 0)
- {
- if (runtime_callers (3, &locs[0], 1, false) < 1)
- return 0;
- name = locs[0].function.str;
- len = locs[0].function.len;
- if (len > 4
- && __builtin_strchr ((const char *) name, '.') == NULL
- && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
- return 1;
- }
-
- /* If the function calling recover was created by reflect.MakeFunc,
- then __go_makefunc_can_recover or __go_makefunc_ffi_can_recover
- will have set the __makefunc_can_recover field. */
- if (!d->__makefunc_can_recover)
- return 0;
-
- /* We look up the stack, ignoring libffi functions and functions in
- the reflect package, until we find reflect.makeFuncStub or
- reflect.ffi_callback called by FFI functions. Then we check the
- caller of that function. */
-
- n = runtime_callers (2, &locs[0], sizeof locs / sizeof locs[0], false);
- found_ffi_callback = 0;
- for (i = 0; i < n; i++)
- {
- const byte *name;
-
- if (locs[i].function.len == 0)
- {
- /* No function name means this caller isn't Go code. Assume
- that this is libffi. */
- continue;
- }
-
- /* Ignore functions in libffi. */
- name = locs[i].function.str;
- if (__builtin_strncmp ((const char *) name, "ffi_", 4) == 0)
- continue;
-
- if (found_ffi_callback)
- break;
-
- if (__builtin_strcmp ((const char *) name, "reflect.ffi_callback") == 0)
- {
- found_ffi_callback = 1;
- continue;
- }
-
- if (__builtin_strcmp ((const char *) name, "reflect.makeFuncStub") == 0)
- {
- i++;
- break;
- }
-
- /* Ignore other functions in the reflect package. */
- if (__builtin_strncmp ((const char *) name, "reflect.", 8) == 0)
- continue;
-
- /* We should now be looking at the real caller. */
- break;
- }
-
- if (i < n && locs[i].function.len > 0)
- {
- name = locs[i].function.str;
- if (__builtin_strncmp ((const char *) name, "__go_", 4) == 0)
- return 1;
- }
-
- return 0;
-}
-
-/* This function is called when code is about to enter a function
- created by reflect.MakeFunc. It is called by the function stub
- used by MakeFunc. If the stub is permitted to call recover, then a
- real MakeFunc function is permitted to call recover. */
-
-void
-__go_makefunc_can_recover (void *retaddr)
-{
- struct __go_defer_stack *d;
-
- d = current_defer ();
- if (d == NULL)
- return;
-
- /* If we are already in a call stack of MakeFunc functions, there is
- nothing we can usefully check here. */
- if (d->__makefunc_can_recover)
- return;
-
- if (__go_can_recover (retaddr))
- d->__makefunc_can_recover = 1;
-}
-
-/* This function is called when code is about to enter a function
- created by the libffi version of reflect.MakeFunc. This function
- is passed the names of the callers of the libffi code that called
- the stub. It uses to decide whether it is permitted to call
- recover, and sets d->__makefunc_can_recover so that __go_recover
- can make the same decision. */
-
-void
-__go_makefunc_ffi_can_recover (struct Location *loc, int n)
-{
- struct __go_defer_stack *d;
- const byte *name;
- intgo len;
-
- d = current_defer ();
- if (d == NULL)
- return;
-
- /* If we are already in a call stack of MakeFunc functions, there is
- nothing we can usefully check here. */
- if (d->__makefunc_can_recover)
- return;
-
- /* LOC points to the caller of our caller. That will be a thunk.
- If its caller was a runtime function, then it was called directly
- by defer. */
-
- if (n < 2)
- return;
-
- name = (loc + 1)->function.str;
- len = (loc + 1)->function.len;
- if (len > 4
- && __builtin_strchr ((const char *) name, '.') == NULL
- && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
- d->__makefunc_can_recover = 1;
-}
-
-/* This function is called when code is about to exit a function
- created by reflect.MakeFunc. It is called by the function stub
- used by MakeFunc. It clears the __makefunc_can_recover field.
- It's OK to always clear this field, because __go_can_recover will
- only be called by a stub created for a function that calls recover.
- That stub will not call a function created by reflect.MakeFunc, so
- by the time we get here any caller higher up on the call stack no
- longer needs the information. */
-
-void
-__go_makefunc_returning (void)
-{
- struct __go_defer_stack *d;
-
- d = runtime_g ()->defer;
- if (d != NULL)
- d->__makefunc_can_recover = 0;
-}
-
-/* This is only called when it is valid for the caller to recover the
- value on top of the panic stack, if there is one. */
-
-struct __go_empty_interface
-__go_recover ()
-{
- G *g;
- struct __go_panic_stack *p;
-
- g = runtime_g ();
-
- if (g->panic == NULL || g->panic->__was_recovered)
- {
- struct __go_empty_interface ret;
-
- ret.__type_descriptor = NULL;
- ret.__object = NULL;
- return ret;
- }
- p = g->panic;
- p->__was_recovered = 1;
- return p->__arg;
-}
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index 2a14d6c6ad..6a9a7f35a1 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -9,10 +9,12 @@
#include <stdlib.h>
#include "runtime.h"
-#include "go-alloc.h"
#include "go-assert.h"
#include "go-type.h"
-#include "go-ffi.h"
+
+#ifdef USE_LIBFFI
+#include "ffi.h"
+#endif
#if defined(USE_LIBFFI) && FFI_GO_CLOSURES
@@ -197,6 +199,11 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
}
}
+/* The code that converts the Go type to an FFI type is written in Go,
+ so that it can allocate Go heap memory. */
+extern void ffiFuncToCIF(const struct __go_func_type*, _Bool, _Bool, ffi_cif*)
+ __asm__ ("runtime.ffiFuncToCIF");
+
/* Call a function. The type of the function is FUNC_TYPE, and the
closure is FUNC_VAL. PARAMS is an array of parameter addresses.
RESULTS is an array of result addresses.
@@ -218,7 +225,7 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
unsigned char *call_result;
__go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
- __go_func_to_cif (func_type, is_interface, is_method, &cif);
+ ffiFuncToCIF (func_type, is_interface, is_method, &cif);
call_result = (unsigned char *) malloc (go_results_size (func_type));
diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c
deleted file mode 100644
index 36f31025d3..0000000000
--- a/libgo/runtime/go-reflect-map.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* go-reflect-map.c -- map reflection support for Go.
-
- Copyright 2009, 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. */
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-type.h"
-#include "map.h"
-
-/* This file implements support for reflection on maps. These
- functions are called from reflect/value.go. */
-
-extern void *mapaccess (struct __go_map_type *, void *, void *)
- __asm__ (GOSYM_PREFIX "reflect.mapaccess");
-
-void *
-mapaccess (struct __go_map_type *mt, void *m, void *key)
-{
- struct __go_map *map = (struct __go_map *) m;
-
- __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
- if (map == NULL)
- return NULL;
- else
- return __go_map_index (map, key, 0);
-}
-
-extern void mapassign (struct __go_map_type *, void *, void *, void *)
- __asm__ (GOSYM_PREFIX "reflect.mapassign");
-
-void
-mapassign (struct __go_map_type *mt, void *m, void *key, void *val)
-{
- struct __go_map *map = (struct __go_map *) m;
- void *p;
-
- __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
- if (map == NULL)
- runtime_panicstring ("assignment to entry in nil map");
- p = __go_map_index (map, key, 1);
- __builtin_memcpy (p, val, mt->__val_type->__size);
-}
-
-extern void mapdelete (struct __go_map_type *, void *, void *)
- __asm__ (GOSYM_PREFIX "reflect.mapdelete");
-
-void
-mapdelete (struct __go_map_type *mt, void *m, void *key)
-{
- struct __go_map *map = (struct __go_map *) m;
-
- __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
- if (map == NULL)
- return;
- __go_map_delete (map, key);
-}
-
-extern int32_t maplen (void *) __asm__ (GOSYM_PREFIX "reflect.maplen");
-
-int32_t
-maplen (void *m)
-{
- struct __go_map *map = (struct __go_map *) m;
-
- if (map == NULL)
- return 0;
- return (int32_t) map->__element_count;
-}
-
-extern unsigned char *mapiterinit (struct __go_map_type *, void *)
- __asm__ (GOSYM_PREFIX "reflect.mapiterinit");
-
-unsigned char *
-mapiterinit (struct __go_map_type *mt, void *m)
-{
- struct __go_hash_iter *it;
-
- __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
- it = __go_alloc (sizeof (struct __go_hash_iter));
- __go_mapiterinit ((struct __go_map *) m, it);
- return (unsigned char *) it;
-}
-
-extern void mapiternext (void *) __asm__ (GOSYM_PREFIX "reflect.mapiternext");
-
-void
-mapiternext (void *it)
-{
- __go_mapiternext ((struct __go_hash_iter *) it);
-}
-
-extern void *mapiterkey (void *) __asm__ (GOSYM_PREFIX "reflect.mapiterkey");
-
-void *
-mapiterkey (void *ita)
-{
- struct __go_hash_iter *it = (struct __go_hash_iter *) ita;
- const struct __go_type_descriptor *key_descriptor;
- void *key;
-
- if (it->entry == NULL)
- return NULL;
-
- key_descriptor = it->map->__descriptor->__map_descriptor->__key_type;
- key = __go_alloc (key_descriptor->__size);
- __go_mapiter1 (it, key);
- return key;
-}
-
-/* Make a new map. We have to build our own map descriptor. */
-
-extern struct __go_map *makemap (const struct __go_map_type *)
- __asm__ (GOSYM_PREFIX "reflect.makemap");
-
-struct __go_map *
-makemap (const struct __go_map_type *t)
-{
- struct __go_map_descriptor *md;
- unsigned int o;
- const struct __go_type_descriptor *kt;
- const struct __go_type_descriptor *vt;
-
- md = (struct __go_map_descriptor *) __go_alloc (sizeof (*md));
- md->__map_descriptor = t;
- o = sizeof (void *);
- kt = t->__key_type;
- o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
- md->__key_offset = o;
- o += kt->__size;
- vt = t->__val_type;
- o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
- md->__val_offset = o;
- o += vt->__size;
- o = (o + sizeof (void *) - 1) & ~ (sizeof (void *) - 1);
- o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
- o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
- md->__entry_size = o;
-
- return __go_new_map (md, 0);
-}
-
-extern _Bool ismapkey (const struct __go_type_descriptor *)
- __asm__ (GOSYM_PREFIX "reflect.ismapkey");
-
-_Bool
-ismapkey (const struct __go_type_descriptor *typ)
-{
- return (typ != NULL
- && (void *) typ->__hashfn->fn != (void *) __go_type_hash_error);
-}
diff --git a/libgo/runtime/go-rune.c b/libgo/runtime/go-rune.c
deleted file mode 100644
index 4c65e21516..0000000000
--- a/libgo/runtime/go-rune.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* go-rune.c -- rune functions for Go.
-
- Copyright 2009, 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. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-string.h"
-
-/* Get a character from the UTF-8 string STR, of length LEN. Store
- the Unicode character, if any, in *RUNE. Return the number of
- characters used from STR. */
-
-int
-__go_get_rune (const unsigned char *str, size_t len, int32 *rune)
-{
- int c, c1, c2, c3, l;
-
- /* Default to the "replacement character". */
- *rune = 0xfffd;
-
- if (len <= 0)
- return 1;
-
- c = *str;
- if (c <= 0x7f)
- {
- *rune = c;
- return 1;
- }
-
- if (len <= 1)
- return 1;
-
- c1 = str[1];
- if ((c & 0xe0) == 0xc0
- && (c1 & 0xc0) == 0x80)
- {
- l = (((c & 0x1f) << 6) + (c1 & 0x3f));
- if (l <= 0x7f)
- return 1;
- *rune = l;
- return 2;
- }
-
- if (len <= 2)
- return 1;
-
- c2 = str[2];
- if ((c & 0xf0) == 0xe0
- && (c1 & 0xc0) == 0x80
- && (c2 & 0xc0) == 0x80)
- {
- l = (((c & 0xf) << 12)
- + ((c1 & 0x3f) << 6)
- + (c2 & 0x3f));
-
- if (l <= 0x7ff)
- return 1;
-
- if (l >= 0xd800 && l < 0xe000)
- {
- /* Invalid surrogate half; return replace character. */
- return 1;
- }
-
- *rune = l;
-
- return 3;
- }
-
- if (len <= 3)
- return 1;
-
- c3 = str[3];
- if ((c & 0xf8) == 0xf0
- && (c1 & 0xc0) == 0x80
- && (c2 & 0xc0) == 0x80
- && (c3 & 0xc0) == 0x80)
- {
- l = (((c & 0x7) << 18)
- + ((c1 & 0x3f) << 12)
- + ((c2 & 0x3f) << 6)
- + (c3 & 0x3f));
-
- if (l <= 0xffff || l > 0x10ffff)
- return 1;
-
- *rune = l;
- return 4;
- }
-
- /* Invalid encoding. Return 1 so that we advance. */
- return 1;
-}
diff --git a/libgo/runtime/go-setenv.c b/libgo/runtime/go-setenv.c
index a75d7c4127..81b1775d2c 100644
--- a/libgo/runtime/go-setenv.c
+++ b/libgo/runtime/go-setenv.c
@@ -9,10 +9,7 @@
#include <stddef.h>
#include <stdlib.h>
-#include "go-alloc.h"
#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
/* Set the C environment from Go. This is called by syscall.Setenv. */
@@ -25,7 +22,6 @@ setenv_c (String k, String v)
unsigned char *kn;
const byte *vs;
unsigned char *vn;
- intgo len;
ks = k.str;
if (ks == NULL)
@@ -39,25 +35,23 @@ setenv_c (String k, String v)
#ifdef HAVE_SETENV
- if (ks != NULL && ks[k.len] != 0)
+ if (ks[k.len] != 0)
{
- // Objects that are explicitly freed must be at least 16 bytes in size,
- // so that they are not allocated using tiny alloc.
- len = k.len + 1;
- if (len < TinySize)
- len = TinySize;
- kn = __go_alloc (len);
+ kn = malloc (k.len + 1);
+ if (kn == NULL)
+ runtime_throw ("out of malloc memory");
__builtin_memcpy (kn, ks, k.len);
+ kn[k.len] = '\0';
ks = kn;
}
- if (vs != NULL && vs[v.len] != 0)
+ if (vs[v.len] != 0)
{
- len = v.len + 1;
- if (len < TinySize)
- len = TinySize;
- vn = __go_alloc (len);
+ vn = malloc (v.len + 1);
+ if (vn == NULL)
+ runtime_throw ("out of malloc memory");
__builtin_memcpy (vn, vs, v.len);
+ vn[v.len] = '\0';
vs = vn;
}
@@ -66,19 +60,20 @@ setenv_c (String k, String v)
#else /* !defined(HAVE_SETENV) */
len = k.len + v.len + 2;
- if (len < TinySize)
- len = TinySize;
- kn = __go_alloc (len);
+ kn = malloc (len);
+ if (kn == NULL)
+ runtime_throw ("out of malloc memory");
__builtin_memcpy (kn, ks, k.len);
kn[k.len] = '=';
__builtin_memcpy (kn + k.len + 1, vs, v.len);
kn[k.len + v.len + 1] = '\0';
putenv ((char *) kn);
+ kn = NULL; /* putenv takes ownership of the string. */
#endif /* !defined(HAVE_SETENV) */
if (kn != NULL)
- __go_free (kn);
+ free (kn);
if (vn != NULL)
- __go_free (vn);
+ free (vn);
}
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
index a948c31cca..711f71e873 100644
--- a/libgo/runtime/go-signal.c
+++ b/libgo/runtime/go-signal.c
@@ -8,11 +8,9 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
+#include <ucontext.h>
#include "runtime.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "signal_unix.h"
#ifndef SA_RESTART
#define SA_RESTART 0
@@ -24,528 +22,270 @@ extern void __splitstack_getcontext(void *context[10]);
extern void __splitstack_setcontext(void *context[10]);
-#endif
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-/* Signal actions. This collects the sigtab tables for several
- different targets from the master library. SIGKILL and SIGSTOP are
- not listed, as we don't want to set signal handlers for them. */
-
-SigTab runtime_sigtab[] = {
-#ifdef SIGHUP
- { SIGHUP, N + K, NULL },
-#endif
-#ifdef SIGINT
- { SIGINT, N + K, NULL },
-#endif
-#ifdef SIGQUIT
- { SIGQUIT, N + T, NULL },
-#endif
-#ifdef SIGILL
- { SIGILL, T, NULL },
-#endif
-#ifdef SIGTRAP
- { SIGTRAP, T, NULL },
-#endif
-#ifdef SIGABRT
- { SIGABRT, N + T, NULL },
-#endif
-#ifdef SIGBUS
- { SIGBUS, P, NULL },
-#endif
-#ifdef SIGFPE
- { SIGFPE, P, NULL },
-#endif
-#ifdef SIGUSR1
- { SIGUSR1, N, NULL },
-#endif
-#ifdef SIGSEGV
- { SIGSEGV, P, NULL },
-#endif
-#ifdef SIGUSR2
- { SIGUSR2, N, NULL },
-#endif
-#ifdef SIGPIPE
- { SIGPIPE, N, NULL },
-#endif
-#ifdef SIGALRM
- { SIGALRM, N, NULL },
-#endif
-#ifdef SIGTERM
- { SIGTERM, N + K, NULL },
-#endif
-#ifdef SIGSTKFLT
- { SIGSTKFLT, T, NULL },
-#endif
-#ifdef SIGCHLD
- { SIGCHLD, N, NULL },
-#endif
-#ifdef SIGCONT
- { SIGCONT, N + D, NULL },
-#endif
-#ifdef SIGTSTP
- { SIGTSTP, N + D, NULL },
-#endif
-#ifdef SIGTTIN
- { SIGTTIN, N + D, NULL },
-#endif
-#ifdef SIGTTOU
- { SIGTTOU, N + D, NULL },
-#endif
-#ifdef SIGURG
- { SIGURG, N, NULL },
-#endif
-#ifdef SIGXCPU
- { SIGXCPU, N, NULL },
-#endif
-#ifdef SIGXFSZ
- { SIGXFSZ, N, NULL },
-#endif
-#ifdef SIGVTALRM
- { SIGVTALRM, N, NULL },
-#endif
-#ifdef SIGPROF
- { SIGPROF, N, NULL },
-#endif
-#ifdef SIGWINCH
- { SIGWINCH, N, NULL },
-#endif
-#ifdef SIGIO
- { SIGIO, N, NULL },
-#endif
-#ifdef SIGPWR
- { SIGPWR, N, NULL },
-#endif
-#ifdef SIGSYS
- { SIGSYS, N, NULL },
-#endif
-#ifdef SIGEMT
- { SIGEMT, T, NULL },
-#endif
-#ifdef SIGINFO
- { SIGINFO, N, NULL },
-#endif
-#ifdef SIGTHR
- { SIGTHR, N, NULL },
-#endif
- { -1, 0, NULL }
-};
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
-
-/* Handle a signal, for cases where we don't panic. We can split the
- stack here. */
-
-void
-runtime_sighandler (int sig, Siginfo *info,
- void *context __attribute__ ((unused)), G *gp)
-{
- M *m;
- int i;
-
- m = runtime_m ();
-
-#ifdef SIGPROF
- if (sig == SIGPROF)
- {
- if (m != NULL && gp != m->g0 && gp != m->gsignal)
- runtime_sigprof ();
- return;
- }
-#endif
-
- if (m == NULL)
- {
- runtime_badsignal (sig);
- return;
- }
-
- for (i = 0; runtime_sigtab[i].sig != -1; ++i)
- {
- SigTab *t;
- bool notify, crash;
-
- t = &runtime_sigtab[i];
+extern void *__splitstack_find_context(void *context[10], size_t *,
+ void **, void **, void **);
- if (t->sig != sig)
- continue;
-
- notify = false;
-#ifdef SA_SIGINFO
- notify = info != NULL && info->si_code == SI_USER;
#endif
- if (notify || (t->flags & SigNotify) != 0)
- {
- if (__go_sigsend (sig))
- return;
- }
- if ((t->flags & SigKill) != 0)
- runtime_exit (2);
- if ((t->flags & SigThrow) == 0)
- return;
-
- runtime_startpanic ();
- {
- const char *name = NULL;
+// The rest of the signal handler, written in Go.
-#ifdef HAVE_STRSIGNAL
- name = strsignal (sig);
-#endif
+extern void sigtrampgo(uint32, siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.sigtrampgo");
- if (name == NULL)
- runtime_printf ("Signal %d\n", sig);
- else
- runtime_printf ("%s\n", name);
- }
+// The Go signal handler, written in C. This should be running on the
+// alternate signal stack. This is responsible for setting up the
+// split stack context so that stack guard checks will work as
+// expected.
- if (m->lockedg != NULL && m->ncgo > 0 && gp == m->g0)
- {
- runtime_printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
+void sigtramp(int, siginfo_t *, void *)
+ __attribute__ ((no_split_stack));
- runtime_printf ("\n");
+void sigtramp(int, siginfo_t *, void *)
+ __asm__ (GOSYM_PREFIX "runtime.sigtramp");
- if (runtime_gotraceback (&crash))
- {
- G *g;
-
- g = runtime_g ();
- runtime_traceback ();
- runtime_tracebackothers (g);
-
- /* The gc library calls runtime_dumpregs here, and provides
- a function that prints the registers saved in context in
- a readable form. */
- }
-
- if (crash)
- runtime_crash ();
-
- runtime_exit (2);
- }
-
- __builtin_unreachable ();
-}
+#ifndef USING_SPLIT_STACK
-/* The start of handling a signal which panics. */
+// When not using split stacks, there are no stack checks, and there
+// is nothing special for this function to do.
-static void
-sig_panic_leadin (G *gp)
+void
+sigtramp(int sig, siginfo_t *info, void *context)
{
- int i;
- sigset_t clear;
-
- if (!runtime_canpanic (gp))
- runtime_throw ("unexpected signal during runtime execution");
-
- /* The signal handler blocked signals; unblock them. */
- i = sigfillset (&clear);
- __go_assert (i == 0);
- i = pthread_sigmask (SIG_UNBLOCK, &clear, NULL);
- __go_assert (i == 0);
+ sigtrampgo(sig, info, context);
}
-#ifdef SA_SIGINFO
-
-/* Signal dispatch for signals which panic, on systems which support
- SA_SIGINFO. This is called on the thread stack, and as such it is
- permitted to split the stack. */
+#else // USING_SPLIT_STACK
-static void
-sig_panic_info_handler (int sig, Siginfo *info, void *context)
+void
+sigtramp(int sig, siginfo_t *info, void *context)
{
- G *g;
-
- g = runtime_g ();
- if (g == NULL || info->si_code == SI_USER)
- {
- runtime_sighandler (sig, info, context, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = info->si_code;
- g->sigcode1 = (uintptr_t) info->si_addr;
-
- /* It would be nice to set g->sigpc here as the gc library does, but
- I don't know how to get it portably. */
-
- sig_panic_leadin (g);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- if ((info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
- || g->paniconfault)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
-
-#ifdef SIGSEGV
- case SIGSEGV:
- if (((info->si_code == 0
- || info->si_code == SEGV_MAPERR
- || info->si_code == SEGV_ACCERR)
- && (uintptr_t) info->si_addr < 0x1000)
- || g->paniconfault)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
+ G *gp;
+ void *stack_context[10];
+ void *stack;
+ size_t stack_size;
+ void *next_segment;
+ void *next_sp;
+ void *initial_sp;
+ uintptr sp;
+ stack_t st;
+ uintptr stsp;
+
+ gp = runtime_g();
+
+ if (gp == nil) {
+ // Let the Go code handle this case.
+ // It should only call nosplit functions in this case.
+ sigtrampgo(sig, info, context);
+ return;
+ }
-#ifdef SIGFPE
- case SIGFPE:
- switch (info->si_code)
- {
- case FPE_INTDIV:
- runtime_panicstring ("integer divide by zero");
- case FPE_INTOVF:
- runtime_panicstring ("integer overflow");
+ // If this signal is one for which we will panic, we are not
+ // on the alternate signal stack. It's OK to call split-stack
+ // functions here.
+ if (sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV) {
+ sigtrampgo(sig, info, context);
+ return;
}
- runtime_panicstring ("floating point error");
-#endif
- }
- /* All signals with SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
-}
+ // We are running on the alternate signal stack.
+
+ __splitstack_getcontext(&stack_context[0]);
+
+ stack = __splitstack_find_context(&gp->m->gsignal->stackcontext[0],
+ &stack_size, &next_segment,
+ &next_sp, &initial_sp);
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp = (uintptr)(&stack_size);
+ if (sp < (uintptr)(stack) || sp >= (uintptr)(stack) + stack_size) {
+ sigaltstack(nil, &st);
+ if ((st.ss_flags & SS_DISABLE) != 0) {
+ runtime_printf("signal %d received on thread with no signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code disabled sigaltstack");
+ }
+
+ stsp = (uintptr)(st.ss_sp);
+ if (sp < stsp || sp >= stsp + st.ss_size) {
+ runtime_printf("signal %d received but handler not on signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code set up signal handler without SA_ONSTACK flag");
+ }
+
+ // Unfortunately __splitstack_find_context will return NULL
+ // when it is called on a context that has never been used.
+ // There isn't much we can do but assume all is well.
+ if (stack != NULL) {
+ // Here the gc runtime adjusts the gsignal
+ // stack guard to match the values returned by
+ // sigaltstack. Unfortunately we have no way
+ // to do that.
+ runtime_printf("signal %d received on unknown signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code changed signal stack");
+ }
+ }
-#else /* !defined (SA_SIGINFO) */
+ // Set the split stack context so that the stack guards are
+ // checked correctly.
-static void
-sig_panic_handler (int sig)
-{
- G *g;
-
- g = runtime_g ();
- if (g == NULL)
- {
- runtime_sighandler (sig, NULL, NULL, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = 0;
- g->sigcode1 = 0;
-
- sig_panic_leadin (g);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+ __splitstack_setcontext(&gp->m->gsignal->stackcontext[0]);
-#ifdef SIGSEGV
- case SIGSEGV:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+ sigtrampgo(sig, info, context);
-#ifdef SIGFPE
- case SIGFPE:
- runtime_panicstring ("integer divide by zero or floating point error");
-#endif
- }
+ // We are going to return back to the signal trampoline and
+ // then to whatever we were doing before we got the signal.
+ // Restore the split stack context so that stack guards are
+ // checked correctly.
- /* All signals with SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
+ __splitstack_setcontext(&stack_context[0]);
}
-#endif /* !defined (SA_SIGINFO) */
+#endif // USING_SPLIT_STACK
-/* A signal handler used for signals which are not going to panic.
- This is called on the alternate signal stack so it may not split
- the stack. */
+// C function to return the address of the sigtramp function.
+uintptr getSigtramp(void) __asm__ (GOSYM_PREFIX "runtime.getSigtramp");
-static void
-sig_tramp_info (int, Siginfo *, void *) __attribute__ ((no_split_stack));
-
-static void
-sig_tramp_info (int sig, Siginfo *info, void *context)
+uintptr
+getSigtramp()
{
- G *gp;
- M *mp;
-#ifdef USING_SPLIT_STACK
- void *stack_context[10];
-#endif
-
- /* We are now running on the stack registered via sigaltstack.
- (Actually there is a small span of time between runtime_siginit
- and sigaltstack when the program starts.) */
- gp = runtime_g ();
- mp = runtime_m ();
-
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_getcontext (&stack_context[0]);
-#endif
- }
-
- if (gp != NULL && mp->gsignal != NULL)
- {
- /* We are running on the signal stack. Set the split stack
- context so that the stack guards are checked correctly. */
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&mp->gsignal->stack_context[0]);
-#endif
- }
-
- runtime_sighandler (sig, info, context, gp);
-
- /* We are going to return back to the signal trampoline and then to
- whatever we were doing before we got the signal. Restore the
- split stack context so that stack guards are checked
- correctly. */
-
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&stack_context[0]);
-#endif
- }
+ return (uintptr)(void*)sigtramp;
}
-#ifndef SA_SIGINFO
+// C code to manage the sigaction sa_sigaction field, which is
+// typically a union and so hard for mksysinfo.sh to handle.
-static void sig_tramp (int sig) __attribute__ ((no_split_stack));
+uintptr getSigactionHandler(struct sigaction*)
+ __attribute__ ((no_split_stack));
-static void
-sig_tramp (int sig)
+uintptr getSigactionHandler(struct sigaction*)
+ __asm__ (GOSYM_PREFIX "runtime.getSigactionHandler");
+
+uintptr
+getSigactionHandler(struct sigaction* sa)
{
- sig_tramp_info (sig, NULL, NULL);
+ return (uintptr)(sa->sa_sigaction);
}
-#endif
+void setSigactionHandler(struct sigaction*, uintptr)
+ __attribute__ ((no_split_stack));
+
+void setSigactionHandler(struct sigaction*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.setSigactionHandler");
void
-runtime_setsig (int32 i, GoSighandler *fn, bool restart)
+setSigactionHandler(struct sigaction* sa, uintptr handler)
{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
-
- r = sigfillset (&sa.sa_mask);
- __go_assert (r == 0);
-
- t = &runtime_sigtab[i];
-
- if ((t->flags & SigPanic) == 0)
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp_info;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = SA_ONSTACK;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp;
- sa.sa_handler = (void *) fn;
-#endif
- }
- else
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_info_handler;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = 0;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_handler;
- sa.sa_handler = (void *) fn;
-#endif
- }
-
- if (restart)
- sa.sa_flags |= SA_RESTART;
-
- if (sigaction (t->sig, &sa, NULL) != 0)
- __go_assert (0);
+ sa->sa_sigaction = (void*)(handler);
}
-GoSighandler*
-runtime_getsig (int32 i)
-{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
-
- r = sigemptyset (&sa.sa_mask);
- __go_assert (r == 0);
+// C code to fetch values from the siginfo_t and ucontext_t pointers
+// passed to a signal handler.
- t = &runtime_sigtab[i];
-
- if (sigaction (t->sig, NULL, &sa) != 0)
- runtime_throw ("sigaction read failure");
-
- if ((void *) sa.sa_handler == sig_tramp_info)
- return runtime_sighandler;
-#ifdef SA_SIGINFO
- if ((void *) sa.sa_handler == sig_panic_info_handler)
- return runtime_sighandler;
-#else
- if ((void *) sa.sa_handler == sig_tramp
- || (void *) sa.sa_handler == sig_panic_handler)
- return runtime_sighandler;
-#endif
-
- return (void *) sa.sa_handler;
-}
-
-/* Used by the os package to raise SIGPIPE. */
+struct getSiginfoRet {
+ uintptr sigaddr;
+ uintptr sigpc;
+};
-void os_sigpipe (void) __asm__ (GOSYM_PREFIX "os.sigpipe");
+struct getSiginfoRet getSiginfo(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.getSiginfo");
-void
-os_sigpipe (void)
+struct getSiginfoRet
+getSiginfo(siginfo_t *info, void *context __attribute__((unused)))
{
- struct sigaction sa;
- int i;
+ struct getSiginfoRet ret;
+ Location loc[1];
+ int32 n;
+
+ if (info == nil) {
+ ret.sigaddr = 0;
+ } else {
+ ret.sigaddr = (uintptr)(info->si_addr);
+ }
+ ret.sigpc = 0;
- if (__go_sigsend (SIGPIPE))
- return;
+ // There doesn't seem to be a portable way to get the PC.
+ // Use unportable code to pull it from context, and if that fails
+ // try a stack backtrace across the signal handler.
- memset (&sa, 0, sizeof sa);
+#ifdef __x86_64__
+ #ifdef __linux__
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_RIP];
+ #endif
+#endif
+#ifdef __i386__
+ #ifdef __linux__
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_EIP];
+ #endif
+#endif
- sa.sa_handler = SIG_DFL;
+ if (ret.sigpc == 0) {
+ // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler.
+ n = runtime_callers(5, &loc[0], 1, false);
+ if (n > 0) {
+ ret.sigpc = loc[0].pc;
+ }
+ }
- i = sigemptyset (&sa.sa_mask);
- __go_assert (i == 0);
+ return ret;
+}
- if (sigaction (SIGPIPE, &sa, NULL) != 0)
- abort ();
+// Dump registers when crashing in a signal.
+// There is no portable way to write this,
+// so we just have some CPU/OS specific implementations.
- raise (SIGPIPE);
-}
+void dumpregs(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.dumpregs");
void
-runtime_setprof(bool on)
+dumpregs(siginfo_t *info __attribute__((unused)), void *context __attribute__((unused)))
{
- USED(on);
+#ifdef __x86_64__
+ #ifdef __linux__
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("rax %X\n", m->gregs[REG_RAX]);
+ runtime_printf("rbx %X\n", m->gregs[REG_RBX]);
+ runtime_printf("rcx %X\n", m->gregs[REG_RCX]);
+ runtime_printf("rdx %X\n", m->gregs[REG_RDX]);
+ runtime_printf("rdi %X\n", m->gregs[REG_RDI]);
+ runtime_printf("rsi %X\n", m->gregs[REG_RSI]);
+ runtime_printf("rbp %X\n", m->gregs[REG_RBP]);
+ runtime_printf("rsp %X\n", m->gregs[REG_RSP]);
+ runtime_printf("r8 %X\n", m->gregs[REG_R8]);
+ runtime_printf("r9 %X\n", m->gregs[REG_R9]);
+ runtime_printf("r10 %X\n", m->gregs[REG_R10]);
+ runtime_printf("r11 %X\n", m->gregs[REG_R11]);
+ runtime_printf("r12 %X\n", m->gregs[REG_R12]);
+ runtime_printf("r13 %X\n", m->gregs[REG_R13]);
+ runtime_printf("r14 %X\n", m->gregs[REG_R14]);
+ runtime_printf("r15 %X\n", m->gregs[REG_R15]);
+ runtime_printf("rip %X\n", m->gregs[REG_RIP]);
+ runtime_printf("rflags %X\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %X\n", m->gregs[REG_CSGSFS] & 0xffff);
+ runtime_printf("fs %X\n", (m->gregs[REG_CSGSFS] >> 16) & 0xffff);
+ runtime_printf("gs %X\n", (m->gregs[REG_CSGSFS] >> 32) & 0xffff);
+ }
+ #endif
+#endif
+
+#ifdef __i386__
+ #ifdef __linux__
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("eax %X\n", m->gregs[REG_EAX]);
+ runtime_printf("ebx %X\n", m->gregs[REG_EBX]);
+ runtime_printf("ecx %X\n", m->gregs[REG_ECX]);
+ runtime_printf("edx %X\n", m->gregs[REG_EDX]);
+ runtime_printf("edi %X\n", m->gregs[REG_EDI]);
+ runtime_printf("esi %X\n", m->gregs[REG_ESI]);
+ runtime_printf("ebp %X\n", m->gregs[REG_EBP]);
+ runtime_printf("esp %X\n", m->gregs[REG_ESP]);
+ runtime_printf("eip %X\n", m->gregs[REG_EIP]);
+ runtime_printf("eflags %X\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %X\n", m->gregs[REG_CS]);
+ runtime_printf("fs %X\n", m->gregs[REG_FS]);
+ runtime_printf("gs %X\n", m->gregs[REG_GS]);
+ }
+ #endif
+#endif
}
diff --git a/libgo/runtime/go-strcmp.c b/libgo/runtime/go-strcmp.c
deleted file mode 100644
index bcc270bf8a..0000000000
--- a/libgo/runtime/go-strcmp.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* go-strcmp.c -- the go string comparison function.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-
-intgo
-__go_strcmp(String s1, String s2)
-{
- int i;
-
- i = __builtin_memcmp(s1.str, s2.str,
- (s1.len < s2.len ? s1.len : s2.len));
- if (i != 0)
- return i;
-
- if (s1.len < s2.len)
- return -1;
- else if (s1.len > s2.len)
- return 1;
- else
- return 0;
-}
diff --git a/libgo/runtime/go-string-to-byte-array.c b/libgo/runtime/go-string-to-byte-array.c
deleted file mode 100644
index 61591eb975..0000000000
--- a/libgo/runtime/go-string-to-byte-array.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* go-string-to-byte-array.c -- convert a string to an array of bytes in Go.
-
- 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. */
-
-#include "runtime.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-struct __go_open_array
-__go_string_to_byte_array (String str)
-{
- uintptr cap;
- unsigned char *data;
- struct __go_open_array ret;
-
- cap = runtime_roundupsize (str.len);
- data = (unsigned char *) runtime_mallocgc (cap, 0, FlagNoScan | FlagNoZero);
- __builtin_memcpy (data, str.str, str.len);
- if (cap != (uintptr) str.len)
- __builtin_memset (data + str.len, 0, cap - (uintptr) str.len);
- ret.__values = (void *) data;
- ret.__count = str.len;
- ret.__capacity = str.len;
- return ret;
-}
diff --git a/libgo/runtime/go-string-to-int-array.c b/libgo/runtime/go-string-to-int-array.c
deleted file mode 100644
index 5546889131..0000000000
--- a/libgo/runtime/go-string-to-int-array.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* go-string-to-int-array.c -- convert a string to an array of ints in Go.
-
- 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. */
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-string.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-struct __go_open_array
-__go_string_to_int_array (String str)
-{
- size_t c;
- const unsigned char *p;
- const unsigned char *pend;
- uintptr mem;
- uint32_t *data;
- uint32_t *pd;
- struct __go_open_array ret;
-
- c = 0;
- p = str.str;
- pend = p + str.len;
- while (p < pend)
- {
- int rune;
-
- ++c;
- p += __go_get_rune (p, pend - p, &rune);
- }
-
- if (c > MaxMem / sizeof (uint32_t))
- runtime_throw ("out of memory");
-
- mem = runtime_roundupsize (c * sizeof (uint32_t));
- data = (uint32_t *) runtime_mallocgc (mem, 0, FlagNoScan | FlagNoZero);
- p = str.str;
- pd = data;
- while (p < pend)
- {
- int rune;
-
- p += __go_get_rune (p, pend - p, &rune);
- *pd++ = rune;
- }
- if (mem > (uintptr) c * sizeof (uint32_t))
- __builtin_memset (data + c, 0, mem - (uintptr) c * sizeof (uint32_t));
- ret.__values = (void *) data;
- ret.__count = c;
- ret.__capacity = (intgo) (mem / sizeof (uint32_t));
- return ret;
-}
diff --git a/libgo/runtime/go-strplus.c b/libgo/runtime/go-strplus.c
deleted file mode 100644
index 13915e3e67..0000000000
--- a/libgo/runtime/go-strplus.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* go-strplus.c -- the go string append function.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-String
-__go_string_plus (String s1, String s2)
-{
- int len;
- byte *retdata;
- String ret;
-
- if (s1.len == 0)
- return s2;
- else if (s2.len == 0)
- return s1;
-
- len = s1.len + s2.len;
- retdata = runtime_mallocgc (len, 0, FlagNoScan | FlagNoZero);
- __builtin_memcpy (retdata, s1.str, s1.len);
- __builtin_memcpy (retdata + s1.len, s2.str, s2.len);
- ret.str = retdata;
- ret.len = len;
- return ret;
-}
diff --git a/libgo/runtime/go-strslice.c b/libgo/runtime/go-strslice.c
index 21e1bc031d..c9f196bc9c 100644
--- a/libgo/runtime/go-strslice.c
+++ b/libgo/runtime/go-strslice.c
@@ -4,10 +4,7 @@
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
-#include "go-panic.h"
#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
String
__go_string_slice (String s, intgo start, intgo end)
diff --git a/libgo/runtime/go-traceback.c b/libgo/runtime/go-traceback.c
deleted file mode 100644
index 7b33cca868..0000000000
--- a/libgo/runtime/go-traceback.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* go-traceback.c -- stack backtrace for Go.
-
- Copyright 2012 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "config.h"
-
-#include "runtime.h"
-
-/* Print a stack trace for the current goroutine. */
-
-void
-runtime_traceback ()
-{
- Location locbuf[100];
- int32 c;
-
- c = runtime_callers (1, locbuf, nelem (locbuf), false);
- runtime_printtrace (locbuf, c, true);
-}
-
-void
-runtime_printtrace (Location *locbuf, int32 c, bool current)
-{
- int32 i;
-
- for (i = 0; i < c; ++i)
- {
- if (runtime_showframe (locbuf[i].function, current))
- {
- runtime_printf ("%S\n", locbuf[i].function);
- runtime_printf ("\t%S:%D\n", locbuf[i].filename,
- (int64) locbuf[i].lineno);
- }
- }
-}
diff --git a/libgo/runtime/go-trampoline.c b/libgo/runtime/go-trampoline.c
deleted file mode 100644
index 17f73d4f56..0000000000
--- a/libgo/runtime/go-trampoline.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* go-trampoline.c -- allocate a trampoline for a nested function.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "config.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <unistd.h>
-
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "go-assert.h"
-
-/* Trampolines need to run in memory that is both writable and
- executable. In order to implement them, we grab a page of memory
- and mprotect it. We fill in the page with trampolines as they are
- required. When we run out of space, we drop the pointer to the
- page and allocate a new one. The page will be freed by the garbage
- collector when there are no more variables of type func pointing to
- it. */
-
-/* A lock to control access to the page of closures. */
-
-static Lock trampoline_lock;
-
-/* The page of closures. */
-
-static unsigned char *trampoline_page;
-
-/* The size of trampoline_page. */
-
-static uintptr_t trampoline_page_size;
-
-/* The number of bytes we have used on trampoline_page. */
-
-static uintptr_t trampoline_page_used;
-
-/* Allocate a trampoline of SIZE bytes that will use the closure in
- CLOSURE. */
-
-void *
-__go_allocate_trampoline (uintptr_t size, void *closure)
-{
- uintptr_t ptr_size;
- uintptr_t full_size;
- unsigned char *ret;
-
- /* Because the garbage collector only looks at aligned addresses, we
- need to store the closure at an aligned address to ensure that it
- sees it. */
- ptr_size = sizeof (void *);
- full_size = (((size + ptr_size - 1) / ptr_size) * ptr_size);
- full_size += ptr_size;
-
- runtime_lock (&trampoline_lock);
-
- if (full_size < trampoline_page_size - trampoline_page_used)
- trampoline_page = NULL;
-
- if (trampoline_page == NULL)
- {
- uintptr_t page_size;
- unsigned char *page;
-
- page_size = getpagesize ();
- __go_assert (page_size >= full_size);
- page = (unsigned char *) runtime_mallocgc (2 * page_size - 1, 0, 0, 0);
- page = (unsigned char *) (((uintptr_t) page + page_size - 1)
- & ~ (page_size - 1));
-
-#ifdef HAVE_SYS_MMAN_H
- {
- int i;
-
- i = mprotect (page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
- __go_assert (i == 0);
- }
-#endif
-
- trampoline_page = page;
- trampoline_page_size = page_size;
- trampoline_page_used = 0;
- }
-
- ret = trampoline_page + trampoline_page_used;
- trampoline_page_used += full_size;
-
- runtime_unlock (&trampoline_lock);
-
- __builtin_memcpy (ret + full_size - ptr_size, &closure, ptr_size);
-
- return (void *) ret;
-}
-
-/* Scan the trampoline page when running the garbage collector. This
- just makes sure that the garbage collector sees the pointer in
- trampoline_page, so that the page itself is not freed if there are
- no other references to it. */
-
-void
-runtime_trampoline_scan (void (*addroot) (Obj))
-{
- if (trampoline_page != NULL)
- addroot ((Obj){(byte *) &trampoline_page, sizeof trampoline_page, 0});
-}
diff --git a/libgo/runtime/go-type-complex.c b/libgo/runtime/go-type-complex.c
deleted file mode 100644
index 585984e9fe..0000000000
--- a/libgo/runtime/go-type-complex.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* go-type-complex.c -- hash and equality complex functions.
-
- Copyright 2012 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <complex.h>
-#include <math.h>
-#include <stdint.h>
-#include <string.h>
-#include "runtime.h"
-#include "go-type.h"
-
-/* Hash function for float types. */
-
-uintptr_t
-__go_type_hash_complex (const void *vkey, uintptr_t key_size)
-{
- if (key_size == 8)
- {
- const complex float *cfp;
- complex float cf;
- float cfr;
- float cfi;
- uint64_t fi;
-
- cfp = (const complex float *) vkey;
- cf = *cfp;
-
- cfr = crealf (cf);
- cfi = cimagf (cf);
-
- if (isinf (cfr) || isinf (cfi))
- return 0;
-
- /* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
- random so that not all NaNs wind up in the same place. */
- if (isnan (cfr) || isnan (cfi))
- return runtime_fastrand1 ();
-
- /* Avoid negative zero. */
- if (cfr == 0 && cfi == 0)
- return 0;
- else if (cfr == 0)
- cf = cfi * I;
- else if (cfi == 0)
- cf = cfr;
-
- memcpy (&fi, &cf, 8);
- return (uintptr_t) cfi;
- }
- else if (key_size == 16)
- {
- const complex double *cdp;
- complex double cd;
- double cdr;
- double cdi;
- uint64_t di[2];
-
- cdp = (const complex double *) vkey;
- cd = *cdp;
-
- cdr = creal (cd);
- cdi = cimag (cd);
-
- if (isinf (cdr) || isinf (cdi))
- return 0;
-
- if (isnan (cdr) || isnan (cdi))
- return runtime_fastrand1 ();
-
- /* Avoid negative zero. */
- if (cdr == 0 && cdi == 0)
- return 0;
- else if (cdr == 0)
- cd = cdi * I;
- else if (cdi == 0)
- cd = cdr;
-
- memcpy (&di, &cd, 16);
- return di[0] ^ di[1];
- }
- else
- runtime_throw ("__go_type_hash_complex: invalid complex size");
-}
-
-const FuncVal __go_type_hash_complex_descriptor =
- { (void *) __go_type_hash_complex };
-
-/* Equality function for complex types. */
-
-_Bool
-__go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
-{
- if (key_size == 8)
- {
- const complex float *cfp1;
- const complex float *cfp2;
-
- cfp1 = (const complex float *) vk1;
- cfp2 = (const complex float *) vk2;
-
- return *cfp1 == *cfp2;
- }
- else if (key_size == 16)
- {
- const complex double *cdp1;
- const complex double *cdp2;
-
- cdp1 = (const complex double *) vk1;
- cdp2 = (const complex double *) vk2;
-
- return *cdp1 == *cdp2;
- }
- else
- runtime_throw ("__go_type_equal_complex: invalid complex size");
-}
-
-const FuncVal __go_type_equal_complex_descriptor =
- { (void *) __go_type_equal_complex };
diff --git a/libgo/runtime/go-type-eface.c b/libgo/runtime/go-type-eface.c
deleted file mode 100644
index 315c30efb7..0000000000
--- a/libgo/runtime/go-type-eface.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* go-type-eface.c -- hash and equality empty interface functions.
-
- 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. */
-
-#include "runtime.h"
-#include "interface.h"
-#include "go-type.h"
-
-/* A hash function for an empty interface. */
-
-uintptr_t
-__go_type_hash_empty_interface (const void *vval,
- uintptr_t key_size __attribute__ ((unused)))
-{
- const struct __go_empty_interface *val;
- const struct __go_type_descriptor *descriptor;
- uintptr_t size;
-
- val = (const struct __go_empty_interface *) vval;
- descriptor = val->__type_descriptor;
- if (descriptor == NULL)
- return 0;
- size = descriptor->__size;
- if (__go_is_pointer_type (descriptor))
- return __go_call_hashfn (descriptor->__hashfn, &val->__object, size);
- else
- return __go_call_hashfn (descriptor->__hashfn, val->__object, size);
-}
-
-const FuncVal __go_type_hash_empty_interface_descriptor =
- { (void *) __go_type_hash_empty_interface };
-
-/* An equality function for an empty interface. */
-
-_Bool
-__go_type_equal_empty_interface (const void *vv1, const void *vv2,
- uintptr_t key_size __attribute__ ((unused)))
-{
- const struct __go_empty_interface *v1;
- const struct __go_empty_interface *v2;
- const struct __go_type_descriptor* v1_descriptor;
- const struct __go_type_descriptor* v2_descriptor;
-
- v1 = (const struct __go_empty_interface *) vv1;
- v2 = (const struct __go_empty_interface *) vv2;
- v1_descriptor = v1->__type_descriptor;
- v2_descriptor = v2->__type_descriptor;
- if (v1_descriptor == NULL || v2_descriptor == NULL)
- return v1_descriptor == v2_descriptor;
- if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
- return 0;
- if (__go_is_pointer_type (v1_descriptor))
- return v1->__object == v2->__object;
- else
- return __go_call_equalfn (v1_descriptor->__equalfn, v1->__object,
- v2->__object, v1_descriptor->__size);
-}
-
-const FuncVal __go_type_equal_empty_interface_descriptor =
- { (void *) __go_type_equal_empty_interface };
diff --git a/libgo/runtime/go-type-error.c b/libgo/runtime/go-type-error.c
deleted file mode 100644
index 8881a86f6e..0000000000
--- a/libgo/runtime/go-type-error.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* go-type-error.c -- invalid hash and equality functions.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-type.h"
-
-/* A hash function used for a type which does not support hash
- functions. */
-
-uintptr_t
-__go_type_hash_error (const void *val __attribute__ ((unused)),
- uintptr_t key_size __attribute__ ((unused)))
-{
- runtime_panicstring ("hash of unhashable type");
-}
-
-const FuncVal __go_type_hash_error_descriptor =
- { (void *) __go_type_hash_error };
-
-/* An equality function for an interface. */
-
-_Bool
-__go_type_equal_error (const void *v1 __attribute__ ((unused)),
- const void *v2 __attribute__ ((unused)),
- uintptr_t key_size __attribute__ ((unused)))
-{
- runtime_panicstring ("comparing uncomparable types");
-}
-
-const FuncVal __go_type_equal_error_descriptor =
- { (void *) __go_type_equal_error };
diff --git a/libgo/runtime/go-type-float.c b/libgo/runtime/go-type-float.c
deleted file mode 100644
index 39f9b29ae7..0000000000
--- a/libgo/runtime/go-type-float.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* go-type-float.c -- hash and equality float functions.
-
- Copyright 2012 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <math.h>
-#include <stdint.h>
-#include "runtime.h"
-#include "go-type.h"
-
-/* Hash function for float types. */
-
-uintptr_t
-__go_type_hash_float (const void *vkey, uintptr_t key_size)
-{
- if (key_size == 4)
- {
- const float *fp;
- float f;
- uint32_t si;
-
- fp = (const float *) vkey;
- f = *fp;
-
- if (isinf (f) || f == 0)
- return 0;
-
- /* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
- random so that not all NaNs wind up in the same place. */
- if (isnan (f))
- return runtime_fastrand1 ();
-
- memcpy (&si, vkey, 4);
- return (uintptr_t) si;
- }
- else if (key_size == 8)
- {
- const double *dp;
- double d;
- uint64_t di;
-
- dp = (const double *) vkey;
- d = *dp;
-
- if (isinf (d) || d == 0)
- return 0;
-
- if (isnan (d))
- return runtime_fastrand1 ();
-
- memcpy (&di, vkey, 8);
- return (uintptr_t) di;
- }
- else
- runtime_throw ("__go_type_hash_float: invalid float size");
-}
-
-const FuncVal __go_type_hash_float_descriptor =
- { (void *) __go_type_hash_float };
-
-/* Equality function for float types. */
-
-_Bool
-__go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
-{
- if (key_size == 4)
- {
- const float *fp1;
- const float *fp2;
-
- fp1 = (const float *) vk1;
- fp2 = (const float *) vk2;
-
- return *fp1 == *fp2;
- }
- else if (key_size == 8)
- {
- const double *dp1;
- const double *dp2;
-
- dp1 = (const double *) vk1;
- dp2 = (const double *) vk2;
-
- return *dp1 == *dp2;
- }
- else
- runtime_throw ("__go_type_equal_float: invalid float size");
-}
-
-const FuncVal __go_type_equal_float_descriptor =
- { (void *) __go_type_equal_float };
diff --git a/libgo/runtime/go-type-identity.c b/libgo/runtime/go-type-identity.c
deleted file mode 100644
index a334d56cbe..0000000000
--- a/libgo/runtime/go-type-identity.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* go-type-identity.c -- hash and equality identity functions.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-type.h"
-
-/* An identity hash function for a type. This is used for types where
- we can simply use the type value itself as a hash code. This is
- true of, e.g., integers and pointers. */
-
-uintptr_t
-__go_type_hash_identity (const void *key, uintptr_t key_size)
-{
- uintptr_t ret;
- uintptr_t i;
- const unsigned char *p;
-
- if (key_size <= 8)
- {
- union
- {
- uint64 v;
- unsigned char a[8];
- } u;
- u.v = 0;
-#ifdef WORDS_BIGENDIAN
- __builtin_memcpy (&u.a[8 - key_size], key, key_size);
-#else
- __builtin_memcpy (&u.a[0], key, key_size);
-#endif
- if (sizeof (uintptr_t) >= 8)
- return (uintptr_t) u.v;
- else
- return (uintptr_t) ((u.v >> 32) ^ (u.v & 0xffffffff));
- }
-
- ret = 5381;
- for (i = 0, p = (const unsigned char *) key; i < key_size; i++, p++)
- ret = ret * 33 + *p;
- return ret;
-}
-
-const FuncVal __go_type_hash_identity_descriptor =
- { (void *) __go_type_hash_identity };
-
-/* An identity equality function for a type. This is used for types
- where we can check for equality by checking that the values have
- the same bits. */
-
-_Bool
-__go_type_equal_identity (const void *k1, const void *k2, uintptr_t key_size)
-{
- return __builtin_memcmp (k1, k2, key_size) == 0;
-}
-
-const FuncVal __go_type_equal_identity_descriptor =
- { (void *) __go_type_equal_identity };
diff --git a/libgo/runtime/go-type-interface.c b/libgo/runtime/go-type-interface.c
deleted file mode 100644
index e9e577956e..0000000000
--- a/libgo/runtime/go-type-interface.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* go-type-interface.c -- hash and equality interface functions.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "interface.h"
-#include "go-type.h"
-
-/* A hash function for an interface. */
-
-uintptr_t
-__go_type_hash_interface (const void *vval,
- uintptr_t key_size __attribute__ ((unused)))
-{
- const struct __go_interface *val;
- const struct __go_type_descriptor *descriptor;
- uintptr_t size;
-
- val = (const struct __go_interface *) vval;
- if (val->__methods == NULL)
- return 0;
- descriptor = (const struct __go_type_descriptor *) val->__methods[0];
- size = descriptor->__size;
- if (__go_is_pointer_type (descriptor))
- return __go_call_hashfn (descriptor->__hashfn, &val->__object, size);
- else
- return __go_call_hashfn (descriptor->__hashfn, val->__object, size);
-}
-
-const FuncVal __go_type_hash_interface_descriptor =
- { (void *) __go_type_hash_interface };
-
-/* An equality function for an interface. */
-
-_Bool
-__go_type_equal_interface (const void *vv1, const void *vv2,
- uintptr_t key_size __attribute__ ((unused)))
-{
- const struct __go_interface *v1;
- const struct __go_interface *v2;
- const struct __go_type_descriptor* v1_descriptor;
- const struct __go_type_descriptor* v2_descriptor;
-
- v1 = (const struct __go_interface *) vv1;
- v2 = (const struct __go_interface *) vv2;
- if (v1->__methods == NULL || v2->__methods == NULL)
- return v1->__methods == v2->__methods;
- v1_descriptor = (const struct __go_type_descriptor *) v1->__methods[0];
- v2_descriptor = (const struct __go_type_descriptor *) v2->__methods[0];
- if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
- return 0;
- if (__go_is_pointer_type (v1_descriptor))
- return v1->__object == v2->__object;
- else
- return __go_call_equalfn (v1_descriptor->__equalfn, v1->__object,
- v2->__object, v1_descriptor->__size);
-}
-
-const FuncVal __go_type_equal_interface_descriptor =
- { (void *) __go_type_equal_interface };
diff --git a/libgo/runtime/go-type-string.c b/libgo/runtime/go-type-string.c
deleted file mode 100644
index 3d33d6ee51..0000000000
--- a/libgo/runtime/go-type-string.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* go-type-string.c -- hash and equality string functions.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "go-string.h"
-
-/* A string hash function for a map. */
-
-uintptr_t
-__go_type_hash_string (const void *vkey,
- uintptr_t key_size __attribute__ ((unused)))
-{
- uintptr_t ret;
- const String *key;
- intgo len;
- intgo i;
- const byte *p;
-
- ret = 5381;
- key = (const String *) vkey;
- len = key->len;
- for (i = 0, p = key->str; i < len; i++, p++)
- ret = ret * 33 + *p;
- return ret;
-}
-
-const FuncVal __go_type_hash_string_descriptor =
- { (void *) __go_type_hash_string };
-
-/* A string equality function for a map. */
-
-_Bool
-__go_type_equal_string (const void *vk1, const void *vk2,
- uintptr_t key_size __attribute__ ((unused)))
-{
- const String *k1;
- const String *k2;
-
- k1 = (const String *) vk1;
- k2 = (const String *) vk2;
- return __go_ptr_strings_equal (k1, k2);
-}
-
-const FuncVal __go_type_equal_string_descriptor =
- { (void *) __go_type_equal_string };
diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h
index eb063ec678..e1552548d1 100644
--- a/libgo/runtime/go-type.h
+++ b/libgo/runtime/go-type.h
@@ -257,6 +257,33 @@ struct __go_map_type
/* The map value type. */
const struct __go_type_descriptor *__val_type;
+
+ /* The map bucket type. */
+ const struct __go_type_descriptor *__bucket_type;
+
+ /* The map header type. */
+ const struct __go_type_descriptor *__hmap_type;
+
+ /* The size of the key slot. */
+ uint8_t __key_size;
+
+ /* Whether to store a pointer to key rather than the key itself. */
+ uint8_t __indirect_key;
+
+ /* The size of the value slot. */
+ uint8_t __value_size;
+
+ /* Whether to store a pointer to value rather than the value itself. */
+ uint8_t __indirect_value;
+
+ /* The size of a bucket. */
+ uint16_t __bucket_size;
+
+ /* Whether the key type is reflexive--whether k==k for all keys. */
+ _Bool __reflexive_key;
+
+ /* Whether we should update the key when overwriting an entry. */
+ _Bool __need_key_update;
};
/* A pointer type. */
@@ -314,10 +341,11 @@ __go_is_pointer_type (const struct __go_type_descriptor *td)
/* Call a type hash function, given the __hashfn value. */
static inline uintptr_t
-__go_call_hashfn (const FuncVal *hashfn, const void *p, uintptr_t size)
+__go_call_hashfn (const FuncVal *hashfn, const void *p, uintptr_t seed,
+ uintptr_t size)
{
- uintptr_t (*h) (const void *, uintptr_t) = (void *) hashfn->fn;
- return __builtin_call_with_static_chain (h (p, size), hashfn);
+ uintptr_t (*h) (const void *, uintptr_t, uintptr_t) = (void *) hashfn->fn;
+ return __builtin_call_with_static_chain (h (p, seed, size), hashfn);
}
/* Call a type equality function, given the __equalfn value. */
@@ -334,29 +362,4 @@ extern _Bool
__go_type_descriptors_equal(const struct __go_type_descriptor*,
const struct __go_type_descriptor*);
-extern uintptr_t __go_type_hash_identity (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_identity_descriptor;
-extern _Bool __go_type_equal_identity (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_identity_descriptor;
-extern uintptr_t __go_type_hash_string (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_string_descriptor;
-extern _Bool __go_type_equal_string (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_string_descriptor;
-extern uintptr_t __go_type_hash_float (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_float_descriptor;
-extern _Bool __go_type_equal_float (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_float_descriptor;
-extern uintptr_t __go_type_hash_complex (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_complex_descriptor;
-extern _Bool __go_type_equal_complex (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_complex_descriptor;
-extern uintptr_t __go_type_hash_interface (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_interface_descriptor;
-extern _Bool __go_type_equal_interface (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_interface_descriptor;
-extern uintptr_t __go_type_hash_error (const void *, uintptr_t);
-extern const FuncVal __go_type_hash_error_descriptor;
-extern _Bool __go_type_equal_error (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_error_descriptor;
-
#endif /* !defined(LIBGO_GO_TYPE_H) */
diff --git a/libgo/runtime/go-unsafe-new.c b/libgo/runtime/go-unsafe-new.c
index 7848642624..07f274f99a 100644
--- a/libgo/runtime/go-unsafe-new.c
+++ b/libgo/runtime/go-unsafe-new.c
@@ -8,7 +8,6 @@
#include "arch.h"
#include "malloc.h"
#include "go-type.h"
-#include "interface.h"
/* Implement unsafe_New, called from the reflect package. */
diff --git a/libgo/runtime/go-unsafe-newarray.c b/libgo/runtime/go-unsafe-newarray.c
index f5c5efce78..409ddd95dc 100644
--- a/libgo/runtime/go-unsafe-newarray.c
+++ b/libgo/runtime/go-unsafe-newarray.c
@@ -8,7 +8,6 @@
#include "arch.h"
#include "malloc.h"
#include "go-type.h"
-#include "interface.h"
/* Implement unsafe_NewArray, called from the reflect package. */
diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c
index ce82fcd407..3a97ee1d4a 100644
--- a/libgo/runtime/go-unsafe-pointer.c
+++ b/libgo/runtime/go-unsafe-pointer.c
@@ -36,7 +36,13 @@ static const String reflection_string =
sizeof REFLECTION - 1
};
-const uintptr unsafe_Pointer_gc[] = {sizeof(void*), GC_APTR, 0, GC_END};
+const uintptr unsafe_Pointer_gc[] __attribute__((aligned(4))) =
+ {sizeof(void*), GC_APTR, 0, GC_END};
+
+extern const FuncVal runtime_pointerhash_descriptor
+ __asm__ (GOSYM_PREFIX "runtime.pointerhash$descriptor");
+extern const FuncVal runtime_pointerequal_descriptor
+ __asm__ (GOSYM_PREFIX "runtime.pointerequal$descriptor");
const struct __go_type_descriptor unsafe_Pointer =
{
@@ -51,9 +57,9 @@ const struct __go_type_descriptor unsafe_Pointer =
/* __hash */
78501163U,
/* __hashfn */
- &__go_type_hash_identity_descriptor,
+ &runtime_pointerhash_descriptor,
/* __equalfn */
- &__go_type_equal_identity_descriptor,
+ &runtime_pointerequal_descriptor,
/* __gc */
unsafe_Pointer_gc,
/* __reflection */
@@ -79,6 +85,12 @@ static const String preflection_string =
sizeof PREFLECTION - 1,
};
+extern const uintptr pointer_unsafe_Pointer_gc[]
+ __asm__ (GOSYM_PREFIX "__go_td_pN14_unsafe.Pointer$gc");
+
+const uintptr pointer_unsafe_Pointer_gc[] __attribute__((aligned(4))) =
+ {sizeof(void*), GC_APTR, 0, GC_END};
+
const struct __go_ptr_type pointer_unsafe_Pointer =
{
/* __common */
@@ -94,11 +106,11 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
/* __hash */
1256018616U,
/* __hashfn */
- &__go_type_hash_identity_descriptor,
+ &runtime_pointerhash_descriptor,
/* __equalfn */
- &__go_type_equal_identity_descriptor,
+ &runtime_pointerequal_descriptor,
/* __gc */
- unsafe_Pointer_gc,
+ pointer_unsafe_Pointer_gc,
/* __reflection */
&preflection_string,
/* __uncommon */
diff --git a/libgo/runtime/go-unsetenv.c b/libgo/runtime/go-unsetenv.c
index 409436a0d3..21359975f2 100644
--- a/libgo/runtime/go-unsetenv.c
+++ b/libgo/runtime/go-unsetenv.c
@@ -9,10 +9,7 @@
#include <stddef.h>
#include <stdlib.h>
-#include "go-alloc.h"
#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
/* Unset an environment variable from Go. This is called by
syscall.Unsetenv. */
@@ -24,7 +21,6 @@ unsetenv_c (String k)
{
const byte *ks;
unsigned char *kn;
- intgo len;
ks = k.str;
if (ks == NULL)
@@ -33,14 +29,11 @@ unsetenv_c (String k)
#ifdef HAVE_UNSETENV
- if (ks != NULL && ks[k.len] != 0)
+ if (ks[k.len] != 0)
{
- // Objects that are explicitly freed must be at least 16 bytes in size,
- // so that they are not allocated using tiny alloc.
- len = k.len + 1;
- if (len < TinySize)
- len = TinySize;
- kn = __go_alloc (len);
+ kn = malloc (k.len + 1);
+ if (kn == NULL)
+ runtime_throw ("out of malloc memory");
__builtin_memcpy (kn, ks, k.len);
ks = kn;
}
@@ -50,5 +43,5 @@ unsetenv_c (String k)
#endif /* !defined(HAVE_UNSETENV) */
if (kn != NULL)
- __go_free (kn);
+ free (kn);
}
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
index 87d9eb3ef4..4c9fb49c99 100644
--- a/libgo/runtime/go-unwind.c
+++ b/libgo/runtime/go-unwind.c
@@ -14,9 +14,6 @@
#include "unwind-pe.h"
#include "runtime.h"
-#include "go-alloc.h"
-#include "go-defer.h"
-#include "go-panic.h"
/* The code for a Go exception. */
@@ -35,111 +32,16 @@ static const _Unwind_Exception_Class __go_exception_class =
<< 8 | (_Unwind_Exception_Class) '\0');
#endif
+/* Rethrow an exception. */
-/* This function is called by exception handlers used when unwinding
- the stack after a recovered panic. The exception handler looks
- like this:
- __go_check_defer (frame);
- return;
- If we have not yet reached the frame we are looking for, we
- continue unwinding. */
+void rethrowException (void) __asm__(GOSYM_PREFIX "runtime.rethrowException");
void
-__go_check_defer (_Bool *frame)
+rethrowException ()
{
- G *g;
struct _Unwind_Exception *hdr;
- g = runtime_g ();
-
- if (g == NULL)
- {
- /* Some other language has thrown an exception. We know there
- are no defer handlers, so there is nothing to do. */
- }
- else if (g->is_foreign)
- {
- struct __go_panic_stack *n;
- _Bool was_recovered;
-
- /* Some other language has thrown an exception. We need to run
- the local defer handlers. If they call recover, we stop
- unwinding the stack here. */
-
- n = ((struct __go_panic_stack *)
- __go_alloc (sizeof (struct __go_panic_stack)));
-
- n->__arg.__type_descriptor = NULL;
- n->__arg.__object = NULL;
- n->__was_recovered = 0;
- n->__is_foreign = 1;
- n->__next = g->panic;
- g->panic = n;
-
- while (1)
- {
- struct __go_defer_stack *d;
- void (*pfn) (void *);
-
- d = g->defer;
- if (d == NULL || d->__frame != frame || d->__pfn == NULL)
- break;
-
- pfn = d->__pfn;
- g->defer = d->__next;
-
- (*pfn) (d->__arg);
-
- if (runtime_m () != NULL)
- runtime_freedefer (d);
-
- if (n->__was_recovered)
- {
- /* The recover function caught the panic thrown by some
- other language. */
- break;
- }
- }
-
- was_recovered = n->__was_recovered;
- g->panic = n->__next;
- __go_free (n);
-
- if (was_recovered)
- {
- /* Just return and continue executing Go code. */
- *frame = 1;
- return;
- }
-
- /* We are panicing through this function. */
- *frame = 0;
- }
- else if (g->defer != NULL
- && g->defer->__pfn == NULL
- && g->defer->__frame == frame)
- {
- struct __go_defer_stack *d;
-
- /* This is the defer function which called recover. Simply
- return to stop the stack unwind, and let the Go code continue
- to execute. */
- d = g->defer;
- g->defer = d->__next;
-
- if (runtime_m () != NULL)
- runtime_freedefer (d);
-
- /* We are returning from this function. */
- *frame = 1;
-
- return;
- }
-
- /* This is some other defer function. It was already run by the
- call to panic, or just above. Rethrow the exception. */
-
- hdr = (struct _Unwind_Exception *) g->exception;
+ hdr = (struct _Unwind_Exception *) runtime_g()->exception;
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_Resume_or_Rethrow (hdr);
@@ -155,23 +57,48 @@ __go_check_defer (_Bool *frame)
abort();
}
-/* Unwind function calls until we reach the one which used a defer
- function which called recover. Each function which uses a defer
- statement will have an exception handler, as shown above. */
+/* Return the size of the type that holds an exception header, so that
+ it can be allocated by Go code. */
+
+uintptr unwindExceptionSize(void)
+ __asm__ (GOSYM_PREFIX "runtime.unwindExceptionSize");
+
+uintptr
+unwindExceptionSize ()
+{
+ uintptr ret, align;
+
+ ret = sizeof (struct _Unwind_Exception);
+ /* Adjust the size fo make sure that we can get an aligned value. */
+ align = __alignof__ (struct _Unwind_Exception);
+ if (align > __alignof__ (uintptr))
+ ret += align - __alignof__ (uintptr);
+ return ret;
+}
+
+/* Throw an exception. This is called with g->exception pointing to
+ an uninitialized _Unwind_Exception instance. */
+
+void throwException (void) __asm__(GOSYM_PREFIX "runtime.throwException");
void
-__go_unwind_stack ()
+throwException ()
{
struct _Unwind_Exception *hdr;
+ uintptr align;
+
+ hdr = (struct _Unwind_Exception *)runtime_g ()->exception;
+ /* Make sure the value is correctly aligned. It will be large
+ enough, because of unwindExceptionSize. */
+ align = __alignof__ (struct _Unwind_Exception);
hdr = ((struct _Unwind_Exception *)
- __go_alloc (sizeof (struct _Unwind_Exception)));
+ (((uintptr) hdr + align - 1) &~ (align - 1)));
+
__builtin_memcpy (&hdr->exception_class, &__go_exception_class,
sizeof hdr->exception_class);
hdr->exception_cleanup = NULL;
- runtime_g ()->exception = hdr;
-
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException (hdr);
#else
@@ -432,7 +359,7 @@ PERSONALITY_FUNCTION (int version,
else
{
g->exception = ue_header;
- g->is_foreign = is_foreign;
+ g->isforeign = is_foreign;
}
_Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
diff --git a/libgo/runtime/heapdump.c b/libgo/runtime/heapdump.c
index d0cfb01478..4c673f4182 100644
--- a/libgo/runtime/heapdump.c
+++ b/libgo/runtime/heapdump.c
@@ -14,8 +14,6 @@
#include "malloc.h"
#include "mgc0.h"
#include "go-type.h"
-#include "go-defer.h"
-#include "go-panic.h"
#define hash __hash
#define KindNoPointers GO_NO_POINTERS
@@ -265,15 +263,15 @@ dumpgoroutine(G *gp)
dumpint((uintptr)0);
dumpint(gp->goid);
dumpint(gp->gopc);
- dumpint(gp->status);
+ dumpint(gp->atomicstatus);
dumpbool(gp->issystem);
dumpbool(gp->isbackground);
dumpint(gp->waitsince);
- dumpcstr((const int8 *)gp->waitreason);
+ dumpstr(gp->waitreason);
dumpint((uintptr)0);
dumpint((uintptr)gp->m);
- dumpint((uintptr)gp->defer);
- dumpint((uintptr)gp->panic);
+ dumpint((uintptr)gp->_defer);
+ dumpint((uintptr)gp->_panic);
// dump stack
// child.args.n = -1;
@@ -285,24 +283,24 @@ dumpgoroutine(G *gp)
// runtime_gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false);
// dump defer & panic records
- for(d = gp->defer; d != nil; d = d->__next) {
+ for(d = gp->_defer; d != nil; d = d->link) {
dumpint(TagDefer);
dumpint((uintptr)d);
dumpint((uintptr)gp);
- dumpint((uintptr)d->__arg);
- dumpint((uintptr)d->__frame);
- dumpint((uintptr)d->__pfn);
+ dumpint((uintptr)d->arg);
+ dumpint((uintptr)d->frame);
+ dumpint((uintptr)d->pfn);
dumpint((uintptr)0);
- dumpint((uintptr)d->__next);
+ dumpint((uintptr)d->link);
}
- for (p = gp->panic; p != nil; p = p->__next) {
+ for (p = gp->_panic; p != nil; p = p->link) {
dumpint(TagPanic);
dumpint((uintptr)p);
dumpint((uintptr)gp);
- dumpint((uintptr)p->__arg.__type_descriptor);
- dumpint((uintptr)p->__arg.__object);
+ dumpint((uintptr)p->arg._type);
+ dumpint((uintptr)p->arg.data);
dumpint((uintptr)0);
- dumpint((uintptr)p->__next);
+ dumpint((uintptr)p->link);
}
}
@@ -313,17 +311,17 @@ dumpgs(void)
uint32 i;
// goroutines & stacks
- for(i = 0; i < runtime_allglen; i++) {
- gp = runtime_allg[i];
- switch(gp->status){
+ for(i = 0; i < runtime_getallglen(); i++) {
+ gp = runtime_getallg(i);
+ switch(gp->atomicstatus){
default:
- runtime_printf("unexpected G.status %d\n", gp->status);
+ runtime_printf("unexpected G.status %d\n", gp->atomicstatus);
runtime_throw("mark - bad status");
- case Gdead:
+ case _Gdead:
break;
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
+ case _Grunnable:
+ case _Gsyscall:
+ case _Gwaiting:
dumpgoroutine(gp);
break;
}
@@ -463,7 +461,7 @@ dumpparams(void)
else
dumpbool(true); // big-endian ptrs
dumpint(PtrSize);
- dumpint(runtime_Hchansize);
+ dumpint(hchanSize);
dumpint((uintptr)runtime_mheap.arena_start);
dumpint((uintptr)runtime_mheap.arena_used);
dumpint(0);
@@ -476,7 +474,7 @@ dumpms(void)
{
M *mp;
- for(mp = runtime_allm; mp != nil; mp = mp->alllink) {
+ for(mp = runtime_getallm(); mp != nil; mp = mp->alllink) {
dumpint(TagOSThread);
dumpint((uintptr)mp);
dumpint(mp->id);
@@ -490,33 +488,33 @@ dumpmemstats(void)
int32 i;
dumpint(TagMemStats);
- dumpint(mstats.alloc);
- dumpint(mstats.total_alloc);
- dumpint(mstats.sys);
- dumpint(mstats.nlookup);
- dumpint(mstats.nmalloc);
- dumpint(mstats.nfree);
- dumpint(mstats.heap_alloc);
- dumpint(mstats.heap_sys);
- dumpint(mstats.heap_idle);
- dumpint(mstats.heap_inuse);
- dumpint(mstats.heap_released);
- dumpint(mstats.heap_objects);
- dumpint(mstats.stacks_inuse);
- dumpint(mstats.stacks_sys);
- dumpint(mstats.mspan_inuse);
- dumpint(mstats.mspan_sys);
- dumpint(mstats.mcache_inuse);
- dumpint(mstats.mcache_sys);
- dumpint(mstats.buckhash_sys);
- dumpint(mstats.gc_sys);
- dumpint(mstats.other_sys);
- dumpint(mstats.next_gc);
- dumpint(mstats.last_gc);
- dumpint(mstats.pause_total_ns);
+ dumpint(mstats()->alloc);
+ dumpint(mstats()->total_alloc);
+ dumpint(mstats()->sys);
+ dumpint(mstats()->nlookup);
+ dumpint(mstats()->nmalloc);
+ dumpint(mstats()->nfree);
+ dumpint(mstats()->heap_alloc);
+ dumpint(mstats()->heap_sys);
+ dumpint(mstats()->heap_idle);
+ dumpint(mstats()->heap_inuse);
+ dumpint(mstats()->heap_released);
+ dumpint(mstats()->heap_objects);
+ dumpint(mstats()->stacks_inuse);
+ dumpint(mstats()->stacks_sys);
+ dumpint(mstats()->mspan_inuse);
+ dumpint(mstats()->mspan_sys);
+ dumpint(mstats()->mcache_inuse);
+ dumpint(mstats()->mcache_sys);
+ dumpint(mstats()->buckhash_sys);
+ dumpint(mstats()->gc_sys);
+ dumpint(mstats()->other_sys);
+ dumpint(mstats()->next_gc);
+ dumpint(mstats()->last_gc);
+ dumpint(mstats()->pause_total_ns);
for(i = 0; i < 256; i++)
- dumpint(mstats.pause_ns[i]);
- dumpint(mstats.numgc);
+ dumpint(mstats()->pause_ns[i]);
+ dumpint(mstats()->numgc);
}
static void
@@ -546,6 +544,8 @@ dumpmemprof_callback(Bucket *b, uintptr nstk, Location *stk, uintptr size, uintp
dumpint(frees);
}
+static FuncVal dumpmemprof_callbackv = {(void(*)(void))dumpmemprof_callback};
+
static void
dumpmemprof(void)
{
@@ -555,7 +555,7 @@ dumpmemprof(void)
SpecialProfile *spp;
byte *p;
- runtime_iterate_memprof(dumpmemprof_callback);
+ runtime_iterate_memprof(&dumpmemprof_callbackv);
allspans = runtime_mheap.allspans;
for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
@@ -602,7 +602,7 @@ mdump(G *gp)
flush();
gp->param = nil;
- gp->status = Grunning;
+ gp->atomicstatus = _Grunning;
runtime_gogo(gp);
}
@@ -616,11 +616,10 @@ runtime_debug_WriteHeapDump(uintptr fd)
G *g;
// Stop the world.
- runtime_semacquire(&runtime_worldsema, false);
+ runtime_acquireWorldsema();
m = runtime_m();
- m->gcing = 1;
- m->locks++;
- runtime_stoptheworld();
+ m->preemptoff = runtime_gostringnocopy((const byte*)"write heap dump");
+ runtime_stopTheWorldWithSema();
// Update stats so we can dump them.
// As a side effect, flushes all the MCaches so the MSpan.freelist
@@ -632,18 +631,17 @@ runtime_debug_WriteHeapDump(uintptr fd)
// Call dump routine on M stack.
g = runtime_g();
- g->status = Gwaiting;
- g->waitreason = "dumping heap";
+ g->atomicstatus = _Gwaiting;
+ g->waitreason = runtime_gostringnocopy((const byte*)"dumping heap");
runtime_mcall(mdump);
// Reset dump file.
dumpfd = 0;
// Start up the world again.
- m->gcing = 0;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- m->locks--;
+ runtime_startTheWorldWithSema();
+ runtime_releaseWorldsema();
+ m->preemptoff = runtime_gostringnocopy(nil);
}
// Runs the specified gc program. Calls the callback for every
@@ -763,14 +761,16 @@ dumpefacetypes(void *obj __attribute__ ((unused)), uintptr size, const Type *typ
//playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj);
break;
case TypeInfo_Array:
- for(i = 0; i <= size - type->__size; i += type->__size)
+ for(i = 0; i <= size - type->__size; i += type->__size) {
//playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ }
break;
case TypeInfo_Chan:
if(type->__size == 0) // channels may have zero-sized objects in them
break;
- for(i = runtime_Hchansize; i <= size - type->__size; i += type->__size)
+ for(i = hchanSize; i <= size - type->__size; i += type->__size) {
//playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ }
break;
}
}
diff --git a/libgo/runtime/interface.h b/libgo/runtime/interface.h
deleted file mode 100644
index f3068a656f..0000000000
--- a/libgo/runtime/interface.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* interface.h -- the interface type for Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#ifndef LIBGO_INTERFACE_H
-#define LIBGO_INTERFACE_H
-
-struct __go_type_descriptor;
-
-/* A variable of interface type is an instance of this struct, if the
- interface has any methods. */
-
-struct __go_interface
-{
- /* A pointer to the interface method table. The first pointer is
- the type descriptor of the object. Subsequent pointers are
- pointers to functions. This is effectively the vtable for this
- interface. The function pointers are in the same order as the
- list in the internal representation of the interface, which sorts
- them by name. */
- const void **__methods;
-
- /* The object. If the object is a pointer--if the type descriptor
- code is GO_PTR or GO_UNSAFE_POINTER--then this field is the value
- of the object itself. Otherwise this is a pointer to memory
- which holds the value. */
- void *__object;
-};
-
-/* A variable of an empty interface type is an instance of this
- struct. */
-
-struct __go_empty_interface
-{
- /* The type descriptor of the object. */
- const struct __go_type_descriptor *__type_descriptor;
-
- /* The object. This is the same as __go_interface above. */
- void *__object;
-};
-
-extern void *
-__go_convert_interface (const struct __go_type_descriptor *,
- const struct __go_type_descriptor *);
-
-extern void *
-__go_convert_interface_2 (const struct __go_type_descriptor *,
- const struct __go_type_descriptor *,
- _Bool may_fail);
-
-extern _Bool
-__go_can_convert_to_interface(const struct __go_type_descriptor *,
- const struct __go_type_descriptor *);
-
-#endif /* !defined(LIBGO_INTERFACE_H) */
diff --git a/libgo/runtime/lfstack.goc b/libgo/runtime/lfstack.goc
deleted file mode 100644
index 5ab1baa436..0000000000
--- a/libgo/runtime/lfstack.goc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Lock-free stack.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-
-#if __SIZEOF_POINTER__ == 8
-// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
-// Use low-order three bits as ABA counter.
-// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
-# if defined(__sparc__) || (defined(__sun__) && defined(__amd64__))
-static inline uint64 lfPack(LFNode *node, uintptr cnt) {
- return ((uint64)(node)) | ((cnt)&7);
-}
-static inline LFNode* lfUnpack(uint64 val) {
- return (LFNode*)(val&~7);
-}
-# else
-# if defined(__aarch64__)
-// Depending on the kernel options, pointers on arm64 can have up to 48 significant
-// bits (see https://www.kernel.org/doc/Documentation/arm64/memory.txt).
-# define PTR_BITS 48
-# else
-// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
-// So we use 17msb of pointers as ABA counter.
-# define PTR_BITS 47
-# endif
-# define CNT_BITS (64 - PTR_BITS + 3)
-static inline uint64 lfPack(LFNode *node, uintptr cnt) {
- return ((uint64)(node)<<(64-PTR_BITS)) | (cnt&(((1<<CNT_BITS)-1)));
-}
-static inline LFNode* lfUnpack(uint64 val) {
- return (LFNode*)((val >> CNT_BITS) << 3);
-}
-# endif
-#else
-static inline uint64 lfPack(LFNode *node, uintptr cnt) {
- return ((uint64)(uintptr)(node)<<32) | cnt;
-}
-static inline LFNode* lfUnpack(uint64 val) {
- return (LFNode*)(uintptr)(val >> 32);
-}
-#endif
-
-void
-runtime_lfstackpush(uint64 *head, LFNode *node)
-{
- uint64 old, new;
-
- if(node != lfUnpack(lfPack(node, 0))) {
- runtime_printf("p=%p\n", node);
- runtime_throw("runtime_lfstackpush: invalid pointer");
- }
-
- node->pushcnt++;
- new = lfPack(node, node->pushcnt);
- for(;;) {
- old = runtime_atomicload64(head);
- node->next = lfUnpack(old);
- if(runtime_cas64(head, old, new))
- break;
- }
-}
-
-LFNode*
-runtime_lfstackpop(uint64 *head)
-{
- LFNode *node, *node2;
- uint64 old, new;
-
- for(;;) {
- old = runtime_atomicload64(head);
- if(old == 0)
- return nil;
- node = lfUnpack(old);
- node2 = runtime_atomicloadp(&node->next);
- new = 0;
- if(node2 != nil)
- new = lfPack(node2, node2->pushcnt);
- if(runtime_cas64(head, old, new))
- return node;
- }
-}
-
-func lfstackpush_go(head *uint64, node *LFNode) {
- runtime_lfstackpush(head, node);
-}
-
-func lfstackpop_go(head *uint64) (node *LFNode) {
- node = runtime_lfstackpop(head);
-}
diff --git a/libgo/runtime/lock_futex.c b/libgo/runtime/lock_futex.c
deleted file mode 100644
index 33ef073c90..0000000000
--- a/libgo/runtime/lock_futex.c
+++ /dev/null
@@ -1,204 +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.
-
-// +build dragonfly freebsd linux
-
-#include "runtime.h"
-
-// This implementation depends on OS-specific implementations of
-//
-// runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
-// Atomically,
-// if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-//
-// runtime_futexwakeup(uint32 *addr, uint32 cnt)
-// If any procs are sleeping on addr, wake up at most cnt.
-
-enum
-{
- MUTEX_UNLOCKED = 0,
- MUTEX_LOCKED = 1,
- MUTEX_SLEEPING = 2,
-
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
- PASSIVE_SPIN = 1,
-};
-
-// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
-// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
-// Note that there can be spinning threads during all states - they do not
-// affect mutex's state.
-void
-runtime_lock(Lock *l)
-{
- uint32 i, v, wait, spin;
-
- if(runtime_m()->locks++ < 0)
- runtime_throw("runtime_lock: lock count");
-
- // Speculative grab for lock.
- v = runtime_xchg((uint32*)&l->key, MUTEX_LOCKED);
- if(v == MUTEX_UNLOCKED)
- return;
-
- // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
- // depending on whether there is a thread sleeping
- // on this mutex. If we ever change l->key from
- // MUTEX_SLEEPING to some other value, we must be
- // careful to change it back to MUTEX_SLEEPING before
- // returning, to ensure that the sleeping thread gets
- // its wakeup call.
- wait = v;
-
- // On uniprocessor's, no point spinning.
- // On multiprocessors, spin for ACTIVE_SPIN attempts.
- spin = 0;
- if(runtime_ncpu > 1)
- spin = ACTIVE_SPIN;
-
- for(;;) {
- // Try for lock, spinning.
- for(i = 0; i < spin; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime_procyield(ACTIVE_SPIN_CNT);
- }
-
- // Try for lock, rescheduling.
- for(i=0; i < PASSIVE_SPIN; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime_osyield();
- }
-
- // Sleep.
- v = runtime_xchg((uint32*)&l->key, MUTEX_SLEEPING);
- if(v == MUTEX_UNLOCKED)
- return;
- wait = MUTEX_SLEEPING;
- runtime_futexsleep((uint32*)&l->key, MUTEX_SLEEPING, -1);
- }
-}
-
-void
-runtime_unlock(Lock *l)
-{
- uint32 v;
-
- v = runtime_xchg((uint32*)&l->key, MUTEX_UNLOCKED);
- if(v == MUTEX_UNLOCKED)
- runtime_throw("unlock of unlocked lock");
- if(v == MUTEX_SLEEPING)
- runtime_futexwakeup((uint32*)&l->key, 1);
-
- if(--runtime_m()->locks < 0)
- runtime_throw("runtime_unlock: lock count");
-}
-
-// One-time notifications.
-void
-runtime_noteclear(Note *n)
-{
- n->key = 0;
-}
-
-void
-runtime_notewakeup(Note *n)
-{
- uint32 old;
-
- old = runtime_xchg((uint32*)&n->key, 1);
- if(old != 0) {
- runtime_printf("notewakeup - double wakeup (%d)\n", old);
- runtime_throw("notewakeup - double wakeup");
- }
- runtime_futexwakeup((uint32*)&n->key, 1);
-}
-
-void
-runtime_notesleep(Note *n)
-{
- M *m = runtime_m();
-
- /* For gccgo it's OK to sleep in non-g0, and it happens in
- stoptheworld because we have not implemented preemption.
-
- if(runtime_g() != runtime_m()->g0)
- runtime_throw("notesleep not on g0");
- */
- while(runtime_atomicload((uint32*)&n->key) == 0) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, -1);
- m->blocked = false;
- }
-}
-
-static bool
-notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
-{
- M *m = runtime_m();
-
- // Conceptually, deadline and now are local variables.
- // They are passed as arguments so that the space for them
- // does not count against our nosplit stack sequence.
-
- if(ns < 0) {
- while(runtime_atomicload((uint32*)&n->key) == 0) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, -1);
- m->blocked = false;
- }
- return true;
- }
-
- if(runtime_atomicload((uint32*)&n->key) != 0)
- return true;
-
- deadline = runtime_nanotime() + ns;
- for(;;) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, ns);
- m->blocked = false;
- if(runtime_atomicload((uint32*)&n->key) != 0)
- break;
- now = runtime_nanotime();
- if(now >= deadline)
- break;
- ns = deadline - now;
- }
- return runtime_atomicload((uint32*)&n->key) != 0;
-}
-
-bool
-runtime_notetsleep(Note *n, int64 ns)
-{
- bool res;
-
- if(runtime_g() != runtime_m()->g0 && !runtime_m()->gcing)
- runtime_throw("notetsleep not on g0");
-
- res = notetsleep(n, ns, 0, 0);
- return res;
-}
-
-// same as runtime_notetsleep, but called on user g (not g0)
-// calls only nosplit functions between entersyscallblock/exitsyscall
-bool
-runtime_notetsleepg(Note *n, int64 ns)
-{
- bool res;
-
- if(runtime_g() == runtime_m()->g0)
- runtime_throw("notetsleepg on g0");
-
- runtime_entersyscallblock();
- res = notetsleep(n, ns, 0, 0);
- runtime_exitsyscall();
- return res;
-}
diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c
deleted file mode 100644
index ef611fb36a..0000000000
--- a/libgo/runtime/lock_sema.c
+++ /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.
-
-// +build darwin nacl netbsd openbsd plan9 solaris windows
-
-#include "runtime.h"
-
-// This implementation depends on OS-specific implementations of
-//
-// uintptr runtime_semacreate(void)
-// Create a semaphore, which will be assigned to m->waitsema.
-// The zero value is treated as absence of any semaphore,
-// so be sure to return a non-zero value.
-//
-// int32 runtime_semasleep(int64 ns)
-// If ns < 0, acquire m->waitsema and return 0.
-// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
-// Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
-//
-// int32 runtime_semawakeup(M *mp)
-// Wake up mp, which is or will soon be sleeping on mp->waitsema.
-//
-
-enum
-{
- LOCKED = 1,
-
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
- PASSIVE_SPIN = 1,
-};
-
-void
-runtime_lock(Lock *l)
-{
- M *m;
- uintptr v;
- uint32 i, spin;
-
- m = runtime_m();
- if(m->locks++ < 0)
- runtime_throw("runtime_lock: lock count");
-
- // Speculative grab for lock.
- if(runtime_casp((void**)&l->key, nil, (void*)LOCKED))
- return;
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- // On uniprocessor's, no point spinning.
- // On multiprocessors, spin for ACTIVE_SPIN attempts.
- spin = 0;
- if(runtime_ncpu > 1)
- spin = ACTIVE_SPIN;
-
- for(i=0;; i++) {
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if((v&LOCKED) == 0) {
-unlocked:
- if(runtime_casp((void**)&l->key, (void*)v, (void*)(v|LOCKED)))
- return;
- i = 0;
- }
- if(i<spin)
- runtime_procyield(ACTIVE_SPIN_CNT);
- else if(i<spin+PASSIVE_SPIN)
- runtime_osyield();
- else {
- // Someone else has it.
- // l->waitm points to a linked list of M's waiting
- // for this lock, chained through m->nextwaitm.
- // Queue this M.
- for(;;) {
- m->nextwaitm = (void*)(v&~LOCKED);
- if(runtime_casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
- break;
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if((v&LOCKED) == 0)
- goto unlocked;
- }
- if(v&LOCKED) {
- // Queued. Wait.
- runtime_semasleep(-1);
- i = 0;
- }
- }
- }
-}
-
-void
-runtime_unlock(Lock *l)
-{
- uintptr v;
- M *mp;
-
- for(;;) {
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if(v == LOCKED) {
- if(runtime_casp((void**)&l->key, (void*)LOCKED, nil))
- break;
- } else {
- // Other M's are waiting for the lock.
- // Dequeue an M.
- mp = (void*)(v&~LOCKED);
- if(runtime_casp((void**)&l->key, (void*)v, mp->nextwaitm)) {
- // Dequeued an M. Wake it.
- runtime_semawakeup(mp);
- break;
- }
- }
- }
-
- if(--runtime_m()->locks < 0)
- runtime_throw("runtime_unlock: lock count");
-}
-
-// One-time notifications.
-void
-runtime_noteclear(Note *n)
-{
- n->key = 0;
-}
-
-void
-runtime_notewakeup(Note *n)
-{
- M *mp;
-
- do
- mp = runtime_atomicloadp((void**)&n->key);
- while(!runtime_casp((void**)&n->key, mp, (void*)LOCKED));
-
- // Successfully set waitm to LOCKED.
- // What was it before?
- if(mp == nil) {
- // Nothing was waiting. Done.
- } else if(mp == (M*)LOCKED) {
- // Two notewakeups! Not allowed.
- runtime_throw("notewakeup - double wakeup");
- } else {
- // Must be the waiting m. Wake it up.
- runtime_semawakeup(mp);
- }
-}
-
-void
-runtime_notesleep(Note *n)
-{
- M *m;
-
- m = runtime_m();
-
- /* For gccgo it's OK to sleep in non-g0, and it happens in
- stoptheworld because we have not implemented preemption.
-
- if(runtime_g() != m->g0)
- runtime_throw("notesleep not on g0");
- */
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
- if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup)
- if(n->key != LOCKED)
- runtime_throw("notesleep - waitm out of sync");
- return;
- }
- // Queued. Sleep.
- m->blocked = true;
- runtime_semasleep(-1);
- m->blocked = false;
-}
-
-static bool
-notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
-{
- M *m;
-
- m = runtime_m();
-
- // Conceptually, deadline and mp are local variables.
- // They are passed as arguments so that the space for them
- // does not count against our nosplit stack sequence.
-
- // Register for wakeup on n->waitm.
- if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup already)
- if(n->key != LOCKED)
- runtime_throw("notetsleep - waitm out of sync");
- return true;
- }
-
- if(ns < 0) {
- // Queued. Sleep.
- m->blocked = true;
- runtime_semasleep(-1);
- m->blocked = false;
- return true;
- }
-
- deadline = runtime_nanotime() + ns;
- for(;;) {
- // Registered. Sleep.
- m->blocked = true;
- if(runtime_semasleep(ns) >= 0) {
- m->blocked = false;
- // Acquired semaphore, semawakeup unregistered us.
- // Done.
- return true;
- }
- m->blocked = false;
-
- // Interrupted or timed out. Still registered. Semaphore not acquired.
- ns = deadline - runtime_nanotime();
- if(ns <= 0)
- break;
- // Deadline hasn't arrived. Keep sleeping.
- }
-
- // Deadline arrived. Still registered. Semaphore not acquired.
- // Want to give up and return, but have to unregister first,
- // so that any notewakeup racing with the return does not
- // try to grant us the semaphore when we don't expect it.
- for(;;) {
- mp = runtime_atomicloadp((void**)&n->key);
- if(mp == m) {
- // No wakeup yet; unregister if possible.
- if(runtime_casp((void**)&n->key, mp, nil))
- return false;
- } else if(mp == (M*)LOCKED) {
- // Wakeup happened so semaphore is available.
- // Grab it to avoid getting out of sync.
- m->blocked = true;
- if(runtime_semasleep(-1) < 0)
- runtime_throw("runtime: unable to acquire - semaphore out of sync");
- m->blocked = false;
- return true;
- } else
- runtime_throw("runtime: unexpected waitm - semaphore out of sync");
- }
-}
-
-bool
-runtime_notetsleep(Note *n, int64 ns)
-{
- M *m;
- bool res;
-
- m = runtime_m();
-
- if(runtime_g() != m->g0 && !m->gcing)
- runtime_throw("notetsleep not on g0");
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- res = notetsleep(n, ns, 0, nil);
- return res;
-}
-
-// same as runtime_notetsleep, but called on user g (not g0)
-// calls only nosplit functions between entersyscallblock/exitsyscall
-bool
-runtime_notetsleepg(Note *n, int64 ns)
-{
- M *m;
- bool res;
-
- m = runtime_m();
-
- if(runtime_g() == m->g0)
- runtime_throw("notetsleepg on g0");
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- runtime_entersyscallblock();
- res = notetsleep(n, ns, 0, nil);
- runtime_exitsyscall();
- return res;
-}
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 0d8629277f..232210fc4e 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -10,22 +10,15 @@ package runtime
#include <stddef.h>
#include <errno.h>
#include <stdlib.h>
-#include "go-alloc.h"
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
-#include "interface.h"
#include "go-type.h"
// Map gccgo field names to gc field names.
-// Eface aka __go_empty_interface.
-#define type __type_descriptor
// Type aka __go_type_descriptor
#define kind __code
#define string __reflection
-#define KindPtr GO_PTR
-#define KindNoPointers GO_NO_POINTERS
-#define kindMask GO_CODE_MASK
// GCCGO SPECIFIC CHANGE
//
@@ -54,12 +47,9 @@ package runtime
// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
MHeap runtime_mheap;
-MStats mstats;
int32 runtime_checking;
-extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go
-
extern volatile intgo runtime_MemProfileRate
__asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
@@ -84,31 +74,33 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
MLink *v, *next;
byte *tiny;
bool incallback;
+ MStats *pmstats;
if(size == 0) {
// All 0-length allocations use this pointer.
// The language does not require the allocations to
// have distinct values.
- return &runtime_zerobase;
+ return runtime_getZerobase();
}
- m = runtime_m();
g = runtime_g();
+ m = g->m;
incallback = false;
- if(m->mcache == nil && g->ncgo > 0) {
+ if(m->mcache == nil && m->ncgo > 0) {
// For gccgo this case can occur when a cgo or SWIG function
// has an interface return type and the function
// returns a non-pointer, so memory allocation occurs
// after syscall.Cgocall but before syscall.CgocallDone.
// We treat it as a callback.
- runtime_exitsyscall();
+ runtime_exitsyscall(0);
m = runtime_m();
incallback = true;
flag |= FlagNoInvokeGC;
}
- if(runtime_gcwaiting() && g != m->g0 && m->locks == 0 && !(flag & FlagNoInvokeGC)) {
+ if((g->preempt || runtime_gcwaiting()) && g != m->g0 && m->locks == 0 && !(flag & FlagNoInvokeGC) && m->preemptoff.len == 0) {
+ g->preempt = false;
runtime_gosched();
m = runtime_m();
}
@@ -165,16 +157,16 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
tiny = (byte*)ROUND((uintptr)tiny, 4);
else if((size&1) == 0)
tiny = (byte*)ROUND((uintptr)tiny, 2);
- size1 = size + (tiny - c->tiny);
+ size1 = size + (tiny - (byte*)c->tiny);
if(size1 <= tinysize) {
// The object fits into existing tiny block.
v = (MLink*)tiny;
- c->tiny += size1;
+ c->tiny = (byte*)c->tiny + size1;
c->tinysize -= size1;
m->mallocing = 0;
m->locks--;
if(incallback)
- runtime_entersyscall();
+ runtime_entersyscall(0);
return v;
}
}
@@ -255,11 +247,12 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
m->locks--;
- if(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
+ pmstats = mstats();
+ if(!(flag & FlagNoInvokeGC) && pmstats->heap_alloc >= pmstats->next_gc)
runtime_gc(0);
if(incallback)
- runtime_entersyscall();
+ runtime_entersyscall(0);
return v;
}
@@ -281,7 +274,7 @@ largealloc(uint32 flag, uintptr *sizep)
s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, !(flag & FlagNoZero));
if(s == nil)
runtime_throw("out of memory");
- s->limit = (byte*)(s->start<<PageShift) + size;
+ s->limit = (uintptr)((byte*)(s->start<<PageShift) + size);
*sizep = npages<<PageShift;
v = (void*)(s->start << PageShift);
// setup for mark sweep
@@ -303,7 +296,7 @@ runtime_profilealloc(void *v, uintptr size)
// If you change this, also change allocmcache.
if(rate > 0x3fffffff) // make 2*rate not overflow
rate = 0x3fffffff;
- next = runtime_fastrand1() % (2*rate);
+ next = runtime_fastrand() % (2*rate);
// Subtract the "remainder" of the current allocation.
// Otherwise objects that are close in size to sampling rate
// will be under-sampled, because we consistently discard this remainder.
@@ -315,107 +308,6 @@ runtime_profilealloc(void *v, uintptr size)
runtime_MProf_Malloc(v, size);
}
-void*
-__go_alloc(uintptr size)
-{
- return runtime_mallocgc(size, 0, FlagNoInvokeGC);
-}
-
-// Free the object whose base pointer is v.
-void
-__go_free(void *v)
-{
- M *m;
- int32 sizeclass;
- MSpan *s;
- MCache *c;
- uintptr size;
-
- if(v == nil)
- return;
-
- // If you change this also change mgc0.c:/^sweep,
- // which has a copy of the guts of free.
-
- m = runtime_m();
- if(m->mallocing)
- runtime_throw("malloc/free - deadlock");
- m->mallocing = 1;
-
- if(!runtime_mlookup(v, nil, nil, &s)) {
- runtime_printf("free %p: not an allocated block\n", v);
- runtime_throw("free runtime_mlookup");
- }
- size = s->elemsize;
- sizeclass = s->sizeclass;
- // Objects that are smaller than TinySize can be allocated using tiny alloc,
- // if then such object is combined with an object with finalizer, we will crash.
- if(size < TinySize)
- runtime_throw("freeing too small block");
-
- if(runtime_debug.allocfreetrace)
- runtime_tracefree(v, size);
-
- // Ensure that the span is swept.
- // If we free into an unswept span, we will corrupt GC bitmaps.
- runtime_MSpan_EnsureSwept(s);
-
- if(s->specials != nil)
- runtime_freeallspecials(s, v, size);
-
- c = m->mcache;
- if(sizeclass == 0) {
- // Large object.
- s->needzero = 1;
- // Must mark v freed before calling unmarkspan and MHeap_Free:
- // they might coalesce v into other spans and change the bitmap further.
- runtime_markfreed(v);
- runtime_unmarkspan(v, 1<<PageShift);
- // NOTE(rsc,dvyukov): The original implementation of efence
- // in CL 22060046 used SysFree instead of SysFault, so that
- // the operating system would eventually give the memory
- // back to us again, so that an efence program could run
- // longer without running out of memory. Unfortunately,
- // calling SysFree here without any kind of adjustment of the
- // heap data structures means that when the memory does
- // come back to us, we have the wrong metadata for it, either in
- // the MSpan structures or in the garbage collection bitmap.
- // Using SysFault here means that the program will run out of
- // memory fairly quickly in efence mode, but at least it won't
- // have mysterious crashes due to confused memory reuse.
- // It should be possible to switch back to SysFree if we also
- // implement and then call some kind of MHeap_DeleteSpan.
- if(runtime_debug.efence)
- runtime_SysFault((void*)(s->start<<PageShift), size);
- else
- runtime_MHeap_Free(&runtime_mheap, s, 1);
- c->local_nlargefree++;
- c->local_largefree += size;
- } else {
- // Small object.
- if(size > 2*sizeof(uintptr))
- ((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
- else if(size > sizeof(uintptr))
- ((uintptr*)v)[1] = 0;
- // Must mark v freed before calling MCache_Free:
- // it might coalesce v and other blocks into a bigger span
- // and change the bitmap further.
- c->local_nsmallfree[sizeclass]++;
- c->local_cachealloc -= size;
- if(c->alloc[sizeclass] == s) {
- // We own the span, so we can just add v to the freelist
- runtime_markfreed(v);
- ((MLink*)v)->next = s->freelist;
- s->freelist = v;
- s->ref--;
- } else {
- // Someone else owns this span. Add to free queue.
- runtime_MCache_Free(c, v, sizeclass, size);
- }
- }
- m->mallocing = 0;
-}
-
int32
runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
{
@@ -475,9 +367,9 @@ runtime_purgecachedstats(MCache *c)
// Protected by either heap or GC lock.
h = &runtime_mheap;
- mstats.heap_alloc += c->local_cachealloc;
+ mstats()->heap_alloc += (intptr)c->local_cachealloc;
c->local_cachealloc = 0;
- mstats.nlookup += c->local_nlookup;
+ mstats()->nlookup += c->local_nlookup;
c->local_nlookup = 0;
h->largefree += c->local_largefree;
c->local_largefree = 0;
@@ -489,13 +381,6 @@ runtime_purgecachedstats(MCache *c)
}
}
-extern uintptr runtime_sizeof_C_MStats
- __asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats");
-
-// Size of the trailing by_size array differs between Go and C,
-// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
-// sizeof_C_MStats is what C thinks about size of Go struct.
-
// Initialized in mallocinit because it's defined in go/runtime/mem.go.
#define MaxArena32 (2U<<30)
@@ -511,8 +396,6 @@ runtime_mallocinit(void)
uint64 i;
bool reserved;
- runtime_sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
-
p = nil;
p_size = 0;
arena_size = 0;
@@ -644,9 +527,6 @@ runtime_mallocinit(void)
// Initialize the rest of the allocator.
runtime_MHeap_Init(&runtime_mheap);
runtime_m()->mcache = runtime_allocmcache();
-
- // See if it works.
- runtime_free(runtime_malloc(TinySize));
}
void*
@@ -688,7 +568,7 @@ runtime_MHeap_SysAlloc(MHeap *h, uintptr n)
if(n <= (uintptr)(h->arena_end - h->arena_used)) {
// Keep taking from our reservation.
p = h->arena_used;
- runtime_SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
+ runtime_SysMap(p, n, h->arena_reserved, &mstats()->heap_sys);
h->arena_used += n;
runtime_MHeap_MapBits(h);
runtime_MHeap_MapSpans(h);
@@ -706,14 +586,14 @@ runtime_MHeap_SysAlloc(MHeap *h, uintptr n)
// try to get memory at a location chosen by the OS
// and hope that it is in the range we allocated bitmap for.
p_size = ROUND(n, PageSize) + PageSize;
- p = runtime_SysAlloc(p_size, &mstats.heap_sys);
+ p = runtime_SysAlloc(p_size, &mstats()->heap_sys);
if(p == nil)
return nil;
if(p < h->arena_start || (uintptr)(p+p_size - h->arena_start) >= MaxArena32) {
runtime_printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
p, h->arena_start, h->arena_start+MaxArena32);
- runtime_SysFree(p, p_size, &mstats.heap_sys);
+ runtime_SysFree(p, p_size, &mstats()->heap_sys);
return nil;
}
@@ -766,7 +646,7 @@ runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
runtime_lock(&persistent);
persistent.pos = (byte*)ROUND((uintptr)persistent.pos, align);
if(persistent.pos + size > persistent.end) {
- persistent.pos = runtime_SysAlloc(PersistentAllocChunk, &mstats.other_sys);
+ persistent.pos = runtime_SysAlloc(PersistentAllocChunk, &mstats()->other_sys);
if(persistent.pos == nil) {
runtime_unlock(&persistent);
runtime_throw("runtime: cannot allocate memory");
@@ -776,10 +656,10 @@ runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
p = persistent.pos;
persistent.pos += size;
runtime_unlock(&persistent);
- if(stat != &mstats.other_sys) {
+ if(stat != &mstats()->other_sys) {
// reaccount the allocation against provided stat
runtime_xadd64(stat, size);
- runtime_xadd64(&mstats.other_sys, -(uint64)size);
+ runtime_xadd64(&mstats()->other_sys, -(uint64)size);
}
return p;
}
@@ -893,30 +773,30 @@ runtime_mal(uintptr n)
}
func new(typ *Type) (ret *uint8) {
- ret = runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
+ ret = runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&kindNoPointers ? FlagNoScan : 0);
}
static void*
-cnew(const Type *typ, intgo n, int32 objtyp)
+runtime_docnew(const Type *typ, intgo n, int32 objtyp)
{
if((objtyp&(PtrSize-1)) != objtyp)
runtime_throw("runtime: invalid objtyp");
if(n < 0 || (typ->__size > 0 && (uintptr)n > (MaxMem/typ->__size)))
runtime_panicstring("runtime: allocation size out of range");
- return runtime_mallocgc(typ->__size*n, (uintptr)typ | objtyp, typ->kind&KindNoPointers ? FlagNoScan : 0);
+ return runtime_mallocgc(typ->__size*n, (uintptr)typ | objtyp, typ->kind&kindNoPointers ? FlagNoScan : 0);
}
// same as runtime_new, but callable from C
void*
runtime_cnew(const Type *typ)
{
- return cnew(typ, 1, TypeInfo_SingleObject);
+ return runtime_docnew(typ, 1, TypeInfo_SingleObject);
}
void*
runtime_cnewarray(const Type *typ, intgo n)
{
- return cnew(typ, n, TypeInfo_Array);
+ return runtime_docnew(typ, n, TypeInfo_Array);
}
func GC() {
@@ -930,15 +810,15 @@ func SetFinalizer(obj Eface, finalizer Eface) {
const Type *fint;
const PtrType *ot;
- if(obj.__type_descriptor == nil) {
+ if((Type*)obj._type == nil) {
runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
goto throw;
}
- if((obj.__type_descriptor->kind&kindMask) != GO_PTR) {
- runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.__type_descriptor->__reflection);
+ if((((Type*)obj._type)->kind&kindMask) != GO_PTR) {
+ runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *((Type*)obj._type)->__reflection);
goto throw;
}
- ot = (const PtrType*)obj.type;
+ ot = (const PtrType*)obj._type;
// As an implementation detail we do not run finalizers for zero-sized objects,
// because we use &runtime_zerobase for all such allocations.
if(ot->__element_type != nil && ot->__element_type->__size == 0)
@@ -950,49 +830,53 @@ func SetFinalizer(obj Eface, finalizer Eface) {
// runtime.SetFinalizer(Foo, nil)
// }
// See issue 7656.
- if((byte*)obj.__object < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.__object)
+ if((byte*)obj.data < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.data)
return;
- if(!runtime_mlookup(obj.__object, &base, &size, nil) || obj.__object != base) {
+ if(!runtime_mlookup(obj.data, &base, &size, nil) || obj.data != base) {
// As an implementation detail we allow to set finalizers for an inner byte
// of an object if it could come from tiny alloc (see mallocgc for details).
- if(ot->__element_type == nil || (ot->__element_type->kind&KindNoPointers) == 0 || ot->__element_type->__size >= TinySize) {
- runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.__object);
+ if(ot->__element_type == nil || (ot->__element_type->kind&kindNoPointers) == 0 || ot->__element_type->__size >= TinySize) {
+ runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data);
goto throw;
}
}
- if(finalizer.__type_descriptor != nil) {
+ if((Type*)finalizer._type != nil) {
runtime_createfing();
- if((finalizer.__type_descriptor->kind&kindMask) != GO_FUNC)
+ if((((Type*)finalizer._type)->kind&kindMask) != GO_FUNC)
goto badfunc;
- ft = (const FuncType*)finalizer.__type_descriptor;
+ ft = (const FuncType*)finalizer._type;
if(ft->__dotdotdot || ft->__in.__count != 1)
goto badfunc;
fint = *(Type**)ft->__in.__values;
- if(__go_type_descriptors_equal(fint, obj.__type_descriptor)) {
+ if(__go_type_descriptors_equal(fint, (Type*)obj._type)) {
// ok - same type
- } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || obj.type->__uncommon == nil || obj.type->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj.type)->__element_type)) {
+ } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || ((Type*)obj._type)->__uncommon == nil || ((Type*)obj._type)->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj._type)->__element_type)) {
// ok - not same type, but both pointers,
// one or the other is unnamed, and same element type, so assignable.
} else if((fint->kind&kindMask) == GO_INTERFACE && ((const InterfaceType*)fint)->__methods.__count == 0) {
// ok - satisfies empty interface
- } else if((fint->kind&kindMask) == GO_INTERFACE && __go_convert_interface_2(fint, obj.__type_descriptor, 1) != nil) {
+ } else if((fint->kind&kindMask) == GO_INTERFACE && getitab(fint, (Type*)obj._type, true) != nil) {
// ok - satisfies non-empty interface
} else
goto badfunc;
- ot = (const PtrType*)obj.__type_descriptor;
- if(!runtime_addfinalizer(obj.__object, *(FuncVal**)finalizer.__object, ft, ot)) {
+ ot = (const PtrType*)obj._type;
+ if(!runtime_addfinalizer(obj.data, *(FuncVal**)finalizer.data, ft, ot)) {
runtime_printf("runtime.SetFinalizer: finalizer already set\n");
goto throw;
}
} else {
// NOTE: asking to remove a finalizer when there currently isn't one set is OK.
- runtime_removefinalizer(obj.__object);
+ runtime_removefinalizer(obj.data);
}
return;
badfunc:
- runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *obj.__type_descriptor->__reflection, *finalizer.__type_descriptor->__reflection);
+ runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *((Type*)obj._type)->__reflection, *((Type*)finalizer._type)->__reflection);
throw:
runtime_throw("runtime.SetFinalizer");
}
+
+func KeepAlive(x Eface) {
+ USED(x);
+}
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
index 065f74a9b5..00e4166d81 100644
--- a/libgo/runtime/malloc.h
+++ b/libgo/runtime/malloc.h
@@ -82,11 +82,11 @@
typedef struct MCentral MCentral;
typedef struct MHeap MHeap;
-typedef struct MSpan MSpan;
-typedef struct MStats MStats;
-typedef struct MLink MLink;
-typedef struct MTypes MTypes;
-typedef struct GCStats GCStats;
+typedef struct mspan MSpan;
+typedef struct mstats MStats;
+typedef struct mlink MLink;
+typedef struct mtypes MTypes;
+typedef struct gcstats GCStats;
enum
{
@@ -100,10 +100,10 @@ enum
{
// Computed constant. The definition of MaxSmallSize and the
// algorithm in msize.c produce some number of different allocation
- // size classes. NumSizeClasses is that number. It's needed here
+ // size classes. _NumSizeClasses is that number. It's needed here
// because there are static arrays of this length; when msize runs its
// size choosing algorithm it double-checks that NumSizeClasses agrees.
- NumSizeClasses = 67,
+ // _NumSizeClasses is defined in runtime2.go as 67.
// Tunable constants.
MaxSmallSize = 32<<10,
@@ -132,12 +132,6 @@ enum
#else
MHeapMap_Bits = 32 - PageShift,
#endif
-
- // Max number of threads to run garbage collection.
- // 2, 3, and 4 are all plausible maximums depending
- // on the hardware details of the machine. The garbage
- // collector scales well to 8 cpus.
- MaxGcproc = 8,
};
// Maximum memory allocation size, a hint for callers.
@@ -148,13 +142,6 @@ enum
#else
#define MaxMem ((uintptr)-1)
#endif
-
-// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
-struct MLink
-{
- MLink *next;
-};
-
// SysAlloc obtains a large chunk of zeroed memory from the
// operating system, typically on the order of a hundred kilobytes
// or a megabyte.
@@ -191,8 +178,10 @@ struct MLink
// SysFault marks a (already SysAlloc'd) region to fault
// if accessed. Used only for debugging the runtime.
-void* runtime_SysAlloc(uintptr nbytes, uint64 *stat);
-void runtime_SysFree(void *v, uintptr nbytes, uint64 *stat);
+void* runtime_SysAlloc(uintptr nbytes, uint64 *stat)
+ __asm__ (GOSYM_PREFIX "runtime.sysAlloc");
+void runtime_SysFree(void *v, uintptr nbytes, uint64 *stat)
+ __asm__ (GOSYM_PREFIX "runtime.sysFree");
void runtime_SysUnused(void *v, uintptr nbytes);
void runtime_SysUsed(void *v, uintptr nbytes);
void runtime_SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
@@ -223,68 +212,15 @@ void runtime_FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*
void* runtime_FixAlloc_Alloc(FixAlloc *f);
void runtime_FixAlloc_Free(FixAlloc *f, void *p);
-
-// Statistics.
-// Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
-struct MStats
-{
- // General statistics.
- uint64 alloc; // bytes allocated and still in use
- uint64 total_alloc; // bytes allocated (even if freed)
- uint64 sys; // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
- uint64 nlookup; // number of pointer lookups
- uint64 nmalloc; // number of mallocs
- uint64 nfree; // number of frees
-
- // Statistics about malloc heap.
- // protected by mheap.Lock
- uint64 heap_alloc; // bytes allocated and still in use
- uint64 heap_sys; // bytes obtained from system
- uint64 heap_idle; // bytes in idle spans
- uint64 heap_inuse; // bytes in non-idle spans
- uint64 heap_released; // bytes released to the OS
- uint64 heap_objects; // total number of allocated objects
-
- // Statistics about allocation of low-level fixed-size structures.
- // Protected by FixAlloc locks.
- uint64 stacks_inuse; // bootstrap stacks
- uint64 stacks_sys;
- uint64 mspan_inuse; // MSpan structures
- uint64 mspan_sys;
- uint64 mcache_inuse; // MCache structures
- uint64 mcache_sys;
- uint64 buckhash_sys; // profiling bucket hash table
- uint64 gc_sys;
- uint64 other_sys;
-
- // Statistics about garbage collector.
- // Protected by mheap or stopping the world during GC.
- uint64 next_gc; // next GC (in heap_alloc time)
- uint64 last_gc; // last GC (in absolute time)
- uint64 pause_total_ns;
- uint64 pause_ns[256];
- uint64 pause_end[256];
- uint32 numgc;
- float64 gc_cpu_fraction;
- bool enablegc;
- bool debuggc;
-
- // Statistics about allocation size classes.
- struct {
- uint32 size;
- uint64 nmalloc;
- uint64 nfree;
- } by_size[NumSizeClasses];
-};
-
-extern MStats mstats
- __asm__ (GOSYM_PREFIX "runtime.memStats");
-void runtime_updatememstats(GCStats *stats);
+extern MStats *mstats(void)
+ __asm__ (GOSYM_PREFIX "runtime.getMstats");
+void runtime_updatememstats(GCStats *stats)
+ __asm__ (GOSYM_PREFIX "runtime.updatememstats");
// Size classes. Computed and initialized by InitSizes.
//
// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
-// 1 <= sizeclass < NumSizeClasses, for n.
+// 1 <= sizeclass < _NumSizeClasses, for n.
// Size class 0 is reserved to mean "not small".
//
// class_to_size[i] = largest size in class i
@@ -292,42 +228,16 @@ void runtime_updatememstats(GCStats *stats);
// making new objects in class i
int32 runtime_SizeToClass(int32);
-uintptr runtime_roundupsize(uintptr);
-extern int32 runtime_class_to_size[NumSizeClasses];
-extern int32 runtime_class_to_allocnpages[NumSizeClasses];
+uintptr runtime_roundupsize(uintptr)
+ __asm__(GOSYM_PREFIX "runtime.roundupsize");
+extern int32 runtime_class_to_size[_NumSizeClasses];
+extern int32 runtime_class_to_allocnpages[_NumSizeClasses];
extern int8 runtime_size_to_class8[1024/8 + 1];
extern int8 runtime_size_to_class128[(MaxSmallSize-1024)/128 + 1];
extern void runtime_InitSizes(void);
-typedef struct MCacheList MCacheList;
-struct MCacheList
-{
- MLink *list;
- uint32 nlist;
-};
-
-// Per-thread (in Go, per-P) cache for small objects.
-// No locking needed because it is per-thread (per-P).
-struct MCache
-{
- // The following members are accessed on every malloc,
- // so they are grouped here for better caching.
- int32 next_sample; // trigger heap sample after allocating this many bytes
- intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
- // Allocator cache for tiny objects w/o pointers.
- // See "Tiny allocator" comment in malloc.goc.
- byte* tiny;
- uintptr tinysize;
- // The rest is not accessed on every malloc.
- MSpan* alloc[NumSizeClasses]; // spans to allocate from
- MCacheList free[NumSizeClasses];// lists of explicitly freed objects
- // Local allocator stats, flushed during GC.
- uintptr local_nlookup; // number of pointer lookups
- uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize)
- uintptr local_nlargefree; // number of frees for large objects (>MaxSmallSize)
- uintptr local_nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
-};
+typedef struct mcachelist MCacheList;
MSpan* runtime_MCache_Refill(MCache *c, int32 sizeclass);
void runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size);
@@ -364,11 +274,6 @@ enum
MTypes_Words = 2,
MTypes_Bytes = 3,
};
-struct MTypes
-{
- byte compression; // one of MTypes_*
- uintptr data;
-};
enum
{
@@ -380,13 +285,7 @@ enum
// if that happens.
};
-typedef struct Special Special;
-struct Special
-{
- Special* next; // linked list in span
- uint16 offset; // span offset of object
- byte kind; // kind of Special
-};
+typedef struct special Special;
// The described object has a finalizer set for it.
typedef struct SpecialFinalizer SpecialFinalizer;
@@ -399,7 +298,7 @@ struct SpecialFinalizer
};
// The described object is being heap profiled.
-typedef struct Bucket Bucket; // from mprof.goc
+typedef struct bucket Bucket; // from mprof.go
typedef struct SpecialProfile SpecialProfile;
struct SpecialProfile
{
@@ -415,33 +314,6 @@ enum
MSpanListHead,
MSpanDead,
};
-struct MSpan
-{
- MSpan *next; // in a span linked list
- MSpan *prev; // in a span linked list
- PageID start; // starting page number
- uintptr npages; // number of pages in span
- MLink *freelist; // list of free objects
- // sweep generation:
- // if sweepgen == h->sweepgen - 2, the span needs sweeping
- // if sweepgen == h->sweepgen - 1, the span is currently being swept
- // if sweepgen == h->sweepgen, the span is swept and ready to use
- // h->sweepgen is incremented by 2 after every GC
- uint32 sweepgen;
- uint16 ref; // capacity - number of objects in freelist
- uint8 sizeclass; // size class
- bool incache; // being used by an MCache
- uint8 state; // MSpanInUse etc
- uint8 needzero; // needs to be zeroed before allocation
- uintptr elemsize; // computed from sizeclass or from npages
- int64 unusedsince; // First time spotted by GC in MSpanFree state
- uintptr npreleased; // number of pages released to the OS
- byte *limit; // end of data in span
- MTypes types; // types of allocated objects in this span
- Lock specialLock; // guards specials list
- Special *specials; // linked list of special records sorted by offset.
- MLink *freebuf; // objects freed explicitly, not incorporated into freelist yet
-};
void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
void runtime_MSpan_EnsureSwept(MSpan *span);
@@ -463,7 +335,7 @@ struct MCentral
Lock;
int32 sizeclass;
MSpan nonempty; // list of spans with a free object
- MSpan empty; // list of spans with no free objects (or cached in an MCache)
+ MSpan mempty; // list of spans with no free objects (or cached in an MCache)
int32 nfree; // # of objects available in nonempty spans
};
@@ -509,7 +381,7 @@ struct MHeap
struct {
MCentral;
byte pad[64];
- } central[NumSizeClasses];
+ } central[_NumSizeClasses];
FixAlloc spanalloc; // allocator for Span*
FixAlloc cachealloc; // allocator for MCache*
@@ -520,7 +392,7 @@ struct MHeap
// Malloc stats.
uint64 largefree; // bytes freed for large objects (>MaxSmallSize)
uint64 nlargefree; // number of frees for large objects (>MaxSmallSize)
- uint64 nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
+ uint64 nsmallfree[_NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
};
extern MHeap runtime_mheap;
@@ -537,7 +409,8 @@ void runtime_MHeap_Scavenger(void*);
void runtime_MHeap_SplitSpan(MHeap *h, MSpan *s);
void* runtime_mallocgc(uintptr size, uintptr typ, uint32 flag);
-void* runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat);
+void* runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
+ __asm__(GOSYM_PREFIX "runtime.persistentalloc");
int32 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s);
void runtime_gc(int32 force);
uintptr runtime_sweepone(void);
@@ -550,11 +423,16 @@ extern int32 runtime_checking;
void runtime_markspan(void *v, uintptr size, uintptr n, bool leftover);
void runtime_unmarkspan(void *v, uintptr size);
void runtime_purgecachedstats(MCache*);
-void* runtime_cnew(const Type*);
-void* runtime_cnewarray(const Type*, intgo);
-void runtime_tracealloc(void*, uintptr, uintptr);
-void runtime_tracefree(void*, uintptr);
-void runtime_tracegc(void);
+void* runtime_cnew(const Type*)
+ __asm__(GOSYM_PREFIX "runtime.newobject");
+void* runtime_cnewarray(const Type*, intgo)
+ __asm__(GOSYM_PREFIX "runtime.newarray");
+void runtime_tracealloc(void*, uintptr, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.tracealloc");
+void runtime_tracefree(void*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.tracefree");
+void runtime_tracegc(void)
+ __asm__ (GOSYM_PREFIX "runtime.tracegc");
uintptr runtime_gettype(void*);
@@ -576,19 +454,28 @@ struct Obj
uintptr ti; // type info
};
-void runtime_MProf_Malloc(void*, uintptr);
-void runtime_MProf_Free(Bucket*, uintptr, bool);
-void runtime_MProf_GC(void);
-void runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr));
-int32 runtime_gcprocs(void);
-void runtime_helpgc(int32 nproc);
-void runtime_gchelper(void);
+void runtime_MProf_Malloc(void*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.mProf_Malloc");
+void runtime_MProf_Free(Bucket*, uintptr, bool)
+ __asm__ (GOSYM_PREFIX "runtime.mProf_Free");
+void runtime_MProf_GC(void)
+ __asm__ (GOSYM_PREFIX "runtime.mProf_GC");
+void runtime_iterate_memprof(FuncVal* callback)
+ __asm__ (GOSYM_PREFIX "runtime.iterate_memprof");
+int32 runtime_gcprocs(void)
+ __asm__ (GOSYM_PREFIX "runtime.gcprocs");
+void runtime_helpgc(int32 nproc)
+ __asm__ (GOSYM_PREFIX "runtime.helpgc");
+void runtime_gchelper(void)
+ __asm__ (GOSYM_PREFIX "runtime.gchelper");
void runtime_createfing(void);
-G* runtime_wakefing(void);
+G* runtime_wakefing(void)
+ __asm__ (GOSYM_PREFIX "runtime.wakefing");
extern bool runtime_fingwait;
extern bool runtime_fingwake;
-void runtime_setprofilebucket(void *p, Bucket *b);
+void runtime_setprofilebucket(void *p, Bucket *b)
+ __asm__ (GOSYM_PREFIX "runtime.setprofilebucket");
struct __go_func_type;
struct __go_ptr_type;
@@ -647,14 +534,11 @@ void runtime_gc_g_ptr(Eface*);
void runtime_gc_itab_ptr(Eface*);
void runtime_memorydump(void);
-int32 runtime_setgcpercent(int32);
+int32 runtime_setgcpercent(int32)
+ __asm__ (GOSYM_PREFIX "runtime.setgcpercent");
// Value we use to mark dead pointers when GODEBUG=gcdead=1.
#define PoisonGC ((uintptr)0xf969696969696969ULL)
#define PoisonStack ((uintptr)0x6868686868686868ULL)
struct Workbuf;
-void runtime_MProf_Mark(struct Workbuf**, void (*)(struct Workbuf**, Obj));
-void runtime_proc_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
-void runtime_time_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
-void runtime_netpoll_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
diff --git a/libgo/runtime/map.goc b/libgo/runtime/map.goc
deleted file mode 100644
index e4b8456dc3..0000000000
--- a/libgo/runtime/map.goc
+++ /dev/null
@@ -1,72 +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
-#include "runtime.h"
-#include "map.h"
-
-typedef struct __go_map Hmap;
-typedef struct __go_hash_iter hiter;
-
-/* Access a value in a map, returning a value and a presence indicator. */
-
-func mapaccess2(t *MapType, h *Hmap, key *byte, val *byte) (present bool) {
- byte *mapval;
- size_t valsize;
-
- mapval = __go_map_index(h, key, 0);
- valsize = t->__val_type->__size;
- if (mapval == nil) {
- __builtin_memset(val, 0, valsize);
- present = 0;
- } else {
- __builtin_memcpy(val, mapval, valsize);
- present = 1;
- }
-}
-
-/* Optionally assign a value to a map (m[k] = v, p). */
-
-func mapassign2(h *Hmap, key *byte, val *byte, p bool) {
- if (!p) {
- __go_map_delete(h, key);
- } else {
- byte *mapval;
- size_t valsize;
-
- mapval = __go_map_index(h, key, 1);
- valsize = h->__descriptor->__map_descriptor->__val_type->__size;
- __builtin_memcpy(mapval, val, valsize);
- }
-}
-
-/* Delete a key from a map. */
-
-func mapdelete(h *Hmap, key *byte) {
- __go_map_delete(h, key);
-}
-
-/* Initialize a range over a map. */
-
-func mapiterinit(h *Hmap, it *hiter) {
- __go_mapiterinit(h, it);
-}
-
-/* Move to the next iteration, updating *HITER. */
-
-func mapiternext(it *hiter) {
- __go_mapiternext(it);
-}
-
-/* Get the key of the current iteration. */
-
-func mapiter1(it *hiter, key *byte) {
- __go_mapiter1(it, key);
-}
-
-/* Get the key and value of the current iteration. */
-
-func mapiter2(it *hiter, key *byte, val *byte) {
- __go_mapiter2(it, key, val);
-}
diff --git a/libgo/runtime/map.h b/libgo/runtime/map.h
deleted file mode 100644
index 0c587bb2af..0000000000
--- a/libgo/runtime/map.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* map.h -- the map type for Go.
-
- Copyright 2009 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "go-type.h"
-
-/* A map descriptor is what we need to manipulate the map. This is
- constant for a given map type. */
-
-struct __go_map_descriptor
-{
- /* A pointer to the type descriptor for the type of the map itself. */
- const struct __go_map_type *__map_descriptor;
-
- /* A map entry is a struct with three fields:
- map_entry_type *next_entry;
- key_type key;
- value_type value;
- This is the size of that struct. */
- uintptr_t __entry_size;
-
- /* The offset of the key field in a map entry struct. */
- uintptr_t __key_offset;
-
- /* The offset of the value field in a map entry struct (the value
- field immediately follows the key field, but there may be some
- bytes inserted for alignment). */
- uintptr_t __val_offset;
-};
-
-struct __go_map
-{
- /* The constant descriptor for this map. */
- const struct __go_map_descriptor *__descriptor;
-
- /* The number of elements in the hash table. */
- uintptr_t __element_count;
-
- /* The number of entries in the __buckets array. */
- uintptr_t __bucket_count;
-
- /* Each bucket is a pointer to a linked list of map entries. */
- void **__buckets;
-};
-
-/* For a map iteration the compiled code will use a pointer to an
- iteration structure. The iteration structure will be allocated on
- the stack. The Go code must allocate at least enough space. */
-
-struct __go_hash_iter
-{
- /* A pointer to the current entry. This will be set to NULL when
- the range has completed. The Go will test this field, so it must
- be the first one in the structure. */
- const void *entry;
- /* The map we are iterating over. */
- const struct __go_map *map;
- /* A pointer to the next entry in the current bucket. This permits
- deleting the current entry. This will be NULL when we have seen
- all the entries in the current bucket. */
- const void *next_entry;
- /* The bucket index of the current and next entry. */
- uintptr_t bucket;
-};
-
-extern struct __go_map *__go_new_map (const struct __go_map_descriptor *,
- uintptr_t);
-
-extern uintptr_t __go_map_next_prime (uintptr_t);
-
-extern void *__go_map_index (struct __go_map *, const void *, _Bool);
-
-extern void __go_map_delete (struct __go_map *, const void *);
-
-extern void __go_mapiterinit (const struct __go_map *, struct __go_hash_iter *);
-
-extern void __go_mapiternext (struct __go_hash_iter *);
-
-extern void __go_mapiter1 (struct __go_hash_iter *it, unsigned char *key);
-
-extern void __go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
- unsigned char *val);
diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c
index 746711a0d3..46684bc824 100644
--- a/libgo/runtime/mcache.c
+++ b/libgo/runtime/mcache.c
@@ -27,7 +27,7 @@ runtime_allocmcache(void)
c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
runtime_unlock(&runtime_mheap);
runtime_memclr((byte*)c, sizeof(*c));
- for(i = 0; i < NumSizeClasses; i++)
+ for(i = 0; i < _NumSizeClasses; i++)
c->alloc[i] = &emptymspan;
// Set first allocation sample size.
@@ -35,7 +35,7 @@ runtime_allocmcache(void)
if(rate > 0x3fffffff) // make 2*rate not overflow
rate = 0x3fffffff;
if(rate != 0)
- c->next_sample = runtime_fastrand1() % (2*rate);
+ c->next_sample = runtime_fastrand() % (2*rate);
return c;
}
@@ -115,7 +115,7 @@ runtime_MCache_ReleaseAll(MCache *c)
MSpan *s;
MCacheList *l;
- for(i=0; i<NumSizeClasses; i++) {
+ for(i=0; i<_NumSizeClasses; i++) {
s = c->alloc[i];
if(s != &emptymspan) {
runtime_MCentral_UncacheSpan(&runtime_mheap.central[i], s);
diff --git a/libgo/runtime/mcentral.c b/libgo/runtime/mcentral.c
index e41a83fbf0..491cac5330 100644
--- a/libgo/runtime/mcentral.c
+++ b/libgo/runtime/mcentral.c
@@ -8,7 +8,7 @@
//
// The MCentral doesn't actually contain the list of free objects; the MSpan does.
// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
-// and those that are completely allocated (c->empty).
+// and those that are completely allocated (c->mempty).
//
// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
// into sections of class_to_transfercount[sizeclass] objects
@@ -28,7 +28,7 @@ runtime_MCentral_Init(MCentral *c, int32 sizeclass)
{
c->sizeclass = sizeclass;
runtime_MSpanList_Init(&c->nonempty);
- runtime_MSpanList_Init(&c->empty);
+ runtime_MSpanList_Init(&c->mempty);
}
// Allocate a span to use in an MCache.
@@ -58,13 +58,13 @@ retry:
goto havespan;
}
- for(s = c->empty.next; s != &c->empty; s = s->next) {
+ for(s = c->mempty.next; s != &c->mempty; s = s->next) {
if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) {
// we have an empty span that requires sweeping,
// sweep it and see if we can free some space in it
runtime_MSpanList_Remove(s);
// swept spans are at the end of the list
- runtime_MSpanList_InsertBack(&c->empty, s);
+ runtime_MSpanList_InsertBack(&c->mempty, s);
runtime_unlock(c);
runtime_MSpan_Sweep(s);
runtime_lock(c);
@@ -96,7 +96,7 @@ havespan:
runtime_throw("freelist empty");
c->nfree -= n;
runtime_MSpanList_Remove(s);
- runtime_MSpanList_InsertBack(&c->empty, s);
+ runtime_MSpanList_InsertBack(&c->mempty, s);
s->incache = true;
runtime_unlock(c);
return s;
@@ -272,7 +272,7 @@ MCentral_Grow(MCentral *c)
// Carve span into sequence of blocks.
tailp = &s->freelist;
p = (byte*)(s->start << PageShift);
- s->limit = p + size*n;
+ s->limit = (uintptr)(p + size*n);
for(i=0; i<n; i++) {
v = (MLink*)p;
*tailp = v;
diff --git a/libgo/runtime/mem_posix_memalign.c b/libgo/runtime/mem_posix_memalign.c
index 8acdf07057..853b5c7ae8 100644
--- a/libgo/runtime/mem_posix_memalign.c
+++ b/libgo/runtime/mem_posix_memalign.c
@@ -9,7 +9,7 @@ runtime_SysAlloc(uintptr n)
{
void *p;
- mstats.sys += n;
+ mstats()->sys += n;
errno = posix_memalign(&p, PageSize, n);
if (errno > 0) {
perror("posix_memalign");
@@ -29,7 +29,7 @@ runtime_SysUnused(void *v, uintptr n)
void
runtime_SysFree(void *v, uintptr n)
{
- mstats.sys -= n;
+ mstats()->sys -= n;
free(v);
}
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index d7d0b27ba9..fc5424149e 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -7,7 +7,7 @@
// GC is:
// - mark&sweep
// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
-// - parallel (up to MaxGcproc threads)
+// - parallel (up to _MaxGcproc threads)
// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
// - non-moving/non-compacting
// - full (non-partial)
@@ -56,22 +56,16 @@
#include "arch.h"
#include "malloc.h"
#include "mgc0.h"
-#include "chan.h"
#include "go-type.h"
// Map gccgo field names to gc field names.
// Slice aka __go_open_array.
#define array __values
#define cap __capacity
-// Iface aka __go_interface
-#define tab __methods
// Hmap aka __go_map
typedef struct __go_map Hmap;
// Type aka __go_type_descriptor
#define string __reflection
-#define KindPtr GO_PTR
-#define KindNoPointers GO_NO_POINTERS
-#define kindMask GO_CODE_MASK
// PtrType aka __go_ptr_type
#define elem __element_type
@@ -130,6 +124,7 @@ clearpools(void)
{
P *p, **pp;
MCache *c;
+ Defer *d, *dlink;
// clear sync.Pool's
if(poolcleanup != nil) {
@@ -144,25 +139,18 @@ clearpools(void)
c->tiny = nil;
c->tinysize = 0;
}
- // clear defer pools
- p->deferpool = nil;
}
-}
-// Holding worldsema grants an M the right to try to stop the world.
-// The procedure is:
-//
-// runtime_semacquire(&runtime_worldsema);
-// m->gcing = 1;
-// runtime_stoptheworld();
-//
-// ... do stuff ...
-//
-// m->gcing = 0;
-// runtime_semrelease(&runtime_worldsema);
-// runtime_starttheworld();
-//
-uint32 runtime_worldsema = 1;
+ // Clear central defer pools.
+ // Leave per-P pools alone, they have strictly bounded size.
+ runtime_lock(&runtime_sched->deferlock);
+ for(d = runtime_sched->deferpool; d != nil; d = dlink) {
+ dlink = d->link;
+ d->link = nil;
+ }
+ runtime_sched->deferpool = nil;
+ runtime_unlock(&runtime_sched->deferlock);
+}
typedef struct Workbuf Workbuf;
struct Workbuf
@@ -216,7 +204,7 @@ static void addstackroots(G *gp, Workbuf **wbufp);
static struct {
uint64 full; // lock-free list of full blocks
- uint64 empty; // lock-free list of empty blocks
+ uint64 wempty; // lock-free list of empty blocks
byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
uint32 nproc;
int64 tstart;
@@ -321,7 +309,7 @@ markonly(const void *obj)
x = k;
x -= (uintptr)runtime_mheap.arena_start>>PageShift;
s = runtime_mheap.spans[x];
- if(s == nil || k < s->start || (const byte*)obj >= s->limit || s->state != MSpanInUse)
+ if(s == nil || k < s->start || (uintptr)obj >= s->limit || s->state != MSpanInUse)
return false;
p = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass == 0) {
@@ -401,7 +389,7 @@ struct BufferList
uint32 busy;
byte pad[CacheLineSize];
};
-static BufferList bufferList[MaxGcproc];
+static BufferList bufferList[_MaxGcproc];
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
@@ -517,7 +505,7 @@ flushptrbuf(Scanbuf *sbuf)
x = k;
x -= (uintptr)arena_start>>PageShift;
s = runtime_mheap.spans[x];
- if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
+ if(s == nil || k < s->start || (uintptr)obj >= s->limit || s->state != MSpanInUse)
continue;
p = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass == 0) {
@@ -651,8 +639,8 @@ static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
static uintptr chanProg[2] = {0, GC_CHAN};
// Local variables of a program fragment or loop
-typedef struct Frame Frame;
-struct Frame {
+typedef struct GCFrame GCFrame;
+struct GCFrame {
uintptr count, elemsize, b;
const uintptr *loop_or_ret;
};
@@ -731,7 +719,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
const Type *t, *et;
Slice *sliceptr;
String *stringptr;
- Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
+ GCFrame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
BufferList *scanbuffers;
Scanbuf sbuf;
Eface *eface;
@@ -926,12 +914,12 @@ scanblock(Workbuf *wbuf, bool keepworking)
eface = (Eface*)(stack_top.b + pc[1]);
pc += 2;
if(Debug > 2)
- runtime_printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->__type_descriptor, eface->__object);
- if(eface->__type_descriptor == nil)
+ runtime_printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->_type, eface->data);
+ if(eface->_type == nil)
continue;
// eface->type
- t = eface->__type_descriptor;
+ t = eface->_type;
if((const byte*)t >= arena_start && (const byte*)t < arena_used) {
union { const Type *tc; Type *tr; } u;
u.tc = t;
@@ -940,23 +928,23 @@ scanblock(Workbuf *wbuf, bool keepworking)
flushptrbuf(&sbuf);
}
- // eface->__object
- if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
+ // eface->data
+ if((byte*)eface->data >= arena_start && (byte*)eface->data < arena_used) {
if(__go_is_pointer_type(t)) {
- if((t->__code & KindNoPointers))
+ if((t->__code & kindNoPointers))
continue;
- obj = eface->__object;
- if((t->__code & kindMask) == KindPtr) {
+ obj = eface->data;
+ if((t->__code & kindMask) == kindPtr) {
// Only use type information if it is a pointer-containing type.
// This matches the GC programs written by cmd/gc/reflect.c's
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
- if(!(et->__code & KindNoPointers))
+ if(!(et->__code & kindNoPointers))
objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
- obj = eface->__object;
+ obj = eface->data;
objti = (uintptr)t->__gc;
}
}
@@ -966,7 +954,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
iface = (Iface*)(stack_top.b + pc[1]);
pc += 2;
if(Debug > 2)
- runtime_printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], iface->__methods[0], nil, iface->__object);
+ runtime_printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], *(Type**)iface->tab, nil, iface->data);
if(iface->tab == nil)
continue;
@@ -978,23 +966,23 @@ scanblock(Workbuf *wbuf, bool keepworking)
}
// iface->data
- if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
- t = (const Type*)iface->tab[0];
+ if((byte*)iface->data >= arena_start && (byte*)iface->data < arena_used) {
+ t = *(Type**)iface->tab;
if(__go_is_pointer_type(t)) {
- if((t->__code & KindNoPointers))
+ if((t->__code & kindNoPointers))
continue;
- obj = iface->__object;
- if((t->__code & kindMask) == KindPtr) {
+ obj = iface->data;
+ if((t->__code & kindMask) == kindPtr) {
// Only use type information if it is a pointer-containing type.
// This matches the GC programs written by cmd/gc/reflect.c's
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
- if(!(et->__code & KindNoPointers))
+ if(!(et->__code & kindNoPointers))
objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
- obj = iface->__object;
+ obj = iface->data;
objti = (uintptr)t->__gc;
}
}
@@ -1057,7 +1045,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
// Stack push.
*stack_ptr-- = stack_top;
- stack_top = (Frame){count, elemsize, i, pc};
+ stack_top = (GCFrame){count, elemsize, i, pc};
continue;
case GC_ARRAY_NEXT:
@@ -1074,7 +1062,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
case GC_CALL:
// Stack push.
*stack_ptr-- = stack_top;
- stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
+ stack_top = (GCFrame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction
continue;
@@ -1101,7 +1089,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
}
if(markonly(chan)) {
chantype = (ChanType*)pc[2];
- if(!(chantype->elem->__code & KindNoPointers)) {
+ if(!(chantype->elem->__code & kindNoPointers)) {
// Start chanProg.
chan_ret = pc+3;
pc = chanProg+1;
@@ -1114,16 +1102,14 @@ scanblock(Workbuf *wbuf, bool keepworking)
case GC_CHAN:
// There are no heap pointers in struct Hchan,
// so we can ignore the leading sizeof(Hchan) bytes.
- if(!(chantype->elem->__code & KindNoPointers)) {
- // Channel's buffer follows Hchan immediately in memory.
- // Size of buffer (cap(c)) is second int in the chan struct.
- chancap = ((uintgo*)chan)[1];
- if(chancap > 0) {
+ if(!(chantype->elem->__code & kindNoPointers)) {
+ chancap = chan->dataqsiz;
+ if(chancap > 0 && markonly(chan->buf)) {
// TODO(atom): split into two chunks so that only the
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
- *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
+ *sbuf.obj.pos++ = (Obj){chan->buf, chancap*chantype->elem->__size,
(uintptr)chantype->elem->__gc | PRECISE | LOOP};
if(sbuf.obj.pos == sbuf.obj.end)
flushobjbuf(&sbuf);
@@ -1293,14 +1279,8 @@ markroot(ParFor *desc, uint32 i)
// For gccgo we use this for all the other global roots.
enqueue1(&wbuf, (Obj){(byte*)&runtime_m0, sizeof runtime_m0, 0});
enqueue1(&wbuf, (Obj){(byte*)&runtime_g0, sizeof runtime_g0, 0});
- enqueue1(&wbuf, (Obj){(byte*)&runtime_allg, sizeof runtime_allg, 0});
- enqueue1(&wbuf, (Obj){(byte*)&runtime_allm, sizeof runtime_allm, 0});
enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
- runtime_proc_scan(&wbuf, enqueue1);
- runtime_MProf_Mark(&wbuf, enqueue1);
- runtime_time_scan(&wbuf, enqueue1);
- runtime_netpoll_scan(&wbuf, enqueue1);
break;
case RootFinalizers:
@@ -1352,12 +1332,12 @@ markroot(ParFor *desc, uint32 i)
default:
// the rest is scanning goroutine stacks
- if(i - RootCount >= runtime_allglen)
+ if(i - RootCount >= runtime_getallglen())
runtime_throw("markroot: bad index");
- gp = runtime_allg[i - RootCount];
+ gp = runtime_getallg(i - RootCount);
// remember when we've first observed the G blocked
// needed only to output in traceback
- if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0)
+ if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == _Gsyscall) && gp->waitsince == 0)
gp->waitsince = work.tstart;
addstackroots(gp, &wbuf);
break;
@@ -1377,13 +1357,13 @@ getempty(Workbuf *b)
{
if(b != nil)
runtime_lfstackpush(&work.full, &b->node);
- b = (Workbuf*)runtime_lfstackpop(&work.empty);
+ b = (Workbuf*)runtime_lfstackpop(&work.wempty);
if(b == nil) {
// Need to allocate.
runtime_lock(&work);
if(work.nchunk < sizeof *b) {
work.nchunk = 1<<20;
- work.chunk = runtime_SysAlloc(work.nchunk, &mstats.gc_sys);
+ work.chunk = runtime_SysAlloc(work.nchunk, &mstats()->gc_sys);
if(work.chunk == nil)
runtime_throw("runtime: cannot allocate memory");
}
@@ -1402,7 +1382,7 @@ putempty(Workbuf *b)
if(CollectStats)
runtime_xadd64(&gcstats.putempty, 1);
- runtime_lfstackpush(&work.empty, &b->node);
+ runtime_lfstackpush(&work.wempty, &b->node);
}
// Get a full work buffer off the work.full list, or return nil.
@@ -1416,7 +1396,7 @@ getfull(Workbuf *b)
runtime_xadd64(&gcstats.getfull, 1);
if(b != nil)
- runtime_lfstackpush(&work.empty, &b->node);
+ runtime_lfstackpush(&work.wempty, &b->node);
b = (Workbuf*)runtime_lfstackpop(&work.full);
if(b != nil || work.nproc == 1)
return b;
@@ -1472,17 +1452,17 @@ handoff(Workbuf *b)
static void
addstackroots(G *gp, Workbuf **wbufp)
{
- switch(gp->status){
+ switch(gp->atomicstatus){
default:
- runtime_printf("unexpected G.status %d (goroutine %p %D)\n", gp->status, gp, gp->goid);
+ runtime_printf("unexpected G.status %d (goroutine %p %D)\n", gp->atomicstatus, gp, gp->goid);
runtime_throw("mark - bad status");
- case Gdead:
+ case _Gdead:
return;
- case Grunning:
+ case _Grunning:
runtime_throw("mark - world not stopped");
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
+ case _Grunnable:
+ case _Gsyscall:
+ case _Gwaiting:
break;
}
@@ -1512,12 +1492,12 @@ addstackroots(G *gp, Workbuf **wbufp)
// the system call instead, since that won't change underfoot.
if(gp->gcstack != nil) {
sp = gp->gcstack;
- spsize = gp->gcstack_size;
- next_segment = gp->gcnext_segment;
- next_sp = gp->gcnext_sp;
- initial_sp = gp->gcinitial_sp;
+ spsize = gp->gcstacksize;
+ next_segment = gp->gcnextsegment;
+ next_sp = gp->gcnextsp;
+ initial_sp = gp->gcinitialsp;
} else {
- sp = __splitstack_find_context(&gp->stack_context[0],
+ sp = __splitstack_find_context(&gp->stackcontext[0],
&spsize, &next_segment,
&next_sp, &initial_sp);
}
@@ -1543,11 +1523,11 @@ addstackroots(G *gp, Workbuf **wbufp)
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
- bottom = (byte*)gp->gcnext_sp;
+ bottom = (byte*)gp->gcnextsp;
if(bottom == nil)
return;
}
- top = (byte*)gp->gcinitial_sp + gp->gcstack_size;
+ top = (byte*)gp->gcinitialsp + gp->gcstacksize;
if(top > bottom)
enqueue1(wbufp, (Obj){bottom, top - bottom, 0});
else
@@ -1564,7 +1544,7 @@ runtime_queuefinalizer(void *p, FuncVal *fn, const FuncType *ft, const PtrType *
runtime_lock(&finlock);
if(finq == nil || finq->cnt == finq->cap) {
if(finc == nil) {
- finc = runtime_persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
+ finc = runtime_persistentalloc(FinBlockSize, 0, &mstats()->gc_sys);
finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
finc->alllink = allfin;
allfin = finc;
@@ -1761,7 +1741,7 @@ runtime_MSpan_Sweep(MSpan *s)
runtime_MHeap_Free(&runtime_mheap, s, 1);
c->local_nlargefree++;
c->local_largefree += size;
- runtime_xadd64(&mstats.next_gc, -(uint64)(size * (gcpercent + 100)/100));
+ runtime_xadd64(&mstats()->next_gc, -(uint64)(size * (gcpercent + 100)/100));
res = true;
} else {
// Free small object.
@@ -1803,7 +1783,7 @@ runtime_MSpan_Sweep(MSpan *s)
if(nfree > 0) {
c->local_nsmallfree[cl] += nfree;
c->local_cachealloc -= nfree * size;
- runtime_xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
+ runtime_xadd64(&mstats()->next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
res = runtime_MCentral_FreeSpan(&runtime_mheap.central[cl], s, nfree, head.next, end);
//MCentral_FreeSpan updates sweepgen
}
@@ -2016,11 +1996,12 @@ runtime_updatememstats(GCStats *stats)
uint32 i;
uint64 stacks_inuse, smallfree;
uint64 *src, *dst;
+ MStats *pmstats;
if(stats)
runtime_memclr((byte*)stats, sizeof(*stats));
stacks_inuse = 0;
- for(mp=runtime_allm; mp; mp=mp->alllink) {
+ for(mp=runtime_getallm(); mp; mp=mp->alllink) {
//stacks_inuse += mp->stackinuse*FixedStack;
if(stats) {
src = (uint64*)&mp->gcstats;
@@ -2030,11 +2011,12 @@ runtime_updatememstats(GCStats *stats)
runtime_memclr((byte*)&mp->gcstats, sizeof(mp->gcstats));
}
}
- mstats.stacks_inuse = stacks_inuse;
- mstats.mcache_inuse = runtime_mheap.cachealloc.inuse;
- mstats.mspan_inuse = runtime_mheap.spanalloc.inuse;
- mstats.sys = mstats.heap_sys + mstats.stacks_sys + mstats.mspan_sys +
- mstats.mcache_sys + mstats.buckhash_sys + mstats.gc_sys + mstats.other_sys;
+ pmstats = mstats();
+ pmstats->stacks_inuse = stacks_inuse;
+ pmstats->mcache_inuse = runtime_mheap.cachealloc.inuse;
+ pmstats->mspan_inuse = runtime_mheap.spanalloc.inuse;
+ pmstats->sys = pmstats->heap_sys + pmstats->stacks_sys + pmstats->mspan_sys +
+ pmstats->mcache_sys + pmstats->buckhash_sys + pmstats->gc_sys + pmstats->other_sys;
// Calculate memory allocator stats.
// During program execution we only count number of frees and amount of freed memory.
@@ -2043,13 +2025,13 @@ runtime_updatememstats(GCStats *stats)
// Total number of mallocs is calculated as number of frees plus number of alive objects.
// Similarly, total amount of allocated memory is calculated as amount of freed memory
// plus amount of alive heap memory.
- mstats.alloc = 0;
- mstats.total_alloc = 0;
- mstats.nmalloc = 0;
- mstats.nfree = 0;
- for(i = 0; i < nelem(mstats.by_size); i++) {
- mstats.by_size[i].nmalloc = 0;
- mstats.by_size[i].nfree = 0;
+ pmstats->alloc = 0;
+ pmstats->total_alloc = 0;
+ pmstats->nmalloc = 0;
+ pmstats->nfree = 0;
+ for(i = 0; i < nelem(pmstats->by_size); i++) {
+ pmstats->by_size[i].nmalloc = 0;
+ pmstats->by_size[i].nfree = 0;
}
// Flush MCache's to MCentral.
@@ -2064,30 +2046,30 @@ runtime_updatememstats(GCStats *stats)
if(s->state != MSpanInUse)
continue;
if(s->sizeclass == 0) {
- mstats.nmalloc++;
- mstats.alloc += s->elemsize;
+ pmstats->nmalloc++;
+ pmstats->alloc += s->elemsize;
} else {
- mstats.nmalloc += s->ref;
- mstats.by_size[s->sizeclass].nmalloc += s->ref;
- mstats.alloc += s->ref*s->elemsize;
+ pmstats->nmalloc += s->ref;
+ pmstats->by_size[s->sizeclass].nmalloc += s->ref;
+ pmstats->alloc += s->ref*s->elemsize;
}
}
// Aggregate by size class.
smallfree = 0;
- mstats.nfree = runtime_mheap.nlargefree;
- for(i = 0; i < nelem(mstats.by_size); i++) {
- mstats.nfree += runtime_mheap.nsmallfree[i];
- mstats.by_size[i].nfree = runtime_mheap.nsmallfree[i];
- mstats.by_size[i].nmalloc += runtime_mheap.nsmallfree[i];
+ pmstats->nfree = runtime_mheap.nlargefree;
+ for(i = 0; i < nelem(pmstats->by_size); i++) {
+ pmstats->nfree += runtime_mheap.nsmallfree[i];
+ pmstats->by_size[i].nfree = runtime_mheap.nsmallfree[i];
+ pmstats->by_size[i].nmalloc += runtime_mheap.nsmallfree[i];
smallfree += runtime_mheap.nsmallfree[i] * runtime_class_to_size[i];
}
- mstats.nmalloc += mstats.nfree;
+ pmstats->nmalloc += pmstats->nfree;
// Calculate derived stats.
- mstats.total_alloc = mstats.alloc + runtime_mheap.largefree + smallfree;
- mstats.heap_alloc = mstats.alloc;
- mstats.heap_objects = mstats.nmalloc - mstats.nfree;
+ pmstats->total_alloc = pmstats->alloc + runtime_mheap.largefree + smallfree;
+ pmstats->heap_alloc = pmstats->alloc;
+ pmstats->heap_objects = pmstats->nmalloc - pmstats->nfree;
}
// Structure of arguments passed to function gc().
@@ -2125,11 +2107,12 @@ runtime_gc(int32 force)
G *g;
struct gc_args a;
int32 i;
+ MStats *pmstats;
// The atomic operations are not atomic if the uint64s
// are not aligned on uint64 boundaries. This has been
// a problem in the past.
- if((((uintptr)&work.empty) & 7) != 0)
+ if((((uintptr)&work.wempty) & 7) != 0)
runtime_throw("runtime: gc work buffer is misaligned");
if((((uintptr)&work.full) & 7) != 0)
runtime_throw("runtime: gc work buffer is misaligned");
@@ -2147,7 +2130,8 @@ runtime_gc(int32 force)
// while holding a lock. The next mallocgc
// without a lock will do the gc instead.
m = runtime_m();
- if(!mstats.enablegc || runtime_g() == m->g0 || m->locks > 0 || runtime_panicking)
+ pmstats = mstats();
+ if(!pmstats->enablegc || runtime_g() == m->g0 || m->locks > 0 || runtime_panicking() || m->preemptoff.len > 0)
return;
if(gcpercent == GcpercentUnknown) { // first time through
@@ -2159,11 +2143,11 @@ runtime_gc(int32 force)
if(gcpercent < 0)
return;
- runtime_semacquire(&runtime_worldsema, false);
- if(force==0 && mstats.heap_alloc < mstats.next_gc) {
+ runtime_acquireWorldsema();
+ if(force==0 && pmstats->heap_alloc < pmstats->next_gc) {
// typically threads which lost the race to grab
// worldsema exit here when gc is done.
- runtime_semrelease(&runtime_worldsema);
+ runtime_releaseWorldsema();
return;
}
@@ -2171,7 +2155,7 @@ runtime_gc(int32 force)
a.start_time = runtime_nanotime();
a.eagersweep = force >= 2;
m->gcing = 1;
- runtime_stoptheworld();
+ runtime_stopTheWorldWithSema();
clearpools();
@@ -2186,8 +2170,8 @@ runtime_gc(int32 force)
// switch to g0, call gc(&a), then switch back
g = runtime_g();
g->param = &a;
- g->status = Gwaiting;
- g->waitreason = "garbage collection";
+ g->atomicstatus = _Gwaiting;
+ g->waitreason = runtime_gostringnocopy((const byte*)"garbage collection");
runtime_mcall(mgc);
m = runtime_m();
}
@@ -2195,8 +2179,8 @@ runtime_gc(int32 force)
// all done
m->gcing = 0;
m->locks++;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
+ runtime_releaseWorldsema();
+ runtime_startTheWorldWithSema();
m->locks--;
// now that gc is done, kick off finalizer thread if needed
@@ -2214,7 +2198,7 @@ mgc(G *gp)
{
gc(gp->param);
gp->param = nil;
- gp->status = Grunning;
+ gp->atomicstatus = _Grunning;
runtime_gogo(gp);
}
@@ -2222,10 +2206,11 @@ static void
gc(struct gc_args *args)
{
M *m;
- int64 t0, t1, t2, t3, t4;
+ int64 tm0, tm1, tm2, tm3, tm4;
uint64 heap0, heap1, obj, ninstr;
GCStats stats;
uint32 i;
+ MStats *pmstats;
// Eface eface;
m = runtime_m();
@@ -2234,7 +2219,7 @@ gc(struct gc_args *args)
runtime_tracegc();
m->traceback = 2;
- t0 = args->start_time;
+ tm0 = args->start_time;
work.tstart = args->start_time;
if(CollectStats)
@@ -2242,12 +2227,12 @@ gc(struct gc_args *args)
m->locks++; // disable gc during mallocs in parforalloc
if(work.markfor == nil)
- work.markfor = runtime_parforalloc(MaxGcproc);
+ work.markfor = runtime_parforalloc(_MaxGcproc);
m->locks--;
- t1 = 0;
+ tm1 = 0;
if(runtime_debug.gctrace)
- t1 = runtime_nanotime();
+ tm1 = runtime_nanotime();
// Sweep what is not sweeped by bgsweep.
while(runtime_sweepone() != (uintptr)-1)
@@ -2256,23 +2241,23 @@ gc(struct gc_args *args)
work.nwait = 0;
work.ndone = 0;
work.nproc = runtime_gcprocs();
- runtime_parforsetup(work.markfor, work.nproc, RootCount + runtime_allglen, false, &markroot_funcval);
+ runtime_parforsetup(work.markfor, work.nproc, RootCount + runtime_getallglen(), false, &markroot_funcval);
if(work.nproc > 1) {
runtime_noteclear(&work.alldone);
runtime_helpgc(work.nproc);
}
- t2 = 0;
+ tm2 = 0;
if(runtime_debug.gctrace)
- t2 = runtime_nanotime();
+ tm2 = runtime_nanotime();
gchelperstart();
runtime_parfordo(work.markfor);
scanblock(nil, true);
- t3 = 0;
+ tm3 = 0;
if(runtime_debug.gctrace)
- t3 = runtime_nanotime();
+ tm3 = runtime_nanotime();
bufferList[m->helpgc].busy = 0;
if(work.nproc > 1)
@@ -2281,28 +2266,29 @@ gc(struct gc_args *args)
cachestats();
// next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
// estimate what was live heap size after previous GC (for tracing only)
- heap0 = mstats.next_gc*100/(gcpercent+100);
+ pmstats = mstats();
+ heap0 = pmstats->next_gc*100/(gcpercent+100);
// conservatively set next_gc to high value assuming that everything is live
// concurrent/lazy sweep will reduce this number while discovering new garbage
- mstats.next_gc = mstats.heap_alloc+(mstats.heap_alloc-runtime_stacks_sys)*gcpercent/100;
+ pmstats->next_gc = pmstats->heap_alloc+(pmstats->heap_alloc-runtime_stacks_sys)*gcpercent/100;
- t4 = runtime_nanotime();
- mstats.last_gc = runtime_unixnanotime(); // must be Unix time to make sense to user
- mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
- mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = mstats.last_gc;
- mstats.pause_total_ns += t4 - t0;
- mstats.numgc++;
- if(mstats.debuggc)
- runtime_printf("pause %D\n", t4-t0);
+ tm4 = runtime_nanotime();
+ pmstats->last_gc = runtime_unixnanotime(); // must be Unix time to make sense to user
+ pmstats->pause_ns[pmstats->numgc%nelem(pmstats->pause_ns)] = tm4 - tm0;
+ pmstats->pause_end[pmstats->numgc%nelem(pmstats->pause_end)] = pmstats->last_gc;
+ pmstats->pause_total_ns += tm4 - tm0;
+ pmstats->numgc++;
+ if(pmstats->debuggc)
+ runtime_printf("pause %D\n", tm4-tm0);
if(runtime_debug.gctrace) {
- heap1 = mstats.heap_alloc;
+ heap1 = pmstats->heap_alloc;
runtime_updatememstats(&stats);
- if(heap1 != mstats.heap_alloc) {
- runtime_printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
+ if(heap1 != pmstats->heap_alloc) {
+ runtime_printf("runtime: mstats skew: heap=%D/%D\n", heap1, pmstats->heap_alloc);
runtime_throw("mstats skew");
}
- obj = mstats.nmalloc - mstats.nfree;
+ obj = pmstats->nmalloc - pmstats->nfree;
stats.nprocyield += work.markfor->nprocyield;
stats.nosyield += work.markfor->nosyield;
@@ -2311,9 +2297,9 @@ gc(struct gc_args *args)
runtime_printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
" %d/%d/%d sweeps,"
" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
- mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
+ pmstats->numgc, work.nproc, (tm1-tm0)/1000, (tm2-tm1)/1000, (tm3-tm2)/1000, (tm4-tm3)/1000,
heap0>>20, heap1>>20, obj,
- mstats.nmalloc, mstats.nfree,
+ pmstats->nmalloc, pmstats->nfree,
sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep,
stats.nhandoff, stats.nhandoffcnt,
work.markfor->nsteal, work.markfor->nstealcnt,
@@ -2352,7 +2338,7 @@ gc(struct gc_args *args)
// Free the old cached array if necessary.
if(sweep.spans && sweep.spans != runtime_mheap.allspans)
- runtime_SysFree(sweep.spans, sweep.nspan*sizeof(sweep.spans[0]), &mstats.other_sys);
+ runtime_SysFree(sweep.spans, sweep.nspan*sizeof(sweep.spans[0]), &pmstats->other_sys);
// Cache the current array.
runtime_mheap.sweepspans = runtime_mheap.allspans;
runtime_mheap.sweepgen += 2;
@@ -2368,7 +2354,7 @@ gc(struct gc_args *args)
sweep.g = __go_go(bgsweep, nil);
else if(sweep.parked) {
sweep.parked = false;
- runtime_ready(sweep.g);
+ runtime_ready(sweep.g, 0, true);
}
runtime_unlock(&gclock);
} else {
@@ -2383,36 +2369,6 @@ gc(struct gc_args *args)
m->traceback = 0;
}
-extern uintptr runtime_sizeof_C_MStats
- __asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats");
-
-void runtime_ReadMemStats(MStats *)
- __asm__ (GOSYM_PREFIX "runtime.ReadMemStats");
-
-void
-runtime_ReadMemStats(MStats *stats)
-{
- M *m;
-
- // Have to acquire worldsema to stop the world,
- // because stoptheworld can only be used by
- // one goroutine at a time, and there might be
- // a pending garbage collection already calling it.
- runtime_semacquire(&runtime_worldsema, false);
- m = runtime_m();
- m->gcing = 1;
- runtime_stoptheworld();
- runtime_updatememstats(nil);
- // Size of the trailing by_size array differs between Go and C,
- // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
- runtime_memmove(stats, &mstats, runtime_sizeof_C_MStats);
- m->gcing = 0;
- m->locks++;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- m->locks--;
-}
-
void runtime_debug_readGCStats(Slice*)
__asm__("runtime_debug.readGCStats");
@@ -2421,30 +2377,34 @@ runtime_debug_readGCStats(Slice *pauses)
{
uint64 *p;
uint32 i, n;
+ MStats *pmstats;
// Calling code in runtime/debug should make the slice large enough.
- if((size_t)pauses->cap < nelem(mstats.pause_ns)+3)
+ pmstats = mstats();
+ if((size_t)pauses->cap < nelem(pmstats->pause_ns)+3)
runtime_throw("runtime: short slice passed to readGCStats");
// Pass back: pauses, last gc (absolute time), number of gc, total pause ns.
p = (uint64*)pauses->array;
runtime_lock(&runtime_mheap);
- n = mstats.numgc;
- if(n > nelem(mstats.pause_ns))
- n = nelem(mstats.pause_ns);
+ n = pmstats->numgc;
+ if(n > nelem(pmstats->pause_ns))
+ n = nelem(pmstats->pause_ns);
// The pause buffer is circular. The most recent pause is at
// pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
// from there to go back farther in time. We deliver the times
// most recent first (in p[0]).
- for(i=0; i<n; i++)
- p[i] = mstats.pause_ns[(mstats.numgc-1-i)%nelem(mstats.pause_ns)];
+ for(i=0; i<n; i++) {
+ p[i] = pmstats->pause_ns[(pmstats->numgc-1-i)%nelem(pmstats->pause_ns)];
+ p[n+i] = pmstats->pause_end[(pmstats->numgc-1-i)%nelem(pmstats->pause_ns)];
+ }
- p[n] = mstats.last_gc;
- p[n+1] = mstats.numgc;
- p[n+2] = mstats.pause_total_ns;
+ p[n+n] = pmstats->last_gc;
+ p[n+n+1] = pmstats->numgc;
+ p[n+n+2] = pmstats->pause_total_ns;
runtime_unlock(&runtime_mheap);
- pauses->__count = n+3;
+ pauses->__count = n+n+3;
}
int32
@@ -2468,7 +2428,7 @@ gchelperstart(void)
M *m;
m = runtime_m();
- if(m->helpgc < 0 || m->helpgc >= MaxGcproc)
+ if(m->helpgc < 0 || m->helpgc >= _MaxGcproc)
runtime_throw("gchelperstart: bad m->helpgc");
if(runtime_xchg(&bufferList[m->helpgc].busy, 1))
runtime_throw("gchelperstart: already busy");
@@ -2492,8 +2452,8 @@ runfinq(void* dummy __attribute__ ((unused)))
fb = nil;
next = nil;
i = 0;
- ef.__type_descriptor = nil;
- ef.__object = nil;
+ ef._type = nil;
+ ef.data = nil;
// force flush to memory
USED(&f);
@@ -2522,21 +2482,23 @@ runfinq(void* dummy __attribute__ ((unused)))
f = &fb->fin[i];
fint = ((const Type**)f->ft->__in.array)[0];
- if((fint->__code & kindMask) == KindPtr) {
+ if((fint->__code & kindMask) == kindPtr) {
// direct use of pointer
param = &f->arg;
} else if(((const InterfaceType*)fint)->__methods.__count == 0) {
// convert to empty interface
- ef.__type_descriptor = (const Type*)f->ot;
- ef.__object = f->arg;
+ // using memcpy as const_cast.
+ memcpy(&ef._type, &f->ot,
+ sizeof ef._type);
+ ef.data = f->arg;
param = &ef;
} else {
// convert to interface with methods
- iface.__methods = __go_convert_interface_2((const Type*)fint,
- (const Type*)f->ot,
- 1);
- iface.__object = f->arg;
- if(iface.__methods == nil)
+ iface.tab = getitab(fint,
+ (const Type*)f->ot,
+ true);
+ iface.data = f->arg;
+ if(iface.data == nil)
runtime_throw("invalid type conversion in runfinq");
param = &iface;
}
@@ -2558,8 +2520,8 @@ runfinq(void* dummy __attribute__ ((unused)))
fb = nil;
next = nil;
i = 0;
- ef.__type_descriptor = nil;
- ef.__object = nil;
+ ef._type = nil;
+ ef.data = nil;
runtime_gc(1); // trigger another gc to clean up the finalized objects, if possible
}
}
@@ -2578,6 +2540,20 @@ runtime_createfing(void)
runtime_unlock(&gclock);
}
+bool getfingwait() __asm__(GOSYM_PREFIX "runtime.getfingwait");
+bool
+getfingwait()
+{
+ return runtime_fingwait;
+}
+
+bool getfingwake() __asm__(GOSYM_PREFIX "runtime.getfingwake");
+bool
+getfingwake()
+{
+ return runtime_fingwake;
+}
+
G*
runtime_wakefing(void)
{
@@ -2751,41 +2727,6 @@ runtime_MHeap_MapBits(MHeap *h)
if(h->bitmap_mapped >= n)
return;
- runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
+ runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats()->gc_sys);
h->bitmap_mapped = n;
}
-
-// typedmemmove copies a value of type t to dst from src.
-
-extern void typedmemmove(const Type* td, void *dst, const void *src)
- __asm__ (GOSYM_PREFIX "reflect.typedmemmove");
-
-void
-typedmemmove(const Type* td, void *dst, const void *src)
-{
- runtime_memmove(dst, src, td->__size);
-}
-
-// typedslicecopy copies a slice of elemType values from src to dst,
-// returning the number of elements copied.
-
-extern intgo typedslicecopy(const Type* elem, Slice dst, Slice src)
- __asm__ (GOSYM_PREFIX "reflect.typedslicecopy");
-
-intgo
-typedslicecopy(const Type* elem, Slice dst, Slice src)
-{
- intgo n;
- void *dstp;
- void *srcp;
-
- n = dst.__count;
- if (n > src.__count)
- n = src.__count;
- if (n == 0)
- return 0;
- dstp = dst.__values;
- srcp = src.__values;
- memmove(dstp, srcp, (uintptr_t)n * elem->__size);
- return n;
-}
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
index 793915ef44..c167bdc819 100644
--- a/libgo/runtime/mheap.c
+++ b/libgo/runtime/mheap.c
@@ -36,7 +36,7 @@ RecordSpan(void *vh, byte *p)
cap = 64*1024/sizeof(all[0]);
if(cap < h->nspancap*3/2)
cap = h->nspancap*3/2;
- all = (MSpan**)runtime_SysAlloc(cap*sizeof(all[0]), &mstats.other_sys);
+ all = (MSpan**)runtime_SysAlloc(cap*sizeof(all[0]), &mstats()->other_sys);
if(all == nil)
runtime_throw("runtime: cannot allocate memory");
if(h->allspans) {
@@ -44,7 +44,7 @@ RecordSpan(void *vh, byte *p)
// Don't free the old array if it's referenced by sweep.
// See the comment in mgc0.c.
if(h->allspans != runtime_mheap.sweepspans)
- runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
+ runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats()->other_sys);
}
h->allspans = all;
h->nspancap = cap;
@@ -56,12 +56,14 @@ RecordSpan(void *vh, byte *p)
void
runtime_MHeap_Init(MHeap *h)
{
+ MStats *pmstats;
uint32 i;
- runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
- runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
- runtime_FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
- runtime_FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
+ pmstats = mstats();
+ runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &pmstats->mspan_sys);
+ runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &pmstats->mcache_sys);
+ runtime_FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &pmstats->other_sys);
+ runtime_FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &pmstats->other_sys);
// h->mapcache needs no init
for(i=0; i<nelem(h->free); i++) {
runtime_MSpanList_Init(&h->free[i]);
@@ -88,7 +90,7 @@ runtime_MHeap_MapSpans(MHeap *h)
n = ROUND(n, pagesize);
if(h->spans_mapped >= n)
return;
- runtime_SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
+ runtime_SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats()->other_sys);
h->spans_mapped = n;
}
@@ -173,17 +175,19 @@ MHeap_Reclaim(MHeap *h, uintptr npage)
MSpan*
runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
{
+ MStats *pmstats;
MSpan *s;
runtime_lock(h);
- mstats.heap_alloc += runtime_m()->mcache->local_cachealloc;
+ pmstats = mstats();
+ pmstats->heap_alloc += (intptr)runtime_m()->mcache->local_cachealloc;
runtime_m()->mcache->local_cachealloc = 0;
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
- mstats.heap_inuse += npage<<PageShift;
+ pmstats->heap_inuse += npage<<PageShift;
if(large) {
- mstats.heap_objects++;
- mstats.heap_alloc += npage<<PageShift;
+ pmstats->heap_objects++;
+ pmstats->heap_alloc += npage<<PageShift;
// Swept spans are at the end of lists.
if(s->npages < nelem(h->free))
runtime_MSpanList_InsertBack(&h->busy[s->npages], s);
@@ -237,8 +241,8 @@ HaveSpan:
runtime_MSpanList_Remove(s);
runtime_atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse;
- mstats.heap_idle -= s->npages<<PageShift;
- mstats.heap_released -= s->npreleased<<PageShift;
+ mstats()->heap_idle -= s->npages<<PageShift;
+ mstats()->heap_released -= s->npreleased<<PageShift;
if(s->npreleased > 0)
runtime_SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
s->npreleased = 0;
@@ -326,7 +330,7 @@ MHeap_Grow(MHeap *h, uintptr npage)
v = runtime_MHeap_SysAlloc(h, ask);
}
if(v == nil) {
- runtime_printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
+ runtime_printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats()->heap_sys);
return false;
}
}
@@ -377,7 +381,7 @@ runtime_MHeap_LookupMaybe(MHeap *h, void *v)
q = p;
q -= (uintptr)h->arena_start >> PageShift;
s = h->spans[q];
- if(s == nil || p < s->start || (byte*)v >= s->limit || s->state != MSpanInUse)
+ if(s == nil || p < s->start || (uintptr)v >= s->limit || s->state != MSpanInUse)
return nil;
return s;
}
@@ -386,13 +390,16 @@ runtime_MHeap_LookupMaybe(MHeap *h, void *v)
void
runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
{
+ MStats *pmstats;
+
runtime_lock(h);
- mstats.heap_alloc += runtime_m()->mcache->local_cachealloc;
+ pmstats = mstats();
+ pmstats->heap_alloc += (intptr)runtime_m()->mcache->local_cachealloc;
runtime_m()->mcache->local_cachealloc = 0;
- mstats.heap_inuse -= s->npages<<PageShift;
+ pmstats->heap_inuse -= s->npages<<PageShift;
if(acct) {
- mstats.heap_alloc -= s->npages<<PageShift;
- mstats.heap_objects--;
+ pmstats->heap_alloc -= s->npages<<PageShift;
+ pmstats->heap_objects--;
}
MHeap_FreeLocked(h, s);
runtime_unlock(h);
@@ -411,7 +418,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
s, s->start<<PageShift, s->state, s->ref, s->sweepgen, h->sweepgen);
runtime_throw("MHeap_FreeLocked - invalid free");
}
- mstats.heap_idle += s->npages<<PageShift;
+ mstats()->heap_idle += s->npages<<PageShift;
s->state = MSpanFree;
runtime_MSpanList_Remove(s);
// Stamp newly unused spans. The scavenger will use that
@@ -472,7 +479,7 @@ scavengelist(MSpan *list, uint64 now, uint64 limit)
for(s=list->next; s != list; s=s->next) {
if((now - s->unusedsince) > limit && s->npreleased != s->npages) {
released = (s->npages - s->npreleased) << PageShift;
- mstats.heap_released += released;
+ mstats()->heap_released += released;
sumreleased += released;
s->npreleased = s->npages;
@@ -508,8 +515,8 @@ scavenge(int32 k, uint64 now, uint64 limit)
if(sumreleased > 0)
runtime_printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
runtime_printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
- k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
- mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
+ k, mstats()->heap_inuse>>20, mstats()->heap_idle>>20, mstats()->heap_sys>>20,
+ mstats()->heap_released>>20, (mstats()->heap_sys - mstats()->heap_released)>>20);
}
}
@@ -550,7 +557,7 @@ runtime_MHeap_Scavenger(void* dummy)
runtime_lock(h);
unixnow = runtime_unixnanotime();
- if(unixnow - mstats.last_gc > forcegc) {
+ if(unixnow - mstats()->last_gc > forcegc) {
runtime_unlock(h);
// The scavenger can not block other goroutines,
// otherwise deadlock detector can fire spuriously.
@@ -597,7 +604,7 @@ runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
span->unusedsince = 0;
span->npreleased = 0;
span->types.compression = MTypes_Empty;
- span->specialLock.key = 0;
+ span->speciallock.key = 0;
span->specials = nil;
span->needzero = 0;
span->freebuf = nil;
@@ -681,13 +688,13 @@ addspecial(void *p, Special *s)
offset = (uintptr)p - (span->start << PageShift);
kind = s->kind;
- runtime_lock(&span->specialLock);
+ runtime_lock(&span->speciallock);
// Find splice point, check for existing record.
t = &span->specials;
while((x = *t) != nil) {
if(offset == x->offset && kind == x->kind) {
- runtime_unlock(&span->specialLock);
+ runtime_unlock(&span->speciallock);
runtime_m()->locks--;
return false; // already exists
}
@@ -699,7 +706,7 @@ addspecial(void *p, Special *s)
s->offset = offset;
s->next = x;
*t = s;
- runtime_unlock(&span->specialLock);
+ runtime_unlock(&span->speciallock);
runtime_m()->locks--;
return true;
}
@@ -725,20 +732,20 @@ removespecial(void *p, byte kind)
offset = (uintptr)p - (span->start << PageShift);
- runtime_lock(&span->specialLock);
+ runtime_lock(&span->speciallock);
t = &span->specials;
while((s = *t) != nil) {
// This function is used for finalizers only, so we don't check for
// "interior" specials (p must be exactly equal to s->offset).
if(offset == s->offset && kind == s->kind) {
*t = s->next;
- runtime_unlock(&span->specialLock);
+ runtime_unlock(&span->speciallock);
runtime_m()->locks--;
return s;
}
t = &s->next;
}
- runtime_unlock(&span->specialLock);
+ runtime_unlock(&span->speciallock);
runtime_m()->locks--;
return nil;
}
@@ -838,7 +845,7 @@ runtime_freeallspecials(MSpan *span, void *p, uintptr size)
// this is required to not cause deadlock between span->specialLock and proflock
list = nil;
offset = (uintptr)p - (span->start << PageShift);
- runtime_lock(&span->specialLock);
+ runtime_lock(&span->speciallock);
t = &span->specials;
while((s = *t) != nil) {
if(offset + size <= s->offset)
@@ -850,7 +857,7 @@ runtime_freeallspecials(MSpan *span, void *p, uintptr size)
} else
t = &s->next;
}
- runtime_unlock(&span->specialLock);
+ runtime_unlock(&span->speciallock);
while(list != nil) {
s = list;
@@ -878,7 +885,7 @@ runtime_MHeap_SplitSpan(MHeap *h, MSpan *s)
// remove the span from whatever list it is in now
if(s->sizeclass > 0) {
- // must be in h->central[x].empty
+ // must be in h->central[x].mempty
c = &h->central[s->sizeclass];
runtime_lock(c);
runtime_MSpanList_Remove(s);
@@ -908,7 +915,7 @@ runtime_MHeap_SplitSpan(MHeap *h, MSpan *s)
// Allocate a new span for the first half.
t = runtime_FixAlloc_Alloc(&h->spanalloc);
runtime_MSpan_Init(t, s->start, npages/2);
- t->limit = (byte*)((t->start + npages/2) << PageShift);
+ t->limit = (uintptr)((t->start + npages/2) << PageShift);
t->state = MSpanInUse;
t->elemsize = npages << (PageShift - 1);
t->sweepgen = s->sweepgen;
@@ -937,7 +944,7 @@ runtime_MHeap_SplitSpan(MHeap *h, MSpan *s)
c = &h->central[s->sizeclass];
runtime_lock(c);
// swept spans are at the end of the list
- runtime_MSpanList_InsertBack(&c->empty, s);
+ runtime_MSpanList_InsertBack(&c->mempty, s);
runtime_unlock(c);
} else {
// Swept spans are at the end of lists.
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
deleted file mode 100644
index 4e8cfc9cac..0000000000
--- a/libgo/runtime/mprof.goc
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Malloc profiling.
-// Patterned after tcmalloc's algorithms; shorter code.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "defs.h"
-#include "go-type.h"
-#include "go-string.h"
-
-// NOTE(rsc): Everything here could use cas if contention became an issue.
-static Lock proflock;
-
-// All memory allocations are local and do not escape outside of the profiler.
-// The profiler is forbidden from referring to garbage-collected memory.
-
-enum { MProf, BProf }; // profile types
-
-// Per-call-stack profiling information.
-// Lookup by hashing call stack into a linked-list hash table.
-struct Bucket
-{
- Bucket *next; // next in hash list
- Bucket *allnext; // next in list of all mbuckets/bbuckets
- int32 typ;
- // Generally unions can break precise GC,
- // this one is fine because it does not contain pointers.
- union
- {
- struct // typ == MProf
- {
- // The following complex 3-stage scheme of stats accumulation
- // is required to obtain a consistent picture of mallocs and frees
- // for some point in time.
- // The problem is that mallocs come in real time, while frees
- // come only after a GC during concurrent sweeping. So if we would
- // naively count them, we would get a skew toward mallocs.
- //
- // Mallocs are accounted in recent stats.
- // Explicit frees are accounted in recent stats.
- // GC frees are accounted in prev stats.
- // After GC prev stats are added to final stats and
- // recent stats are moved into prev stats.
- uintptr allocs;
- uintptr frees;
- uintptr alloc_bytes;
- uintptr free_bytes;
-
- uintptr prev_allocs; // since last but one till last gc
- uintptr prev_frees;
- uintptr prev_alloc_bytes;
- uintptr prev_free_bytes;
-
- uintptr recent_allocs; // since last gc till now
- uintptr recent_frees;
- uintptr recent_alloc_bytes;
- uintptr recent_free_bytes;
-
- };
- struct // typ == BProf
- {
- int64 count;
- int64 cycles;
- };
- };
- uintptr hash; // hash of size + stk
- uintptr size;
- uintptr nstk;
- Location stk[1];
-};
-enum {
- BuckHashSize = 179999,
-};
-static Bucket **buckhash;
-static Bucket *mbuckets; // memory profile buckets
-static Bucket *bbuckets; // blocking profile buckets
-static uintptr bucketmem;
-
-// Return the bucket for stk[0:nstk], allocating new bucket if needed.
-static Bucket*
-stkbucket(int32 typ, uintptr size, Location *stk, int32 nstk, bool alloc)
-{
- int32 i, j;
- uintptr h;
- Bucket *b;
-
- if(buckhash == nil) {
- buckhash = runtime_SysAlloc(BuckHashSize*sizeof buckhash[0], &mstats.buckhash_sys);
- if(buckhash == nil)
- runtime_throw("runtime: cannot allocate memory");
- }
-
- // Hash stack.
- h = 0;
- for(i=0; i<nstk; i++) {
- h += stk[i].pc;
- h += h<<10;
- h ^= h>>6;
- }
- // hash in size
- h += size;
- h += h<<10;
- h ^= h>>6;
- // finalize
- h += h<<3;
- h ^= h>>11;
-
- i = h%BuckHashSize;
- for(b = buckhash[i]; b; b=b->next) {
- if(b->typ == typ && b->hash == h && b->size == size && b->nstk == (uintptr)nstk) {
- for(j = 0; j < nstk; j++) {
- if(b->stk[j].pc != stk[j].pc ||
- b->stk[j].lineno != stk[j].lineno ||
- !__go_strings_equal(b->stk[j].filename, stk[j].filename))
- break;
- }
- if (j == nstk)
- return b;
- }
- }
-
- if(!alloc)
- return nil;
-
- b = runtime_persistentalloc(sizeof *b + nstk*sizeof stk[0], 0, &mstats.buckhash_sys);
- bucketmem += sizeof *b + nstk*sizeof stk[0];
- runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
- b->typ = typ;
- b->hash = h;
- b->size = size;
- b->nstk = nstk;
- b->next = buckhash[i];
- buckhash[i] = b;
- if(typ == MProf) {
- b->allnext = mbuckets;
- mbuckets = b;
- } else {
- b->allnext = bbuckets;
- bbuckets = b;
- }
- return b;
-}
-
-static void
-MProf_GC(void)
-{
- Bucket *b;
-
- for(b=mbuckets; b; b=b->allnext) {
- b->allocs += b->prev_allocs;
- b->frees += b->prev_frees;
- b->alloc_bytes += b->prev_alloc_bytes;
- b->free_bytes += b->prev_free_bytes;
-
- b->prev_allocs = b->recent_allocs;
- b->prev_frees = b->recent_frees;
- b->prev_alloc_bytes = b->recent_alloc_bytes;
- b->prev_free_bytes = b->recent_free_bytes;
-
- b->recent_allocs = 0;
- b->recent_frees = 0;
- b->recent_alloc_bytes = 0;
- b->recent_free_bytes = 0;
- }
-}
-
-// Record that a gc just happened: all the 'recent' statistics are now real.
-void
-runtime_MProf_GC(void)
-{
- runtime_lock(&proflock);
- MProf_GC();
- runtime_unlock(&proflock);
-}
-
-// Called by malloc to record a profiled block.
-void
-runtime_MProf_Malloc(void *p, uintptr size)
-{
- Location stk[32];
- Bucket *b;
- int32 nstk;
-
- nstk = runtime_callers(1, stk, nelem(stk), false);
- runtime_lock(&proflock);
- b = stkbucket(MProf, size, stk, nstk, true);
- b->recent_allocs++;
- b->recent_alloc_bytes += size;
- runtime_unlock(&proflock);
-
- // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
- // This reduces potential contention and chances of deadlocks.
- // Since the object must be alive during call to MProf_Malloc,
- // it's fine to do this non-atomically.
- runtime_setprofilebucket(p, b);
-}
-
-// Called when freeing a profiled block.
-void
-runtime_MProf_Free(Bucket *b, uintptr size, bool freed)
-{
- runtime_lock(&proflock);
- if(freed) {
- b->recent_frees++;
- b->recent_free_bytes += size;
- } else {
- b->prev_frees++;
- b->prev_free_bytes += size;
- }
- runtime_unlock(&proflock);
-}
-
-int64 runtime_blockprofilerate; // in CPU ticks
-
-void runtime_SetBlockProfileRate(intgo) __asm__ (GOSYM_PREFIX "runtime.SetBlockProfileRate");
-
-void
-runtime_SetBlockProfileRate(intgo rate)
-{
- int64 r;
-
- if(rate <= 0)
- r = 0; // disable profiling
- else {
- // convert ns to cycles, use float64 to prevent overflow during multiplication
- r = (float64)rate*runtime_tickspersecond()/(1000*1000*1000);
- if(r == 0)
- r = 1;
- }
- runtime_atomicstore64((uint64*)&runtime_blockprofilerate, r);
-}
-
-void
-runtime_blockevent(int64 cycles, int32 skip)
-{
- int32 nstk;
- int64 rate;
- Location stk[32];
- Bucket *b;
-
- if(cycles <= 0)
- return;
- rate = runtime_atomicload64((uint64*)&runtime_blockprofilerate);
- if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
- return;
-
- nstk = runtime_callers(skip, stk, nelem(stk), false);
- runtime_lock(&proflock);
- b = stkbucket(BProf, 0, stk, nstk, true);
- b->count++;
- b->cycles += cycles;
- runtime_unlock(&proflock);
-}
-
-// Go interface to profile data. (Declared in debug.go)
-
-// Must match MemProfileRecord in debug.go.
-typedef struct Record Record;
-struct Record {
- int64 alloc_bytes, free_bytes;
- int64 alloc_objects, free_objects;
- uintptr stk[32];
-};
-
-// Write b's data to r.
-static void
-record(Record *r, Bucket *b)
-{
- uint32 i;
-
- r->alloc_bytes = b->alloc_bytes;
- r->free_bytes = b->free_bytes;
- r->alloc_objects = b->allocs;
- r->free_objects = b->frees;
- for(i=0; i<b->nstk && i<nelem(r->stk); i++)
- r->stk[i] = b->stk[i].pc;
- for(; i<nelem(r->stk); i++)
- r->stk[i] = 0;
-}
-
-func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
- Bucket *b;
- Record *r;
- bool clear;
-
- runtime_lock(&proflock);
- n = 0;
- clear = true;
- for(b=mbuckets; b; b=b->allnext) {
- if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
- n++;
- if(b->allocs != 0 || b->frees != 0)
- clear = false;
- }
- if(clear) {
- // Absolutely no data, suggesting that a garbage collection
- // has not yet happened. In order to allow profiling when
- // garbage collection is disabled from the beginning of execution,
- // accumulate stats as if a GC just happened, and recount buckets.
- MProf_GC();
- MProf_GC();
- n = 0;
- for(b=mbuckets; b; b=b->allnext)
- if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
- n++;
- }
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (Record*)p.__values;
- for(b=mbuckets; b; b=b->allnext)
- if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
- record(r++, b);
- }
- runtime_unlock(&proflock);
-}
-
-void
-runtime_MProf_Mark(struct Workbuf **wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- // buckhash is not allocated via mallocgc.
- enqueue1(wbufp, (Obj){(byte*)&mbuckets, sizeof mbuckets, 0});
- enqueue1(wbufp, (Obj){(byte*)&bbuckets, sizeof bbuckets, 0});
-}
-
-void
-runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr))
-{
- Bucket *b;
-
- runtime_lock(&proflock);
- for(b=mbuckets; b; b=b->allnext) {
- callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
- }
- runtime_unlock(&proflock);
-}
-
-// Must match BlockProfileRecord in debug.go.
-typedef struct BRecord BRecord;
-struct BRecord {
- int64 count;
- int64 cycles;
- uintptr stk[32];
-};
-
-func BlockProfile(p Slice) (n int, ok bool) {
- Bucket *b;
- BRecord *r;
- int32 i;
-
- runtime_lock(&proflock);
- n = 0;
- for(b=bbuckets; b; b=b->allnext)
- n++;
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (BRecord*)p.__values;
- for(b=bbuckets; b; b=b->allnext, r++) {
- r->count = b->count;
- r->cycles = b->cycles;
- for(i=0; (uintptr)i<b->nstk && (uintptr)i<nelem(r->stk); i++)
- r->stk[i] = b->stk[i].pc;
- for(; (uintptr)i<nelem(r->stk); i++)
- r->stk[i] = 0;
- }
- }
- runtime_unlock(&proflock);
-}
-
-// Must match StackRecord in debug.go.
-typedef struct TRecord TRecord;
-struct TRecord {
- uintptr stk[32];
-};
-
-func ThreadCreateProfile(p Slice) (n int, ok bool) {
- TRecord *r;
- M *first, *mp;
- int32 i;
-
- first = runtime_atomicloadp(&runtime_allm);
- n = 0;
- for(mp=first; mp; mp=mp->alllink)
- n++;
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (TRecord*)p.__values;
- for(mp=first; mp; mp=mp->alllink) {
- for(i = 0; (uintptr)i < nelem(r->stk); i++) {
- r->stk[i] = mp->createstack[i].pc;
- }
- r++;
- }
- }
-}
-
-func Stack(b Slice, all bool) (n int) {
- byte *pc;
- bool enablegc = false;
-
- pc = (byte*)(uintptr)runtime_getcallerpc(&b);
-
- if(all) {
- runtime_semacquire(&runtime_worldsema, false);
- runtime_m()->gcing = 1;
- runtime_stoptheworld();
- enablegc = mstats.enablegc;
- mstats.enablegc = false;
- }
-
- if(b.__count == 0)
- n = 0;
- else{
- G* g = runtime_g();
- g->writebuf = (byte*)b.__values;
- g->writenbuf = b.__count;
- USED(pc);
- runtime_goroutineheader(g);
- runtime_traceback();
- runtime_printcreatedby(g);
- if(all)
- runtime_tracebackothers(g);
- n = b.__count - g->writenbuf;
- g->writebuf = nil;
- g->writenbuf = 0;
- }
-
- if(all) {
- runtime_m()->gcing = 0;
- mstats.enablegc = enablegc;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- }
-}
-
-static void
-saveg(G *gp, TRecord *r)
-{
- int32 n, i;
- Location locstk[nelem(r->stk)];
-
- if(gp == runtime_g()) {
- n = runtime_callers(0, locstk, nelem(r->stk), false);
- for(i = 0; i < n; i++)
- r->stk[i] = locstk[i].pc;
- }
- else {
- // FIXME: Not implemented.
- n = 0;
- }
- if((size_t)n < nelem(r->stk))
- r->stk[n] = 0;
-}
-
-func GoroutineProfile(b Slice) (n int, ok bool) {
- uintptr i;
- TRecord *r;
- G *gp;
-
- ok = false;
- n = runtime_gcount();
- if(n <= b.__count) {
- runtime_semacquire(&runtime_worldsema, false);
- runtime_m()->gcing = 1;
- runtime_stoptheworld();
-
- n = runtime_gcount();
- if(n <= b.__count) {
- G* g = runtime_g();
- ok = true;
- r = (TRecord*)b.__values;
- saveg(g, r++);
- for(i = 0; i < runtime_allglen; i++) {
- gp = runtime_allg[i];
- if(gp == g || gp->status == Gdead)
- continue;
- saveg(gp, r++);
- }
- }
-
- runtime_m()->gcing = 0;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- }
-}
-
-// Tracing of alloc/free/gc.
-
-static Lock tracelock;
-
-static const char*
-typeinfoname(int32 typeinfo)
-{
- if(typeinfo == TypeInfo_SingleObject)
- return "single object";
- else if(typeinfo == TypeInfo_Array)
- return "array";
- else if(typeinfo == TypeInfo_Chan)
- return "channel";
- runtime_throw("typinfoname: unknown type info");
- return nil;
-}
-
-void
-runtime_tracealloc(void *p, uintptr size, uintptr typ)
-{
- const char *name;
- Type *type;
-
- runtime_lock(&tracelock);
- runtime_m()->traceback = 2;
- type = (Type*)(typ & ~3);
- name = typeinfoname(typ & 3);
- if(type == nil)
- runtime_printf("tracealloc(%p, %p, %s)\n", p, size, name);
- else
- runtime_printf("tracealloc(%p, %p, %s of %S)\n", p, size, name, *type->__reflection);
- if(runtime_m()->curg == nil || runtime_g() == runtime_m()->curg) {
- runtime_goroutineheader(runtime_g());
- runtime_traceback();
- } else {
- runtime_goroutineheader(runtime_m()->curg);
- runtime_traceback();
- }
- runtime_printf("\n");
- runtime_m()->traceback = 0;
- runtime_unlock(&tracelock);
-}
-
-void
-runtime_tracefree(void *p, uintptr size)
-{
- runtime_lock(&tracelock);
- runtime_m()->traceback = 2;
- runtime_printf("tracefree(%p, %p)\n", p, size);
- runtime_goroutineheader(runtime_g());
- runtime_traceback();
- runtime_printf("\n");
- runtime_m()->traceback = 0;
- runtime_unlock(&tracelock);
-}
-
-void
-runtime_tracegc(void)
-{
- runtime_lock(&tracelock);
- runtime_m()->traceback = 2;
- runtime_printf("tracegc()\n");
- // running on m->g0 stack; show all non-g0 goroutines
- runtime_tracebackothers(runtime_g());
- runtime_printf("end tracegc\n");
- runtime_printf("\n");
- runtime_m()->traceback = 0;
- runtime_unlock(&tracelock);
-}
diff --git a/libgo/runtime/msize.c b/libgo/runtime/msize.c
index 34509d0456..b82c709297 100644
--- a/libgo/runtime/msize.c
+++ b/libgo/runtime/msize.c
@@ -29,8 +29,8 @@
#include "arch.h"
#include "malloc.h"
-int32 runtime_class_to_size[NumSizeClasses];
-int32 runtime_class_to_allocnpages[NumSizeClasses];
+int32 runtime_class_to_size[_NumSizeClasses];
+int32 runtime_class_to_allocnpages[_NumSizeClasses];
// The SizeToClass lookup is implemented using two arrays,
// one mapping sizes <= 1024 to their class and one mapping
@@ -60,6 +60,7 @@ runtime_InitSizes(void)
int32 align, sizeclass, size, nextsize, n;
uint32 i;
uintptr allocsize, npages;
+ MStats *pmstats;
// Initialize the runtime_class_to_size table (and choose class sizes in the process).
runtime_class_to_size[0] = 0;
@@ -101,14 +102,14 @@ runtime_InitSizes(void)
runtime_class_to_size[sizeclass] = size;
sizeclass++;
}
- if(sizeclass != NumSizeClasses) {
- runtime_printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
- runtime_throw("InitSizes - bad NumSizeClasses");
+ if(sizeclass != _NumSizeClasses) {
+ runtime_printf("sizeclass=%d _NumSizeClasses=%d\n", sizeclass, _NumSizeClasses);
+ runtime_throw("InitSizes - bad _NumSizeClasses");
}
// Initialize the size_to_class tables.
nextsize = 0;
- for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ for (sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++) {
for(; nextsize < 1024 && nextsize <= runtime_class_to_size[sizeclass]; nextsize+=8)
runtime_size_to_class8[nextsize/8] = sizeclass;
if(nextsize >= 1024)
@@ -120,7 +121,7 @@ runtime_InitSizes(void)
if(0) {
for(n=0; n < MaxSmallSize; n++) {
sizeclass = runtime_SizeToClass(n);
- if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime_class_to_size[sizeclass] < n) {
+ if(sizeclass < 1 || sizeclass >= _NumSizeClasses || runtime_class_to_size[sizeclass] < n) {
runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
runtime_printf("incorrect SizeToClass");
goto dump;
@@ -134,15 +135,16 @@ runtime_InitSizes(void)
}
// Copy out for statistics table.
+ pmstats = mstats();
for(i=0; i<nelem(runtime_class_to_size); i++)
- mstats.by_size[i].size = runtime_class_to_size[i];
+ pmstats->by_size[i].size = runtime_class_to_size[i];
return;
dump:
if(1){
- runtime_printf("NumSizeClasses=%d\n", NumSizeClasses);
+ runtime_printf("NumSizeClasses=%d\n", _NumSizeClasses);
runtime_printf("runtime_class_to_size:");
- for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+ for(sizeclass=0; sizeclass<_NumSizeClasses; sizeclass++)
runtime_printf(" %d", runtime_class_to_size[sizeclass]);
runtime_printf("\n\n");
runtime_printf("size_to_class8:");
diff --git a/libgo/runtime/netpoll.goc b/libgo/runtime/netpoll.goc
deleted file mode 100644
index 2f3fa455f3..0000000000
--- a/libgo/runtime/netpoll.goc
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
-
-package net
-
-#include "runtime.h"
-#include "defs.h"
-#include "arch.h"
-#include "malloc.h"
-
-// Map gccgo field names to gc field names.
-// Eface aka __go_empty_interface.
-#define type __type_descriptor
-#define data __object
-
-// Integrated network poller (platform-independent part).
-// A particular implementation (epoll/kqueue) must define the following functions:
-// void runtime_netpollinit(void); // to initialize the poller
-// int32 runtime_netpollopen(uintptr fd, PollDesc *pd); // to arm edge-triggered notifications
- // and associate fd with pd.
-// An implementation must call the following function to denote that the pd is ready.
-// void runtime_netpollready(G **gpp, PollDesc *pd, int32 mode);
-
-// PollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
-// goroutines respectively. The semaphore can be in the following states:
-// READY - io readiness notification is pending;
-// a goroutine consumes the notification by changing the state to nil.
-// WAIT - a goroutine prepares to park on the semaphore, but not yet parked;
-// the goroutine commits to park by changing the state to G pointer,
-// or, alternatively, concurrent io notification changes the state to READY,
-// or, alternatively, concurrent timeout/close changes the state to nil.
-// G pointer - the goroutine is blocked on the semaphore;
-// io notification or timeout/close changes the state to READY or nil respectively
-// and unparks the goroutine.
-// nil - nothing of the above.
-#define READY ((G*)1)
-#define WAIT ((G*)2)
-
-enum
-{
- PollBlockSize = 4*1024,
-};
-
-struct PollDesc
-{
- PollDesc* link; // in pollcache, protected by pollcache.Lock
-
- // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
- // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
- // pollReset, pollWait, pollWaitCanceled and runtime_netpollready (IO rediness notification)
- // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
- // in a lock-free way by all operations.
- Lock; // protectes the following fields
- uintptr fd;
- bool closing;
- uintptr seq; // protects from stale timers and ready notifications
- G* rg; // READY, WAIT, G waiting for read or nil
- Timer rt; // read deadline timer (set if rt.fv != nil)
- int64 rd; // read deadline
- G* wg; // READY, WAIT, G waiting for write or nil
- Timer wt; // write deadline timer
- int64 wd; // write deadline
- void* user; // user settable cookie
-};
-
-static struct
-{
- Lock;
- PollDesc* first;
- // PollDesc objects must be type-stable,
- // because we can get ready notification from epoll/kqueue
- // after the descriptor is closed/reused.
- // Stale notifications are detected using seq variable,
- // seq is incremented when deadlines are changed or descriptor is reused.
-} pollcache;
-
-static bool netpollblock(PollDesc*, int32, bool);
-static G* netpollunblock(PollDesc*, int32, bool);
-static void deadline(Eface, uintptr);
-static void readDeadline(Eface, uintptr);
-static void writeDeadline(Eface, uintptr);
-static PollDesc* allocPollDesc(void);
-static intgo checkerr(PollDesc *pd, int32 mode);
-
-static FuncVal deadlineFn = {(void(*)(void))deadline};
-static FuncVal readDeadlineFn = {(void(*)(void))readDeadline};
-static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline};
-
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() (ns int64) {
- ns = runtime_nanotime();
-}
-
-func runtime_pollServerInit() {
- runtime_netpollinit();
-}
-
-func runtime_pollOpen(fd uintptr) (pd *PollDesc, errno int) {
- pd = allocPollDesc();
- runtime_lock(pd);
- if(pd->wg != nil && pd->wg != READY)
- runtime_throw("runtime_pollOpen: blocked write on free descriptor");
- if(pd->rg != nil && pd->rg != READY)
- runtime_throw("runtime_pollOpen: blocked read on free descriptor");
- pd->fd = fd;
- pd->closing = false;
- pd->seq++;
- pd->rg = nil;
- pd->rd = 0;
- pd->wg = nil;
- pd->wd = 0;
- runtime_unlock(pd);
-
- errno = runtime_netpollopen(fd, pd);
-}
-
-func runtime_pollClose(pd *PollDesc) {
- if(!pd->closing)
- runtime_throw("runtime_pollClose: close w/o unblock");
- if(pd->wg != nil && pd->wg != READY)
- runtime_throw("runtime_pollClose: blocked write on closing descriptor");
- if(pd->rg != nil && pd->rg != READY)
- runtime_throw("runtime_pollClose: blocked read on closing descriptor");
- runtime_netpollclose(pd->fd);
- runtime_lock(&pollcache);
- pd->link = pollcache.first;
- pollcache.first = pd;
- runtime_unlock(&pollcache);
-}
-
-func runtime_pollReset(pd *PollDesc, mode int) (err int) {
- err = checkerr(pd, mode);
- if(err)
- goto ret;
- if(mode == 'r')
- pd->rg = nil;
- else if(mode == 'w')
- pd->wg = nil;
-ret:
-}
-
-func runtime_pollWait(pd *PollDesc, mode int) (err int) {
- err = checkerr(pd, mode);
- if(err == 0) {
- // As for now only Solaris uses level-triggered IO.
- if(Solaris)
- runtime_netpollarm(pd, mode);
- while(!netpollblock(pd, mode, false)) {
- err = checkerr(pd, mode);
- if(err != 0)
- break;
- // Can happen if timeout has fired and unblocked us,
- // but before we had a chance to run, timeout has been reset.
- // Pretend it has not happened and retry.
- }
- }
-}
-
-func runtime_pollWaitCanceled(pd *PollDesc, mode int) {
- // This function is used only on windows after a failed attempt to cancel
- // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
- while(!netpollblock(pd, mode, true))
- ;
-}
-
-func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
- G *rg, *wg;
-
- runtime_lock(pd);
- if(pd->closing) {
- runtime_unlock(pd);
- return;
- }
- pd->seq++; // invalidate current timers
- // Reset current timers.
- if(pd->rt.fv) {
- runtime_deltimer(&pd->rt);
- pd->rt.fv = nil;
- }
- if(pd->wt.fv) {
- runtime_deltimer(&pd->wt);
- pd->wt.fv = nil;
- }
- // Setup new timers.
- if(d != 0 && d <= runtime_nanotime())
- d = -1;
- if(mode == 'r' || mode == 'r'+'w')
- pd->rd = d;
- if(mode == 'w' || mode == 'r'+'w')
- pd->wd = d;
- if(pd->rd > 0 && pd->rd == pd->wd) {
- pd->rt.fv = &deadlineFn;
- pd->rt.when = pd->rd;
- // Copy current seq into the timer arg.
- // Timer func will check the seq against current descriptor seq,
- // if they differ the descriptor was reused or timers were reset.
- pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
- pd->rt.arg.data = pd;
- pd->rt.seq = pd->seq;
- runtime_addtimer(&pd->rt);
- } else {
- if(pd->rd > 0) {
- pd->rt.fv = &readDeadlineFn;
- pd->rt.when = pd->rd;
- pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
- pd->rt.arg.data = pd;
- pd->rt.seq = pd->seq;
- runtime_addtimer(&pd->rt);
- }
- if(pd->wd > 0) {
- pd->wt.fv = &writeDeadlineFn;
- pd->wt.when = pd->wd;
- pd->wt.arg.type = nil; // should be *pollDesc type descriptor.
- pd->wt.arg.data = pd;
- pd->wt.seq = pd->seq;
- runtime_addtimer(&pd->wt);
- }
- }
- // If we set the new deadline in the past, unblock currently pending IO if any.
- rg = nil;
- runtime_atomicstorep(&wg, nil); // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
- if(pd->rd < 0)
- rg = netpollunblock(pd, 'r', false);
- if(pd->wd < 0)
- wg = netpollunblock(pd, 'w', false);
- runtime_unlock(pd);
- if(rg)
- runtime_ready(rg);
- if(wg)
- runtime_ready(wg);
-}
-
-func runtime_pollUnblock(pd *PollDesc) {
- G *rg, *wg;
-
- runtime_lock(pd);
- if(pd->closing)
- runtime_throw("runtime_pollUnblock: already closing");
- pd->closing = true;
- pd->seq++;
- runtime_atomicstorep(&rg, nil); // full memory barrier between store to closing and read of rg/wg in netpollunblock
- rg = netpollunblock(pd, 'r', false);
- wg = netpollunblock(pd, 'w', false);
- if(pd->rt.fv) {
- runtime_deltimer(&pd->rt);
- pd->rt.fv = nil;
- }
- if(pd->wt.fv) {
- runtime_deltimer(&pd->wt);
- pd->wt.fv = nil;
- }
- runtime_unlock(pd);
- if(rg)
- runtime_ready(rg);
- if(wg)
- runtime_ready(wg);
-}
-
-uintptr
-runtime_netpollfd(PollDesc *pd)
-{
- return pd->fd;
-}
-
-void**
-runtime_netpolluser(PollDesc *pd)
-{
- return &pd->user;
-}
-
-bool
-runtime_netpollclosing(PollDesc *pd)
-{
- return pd->closing;
-}
-
-void
-runtime_netpolllock(PollDesc *pd)
-{
- runtime_lock(pd);
-}
-
-void
-runtime_netpollunlock(PollDesc *pd)
-{
- runtime_unlock(pd);
-}
-
-// make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
-void
-runtime_netpollready(G **gpp, PollDesc *pd, int32 mode)
-{
- G *rg, *wg;
-
- rg = wg = nil;
- if(mode == 'r' || mode == 'r'+'w')
- rg = netpollunblock(pd, 'r', true);
- if(mode == 'w' || mode == 'r'+'w')
- wg = netpollunblock(pd, 'w', true);
- if(rg) {
- rg->schedlink = *gpp;
- *gpp = rg;
- }
- if(wg) {
- wg->schedlink = *gpp;
- *gpp = wg;
- }
-}
-
-static intgo
-checkerr(PollDesc *pd, int32 mode)
-{
- if(pd->closing)
- return 1; // errClosing
- if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0))
- return 2; // errTimeout
- return 0;
-}
-
-static bool
-blockcommit(G *gp, G **gpp)
-{
- return runtime_casp(gpp, WAIT, gp);
-}
-
-// returns true if IO is ready, or false if timedout or closed
-// waitio - wait only for completed IO, ignore errors
-static bool
-netpollblock(PollDesc *pd, int32 mode, bool waitio)
-{
- G **gpp, *old;
-
- gpp = &pd->rg;
- if(mode == 'w')
- gpp = &pd->wg;
-
- // set the gpp semaphore to WAIT
- for(;;) {
- old = *gpp;
- if(old == READY) {
- *gpp = nil;
- return true;
- }
- if(old != nil)
- runtime_throw("netpollblock: double wait");
- if(runtime_casp(gpp, nil, WAIT))
- break;
- }
-
- // need to recheck error states after setting gpp to WAIT
- // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
- // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
- if(waitio || checkerr(pd, mode) == 0)
- runtime_park((bool(*)(G*, void*))blockcommit, gpp, "IO wait");
- // be careful to not lose concurrent READY notification
- old = runtime_xchgp(gpp, nil);
- if(old > WAIT)
- runtime_throw("netpollblock: corrupted state");
- return old == READY;
-}
-
-static G*
-netpollunblock(PollDesc *pd, int32 mode, bool ioready)
-{
- G **gpp, *old, *new;
-
- gpp = &pd->rg;
- if(mode == 'w')
- gpp = &pd->wg;
-
- for(;;) {
- old = *gpp;
- if(old == READY)
- return nil;
- if(old == nil && !ioready) {
- // Only set READY for ioready. runtime_pollWait
- // will check for timeout/cancel before waiting.
- return nil;
- }
- new = nil;
- if(ioready)
- new = READY;
- if(runtime_casp(gpp, old, new))
- break;
- }
- if(old > WAIT)
- return old; // must be G*
- return nil;
-}
-
-static void
-deadlineimpl(Eface arg, uintptr seq, bool read, bool write)
-{
- PollDesc *pd;
- G *rg, *wg;
-
- pd = (PollDesc*)arg.data;
- rg = wg = nil;
- runtime_lock(pd);
- // Seq arg is seq when the timer was set.
- // If it's stale, ignore the timer event.
- if(seq != pd->seq) {
- // The descriptor was reused or timers were reset.
- runtime_unlock(pd);
- return;
- }
- if(read) {
- if(pd->rd <= 0 || pd->rt.fv == nil)
- runtime_throw("deadlineimpl: inconsistent read deadline");
- pd->rd = -1;
- runtime_atomicstorep(&pd->rt.fv, nil); // full memory barrier between store to rd and load of rg in netpollunblock
- rg = netpollunblock(pd, 'r', false);
- }
- if(write) {
- if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
- runtime_throw("deadlineimpl: inconsistent write deadline");
- pd->wd = -1;
- runtime_atomicstorep(&pd->wt.fv, nil); // full memory barrier between store to wd and load of wg in netpollunblock
- wg = netpollunblock(pd, 'w', false);
- }
- runtime_unlock(pd);
- if(rg)
- runtime_ready(rg);
- if(wg)
- runtime_ready(wg);
-}
-
-static void
-deadline(Eface arg, uintptr seq)
-{
- deadlineimpl(arg, seq, true, true);
-}
-
-static void
-readDeadline(Eface arg, uintptr seq)
-{
- deadlineimpl(arg, seq, true, false);
-}
-
-static void
-writeDeadline(Eface arg, uintptr seq)
-{
- deadlineimpl(arg, seq, false, true);
-}
-
-static PollDesc*
-allocPollDesc(void)
-{
- PollDesc *pd;
- uint32 i, n;
-
- runtime_lock(&pollcache);
- if(pollcache.first == nil) {
- n = PollBlockSize/sizeof(*pd);
- if(n == 0)
- n = 1;
- // Must be in non-GC memory because can be referenced
- // only from epoll/kqueue internals.
- pd = runtime_persistentalloc(n*sizeof(*pd), 0, &mstats.other_sys);
- for(i = 0; i < n; i++) {
- pd[i].link = pollcache.first;
- pollcache.first = &pd[i];
- }
- }
- pd = pollcache.first;
- pollcache.first = pd->link;
- runtime_unlock(&pollcache);
- return pd;
-}
diff --git a/libgo/runtime/netpoll_epoll.c b/libgo/runtime/netpoll_epoll.c
deleted file mode 100644
index 1281f45b08..0000000000
--- a/libgo/runtime/netpoll_epoll.c
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux
-
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-
-#include "runtime.h"
-#include "defs.h"
-#include "malloc.h"
-
-#ifndef EPOLLRDHUP
-#define EPOLLRDHUP 0x2000
-#endif
-
-#ifndef EPOLL_CLOEXEC
-#define EPOLL_CLOEXEC 02000000
-#endif
-
-#ifndef HAVE_EPOLL_CREATE1
-extern int epoll_create1(int __flags);
-#endif
-
-typedef struct epoll_event EpollEvent;
-
-static int32
-runtime_epollcreate(int32 size)
-{
- int r;
-
- r = epoll_create(size);
- if(r >= 0)
- return r;
- return - errno;
-}
-
-static int32
-runtime_epollcreate1(int32 flags)
-{
- int r;
-
- r = epoll_create1(flags);
- if(r >= 0)
- return r;
- return - errno;
-}
-
-static int32
-runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
-{
- int r;
-
- r = epoll_ctl(epfd, op, fd, ev);
- if(r >= 0)
- return r;
- return - errno;
-}
-
-static int32
-runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
-{
- int r;
-
- r = epoll_wait(epfd, ev, nev, timeout);
- if(r >= 0)
- return r;
- return - errno;
-}
-
-static void
-runtime_closeonexec(int32 fd)
-{
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-static int32 epfd = -1; // epoll descriptor
-
-void
-runtime_netpollinit(void)
-{
- epfd = runtime_epollcreate1(EPOLL_CLOEXEC);
- if(epfd >= 0)
- return;
- epfd = runtime_epollcreate(1024);
- if(epfd >= 0) {
- runtime_closeonexec(epfd);
- return;
- }
- runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd);
- runtime_throw("netpollinit: failed to create descriptor");
-}
-
-int32
-runtime_netpollopen(uintptr fd, PollDesc *pd)
-{
- EpollEvent ev;
- int32 res;
-
- ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET;
- ev.data.ptr = (void*)pd;
- res = runtime_epollctl(epfd, EPOLL_CTL_ADD, (int32)fd, &ev);
- return -res;
-}
-
-int32
-runtime_netpollclose(uintptr fd)
-{
- EpollEvent ev;
- int32 res;
-
- res = runtime_epollctl(epfd, EPOLL_CTL_DEL, (int32)fd, &ev);
- return -res;
-}
-
-void
-runtime_netpollarm(PollDesc* pd, int32 mode)
-{
- USED(pd);
- USED(mode);
- runtime_throw("unused");
-}
-
-// polls for ready network connections
-// returns list of goroutines that become runnable
-G*
-runtime_netpoll(bool block)
-{
- static int32 lasterr;
- EpollEvent events[128], *ev;
- int32 n, i, waitms, mode;
- G *gp;
-
- if(epfd == -1)
- return nil;
- waitms = -1;
- if(!block)
- waitms = 0;
-retry:
- n = runtime_epollwait(epfd, events, nelem(events), waitms);
- if(n < 0) {
- if(n != -EINTR && n != lasterr) {
- lasterr = n;
- runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n);
- }
- goto retry;
- }
- gp = nil;
- for(i = 0; i < n; i++) {
- ev = &events[i];
- if(ev->events == 0)
- continue;
- mode = 0;
- if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR))
- mode += 'r';
- if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR))
- mode += 'w';
- if(mode)
- runtime_netpollready(&gp, (void*)ev->data.ptr, mode);
- }
- if(block && gp == nil)
- goto retry;
- return gp;
-}
-
-void
-runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- USED(wbufp);
- USED(enqueue1);
-}
diff --git a/libgo/runtime/netpoll_kqueue.c b/libgo/runtime/netpoll_kqueue.c
deleted file mode 100644
index 5144a870fb..0000000000
--- a/libgo/runtime/netpoll_kqueue.c
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd netbsd openbsd
-
-#include "runtime.h"
-#include "defs.h"
-#include "malloc.h"
-
-// Integrated network poller (kqueue-based implementation).
-
-int32 runtime_kqueue(void);
-int32 runtime_kevent(int32, Kevent*, int32, Kevent*, int32, Timespec*);
-void runtime_closeonexec(int32);
-
-static int32 kq = -1;
-
-void
-runtime_netpollinit(void)
-{
- kq = runtime_kqueue();
- if(kq < 0) {
- runtime_printf("netpollinit: kqueue failed with %d\n", -kq);
- runtime_throw("netpollinit: kqueue failed");
- }
- runtime_closeonexec(kq);
-}
-
-int32
-runtime_netpollopen(uintptr fd, PollDesc *pd)
-{
- Kevent ev[2];
- int32 n;
-
- // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR)
- // for the whole fd lifetime. The notifications are automatically unregistered
- // when fd is closed.
- ev[0].ident = (uint32)fd;
- ev[0].filter = EVFILT_READ;
- ev[0].flags = EV_ADD|EV_CLEAR;
- ev[0].fflags = 0;
- ev[0].data = 0;
- ev[0].udata = (kevent_udata)pd;
- ev[1] = ev[0];
- ev[1].filter = EVFILT_WRITE;
- n = runtime_kevent(kq, ev, 2, nil, 0, nil);
- if(n < 0)
- return -n;
- return 0;
-}
-
-int32
-runtime_netpollclose(uintptr fd)
-{
- // Don't need to unregister because calling close()
- // on fd will remove any kevents that reference the descriptor.
- USED(fd);
- return 0;
-}
-
-void
-runtime_netpollarm(PollDesc* pd, int32 mode)
-{
- USED(pd, mode);
- runtime_throw("unused");
-}
-
-// Polls for ready network connections.
-// Returns list of goroutines that become runnable.
-G*
-runtime_netpoll(bool block)
-{
- static int32 lasterr;
- Kevent events[64], *ev;
- Timespec ts, *tp;
- int32 n, i, mode;
- G *gp;
-
- if(kq == -1)
- return nil;
- tp = nil;
- if(!block) {
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- tp = &ts;
- }
- gp = nil;
-retry:
- n = runtime_kevent(kq, nil, 0, events, nelem(events), tp);
- if(n < 0) {
- if(n != -EINTR && n != lasterr) {
- lasterr = n;
- runtime_printf("runtime: kevent on fd %d failed with %d\n", kq, -n);
- }
- goto retry;
- }
- for(i = 0; i < n; i++) {
- ev = &events[i];
- mode = 0;
- if(ev->filter == EVFILT_READ)
- mode += 'r';
- if(ev->filter == EVFILT_WRITE)
- mode += 'w';
- if(mode)
- runtime_netpollready(&gp, (PollDesc*)ev->udata, mode);
- }
- if(block && gp == nil)
- goto retry;
- return gp;
-}
-
-void
-runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- USED(wbufp);
- USED(enqueue1);
-}
diff --git a/libgo/runtime/netpoll_select.c b/libgo/runtime/netpoll_select.c
deleted file mode 100644
index 033661d17f..0000000000
--- a/libgo/runtime/netpoll_select.c
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build solaris
-
-#include "config.h"
-
-#include <errno.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#include "runtime.h"
-#include "malloc.h"
-
-static Lock selectlock;
-static int rdwake;
-static int wrwake;
-static fd_set fds;
-static PollDesc **data;
-static int allocated;
-
-void
-runtime_netpollinit(void)
-{
- int p[2];
- int fl;
-
- FD_ZERO(&fds);
- allocated = 128;
- data = runtime_mallocgc(allocated * sizeof(PollDesc *), 0,
- FlagNoScan|FlagNoProfiling|FlagNoInvokeGC);
-
- if(pipe(p) < 0)
- runtime_throw("netpollinit: failed to create pipe");
- rdwake = p[0];
- wrwake = p[1];
-
- fl = fcntl(rdwake, F_GETFL);
- if(fl < 0)
- runtime_throw("netpollinit: fcntl failed");
- fl |= O_NONBLOCK;
- if(fcntl(rdwake, F_SETFL, fl))
- runtime_throw("netpollinit: fcntl failed");
- fcntl(rdwake, F_SETFD, FD_CLOEXEC);
-
- fl = fcntl(wrwake, F_GETFL);
- if(fl < 0)
- runtime_throw("netpollinit: fcntl failed");
- fl |= O_NONBLOCK;
- if(fcntl(wrwake, F_SETFL, fl))
- runtime_throw("netpollinit: fcntl failed");
- fcntl(wrwake, F_SETFD, FD_CLOEXEC);
-
- FD_SET(rdwake, &fds);
-}
-
-int32
-runtime_netpollopen(uintptr fd, PollDesc *pd)
-{
- byte b;
-
- runtime_lock(&selectlock);
-
- if((int)fd >= allocated) {
- int c;
- PollDesc **n;
-
- c = allocated;
-
- runtime_unlock(&selectlock);
-
- while((int)fd >= c)
- c *= 2;
- n = runtime_mallocgc(c * sizeof(PollDesc *), 0,
- FlagNoScan|FlagNoProfiling|FlagNoInvokeGC);
-
- runtime_lock(&selectlock);
-
- if(c > allocated) {
- __builtin_memcpy(n, data, allocated * sizeof(PollDesc *));
- allocated = c;
- data = n;
- }
- }
- FD_SET(fd, &fds);
- data[fd] = pd;
-
- runtime_unlock(&selectlock);
-
- b = 0;
- write(wrwake, &b, sizeof b);
-
- return 0;
-}
-
-int32
-runtime_netpollclose(uintptr fd)
-{
- byte b;
-
- runtime_lock(&selectlock);
-
- FD_CLR(fd, &fds);
- data[fd] = nil;
-
- runtime_unlock(&selectlock);
-
- b = 0;
- write(wrwake, &b, sizeof b);
-
- return 0;
-}
-
-/* Used to avoid using too much stack memory. */
-static bool inuse;
-static fd_set grfds, gwfds, gefds, gtfds;
-
-G*
-runtime_netpoll(bool block)
-{
- fd_set *prfds, *pwfds, *pefds, *ptfds;
- bool allocatedfds;
- struct timeval timeout;
- struct timeval *pt;
- int max, c, i;
- G *gp;
- int32 mode;
- byte b;
- struct stat st;
-
- allocatedfds = false;
-
- retry:
- runtime_lock(&selectlock);
-
- max = allocated;
-
- if(max == 0) {
- runtime_unlock(&selectlock);
- return nil;
- }
-
- if(inuse) {
- if(!allocatedfds) {
- prfds = runtime_SysAlloc(4 * sizeof fds, &mstats.other_sys);
- pwfds = prfds + 1;
- pefds = pwfds + 1;
- ptfds = pefds + 1;
- allocatedfds = true;
- }
- } else {
- prfds = &grfds;
- pwfds = &gwfds;
- pefds = &gefds;
- ptfds = &gtfds;
- inuse = true;
- allocatedfds = false;
- }
-
- __builtin_memcpy(prfds, &fds, sizeof fds);
-
- runtime_unlock(&selectlock);
-
- __builtin_memcpy(pwfds, prfds, sizeof fds);
- FD_CLR(rdwake, pwfds);
- __builtin_memcpy(pefds, pwfds, sizeof fds);
-
- __builtin_memcpy(ptfds, pwfds, sizeof fds);
-
- __builtin_memset(&timeout, 0, sizeof timeout);
- pt = &timeout;
- if(block)
- pt = nil;
-
- c = select(max, prfds, pwfds, pefds, pt);
- if(c < 0) {
- if(errno == EBADF) {
- // Some file descriptor has been closed.
- // Check each one, and treat each closed
- // descriptor as ready for read/write.
- c = 0;
- FD_ZERO(prfds);
- FD_ZERO(pwfds);
- FD_ZERO(pefds);
- for(i = 0; i < max; i++) {
- if(FD_ISSET(i, ptfds)
- && fstat(i, &st) < 0
- && errno == EBADF) {
- FD_SET(i, prfds);
- FD_SET(i, pwfds);
- c += 2;
- }
- }
- }
- else {
- if(errno != EINTR)
- runtime_printf("runtime: select failed with %d\n", errno);
- goto retry;
- }
- }
- gp = nil;
- for(i = 0; i < max && c > 0; i++) {
- mode = 0;
- if(FD_ISSET(i, prfds)) {
- mode += 'r';
- --c;
- }
- if(FD_ISSET(i, pwfds)) {
- mode += 'w';
- --c;
- }
- if(FD_ISSET(i, pefds)) {
- mode = 'r' + 'w';
- --c;
- }
- if(i == rdwake && mode != 0) {
- while(read(rdwake, &b, sizeof b) > 0)
- ;
- continue;
- }
- if(mode) {
- PollDesc *pd;
-
- runtime_lock(&selectlock);
- pd = data[i];
- runtime_unlock(&selectlock);
- if(pd != nil)
- runtime_netpollready(&gp, pd, mode);
- }
- }
- if(block && gp == nil)
- goto retry;
-
- if(allocatedfds) {
- runtime_SysFree(prfds, 4 * sizeof fds, &mstats.other_sys);
- } else {
- runtime_lock(&selectlock);
- inuse = false;
- runtime_unlock(&selectlock);
- }
-
- return gp;
-}
-
-void
-runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0});
-}
diff --git a/libgo/runtime/panic.c b/libgo/runtime/panic.c
index de000db988..493fde8932 100644
--- a/libgo/runtime/panic.c
+++ b/libgo/runtime/panic.c
@@ -3,196 +3,14 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "malloc.h"
-#include "go-defer.h"
-#include "go-panic.h"
-// Code related to defer, panic and recover.
-
-uint32 runtime_panicking;
-static Lock paniclk;
-
-// Allocate a Defer, usually using per-P pool.
-// Each defer must be released with freedefer.
-Defer*
-runtime_newdefer()
-{
- Defer *d;
- P *p;
-
- d = nil;
- p = runtime_m()->p;
- d = p->deferpool;
- if(d)
- p->deferpool = d->__next;
- if(d == nil) {
- // deferpool is empty
- d = runtime_malloc(sizeof(Defer));
- }
- return d;
-}
-
-// Free the given defer.
-// The defer cannot be used after this call.
-void
-runtime_freedefer(Defer *d)
-{
- P *p;
-
- if(d->__special)
- return;
- p = runtime_m()->p;
- d->__next = p->deferpool;
- p->deferpool = d;
- // No need to wipe out pointers in argp/pc/fn/args,
- // because we empty the pool before GC.
-}
-
-// Run all deferred functions for the current goroutine.
-// This is noinline for go_can_recover.
-static void __go_rundefer (void) __attribute__ ((noinline));
-static void
-__go_rundefer(void)
-{
- G *g;
- Defer *d;
-
- g = runtime_g();
- while((d = g->defer) != nil) {
- void (*pfn)(void*);
-
- g->defer = d->__next;
- pfn = d->__pfn;
- d->__pfn = nil;
- if (pfn != nil)
- (*pfn)(d->__arg);
- runtime_freedefer(d);
- }
-}
-
-void
-runtime_startpanic(void)
-{
- M *m;
-
- m = runtime_m();
- if(runtime_mheap.cachealloc.size == 0) { // very early
- runtime_printf("runtime: panic before malloc heap initialized\n");
- m->mallocing = 1; // tell rest of panic not to try to malloc
- } else if(m->mcache == nil) // can happen if called from signal handler or throw
- m->mcache = runtime_allocmcache();
- switch(m->dying) {
- case 0:
- m->dying = 1;
- if(runtime_g() != nil)
- runtime_g()->writebuf = nil;
- runtime_xadd(&runtime_panicking, 1);
- runtime_lock(&paniclk);
- if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
- runtime_schedtrace(true);
- runtime_freezetheworld();
- return;
- case 1:
- // Something failed while panicing, probably the print of the
- // argument to panic(). Just print a stack trace and exit.
- m->dying = 2;
- runtime_printf("panic during panic\n");
- runtime_dopanic(0);
- runtime_exit(3);
- case 2:
- // This is a genuine bug in the runtime, we couldn't even
- // print the stack trace successfully.
- m->dying = 3;
- runtime_printf("stack trace unavailable\n");
- runtime_exit(4);
- default:
- // Can't even print! Just exit.
- runtime_exit(5);
- }
-}
-
-void
-runtime_dopanic(int32 unused __attribute__ ((unused)))
-{
- G *g;
- static bool didothers;
- bool crash;
- int32 t;
-
- g = runtime_g();
- if(g->sig != 0)
- runtime_printf("[signal %x code=%p addr=%p]\n",
- g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
-
- if((t = runtime_gotraceback(&crash)) > 0){
- if(g != runtime_m()->g0) {
- runtime_printf("\n");
- runtime_goroutineheader(g);
- runtime_traceback();
- runtime_printcreatedby(g);
- } else if(t >= 2 || runtime_m()->throwing > 0) {
- runtime_printf("\nruntime stack:\n");
- runtime_traceback();
- }
- if(!didothers) {
- didothers = true;
- runtime_tracebackothers(g);
- }
- }
- runtime_unlock(&paniclk);
- if(runtime_xadd(&runtime_panicking, -1) != 0) {
- // Some other m is panicking too.
- // Let it print what it needs to print.
- // Wait forever without chewing up cpu.
- // It will exit when it's done.
- static Lock deadlock;
- runtime_lock(&deadlock);
- runtime_lock(&deadlock);
- }
-
- if(crash)
- runtime_crash();
-
- runtime_exit(2);
-}
-
-bool
-runtime_canpanic(G *gp)
-{
- M *m = runtime_m();
- byte g;
-
- USED(&g); // don't use global g, it points to gsignal
-
- // Is it okay for gp to panic instead of crashing the program?
- // Yes, as long as it is running Go code, not runtime code,
- // and not stuck in a system call.
- if(gp == nil || gp != m->curg)
- return false;
- if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
- return false;
- if(gp->status != Grunning)
- return false;
-#ifdef GOOS_windows
- if(m->libcallsp != 0)
- return false;
-#endif
- return true;
-}
+extern void gothrow(String) __attribute__((noreturn));
+extern void gothrow(String) __asm__(GOSYM_PREFIX "runtime.throw");
void
runtime_throw(const char *s)
{
- M *mp;
-
- mp = runtime_m();
- if(mp->throwing == 0)
- mp->throwing = 1;
- runtime_startpanic();
- runtime_printf("fatal error: %s\n", s);
- runtime_dopanic(0);
- *(int32*)0 = 0; // not reached
- runtime_exit(1); // even more not reached
+ gothrow(runtime_gostringnocopy((const byte *)s));
}
void
@@ -215,18 +33,3 @@ runtime_panicstring(const char *s)
runtime_newErrorCString(s, &err);
runtime_panic(err);
}
-
-void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
-
-void
-runtime_Goexit(void)
-{
- __go_rundefer();
- runtime_goexit();
-}
-
-void
-runtime_panicdivide(void)
-{
- runtime_panicstring("integer divide by zero");
-}
diff --git a/libgo/runtime/parfor.c b/libgo/runtime/parfor.c
index ede921b9aa..d64d74ccd3 100644
--- a/libgo/runtime/parfor.c
+++ b/libgo/runtime/parfor.c
@@ -5,12 +5,13 @@
// Parallel for algorithm.
#include "runtime.h"
+#include "malloc.h"
#include "arch.h"
struct ParForThread
{
// the thread's iteration space [32lsb, 32msb)
- uint64 pos;
+ uint64 pos __attribute__((aligned(8)));
// stats
uint64 nsteal;
uint64 nstealcnt;
@@ -27,7 +28,7 @@ runtime_parforalloc(uint32 nthrmax)
// The ParFor object is followed by CacheLineSize padding
// and then nthrmax ParForThread.
- desc = (ParFor*)runtime_malloc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread));
+ desc = (ParFor*)runtime_mallocgc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread), 0, FlagNoInvokeGC);
desc->thr = (ParForThread*)((byte*)(desc+1) + CacheLineSize);
desc->nthrmax = nthrmax;
return desc;
@@ -125,7 +126,7 @@ runtime_parfordo(ParFor *desc)
goto exit;
}
// Choose a random victim for stealing.
- victim = runtime_fastrand1() % (desc->nthr-1);
+ victim = runtime_fastrand() % (desc->nthr-1);
if(victim >= tid)
victim++;
victimpos = &desc->thr[victim].pos;
diff --git a/libgo/runtime/print.c b/libgo/runtime/print.c
index 69b1f81fb4..4da879620c 100644
--- a/libgo/runtime/print.c
+++ b/libgo/runtime/print.c
@@ -9,58 +9,60 @@
#include "array.h"
#include "go-type.h"
-//static Lock debuglock;
+extern void runtime_printlock(void)
+ __asm__(GOSYM_PREFIX "runtime.printlock");
+extern void runtime_printunlock(void)
+ __asm__(GOSYM_PREFIX "runtime.printunlock");
+extern void gwrite(Slice)
+ __asm__(GOSYM_PREFIX "runtime.gwrite");
+extern void runtime_printint(int64)
+ __asm__(GOSYM_PREFIX "runtime.printint");
+extern void runtime_printuint(uint64)
+ __asm__(GOSYM_PREFIX "runtime.printuint");
+extern void runtime_printhex(uint64)
+ __asm__(GOSYM_PREFIX "runtime.printhex");
+extern void runtime_printfloat(float64)
+ __asm__(GOSYM_PREFIX "runtime.printfloat");
+extern void runtime_printcomplex(complex double)
+ __asm__(GOSYM_PREFIX "runtime.printcomplex");
+extern void runtime_printbool(_Bool)
+ __asm__(GOSYM_PREFIX "runtime.printbool");
+extern void runtime_printstring(String)
+ __asm__(GOSYM_PREFIX "runtime.printstring");
+extern void runtime_printpointer(void *)
+ __asm__(GOSYM_PREFIX "runtime.printpointer");
+extern void runtime_printslice(Slice)
+ __asm__(GOSYM_PREFIX "runtime.printslice");
+extern void runtime_printeface(Eface)
+ __asm__(GOSYM_PREFIX "runtime.printeface");
+extern void runtime_printiface(Iface)
+ __asm__(GOSYM_PREFIX "runtime.printiface");
// Clang requires this function to not be inlined (see below).
static void go_vprintf(const char*, va_list)
__attribute__((noinline));
-// write to goroutine-local buffer if diverting output,
-// or else standard error.
static void
-gwrite(const void *v, intgo n)
+runtime_prints(const char *s)
{
- G* g = runtime_g();
-
- if(g == nil || g->writebuf == nil) {
- // Avoid -D_FORTIFY_SOURCE problems.
- int rv __attribute__((unused));
-
- rv = runtime_write(2, v, n);
- return;
- }
-
- if(g->writenbuf == 0)
- return;
+ Slice sl;
- if(n > g->writenbuf)
- n = g->writenbuf;
- runtime_memmove(g->writebuf, v, n);
- g->writebuf += n;
- g->writenbuf -= n;
+ // Use memcpy to avoid const-cast warning.
+ memcpy(&sl.__values, &s, sizeof(char*));
+ sl.__count = runtime_findnull((const byte*)s);
+ sl.__capacity = sl.__count;
+ gwrite(sl);
}
-void
-runtime_dump(byte *p, int32 n)
+static void
+runtime_printbyte(int8 c)
{
- int32 i;
-
- for(i=0; i<n; i++) {
- runtime_printpointer((byte*)(uintptr)(p[i]>>4));
- runtime_printpointer((byte*)(uintptr)(p[i]&0xf));
- if((i&15) == 15)
- runtime_prints("\n");
- else
- runtime_prints(" ");
- }
- if(n & 15)
- runtime_prints("\n");
-}
+ Slice sl;
-void
-runtime_prints(const char *s)
-{
- gwrite(s, runtime_findnull((const byte*)s));
+ sl.__values = &c;
+ sl.__count = 1;
+ sl.__capacity = 1;
+ gwrite(sl);
}
#if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
@@ -104,15 +106,17 @@ runtime_snprintf(byte *buf, int32 n, const char *s, ...)
va_list va;
int32 m;
- g->writebuf = buf;
- g->writenbuf = n-1;
+ g->writebuf.__values = buf;
+ g->writebuf.__count = 0;
+ g->writebuf.__capacity = n-1;
va_start(va, s);
go_vprintf(s, va);
va_end(va);
- *g->writebuf = '\0';
- m = g->writebuf - buf;
- g->writenbuf = 0;
- g->writebuf = nil;
+ m = g->writebuf.__count;
+ ((byte*)g->writebuf.__values)[m] = '\0';
+ g->writebuf.__values = nil;
+ g->writebuf.__count = 0;
+ g->writebuf.__capacity = 0;
return m;
}
@@ -122,15 +126,21 @@ static void
go_vprintf(const char *s, va_list va)
{
const char *p, *lp;
+ Slice sl;
- //runtime_lock(&debuglock);
+ runtime_printlock();
lp = p = s;
for(; *p; p++) {
if(*p != '%')
continue;
- if(p > lp)
- gwrite(lp, p-lp);
+ if(p > lp) {
+ // Use memcpy to avoid const-cast warning.
+ memcpy(&sl.__values, &lp, sizeof(char*));
+ sl.__count = p - lp;
+ sl.__capacity = p - lp;
+ gwrite(sl);
+ }
p++;
switch(*p) {
case 'a':
@@ -181,192 +191,13 @@ go_vprintf(const char *s, va_list va)
}
lp = p+1;
}
- if(p > lp)
- gwrite(lp, p-lp);
-
- //runtime_unlock(&debuglock);
-}
-
-void
-runtime_printpc(void *p __attribute__ ((unused)))
-{
- runtime_prints("PC=");
- runtime_printhex((uint64)(uintptr)runtime_getcallerpc(p));
-}
-
-void
-runtime_printbool(_Bool v)
-{
- if(v) {
- gwrite("true", 4);
- return;
- }
- gwrite("false", 5);
-}
-
-void
-runtime_printbyte(int8 c)
-{
- gwrite(&c, 1);
-}
-
-void
-runtime_printfloat(double v)
-{
- byte buf[20];
- int32 e, s, i, n;
- float64 h;
-
- if(ISNAN(v)) {
- gwrite("NaN", 3);
- return;
- }
- if(isinf(v)) {
- if(signbit(v)) {
- gwrite("-Inf", 4);
- } else {
- gwrite("+Inf", 4);
- }
- return;
+ if(p > lp) {
+ // Use memcpy to avoid const-cast warning.
+ memcpy(&sl.__values, &lp, sizeof(char*));
+ sl.__count = p - lp;
+ sl.__capacity = p - lp;
+ gwrite(sl);
}
- n = 7; // digits printed
- e = 0; // exp
- s = 0; // sign
- if(v == 0) {
- if(isinf(1/v) && 1/v < 0)
- s = 1;
- } else {
- // sign
- if(v < 0) {
- v = -v;
- s = 1;
- }
-
- // normalize
- while(v >= 10) {
- e++;
- v /= 10;
- }
- while(v < 1) {
- e--;
- v *= 10;
- }
-
- // round
- h = 5;
- for(i=0; i<n; i++)
- h /= 10;
-
- v += h;
- if(v >= 10) {
- e++;
- v /= 10;
- }
- }
-
- // format +d.dddd+edd
- buf[0] = '+';
- if(s)
- buf[0] = '-';
- for(i=0; i<n; i++) {
- s = v;
- buf[i+2] = s+'0';
- v -= s;
- v *= 10.;
- }
- buf[1] = buf[2];
- buf[2] = '.';
-
- buf[n+2] = 'e';
- buf[n+3] = '+';
- if(e < 0) {
- e = -e;
- buf[n+3] = '-';
- }
-
- buf[n+4] = (e/100) + '0';
- buf[n+5] = (e/10)%10 + '0';
- buf[n+6] = (e%10) + '0';
- gwrite(buf, n+7);
-}
-
-void
-runtime_printcomplex(complex double v)
-{
- gwrite("(", 1);
- runtime_printfloat(creal(v));
- runtime_printfloat(cimag(v));
- gwrite("i)", 2);
-}
-
-void
-runtime_printuint(uint64 v)
-{
- byte buf[100];
- int32 i;
-
- for(i=nelem(buf)-1; i>0; i--) {
- buf[i] = v%10 + '0';
- if(v < 10)
- break;
- v = v/10;
- }
- gwrite(buf+i, nelem(buf)-i);
-}
-
-void
-runtime_printint(int64 v)
-{
- if(v < 0) {
- gwrite("-", 1);
- v = -v;
- }
- runtime_printuint(v);
-}
-
-void
-runtime_printhex(uint64 v)
-{
- static const char *dig = "0123456789abcdef";
- byte buf[100];
- int32 i;
-
- i=nelem(buf);
- for(; v>0; v/=16)
- buf[--i] = dig[v%16];
- if(i == nelem(buf))
- buf[--i] = '0';
- buf[--i] = 'x';
- buf[--i] = '0';
- gwrite(buf+i, nelem(buf)-i);
-}
-
-void
-runtime_printpointer(void *p)
-{
- runtime_printhex((uintptr)p);
-}
-
-void
-runtime_printstring(String v)
-{
- // if(v.len > runtime_maxstring) {
- // gwrite("[string too long]", 17);
- // return;
- // }
- if(v.len > 0)
- gwrite(v.str, v.len);
-}
-
-void
-__go_print_space(void)
-{
- gwrite(" ", 1);
-}
-
-void
-__go_print_nl(void)
-{
- gwrite("\n", 1);
+ runtime_printunlock();
}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index c6ac972bd4..06a9c2ad6b 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
@@ -19,7 +20,6 @@
#include "defs.h"
#include "malloc.h"
#include "go-type.h"
-#include "go-defer.h"
#ifdef USING_SPLIT_STACK
@@ -62,7 +62,6 @@ static void gtraceback(G*);
#endif
static __thread G *g;
-static __thread M *m;
#ifndef SETCONTEXT_CLOBBERS_TLS
@@ -158,6 +157,26 @@ fixcontext(ucontext_t *c)
#endif
+// ucontext_arg returns a properly aligned ucontext_t value. On some
+// systems a ucontext_t value must be aligned to a 16-byte boundary.
+// The g structure that has fields of type ucontext_t is defined in
+// Go, and Go has no simple way to align a field to such a boundary.
+// So we make the field larger in runtime2.go and pick an appropriate
+// offset within the field here.
+static ucontext_t*
+ucontext_arg(void** go_ucontext)
+{
+ uintptr_t p = (uintptr_t)go_ucontext;
+ size_t align = __alignof__(ucontext_t);
+ if(align > 16) {
+ // We only ensured space for up to a 16 byte alignment
+ // in libgo/go/runtime/runtime2.go.
+ runtime_throw("required alignment of ucontext_t too large");
+ }
+ p = (p + align - 1) &~ (uintptr_t)(align - 1);
+ return (ucontext_t*)p;
+}
+
// We can not always refer to the TLS variables directly. The
// compiler will call tls_get_addr to get the address of the variable,
// and it may hold it in a register across a call to schedule. When
@@ -179,14 +198,15 @@ M* runtime_m(void) __attribute__ ((noinline, no_split_stack));
M*
runtime_m(void)
{
- return m;
+ if(g == nil)
+ return nil;
+ return g->m;
}
-// Set m and g.
+// Set g.
void
-runtime_setmg(M* mp, G* gp)
+runtime_setg(G* gp)
{
- m = mp;
g = gp;
}
@@ -197,6 +217,7 @@ runtime_newosproc(M *mp)
pthread_attr_t attr;
sigset_t clear, old;
pthread_t tid;
+ int tries;
int ret;
if(pthread_attr_init(&attr) != 0)
@@ -215,11 +236,21 @@ runtime_newosproc(M *mp)
sigemptyset(&old);
pthread_sigmask(SIG_BLOCK, &clear, &old);
- ret = pthread_create(&tid, &attr, runtime_mstart, mp);
+
+ for (tries = 0; tries < 20; tries++) {
+ ret = pthread_create(&tid, &attr, runtime_mstart, mp);
+ if (ret != EAGAIN) {
+ break;
+ }
+ runtime_usleep((tries + 1) * 1000); // Milliseconds.
+ }
+
pthread_sigmask(SIG_SETMASK, &old, nil);
- if (ret != 0)
+ if (ret != 0) {
+ runtime_printf("pthread_create failed: %d\n", ret);
runtime_throw("pthread_create");
+ }
}
// First function run by a new goroutine. This replaces gogocall.
@@ -227,13 +258,17 @@ static void
kickoff(void)
{
void (*fn)(void*);
+ void *param;
if(g->traceback != nil)
gtraceback(g);
fn = (void (*)(void*))(g->entry);
- fn(g->param);
- runtime_goexit();
+ param = g->param;
+ g->entry = nil;
+ g->param = nil;
+ fn(param);
+ runtime_goexit1();
}
// Switch context to a different goroutine. This is like longjmp.
@@ -242,12 +277,12 @@ void
runtime_gogo(G* newg)
{
#ifdef USING_SPLIT_STACK
- __splitstack_setcontext(&newg->stack_context[0]);
+ __splitstack_setcontext(&newg->stackcontext[0]);
#endif
g = newg;
newg->fromgogo = true;
- fixcontext(&newg->context);
- setcontext(&newg->context);
+ fixcontext(ucontext_arg(&newg->context[0]));
+ setcontext(ucontext_arg(&newg->context[0]));
runtime_throw("gogo setcontext returned");
}
@@ -261,42 +296,47 @@ runtime_mcall(void (*pfn)(G*))
{
M *mp;
G *gp;
+#ifndef USING_SPLIT_STACK
+ void *afterregs;
+#endif
// Ensure that all registers are on the stack for the garbage
// collector.
__builtin_unwind_init();
- mp = m;
gp = g;
+ mp = gp->m;
if(gp == mp->g0)
runtime_throw("runtime: mcall called on m->g0 stack");
if(gp != nil) {
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&g->stack_context[0]);
+ __splitstack_getcontext(&g->stackcontext[0]);
#else
- gp->gcnext_sp = &pfn;
+ // We have to point to an address on the stack that is
+ // below the saved registers.
+ gp->gcnextsp = &afterregs;
#endif
gp->fromgogo = false;
- getcontext(&gp->context);
+ getcontext(ucontext_arg(&gp->context[0]));
// When we return from getcontext, we may be running
- // in a new thread. That means that m and g may have
- // changed. They are global variables so we will
- // reload them, but the addresses of m and g may be
- // cached in our local stack frame, and those
- // addresses may be wrong. Call functions to reload
- // the values for this thread.
- mp = runtime_m();
+ // in a new thread. That means that g may have
+ // changed. It is a global variables so we will
+ // reload it, but the address of g may be cached in
+ // our local stack frame, and that address may be
+ // wrong. Call the function to reload the value for
+ // this thread.
gp = runtime_g();
+ mp = gp->m;
if(gp->traceback != nil)
gtraceback(gp);
}
if (gp == nil || !gp->fromgogo) {
#ifdef USING_SPLIT_STACK
- __splitstack_setcontext(&mp->g0->stack_context[0]);
+ __splitstack_setcontext(&mp->g0->stackcontext[0]);
#endif
mp->g0->entry = (byte*)pfn;
mp->g0->param = gp;
@@ -306,8 +346,8 @@ runtime_mcall(void (*pfn)(G*))
// the getcontext call just above.
g = mp->g0;
- fixcontext(&mp->g0->context);
- setcontext(&mp->g0->context);
+ fixcontext(ucontext_arg(&mp->g0->context[0]));
+ setcontext(ucontext_arg(&mp->g0->context[0]));
runtime_throw("runtime: mcall function returned");
}
}
@@ -324,110 +364,92 @@ runtime_mcall(void (*pfn)(G*))
//
// Design doc at http://golang.org/s/go11sched.
-typedef struct Sched Sched;
-struct Sched {
- Lock;
-
- uint64 goidgen;
- M* midle; // idle m's waiting for work
- int32 nmidle; // number of idle m's waiting for work
- int32 nmidlelocked; // number of locked m's waiting for work
- int32 mcount; // number of m's that have been created
- int32 maxmcount; // maximum number of m's allowed (or die)
-
- P* pidle; // idle P's
- uint32 npidle;
- uint32 nmspinning;
-
- // Global runnable queue.
- G* runqhead;
- G* runqtail;
- int32 runqsize;
-
- // Global cache of dead G's.
- Lock gflock;
- G* gfree;
-
- uint32 gcwaiting; // gc is waiting to run
- int32 stopwait;
- Note stopnote;
- uint32 sysmonwait;
- Note sysmonnote;
- uint64 lastpoll;
-
- int32 profilehz; // cpu profiling rate
-};
-
enum
{
- // The max value of GOMAXPROCS.
- // There are no fundamental restrictions on the value.
- MaxGomaxprocs = 1<<8,
-
- // Number of goroutine ids to grab from runtime_sched.goidgen to local per-P cache at once.
+ // Number of goroutine ids to grab from runtime_sched->goidgen to local per-P cache at once.
// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
GoidCacheBatch = 16,
};
-Sched runtime_sched;
-int32 runtime_gomaxprocs;
-uint32 runtime_needextram = 1;
+extern Sched* runtime_getsched() __asm__ (GOSYM_PREFIX "runtime.getsched");
+extern bool* runtime_getCgoHasExtraM()
+ __asm__ (GOSYM_PREFIX "runtime.getCgoHasExtraM");
+extern P** runtime_getAllP()
+ __asm__ (GOSYM_PREFIX "runtime.getAllP");
+extern G* allocg(void)
+ __asm__ (GOSYM_PREFIX "runtime.allocg");
+extern bool needaddgcproc(void)
+ __asm__ (GOSYM_PREFIX "runtime.needaddgcproc");
+extern void startm(P*, bool)
+ __asm__(GOSYM_PREFIX "runtime.startm");
+extern void newm(void(*)(void), P*)
+ __asm__(GOSYM_PREFIX "runtime.newm");
+
+Sched* runtime_sched;
M runtime_m0;
G runtime_g0; // idle goroutine for m0
G* runtime_lastg;
-M* runtime_allm;
P** runtime_allp;
-M* runtime_extram;
int8* runtime_goos;
int32 runtime_ncpu;
bool runtime_precisestack;
-static int32 newprocs;
-
-static Lock allglock; // the following vars are protected by this lock or by stoptheworld
-G** runtime_allg;
-uintptr runtime_allglen;
-static uintptr allgcap;
bool runtime_isarchive;
void* runtime_mstart(void*);
-static void runqput(P*, G*);
-static G* runqget(P*);
-static bool runqputslow(P*, G*, uint32, uint32);
-static G* runqsteal(P*, P*);
-static void mput(M*);
-static M* mget(void);
-static void mcommoninit(M*);
-static void schedule(void);
-static void procresize(int32);
-static void acquirep(P*);
-static P* releasep(void);
-static void newm(void(*)(void), P*);
-static void stopm(void);
-static void startm(P*, bool);
-static void handoffp(P*);
-static void wakep(void);
-static void stoplockedm(void);
-static void startlockedm(G*);
-static void sysmon(void);
-static uint32 retake(int64);
-static void incidlelocked(int32);
-static void checkdead(void);
static void exitsyscall0(G*);
static void park0(G*);
static void goexit0(G*);
-static void gfput(P*, G*);
-static G* gfget(P*);
-static void gfpurge(P*);
-static void globrunqput(G*);
-static void globrunqputbatch(G*, G*, int32);
-static G* globrunqget(P*, int32);
-static P* pidleget(void);
-static void pidleput(P*);
-static void injectglist(G*);
-static bool preemptall(void);
static bool exitsyscallfast(void);
-static void allgadd(G*);
+
+extern void setncpu(int32)
+ __asm__(GOSYM_PREFIX "runtime.setncpu");
+extern void setpagesize(uintptr_t)
+ __asm__(GOSYM_PREFIX "runtime.setpagesize");
+extern void allgadd(G*)
+ __asm__(GOSYM_PREFIX "runtime.allgadd");
+extern void mcommoninit(M*)
+ __asm__(GOSYM_PREFIX "runtime.mcommoninit");
+extern void stopm(void)
+ __asm__(GOSYM_PREFIX "runtime.stopm");
+extern void handoffp(P*)
+ __asm__(GOSYM_PREFIX "runtime.handoffp");
+extern void wakep(void)
+ __asm__(GOSYM_PREFIX "runtime.wakep");
+extern void stoplockedm(void)
+ __asm__(GOSYM_PREFIX "runtime.stoplockedm");
+extern void schedule(void)
+ __asm__(GOSYM_PREFIX "runtime.schedule");
+extern void execute(G*, bool)
+ __asm__(GOSYM_PREFIX "runtime.execute");
+extern void gfput(P*, G*)
+ __asm__(GOSYM_PREFIX "runtime.gfput");
+extern G* gfget(P*)
+ __asm__(GOSYM_PREFIX "runtime.gfget");
+extern void procresize(int32)
+ __asm__(GOSYM_PREFIX "runtime.procresize");
+extern void acquirep(P*)
+ __asm__(GOSYM_PREFIX "runtime.acquirep");
+extern P* releasep(void)
+ __asm__(GOSYM_PREFIX "runtime.releasep");
+extern void incidlelocked(int32)
+ __asm__(GOSYM_PREFIX "runtime.incidlelocked");
+extern void checkdead(void)
+ __asm__(GOSYM_PREFIX "runtime.checkdead");
+extern void sysmon(void)
+ __asm__(GOSYM_PREFIX "runtime.sysmon");
+extern void mput(M*)
+ __asm__(GOSYM_PREFIX "runtime.mput");
+extern M* mget(void)
+ __asm__(GOSYM_PREFIX "runtime.mget");
+extern void globrunqput(G*)
+ __asm__(GOSYM_PREFIX "runtime.globrunqput");
+extern P* pidleget(void)
+ __asm__(GOSYM_PREFIX "runtime.pidleget");
+extern bool runqempty(P*)
+ __asm__(GOSYM_PREFIX "runtime.runqempty");
+extern void runqput(P*, G*, bool)
+ __asm__(GOSYM_PREFIX "runtime.runqput");
bool runtime_isstarted;
@@ -442,11 +464,16 @@ bool runtime_isstarted;
void
runtime_schedinit(void)
{
+ M *m;
int32 n, procs;
String s;
const byte *p;
Eface i;
+ setncpu(runtime_ncpu);
+ setpagesize(getpagesize());
+ runtime_sched = runtime_getsched();
+
m = &runtime_m0;
g = &runtime_g0;
m->g0 = g;
@@ -455,13 +482,14 @@ runtime_schedinit(void)
initcontext();
- runtime_sched.maxmcount = 10000;
+ runtime_sched->maxmcount = 10000;
runtime_precisestack = 0;
// runtime_symtabinit();
runtime_mallocinit();
mcommoninit(m);
-
+ runtime_alginit(); // maps must not be used before this call
+
// Initialize the itable value for newErrorCString,
// so that the next time it gets called, possibly
// in a fault during a garbage collection, it will not
@@ -476,20 +504,20 @@ runtime_schedinit(void)
runtime_goenvs();
runtime_parsedebugvars();
- runtime_sched.lastpoll = runtime_nanotime();
+ runtime_sched->lastpoll = runtime_nanotime();
procs = 1;
s = runtime_getenv("GOMAXPROCS");
p = s.str;
if(p != nil && (n = runtime_atoi(p, s.len)) > 0) {
- if(n > MaxGomaxprocs)
- n = MaxGomaxprocs;
+ if(n > _MaxGomaxprocs)
+ n = _MaxGomaxprocs;
procs = n;
}
- runtime_allp = runtime_malloc((MaxGomaxprocs+1)*sizeof(runtime_allp[0]));
+ runtime_allp = runtime_getAllP();
procresize(procs);
// Can not enable GC until all roots are registered.
- // mstats.enablegc = 1;
+ // mstats()->enablegc = 1;
}
extern void main_init(void) __asm__ (GOSYM_PREFIX "__go_init_main");
@@ -503,54 +531,6 @@ struct field_align
Hchan *p;
};
-// main_init_done is a signal used by cgocallbackg that initialization
-// has been completed. It is made before _cgo_notify_runtime_init_done,
-// so all cgo calls can rely on it existing. When main_init is
-// complete, it is closed, meaning cgocallbackg can reliably receive
-// from it.
-Hchan *runtime_main_init_done;
-
-// The chan bool type, for runtime_main_init_done.
-
-extern const struct __go_type_descriptor bool_type_descriptor
- __asm__ (GOSYM_PREFIX "__go_tdn_bool");
-
-static struct __go_channel_type chan_bool_type_descriptor =
- {
- /* __common */
- {
- /* __code */
- GO_CHAN,
- /* __align */
- __alignof (Hchan *),
- /* __field_align */
- offsetof (struct field_align, p) - 1,
- /* __size */
- sizeof (Hchan *),
- /* __hash */
- 0, /* This value doesn't matter. */
- /* __hashfn */
- &__go_type_hash_error_descriptor,
- /* __equalfn */
- &__go_type_equal_error_descriptor,
- /* __gc */
- NULL, /* This value doesn't matter */
- /* __reflection */
- NULL, /* This value doesn't matter */
- /* __uncommon */
- NULL,
- /* __pointer_to_this */
- NULL
- },
- /* __element_type */
- &bool_type_descriptor,
- /* __dir */
- CHANNEL_BOTH_DIR
- };
-
-extern Hchan *__go_new_channel (ChanType *, uintptr);
-extern void closechan(Hchan *) __asm__ (GOSYM_PREFIX "runtime.closechan");
-
static void
initDone(void *arg __attribute__ ((unused))) {
runtime_unlockOSThread();
@@ -583,37 +563,37 @@ runtime_main(void* dummy __attribute__((unused)))
runtime_lockOSThread();
// Defer unlock so that runtime.Goexit during init does the unlock too.
- d.__pfn = initDone;
- d.__next = g->defer;
- d.__arg = (void*)-1;
- d.__panic = g->panic;
- d.__retaddr = nil;
- d.__makefunc_can_recover = 0;
- d.__frame = &frame;
- d.__special = true;
- g->defer = &d;
-
- if(m != &runtime_m0)
+ d.pfn = (uintptr)(void*)initDone;
+ d.link = g->_defer;
+ d.arg = (void*)-1;
+ d._panic = g->_panic;
+ d.retaddr = 0;
+ d.makefunccanrecover = 0;
+ d.frame = &frame;
+ d.special = true;
+ g->_defer = &d;
+
+ if(g->m != &runtime_m0)
runtime_throw("runtime_main not on m0");
__go_go(runtime_MHeap_Scavenger, nil);
- runtime_main_init_done = __go_new_channel(&chan_bool_type_descriptor, 0);
+ makeMainInitDone();
_cgo_notify_runtime_init_done();
main_init();
- closechan(runtime_main_init_done);
+ closeMainInitDone();
- if(g->defer != &d || d.__pfn != initDone)
+ if(g->_defer != &d || (void*)d.pfn != initDone)
runtime_throw("runtime: bad defer entry after init");
- g->defer = d.__next;
+ g->_defer = d.link;
runtime_unlockOSThread();
// For gccgo we have to wait until after main is initialized
// to enable GC, because initializing main registers the GC
// roots.
- mstats.enablegc = 1;
+ mstats()->enablegc = 1;
if(runtime_isarchive) {
// This is not a complete program, but is instead a
@@ -629,7 +609,7 @@ runtime_main(void* dummy __attribute__((unused)))
// another goroutine at the same time as main returns,
// let the other goroutine finish printing the panic trace.
// Once it does, it will exit. See issue 3934.
- if(runtime_panicking)
+ if(runtime_panicking())
runtime_park(nil, nil, "panicwait");
runtime_exit(0);
@@ -637,150 +617,24 @@ runtime_main(void* dummy __attribute__((unused)))
*(int32*)0 = 0;
}
-void
-runtime_goroutineheader(G *gp)
-{
- const char *status;
- int64 waitfor;
-
- switch(gp->status) {
- case Gidle:
- status = "idle";
- break;
- case Grunnable:
- status = "runnable";
- break;
- case Grunning:
- status = "running";
- break;
- case Gsyscall:
- status = "syscall";
- break;
- case Gwaiting:
- if(gp->waitreason)
- status = gp->waitreason;
- else
- status = "waiting";
- break;
- default:
- status = "???";
- break;
- }
-
- // approx time the G is blocked, in minutes
- waitfor = 0;
- if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0)
- waitfor = (runtime_nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
-
- if(waitfor < 1)
- runtime_printf("goroutine %D [%s]:\n", gp->goid, status);
- else
- runtime_printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor);
-}
-
-void
-runtime_printcreatedby(G *g)
-{
- if(g != nil && g->gopc != 0 && g->goid != 1) {
- String fn;
- String file;
- intgo line;
-
- if(__go_file_line(g->gopc - 1, &fn, &file, &line)) {
- runtime_printf("created by %S\n", fn);
- runtime_printf("\t%S:%D\n", file, (int64) line);
- }
- }
-}
-
-struct Traceback
-{
- G* gp;
- Location locbuf[TracebackMaxFrames];
- int32 c;
-};
+void getTraceback(G*, G*) __asm__(GOSYM_PREFIX "runtime.getTraceback");
-void
-runtime_tracebackothers(G * volatile me)
+// getTraceback stores a traceback of gp in the g's traceback field
+// and then returns to me. We expect that gp's traceback is not nil.
+// It works by saving me's current context, and checking gp's traceback field.
+// If gp's traceback field is not nil, it starts running gp.
+// In places where we call getcontext, we check the traceback field.
+// If it is not nil, we collect a traceback, and then return to the
+// goroutine stored in the traceback field, which is me.
+void getTraceback(G* me, G* gp)
{
- G * volatile gp;
- Traceback tb;
- int32 traceback;
- volatile uintptr i;
-
- tb.gp = me;
- traceback = runtime_gotraceback(nil);
-
- // Show the current goroutine first, if we haven't already.
- if((gp = m->curg) != nil && gp != me) {
- runtime_printf("\n");
- runtime_goroutineheader(gp);
- gp->traceback = &tb;
-
-#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&me->stack_context[0]);
-#endif
- getcontext(&me->context);
-
- if(gp->traceback != nil) {
- runtime_gogo(gp);
- }
-
- runtime_printtrace(tb.locbuf, tb.c, false);
- runtime_printcreatedby(gp);
- }
-
- runtime_lock(&allglock);
- for(i = 0; i < runtime_allglen; i++) {
- gp = runtime_allg[i];
- if(gp == me || gp == m->curg || gp->status == Gdead)
- continue;
- if(gp->issystem && traceback < 2)
- continue;
- runtime_printf("\n");
- runtime_goroutineheader(gp);
-
- // Our only mechanism for doing a stack trace is
- // _Unwind_Backtrace. And that only works for the
- // current thread, not for other random goroutines.
- // So we need to switch context to the goroutine, get
- // the backtrace, and then switch back.
-
- // This means that if g is running or in a syscall, we
- // can't reliably print a stack trace. FIXME.
-
- if(gp->status == Grunning) {
- runtime_printf("\tgoroutine running on other thread; stack unavailable\n");
- runtime_printcreatedby(gp);
- } else if(gp->status == Gsyscall) {
- runtime_printf("\tgoroutine in C code; stack unavailable\n");
- runtime_printcreatedby(gp);
- } else {
- gp->traceback = &tb;
-
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&me->stack_context[0]);
+ __splitstack_getcontext(&me->stackcontext[0]);
#endif
- getcontext(&me->context);
-
- if(gp->traceback != nil) {
- runtime_gogo(gp);
- }
+ getcontext(ucontext_arg(&me->context[0]));
- runtime_printtrace(tb.locbuf, tb.c, false);
- runtime_printcreatedby(gp);
- }
- }
- runtime_unlock(&allglock);
-}
-
-static void
-checkmcount(void)
-{
- // sched lock is held
- if(runtime_sched.mcount > runtime_sched.maxmcount) {
- runtime_printf("runtime: program exceeds %d-thread limit\n", runtime_sched.maxmcount);
- runtime_throw("thread exhaustion");
+ if (gp->traceback != nil) {
+ runtime_gogo(gp);
}
}
@@ -794,286 +648,56 @@ gtraceback(G* gp)
traceback = gp->traceback;
gp->traceback = nil;
+ if(gp->m != nil)
+ runtime_throw("gtraceback: m is not nil");
+ gp->m = traceback->gp->m;
traceback->c = runtime_callers(1, traceback->locbuf,
sizeof traceback->locbuf / sizeof traceback->locbuf[0], false);
+ gp->m = nil;
runtime_gogo(traceback->gp);
}
-static void
-mcommoninit(M *mp)
-{
- // If there is no mcache runtime_callers() will crash,
- // and we are most likely in sysmon thread so the stack is senseless anyway.
- if(m->mcache)
- runtime_callers(1, mp->createstack, nelem(mp->createstack), false);
-
- mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks();
-
- runtime_lock(&runtime_sched);
- mp->id = runtime_sched.mcount++;
- checkmcount();
- runtime_mpreinit(mp);
-
- // Add to runtime_allm so garbage collector doesn't free m
- // when it is just in a register or thread-local storage.
- mp->alllink = runtime_allm;
- // runtime_NumCgoCall() iterates over allm w/o schedlock,
- // so we need to publish it safely.
- runtime_atomicstorep(&runtime_allm, mp);
- runtime_unlock(&runtime_sched);
-}
-
-// Mark gp ready to run.
-void
-runtime_ready(G *gp)
-{
- // Mark runnable.
- m->locks++; // disable preemption because it can be holding p in a local var
- if(gp->status != Gwaiting) {
- runtime_printf("goroutine %D has status %d\n", gp->goid, gp->status);
- runtime_throw("bad g->status in ready");
- }
- gp->status = Grunnable;
- runqput(m->p, gp);
- if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0) // TODO: fast atomic
- wakep();
- m->locks--;
-}
-
-int32
-runtime_gcprocs(void)
-{
- int32 n;
-
- // Figure out how many CPUs to use during GC.
- // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
- runtime_lock(&runtime_sched);
- n = runtime_gomaxprocs;
- if(n > runtime_ncpu)
- n = runtime_ncpu > 0 ? runtime_ncpu : 1;
- if(n > MaxGcproc)
- n = MaxGcproc;
- if(n > runtime_sched.nmidle+1) // one M is currently running
- n = runtime_sched.nmidle+1;
- runtime_unlock(&runtime_sched);
- return n;
-}
-
-static bool
-needaddgcproc(void)
-{
- int32 n;
-
- runtime_lock(&runtime_sched);
- n = runtime_gomaxprocs;
- if(n > runtime_ncpu)
- n = runtime_ncpu;
- if(n > MaxGcproc)
- n = MaxGcproc;
- n -= runtime_sched.nmidle+1; // one M is currently running
- runtime_unlock(&runtime_sched);
- return n > 0;
-}
-
-void
-runtime_helpgc(int32 nproc)
-{
- M *mp;
- int32 n, pos;
-
- runtime_lock(&runtime_sched);
- pos = 0;
- for(n = 1; n < nproc; n++) { // one M is currently running
- if(runtime_allp[pos]->mcache == m->mcache)
- pos++;
- mp = mget();
- if(mp == nil)
- runtime_throw("runtime_gcprocs inconsistency");
- mp->helpgc = n;
- mp->mcache = runtime_allp[pos]->mcache;
- pos++;
- runtime_notewakeup(&mp->park);
- }
- runtime_unlock(&runtime_sched);
-}
-
-// Similar to stoptheworld but best-effort and can be called several times.
-// There is no reverse operation, used during crashing.
-// This function must not lock any mutexes.
-void
-runtime_freezetheworld(void)
-{
- int32 i;
-
- if(runtime_gomaxprocs == 1)
- return;
- // stopwait and preemption requests can be lost
- // due to races with concurrently executing threads,
- // so try several times
- for(i = 0; i < 5; i++) {
- // this should tell the scheduler to not start any new goroutines
- runtime_sched.stopwait = 0x7fffffff;
- runtime_atomicstore((uint32*)&runtime_sched.gcwaiting, 1);
- // this should stop running goroutines
- if(!preemptall())
- break; // no running goroutines
- runtime_usleep(1000);
- }
- // to be sure
- runtime_usleep(1000);
- preemptall();
- runtime_usleep(1000);
-}
-
-void
-runtime_stoptheworld(void)
-{
- int32 i;
- uint32 s;
- P *p;
- bool wait;
-
- runtime_lock(&runtime_sched);
- runtime_sched.stopwait = runtime_gomaxprocs;
- runtime_atomicstore((uint32*)&runtime_sched.gcwaiting, 1);
- preemptall();
- // stop current P
- m->p->status = Pgcstop;
- runtime_sched.stopwait--;
- // try to retake all P's in Psyscall status
- for(i = 0; i < runtime_gomaxprocs; i++) {
- p = runtime_allp[i];
- s = p->status;
- if(s == Psyscall && runtime_cas(&p->status, s, Pgcstop))
- runtime_sched.stopwait--;
- }
- // stop idle P's
- while((p = pidleget()) != nil) {
- p->status = Pgcstop;
- runtime_sched.stopwait--;
- }
- wait = runtime_sched.stopwait > 0;
- runtime_unlock(&runtime_sched);
-
- // wait for remaining P's to stop voluntarily
- if(wait) {
- runtime_notesleep(&runtime_sched.stopnote);
- runtime_noteclear(&runtime_sched.stopnote);
- }
- if(runtime_sched.stopwait)
- runtime_throw("stoptheworld: not stopped");
- for(i = 0; i < runtime_gomaxprocs; i++) {
- p = runtime_allp[i];
- if(p->status != Pgcstop)
- runtime_throw("stoptheworld: not stopped");
- }
-}
-
-static void
-mhelpgc(void)
-{
- m->helpgc = -1;
-}
-
-void
-runtime_starttheworld(void)
-{
- P *p, *p1;
- M *mp;
- G *gp;
- bool add;
-
- m->locks++; // disable preemption because it can be holding p in a local var
- gp = runtime_netpoll(false); // non-blocking
- injectglist(gp);
- add = needaddgcproc();
- runtime_lock(&runtime_sched);
- if(newprocs) {
- procresize(newprocs);
- newprocs = 0;
- } else
- procresize(runtime_gomaxprocs);
- runtime_sched.gcwaiting = 0;
-
- p1 = nil;
- while((p = pidleget()) != nil) {
- // procresize() puts p's with work at the beginning of the list.
- // Once we reach a p without a run queue, the rest don't have one either.
- if(p->runqhead == p->runqtail) {
- pidleput(p);
- break;
- }
- p->m = mget();
- p->link = p1;
- p1 = p;
- }
- if(runtime_sched.sysmonwait) {
- runtime_sched.sysmonwait = false;
- runtime_notewakeup(&runtime_sched.sysmonnote);
- }
- runtime_unlock(&runtime_sched);
-
- while(p1) {
- p = p1;
- p1 = p1->link;
- if(p->m) {
- mp = p->m;
- p->m = nil;
- if(mp->nextp)
- runtime_throw("starttheworld: inconsistent mp->nextp");
- mp->nextp = p;
- runtime_notewakeup(&mp->park);
- } else {
- // Start M to run P. Do not start another M below.
- newm(nil, p);
- add = false;
- }
- }
-
- if(add) {
- // If GC could have used another helper proc, start one now,
- // in the hope that it will be available next time.
- // It would have been even better to start it before the collection,
- // but doing so requires allocating memory, so it's tricky to
- // coordinate. This lazy approach works out in practice:
- // we don't mind if the first couple gc rounds don't have quite
- // the maximum number of procs.
- newm(mhelpgc, nil);
- }
- m->locks--;
-}
-
// Called to start an M.
void*
runtime_mstart(void* mp)
{
+ M *m;
+ G *gp;
+
m = (M*)mp;
g = m->g0;
+ g->m = m;
+ gp = g;
initcontext();
- g->entry = nil;
- g->param = nil;
+ gp->entry = nil;
+ gp->param = nil;
// Record top of stack for use by mcall.
// Once we call schedule we're never coming back,
// so other calls can reuse this stack space.
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&g->stack_context[0]);
+ __splitstack_getcontext(&g->stackcontext[0]);
#else
- g->gcinitial_sp = &mp;
- // Setting gcstack_size to 0 is a marker meaning that gcinitial_sp
+ gp->gcinitialsp = &mp;
+ // Setting gcstacksize to 0 is a marker meaning that gcinitialsp
// is the top of the stack, not the bottom.
- g->gcstack_size = 0;
- g->gcnext_sp = &mp;
+ gp->gcstacksize = 0;
+ gp->gcnextsp = &mp;
#endif
- getcontext(&g->context);
+ getcontext(ucontext_arg(&gp->context[0]));
+
+ if(gp->traceback != nil)
+ gtraceback(gp);
- if(g->entry != nil) {
+ if(gp->entry != nil) {
// Got here from mcall.
- void (*pfn)(G*) = (void (*)(G*))g->entry;
- G* gp = (G*)g->param;
- pfn(gp);
+ void (*pfn)(G*) = (void (*)(G*))gp->entry;
+ G* gp1 = (G*)gp->param;
+ gp->entry = nil;
+ gp->param = nil;
+ pfn(gp1);
*(int*)0x21 = 0x21;
}
runtime_minit();
@@ -1088,23 +712,25 @@ runtime_mstart(void* mp)
// Install signal handlers; after minit so that minit can
// prepare the thread to be able to handle the signals.
if(m == &runtime_m0) {
- if(runtime_iscgo && !runtime_cgoHasExtraM) {
- runtime_cgoHasExtraM = true;
- runtime_newextram();
- runtime_needextram = 0;
+ if(runtime_iscgo) {
+ bool* cgoHasExtraM = runtime_getCgoHasExtraM();
+ if(!*cgoHasExtraM) {
+ *cgoHasExtraM = true;
+ runtime_newextram();
+ }
}
runtime_initsig(false);
}
if(m->mstartfn)
- m->mstartfn();
+ ((void (*)(void))m->mstartfn)();
if(m->helpgc) {
m->helpgc = 0;
stopm();
} else if(m != &runtime_m0) {
- acquirep(m->nextp);
- m->nextp = nil;
+ acquirep((P*)m->nextp);
+ m->nextp = 0;
}
schedule();
@@ -1124,15 +750,18 @@ struct CgoThreadStart
void (*fn)(void);
};
+M* runtime_allocm(P*, bool, byte**, uintptr*)
+ __asm__(GOSYM_PREFIX "runtime.allocm");
+
// Allocate a new m unassociated with any thread.
// Can use p for allocation context if needed.
M*
-runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacksize)
+runtime_allocm(P *p, bool allocatestack, byte** ret_g0_stack, uintptr* ret_g0_stacksize)
{
M *mp;
- m->locks++; // disable GC because it can be called from sysmon
- if(m->p == nil)
+ g->m->locks++; // disable GC because it can be called from sysmon
+ if(g->m->p == 0)
acquirep(p); // temporarily borrow p for mallocs in this function
#if 0
if(mtype == nil) {
@@ -1144,355 +773,106 @@ runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacks
mp = runtime_mal(sizeof *mp);
mcommoninit(mp);
- mp->g0 = runtime_malg(stacksize, ret_g0_stack, ret_g0_stacksize);
+ mp->g0 = runtime_malg(allocatestack, false, ret_g0_stack, ret_g0_stacksize);
+ mp->g0->m = mp;
- if(p == m->p)
+ if(p == (P*)g->m->p)
releasep();
- m->locks--;
+ g->m->locks--;
return mp;
}
-static G*
-allocg(void)
-{
- G *gp;
- // static Type *gtype;
-
- // if(gtype == nil) {
- // Eface e;
- // runtime_gc_g_ptr(&e);
- // gtype = ((PtrType*)e.__type_descriptor)->__element_type;
- // }
- // gp = runtime_cnew(gtype);
- gp = runtime_malloc(sizeof(G));
- return gp;
-}
+void setGContext(void) __asm__ (GOSYM_PREFIX "runtime.setGContext");
-static M* lockextra(bool nilokay);
-static void unlockextra(M*);
-
-// needm is called when a cgo callback happens on a
-// thread without an m (a thread not created by Go).
-// In this case, needm is expected to find an m to use
-// and return with m, g initialized correctly.
-// Since m and g are not set now (likely nil, but see below)
-// needm is limited in what routines it can call. In particular
-// it can only call nosplit functions (textflag 7) and cannot
-// do any scheduling that requires an m.
-//
-// In order to avoid needing heavy lifting here, we adopt
-// the following strategy: there is a stack of available m's
-// that can be stolen. Using compare-and-swap
-// to pop from the stack has ABA races, so we simulate
-// a lock by doing an exchange (via casp) to steal the stack
-// head and replace the top pointer with MLOCKED (1).
-// This serves as a simple spin lock that we can use even
-// without an m. The thread that locks the stack in this way
-// unlocks the stack by storing a valid stack head pointer.
-//
-// In order to make sure that there is always an m structure
-// available to be stolen, we maintain the invariant that there
-// is always one more than needed. At the beginning of the
-// program (if cgo is in use) the list is seeded with a single m.
-// If needm finds that it has taken the last m off the list, its job
-// is - once it has installed its own m so that it can do things like
-// allocate memory - to create a spare m and put it on the list.
-//
-// Each of these extra m's also has a g0 and a curg that are
-// pressed into service as the scheduling stack and current
-// goroutine for the duration of the cgo callback.
-//
-// When the callback is done with the m, it calls dropm to
-// put the m back on the list.
-//
-// Unlike the gc toolchain, we start running on curg, since we are
-// just going to return and let the caller continue.
+// setGContext sets up a new goroutine context for the current g.
void
-runtime_needm(void)
+setGContext()
{
- M *mp;
-
- if(runtime_needextram) {
- // Can happen if C/C++ code calls Go from a global ctor.
- // Can not throw, because scheduler is not initialized yet.
- int rv __attribute__((unused));
- rv = runtime_write(2, "fatal error: cgo callback before cgo call\n",
- sizeof("fatal error: cgo callback before cgo call\n")-1);
- runtime_exit(1);
- }
+ int val;
+ G *gp;
- // Lock extra list, take head, unlock popped list.
- // nilokay=false is safe here because of the invariant above,
- // that the extra list always contains or will soon contain
- // at least one m.
- mp = lockextra(false);
-
- // Set needextram when we've just emptied the list,
- // so that the eventual call into cgocallbackg will
- // allocate a new m for the extra list. We delay the
- // allocation until then so that it can be done
- // after exitsyscall makes sure it is okay to be
- // running at all (that is, there's no garbage collection
- // running right now).
- mp->needextram = mp->schedlink == nil;
- unlockextra(mp->schedlink);
-
- // Install m and g (= m->curg).
- runtime_setmg(mp, mp->curg);
-
- // Initialize g's context as in mstart.
initcontext();
- g->status = Gsyscall;
- g->entry = nil;
- g->param = nil;
+ gp = g;
+ gp->entry = nil;
+ gp->param = nil;
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&g->stack_context[0]);
+ __splitstack_getcontext(&gp->stackcontext[0]);
+ val = 0;
+ __splitstack_block_signals(&val, nil);
#else
- g->gcinitial_sp = &mp;
- g->gcstack = nil;
- g->gcstack_size = 0;
- g->gcnext_sp = &mp;
+ gp->gcinitialsp = &val;
+ gp->gcstack = nil;
+ gp->gcstacksize = 0;
+ gp->gcnextsp = &val;
#endif
- getcontext(&g->context);
+ getcontext(ucontext_arg(&gp->context[0]));
- if(g->entry != nil) {
+ if(gp->entry != nil) {
// Got here from mcall.
- void (*pfn)(G*) = (void (*)(G*))g->entry;
- G* gp = (G*)g->param;
- pfn(gp);
+ void (*pfn)(G*) = (void (*)(G*))gp->entry;
+ G* gp1 = (G*)gp->param;
+ gp->entry = nil;
+ gp->param = nil;
+ pfn(gp1);
*(int*)0x22 = 0x22;
}
-
- // Initialize this thread to use the m.
- runtime_minit();
-
-#ifdef USING_SPLIT_STACK
- {
- int dont_block_signals = 0;
- __splitstack_block_signals(&dont_block_signals, nil);
- }
-#endif
}
-// newextram allocates an m and puts it on the extra list.
-// It is called with a working local m, so that it can do things
-// like call schedlock and allocate.
-void
-runtime_newextram(void)
-{
- M *mp, *mnext;
- G *gp;
- byte *g0_sp, *sp;
- size_t g0_spsize, spsize;
-
- // Create extra goroutine locked to extra m.
- // The goroutine is the context in which the cgo callback will run.
- // The sched.pc will never be returned to, but setting it to
- // runtime.goexit makes clear to the traceback routines where
- // the goroutine stack ends.
- mp = runtime_allocm(nil, StackMin, &g0_sp, &g0_spsize);
- gp = runtime_malg(StackMin, &sp, &spsize);
- gp->status = Gdead;
- mp->curg = gp;
- mp->locked = LockInternal;
- mp->lockedg = gp;
- gp->lockedm = mp;
- gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1);
- // put on allg for garbage collector
- allgadd(gp);
-
- // The context for gp will be set up in runtime_needm. But
- // here we need to set up the context for g0.
- getcontext(&mp->g0->context);
- mp->g0->context.uc_stack.ss_sp = g0_sp;
- mp->g0->context.uc_stack.ss_size = g0_spsize;
- makecontext(&mp->g0->context, kickoff, 0);
-
- // Add m to the extra list.
- mnext = lockextra(true);
- mp->schedlink = mnext;
- unlockextra(mp);
-}
+void makeGContext(G*, byte*, uintptr)
+ __asm__(GOSYM_PREFIX "runtime.makeGContext");
-// dropm is called when a cgo callback has called needm but is now
-// done with the callback and returning back into the non-Go thread.
-// It puts the current m back onto the extra list.
-//
-// The main expense here is the call to signalstack to release the
-// m's signal stack, and then the call to needm on the next callback
-// from this thread. It is tempting to try to save the m for next time,
-// which would eliminate both these costs, but there might not be
-// a next time: the current thread (which Go does not control) might exit.
-// If we saved the m for that thread, there would be an m leak each time
-// such a thread exited. Instead, we acquire and release an m on each
-// call. These should typically not be scheduling operations, just a few
-// atomics, so the cost should be small.
-//
-// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
-// variable using pthread_key_create. Unlike the pthread keys we already use
-// on OS X, this dummy key would never be read by Go code. It would exist
-// only so that we could register at thread-exit-time destructor.
-// That destructor would put the m back onto the extra list.
-// This is purely a performance optimization. The current version,
-// in which dropm happens on each cgo call, is still correct too.
-// We may have to keep the current version on systems with cgo
-// but without pthreads, like Windows.
+// makeGContext makes a new context for a g.
void
-runtime_dropm(void)
-{
- M *mp, *mnext;
-
- // Undo whatever initialization minit did during needm.
- runtime_unminit();
+makeGContext(G* gp, byte* sp, uintptr spsize) {
+ ucontext_t *uc;
- // Clear m and g, and return m to the extra list.
- // After the call to setmg we can only call nosplit functions.
- mp = m;
- runtime_setmg(nil, nil);
-
- mp->curg->status = Gdead;
- mp->curg->gcstack = nil;
- mp->curg->gcnext_sp = nil;
-
- mnext = lockextra(true);
- mp->schedlink = mnext;
- unlockextra(mp);
-}
-
-#define MLOCKED ((M*)1)
-
-// lockextra locks the extra list and returns the list head.
-// The caller must unlock the list by storing a new list head
-// to runtime.extram. If nilokay is true, then lockextra will
-// return a nil list head if that's what it finds. If nilokay is false,
-// lockextra will keep waiting until the list head is no longer nil.
-static M*
-lockextra(bool nilokay)
-{
- M *mp;
- void (*yield)(void);
-
- for(;;) {
- mp = runtime_atomicloadp(&runtime_extram);
- if(mp == MLOCKED) {
- yield = runtime_osyield;
- yield();
- continue;
- }
- if(mp == nil && !nilokay) {
- runtime_usleep(1);
- continue;
- }
- if(!runtime_casp(&runtime_extram, mp, MLOCKED)) {
- yield = runtime_osyield;
- yield();
- continue;
- }
- break;
- }
- return mp;
-}
-
-static void
-unlockextra(M *mp)
-{
- runtime_atomicstorep(&runtime_extram, mp);
-}
-
-static int32
-countextra()
-{
- M *mp, *mc;
- int32 c;
-
- for(;;) {
- mp = runtime_atomicloadp(&runtime_extram);
- if(mp == MLOCKED) {
- runtime_osyield();
- continue;
- }
- if(!runtime_casp(&runtime_extram, mp, MLOCKED)) {
- runtime_osyield();
- continue;
- }
- c = 0;
- for(mc = mp; mc != nil; mc = mc->schedlink)
- c++;
- runtime_atomicstorep(&runtime_extram, mp);
- return c;
- }
+ uc = ucontext_arg(&gp->context[0]);
+ getcontext(uc);
+ uc->uc_stack.ss_sp = sp;
+ uc->uc_stack.ss_size = (size_t)spsize;
+ makecontext(uc, kickoff, 0);
}
// Create a new m. It will start off with a call to fn, or else the scheduler.
-static void
+void
newm(void(*fn)(void), P *p)
{
M *mp;
- mp = runtime_allocm(p, -1, nil, nil);
- mp->nextp = p;
- mp->mstartfn = fn;
+ mp = runtime_allocm(p, false, nil, nil);
+ mp->nextp = (uintptr)p;
+ mp->mstartfn = (uintptr)(void*)fn;
runtime_newosproc(mp);
}
-// Stops execution of the current m until new work is available.
-// Returns with acquired P.
-static void
-stopm(void)
-{
- if(m->locks)
- runtime_throw("stopm holding locks");
- if(m->p)
- runtime_throw("stopm holding p");
- if(m->spinning) {
- m->spinning = false;
- runtime_xadd(&runtime_sched.nmspinning, -1);
- }
-
-retry:
- runtime_lock(&runtime_sched);
- mput(m);
- runtime_unlock(&runtime_sched);
- runtime_notesleep(&m->park);
- runtime_noteclear(&m->park);
- if(m->helpgc) {
- runtime_gchelper();
- m->helpgc = 0;
- m->mcache = nil;
- goto retry;
- }
- acquirep(m->nextp);
- m->nextp = nil;
-}
-
static void
mspinning(void)
{
- m->spinning = true;
+ g->m->spinning = true;
}
// Schedules some M to run the p (creates an M if necessary).
// If p==nil, tries to get an idle P, if no idle P's does nothing.
-static void
+void
startm(P *p, bool spinning)
{
M *mp;
void (*fn)(void);
- runtime_lock(&runtime_sched);
+ runtime_lock(&runtime_sched->lock);
if(p == nil) {
p = pidleget();
if(p == nil) {
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
if(spinning)
- runtime_xadd(&runtime_sched.nmspinning, -1);
+ runtime_xadd(&runtime_sched->nmspinning, -1);
return;
}
}
mp = mget();
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
if(mp == nil) {
fn = nil;
if(spinning)
@@ -1504,369 +884,39 @@ startm(P *p, bool spinning)
runtime_throw("startm: m is spinning");
if(mp->nextp)
runtime_throw("startm: m has p");
- mp->spinning = spinning;
- mp->nextp = p;
- runtime_notewakeup(&mp->park);
-}
-
-// Hands off P from syscall or locked M.
-static void
-handoffp(P *p)
-{
- // if it has local work, start it straight away
- if(p->runqhead != p->runqtail || runtime_sched.runqsize) {
- startm(p, false);
- return;
- }
- // no local work, check that there are no spinning/idle M's,
- // otherwise our help is not required
- if(runtime_atomicload(&runtime_sched.nmspinning) + runtime_atomicload(&runtime_sched.npidle) == 0 && // TODO: fast atomic
- runtime_cas(&runtime_sched.nmspinning, 0, 1)) {
- startm(p, true);
- return;
- }
- runtime_lock(&runtime_sched);
- if(runtime_sched.gcwaiting) {
- p->status = Pgcstop;
- if(--runtime_sched.stopwait == 0)
- runtime_notewakeup(&runtime_sched.stopnote);
- runtime_unlock(&runtime_sched);
- return;
- }
- if(runtime_sched.runqsize) {
- runtime_unlock(&runtime_sched);
- startm(p, false);
- return;
- }
- // If this is the last running P and nobody is polling network,
- // need to wakeup another M to poll network.
- if(runtime_sched.npidle == (uint32)runtime_gomaxprocs-1 && runtime_atomicload64(&runtime_sched.lastpoll) != 0) {
- runtime_unlock(&runtime_sched);
- startm(p, false);
- return;
- }
- pidleput(p);
- runtime_unlock(&runtime_sched);
-}
-
-// Tries to add one more P to execute G's.
-// Called when a G is made runnable (newproc, ready).
-static void
-wakep(void)
-{
- // be conservative about spinning threads
- if(!runtime_cas(&runtime_sched.nmspinning, 0, 1))
- return;
- startm(nil, true);
-}
-
-// Stops execution of the current m that is locked to a g until the g is runnable again.
-// Returns with acquired P.
-static void
-stoplockedm(void)
-{
- P *p;
-
- if(m->lockedg == nil || m->lockedg->lockedm != m)
- runtime_throw("stoplockedm: inconsistent locking");
- if(m->p) {
- // Schedule another M to run this p.
- p = releasep();
- handoffp(p);
+ if(spinning && !runqempty(p)) {
+ runtime_throw("startm: p has runnable gs");
}
- incidlelocked(1);
- // Wait until another thread schedules lockedg again.
- runtime_notesleep(&m->park);
- runtime_noteclear(&m->park);
- if(m->lockedg->status != Grunnable)
- runtime_throw("stoplockedm: not runnable");
- acquirep(m->nextp);
- m->nextp = nil;
-}
-
-// Schedules the locked m to run the locked gp.
-static void
-startlockedm(G *gp)
-{
- M *mp;
- P *p;
-
- mp = gp->lockedm;
- if(mp == m)
- runtime_throw("startlockedm: locked to me");
- if(mp->nextp)
- runtime_throw("startlockedm: m has p");
- // directly handoff current P to the locked m
- incidlelocked(-1);
- p = releasep();
- mp->nextp = p;
+ mp->spinning = spinning;
+ mp->nextp = (uintptr)p;
runtime_notewakeup(&mp->park);
- stopm();
-}
-
-// Stops the current m for stoptheworld.
-// Returns when the world is restarted.
-static void
-gcstopm(void)
-{
- P *p;
-
- if(!runtime_sched.gcwaiting)
- runtime_throw("gcstopm: not waiting for gc");
- if(m->spinning) {
- m->spinning = false;
- runtime_xadd(&runtime_sched.nmspinning, -1);
- }
- p = releasep();
- runtime_lock(&runtime_sched);
- p->status = Pgcstop;
- if(--runtime_sched.stopwait == 0)
- runtime_notewakeup(&runtime_sched.stopnote);
- runtime_unlock(&runtime_sched);
- stopm();
-}
-
-// Schedules gp to run on the current M.
-// Never returns.
-static void
-execute(G *gp)
-{
- int32 hz;
-
- if(gp->status != Grunnable) {
- runtime_printf("execute: bad g status %d\n", gp->status);
- runtime_throw("execute: bad g status");
- }
- gp->status = Grunning;
- gp->waitsince = 0;
- m->p->schedtick++;
- m->curg = gp;
- gp->m = m;
-
- // Check whether the profiler needs to be turned on or off.
- hz = runtime_sched.profilehz;
- if(m->profilehz != hz)
- runtime_resetcpuprofiler(hz);
-
- runtime_gogo(gp);
}
-// Finds a runnable goroutine to execute.
-// Tries to steal from other P's, get g from global queue, poll network.
-static G*
-findrunnable(void)
-{
- G *gp;
- P *p;
- int32 i;
-
-top:
- if(runtime_sched.gcwaiting) {
- gcstopm();
- goto top;
- }
- if(runtime_fingwait && runtime_fingwake && (gp = runtime_wakefing()) != nil)
- runtime_ready(gp);
- // local runq
- gp = runqget(m->p);
- if(gp)
- return gp;
- // global runq
- if(runtime_sched.runqsize) {
- runtime_lock(&runtime_sched);
- gp = globrunqget(m->p, 0);
- runtime_unlock(&runtime_sched);
- if(gp)
- return gp;
- }
- // poll network
- gp = runtime_netpoll(false); // non-blocking
- if(gp) {
- injectglist(gp->schedlink);
- gp->status = Grunnable;
- return gp;
- }
- // If number of spinning M's >= number of busy P's, block.
- // This is necessary to prevent excessive CPU consumption
- // when GOMAXPROCS>>1 but the program parallelism is low.
- if(!m->spinning && 2 * runtime_atomicload(&runtime_sched.nmspinning) >= runtime_gomaxprocs - runtime_atomicload(&runtime_sched.npidle)) // TODO: fast atomic
- goto stop;
- if(!m->spinning) {
- m->spinning = true;
- runtime_xadd(&runtime_sched.nmspinning, 1);
- }
- // random steal from other P's
- for(i = 0; i < 2*runtime_gomaxprocs; i++) {
- if(runtime_sched.gcwaiting)
- goto top;
- p = runtime_allp[runtime_fastrand1()%runtime_gomaxprocs];
- if(p == m->p)
- gp = runqget(p);
- else
- gp = runqsteal(m->p, p);
- if(gp)
- return gp;
- }
-stop:
- // return P and block
- runtime_lock(&runtime_sched);
- if(runtime_sched.gcwaiting) {
- runtime_unlock(&runtime_sched);
- goto top;
- }
- if(runtime_sched.runqsize) {
- gp = globrunqget(m->p, 0);
- runtime_unlock(&runtime_sched);
- return gp;
- }
- p = releasep();
- pidleput(p);
- runtime_unlock(&runtime_sched);
- if(m->spinning) {
- m->spinning = false;
- runtime_xadd(&runtime_sched.nmspinning, -1);
- }
- // check all runqueues once again
- for(i = 0; i < runtime_gomaxprocs; i++) {
- p = runtime_allp[i];
- if(p && p->runqhead != p->runqtail) {
- runtime_lock(&runtime_sched);
- p = pidleget();
- runtime_unlock(&runtime_sched);
- if(p) {
- acquirep(p);
- goto top;
- }
- break;
- }
- }
- // poll network
- if(runtime_xchg64(&runtime_sched.lastpoll, 0) != 0) {
- if(m->p)
- runtime_throw("findrunnable: netpoll with p");
- if(m->spinning)
- runtime_throw("findrunnable: netpoll with spinning");
- gp = runtime_netpoll(true); // block until new work is available
- runtime_atomicstore64(&runtime_sched.lastpoll, runtime_nanotime());
- if(gp) {
- runtime_lock(&runtime_sched);
- p = pidleget();
- runtime_unlock(&runtime_sched);
- if(p) {
- acquirep(p);
- injectglist(gp->schedlink);
- gp->status = Grunnable;
- return gp;
- }
- injectglist(gp);
- }
- }
- stopm();
- goto top;
-}
-
-static void
-resetspinning(void)
-{
- int32 nmspinning;
-
- if(m->spinning) {
- m->spinning = false;
- nmspinning = runtime_xadd(&runtime_sched.nmspinning, -1);
- if(nmspinning < 0)
- runtime_throw("findrunnable: negative nmspinning");
- } else
- nmspinning = runtime_atomicload(&runtime_sched.nmspinning);
-
- // M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
- // so see if we need to wakeup another P here.
- if (nmspinning == 0 && runtime_atomicload(&runtime_sched.npidle) > 0)
- wakep();
-}
-
-// Injects the list of runnable G's into the scheduler.
-// Can run concurrently with GC.
-static void
-injectglist(G *glist)
+// Puts the current goroutine into a waiting state and calls unlockf.
+// If unlockf returns false, the goroutine is resumed.
+void
+runtime_park(bool(*unlockf)(G*, void*), void *lock, const char *reason)
{
- int32 n;
- G *gp;
-
- if(glist == nil)
- return;
- runtime_lock(&runtime_sched);
- for(n = 0; glist; n++) {
- gp = glist;
- glist = gp->schedlink;
- gp->status = Grunnable;
- globrunqput(gp);
- }
- runtime_unlock(&runtime_sched);
-
- for(; n && runtime_sched.npidle; n--)
- startm(nil, false);
+ if(g->atomicstatus != _Grunning)
+ runtime_throw("bad g status");
+ g->m->waitlock = lock;
+ g->m->waitunlockf = unlockf;
+ g->waitreason = runtime_gostringnocopy((const byte*)reason);
+ runtime_mcall(park0);
}
-// One round of scheduler: find a runnable goroutine and execute it.
-// Never returns.
-static void
-schedule(void)
-{
- G *gp;
- uint32 tick;
-
- if(m->locks)
- runtime_throw("schedule: holding locks");
-
-top:
- if(runtime_sched.gcwaiting) {
- gcstopm();
- goto top;
- }
+void gopark(FuncVal *, void *, String, byte, int)
+ __asm__ ("runtime.gopark");
- gp = nil;
- // Check the global runnable queue once in a while to ensure fairness.
- // Otherwise two goroutines can completely occupy the local runqueue
- // by constantly respawning each other.
- tick = m->p->schedtick;
- // This is a fancy way to say tick%61==0,
- // it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors.
- if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime_sched.runqsize > 0) {
- runtime_lock(&runtime_sched);
- gp = globrunqget(m->p, 1);
- runtime_unlock(&runtime_sched);
- if(gp)
- resetspinning();
- }
- if(gp == nil) {
- gp = runqget(m->p);
- if(gp && m->spinning)
- runtime_throw("schedule: spinning with local work");
- }
- if(gp == nil) {
- gp = findrunnable(); // blocks until work is available
- resetspinning();
- }
-
- if(gp->lockedm) {
- // Hands off own p to the locked m,
- // then blocks waiting for a new p.
- startlockedm(gp);
- goto top;
- }
-
- execute(gp);
-}
-
-// Puts the current goroutine into a waiting state and calls unlockf.
-// If unlockf returns false, the goroutine is resumed.
void
-runtime_park(bool(*unlockf)(G*, void*), void *lock, const char *reason)
+gopark(FuncVal *unlockf, void *lock, String reason,
+ byte traceEv __attribute__ ((unused)),
+ int traceskip __attribute__ ((unused)))
{
- if(g->status != Grunning)
+ if(g->atomicstatus != _Grunning)
runtime_throw("bad g status");
- m->waitlock = lock;
- m->waitunlockf = unlockf;
+ g->m->waitlock = lock;
+ g->m->waitunlockf = unlockf == nil ? nil : (void*)unlockf->fn;
g->waitreason = reason;
runtime_mcall(park0);
}
@@ -1887,27 +937,44 @@ runtime_parkunlock(Lock *lock, const char *reason)
runtime_park(parkunlock, lock, reason);
}
+void goparkunlock(Lock *, String, byte, int)
+ __asm__ (GOSYM_PREFIX "runtime.goparkunlock");
+
+void
+goparkunlock(Lock *lock, String reason, byte traceEv __attribute__ ((unused)),
+ int traceskip __attribute__ ((unused)))
+{
+ if(g->atomicstatus != _Grunning)
+ runtime_throw("bad g status");
+ g->m->waitlock = lock;
+ g->m->waitunlockf = parkunlock;
+ g->waitreason = reason;
+ runtime_mcall(park0);
+}
+
// runtime_park continuation on g0.
static void
park0(G *gp)
{
+ M *m;
bool ok;
- gp->status = Gwaiting;
+ m = g->m;
+ gp->atomicstatus = _Gwaiting;
gp->m = nil;
m->curg = nil;
if(m->waitunlockf) {
- ok = m->waitunlockf(gp, m->waitlock);
+ ok = ((bool (*)(G*, void*))m->waitunlockf)(gp, m->waitlock);
m->waitunlockf = nil;
m->waitlock = nil;
if(!ok) {
- gp->status = Grunnable;
- execute(gp); // Schedule it back, never returns.
+ gp->atomicstatus = _Grunnable;
+ execute(gp, true); // Schedule it back, never returns.
}
}
if(m->lockedg) {
stoplockedm();
- execute(gp); // Never returns.
+ execute(gp, true); // Never returns.
}
schedule();
}
@@ -1916,7 +983,7 @@ park0(G *gp)
void
runtime_gosched(void)
{
- if(g->status != Grunning)
+ if(g->atomicstatus != _Grunning)
runtime_throw("bad g status");
runtime_mcall(runtime_gosched0);
}
@@ -1925,15 +992,18 @@ runtime_gosched(void)
void
runtime_gosched0(G *gp)
{
- gp->status = Grunnable;
+ M *m;
+
+ m = g->m;
+ gp->atomicstatus = _Grunnable;
gp->m = nil;
m->curg = nil;
- runtime_lock(&runtime_sched);
+ runtime_lock(&runtime_sched->lock);
globrunqput(gp);
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
if(m->lockedg) {
stoplockedm();
- execute(gp); // Never returns.
+ execute(gp, true); // Never returns.
}
schedule();
}
@@ -1942,38 +1012,43 @@ runtime_gosched0(G *gp)
// Need to mark it as nosplit, because it runs with sp > stackbase (as runtime_lessstack).
// Since it does not return it does not matter. But if it is preempted
// at the split stack check, GC will complain about inconsistent sp.
-void runtime_goexit(void) __attribute__ ((noinline));
+void runtime_goexit1(void) __attribute__ ((noinline));
void
-runtime_goexit(void)
+runtime_goexit1(void)
{
- if(g->status != Grunning)
+ if(g->atomicstatus != _Grunning)
runtime_throw("bad g status");
runtime_mcall(goexit0);
}
-// runtime_goexit continuation on g0.
+// runtime_goexit1 continuation on g0.
static void
goexit0(G *gp)
{
- gp->status = Gdead;
+ M *m;
+
+ m = g->m;
+ gp->atomicstatus = _Gdead;
gp->entry = nil;
gp->m = nil;
gp->lockedm = nil;
gp->paniconfault = 0;
- gp->defer = nil; // should be true already but just in case.
- gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
- gp->writenbuf = 0;
- gp->writebuf = nil;
- gp->waitreason = nil;
+ gp->_defer = nil; // should be true already but just in case.
+ gp->_panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
+ gp->writebuf.__values = nil;
+ gp->writebuf.__count = 0;
+ gp->writebuf.__capacity = 0;
+ gp->waitreason = runtime_gostringnocopy(nil);
gp->param = nil;
+ m->curg->m = nil;
m->curg = nil;
m->lockedg = nil;
- if(m->locked & ~LockExternal) {
+ if(m->locked & ~_LockExternal) {
runtime_printf("invalid m->locked = %d\n", m->locked);
runtime_throw("internal lockOSThread error");
}
m->locked = 0;
- gfput(m->p, gp);
+ gfput((P*)m->p, gp);
schedule();
}
@@ -1986,15 +1061,16 @@ goexit0(G *gp)
// make g->sched refer to the caller's stack segment, because
// entersyscall is going to return immediately after.
-void runtime_entersyscall(void) __attribute__ ((no_split_stack));
-static void doentersyscall(void) __attribute__ ((no_split_stack, noinline));
+void runtime_entersyscall(int32) __attribute__ ((no_split_stack));
+static void doentersyscall(uintptr, uintptr)
+ __attribute__ ((no_split_stack, noinline));
void
-runtime_entersyscall()
+runtime_entersyscall(int32 dummy __attribute__ ((unused)))
{
// Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector.
- getcontext(&g->gcregs);
+ getcontext(ucontext_arg(&g->gcregs[0]));
// Do the work in a separate function, so that this function
// doesn't save any registers on its own stack. If this
@@ -2005,84 +1081,99 @@ runtime_entersyscall()
// callee-saved registers to access the TLS variable g. We
// don't want to put the ucontext_t on the stack because it is
// large and we can not split the stack here.
- doentersyscall();
+ doentersyscall((uintptr)runtime_getcallerpc(&dummy),
+ (uintptr)runtime_getcallersp(&dummy));
}
static void
-doentersyscall()
+doentersyscall(uintptr pc, uintptr sp)
{
- // Disable preemption because during this function g is in Gsyscall status,
+ // Disable preemption because during this function g is in _Gsyscall status,
// but can have inconsistent g->sched, do not let GC observe it.
- m->locks++;
+ g->m->locks++;
// Leave SP around for GC and traceback.
#ifdef USING_SPLIT_STACK
- g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size,
- &g->gcnext_segment, &g->gcnext_sp,
- &g->gcinitial_sp);
+ {
+ size_t gcstacksize;
+ g->gcstack = __splitstack_find(nil, nil, &gcstacksize,
+ &g->gcnextsegment, &g->gcnextsp,
+ &g->gcinitialsp);
+ g->gcstacksize = (uintptr)gcstacksize;
+ }
#else
{
void *v;
- g->gcnext_sp = (byte *) &v;
+ g->gcnextsp = (byte *) &v;
}
#endif
- g->status = Gsyscall;
+ g->syscallsp = sp;
+ g->syscallpc = pc;
- if(runtime_atomicload(&runtime_sched.sysmonwait)) { // TODO: fast atomic
- runtime_lock(&runtime_sched);
- if(runtime_atomicload(&runtime_sched.sysmonwait)) {
- runtime_atomicstore(&runtime_sched.sysmonwait, 0);
- runtime_notewakeup(&runtime_sched.sysmonnote);
+ g->atomicstatus = _Gsyscall;
+
+ if(runtime_atomicload(&runtime_sched->sysmonwait)) { // TODO: fast atomic
+ runtime_lock(&runtime_sched->lock);
+ if(runtime_atomicload(&runtime_sched->sysmonwait)) {
+ runtime_atomicstore(&runtime_sched->sysmonwait, 0);
+ runtime_notewakeup(&runtime_sched->sysmonnote);
}
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
}
- m->mcache = nil;
- m->p->m = nil;
- runtime_atomicstore(&m->p->status, Psyscall);
- if(runtime_atomicload(&runtime_sched.gcwaiting)) {
- runtime_lock(&runtime_sched);
- if (runtime_sched.stopwait > 0 && runtime_cas(&m->p->status, Psyscall, Pgcstop)) {
- if(--runtime_sched.stopwait == 0)
- runtime_notewakeup(&runtime_sched.stopnote);
+ g->m->mcache = nil;
+ ((P*)(g->m->p))->m = 0;
+ runtime_atomicstore(&((P*)g->m->p)->status, _Psyscall);
+ if(runtime_atomicload(&runtime_sched->gcwaiting)) {
+ runtime_lock(&runtime_sched->lock);
+ if (runtime_sched->stopwait > 0 && runtime_cas(&((P*)g->m->p)->status, _Psyscall, _Pgcstop)) {
+ if(--runtime_sched->stopwait == 0)
+ runtime_notewakeup(&runtime_sched->stopnote);
}
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
}
- m->locks--;
+ g->m->locks--;
}
// The same as runtime_entersyscall(), but with a hint that the syscall is blocking.
void
-runtime_entersyscallblock(void)
+runtime_entersyscallblock(int32 dummy __attribute__ ((unused)))
{
P *p;
- m->locks++; // see comment in entersyscall
+ g->m->locks++; // see comment in entersyscall
// Leave SP around for GC and traceback.
#ifdef USING_SPLIT_STACK
- g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size,
- &g->gcnext_segment, &g->gcnext_sp,
- &g->gcinitial_sp);
+ {
+ size_t gcstacksize;
+ g->gcstack = __splitstack_find(nil, nil, &gcstacksize,
+ &g->gcnextsegment, &g->gcnextsp,
+ &g->gcinitialsp);
+ g->gcstacksize = (uintptr)gcstacksize;
+ }
#else
- g->gcnext_sp = (byte *) &p;
+ g->gcnextsp = (byte *) &p;
#endif
// Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector.
- getcontext(&g->gcregs);
+ getcontext(ucontext_arg(&g->gcregs[0]));
+
+ g->syscallpc = (uintptr)runtime_getcallerpc(&dummy);
+ g->syscallsp = (uintptr)runtime_getcallersp(&dummy);
- g->status = Gsyscall;
+ g->atomicstatus = _Gsyscall;
p = releasep();
handoffp(p);
if(g->isbackground) // do not consider blocked scavenger for deadlock detection
incidlelocked(1);
- m->locks--;
+ g->m->locks--;
}
// The goroutine g exited its system call.
@@ -2090,33 +1181,34 @@ runtime_entersyscallblock(void)
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
void
-runtime_exitsyscall(void)
+runtime_exitsyscall(int32 dummy __attribute__ ((unused)))
{
G *gp;
- m->locks++; // see comment in entersyscall
-
gp = g;
+ gp->m->locks++; // see comment in entersyscall
+
if(gp->isbackground) // do not consider blocked scavenger for deadlock detection
incidlelocked(-1);
- g->waitsince = 0;
+ gp->waitsince = 0;
if(exitsyscallfast()) {
// There's a cpu for us, so we can run.
- m->p->syscalltick++;
- gp->status = Grunning;
+ ((P*)gp->m->p)->syscalltick++;
+ gp->atomicstatus = _Grunning;
// Garbage collector isn't running (since we are),
// so okay to clear gcstack and gcsp.
#ifdef USING_SPLIT_STACK
gp->gcstack = nil;
#endif
- gp->gcnext_sp = nil;
- runtime_memclr(&gp->gcregs, sizeof gp->gcregs);
- m->locks--;
+ gp->gcnextsp = nil;
+ runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs);
+ gp->syscallsp = 0;
+ gp->m->locks--;
return;
}
- m->locks--;
+ gp->m->locks--;
// Call the scheduler.
runtime_mcall(exitsyscall0);
@@ -2130,42 +1222,47 @@ runtime_exitsyscall(void)
#ifdef USING_SPLIT_STACK
gp->gcstack = nil;
#endif
- gp->gcnext_sp = nil;
- runtime_memclr(&gp->gcregs, sizeof gp->gcregs);
+ gp->gcnextsp = nil;
+ runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs);
+
+ gp->syscallsp = 0;
- // Don't refer to m again, we might be running on a different
- // thread after returning from runtime_mcall.
- runtime_m()->p->syscalltick++;
+ // Note that this gp->m might be different than the earlier
+ // gp->m after returning from runtime_mcall.
+ ((P*)gp->m->p)->syscalltick++;
}
static bool
exitsyscallfast(void)
{
+ G *gp;
P *p;
+ gp = g;
+
// Freezetheworld sets stopwait but does not retake P's.
- if(runtime_sched.stopwait) {
- m->p = nil;
+ if(runtime_sched->stopwait) {
+ gp->m->p = 0;
return false;
}
// Try to re-acquire the last P.
- if(m->p && m->p->status == Psyscall && runtime_cas(&m->p->status, Psyscall, Prunning)) {
+ if(gp->m->p && ((P*)gp->m->p)->status == _Psyscall && runtime_cas(&((P*)gp->m->p)->status, _Psyscall, _Prunning)) {
// There's a cpu for us, so we can run.
- m->mcache = m->p->mcache;
- m->p->m = m;
+ gp->m->mcache = ((P*)gp->m->p)->mcache;
+ ((P*)gp->m->p)->m = (uintptr)gp->m;
return true;
}
// Try to get any other idle P.
- m->p = nil;
- if(runtime_sched.pidle) {
- runtime_lock(&runtime_sched);
+ gp->m->p = 0;
+ if(runtime_sched->pidle) {
+ runtime_lock(&runtime_sched->lock);
p = pidleget();
- if(p && runtime_atomicload(&runtime_sched.sysmonwait)) {
- runtime_atomicstore(&runtime_sched.sysmonwait, 0);
- runtime_notewakeup(&runtime_sched.sysmonnote);
+ if(p && runtime_atomicload(&runtime_sched->sysmonwait)) {
+ runtime_atomicstore(&runtime_sched->sysmonwait, 0);
+ runtime_notewakeup(&runtime_sched->sysmonnote);
}
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
if(p) {
acquirep(p);
return true;
@@ -2179,75 +1276,93 @@ exitsyscallfast(void)
static void
exitsyscall0(G *gp)
{
+ M *m;
P *p;
- gp->status = Grunnable;
+ m = g->m;
+ gp->atomicstatus = _Grunnable;
gp->m = nil;
m->curg = nil;
- runtime_lock(&runtime_sched);
+ runtime_lock(&runtime_sched->lock);
p = pidleget();
if(p == nil)
globrunqput(gp);
- else if(runtime_atomicload(&runtime_sched.sysmonwait)) {
- runtime_atomicstore(&runtime_sched.sysmonwait, 0);
- runtime_notewakeup(&runtime_sched.sysmonnote);
+ else if(runtime_atomicload(&runtime_sched->sysmonwait)) {
+ runtime_atomicstore(&runtime_sched->sysmonwait, 0);
+ runtime_notewakeup(&runtime_sched->sysmonnote);
}
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&runtime_sched->lock);
if(p) {
acquirep(p);
- execute(gp); // Never returns.
+ execute(gp, false); // Never returns.
}
if(m->lockedg) {
// Wait until another thread schedules gp and so m again.
stoplockedm();
- execute(gp); // Never returns.
+ execute(gp, false); // Never returns.
}
stopm();
schedule(); // Never returns.
}
-// Called from syscall package before fork.
-void syscall_runtime_BeforeFork(void)
- __asm__(GOSYM_PREFIX "syscall.runtime_BeforeFork");
+void syscall_entersyscall(void)
+ __asm__(GOSYM_PREFIX "syscall.Entersyscall");
+
+void syscall_entersyscall(void) __attribute__ ((no_split_stack));
+
void
-syscall_runtime_BeforeFork(void)
+syscall_entersyscall()
{
- // Fork can hang if preempted with signals frequently enough (see issue 5517).
- // Ensure that we stay on the same M where we disable profiling.
- runtime_m()->locks++;
- if(runtime_m()->profilehz != 0)
- runtime_resetcpuprofiler(0);
+ runtime_entersyscall(0);
}
-// Called from syscall package after fork in parent.
-void syscall_runtime_AfterFork(void)
- __asm__(GOSYM_PREFIX "syscall.runtime_AfterFork");
+void syscall_exitsyscall(void)
+ __asm__(GOSYM_PREFIX "syscall.Exitsyscall");
+
+void syscall_exitsyscall(void) __attribute__ ((no_split_stack));
+
void
-syscall_runtime_AfterFork(void)
+syscall_exitsyscall()
{
- int32 hz;
-
- hz = runtime_sched.profilehz;
- if(hz != 0)
- runtime_resetcpuprofiler(hz);
- runtime_m()->locks--;
+ runtime_exitsyscall(0);
}
// Allocate a new g, with a stack big enough for stacksize bytes.
G*
-runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
+runtime_malg(bool allocatestack, bool signalstack, byte** ret_stack, uintptr* ret_stacksize)
{
+ uintptr stacksize;
G *newg;
+ byte* unused_stack;
+ uintptr unused_stacksize;
+#if USING_SPLIT_STACK
+ int dont_block_signals = 0;
+ size_t ss_stacksize;
+#endif
+ if (ret_stack == nil) {
+ ret_stack = &unused_stack;
+ }
+ if (ret_stacksize == nil) {
+ ret_stacksize = &unused_stacksize;
+ }
newg = allocg();
- if(stacksize >= 0) {
-#if USING_SPLIT_STACK
- int dont_block_signals = 0;
+ if(allocatestack) {
+ stacksize = StackMin;
+ if(signalstack) {
+ stacksize = 32 * 1024; // OS X wants >= 8K, GNU/Linux >= 2K
+#ifdef SIGSTKSZ
+ if(stacksize < SIGSTKSZ)
+ stacksize = SIGSTKSZ;
+#endif
+ }
+#if USING_SPLIT_STACK
*ret_stack = __splitstack_makecontext(stacksize,
- &newg->stack_context[0],
- ret_stacksize);
- __splitstack_block_signals_context(&newg->stack_context[0],
+ &newg->stackcontext[0],
+ &ss_stacksize);
+ *ret_stacksize = (uintptr)ss_stacksize;
+ __splitstack_block_signals_context(&newg->stackcontext[0],
&dont_block_signals, nil);
#else
// In 64-bit mode, the maximum Go allocation space is
@@ -2257,7 +1372,7 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
// 32-bit mode, the Go allocation space is all of
// memory anyhow.
if(sizeof(void*) == 8) {
- void *p = runtime_SysAlloc(stacksize, &mstats.other_sys);
+ void *p = runtime_SysAlloc(stacksize, &mstats()->other_sys);
if(p == nil)
runtime_throw("runtime: cannot allocate memory for goroutine stack");
*ret_stack = (byte*)p;
@@ -2265,41 +1380,14 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
*ret_stack = runtime_mallocgc(stacksize, 0, FlagNoProfiling|FlagNoGC);
runtime_xadd(&runtime_stacks_sys, stacksize);
}
- *ret_stacksize = stacksize;
- newg->gcinitial_sp = *ret_stack;
- newg->gcstack_size = (size_t)stacksize;
+ *ret_stacksize = (uintptr)stacksize;
+ newg->gcinitialsp = *ret_stack;
+ newg->gcstacksize = (uintptr)stacksize;
#endif
}
return newg;
}
-/* For runtime package testing. */
-
-
-// Create a new g running fn with siz bytes of arguments.
-// Put it on the queue of g's waiting to run.
-// The compiler turns a go statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred. It's OK for this to call
-// functions that split the stack.
-void runtime_testing_entersyscall(int32)
- __asm__ (GOSYM_PREFIX "runtime.entersyscall");
-void
-runtime_testing_entersyscall(int32 dummy __attribute__ ((unused)))
-{
- runtime_entersyscall();
-}
-
-void runtime_testing_exitsyscall(int32)
- __asm__ (GOSYM_PREFIX "runtime.exitsyscall");
-
-void
-runtime_testing_exitsyscall(int32 dummy __attribute__ ((unused)))
-{
- runtime_exitsyscall();
-}
-
G*
__go_go(void (*fn)(void*), void* arg)
{
@@ -2310,155 +1398,55 @@ __go_go(void (*fn)(void*), void* arg)
//runtime_printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret);
if(fn == nil) {
- m->throwing = -1; // do not dump full stacks
+ g->m->throwing = -1; // do not dump full stacks
runtime_throw("go of nil func value");
}
- m->locks++; // disable preemption because it can be holding p in a local var
+ g->m->locks++; // disable preemption because it can be holding p in a local var
- p = m->p;
+ p = (P*)g->m->p;
if((newg = gfget(p)) != nil) {
#ifdef USING_SPLIT_STACK
int dont_block_signals = 0;
- sp = __splitstack_resetcontext(&newg->stack_context[0],
+ sp = __splitstack_resetcontext(&newg->stackcontext[0],
&spsize);
- __splitstack_block_signals_context(&newg->stack_context[0],
+ __splitstack_block_signals_context(&newg->stackcontext[0],
&dont_block_signals, nil);
#else
- sp = newg->gcinitial_sp;
- spsize = newg->gcstack_size;
+ sp = newg->gcinitialsp;
+ spsize = newg->gcstacksize;
if(spsize == 0)
runtime_throw("bad spsize in __go_go");
- newg->gcnext_sp = sp;
+ newg->gcnextsp = sp;
#endif
+ newg->traceback = nil;
} else {
- newg = runtime_malg(StackMin, &sp, &spsize);
+ uintptr malsize;
+
+ newg = runtime_malg(true, false, &sp, &malsize);
+ spsize = (size_t)malsize;
+ newg->atomicstatus = _Gdead;
allgadd(newg);
}
newg->entry = (byte*)fn;
newg->param = arg;
newg->gopc = (uintptr)__builtin_return_address(0);
- newg->status = Grunnable;
+ newg->atomicstatus = _Grunnable;
if(p->goidcache == p->goidcacheend) {
- p->goidcache = runtime_xadd64(&runtime_sched.goidgen, GoidCacheBatch);
+ p->goidcache = runtime_xadd64(&runtime_sched->goidgen, GoidCacheBatch);
p->goidcacheend = p->goidcache + GoidCacheBatch;
}
newg->goid = p->goidcache++;
- {
- // Avoid warnings about variables clobbered by
- // longjmp.
- byte * volatile vsp = sp;
- size_t volatile vspsize = spsize;
- G * volatile vnewg = newg;
-
- getcontext(&vnewg->context);
- vnewg->context.uc_stack.ss_sp = vsp;
-#ifdef MAKECONTEXT_STACK_TOP
- vnewg->context.uc_stack.ss_sp += vspsize;
-#endif
- vnewg->context.uc_stack.ss_size = vspsize;
- makecontext(&vnewg->context, kickoff, 0);
-
- runqput(p, vnewg);
-
- if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0 && fn != runtime_main) // TODO: fast atomic
- wakep();
- m->locks--;
- return vnewg;
- }
-}
-
-static void
-allgadd(G *gp)
-{
- G **new;
- uintptr cap;
-
- runtime_lock(&allglock);
- if(runtime_allglen >= allgcap) {
- cap = 4096/sizeof(new[0]);
- if(cap < 2*allgcap)
- cap = 2*allgcap;
- new = runtime_malloc(cap*sizeof(new[0]));
- if(new == nil)
- runtime_throw("runtime: cannot allocate memory");
- if(runtime_allg != nil) {
- runtime_memmove(new, runtime_allg, runtime_allglen*sizeof(new[0]));
- runtime_free(runtime_allg);
- }
- runtime_allg = new;
- allgcap = cap;
- }
- runtime_allg[runtime_allglen++] = gp;
- runtime_unlock(&allglock);
-}
-
-// Put on gfree list.
-// If local list is too long, transfer a batch to the global list.
-static void
-gfput(P *p, G *gp)
-{
- gp->schedlink = p->gfree;
- p->gfree = gp;
- p->gfreecnt++;
- if(p->gfreecnt >= 64) {
- runtime_lock(&runtime_sched.gflock);
- while(p->gfreecnt >= 32) {
- p->gfreecnt--;
- gp = p->gfree;
- p->gfree = gp->schedlink;
- gp->schedlink = runtime_sched.gfree;
- runtime_sched.gfree = gp;
- }
- runtime_unlock(&runtime_sched.gflock);
- }
-}
+ makeGContext(newg, sp, (uintptr)spsize);
-// Get from gfree list.
-// If local list is empty, grab a batch from global list.
-static G*
-gfget(P *p)
-{
- G *gp;
+ runqput(p, newg, true);
-retry:
- gp = p->gfree;
- if(gp == nil && runtime_sched.gfree) {
- runtime_lock(&runtime_sched.gflock);
- while(p->gfreecnt < 32 && runtime_sched.gfree) {
- p->gfreecnt++;
- gp = runtime_sched.gfree;
- runtime_sched.gfree = gp->schedlink;
- gp->schedlink = p->gfree;
- p->gfree = gp;
- }
- runtime_unlock(&runtime_sched.gflock);
- goto retry;
- }
- if(gp) {
- p->gfree = gp->schedlink;
- p->gfreecnt--;
- }
- return gp;
-}
-
-// Purge all cached G's from gfree list to the global list.
-static void
-gfpurge(P *p)
-{
- G *gp;
-
- runtime_lock(&runtime_sched.gflock);
- while(p->gfreecnt) {
- p->gfreecnt--;
- gp = p->gfree;
- p->gfree = gp->schedlink;
- gp->schedlink = runtime_sched.gfree;
- runtime_sched.gfree = gp;
- }
- runtime_unlock(&runtime_sched.gflock);
+ if(runtime_atomicload(&runtime_sched->npidle) != 0 && runtime_atomicload(&runtime_sched->nmspinning) == 0 && fn != runtime_main) // TODO: fast atomic
+ wakep();
+ g->m->locks--;
+ return newg;
}
void
@@ -2475,131 +1463,9 @@ runtime_Gosched(void)
runtime_gosched();
}
-// Implementation of runtime.GOMAXPROCS.
-// delete when scheduler is even stronger
-int32
-runtime_gomaxprocsfunc(int32 n)
-{
- int32 ret;
-
- if(n > MaxGomaxprocs)
- n = MaxGomaxprocs;
- runtime_lock(&runtime_sched);
- ret = runtime_gomaxprocs;
- if(n <= 0 || n == ret) {
- runtime_unlock(&runtime_sched);
- return ret;
- }
- runtime_unlock(&runtime_sched);
-
- runtime_semacquire(&runtime_worldsema, false);
- m->gcing = 1;
- runtime_stoptheworld();
- newprocs = n;
- m->gcing = 0;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
-
- return ret;
-}
-
-// lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below
-// after they modify m->locked. Do not allow preemption during this call,
-// or else the m might be different in this function than in the caller.
-static void
-lockOSThread(void)
-{
- m->lockedg = g;
- g->lockedm = m;
-}
-
-void runtime_LockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.LockOSThread");
-void
-runtime_LockOSThread(void)
-{
- m->locked |= LockExternal;
- lockOSThread();
-}
-
-void
-runtime_lockOSThread(void)
-{
- m->locked += LockInternal;
- lockOSThread();
-}
-
-
-// unlockOSThread is called by runtime.UnlockOSThread and runtime.unlockOSThread below
-// after they update m->locked. Do not allow preemption during this call,
-// or else the m might be in different in this function than in the caller.
-static void
-unlockOSThread(void)
-{
- if(m->locked != 0)
- return;
- m->lockedg = nil;
- g->lockedm = nil;
-}
-
-void runtime_UnlockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.UnlockOSThread");
-
-void
-runtime_UnlockOSThread(void)
-{
- m->locked &= ~LockExternal;
- unlockOSThread();
-}
-
-void
-runtime_unlockOSThread(void)
-{
- if(m->locked < LockInternal)
- runtime_throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
- m->locked -= LockInternal;
- unlockOSThread();
-}
-
-bool
-runtime_lockedOSThread(void)
-{
- return g->lockedm != nil && m->lockedg != nil;
-}
-
-int32
-runtime_gcount(void)
-{
- G *gp;
- int32 n, s;
- uintptr i;
-
- n = 0;
- runtime_lock(&allglock);
- // TODO(dvyukov): runtime.NumGoroutine() is O(N).
- // We do not want to increment/decrement centralized counter in newproc/goexit,
- // just to make runtime.NumGoroutine() faster.
- // Compromise solution is to introduce per-P counters of active goroutines.
- for(i = 0; i < runtime_allglen; i++) {
- gp = runtime_allg[i];
- s = gp->status;
- if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
- n++;
- }
- runtime_unlock(&allglock);
- return n;
-}
-
-int32
-runtime_mcount(void)
-{
- return runtime_sched.mcount;
-}
-
static struct {
- Lock;
- void (*fn)(uintptr*, int32);
+ uint32 lock;
int32 hz;
- uintptr pcbuf[TracebackMaxFrames];
- Location locbuf[TracebackMaxFrames];
} prof;
static void System(void) {}
@@ -2609,11 +1475,14 @@ static void GC(void) {}
void
runtime_sigprof()
{
- M *mp = m;
+ M *mp = g->m;
int32 n, i;
bool traceback;
+ uintptr pcbuf[TracebackMaxFrames];
+ Location locbuf[TracebackMaxFrames];
+ Slice stk;
- if(prof.fn == nil || prof.hz == 0)
+ if(prof.hz == 0)
return;
if(mp == nil)
@@ -2627,12 +1496,6 @@ runtime_sigprof()
if(mp->mcache == nil)
traceback = false;
- runtime_lock(&prof);
- if(prof.fn == nil) {
- runtime_unlock(&prof);
- mp->mallocing--;
- return;
- }
n = 0;
if(runtime_atomicload(&runtime_in_callers) > 0) {
@@ -2644,797 +1507,68 @@ runtime_sigprof()
}
if(traceback) {
- n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf), false);
+ n = runtime_callers(0, locbuf, nelem(locbuf), false);
for(i = 0; i < n; i++)
- prof.pcbuf[i] = prof.locbuf[i].pc;
+ pcbuf[i] = locbuf[i].pc;
}
if(!traceback || n <= 0) {
n = 2;
- prof.pcbuf[0] = (uintptr)runtime_getcallerpc(&n);
+ pcbuf[0] = (uintptr)runtime_getcallerpc(&n);
if(mp->gcing || mp->helpgc)
- prof.pcbuf[1] = (uintptr)GC;
+ pcbuf[1] = (uintptr)GC;
else
- prof.pcbuf[1] = (uintptr)System;
+ pcbuf[1] = (uintptr)System;
+ }
+
+ if (prof.hz != 0) {
+ stk.__values = &pcbuf[0];
+ stk.__count = n;
+ stk.__capacity = n;
+
+ // Simple cas-lock to coordinate with setcpuprofilerate.
+ while (!runtime_cas(&prof.lock, 0, 1)) {
+ runtime_osyield();
+ }
+ if (prof.hz != 0) {
+ runtime_cpuprofAdd(stk);
+ }
+ runtime_atomicstore(&prof.lock, 0);
}
- prof.fn(prof.pcbuf, n);
- runtime_unlock(&prof);
+
mp->mallocing--;
}
// Arrange to call fn with a traceback hz times a second.
void
-runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
+runtime_setcpuprofilerate_m(int32 hz)
{
// Force sane arguments.
if(hz < 0)
hz = 0;
- if(hz == 0)
- fn = nil;
- if(fn == nil)
- hz = 0;
// Disable preemption, otherwise we can be rescheduled to another thread
// that has profiling enabled.
- m->locks++;
+ g->m->locks++;
// Stop profiler on this thread so that it is safe to lock prof.
// if a profiling signal came in while we had prof locked,
// it would deadlock.
runtime_resetcpuprofiler(0);
- runtime_lock(&prof);
- prof.fn = fn;
+ while (!runtime_cas(&prof.lock, 0, 1)) {
+ runtime_osyield();
+ }
prof.hz = hz;
- runtime_unlock(&prof);
- runtime_lock(&runtime_sched);
- runtime_sched.profilehz = hz;
- runtime_unlock(&runtime_sched);
+ runtime_atomicstore(&prof.lock, 0);
+
+ runtime_lock(&runtime_sched->lock);
+ runtime_sched->profilehz = hz;
+ runtime_unlock(&runtime_sched->lock);
if(hz != 0)
runtime_resetcpuprofiler(hz);
- m->locks--;
-}
-
-// Change number of processors. The world is stopped, sched is locked.
-static void
-procresize(int32 new)
-{
- int32 i, old;
- bool empty;
- G *gp;
- P *p;
-
- old = runtime_gomaxprocs;
- if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs)
- runtime_throw("procresize: invalid arg");
- // initialize new P's
- for(i = 0; i < new; i++) {
- p = runtime_allp[i];
- if(p == nil) {
- p = (P*)runtime_mallocgc(sizeof(*p), 0, FlagNoInvokeGC);
- p->id = i;
- p->status = Pgcstop;
- runtime_atomicstorep(&runtime_allp[i], p);
- }
- if(p->mcache == nil) {
- if(old==0 && i==0)
- p->mcache = m->mcache; // bootstrap
- else
- p->mcache = runtime_allocmcache();
- }
- }
-
- // redistribute runnable G's evenly
- // collect all runnable goroutines in global queue preserving FIFO order
- // FIFO order is required to ensure fairness even during frequent GCs
- // see http://golang.org/issue/7126
- empty = false;
- while(!empty) {
- empty = true;
- for(i = 0; i < old; i++) {
- p = runtime_allp[i];
- if(p->runqhead == p->runqtail)
- continue;
- empty = false;
- // pop from tail of local queue
- p->runqtail--;
- gp = p->runq[p->runqtail%nelem(p->runq)];
- // push onto head of global queue
- gp->schedlink = runtime_sched.runqhead;
- runtime_sched.runqhead = gp;
- if(runtime_sched.runqtail == nil)
- runtime_sched.runqtail = gp;
- runtime_sched.runqsize++;
- }
- }
- // fill local queues with at most nelem(p->runq)/2 goroutines
- // start at 1 because current M already executes some G and will acquire allp[0] below,
- // so if we have a spare G we want to put it into allp[1].
- for(i = 1; (uint32)i < (uint32)new * nelem(p->runq)/2 && runtime_sched.runqsize > 0; i++) {
- gp = runtime_sched.runqhead;
- runtime_sched.runqhead = gp->schedlink;
- if(runtime_sched.runqhead == nil)
- runtime_sched.runqtail = nil;
- runtime_sched.runqsize--;
- runqput(runtime_allp[i%new], gp);
- }
-
- // free unused P's
- for(i = new; i < old; i++) {
- p = runtime_allp[i];
- runtime_freemcache(p->mcache);
- p->mcache = nil;
- gfpurge(p);
- p->status = Pdead;
- // can't free P itself because it can be referenced by an M in syscall
- }
-
- if(m->p)
- m->p->m = nil;
- m->p = nil;
- m->mcache = nil;
- p = runtime_allp[0];
- p->m = nil;
- p->status = Pidle;
- acquirep(p);
- for(i = new-1; i > 0; i--) {
- p = runtime_allp[i];
- p->status = Pidle;
- pidleput(p);
- }
- runtime_atomicstore((uint32*)&runtime_gomaxprocs, new);
-}
-
-// Associate p and the current m.
-static void
-acquirep(P *p)
-{
- if(m->p || m->mcache)
- runtime_throw("acquirep: already in go");
- if(p->m || p->status != Pidle) {
- runtime_printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status);
- runtime_throw("acquirep: invalid p state");
- }
- m->mcache = p->mcache;
- m->p = p;
- p->m = m;
- p->status = Prunning;
-}
-
-// Disassociate p and the current m.
-static P*
-releasep(void)
-{
- P *p;
-
- if(m->p == nil || m->mcache == nil)
- runtime_throw("releasep: invalid arg");
- p = m->p;
- if(p->m != m || p->mcache != m->mcache || p->status != Prunning) {
- runtime_printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n",
- m, m->p, p->m, m->mcache, p->mcache, p->status);
- runtime_throw("releasep: invalid p state");
- }
- m->p = nil;
- m->mcache = nil;
- p->m = nil;
- p->status = Pidle;
- return p;
-}
-
-static void
-incidlelocked(int32 v)
-{
- runtime_lock(&runtime_sched);
- runtime_sched.nmidlelocked += v;
- if(v > 0)
- checkdead();
- runtime_unlock(&runtime_sched);
-}
-
-// Check for deadlock situation.
-// The check is based on number of running M's, if 0 -> deadlock.
-static void
-checkdead(void)
-{
- G *gp;
- int32 run, grunning, s;
- uintptr i;
-
- // For -buildmode=c-shared or -buildmode=c-archive it's OK if
- // there are no running goroutines. The calling program is
- // assumed to be running.
- if(runtime_isarchive) {
- return;
- }
-
- // -1 for sysmon
- run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.nmidlelocked - 1 - countextra();
- if(run > 0)
- return;
- // If we are dying because of a signal caught on an already idle thread,
- // freezetheworld will cause all running threads to block.
- // And runtime will essentially enter into deadlock state,
- // except that there is a thread that will call runtime_exit soon.
- if(runtime_panicking > 0)
- return;
- if(run < 0) {
- runtime_printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
- runtime_sched.nmidle, runtime_sched.nmidlelocked, runtime_sched.mcount);
- runtime_throw("checkdead: inconsistent counts");
- }
- grunning = 0;
- runtime_lock(&allglock);
- for(i = 0; i < runtime_allglen; i++) {
- gp = runtime_allg[i];
- if(gp->isbackground)
- continue;
- s = gp->status;
- if(s == Gwaiting)
- grunning++;
- else if(s == Grunnable || s == Grunning || s == Gsyscall) {
- runtime_unlock(&allglock);
- runtime_printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
- runtime_throw("checkdead: runnable g");
- }
- }
- runtime_unlock(&allglock);
- if(grunning == 0) // possible if main goroutine calls runtime_Goexit()
- runtime_throw("no goroutines (main called runtime.Goexit) - deadlock!");
- m->throwing = -1; // do not dump full stacks
- runtime_throw("all goroutines are asleep - deadlock!");
-}
-
-static void
-sysmon(void)
-{
- uint32 idle, delay;
- int64 now, lastpoll, lasttrace;
- G *gp;
-
- lasttrace = 0;
- idle = 0; // how many cycles in succession we had not wokeup somebody
- delay = 0;
- for(;;) {
- if(idle == 0) // start with 20us sleep...
- delay = 20;
- else if(idle > 50) // start doubling the sleep after 1ms...
- delay *= 2;
- if(delay > 10*1000) // up to 10ms
- delay = 10*1000;
- runtime_usleep(delay);
- if(runtime_debug.schedtrace <= 0 &&
- (runtime_sched.gcwaiting || runtime_atomicload(&runtime_sched.npidle) == (uint32)runtime_gomaxprocs)) { // TODO: fast atomic
- runtime_lock(&runtime_sched);
- if(runtime_atomicload(&runtime_sched.gcwaiting) || runtime_atomicload(&runtime_sched.npidle) == (uint32)runtime_gomaxprocs) {
- runtime_atomicstore(&runtime_sched.sysmonwait, 1);
- runtime_unlock(&runtime_sched);
- runtime_notesleep(&runtime_sched.sysmonnote);
- runtime_noteclear(&runtime_sched.sysmonnote);
- idle = 0;
- delay = 20;
- } else
- runtime_unlock(&runtime_sched);
- }
- // poll network if not polled for more than 10ms
- lastpoll = runtime_atomicload64(&runtime_sched.lastpoll);
- now = runtime_nanotime();
- if(lastpoll != 0 && lastpoll + 10*1000*1000 < now) {
- runtime_cas64(&runtime_sched.lastpoll, lastpoll, now);
- gp = runtime_netpoll(false); // non-blocking
- if(gp) {
- // Need to decrement number of idle locked M's
- // (pretending that one more is running) before injectglist.
- // Otherwise it can lead to the following situation:
- // injectglist grabs all P's but before it starts M's to run the P's,
- // another M returns from syscall, finishes running its G,
- // observes that there is no work to do and no other running M's
- // and reports deadlock.
- incidlelocked(-1);
- injectglist(gp);
- incidlelocked(1);
- }
- }
- // retake P's blocked in syscalls
- // and preempt long running G's
- if(retake(now))
- idle = 0;
- else
- idle++;
-
- if(runtime_debug.schedtrace > 0 && lasttrace + runtime_debug.schedtrace*1000000ll <= now) {
- lasttrace = now;
- runtime_schedtrace(runtime_debug.scheddetail);
- }
- }
-}
-
-typedef struct Pdesc Pdesc;
-struct Pdesc
-{
- uint32 schedtick;
- int64 schedwhen;
- uint32 syscalltick;
- int64 syscallwhen;
-};
-static Pdesc pdesc[MaxGomaxprocs];
-
-static uint32
-retake(int64 now)
-{
- uint32 i, s, n;
- int64 t;
- P *p;
- Pdesc *pd;
-
- n = 0;
- for(i = 0; i < (uint32)runtime_gomaxprocs; i++) {
- p = runtime_allp[i];
- if(p==nil)
- continue;
- pd = &pdesc[i];
- s = p->status;
- if(s == Psyscall) {
- // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
- t = p->syscalltick;
- if(pd->syscalltick != t) {
- pd->syscalltick = t;
- pd->syscallwhen = now;
- continue;
- }
- // On the one hand we don't want to retake Ps if there is no other work to do,
- // but on the other hand we want to retake them eventually
- // because they can prevent the sysmon thread from deep sleep.
- if(p->runqhead == p->runqtail &&
- runtime_atomicload(&runtime_sched.nmspinning) + runtime_atomicload(&runtime_sched.npidle) > 0 &&
- pd->syscallwhen + 10*1000*1000 > now)
- continue;
- // Need to decrement number of idle locked M's
- // (pretending that one more is running) before the CAS.
- // Otherwise the M from which we retake can exit the syscall,
- // increment nmidle and report deadlock.
- incidlelocked(-1);
- if(runtime_cas(&p->status, s, Pidle)) {
- n++;
- handoffp(p);
- }
- incidlelocked(1);
- } else if(s == Prunning) {
- // Preempt G if it's running for more than 10ms.
- t = p->schedtick;
- if(pd->schedtick != t) {
- pd->schedtick = t;
- pd->schedwhen = now;
- continue;
- }
- if(pd->schedwhen + 10*1000*1000 > now)
- continue;
- // preemptone(p);
- }
- }
- return n;
-}
-
-// Tell all goroutines that they have been preempted and they should stop.
-// This function is purely best-effort. It can fail to inform a goroutine if a
-// processor just started running it.
-// No locks need to be held.
-// Returns true if preemption request was issued to at least one goroutine.
-static bool
-preemptall(void)
-{
- return false;
-}
-
-void
-runtime_schedtrace(bool detailed)
-{
- static int64 starttime;
- int64 now;
- int64 id1, id2, id3;
- int32 i, t, h;
- uintptr gi;
- const char *fmt;
- M *mp, *lockedm;
- G *gp, *lockedg;
- P *p;
-
- now = runtime_nanotime();
- if(starttime == 0)
- starttime = now;
-
- runtime_lock(&runtime_sched);
- runtime_printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d idlethreads=%d runqueue=%d",
- (now-starttime)/1000000, runtime_gomaxprocs, runtime_sched.npidle, runtime_sched.mcount,
- runtime_sched.nmidle, runtime_sched.runqsize);
- if(detailed) {
- runtime_printf(" gcwaiting=%d nmidlelocked=%d nmspinning=%d stopwait=%d sysmonwait=%d\n",
- runtime_sched.gcwaiting, runtime_sched.nmidlelocked, runtime_sched.nmspinning,
- runtime_sched.stopwait, runtime_sched.sysmonwait);
- }
- // We must be careful while reading data from P's, M's and G's.
- // Even if we hold schedlock, most data can be changed concurrently.
- // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
- for(i = 0; i < runtime_gomaxprocs; i++) {
- p = runtime_allp[i];
- if(p == nil)
- continue;
- mp = p->m;
- h = runtime_atomicload(&p->runqhead);
- t = runtime_atomicload(&p->runqtail);
- if(detailed)
- runtime_printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
- i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
- else {
- // In non-detailed mode format lengths of per-P run queues as:
- // [len1 len2 len3 len4]
- fmt = " %d";
- if(runtime_gomaxprocs == 1)
- fmt = " [%d]\n";
- else if(i == 0)
- fmt = " [%d";
- else if(i == runtime_gomaxprocs-1)
- fmt = " %d]\n";
- runtime_printf(fmt, t-h);
- }
- }
- if(!detailed) {
- runtime_unlock(&runtime_sched);
- return;
- }
- for(mp = runtime_allm; mp; mp = mp->alllink) {
- p = mp->p;
- gp = mp->curg;
- lockedg = mp->lockedg;
- id1 = -1;
- if(p)
- id1 = p->id;
- id2 = -1;
- if(gp)
- id2 = gp->goid;
- id3 = -1;
- if(lockedg)
- id3 = lockedg->goid;
- runtime_printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
- " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
- mp->id, id1, id2,
- mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
- mp->spinning, m->blocked, id3);
- }
- runtime_lock(&allglock);
- for(gi = 0; gi < runtime_allglen; gi++) {
- gp = runtime_allg[gi];
- mp = gp->m;
- lockedm = gp->lockedm;
- runtime_printf(" G%D: status=%d(%s) m=%d lockedm=%d\n",
- gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1,
- lockedm ? lockedm->id : -1);
- }
- runtime_unlock(&allglock);
- runtime_unlock(&runtime_sched);
-}
-
-// Put mp on midle list.
-// Sched must be locked.
-static void
-mput(M *mp)
-{
- mp->schedlink = runtime_sched.midle;
- runtime_sched.midle = mp;
- runtime_sched.nmidle++;
- checkdead();
-}
-
-// Try to get an m from midle list.
-// Sched must be locked.
-static M*
-mget(void)
-{
- M *mp;
-
- if((mp = runtime_sched.midle) != nil){
- runtime_sched.midle = mp->schedlink;
- runtime_sched.nmidle--;
- }
- return mp;
-}
-
-// Put gp on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqput(G *gp)
-{
- gp->schedlink = nil;
- if(runtime_sched.runqtail)
- runtime_sched.runqtail->schedlink = gp;
- else
- runtime_sched.runqhead = gp;
- runtime_sched.runqtail = gp;
- runtime_sched.runqsize++;
-}
-
-// Put a batch of runnable goroutines on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqputbatch(G *ghead, G *gtail, int32 n)
-{
- gtail->schedlink = nil;
- if(runtime_sched.runqtail)
- runtime_sched.runqtail->schedlink = ghead;
- else
- runtime_sched.runqhead = ghead;
- runtime_sched.runqtail = gtail;
- runtime_sched.runqsize += n;
-}
-
-// Try get a batch of G's from the global runnable queue.
-// Sched must be locked.
-static G*
-globrunqget(P *p, int32 max)
-{
- G *gp, *gp1;
- int32 n;
-
- if(runtime_sched.runqsize == 0)
- return nil;
- n = runtime_sched.runqsize/runtime_gomaxprocs+1;
- if(n > runtime_sched.runqsize)
- n = runtime_sched.runqsize;
- if(max > 0 && n > max)
- n = max;
- if((uint32)n > nelem(p->runq)/2)
- n = nelem(p->runq)/2;
- runtime_sched.runqsize -= n;
- if(runtime_sched.runqsize == 0)
- runtime_sched.runqtail = nil;
- gp = runtime_sched.runqhead;
- runtime_sched.runqhead = gp->schedlink;
- n--;
- while(n--) {
- gp1 = runtime_sched.runqhead;
- runtime_sched.runqhead = gp1->schedlink;
- runqput(p, gp1);
- }
- return gp;
-}
-
-// Put p to on pidle list.
-// Sched must be locked.
-static void
-pidleput(P *p)
-{
- p->link = runtime_sched.pidle;
- runtime_sched.pidle = p;
- runtime_xadd(&runtime_sched.npidle, 1); // TODO: fast atomic
-}
-
-// Try get a p from pidle list.
-// Sched must be locked.
-static P*
-pidleget(void)
-{
- P *p;
-
- p = runtime_sched.pidle;
- if(p) {
- runtime_sched.pidle = p->link;
- runtime_xadd(&runtime_sched.npidle, -1); // TODO: fast atomic
- }
- return p;
-}
-
-// Try to put g on local runnable queue.
-// If it's full, put onto global queue.
-// Executed only by the owner P.
-static void
-runqput(P *p, G *gp)
-{
- uint32 h, t;
-
-retry:
- h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers
- t = p->runqtail;
- if(t - h < nelem(p->runq)) {
- p->runq[t%nelem(p->runq)] = gp;
- runtime_atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption
- return;
- }
- if(runqputslow(p, gp, h, t))
- return;
- // the queue is not full, now the put above must suceed
- goto retry;
-}
-
-// Put g and a batch of work from local runnable queue on global queue.
-// Executed only by the owner P.
-static bool
-runqputslow(P *p, G *gp, uint32 h, uint32 t)
-{
- G *batch[nelem(p->runq)/2+1];
- uint32 n, i;
-
- // First, grab a batch from local queue.
- n = t-h;
- n = n/2;
- if(n != nelem(p->runq)/2)
- runtime_throw("runqputslow: queue is not full");
- for(i=0; i<n; i++)
- batch[i] = p->runq[(h+i)%nelem(p->runq)];
- if(!runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume
- return false;
- batch[n] = gp;
- // Link the goroutines.
- for(i=0; i<n; i++)
- batch[i]->schedlink = batch[i+1];
- // Now put the batch on global queue.
- runtime_lock(&runtime_sched);
- globrunqputbatch(batch[0], batch[n], n+1);
- runtime_unlock(&runtime_sched);
- return true;
-}
-
-// Get g from local runnable queue.
-// Executed only by the owner P.
-static G*
-runqget(P *p)
-{
- G *gp;
- uint32 t, h;
-
- for(;;) {
- h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
- t = p->runqtail;
- if(t == h)
- return nil;
- gp = p->runq[h%nelem(p->runq)];
- if(runtime_cas(&p->runqhead, h, h+1)) // cas-release, commits consume
- return gp;
- }
-}
-
-// Grabs a batch of goroutines from local runnable queue.
-// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
-// Can be executed by any P.
-static uint32
-runqgrab(P *p, G **batch)
-{
- uint32 t, h, n, i;
-
- for(;;) {
- h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
- t = runtime_atomicload(&p->runqtail); // load-acquire, synchronize with the producer
- n = t-h;
- n = n - n/2;
- if(n == 0)
- break;
- if(n > nelem(p->runq)/2) // read inconsistent h and t
- continue;
- for(i=0; i<n; i++)
- batch[i] = p->runq[(h+i)%nelem(p->runq)];
- if(runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume
- break;
- }
- return n;
-}
-
-// Steal half of elements from local runnable queue of p2
-// and put onto local runnable queue of p.
-// Returns one of the stolen elements (or nil if failed).
-static G*
-runqsteal(P *p, P *p2)
-{
- G *gp;
- G *batch[nelem(p->runq)/2];
- uint32 t, h, n, i;
-
- n = runqgrab(p2, batch);
- if(n == 0)
- return nil;
- n--;
- gp = batch[n];
- if(n == 0)
- return gp;
- h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers
- t = p->runqtail;
- if(t - h + n >= nelem(p->runq))
- runtime_throw("runqsteal: runq overflow");
- for(i=0; i<n; i++, t++)
- p->runq[t%nelem(p->runq)] = batch[i];
- runtime_atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption
- return gp;
-}
-
-void runtime_testSchedLocalQueue(void)
- __asm__("runtime.testSchedLocalQueue");
-
-void
-runtime_testSchedLocalQueue(void)
-{
- P p;
- G gs[nelem(p.runq)];
- int32 i, j;
-
- runtime_memclr((byte*)&p, sizeof(p));
-
- for(i = 0; i < (int32)nelem(gs); i++) {
- if(runqget(&p) != nil)
- runtime_throw("runq is not empty initially");
- for(j = 0; j < i; j++)
- runqput(&p, &gs[i]);
- for(j = 0; j < i; j++) {
- if(runqget(&p) != &gs[i]) {
- runtime_printf("bad element at iter %d/%d\n", i, j);
- runtime_throw("bad element");
- }
- }
- if(runqget(&p) != nil)
- runtime_throw("runq is not empty afterwards");
- }
-}
-
-void runtime_testSchedLocalQueueSteal(void)
- __asm__("runtime.testSchedLocalQueueSteal");
-
-void
-runtime_testSchedLocalQueueSteal(void)
-{
- P p1, p2;
- G gs[nelem(p1.runq)], *gp;
- int32 i, j, s;
-
- runtime_memclr((byte*)&p1, sizeof(p1));
- runtime_memclr((byte*)&p2, sizeof(p2));
-
- for(i = 0; i < (int32)nelem(gs); i++) {
- for(j = 0; j < i; j++) {
- gs[j].sig = 0;
- runqput(&p1, &gs[j]);
- }
- gp = runqsteal(&p2, &p1);
- s = 0;
- if(gp) {
- s++;
- gp->sig++;
- }
- while((gp = runqget(&p2)) != nil) {
- s++;
- gp->sig++;
- }
- while((gp = runqget(&p1)) != nil)
- gp->sig++;
- for(j = 0; j < i; j++) {
- if(gs[j].sig != 1) {
- runtime_printf("bad element %d(%d) at iter %d\n", j, gs[j].sig, i);
- runtime_throw("bad element");
- }
- }
- if(s != i/2 && s != i/2+1) {
- runtime_printf("bad steal %d, want %d or %d, iter %d\n",
- s, i/2, i/2+1, i);
- runtime_throw("bad steal");
- }
- }
-}
-
-int32
-runtime_setmaxthreads(int32 in)
-{
- int32 out;
-
- runtime_lock(&runtime_sched);
- out = runtime_sched.maxmcount;
- runtime_sched.maxmcount = in;
- checkmcount();
- runtime_unlock(&runtime_sched);
- return out;
-}
-
-void
-runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- enqueue1(wbufp, (Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0});
- enqueue1(wbufp, (Obj){(byte*)&runtime_main_init_done, sizeof runtime_main_init_done, 0});
+ g->m->locks--;
}
// Return whether we are waiting for a GC. This gc toolchain uses
@@ -3442,7 +1576,7 @@ runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj
bool
runtime_gcwaiting(void)
{
- return runtime_sched.gcwaiting;
+ return runtime_sched->gcwaiting;
}
// os_beforeExit is called from os.Exit(0).
@@ -3455,43 +1589,10 @@ os_beforeExit()
{
}
-// Active spinning for sync.Mutex.
-//go:linkname sync_runtime_canSpin sync.runtime_canSpin
-
-enum
-{
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
-};
-
-extern _Bool sync_runtime_canSpin(intgo i)
- __asm__ (GOSYM_PREFIX "sync.runtime_canSpin");
+intgo NumCPU(void) __asm__ (GOSYM_PREFIX "runtime.NumCPU");
-_Bool
-sync_runtime_canSpin(intgo i)
-{
- P *p;
-
- // sync.Mutex is cooperative, so we are conservative with spinning.
- // Spin only few times and only if running on a multicore machine and
- // GOMAXPROCS>1 and there is at least one other running P and local runq is empty.
- // As opposed to runtime mutex we don't do passive spinning here,
- // because there can be work on global runq on on other Ps.
- if (i >= ACTIVE_SPIN || runtime_ncpu <= 1 || runtime_gomaxprocs <= (int32)(runtime_sched.npidle+runtime_sched.nmspinning)+1) {
- return false;
- }
- p = m->p;
- return p != nil && p->runqhead == p->runqtail;
-}
-
-//go:linkname sync_runtime_doSpin sync.runtime_doSpin
-//go:nosplit
-
-extern void sync_runtime_doSpin(void)
- __asm__ (GOSYM_PREFIX "sync.runtime_doSpin");
-
-void
-sync_runtime_doSpin()
+intgo
+NumCPU()
{
- runtime_procyield(ACTIVE_SPIN_CNT);
+ return (intgo)(runtime_ncpu);
}
diff --git a/libgo/runtime/rdebug.goc b/libgo/runtime/rdebug.goc
deleted file mode 100644
index 63eb4dd457..0000000000
--- a/libgo/runtime/rdebug.goc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime_debug
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-
-func setMaxStack(in int) (out int) {
- out = runtime_maxstacksize;
- runtime_maxstacksize = in;
-}
-
-func setGCPercent(in int) (out int) {
- out = runtime_setgcpercent(in);
-}
-
-func setMaxThreads(in int) (out int) {
- out = runtime_setmaxthreads(in);
-}
-
-func SetPanicOnFault(enabled bool) (old bool) {
- old = runtime_g()->paniconfault;
- runtime_g()->paniconfault = enabled;
-}
diff --git a/libgo/runtime/reflect.goc b/libgo/runtime/reflect.goc
deleted file mode 100644
index 4e493ee810..0000000000
--- a/libgo/runtime/reflect.goc
+++ /dev/null
@@ -1,25 +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 reflect
-#include "runtime.h"
-#include "go-type.h"
-#include "interface.h"
-#include "go-panic.h"
-
-func ifaceE2I(inter *Type, e Eface, ret *Iface) {
- const Type *t;
- Eface err;
-
- t = e.__type_descriptor;
- if(t == nil) {
- // explicit conversions require non-nil interface value.
- runtime_newTypeAssertionError(
- nil, nil, inter->__reflection,
- nil, &err);
- runtime_panic(err);
- }
- ret->__object = e.__object;
- ret->__methods = __go_convert_interface(inter, t);
-}
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
deleted file mode 100644
index 4140d33d04..0000000000
--- a/libgo/runtime/runtime.c
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <signal.h>
-#include <unistd.h>
-
-#include "config.h"
-
-#include "runtime.h"
-#include "arch.h"
-#include "array.h"
-
-enum {
- maxround = sizeof(uintptr),
-};
-
-// Keep a cached value to make gotraceback fast,
-// since we call it on every call to gentraceback.
-// The cached value is a uint32 in which the low bit
-// is the "crash" setting and the top 31 bits are the
-// gotraceback value.
-enum {
- tracebackCrash = 1 << 0,
- tracebackAll = 1 << 1,
- tracebackShift = 2,
-};
-static uint32 traceback_cache = 2 << tracebackShift;
-static uint32 traceback_env;
-
-extern volatile intgo runtime_MemProfileRate
- __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
-
-
-// gotraceback returns the current traceback settings.
-//
-// If level is 0, suppress all tracebacks.
-// If level is 1, show tracebacks, but exclude runtime frames.
-// If level is 2, show tracebacks including runtime frames.
-// If all is set, print all goroutine stacks. Otherwise, print just the current goroutine.
-// If crash is set, crash (core dump, etc) after tracebacking.
-int32
-runtime_gotraceback(bool *crash)
-{
- uint32 x;
-
- if(crash != nil)
- *crash = false;
- if(runtime_m()->traceback != 0)
- return runtime_m()->traceback;
- x = runtime_atomicload(&traceback_cache);
- if(crash != nil)
- *crash = x&tracebackCrash;
- return x>>tracebackShift;
-}
-
-static int32 argc;
-static byte** argv;
-
-static Slice args;
-Slice envs;
-
-void (*runtime_sysargs)(int32, uint8**);
-
-void
-runtime_args(int32 c, byte **v)
-{
- argc = c;
- argv = v;
- if(runtime_sysargs != nil)
- runtime_sysargs(c, v);
-}
-
-byte*
-runtime_progname()
-{
- return argc == 0 ? nil : argv[0];
-}
-
-void
-runtime_goargs(void)
-{
- String *s;
- int32 i;
-
- // for windows implementation see "os" package
- if(Windows)
- return;
-
- s = runtime_malloc(argc*sizeof s[0]);
- for(i=0; i<argc; i++)
- s[i] = runtime_gostringnocopy((const byte*)argv[i]);
- args.__values = (void*)s;
- args.__count = argc;
- args.__capacity = argc;
-}
-
-void
-runtime_goenvs_unix(void)
-{
- String *s;
- int32 i, n;
-
- for(n=0; argv[argc+1+n] != 0; n++)
- ;
-
- s = runtime_malloc(n*sizeof s[0]);
- for(i=0; i<n; i++)
- s[i] = runtime_gostringnocopy(argv[argc+1+i]);
- envs.__values = (void*)s;
- envs.__count = n;
- envs.__capacity = n;
-}
-
-// Called from the syscall package.
-Slice runtime_envs(void) __asm__ (GOSYM_PREFIX "syscall.runtime_envs");
-
-Slice
-runtime_envs()
-{
- return envs;
-}
-
-Slice os_runtime_args(void) __asm__ (GOSYM_PREFIX "os.runtime_args");
-
-Slice
-os_runtime_args()
-{
- return args;
-}
-
-int32
-runtime_atoi(const byte *p, intgo len)
-{
- int32 n;
-
- n = 0;
- while(len > 0 && '0' <= *p && *p <= '9') {
- n = n*10 + *p++ - '0';
- len--;
- }
- return n;
-}
-
-static struct root_list runtime_roots =
-{ nil,
- { { &envs, sizeof envs },
- { &args, sizeof args },
- { nil, 0 } },
-};
-
-static void
-TestAtomic64(void)
-{
- uint64 z64, x64;
-
- z64 = 42;
- x64 = 0;
- PREFETCH(&z64);
- if(runtime_cas64(&z64, x64, 1))
- runtime_throw("cas64 failed");
- if(x64 != 0)
- runtime_throw("cas64 failed");
- x64 = 42;
- if(!runtime_cas64(&z64, x64, 1))
- runtime_throw("cas64 failed");
- if(x64 != 42 || z64 != 1)
- runtime_throw("cas64 failed");
- if(runtime_atomicload64(&z64) != 1)
- runtime_throw("load64 failed");
- runtime_atomicstore64(&z64, (1ull<<40)+1);
- if(runtime_atomicload64(&z64) != (1ull<<40)+1)
- runtime_throw("store64 failed");
- if(runtime_xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
- runtime_throw("xadd64 failed");
- if(runtime_atomicload64(&z64) != (2ull<<40)+2)
- runtime_throw("xadd64 failed");
- if(runtime_xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
- runtime_throw("xchg64 failed");
- if(runtime_atomicload64(&z64) != (3ull<<40)+3)
- runtime_throw("xchg64 failed");
-}
-
-void
-runtime_check(void)
-{
- __go_register_gc_roots(&runtime_roots);
-
- TestAtomic64();
-}
-
-uint32
-runtime_fastrand1(void)
-{
- M *m;
- uint32 x;
-
- m = runtime_m();
- x = m->fastrand;
- x += x;
- if(x & 0x80000000L)
- x ^= 0x88888eefUL;
- m->fastrand = x;
- return x;
-}
-
-int64
-runtime_cputicks(void)
-{
-#if defined(__386__) || defined(__x86_64__)
- uint32 low, high;
- asm("rdtsc" : "=a" (low), "=d" (high));
- return (int64)(((uint64)high << 32) | (uint64)low);
-#elif defined (__s390__) || defined (__s390x__)
- uint64 clock = 0;
- /* stckf may not write the return variable in case of a clock error, so make
- it read-write to prevent that the initialisation is optimised out.
- Note: Targets below z9-109 will crash when executing store clock fast, i.e.
- we don't support Go for machines older than that. */
- asm volatile(".insn s,0xb27c0000,%0" /* stckf */ : "+Q" (clock) : : "cc" );
- return (int64)clock;
-#else
- // FIXME: implement for other processors.
- return 0;
-#endif
-}
-
-bool
-runtime_showframe(String s, bool current)
-{
- static int32 traceback = -1;
-
- if(current && runtime_m()->throwing > 0)
- return 1;
- if(traceback < 0)
- traceback = runtime_gotraceback(nil);
- return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
-}
-
-static Lock ticksLock;
-static int64 ticks;
-
-int64
-runtime_tickspersecond(void)
-{
- int64 res, t0, t1, c0, c1;
-
- res = (int64)runtime_atomicload64((uint64*)&ticks);
- if(res != 0)
- return ticks;
- runtime_lock(&ticksLock);
- res = ticks;
- if(res == 0) {
- t0 = runtime_nanotime();
- c0 = runtime_cputicks();
- runtime_usleep(100*1000);
- t1 = runtime_nanotime();
- c1 = runtime_cputicks();
- if(t1 == t0)
- t1++;
- res = (c1-c0)*1000*1000*1000/(t1-t0);
- if(res == 0)
- res++;
- runtime_atomicstore64((uint64*)&ticks, res);
- }
- runtime_unlock(&ticksLock);
- return res;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime_mpreinit(M *mp)
-{
- mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime_minit(void)
-{
- M* m;
- sigset_t sigs;
-
- // Initialize signal handling.
- m = runtime_m();
- runtime_signalstack(m->gsignalstack, m->gsignalstacksize);
- if (sigemptyset(&sigs) != 0)
- runtime_throw("sigemptyset");
- pthread_sigmask(SIG_SETMASK, &sigs, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime_unminit(void)
-{
- runtime_signalstack(nil, 0);
-}
-
-
-void
-runtime_signalstack(byte *p, int32 n)
-{
- stack_t st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- if(sigaltstack(&st, nil) < 0)
- *(int *)0xf1 = 0xf1;
-}
-
-void setTraceback(String level)
- __asm__ (GOSYM_PREFIX "runtime_debug.SetTraceback");
-
-void setTraceback(String level) {
- uint32 t;
-
- if (level.len == 4 && __builtin_memcmp(level.str, "none", 4) == 0) {
- t = 0;
- } else if (level.len == 0 || (level.len == 6 && __builtin_memcmp(level.str, "single", 6) == 0)) {
- t = 1 << tracebackShift;
- } else if (level.len == 3 && __builtin_memcmp(level.str, "all", 3) == 0) {
- t = (1<<tracebackShift) | tracebackAll;
- } else if (level.len == 6 && __builtin_memcmp(level.str, "system", 6) == 0) {
- t = (2<<tracebackShift) | tracebackAll;
- } else if (level.len == 5 && __builtin_memcmp(level.str, "crash", 5) == 0) {
- t = (2<<tracebackShift) | tracebackAll | tracebackCrash;
- } else {
- t = (runtime_atoi(level.str, level.len)<<tracebackShift) | tracebackAll;
- }
-
- t |= traceback_env;
-
- runtime_atomicstore(&traceback_cache, t);
-}
-
-DebugVars runtime_debug;
-
-// Holds variables parsed from GODEBUG env var,
-// except for "memprofilerate" since there is an
-// existing var for that value which is int
-// instead of in32 and might have an
-// initial value.
-static struct {
- const char* name;
- int32* value;
-} dbgvar[] = {
- {"allocfreetrace", &runtime_debug.allocfreetrace},
- {"cgocheck", &runtime_debug.cgocheck},
- {"efence", &runtime_debug.efence},
- {"gccheckmark", &runtime_debug.gccheckmark},
- {"gcpacertrace", &runtime_debug.gcpacertrace},
- {"gcshrinkstackoff", &runtime_debug.gcshrinkstackoff},
- {"gcstackbarrieroff", &runtime_debug.gcstackbarrieroff},
- {"gcstackbarrierall", &runtime_debug.gcstackbarrierall},
- {"gcstoptheworld", &runtime_debug.gcstoptheworld},
- {"gctrace", &runtime_debug.gctrace},
- {"gcdead", &runtime_debug.gcdead},
- {"invalidptr", &runtime_debug.invalidptr},
- {"sbrk", &runtime_debug.sbrk},
- {"scavenge", &runtime_debug.scavenge},
- {"scheddetail", &runtime_debug.scheddetail},
- {"schedtrace", &runtime_debug.schedtrace},
- {"wbshadow", &runtime_debug.wbshadow},
-};
-
-void
-runtime_parsedebugvars(void)
-{
- String s;
- const byte *p, *pn;
- intgo len;
- intgo i, n;
-
- s = runtime_getenv("GODEBUG");
- if(s.len == 0)
- return;
- p = s.str;
- len = s.len;
- for(;;) {
- for(i=0; i<(intgo)nelem(dbgvar); i++) {
- n = runtime_findnull((const byte*)dbgvar[i].name);
- if(len > n && runtime_mcmp(p, "memprofilerate", n) == 0 && p[n] == '=')
- // Set the MemProfileRate directly since it
- // is an int, not int32, and should only lbe
- // set here if specified by GODEBUG
- runtime_MemProfileRate = runtime_atoi(p+n+1, len-(n+1));
- else if(len > n && runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=')
- *dbgvar[i].value = runtime_atoi(p+n+1, len-(n+1));
- }
- pn = (const byte *)runtime_strstr((const char *)p, ",");
- if(pn == nil || pn - p >= len)
- break;
- len -= (pn - p) - 1;
- p = pn + 1;
- }
-
- setTraceback(runtime_getenv("GOTRACEBACK"));
- traceback_env = traceback_cache;
-}
-
-// SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
-// the "environment" traceback level, so later calls to
-// debug.SetTraceback (e.g., from testing timeouts) can't lower it.
-void SetTracebackEnv(String level)
- __asm__ (GOSYM_PREFIX "runtime.SetTracebackEnv");
-
-void SetTracebackEnv(String level) {
- setTraceback(level);
- traceback_env = traceback_cache;
-}
-
-// Poor mans 64-bit division.
-// This is a very special function, do not use it if you are not sure what you are doing.
-// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
-// Handles overflow in a time-specific manner.
-int32
-runtime_timediv(int64 v, int32 div, int32 *rem)
-{
- int32 res, bit;
-
- if(v >= (int64)div*0x7fffffffLL) {
- if(rem != nil)
- *rem = 0;
- return 0x7fffffff;
- }
- res = 0;
- for(bit = 30; bit >= 0; bit--) {
- if(v >= ((int64)div<<bit)) {
- v = v - ((int64)div<<bit);
- res += 1<<bit;
- }
- }
- if(rem != nil)
- *rem = v;
- return res;
-}
-
-// Setting the max stack size doesn't really do anything for gccgo.
-
-uintptr runtime_maxstacksize = 1<<20; // enough until runtime.main sets it for real
-
-void memclrBytes(Slice)
- __asm__ (GOSYM_PREFIX "runtime.memclrBytes");
-
-void
-memclrBytes(Slice s)
-{
- runtime_memclr(s.__values, s.__count);
-}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 73c46e9117..644fe92865 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -7,6 +7,7 @@
#include "go-assert.h"
#include <complex.h>
#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -22,9 +23,6 @@
#include <sys/mman.h>
#endif
-#include "interface.h"
-#include "go-alloc.h"
-
#define _STRINGIFY2_(x) #x
#define _STRINGIFY_(x) _STRINGIFY2_(x)
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
@@ -53,36 +51,35 @@ typedef uintptr uintreg;
/* Defined types. */
-typedef uint8 bool;
+typedef _Bool bool;
typedef uint8 byte;
-typedef struct Func Func;
-typedef struct G G;
-typedef struct Lock Lock;
-typedef struct M M;
-typedef struct P P;
-typedef struct Note Note;
+typedef struct g G;
+typedef struct mutex Lock;
+typedef struct m M;
+typedef struct p P;
+typedef struct note Note;
typedef struct String String;
typedef struct FuncVal FuncVal;
typedef struct SigTab SigTab;
-typedef struct MCache MCache;
+typedef struct mcache MCache;
typedef struct FixAlloc FixAlloc;
-typedef struct Hchan Hchan;
-typedef struct Timers Timers;
-typedef struct Timer Timer;
-typedef struct GCStats GCStats;
-typedef struct LFNode LFNode;
+typedef struct hchan Hchan;
+typedef struct timer Timer;
+typedef struct gcstats GCStats;
+typedef struct lfnode LFNode;
typedef struct ParFor ParFor;
typedef struct ParForThread ParForThread;
-typedef struct CgoMal CgoMal;
+typedef struct cgoMal CgoMal;
typedef struct PollDesc PollDesc;
-typedef struct DebugVars DebugVars;
+typedef struct sudog SudoG;
+typedef struct schedt Sched;
typedef struct __go_open_array Slice;
-typedef struct __go_interface Iface;
-typedef struct __go_empty_interface Eface;
+typedef struct iface Iface;
+typedef struct eface Eface;
typedef struct __go_type_descriptor Type;
-typedef struct __go_defer_stack Defer;
-typedef struct __go_panic_stack Panic;
+typedef struct _defer Defer;
+typedef struct _panic Panic;
typedef struct __go_ptr_type PtrType;
typedef struct __go_func_type FuncType;
@@ -90,46 +87,44 @@ typedef struct __go_interface_type InterfaceType;
typedef struct __go_map_type MapType;
typedef struct __go_channel_type ChanType;
-typedef struct Traceback Traceback;
+typedef struct tracebackg Traceback;
+
+typedef struct location Location;
-typedef struct Location Location;
+struct String
+{
+ const byte* str;
+ intgo len;
+};
+
+struct FuncVal
+{
+ void (*fn)(void);
+ // variable-size, fn-specific data here
+};
+
+#include "array.h"
+
+// Rename Go types generated by mkrsysinfo.sh from C types, to avoid
+// the name conflict.
+#define timeval go_timeval
+#define timespec go_timespec
+
+#include "runtime.inc"
+
+#undef timeval
+#undef timespec
/*
* Per-CPU declaration.
*/
extern M* runtime_m(void);
-extern G* runtime_g(void);
+extern G* runtime_g(void)
+ __asm__(GOSYM_PREFIX "runtime.getg");
extern M runtime_m0;
extern G runtime_g0;
-/*
- * defined constants
- */
-enum
-{
- // G status
- //
- // If you add to this list, add to the list
- // of "okay during garbage collection" status
- // in mgc0.c too.
- Gidle,
- Grunnable,
- Grunning,
- Gsyscall,
- Gwaiting,
- Gmoribund_unused, // currently unused, but hardcoded in gdb scripts
- Gdead,
-};
-enum
-{
- // P status
- Pidle,
- Prunning,
- Psyscall,
- Pgcstop,
- Pdead,
-};
enum
{
true = 1,
@@ -146,184 +141,6 @@ enum
// Global <-> per-M stack segment cache transfer batch size.
StackCacheBatch = 16,
};
-/*
- * structures
- */
-struct Lock
-{
- // Futex-based impl treats it as uint32 key,
- // while sema-based impl as M* waitm.
- // Used to be a union, but unions break precise GC.
- uintptr key;
-};
-struct Note
-{
- // Futex-based impl treats it as uint32 key,
- // while sema-based impl as M* waitm.
- // Used to be a union, but unions break precise GC.
- uintptr key;
-};
-struct String
-{
- const byte* str;
- intgo len;
-};
-struct FuncVal
-{
- void (*fn)(void);
- // variable-size, fn-specific data here
-};
-struct GCStats
-{
- // the struct must consist of only uint64's,
- // because it is casted to uint64[].
- uint64 nhandoff;
- uint64 nhandoffcnt;
- uint64 nprocyield;
- uint64 nosyield;
- uint64 nsleep;
-};
-
-// A location in the program, used for backtraces.
-struct Location
-{
- uintptr pc;
- String filename;
- String function;
- intgo lineno;
-};
-
-struct G
-{
- Defer* defer;
- Panic* panic;
- void* exception; // current exception being thrown
- bool is_foreign; // whether current exception from other language
- void *gcstack; // if status==Gsyscall, gcstack = stackbase to use during gc
- size_t gcstack_size;
- void* gcnext_segment;
- void* gcnext_sp;
- void* gcinitial_sp;
- ucontext_t gcregs;
- byte* entry; // initial function
- void* param; // passed parameter on wakeup
- bool fromgogo; // reached from gogo
- int16 status;
- uint32 selgen; // valid sudog pointer
- int64 goid;
- int64 waitsince; // approx time when the G become blocked
- const char* waitreason; // if status==Gwaiting
- G* schedlink;
- bool ispanic;
- bool issystem; // do not output in stack dump
- bool isbackground; // ignore in deadlock detector
- bool paniconfault; // panic (instead of crash) on unexpected fault address
- M* m; // for debuggers, but offset not hard-coded
- M* lockedm;
- int32 sig;
- int32 writenbuf;
- byte* writebuf;
- uintptr sigcode0;
- uintptr sigcode1;
- // uintptr sigpc;
- uintptr gopc; // pc of go statement that created this goroutine
-
- int32 ncgo;
- CgoMal* cgomal;
-
- Traceback* traceback;
-
- ucontext_t context;
- void* stack_context[10];
-};
-
-struct M
-{
- G* g0; // goroutine with scheduling stack
- G* gsignal; // signal-handling G
- byte* gsignalstack;
- size_t gsignalstacksize;
- void (*mstartfn)(void);
- G* curg; // current running goroutine
- G* caughtsig; // goroutine running during fatal signal
- P* p; // attached P for executing Go code (nil if not executing Go code)
- P* nextp;
- int32 id;
- int32 mallocing;
- int32 throwing;
- int32 gcing;
- int32 locks;
- int32 softfloat;
- int32 dying;
- int32 profilehz;
- int32 helpgc;
- bool spinning; // M is out of work and is actively looking for work
- bool blocked; // M is blocked on a Note
- uint32 fastrand;
- uint64 ncgocall; // number of cgo calls in total
- int32 ncgo; // number of cgo calls currently in progress
- CgoMal* cgomal;
- Note park;
- M* alllink; // on allm
- M* schedlink;
- MCache *mcache;
- G* lockedg;
- Location createstack[32]; // Stack that created this thread.
- uint32 locked; // tracking for LockOSThread
- M* nextwaitm; // next M waiting for lock
- uintptr waitsema; // semaphore for parking on locks
- uint32 waitsemacount;
- uint32 waitsemalock;
- GCStats gcstats;
- bool needextram;
- bool dropextram; // for gccgo: drop after call is done.
- uint8 traceback;
- bool (*waitunlockf)(G*, void*);
- void* waitlock;
- uintptr end[];
-};
-
-struct P
-{
- Lock;
-
- int32 id;
- uint32 status; // one of Pidle/Prunning/...
- P* link;
- uint32 schedtick; // incremented on every scheduler call
- uint32 syscalltick; // incremented on every system call
- M* m; // back-link to associated M (nil if idle)
- MCache* mcache;
- Defer* deferpool; // pool of available Defer structs (see panic.c)
-
- // Cache of goroutine ids, amortizes accesses to runtime_sched.goidgen.
- uint64 goidcache;
- uint64 goidcacheend;
-
- // Queue of runnable goroutines.
- uint32 runqhead;
- uint32 runqtail;
- G* runq[256];
-
- // Available G's (status == Gdead)
- G* gfree;
- int32 gfreecnt;
-
- byte pad[64];
-};
-
-// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
-// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
-// External locks are not recursive; a second lock is silently ignored.
-// The upper bits of m->lockedcount record the nesting depth of calls to lockOSThread
-// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
-// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
-// goroutine is holding the lock during the initialization phase.
-enum
-{
- LockExternal = 1,
- LockInternal = 2,
-};
struct SigTab
{
@@ -331,26 +148,6 @@ struct SigTab
int32 flags;
void* fwdsig;
};
-enum
-{
- SigNotify = 1<<0, // let signal.Notify have signal, even if from kernel
- SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly
- SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
- SigPanic = 1<<3, // if the signal is from the kernel, panic
- SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
- SigHandling = 1<<5, // our signal handler is registered
- SigGoExit = 1<<6, // cause all runtime procs to exit (only used on Plan 9).
-};
-
-// Layout of in-memory per-function information prepared by linker
-// See http://golang.org/s/go12symtab.
-// Keep in sync with linker and with ../../libmach/sym.c
-// and with package debug/gosym.
-struct Func
-{
- String name;
- uintptr entry; // entry pc
-};
#ifdef GOOS_nacl
enum {
@@ -381,43 +178,6 @@ enum {
};
#endif
-struct Timers
-{
- Lock;
- G *timerproc;
- bool sleeping;
- bool rescheduling;
- Note waitnote;
- Timer **t;
- int32 len;
- int32 cap;
-};
-
-// Package time knows the layout of this structure.
-// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
-// For GOOS=nacl, package syscall knows the layout of this structure.
-// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
-struct Timer
-{
- intgo i; // heap index
-
- // Timer wakes up at when, and then at when+period, ... (period > 0 only)
- // each time calling f(now, arg) in the timer goroutine, so f must be
- // a well-behaved function and not block.
- int64 when;
- int64 period;
- FuncVal *fv;
- Eface arg;
- uintptr seq;
-};
-
-// Lock-free stack node.
-struct LFNode
-{
- LFNode *next;
- uintptr pushcnt;
-};
-
// Parallel for descriptor.
struct ParFor
{
@@ -431,43 +191,13 @@ struct ParFor
// otherwise parfor may return while other threads are still working
ParForThread *thr; // array of thread descriptors
// stats
- uint64 nsteal;
+ uint64 nsteal __attribute__((aligned(8))); // force alignment for m68k
uint64 nstealcnt;
uint64 nprocyield;
uint64 nosyield;
uint64 nsleep;
};
-// Track memory allocated by code not written in Go during a cgo call,
-// so that the garbage collector can see them.
-struct CgoMal
-{
- CgoMal *next;
- void *alloc;
-};
-
-// Holds variables parsed from GODEBUG env var.
-struct DebugVars
-{
- int32 allocfreetrace;
- int32 cgocheck;
- int32 efence;
- int32 gccheckmark;
- int32 gcpacertrace;
- int32 gcshrinkstackoff;
- int32 gcstackbarrieroff;
- int32 gcstackbarrierall;
- int32 gcstoptheworld;
- int32 gctrace;
- int32 gcdead;
- int32 invalidptr;
- int32 sbrk;
- int32 scavenge;
- int32 scheddetail;
- int32 schedtrace;
- int32 wbshadow;
-};
-
extern bool runtime_precisestack;
extern bool runtime_copystack;
@@ -481,18 +211,16 @@ extern bool runtime_copystack;
#define USED(v) ((void) v)
#define ROUND(x, n) (((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
-byte* runtime_startup_random_data;
-uint32 runtime_startup_random_data_len;
-void runtime_get_random_data(byte**, int32*);
-
enum {
// hashinit wants this many random bytes
HashRandomBytes = 32
};
void runtime_hashinit(void);
-void runtime_traceback(void);
-void runtime_tracebackothers(G*);
+void runtime_traceback(int32)
+ __asm__ (GOSYM_PREFIX "runtime.traceback");
+void runtime_tracebackothers(G*)
+ __asm__ (GOSYM_PREFIX "runtime.tracebackothers");
enum
{
// The maximum number of frames we print for a traceback
@@ -502,21 +230,23 @@ enum
/*
* external data
*/
-extern uintptr runtime_zerobase;
-extern G** runtime_allg;
-extern uintptr runtime_allglen;
+extern uintptr* runtime_getZerobase(void)
+ __asm__(GOSYM_PREFIX "runtime.getZerobase");
+extern G* runtime_getallg(intgo)
+ __asm__(GOSYM_PREFIX "runtime.getallg");
+extern uintptr runtime_getallglen(void)
+ __asm__(GOSYM_PREFIX "runtime.getallglen");
extern G* runtime_lastg;
-extern M* runtime_allm;
+extern M* runtime_getallm(void)
+ __asm__(GOSYM_PREFIX "runtime.getallm");
extern P** runtime_allp;
-extern int32 runtime_gomaxprocs;
-extern uint32 runtime_needextram;
-extern uint32 runtime_panicking;
+extern Sched* runtime_sched;
+extern uint32 runtime_panicking(void)
+ __asm__ (GOSYM_PREFIX "runtime.getPanicking");
extern int8* runtime_goos;
extern int32 runtime_ncpu;
extern void (*runtime_sysargs)(int32, uint8**);
-extern uint32 runtime_Hchansize;
-extern DebugVars runtime_debug;
-extern uintptr runtime_maxstacksize;
+extern struct debugVars runtime_debug;
extern bool runtime_isstarted;
extern bool runtime_isarchive;
@@ -527,63 +257,66 @@ extern bool runtime_isarchive;
#define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
#define runtime_strncmp(s1, s2, n) __builtin_strncmp((s1), (s2), (n))
#define runtime_strstr(s1, s2) __builtin_strstr((s1), (s2))
-intgo runtime_findnull(const byte*);
-intgo runtime_findnullw(const uint16*);
-void runtime_dump(byte*, int32);
+intgo runtime_findnull(const byte*)
+ __asm__ (GOSYM_PREFIX "runtime.findnull");
-void runtime_gogo(G*);
+void runtime_gogo(G*)
+ __asm__ (GOSYM_PREFIX "runtime.gogo");
struct __go_func_type;
-void runtime_args(int32, byte**);
+void runtime_args(int32, byte**)
+ __asm__ (GOSYM_PREFIX "runtime.args");
void runtime_osinit();
-void runtime_goargs(void);
+void runtime_alginit(void)
+ __asm__ (GOSYM_PREFIX "runtime.alginit");
+void runtime_goargs(void)
+ __asm__ (GOSYM_PREFIX "runtime.goargs");
void runtime_goenvs(void);
-void runtime_goenvs_unix(void);
+void runtime_goenvs_unix(void)
+ __asm__ (GOSYM_PREFIX "runtime.goenvs_unix");
void runtime_throw(const char*) __attribute__ ((noreturn));
void runtime_panicstring(const char*) __attribute__ ((noreturn));
bool runtime_canpanic(G*);
-void runtime_prints(const char*);
void runtime_printf(const char*, ...);
int32 runtime_snprintf(byte*, int32, const char*, ...);
#define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
#define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
void* runtime_mal(uintptr);
-String runtime_gostring(const byte*);
-String runtime_gostringnocopy(const byte*);
+String runtime_gostringnocopy(const byte*)
+ __asm__ (GOSYM_PREFIX "runtime.gostringnocopy");
void runtime_schedinit(void);
-void runtime_initsig(bool);
-void runtime_sigenable(uint32 sig);
-void runtime_sigdisable(uint32 sig);
-void runtime_sigignore(uint32 sig);
+void runtime_initsig(bool)
+ __asm__ (GOSYM_PREFIX "runtime.initsig");
int32 runtime_gotraceback(bool *crash);
-void runtime_goroutineheader(G*);
-void runtime_printtrace(Location*, int32, bool);
+void runtime_goroutineheader(G*)
+ __asm__ (GOSYM_PREFIX "runtime.goroutineheader");
+void runtime_printtrace(Slice, G*)
+ __asm__ (GOSYM_PREFIX "runtime.printtrace");
#define runtime_open(p, f, m) open((p), (f), (m))
#define runtime_read(d, v, n) read((d), (v), (n))
#define runtime_write(d, v, n) write((d), (v), (n))
#define runtime_close(d) close(d)
-void runtime_ready(G*);
+void runtime_ready(G*, intgo, bool)
+ __asm__ (GOSYM_PREFIX "runtime.ready");
String runtime_getenv(const char*);
int32 runtime_atoi(const byte*, intgo);
void* runtime_mstart(void*);
-G* runtime_malg(int32, byte**, size_t*);
-void runtime_mpreinit(M*);
-void runtime_minit(void);
-void runtime_unminit(void);
-void runtime_needm(void);
-void runtime_dropm(void);
-void runtime_signalstack(byte*, int32);
-MCache* runtime_allocmcache(void);
-void runtime_freemcache(MCache*);
+G* runtime_malg(bool, bool, byte**, uintptr*)
+ __asm__(GOSYM_PREFIX "runtime.malg");
+void runtime_minit(void)
+ __asm__ (GOSYM_PREFIX "runtime.minit");
+void runtime_signalstack(byte*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.signalstack");
+MCache* runtime_allocmcache(void)
+ __asm__ (GOSYM_PREFIX "runtime.allocmcache");
+void runtime_freemcache(MCache*)
+ __asm__ (GOSYM_PREFIX "runtime.freemcache");
void runtime_mallocinit(void);
void runtime_mprofinit(void);
-#define runtime_malloc(s) __go_alloc(s)
-#define runtime_free(p) __go_free(p)
-#define runtime_getcallersp(p) __builtin_frame_address(1)
-int32 runtime_mcount(void);
-int32 runtime_gcount(void);
+#define runtime_getcallersp(p) __builtin_frame_address(0)
void runtime_mcall(void(*)(G*));
-uint32 runtime_fastrand1(void);
-int32 runtime_timediv(int64, int32, int32*);
+uint32 runtime_fastrand(void) __asm__ (GOSYM_PREFIX "runtime.fastrand");
+int32 runtime_timediv(int64, int32, int32*)
+ __asm__ (GOSYM_PREFIX "runtime.timediv");
int32 runtime_round2(int32 x); // round x up to a power of 2.
// atomic operations
@@ -604,63 +337,72 @@ int32 runtime_round2(int32 x); // round x up to a power of 2.
#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
-void runtime_setmg(M*, G*);
-void runtime_newextram(void);
+void runtime_setg(G*)
+ __asm__ (GOSYM_PREFIX "runtime.setg");
+void runtime_newextram(void)
+ __asm__ (GOSYM_PREFIX "runtime.newextram");
#define runtime_exit(s) exit(s)
#define runtime_breakpoint() __builtin_trap()
void runtime_gosched(void);
void runtime_gosched0(G*);
-void runtime_schedtrace(bool);
+void runtime_schedtrace(bool)
+ __asm__ (GOSYM_PREFIX "runtime.schedtrace");
void runtime_park(bool(*)(G*, void*), void*, const char*);
void runtime_parkunlock(Lock*, const char*);
void runtime_tsleep(int64, const char*);
M* runtime_newm(void);
-void runtime_goexit(void);
-void runtime_entersyscall(void) __asm__ (GOSYM_PREFIX "syscall.Entersyscall");
-void runtime_entersyscallblock(void);
-void runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
+void runtime_goexit1(void)
+ __asm__ (GOSYM_PREFIX "runtime.goexit1");
+void runtime_entersyscall(int32)
+ __asm__ (GOSYM_PREFIX "runtime.entersyscall");
+void runtime_entersyscallblock(int32)
+ __asm__ (GOSYM_PREFIX "runtime.entersyscallblock");
+void runtime_exitsyscall(int32)
+ __asm__ (GOSYM_PREFIX "runtime.exitsyscall");
G* __go_go(void (*pfn)(void*), void*);
-void siginit(void);
-bool __go_sigsend(int32 sig);
int32 runtime_callers(int32, Location*, int32, bool keep_callers);
-int64 runtime_nanotime(void); // monotonic time
-int64 runtime_unixnanotime(void); // real time, can skip
+int64 runtime_nanotime(void) // monotonic time
+ __asm__(GOSYM_PREFIX "runtime.nanotime");
+int64 runtime_unixnanotime(void) // real time, can skip
+ __asm__ (GOSYM_PREFIX "runtime.unixnanotime");
void runtime_dopanic(int32) __attribute__ ((noreturn));
-void runtime_startpanic(void);
-void runtime_freezetheworld(void);
+void runtime_startpanic(void)
+ __asm__ (GOSYM_PREFIX "runtime.startpanic");
void runtime_unwindstack(G*, byte*);
-void runtime_sigprof();
-void runtime_resetcpuprofiler(int32);
-void runtime_setcpuprofilerate(void(*)(uintptr*, int32), int32);
-void runtime_usleep(uint32);
-int64 runtime_cputicks(void);
-int64 runtime_tickspersecond(void);
+void runtime_sigprof()
+ __asm__ (GOSYM_PREFIX "runtime.sigprof");
+void runtime_resetcpuprofiler(int32)
+ __asm__ (GOSYM_PREFIX "runtime.resetcpuprofiler");
+void runtime_setcpuprofilerate_m(int32)
+ __asm__ (GOSYM_PREFIX "runtime.setcpuprofilerate_m");
+void runtime_cpuprofAdd(Slice)
+ __asm__ (GOSYM_PREFIX "runtime.cpuprofAdd");
+void runtime_usleep(uint32)
+ __asm__ (GOSYM_PREFIX "runtime.usleep");
+int64 runtime_cputicks(void)
+ __asm__ (GOSYM_PREFIX "runtime.cputicks");
+int64 runtime_tickspersecond(void)
+ __asm__ (GOSYM_PREFIX "runtime.tickspersecond");
void runtime_blockevent(int64, int32);
extern int64 runtime_blockprofilerate;
-void runtime_addtimer(Timer*);
-bool runtime_deltimer(Timer*);
-G* runtime_netpoll(bool);
-void runtime_netpollinit(void);
-int32 runtime_netpollopen(uintptr, PollDesc*);
-int32 runtime_netpollclose(uintptr);
-void runtime_netpollready(G**, PollDesc*, int32);
-uintptr runtime_netpollfd(PollDesc*);
-void runtime_netpollarm(PollDesc*, int32);
-void** runtime_netpolluser(PollDesc*);
-bool runtime_netpollclosing(PollDesc*);
-void runtime_netpolllock(PollDesc*);
-void runtime_netpollunlock(PollDesc*);
-void runtime_crash(void);
-void runtime_parsedebugvars(void);
+G* runtime_netpoll(bool)
+ __asm__ (GOSYM_PREFIX "runtime.netpoll");
+void runtime_crash(void)
+ __asm__ (GOSYM_PREFIX "runtime.crash");
+void runtime_parsedebugvars(void)
+ __asm__(GOSYM_PREFIX "runtime.parsedebugvars");
void _rt0_go(void);
-void* runtime_funcdata(Func*, int32);
-int32 runtime_setmaxthreads(int32);
G* runtime_timejump(void);
void runtime_iterate_finq(void (*callback)(FuncVal*, void*, const FuncType*, const PtrType*));
-void runtime_stoptheworld(void);
-void runtime_starttheworld(void);
-extern uint32 runtime_worldsema;
+void runtime_stopTheWorldWithSema(void)
+ __asm__(GOSYM_PREFIX "runtime.stopTheWorldWithSema");
+void runtime_startTheWorldWithSema(void)
+ __asm__(GOSYM_PREFIX "runtime.startTheWorldWithSema");
+void runtime_acquireWorldsema(void)
+ __asm__(GOSYM_PREFIX "runtime.acquireWorldsema");
+void runtime_releaseWorldsema(void)
+ __asm__(GOSYM_PREFIX "runtime.releaseWorldsema");
/*
* mutual exclusion locks. in the uncontended case,
@@ -668,8 +410,10 @@ extern uint32 runtime_worldsema;
* but on the contention path they sleep in the kernel.
* a zeroed Lock is unlocked (no need to initialize each lock).
*/
-void runtime_lock(Lock*);
-void runtime_unlock(Lock*);
+void runtime_lock(Lock*)
+ __asm__(GOSYM_PREFIX "runtime.lock");
+void runtime_unlock(Lock*)
+ __asm__(GOSYM_PREFIX "runtime.unlock");
/*
* sleep and wakeup on one-time events.
@@ -693,21 +437,16 @@ void runtime_unlock(Lock*);
* notesleep/notetsleep are generally called on g0,
* notetsleepg is similar to notetsleep but is called on user g.
*/
-void runtime_noteclear(Note*);
-void runtime_notesleep(Note*);
-void runtime_notewakeup(Note*);
-bool runtime_notetsleep(Note*, int64); // false - timeout
-bool runtime_notetsleepg(Note*, int64); // false - timeout
-
-/*
- * low-level synchronization for implementing the above
- */
-uintptr runtime_semacreate(void);
-int32 runtime_semasleep(int64);
-void runtime_semawakeup(M*);
-// or
-void runtime_futexsleep(uint32*, uint32, int64);
-void runtime_futexwakeup(uint32*, uint32);
+void runtime_noteclear(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.noteclear");
+void runtime_notesleep(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.notesleep");
+void runtime_notewakeup(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.notewakeup");
+bool runtime_notetsleep(Note*, int64) // false - timeout
+ __asm__ (GOSYM_PREFIX "runtime.notetsleep");
+bool runtime_notetsleepg(Note*, int64) // false - timeout
+ __asm__ (GOSYM_PREFIX "runtime.notetsleepg");
/*
* Lock-free stack.
@@ -717,7 +456,8 @@ void runtime_futexwakeup(uint32*, uint32);
*/
void runtime_lfstackpush(uint64 *head, LFNode *node)
__asm__ (GOSYM_PREFIX "runtime.lfstackpush");
-LFNode* runtime_lfstackpop(uint64 *head);
+void* runtime_lfstackpop(uint64 *head)
+ __asm__ (GOSYM_PREFIX "runtime.lfstackpop");
/*
* Parallel for over [0, n).
@@ -745,45 +485,19 @@ void __wrap_rtems_task_variable_add(void **);
#endif
/*
- * Names generated by gccgo.
- */
-#define runtime_printbool __go_print_bool
-#define runtime_printfloat __go_print_double
-#define runtime_printint __go_print_int64
-#define runtime_printiface __go_print_interface
-#define runtime_printeface __go_print_empty_interface
-#define runtime_printstring __go_print_string
-#define runtime_printpointer __go_print_pointer
-#define runtime_printuint __go_print_uint64
-#define runtime_printslice __go_print_slice
-#define runtime_printcomplex __go_print_complex
-
-/*
* runtime go-called
*/
-void runtime_printbool(_Bool);
-void runtime_printbyte(int8);
-void runtime_printfloat(double);
-void runtime_printint(int64);
-void runtime_printiface(Iface);
-void runtime_printeface(Eface);
-void runtime_printstring(String);
-void runtime_printpc(void*);
-void runtime_printpointer(void*);
-void runtime_printuint(uint64);
-void runtime_printhex(uint64);
-void runtime_printslice(Slice);
-void runtime_printcomplex(complex double);
void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool,
void **, void **)
__asm__ (GOSYM_PREFIX "reflect.call");
-#define runtime_panic __go_panic
+void runtime_panic(Eface)
+ __asm__ (GOSYM_PREFIX "runtime.gopanic");
+void runtime_panic(Eface)
+ __attribute__ ((noreturn));
/*
* runtime c-called (but written in Go)
*/
-void runtime_printany(Eface)
- __asm__ (GOSYM_PREFIX "runtime.Printany");
void runtime_newTypeAssertionError(const String*, const String*, const String*, const String*, Eface*)
__asm__ (GOSYM_PREFIX "runtime.NewTypeAssertionError");
void runtime_newErrorCString(const char*, Eface*)
@@ -792,17 +506,17 @@ void runtime_newErrorCString(const char*, Eface*)
/*
* wrapped for go users
*/
-void runtime_semacquire(uint32 volatile *, bool);
-void runtime_semrelease(uint32 volatile *);
-int32 runtime_gomaxprocsfunc(int32 n);
-void runtime_procyield(uint32);
-void runtime_osyield(void);
-void runtime_lockOSThread(void);
-void runtime_unlockOSThread(void);
-bool runtime_lockedOSThread(void);
-
-bool runtime_showframe(String, bool);
-void runtime_printcreatedby(G*);
+void runtime_procyield(uint32)
+ __asm__(GOSYM_PREFIX "runtime.procyield");
+void runtime_osyield(void)
+ __asm__(GOSYM_PREFIX "runtime.osyield");
+void runtime_lockOSThread(void)
+ __asm__(GOSYM_PREFIX "runtime.lockOSThread");
+void runtime_unlockOSThread(void)
+ __asm__(GOSYM_PREFIX "runtime.unlockOSThread");
+
+void runtime_printcreatedby(G*)
+ __asm__(GOSYM_PREFIX "runtime.printcreatedby");
uintptr runtime_memlimit(void);
@@ -815,7 +529,8 @@ enum
#define runtime_setitimer setitimer
-void runtime_check(void);
+void runtime_check(void)
+ __asm__ (GOSYM_PREFIX "runtime.check");
// A list of global variables that the garbage collector must scan.
struct root_list {
@@ -835,8 +550,7 @@ extern uintptr runtime_stacks_sys;
struct backtrace_state;
extern struct backtrace_state *__go_get_backtrace_state(void);
-extern _Bool __go_file_line(uintptr, String*, String*, intgo *);
-extern byte* runtime_progname();
+extern _Bool __go_file_line(uintptr, int, String*, String*, intgo *);
extern void runtime_main(void*);
extern uint32 runtime_in_callers;
@@ -861,6 +575,22 @@ struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now")
extern void _cgo_wait_runtime_init_done (void);
extern void _cgo_notify_runtime_init_done (void);
extern _Bool runtime_iscgo;
-extern _Bool runtime_cgoHasExtraM;
-extern Hchan *runtime_main_init_done;
extern uintptr __go_end __attribute__ ((weak));
+extern void *getitab(const struct __go_type_descriptor *,
+ const struct __go_type_descriptor *,
+ _Bool)
+ __asm__ (GOSYM_PREFIX "runtime.getitab");
+
+extern void runtime_cpuinit(void);
+extern void setIsCgo(void)
+ __asm__ (GOSYM_PREFIX "runtime.setIsCgo");
+extern void setCpuidECX(uint32)
+ __asm__ (GOSYM_PREFIX "runtime.setCpuidECX");
+extern void setSupportAES(bool)
+ __asm__ (GOSYM_PREFIX "runtime.setSupportAES");
+extern void makeMainInitDone(void)
+ __asm__ (GOSYM_PREFIX "runtime.makeMainInitDone");
+extern void closeMainInitDone(void)
+ __asm__ (GOSYM_PREFIX "runtime.closeMainInitDone");
+extern void typedmemmove(const Type *, void *, const void *)
+ __asm__ (GOSYM_PREFIX "runtime.typedmemmove");
diff --git a/libgo/runtime/runtime1.goc b/libgo/runtime/runtime1.goc
deleted file mode 100644
index cd9d3017b5..0000000000
--- a/libgo/runtime/runtime1.goc
+++ /dev/null
@@ -1,96 +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
-#include "runtime.h"
-#include "arch.h"
-#include "go-type.h"
-
-func GOMAXPROCS(n int) (ret int) {
- ret = runtime_gomaxprocsfunc(n);
-}
-
-func NumCPU() (ret int) {
- ret = runtime_ncpu;
-}
-
-func NumCgoCall() (ret int64) {
- M *mp;
-
- ret = 0;
- for(mp=runtime_atomicloadp(&runtime_allm); mp; mp=mp->alllink)
- ret += mp->ncgocall;
-}
-
-func newParFor(nthrmax uint32) (desc *ParFor) {
- desc = runtime_parforalloc(nthrmax);
-}
-
-func parForSetup(desc *ParFor, nthr uint32, n uint32, wait bool, body *byte) {
- runtime_parforsetup(desc, nthr, n, wait, (const FuncVal*) body);
-}
-
-func parForDo(desc *ParFor) {
- runtime_parfordo(desc);
-}
-
-func parForIters(desc *ParFor, tid uintptr) (start uintptr, end uintptr) {
- runtime_parforiters(desc, tid, &start, &end);
-}
-
-func typestring(e Eface) (s String) {
- s = *e.__type_descriptor->__reflection;
-}
-
-func golockedOSThread() (ret bool) {
- ret = runtime_lockedOSThread();
-}
-
-func NumGoroutine() (ret int) {
- ret = runtime_gcount();
-}
-
-func getgoroot() (out String) {
- out = runtime_getenv("GOROOT");
-}
-
-func runtime_pprof.runtime_cyclesPerSecond() (res int64) {
- res = runtime_tickspersecond();
-}
-
-func sync.runtime_procPin() (p int) {
- M *mp;
-
- mp = runtime_m();
- // Disable preemption.
- mp->locks++;
- p = mp->p->id;
-}
-
-func sync.runtime_procUnpin() {
- runtime_m()->locks--;
-}
-
-func sync_atomic.runtime_procPin() (p int) {
- M *mp;
-
- mp = runtime_m();
- // Disable preemption.
- mp->locks++;
- p = mp->p->id;
-}
-
-func sync_atomic.runtime_procUnpin() {
- runtime_m()->locks--;
-}
-
-extern Slice envs;
-
-func envs() (s Slice) {
- s = envs;
-}
-
-func setenvs(e Slice) {
- envs = e;
-}
diff --git a/libgo/runtime/runtime_c.c b/libgo/runtime/runtime_c.c
new file mode 100644
index 0000000000..9883e0a6c9
--- /dev/null
+++ b/libgo/runtime/runtime_c.c
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h>
+#endif
+
+#include "config.h"
+
+#include "runtime.h"
+#include "arch.h"
+#include "array.h"
+
+enum {
+ maxround = sizeof(uintptr),
+};
+
+extern volatile intgo runtime_MemProfileRate
+ __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
+
+struct gotraceback_ret {
+ int32 level;
+ bool all;
+ bool crash;
+};
+
+extern struct gotraceback_ret gotraceback(void)
+ __asm__ (GOSYM_PREFIX "runtime.gotraceback");
+
+// runtime_gotraceback is the C interface to runtime.gotraceback.
+int32
+runtime_gotraceback(bool *crash)
+{
+ struct gotraceback_ret r;
+
+ r = gotraceback();
+ if(crash != nil)
+ *crash = r.crash;
+ return r.level;
+}
+
+int32
+runtime_atoi(const byte *p, intgo len)
+{
+ int32 n;
+
+ n = 0;
+ while(len > 0 && '0' <= *p && *p <= '9') {
+ n = n*10 + *p++ - '0';
+ len--;
+ }
+ return n;
+}
+
+uint32
+runtime_fastrand(void)
+{
+ M *m;
+ uint32 x;
+
+ m = runtime_m();
+ x = m->fastrand;
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ m->fastrand = x;
+ return x;
+}
+
+int64
+runtime_cputicks(void)
+{
+#if defined(__386__) || defined(__x86_64__)
+ uint32 low, high;
+ asm("rdtsc" : "=a" (low), "=d" (high));
+ return (int64)(((uint64)high << 32) | (uint64)low);
+#elif defined (__s390__) || defined (__s390x__)
+ uint64 clock = 0;
+ /* stckf may not write the return variable in case of a clock error, so make
+ it read-write to prevent that the initialisation is optimised out.
+ Note: Targets below z9-109 will crash when executing store clock fast, i.e.
+ we don't support Go for machines older than that. */
+ asm volatile(".insn s,0xb27c0000,%0" /* stckf */ : "+Q" (clock) : : "cc" );
+ return (int64)clock;
+#else
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
+ // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // TODO: need more entropy to better seed fastrand.
+ return runtime_nanotime();
+#endif
+}
+
+void
+runtime_signalstack(byte *p, uintptr n)
+{
+ stack_t st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ if(sigaltstack(&st, nil) < 0)
+ *(int *)0xf1 = 0xf1;
+}
+
+struct debugVars runtime_debug;
+
+void
+runtime_setdebug(struct debugVars* d) {
+ runtime_debug = *d;
+}
+
+void memclrBytes(Slice)
+ __asm__ (GOSYM_PREFIX "runtime.memclrBytes");
+
+void
+memclrBytes(Slice s)
+{
+ runtime_memclr(s.__values, s.__count);
+}
+
+int32 go_open(char *, int32, int32)
+ __asm__ (GOSYM_PREFIX "runtime.open");
+
+int32
+go_open(char *name, int32 mode, int32 perm)
+{
+ return runtime_open(name, mode, perm);
+}
+
+int32 go_read(int32, void *, int32)
+ __asm__ (GOSYM_PREFIX "runtime.read");
+
+int32
+go_read(int32 fd, void *p, int32 n)
+{
+ return runtime_read(fd, p, n);
+}
+
+int32 go_write(uintptr, void *, int32)
+ __asm__ (GOSYM_PREFIX "runtime.write");
+
+int32
+go_write(uintptr fd, void *p, int32 n)
+{
+ return runtime_write(fd, p, n);
+}
+
+int32 go_closefd(int32)
+ __asm__ (GOSYM_PREFIX "runtime.closefd");
+
+int32
+go_closefd(int32 fd)
+{
+ return runtime_close(fd);
+}
+
+intgo go_errno(void)
+ __asm__ (GOSYM_PREFIX "runtime.errno");
+
+intgo
+go_errno()
+{
+ return (intgo)errno;
+}
+
+// CPU-specific initialization.
+// Fetch CPUID info on x86.
+
+void
+runtime_cpuinit()
+{
+#if defined(__i386__) || defined(__x86_64__)
+ unsigned int eax, ebx, ecx, edx;
+
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
+ setCpuidECX(ecx);
+ }
+
+#if defined(HAVE_AS_X86_AES)
+ setSupportAES(true);
+#endif
+#endif
+}
diff --git a/libgo/runtime/sema.goc b/libgo/runtime/sema.goc
deleted file mode 100644
index 50f0e973d7..0000000000
--- a/libgo/runtime/sema.goc
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Semaphore implementation exposed to Go.
-// Intended use is provide a sleep and wakeup
-// primitive that can be used in the contended case
-// of other synchronization primitives.
-// Thus it targets the same goal as Linux's futex,
-// but it has much simpler semantics.
-//
-// That is, don't think of these as semaphores.
-// Think of them as a way to implement sleep and wakeup
-// such that every sleep is paired with a single wakeup,
-// even if, due to races, the wakeup happens before the sleep.
-//
-// See Mullender and Cox, ``Semaphores in Plan 9,''
-// http://swtch.com/semaphore.pdf
-
-package sync
-#include "runtime.h"
-#include "arch.h"
-
-typedef struct SemaWaiter SemaWaiter;
-struct SemaWaiter
-{
- uint32 volatile* addr;
- G* g;
- int64 releasetime;
- int32 nrelease; // -1 for acquire
- SemaWaiter* prev;
- SemaWaiter* next;
-};
-
-typedef struct SemaRoot SemaRoot;
-struct SemaRoot
-{
- Lock;
- SemaWaiter* head;
- SemaWaiter* tail;
- // Number of waiters. Read w/o the lock.
- uint32 volatile nwait;
-};
-
-// Prime to not correlate with any user patterns.
-#define SEMTABLESZ 251
-
-struct semtable
-{
- SemaRoot;
- uint8 pad[CacheLineSize-sizeof(SemaRoot)];
-};
-static struct semtable semtable[SEMTABLESZ];
-
-static SemaRoot*
-semroot(uint32 volatile *addr)
-{
- return &semtable[((uintptr)addr >> 3) % SEMTABLESZ];
-}
-
-static void
-semqueue(SemaRoot *root, uint32 volatile *addr, SemaWaiter *s)
-{
- s->g = runtime_g();
- s->addr = addr;
- s->next = nil;
- s->prev = root->tail;
- if(root->tail)
- root->tail->next = s;
- else
- root->head = s;
- root->tail = s;
-}
-
-static void
-semdequeue(SemaRoot *root, SemaWaiter *s)
-{
- if(s->next)
- s->next->prev = s->prev;
- else
- root->tail = s->prev;
- if(s->prev)
- s->prev->next = s->next;
- else
- root->head = s->next;
- s->prev = nil;
- s->next = nil;
-}
-
-static int32
-cansemacquire(uint32 volatile *addr)
-{
- uint32 v;
-
- while((v = runtime_atomicload(addr)) > 0)
- if(runtime_cas(addr, v, v-1))
- return 1;
- return 0;
-}
-
-void
-runtime_semacquire(uint32 volatile *addr, bool profile)
-{
- SemaWaiter s; // Needs to be allocated on stack, otherwise garbage collector could deallocate it
- SemaRoot *root;
- int64 t0;
-
- // Easy case.
- if(cansemacquire(addr))
- return;
-
- // Harder case:
- // increment waiter count
- // try cansemacquire one more time, return if succeeded
- // enqueue itself as a waiter
- // sleep
- // (waiter descriptor is dequeued by signaler)
- root = semroot(addr);
- t0 = 0;
- s.releasetime = 0;
- if(profile && runtime_blockprofilerate > 0) {
- t0 = runtime_cputicks();
- s.releasetime = -1;
- }
- for(;;) {
-
- runtime_lock(root);
- // Add ourselves to nwait to disable "easy case" in semrelease.
- runtime_xadd(&root->nwait, 1);
- // Check cansemacquire to avoid missed wakeup.
- if(cansemacquire(addr)) {
- runtime_xadd(&root->nwait, -1);
- runtime_unlock(root);
- return;
- }
- // Any semrelease after the cansemacquire knows we're waiting
- // (we set nwait above), so go to sleep.
- semqueue(root, addr, &s);
- runtime_parkunlock(root, "semacquire");
- if(cansemacquire(addr)) {
- if(t0)
- runtime_blockevent(s.releasetime - t0, 3);
- return;
- }
- }
-}
-
-void
-runtime_semrelease(uint32 volatile *addr)
-{
- SemaWaiter *s;
- SemaRoot *root;
-
- root = semroot(addr);
- runtime_xadd(addr, 1);
-
- // Easy case: no waiters?
- // This check must happen after the xadd, to avoid a missed wakeup
- // (see loop in semacquire).
- if(runtime_atomicload(&root->nwait) == 0)
- return;
-
- // Harder case: search for a waiter and wake it.
- runtime_lock(root);
- if(runtime_atomicload(&root->nwait) == 0) {
- // The count is already consumed by another goroutine,
- // so no need to wake up another goroutine.
- runtime_unlock(root);
- return;
- }
- for(s = root->head; s; s = s->next) {
- if(s->addr == addr) {
- runtime_xadd(&root->nwait, -1);
- semdequeue(root, s);
- break;
- }
- }
- runtime_unlock(root);
- if(s) {
- if(s->releasetime)
- s->releasetime = runtime_cputicks();
- runtime_ready(s->g);
- }
-}
-
-// TODO(dvyukov): move to netpoll.goc once it's used by all OSes.
-void net_runtime_Semacquire(uint32 *addr)
- __asm__ (GOSYM_PREFIX "net.runtime_Semacquire");
-
-void net_runtime_Semacquire(uint32 *addr)
-{
- runtime_semacquire(addr, true);
-}
-
-void net_runtime_Semrelease(uint32 *addr)
- __asm__ (GOSYM_PREFIX "net.runtime_Semrelease");
-
-void net_runtime_Semrelease(uint32 *addr)
-{
- runtime_semrelease(addr);
-}
-
-func runtime_Semacquire(addr *uint32) {
- runtime_semacquire(addr, true);
-}
-
-func runtime_Semrelease(addr *uint32) {
- runtime_semrelease(addr);
-}
-
-typedef struct SyncSema SyncSema;
-struct SyncSema
-{
- Lock;
- SemaWaiter* head;
- SemaWaiter* tail;
-};
-
-func runtime_Syncsemcheck(size uintptr) {
- if(size != sizeof(SyncSema)) {
- runtime_printf("bad SyncSema size: sync:%D runtime:%D\n", (int64)size, (int64)sizeof(SyncSema));
- runtime_throw("bad SyncSema size");
- }
-}
-
-// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s.
-func runtime_Syncsemacquire(s *SyncSema) {
- SemaWaiter w, *wake;
- int64 t0;
-
- w.g = runtime_g();
- w.nrelease = -1;
- w.next = nil;
- w.releasetime = 0;
- t0 = 0;
- if(runtime_blockprofilerate > 0) {
- t0 = runtime_cputicks();
- w.releasetime = -1;
- }
-
- runtime_lock(s);
- if(s->head && s->head->nrelease > 0) {
- // have pending release, consume it
- wake = nil;
- s->head->nrelease--;
- if(s->head->nrelease == 0) {
- wake = s->head;
- s->head = wake->next;
- if(s->head == nil)
- s->tail = nil;
- }
- runtime_unlock(s);
- if(wake)
- runtime_ready(wake->g);
- } else {
- // enqueue itself
- if(s->tail == nil)
- s->head = &w;
- else
- s->tail->next = &w;
- s->tail = &w;
- runtime_parkunlock(s, "semacquire");
- if(t0)
- runtime_blockevent(w.releasetime - t0, 2);
- }
-}
-
-// Syncsemrelease waits for n pairing Syncsemacquire on the same semaphore s.
-func runtime_Syncsemrelease(s *SyncSema, n uint32) {
- SemaWaiter w, *wake;
-
- w.g = runtime_g();
- w.nrelease = (int32)n;
- w.next = nil;
- w.releasetime = 0;
-
- runtime_lock(s);
- while(w.nrelease > 0 && s->head && s->head->nrelease < 0) {
- // have pending acquire, satisfy it
- wake = s->head;
- s->head = wake->next;
- if(s->head == nil)
- s->tail = nil;
- if(wake->releasetime)
- wake->releasetime = runtime_cputicks();
- runtime_ready(wake->g);
- w.nrelease--;
- }
- if(w.nrelease > 0) {
- // enqueue itself
- if(s->tail == nil)
- s->head = &w;
- else
- s->tail->next = &w;
- s->tail = &w;
- runtime_parkunlock(s, "semarelease");
- } else
- runtime_unlock(s);
-}
diff --git a/libgo/runtime/signal_unix.c b/libgo/runtime/signal_unix.c
deleted file mode 100644
index 5bee0d2a70..0000000000
--- a/libgo/runtime/signal_unix.c
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-#include <sys/time.h>
-
-#include "runtime.h"
-#include "defs.h"
-#include "signal_unix.h"
-
-extern SigTab runtime_sigtab[];
-
-void
-runtime_initsig(bool preinit)
-{
- int32 i;
- SigTab *t;
-
- // For c-archive/c-shared this is called by go-libmain.c with
- // preinit == true.
- if(runtime_isarchive && !preinit)
- return;
-
- // First call: basic setup.
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- t = &runtime_sigtab[i];
- if((t->flags == 0) || (t->flags & SigDefault))
- continue;
-
- t->fwdsig = runtime_getsig(i);
-
- // For some signals, we respect an inherited SIG_IGN handler
- // rather than insist on installing our own default handler.
- // Even these signals can be fetched using the os/signal package.
- switch(t->sig) {
- case SIGHUP:
- case SIGINT:
- if(t->fwdsig == GO_SIG_IGN) {
- continue;
- }
- }
-
- if(runtime_isarchive && (t->flags&SigPanic) == 0)
- continue;
-
- t->flags |= SigHandling;
- runtime_setsig(i, runtime_sighandler, true);
- }
-}
-
-void
-runtime_sigenable(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
- t->flags |= SigHandling;
- t->fwdsig = runtime_getsig(i);
- runtime_setsig(i, runtime_sighandler, true);
- }
-}
-
-void
-runtime_sigdisable(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((sig == SIGHUP || sig == SIGINT) && t->fwdsig == GO_SIG_IGN) {
- t->flags &= ~SigHandling;
- runtime_setsig(i, t->fwdsig, true);
- }
-}
-
-void
-runtime_sigignore(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((t->flags & SigNotify) != 0) {
- t->flags &= ~SigHandling;
- runtime_setsig(i, GO_SIG_IGN, true);
- }
-}
-
-void
-runtime_resetcpuprofiler(int32 hz)
-{
- struct itimerval it;
-
- runtime_memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime_setitimer(ITIMER_PROF, &it, nil);
- } else {
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime_setitimer(ITIMER_PROF, &it, nil);
- }
- runtime_m()->profilehz = hz;
-}
-
-void
-runtime_unblocksignals(void)
-{
- sigset_t sigset_none;
- sigemptyset(&sigset_none);
- pthread_sigmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-void
-runtime_crash(void)
-{
- int32 i;
-
-#ifdef GOOS_darwin
- // OS X core dumps are linear dumps of the mapped memory,
- // from the first virtual byte to the last, with zeros in the gaps.
- // Because of the way we arrange the address space on 64-bit systems,
- // this means the OS X core file will be >128 GB and even on a zippy
- // workstation can take OS X well over an hour to write (uninterruptible).
- // Save users from making that mistake.
- if(sizeof(void*) == 8)
- return;
-#endif
-
- runtime_unblocksignals();
- for(i = 0; runtime_sigtab[i].sig != -1; i++)
- if(runtime_sigtab[i].sig == SIGABRT)
- break;
- runtime_setsig(i, GO_SIG_DFL, false);
- runtime_raise(SIGABRT);
-}
-
-void
-runtime_raise(int32 sig)
-{
- raise(sig);
-}
diff --git a/libgo/runtime/signal_unix.h b/libgo/runtime/signal_unix.h
deleted file mode 100644
index 1c51740bf1..0000000000
--- a/libgo/runtime/signal_unix.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <signal.h>
-
-#define GO_SIG_DFL ((void*)SIG_DFL)
-#define GO_SIG_IGN ((void*)SIG_IGN)
-
-#ifdef SA_SIGINFO
-typedef siginfo_t Siginfo;
-#else
-typedef void *Siginfo;
-#endif
-
-typedef void GoSighandler(int32, Siginfo*, void*, G*);
-void runtime_setsig(int32, GoSighandler*, bool);
-GoSighandler* runtime_getsig(int32);
-
-void runtime_sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void runtime_raise(int32);
-
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
deleted file mode 100644
index fba1c71e2c..0000000000
--- a/libgo/runtime/sigqueue.goc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements runtime support for signal handling.
-//
-// Most synchronization primitives are not available from
-// the signal handler (it cannot block, allocate memory, or use locks)
-// so the handler communicates with a processing goroutine
-// via struct sig, below.
-//
-// sigsend() is called by the signal handler to queue a new signal.
-// signal_recv() is called by the Go program to receive a newly queued signal.
-// Synchronization between sigsend() and signal_recv() is based on the sig.state
-// variable. It can be in 3 states: 0, HASWAITER and HASSIGNAL.
-// HASWAITER means that signal_recv() is blocked on sig.Note and there are no
-// new pending signals.
-// HASSIGNAL means that sig.mask *may* contain new pending signals,
-// signal_recv() can't be blocked in this state.
-// 0 means that there are no new pending signals and signal_recv() is not blocked.
-// Transitions between states are done atomically with CAS.
-// When signal_recv() is unblocked, it resets sig.Note and rechecks sig.mask.
-// If several sigsend()'s and signal_recv() execute concurrently, it can lead to
-// unnecessary rechecks of sig.mask, but must not lead to missed signals
-// nor deadlocks.
-
-package signal
-#include "config.h"
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "defs.h"
-
-static struct {
- Note;
- uint32 mask[(NSIG+31)/32];
- uint32 wanted[(NSIG+31)/32];
- uint32 state;
- bool inuse;
-} sig;
-
-enum {
- HASWAITER = 1,
- HASSIGNAL = 2,
-};
-
-// Called from sighandler to send a signal back out of the signal handling thread.
-bool
-__go_sigsend(int32 s)
-{
- uint32 bit, mask, old, new;
-
- if(!sig.inuse || s < 0 || (size_t)s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
- return false;
- bit = 1 << (s&31);
- for(;;) {
- mask = sig.mask[s/32];
- if(mask & bit)
- break; // signal already in queue
- if(runtime_cas(&sig.mask[s/32], mask, mask|bit)) {
- // Added to queue.
- // Only send a wakeup if the receiver needs a kick.
- for(;;) {
- old = runtime_atomicload(&sig.state);
- if(old == HASSIGNAL)
- break;
- if(old == HASWAITER)
- new = 0;
- else // if(old == 0)
- new = HASSIGNAL;
- if(runtime_cas(&sig.state, old, new)) {
- if (old == HASWAITER)
- runtime_notewakeup(&sig);
- break;
- }
- }
- break;
- }
- }
- return true;
-}
-
-// Called to receive the next queued signal.
-// Must only be called from a single goroutine at a time.
-func signal_recv() (m uint32) {
- static uint32 recv[nelem(sig.mask)];
- uint32 i, old, new;
-
- for(;;) {
- // Serve from local copy if there are bits left.
- for(i=0; i<NSIG; i++) {
- if(recv[i/32]&(1U<<(i&31))) {
- recv[i/32] ^= 1U<<(i&31);
- m = i;
- goto done;
- }
- }
-
- // Check and update sig.state.
- for(;;) {
- old = runtime_atomicload(&sig.state);
- if(old == HASWAITER)
- runtime_throw("inconsistent state in signal_recv");
- if(old == HASSIGNAL)
- new = 0;
- else // if(old == 0)
- new = HASWAITER;
- if(runtime_cas(&sig.state, old, new)) {
- if (new == HASWAITER) {
- runtime_notetsleepg(&sig, -1);
- runtime_noteclear(&sig);
- }
- break;
- }
- }
-
- // Get a new local copy.
- for(i=0; (size_t)i<nelem(sig.mask); i++) {
- for(;;) {
- m = sig.mask[i];
- if(runtime_cas(&sig.mask[i], m, 0))
- break;
- }
- recv[i] = m;
- }
- }
-
-done:;
- // goc requires that we fall off the end of functions
- // that return values instead of using our own return
- // statements.
-}
-
-// Must only be called from a single goroutine at a time.
-func signal_enable(s uint32) {
- if(!sig.inuse) {
- // The first call to signal_enable is for us
- // to use for initialization. It does not pass
- // signal information in m.
- sig.inuse = true; // enable reception of signals; cannot disable
- runtime_noteclear(&sig);
- return;
- }
-
- if(s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] |= 1U<<(s&31);
- runtime_sigenable(s);
-}
-
-// Must only be called from a single goroutine at a time.
-func signal_disable(s uint32) {
- if(s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] &= ~(1U<<(s&31));
- runtime_sigdisable(s);
-}
-
-// Must only be called from a single goroutine at a time.
-func signal_ignore(s uint32) {
- if (s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] &= ~(1U<<(s&31));
- runtime_sigignore(s);
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-void
-runtime_badsignal(int sig)
-{
- __go_sigsend(sig);
-}
diff --git a/libgo/runtime/string.goc b/libgo/runtime/string.goc
deleted file mode 100644
index 0ad180b983..0000000000
--- a/libgo/runtime/string.goc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2009, 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
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "go-string.h"
-
-#define charntorune(pv, str, len) __go_get_rune(str, len, pv)
-
-const String runtime_emptystring;
-
-intgo
-runtime_findnull(const byte *s)
-{
- if(s == nil)
- return 0;
- return __builtin_strlen((const char*) s);
-}
-
-intgo
-runtime_findnullw(const uint16 *s)
-{
- intgo l;
-
- if(s == nil)
- return 0;
- for(l=0; s[l]!=0; l++)
- ;
- return l;
-}
-
-static String
-gostringsize(intgo l, byte** pmem)
-{
- String s;
- byte *mem;
-
- if(l == 0) {
- *pmem = nil;
- return runtime_emptystring;
- }
- mem = runtime_mallocgc(l, 0, FlagNoScan|FlagNoZero);
- s.str = mem;
- s.len = l;
- *pmem = mem;
- return s;
-}
-
-String
-runtime_gostring(const byte *str)
-{
- intgo l;
- String s;
- byte *mem;
-
- l = runtime_findnull(str);
- s = gostringsize(l, &mem);
- runtime_memmove(mem, str, l);
- return s;
-}
-
-String
-runtime_gostringnocopy(const byte *str)
-{
- String s;
-
- s.str = str;
- s.len = runtime_findnull(str);
- return s;
-}
-
-func cstringToGo(str *byte) (s String) {
- s = runtime_gostringnocopy(str);
-}
-
-enum
-{
- Runeself = 0x80,
-};
-
-func stringiter(s String, k int) (retk int) {
- int32 l;
-
- if(k >= s.len) {
- // retk=0 is end of iteration
- retk = 0;
- goto out;
- }
-
- l = s.str[k];
- if(l < Runeself) {
- retk = k+1;
- goto out;
- }
-
- // multi-char rune
- retk = k + charntorune(&l, s.str+k, s.len-k);
-
-out:
-}
-
-func stringiter2(s String, k int) (retk int, retv int32) {
- if(k >= s.len) {
- // retk=0 is end of iteration
- retk = 0;
- retv = 0;
- goto out;
- }
-
- retv = s.str[k];
- if(retv < Runeself) {
- retk = k+1;
- goto out;
- }
-
- // multi-char rune
- retk = k + charntorune(&retv, s.str+k, s.len-k);
-
-out:
-}
diff --git a/libgo/runtime/thread-linux.c b/libgo/runtime/thread-linux.c
index ae56261e6f..81ad0f9c90 100644
--- a/libgo/runtime/thread-linux.c
+++ b/libgo/runtime/thread-linux.c
@@ -4,72 +4,13 @@
#include "runtime.h"
#include "defs.h"
-#include "signal_unix.h"
// Linux futex.
-//
-// futexsleep(uint32 *addr, uint32 val)
-// futexwakeup(uint32 *addr)
-//
-// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up threads sleeping on addr.
-// Futexsleep is allowed to wake up spuriously.
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <unistd.h>
#include <syscall.h>
#include <linux/futex.h>
-typedef struct timespec Timespec;
-
-// Atomically,
-// if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-void
-runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
- Timespec ts;
- int32 nsec;
-
- // Some Linux kernels have a bug where futex of
- // FUTEX_WAIT returns an internal error code
- // as an errno. Libpthread ignores the return value
- // here, and so can we: as it says a few lines up,
- // spurious wakeups are allowed.
-
- if(ns < 0) {
- syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0);
- return;
- }
- ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec);
- ts.tv_nsec = nsec;
- syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0);
-}
-
-// If any procs are sleeping on addr, wake up at most cnt.
-void
-runtime_futexwakeup(uint32 *addr, uint32 cnt)
-{
- int64 ret;
-
- ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0);
-
- if(ret >= 0)
- return;
-
- // I don't know that futex wakeup can return
- // EAGAIN or EINTR, but if it does, it would be
- // safe to loop and call futex again.
- runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret);
- *(int32*)0x1006 = 0x1006;
-}
-
void
runtime_osinit(void)
{
diff --git a/libgo/runtime/thread-sema.c b/libgo/runtime/thread-sema.c
index 18827b025d..b74b1dab11 100644
--- a/libgo/runtime/thread-sema.c
+++ b/libgo/runtime/thread-sema.c
@@ -10,131 +10,6 @@
#include <time.h>
#include <semaphore.h>
-/* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
- We don't always use condition variables because on some systems
- pthread_mutex_lock and pthread_mutex_unlock must be called by the
- same thread. That is never true of semaphores. */
-
-struct go_sem
-{
- sem_t sem;
-
-#ifndef HAVE_SEM_TIMEDWAIT
- int timedwait;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-#endif
-};
-
-/* Create a semaphore. */
-
-uintptr
-runtime_semacreate(void)
-{
- struct go_sem *p;
-
- /* Call malloc rather than runtime_malloc. This will allocate space
- on the C heap. We can't call runtime_malloc here because it
- could cause a deadlock. */
- p = malloc (sizeof (struct go_sem));
- if (sem_init (&p->sem, 0, 0) != 0)
- runtime_throw ("sem_init");
-
-#ifndef HAVE_SEM_TIMEDWAIT
- if (pthread_mutex_init (&p->mutex, NULL) != 0)
- runtime_throw ("pthread_mutex_init");
- if (pthread_cond_init (&p->cond, NULL) != 0)
- runtime_throw ("pthread_cond_init");
-#endif
-
- return (uintptr) p;
-}
-
-/* Acquire m->waitsema. */
-
-int32
-runtime_semasleep (int64 ns)
-{
- M *m;
- struct go_sem *sem;
- int r;
-
- m = runtime_m ();
- sem = (struct go_sem *) m->waitsema;
- if (ns >= 0)
- {
- int64 abs;
- struct timespec ts;
- int err;
-
- abs = ns + runtime_nanotime ();
- ts.tv_sec = abs / 1000000000LL;
- ts.tv_nsec = abs % 1000000000LL;
-
- err = 0;
-
-#ifdef HAVE_SEM_TIMEDWAIT
- r = sem_timedwait (&sem->sem, &ts);
- if (r != 0)
- err = errno;
-#else
- if (pthread_mutex_lock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_lock");
-
- while ((r = sem_trywait (&sem->sem)) != 0)
- {
- r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
- if (r != 0)
- {
- err = r;
- break;
- }
- }
-
- if (pthread_mutex_unlock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_unlock");
-#endif
-
- if (err != 0)
- {
- if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
- return -1;
- runtime_throw ("sema_timedwait");
- }
- return 0;
- }
-
- while (sem_wait (&sem->sem) != 0)
- {
- if (errno == EINTR)
- continue;
- runtime_throw ("sem_wait");
- }
-
- return 0;
-}
-
-/* Wake up mp->waitsema. */
-
-void
-runtime_semawakeup (M *mp)
-{
- struct go_sem *sem;
-
- sem = (struct go_sem *) mp->waitsema;
- if (sem_post (&sem->sem) != 0)
- runtime_throw ("sem_post");
-
-#ifndef HAVE_SEM_TIMEDWAIT
- if (pthread_mutex_lock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_lock");
- if (pthread_cond_broadcast (&sem->cond) != 0)
- runtime_throw ("pthread_cond_broadcast");
- if (pthread_mutex_unlock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_unlock");
-#endif
-}
-
void
runtime_osinit (void)
{
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
deleted file mode 100644
index b77ad3333d..0000000000
--- a/libgo/runtime/time.goc
+++ /dev/null
@@ -1,353 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Time-related runtime and pieces of package time.
-
-package time
-
-#include <sys/time.h>
-
-#include "runtime.h"
-#include "defs.h"
-#include "arch.h"
-#include "malloc.h"
-
-enum {
- debug = 0,
-};
-
-static Timers timers;
-static void addtimer(Timer*);
-static void dumptimers(const char*);
-
-// nacl fake time support.
-int64 runtime_timens;
-
-// Package time APIs.
-// Godoc uses the comments in package time, not these.
-
-// time.now is implemented in assembly.
-
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() (ns int64) {
- ns = runtime_nanotime();
-}
-
-// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
-func Sleep(ns int64) {
- runtime_tsleep(ns, "sleep");
-}
-
-// startTimer adds t to the timer heap.
-func startTimer(t *Timer) {
- runtime_addtimer(t);
-}
-
-// stopTimer removes t from the timer heap if it is there.
-// It returns true if t was removed, false if t wasn't even there.
-func stopTimer(t *Timer) (stopped bool) {
- stopped = runtime_deltimer(t);
-}
-
-// C runtime.
-
-int64 runtime_unixnanotime(void)
-{
- struct time_now_ret r;
-
- r = now();
- return r.sec*1000000000 + r.nsec;
-}
-
-static void timerproc(void*);
-static void siftup(int32);
-static void siftdown(int32);
-
-// Ready the goroutine e.data.
-static void
-ready(Eface e, uintptr seq)
-{
- USED(seq);
-
- runtime_ready(e.__object);
-}
-
-static FuncVal readyv = {(void(*)(void))ready};
-
-// Put the current goroutine to sleep for ns nanoseconds.
-void
-runtime_tsleep(int64 ns, const char *reason)
-{
- G* g;
- Timer t;
-
- g = runtime_g();
-
- if(ns <= 0)
- return;
-
- t.when = runtime_nanotime() + ns;
- t.period = 0;
- t.fv = &readyv;
- t.arg.__object = g;
- t.seq = 0;
- runtime_lock(&timers);
- addtimer(&t);
- runtime_parkunlock(&timers, reason);
-}
-
-void
-runtime_addtimer(Timer *t)
-{
- runtime_lock(&timers);
- addtimer(t);
- runtime_unlock(&timers);
-}
-
-// Add a timer to the heap and start or kick the timer proc
-// if the new timer is earlier than any of the others.
-static void
-addtimer(Timer *t)
-{
- int32 n;
- Timer **nt;
-
- // when must never be negative; otherwise timerproc will overflow
- // during its delta calculation and never expire other timers.
- if(t->when < 0)
- t->when = (int64)((1ULL<<63)-1);
-
- if(timers.len >= timers.cap) {
- // Grow slice.
- n = 16;
- if(n <= timers.cap)
- n = timers.cap*3 / 2;
- nt = runtime_malloc(n*sizeof nt[0]);
- runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]);
- runtime_free(timers.t);
- timers.t = nt;
- timers.cap = n;
- }
- t->i = timers.len++;
- timers.t[t->i] = t;
- siftup(t->i);
- if(t->i == 0) {
- // siftup moved to top: new earliest deadline.
- if(timers.sleeping) {
- timers.sleeping = false;
- runtime_notewakeup(&timers.waitnote);
- }
- if(timers.rescheduling) {
- timers.rescheduling = false;
- runtime_ready(timers.timerproc);
- }
- }
- if(timers.timerproc == nil) {
- timers.timerproc = __go_go(timerproc, nil);
- timers.timerproc->issystem = true;
- }
- if(debug)
- dumptimers("addtimer");
-}
-
-// Used to force a dereference before the lock is acquired.
-static int32 gi;
-
-// Delete timer t from the heap.
-// Do not need to update the timerproc:
-// if it wakes up early, no big deal.
-bool
-runtime_deltimer(Timer *t)
-{
- int32 i;
-
- // Dereference t so that any panic happens before the lock is held.
- // Discard result, because t might be moving in the heap.
- i = t->i;
- gi = i;
-
- runtime_lock(&timers);
-
- // t may not be registered anymore and may have
- // a bogus i (typically 0, if generated by Go).
- // Verify it before proceeding.
- i = t->i;
- if(i < 0 || i >= timers.len || timers.t[i] != t) {
- runtime_unlock(&timers);
- return false;
- }
-
- timers.len--;
- if(i == timers.len) {
- timers.t[i] = nil;
- } else {
- timers.t[i] = timers.t[timers.len];
- timers.t[timers.len] = nil;
- timers.t[i]->i = i;
- siftup(i);
- siftdown(i);
- }
- if(debug)
- dumptimers("deltimer");
- runtime_unlock(&timers);
- return true;
-}
-
-// Timerproc runs the time-driven events.
-// It sleeps until the next event in the timers heap.
-// If addtimer inserts a new earlier event, addtimer
-// wakes timerproc early.
-static void
-timerproc(void* dummy __attribute__ ((unused)))
-{
- int64 delta, now;
- Timer *t;
- FuncVal *fv;
- void (*f)(Eface, uintptr);
- Eface arg;
- uintptr seq;
-
- for(;;) {
- runtime_lock(&timers);
- timers.sleeping = false;
- now = runtime_nanotime();
- for(;;) {
- if(timers.len == 0) {
- delta = -1;
- break;
- }
- t = timers.t[0];
- delta = t->when - now;
- if(delta > 0)
- break;
- if(t->period > 0) {
- // leave in heap but adjust next time to fire
- t->when += t->period * (1 + -delta/t->period);
- siftdown(0);
- } else {
- // remove from heap
- timers.t[0] = timers.t[--timers.len];
- timers.t[0]->i = 0;
- siftdown(0);
- t->i = -1; // mark as removed
- }
- fv = t->fv;
- f = (void*)t->fv->fn;
- arg = t->arg;
- seq = t->seq;
- runtime_unlock(&timers);
- __builtin_call_with_static_chain(f(arg, seq), fv);
-
- // clear f and arg to avoid leak while sleeping for next timer
- f = nil;
- USED(f);
- arg.__type_descriptor = nil;
- arg.__object = nil;
- USED(&arg);
-
- runtime_lock(&timers);
- }
- if(delta < 0) {
- // No timers left - put goroutine to sleep.
- timers.rescheduling = true;
- runtime_g()->isbackground = true;
- runtime_parkunlock(&timers, "timer goroutine (idle)");
- runtime_g()->isbackground = false;
- continue;
- }
- // At least one timer pending. Sleep until then.
- timers.sleeping = true;
- runtime_noteclear(&timers.waitnote);
- runtime_unlock(&timers);
- runtime_notetsleepg(&timers.waitnote, delta);
- }
-}
-
-// heap maintenance algorithms.
-
-static void
-siftup(int32 i)
-{
- int32 p;
- int64 when;
- Timer **t, *tmp;
-
- t = timers.t;
- when = t[i]->when;
- tmp = t[i];
- while(i > 0) {
- p = (i-1)/4; // parent
- if(when >= t[p]->when)
- break;
- t[i] = t[p];
- t[i]->i = i;
- t[p] = tmp;
- tmp->i = p;
- i = p;
- }
-}
-
-static void
-siftdown(int32 i)
-{
- int32 c, c3, len;
- int64 when, w, w3;
- Timer **t, *tmp;
-
- t = timers.t;
- len = timers.len;
- when = t[i]->when;
- tmp = t[i];
- for(;;) {
- c = i*4 + 1; // left child
- c3 = c + 2; // mid child
- if(c >= len) {
- break;
- }
- w = t[c]->when;
- if(c+1 < len && t[c+1]->when < w) {
- w = t[c+1]->when;
- c++;
- }
- if(c3 < len) {
- w3 = t[c3]->when;
- if(c3+1 < len && t[c3+1]->when < w3) {
- w3 = t[c3+1]->when;
- c3++;
- }
- if(w3 < w) {
- w = w3;
- c = c3;
- }
- }
- if(w >= when)
- break;
- t[i] = t[c];
- t[i]->i = i;
- t[c] = tmp;
- tmp->i = c;
- i = c;
- }
-}
-
-static void
-dumptimers(const char *msg)
-{
- Timer *t;
- int32 i;
-
- runtime_printf("timers: %s\n", msg);
- for(i = 0; i < timers.len; i++) {
- t = timers.t[i];
- runtime_printf("\t%d\t%p:\ti %d when %D period %D fn %p\n",
- i, t, t->i, t->when, t->period, t->fv->fn);
- }
- runtime_printf("\n");
-}
-
-void
-runtime_time_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
- enqueue1(wbufp, (Obj){(byte*)&timers, sizeof timers, 0});
-}
diff --git a/libgo/runtime/yield.c b/libgo/runtime/yield.c
index 442d346db7..d0aed8d22e 100644
--- a/libgo/runtime/yield.c
+++ b/libgo/runtime/yield.c
@@ -37,6 +37,9 @@ runtime_procyield (uint32 cnt)
/* Ask the OS to reschedule this thread. */
+void runtime_osyield(void)
+ __attribute__ ((no_split_stack));
+
void
runtime_osyield (void)
{
diff --git a/libgo/sysinfo.c b/libgo/sysinfo.c
new file mode 100644
index 0000000000..235941b621
--- /dev/null
+++ b/libgo/sysinfo.c
@@ -0,0 +1,279 @@
+/* sysinfo.c -- input for mksysinfo.sh
+
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file. */
+
+/* This file is passed to GCC with the -fdump-go-spec option to
+ generate a Go version of the system information. */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ucontext.h>
+#include <netinet/in.h>
+/* <netinet/tcp.h> needs u_char/u_short, but <sys/bsd_types> is only
+ included by <netinet/in.h> if _SGIAPI (i.e. _SGI_SOURCE
+ && !_XOPEN_SOURCE.
+ <sys/termios.h> only defines TIOCNOTTY if !_XOPEN_SOURCE, while
+ <sys/ttold.h> does so unconditionally. */
+#ifdef __sgi__
+#include <sys/bsd_types.h>
+#include <sys/ttold.h>
+#endif
+#include <netinet/tcp.h>
+#if defined(HAVE_NETINET_IN_SYSTM_H)
+#include <netinet/in_systm.h>
+#endif
+#if defined(HAVE_NETINET_IP_H)
+#include <netinet/ip.h>
+#endif
+#if defined(HAVE_NETINET_IP_MROUTE_H)
+#include <netinet/ip_mroute.h>
+#endif
+#if defined(HAVE_NETINET_IF_ETHER_H)
+#include <netinet/if_ether.h>
+#endif
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h>
+#endif
+#if defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+#if defined(HAVE_SYS_EPOLL_H)
+#include <sys/epoll.h>
+#endif
+#if defined(HAVE_SYS_EVENT_H)
+#include <sys/event.h>
+#endif
+#if defined(HAVE_SYS_FILE_H)
+#include <sys/file.h>
+#endif
+#if defined(HAVE_SYS_MMAN_H)
+#include <sys/mman.h>
+#endif
+#if defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#endif
+#if defined(HAVE_SYS_PTRACE_H)
+#include <sys/ptrace.h>
+#endif
+#include <sys/resource.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#if defined(HAVE_SYS_USER_H)
+#include <sys/user.h>
+#endif
+#if defined(HAVE_SYS_UTSNAME_H)
+#include <sys/utsname.h>
+#endif
+#if defined(HAVE_SYS_SELECT_H)
+#include <sys/select.h>
+#endif
+#include <time.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+#if defined(HAVE_LINUX_FILTER_H)
+#include <linux/filter.h>
+#endif
+#if defined(HAVE_LINUX_IF_ADDR_H)
+#include <linux/if_addr.h>
+#endif
+#if defined(HAVE_LINUX_IF_ETHER_H)
+#include <linux/if_ether.h>
+#endif
+#if defined(HAVE_LINUX_IF_TUN_H)
+#include <linux/if_tun.h>
+#endif
+#if defined(HAVE_LINUX_NETLINK_H)
+#include <linux/netlink.h>
+#endif
+#if defined(HAVE_LINUX_RTNETLINK_H)
+#include <linux/rtnetlink.h>
+#endif
+#if defined(HAVE_NET_IF_H)
+#include <net/if.h>
+#endif
+#if defined(HAVE_NET_IF_ARP_H)
+#include <net/if_arp.h>
+#endif
+#if defined(HAVE_NET_ROUTE_H)
+#include <net/route.h>
+#endif
+#if defined (HAVE_NETPACKET_PACKET_H)
+#include <netpacket/packet.h>
+#endif
+#if defined(HAVE_SYS_MOUNT_H)
+#include <sys/mount.h>
+#endif
+#if defined(HAVE_SYS_VFS_H)
+#include <sys/vfs.h>
+#endif
+#if defined(HAVE_STATFS_H)
+#include <sys/statfs.h>
+#endif
+#if defined(HAVE_SYS_TIMEX_H)
+#include <sys/timex.h>
+#endif
+#if defined(HAVE_SYS_SYSINFO_H)
+#include <sys/sysinfo.h>
+#endif
+#if defined(HAVE_USTAT_H)
+#include <ustat.h>
+#endif
+#if defined(HAVE_UTIME_H)
+#include <utime.h>
+#endif
+#if defined(HAVE_LINUX_ETHER_H)
+#include <linux/ether.h>
+#endif
+#if defined(HAVE_LINUX_FS_H)
+#include <linux/fs.h>
+#endif
+#if defined(HAVE_LINUX_REBOOT_H)
+#include <linux/reboot.h>
+#endif
+#if defined(HAVE_SYS_INOTIFY_H)
+#include <sys/inotify.h>
+#endif
+#if defined(HAVE_NETINET_ICMP6_H)
+#include <netinet/icmp6.h>
+#endif
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+#if defined(HAVE_SEMAPHORE_H)
+#include <semaphore.h>
+#endif
+#if defined(HAVE_PORT_H)
+#include <port.h>
+#endif
+
+#ifdef USE_LIBFFI
+#include "ffi.h"
+#endif
+
+/* Constants that may only be defined as expressions on some systems,
+ expressions too complex for -fdump-go-spec to handle. These are
+ handled specially below. */
+enum {
+#ifdef TIOCGWINSZ
+ TIOCGWINSZ_val = TIOCGWINSZ,
+#endif
+#ifdef TIOCSWINSZ
+ TIOCSWINSZ_val = TIOCSWINSZ,
+#endif
+#ifdef TIOCNOTTY
+ TIOCNOTTY_val = TIOCNOTTY,
+#endif
+#ifdef TIOCSCTTY
+ TIOCSCTTY_val = TIOCSCTTY,
+#endif
+#ifdef TIOCGPGRP
+ TIOCGPGRP_val = TIOCGPGRP,
+#endif
+#ifdef TIOCSPGRP
+ TIOCSPGRP_val = TIOCSPGRP,
+#endif
+#ifdef TIOCGPTN
+ TIOCGPTN_val = TIOCGPTN,
+#endif
+#ifdef TIOCSPTLCK
+ TIOCSPTLCK_val = TIOCSPTLCK,
+#endif
+#ifdef TIOCGDEV
+ TIOCGDEV_val = TIOCGDEV,
+#endif
+#ifdef TIOCSIG
+ TIOCSIG_val = TIOCSIG,
+#endif
+#ifdef TCGETS
+ TCGETS_val = TCGETS,
+#endif
+#ifdef TCSETS
+ TCSETS_val = TCSETS,
+#endif
+#ifdef TUNSETIFF
+ TUNSETIFF_val = TUNSETIFF,
+#endif
+#ifdef TUNSETNOCSUM
+ TUNSETNOCSUM_val = TUNSETNOCSUM,
+#endif
+#ifdef TUNSETDEBUG
+ TUNSETDEBUG_val = TUNSETDEBUG,
+#endif
+#ifdef TUNSETPERSIST
+ TUNSETPERSIST_val = TUNSETPERSIST,
+#endif
+#ifdef TUNSETOWNER
+ TUNSETOWNER_val = TUNSETOWNER,
+#endif
+#ifdef TUNSETLINK
+ TUNSETLINK_val = TUNSETLINK,
+#endif
+#ifdef TUNSETGROUP
+ TUNSETGROUP_val = TUNSETGROUP,
+#endif
+#ifdef TUNGETFEATURES
+ TUNGETFEATURES_val = TUNGETFEATURES,
+#endif
+#ifdef TUNSETOFFLOAD
+ TUNSETOFFLOAD_val = TUNSETOFFLOAD,
+#endif
+#ifdef TUNSETTXFILTER
+ TUNSETTXFILTER_val = TUNSETTXFILTER,
+#endif
+#ifdef TUNGETIFF
+ TUNGETIFF_val = TUNGETIFF,
+#endif
+#ifdef TUNGETSNDBUF
+ TUNGETSNDBUF_val = TUNGETSNDBUF,
+#endif
+#ifdef TUNSETSNDBUF
+ TUNSETSNDBUF_val = TUNSETSNDBUF,
+#endif
+#ifdef TUNATTACHFILTER
+ TUNATTACHFILTER_val = TUNATTACHFILTER,
+#endif
+#ifdef TUNDETACHFILTER
+ TUNDETACHFILTER_val = TUNDETACHFILTER,
+#endif
+#ifdef TUNGETVNETHDRSZ
+ TUNGETVNETHDRSZ_val = TUNGETVNETHDRSZ,
+#endif
+#ifdef TUNSETVNETHDRSZ
+ TUNSETVNETHDRSZ_val = TUNSETVNETHDRSZ,
+#endif
+#ifdef TUNSETQUEUE
+ TUNSETQUEUE_val = TUNSETQUEUE,
+#endif
+#ifdef TUNSETIFINDEX
+ TUNSETIFINDEX_val = TUNSETIFINDEX,
+#endif
+#ifdef TUNGETFILTER
+ TUNGETFILTER_val = TUNGETFILTER,
+#endif
+#ifdef NLA_HDRLEN
+ NLA_HDRLEN_val = NLA_HDRLEN,
+#endif
+};
+
+#if defined(HAVE_SYS_EPOLL_H)
+enum {
+ epoll_data_offset = offsetof(struct epoll_event, data)
+};
+#endif
diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in
index ba04a504cf..79da1c91ff 100644
--- a/libgo/testsuite/Makefile.in
+++ b/libgo/testsuite/Makefile.in
@@ -55,6 +55,7 @@ subdir = testsuite
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+ $(top_srcdir)/../config/hwcaps.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../config/multi.m4 \
$(top_srcdir)/../config/override.m4 \
@@ -79,6 +80,9 @@ am__can_run_installinfo = \
DEJATOOL = $(PACKAGE)
RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
ACLOCAL = @ACLOCAL@
+ALLGOARCH = @ALLGOARCH@
+ALLGOARCHFAMILY = @ALLGOARCHFAMILY@
+ALLGOOS = @ALLGOOS@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
@@ -103,6 +107,14 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GOARCH = @GOARCH@
+GOARCH_BIGENDIAN = @GOARCH_BIGENDIAN@
+GOARCH_CACHELINESIZE = @GOARCH_CACHELINESIZE@
+GOARCH_FAMILY = @GOARCH_FAMILY@
+GOARCH_HUGEPAGESIZE = @GOARCH_HUGEPAGESIZE@
+GOARCH_INT64ALIGN = @GOARCH_INT64ALIGN@
+GOARCH_MINFRAMESIZE = @GOARCH_MINFRAMESIZE@
+GOARCH_PCQUANTUM = @GOARCH_PCQUANTUM@
+GOARCH_PHYSPAGESIZE = @GOARCH_PHYSPAGESIZE@
GOC = @GOC@
GOCFLAGS = @GOCFLAGS@
GOOS = @GOOS@
@@ -112,6 +124,7 @@ GO_SPLIT_STACK = @GO_SPLIT_STACK@
GO_SYSCALL_OS_ARCH_FILE = @GO_SYSCALL_OS_ARCH_FILE@
GO_SYSCALL_OS_FILE = @GO_SYSCALL_OS_FILE@
GREP = @GREP@
+HWCAP_CFLAGS = @HWCAP_CFLAGS@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
index 79e02e2a1e..f070a8ae69 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -10,9 +10,10 @@
# Makes egrep,grep work better in general if we put them
# in ordinary C mode instead of what the current language is.
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
+LANG=C
+LC_ALL=C
+LC_CTYPE=C
+export LANG LC_ALL LC_CTYPE
GC=${GC:-gccgo}
GL=${GL:-${GC-gccgo}}
@@ -217,18 +218,27 @@ x)
;;
*)
for f in $pkgfiles; do
- if test -f $basedir/$f; then
- b=`basename $f`
- rm -f $b
- cp $basedir/$f $b
- elif test -f ../../$f; then
- b=`basename $f`
- rm -f $b
- cp ../../$f $b
- else
- echo "file $f not found" 1>&2
- exit 1
- fi
+ case $f in
+ /*)
+ b=`basename $f`
+ rm -f $b
+ cp $f $b
+ ;;
+ *)
+ if test -f $basedir/$f; then
+ b=`basename $f`
+ rm -f $b
+ cp $basedir/$f $b
+ elif test -f ../../$f; then
+ b=`basename $f`
+ rm -f $b
+ cp ../../$f $b
+ else
+ echo "file $f not found" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
done
for f in `cd $srcdir; ls *_test.go`; do
rm -f $f
@@ -252,18 +262,27 @@ x)
;;
*)
for f in $pkgfiles; do
- if test -f $basedir/$f; then
- b=`basename $f`
- rm -f $b
- cp $basedir/$f $b
- elif test -f ../../$f; then
- b=`basename $f`
- rm -f $b
- cp ../../$f $b
- else
- echo "file $f not found" 1>&2
- exit 1
- fi
+ case $f in
+ /*)
+ b=`basename $f`
+ rm -f $b
+ cp $f $b
+ ;;
+ *)
+ if test -f $basedir/$f; then
+ b=`basename $f`
+ rm -f $b
+ cp $basedir/$f $b
+ elif test -f ../../$f; then
+ b=`basename $f`
+ rm -f $b
+ cp ../../$f $b
+ else
+ echo "file $f not found" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
done
;;
esac
@@ -295,7 +314,7 @@ x)
android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows)
tag1=nonmatchingtag
;;
- 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
+ 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
tag1=nonmatchingtag
;;
esac
@@ -307,62 +326,63 @@ x)
android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows)
tag2=nonmatchingtag
;;
- 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
+ 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64)
tag2=nonmatchingtag
;;
esac
if test x$tag1 != xnonmatchingtag -a x$tag2 != xnonmatchingtag; then
- taglines=`sed '/^package /q' < $f | fgrep '// +build '`
- if test "$taglines" = ""; then
- omatch=true
- else
- omatch=false
- fi
- for tags in $taglines; do
- match=false
- for tag in $tags; do
- reverse=false
- case $tag in
- "!"*)
- reverse=true
- tag=`echo $tag | sed -e 's/^!//'`
- ;;
- esac
-
- case $tag in
- "//" | "+build")
- ;;
- $goos | $goarch | cgo)
- match=true
- ;;
- *,*)
+ tags=`sed '/^package /q' < $f | grep '^// +build '`
+ omatch=true
+ first=true
+ match=false
+ for tag in $tags; do
+ case $tag in
+ "//")
+ ;;
+ "+build")
+ if test "$first" = "true"; then
+ first=false
+ elif test "$match" = "false"; then
+ omatch=false
+ fi
+ match=false
+ ;;
+ $goos | $goarch | cgo)
+ match=true
+ ;;
+ "!"$goos | "!"$goarch | "!cgo")
+ ;;
+ *,*)
+ cmatch=true
+ for ctag in `echo $tag | sed -e 's/,/ /g'`; do
+ case $ctag in
+ $goos | $goarch | cgo)
+ ;;
+ "!"$goos | "!"$goarch | "!cgo")
+ cmatch=false
+ ;;
+ "!"*)
+ ;;
+ *)
+ cmatch=false
+ ;;
+ esac
+ done
+ if test "$cmatch" = "true"; then
match=true
- for ctag in `echo $tag | sed -e 's/,/ /g'`; do
- case $ctag in
- $goos | $goarch | cgo)
- ;;
- *)
- match=false
- ;;
- esac
- done
- ;;
- esac
-
- if test "$reverse" = true; then
- if test "$match" = true; then
- match=false
- else
- match=true
- fi
fi
- done
- if test "$match" = "true"; then
- omatch=true
- fi
+ ;;
+ "!"*)
+ match=true
+ ;;
+ esac
done
+ if test "$match" = "false" -a "$first" = "false"; then
+ omatch=false
+ fi
+
if test "$omatch" = "true"; then
gofiles="$gofiles $f"
fi
@@ -522,7 +542,7 @@ localname() {
echo 'import "./_xtest_"'
fi
echo 'import "testing"'
- echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
+ echo 'import "testing/internal/testdeps"'
if ! test -n "$testmain"; then
echo 'import __os__ "os"'
fi
@@ -565,22 +585,8 @@ localname() {
# body
echo \
'
-var matchPat string
-var matchRe *__regexp__.Regexp
-
-func matchString(pat, str string) (result bool, err error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = __regexp__.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
func main() {
- m := testing.MainStart(matchString, tests, benchmarks, examples)
+ m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
'
if test -n "$testmain"; then
echo " ${testmain}(m)"